Skip to content

Commit

Permalink
Filter logic
Browse files Browse the repository at this point in the history
Signed-off-by: Gabriel Indik <[email protected]>
  • Loading branch information
gabriel-indik committed Feb 12, 2025
1 parent 57acaee commit 9e1e733
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 46 deletions.
4 changes: 1 addition & 3 deletions ui/client/src/components/Filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,10 @@ export const Filters: React.FC<Props> = ({
const [addFilterDialogOpen, setAddFilterDialogOpen] = useState(false);
const { t } = useTranslation();

console.log(filters)

const getOperatorLabel = (operator: string) => {
switch (operator) {
case 'equal': return '= ';
case 'notEqual': return '!= ';
case 'neq': return '!= ';
case 'greaterThan': return '> ';
case 'greaterThanOrEqual': return '>= ';
case 'lessThan': return '< ';
Expand Down
12 changes: 9 additions & 3 deletions ui/client/src/dialogs/AddFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export const AddFilterDialog: React.FC<Props> = ({
} else {
availableOperators = [
...availableOperators,
<MenuItem key="notEqual" value="notEqual">{t('notEqual')}</MenuItem>,
<MenuItem key="neq" value="neq">{t('notEqual')}</MenuItem>,
<MenuItem key="greaterThan" value="greaterThan">{t('greaterThan')}</MenuItem>,
<MenuItem key="greaterThanOrEqual" value="greaterThanOrEqual">{t('greaterThanOrEqual')}</MenuItem>,
<MenuItem key="lessThan" value="lessThan">{t('lessThan')}</MenuItem>,
Expand All @@ -101,10 +101,13 @@ export const AddFilterDialog: React.FC<Props> = ({
if (selectedFilterField.type === 'number' && isNaN(Number(value))) {
setValue('');
}
if (selectedOperator !== undefined && ['greaterThan', 'greaterThanOrEqual', 'lessThan', 'lessThanOrEqual'].includes(selectedOperator)) {
setIsCaseSensitive(true);
}
setValues(availableValues);
setOperators(availableOperators);
}
}, [selectedFilterField]);
}, [selectedFilterField, selectedOperator]);

const handleSubmit = () => {
if (selectedFilterField !== undefined && selectedOperator !== undefined) {
Expand Down Expand Up @@ -184,7 +187,10 @@ export const AddFilterDialog: React.FC<Props> = ({
</TextField>
<Box sx={{ textAlign: 'center' }}>
<FormControlLabel
disabled={selectedFilterField === undefined || selectedFilterField.type !== 'string'}
disabled={selectedFilterField === undefined || selectedFilterField.type !== 'string'
|| (selectedOperator !== undefined &&
['greaterThan', 'greaterThanOrEqual', 'lessThan', 'lessThanOrEqual'].includes(selectedOperator))
}
control={<Checkbox checked={isCaseSensitive} onChange={event => setIsCaseSensitive(event.target.checked)} />}
label={t('caseSensitive')} />
</Box>
Expand Down
26 changes: 22 additions & 4 deletions ui/client/src/dialogs/ReverseKeyLookup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,20 @@ import { Dispatch, SetStateAction, useEffect, useState } from 'react';
import { reverseKeyLookup } from '../queries/keys';
import { constants } from '../components/config';
import { useTranslation } from 'react-i18next';
import { IFilter } from '../interfaces';

type Props = {
dialogOpen: boolean
setDialogOpen: React.Dispatch<React.SetStateAction<boolean>>
setParent: Dispatch<SetStateAction<string>>
setFilter: Dispatch<SetStateAction<string | undefined>>
setFilters: Dispatch<SetStateAction<IFilter[]>>
}

export const ReverseKeyLookupDialog: React.FC<Props> = ({
dialogOpen,
setDialogOpen,
setParent,
setFilter
setFilters
}) => {

const [verifier, setVerifier] = useState('');
Expand Down Expand Up @@ -88,9 +89,26 @@ export const ReverseKeyLookupDialog: React.FC<Props> = ({
const index = path.lastIndexOf('.');
if(index !== -1) {
setParent(path.substring(0, index));
setFilter(path.substring(index + 1))
// setFilter(path.substring(index + 1))
setFilters([{
field: {
label: t('name'),
name: 'path',
type: 'string'
},
operator: 'equal',
value: path.substring(index + 1)
}]);
} else {
setFilter(path);
setFilters([{
field: {
label: t('name'),
name: 'path',
type: 'string'
},
operator: 'equal',
value: path
}]);
}
setDialogOpen(false);
} else if (result.status === 'error') {
Expand Down
40 changes: 26 additions & 14 deletions ui/client/src/queries/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,53 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { IKeyEntry, IKeyMappingAndVerifier } from "../interfaces";
import { IFilter, IKeyEntry, IKeyMappingAndVerifier } from "../interfaces";
import { translateFilters } from "../utils";
import { generatePostReq, returnResponse } from "./common";
import { RpcEndpoint, RpcMethods } from "./rpcMethods";
import i18next from "i18next";

export const fetchKeys = async (parent: string, limit: number, sortBy: string, sortOrder: 'asc' | 'desc', pathFilter?: string, refEntry?: IKeyEntry): Promise<IKeyEntry[]> => {
export const fetchKeys = async (parent: string, limit: number, sortBy: string, sortOrder: 'asc' | 'desc', filters: IFilter[], refEntry?: IKeyEntry): Promise<IKeyEntry[]> => {

let translatedFilters = translateFilters(filters);

if (translatedFilters.eq === undefined) {
translatedFilters.eq = [];
}
translatedFilters.eq.push({
field: 'parent',
value: parent
});

let requestPayload: any = {
jsonrpc: "2.0",
id: Date.now(),
method: RpcMethods.keymgr_queryKeys,
params: [{
eq: [
{
field: 'parent',
value: parent
}
],
...translatedFilters,
sort: [`${sortBy} ${sortOrder}`],
limit
}]
};


// console.log(translateFilters(filters))

if (refEntry !== undefined) {
requestPayload.params[0][sortOrder === 'asc' ? 'greaterThan' : 'lessThan'] = [{
field: sortBy,
value: refEntry[sortBy as 'path' | 'index']
}];
}

if (pathFilter !== undefined) {
requestPayload.params[0].eq.push({
field: 'path',
value: parent !== '' ? `${parent}.${pathFilter}` : pathFilter
});
}
// if (pathFilter !== undefined) {
// requestPayload.params[0].eq.push({
// field: 'path',
// value: parent !== '' ? `${parent}.${pathFilter}` : pathFilter
// });
// }

// console.log(JSON.stringify(translateFilters(filters), null, 2));

return <Promise<IKeyEntry[]>>(
returnResponse(
Expand Down
39 changes: 38 additions & 1 deletion ui/client/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,48 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { IFilter } from "./interfaces";

export const formatJSONWhenApplicable = (value: any) => {
if (typeof value === 'object') {
try {
return JSON.stringify(value, null, 2);
} catch (err) { }
}
return String(value);
};
};

export const translateFilters = (filters: IFilter[]) => {

let result: any = {};

for (const filter of filters) {

let entry: any = {
field: filter.field.name,
value: filter.value,
};

if(filter.caseSensitive === false) {
entry.caseInsensitive = true;
}

let operator = filter.operator;

switch (operator) {
case 'contains': operator = 'like'; entry.value = `%${entry.value}%`; break;
case 'startsWith': operator = 'like'; entry.value = `${entry.value}%`; break;
case 'endsWith': operator = 'like'; entry.value = `%${entry.value}`; break;
case 'doesNotContain': operator = 'like'; entry.not = true; entry.value = `%${entry.value}%`; break;
case 'doesNotStartWith': operator = 'like'; entry.not = true; entry.value = `${entry.value}%`; break;
case 'doesNotEndWith': operator = 'like'; entry.not = true; entry.value = `%${entry.value}`; break;
}

let group = result[operator] ?? [];
group.push(entry);
result[operator] = group;
}

return result;

};
29 changes: 8 additions & 21 deletions ui/client/src/views/Keys.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export const Keys: React.FC = () => {

const [searchParams, setSearchParams] = useSearchParams();
const [refEntries, setRefEntries] = useState<IKeyEntry[]>([]);
const [filter, setFilter] = useState<string | undefined>(searchParams.get('filter') ?? undefined);
const [page, setPage] = useState(0);
const [count, setCount] = useState(-1);
const [rowsPerPage, setRowsPerPage] = useState(getDefaultRowsPerPage());
Expand All @@ -66,13 +65,12 @@ export const Keys: React.FC = () => {
const { t } = useTranslation();

useEffect(() => {
setFilter(searchParams.get('filter') ?? undefined);
setParent(searchParams.get('path') ?? '');
}, [searchParams]);

const { data: keys, error } = useQuery({
queryKey: ["keys", parent, sortBy, sortOrder, refEntries, rowsPerPage, filter],
queryFn: () => fetchKeys(parent, rowsPerPage, sortBy, sortOrder, filter, refEntries[refEntries.length - 1])
queryKey: ["keys", parent, sortBy, sortOrder, refEntries, rowsPerPage, filters],
queryFn: () => fetchKeys(parent, rowsPerPage, sortBy, sortOrder, filters, refEntries[refEntries.length - 1])
});

useEffect(() => {
Expand Down Expand Up @@ -100,11 +98,8 @@ export const Keys: React.FC = () => {
if (parent !== '') {
value.path = parent;
}
if (filter !== undefined) {
value.filter = filter;
}
setSearchParams(value);
}, [parent, page, filter]);
}, [parent, page]);

if (error) {
return <Alert sx={{ margin: '30px' }} severity="error" variant="filled">{error.message}</Alert>
Expand Down Expand Up @@ -150,21 +145,13 @@ export const Keys: React.FC = () => {
href=""
onClick={event => {
event.preventDefault();
setFilter(undefined);
setParent(target);
}}>
{segment === '' ? t('root') : segment}
</Link>
)
}
}
if (filter !== undefined) {
breadcrumbContent.push(
<Link underline="none"
key={filter}>
{filter}
</Link>);
}

const getEthAddress = (key: IKeyEntry) => {
const entry = key.verifiers?.find(entry => entry.type === 'eth_address');
Expand Down Expand Up @@ -291,12 +278,12 @@ export const Keys: React.FC = () => {
},
{
label: t('handle'),
name: 'handle',
name: 'keyHandle',
type: 'string'
},
{
label: t('isFolder'),
name: 'isFolder',
name: 'hasChildren',
type: 'boolean'
},
{
Expand All @@ -313,7 +300,7 @@ export const Keys: React.FC = () => {
sx={{ marginLeft: '10px', marginBottom: '10px' }}>
<Link underline="none"
href=""
onClick={event => { event.preventDefault(); setFilter(undefined); setParent('') }}>
onClick={event => { event.preventDefault(); setParent('') }}>
{t('root')}
</Link>
{breadcrumbContent}
Expand Down Expand Up @@ -354,7 +341,7 @@ export const Keys: React.FC = () => {
<TableRow sx={{ height: '70px' }} key={`${key.path}${key.index}`}>
<TableCell>{key.hasChildren &&
<Tooltip arrow title={t('openFolder')}>
<IconButton onClick={() => { setFilter(undefined); setParent(key.path) }}>
<IconButton onClick={() => { setParent(key.path) }}>
<FolderOpenIcon fontSize="small" />
</IconButton>
</Tooltip>
Expand Down Expand Up @@ -399,7 +386,7 @@ export const Keys: React.FC = () => {
dialogOpen={reverseLookupDialogOpen}
setDialogOpen={setReverseLookupDialogOpen}
setParent={setParent}
setFilter={setFilter}
setFilters={setFilters}
/>
{selectedVerifiers &&
<VerifiersDialog
Expand Down

0 comments on commit 9e1e733

Please sign in to comment.