Skip to content
This repository was archived by the owner on Jan 19, 2025. It is now read-only.

Commit 11878d5

Browse files
authored
feat(gui): improved saving of filters (#775)
* feat(gui): improved saving of filters * feat(gui): allow saving empty filter
1 parent 3b14688 commit 11878d5

File tree

2 files changed

+58
-28
lines changed

2 files changed

+58
-28
lines changed

api-editor/gui/src/features/filter/SaveFilterDialog.tsx

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,31 @@ import {
1313
ModalFooter,
1414
ModalHeader,
1515
ModalOverlay,
16+
Text as ChakraText,
17+
Textarea,
18+
VStack,
1619
} from '@chakra-ui/react';
1720
import React, { useState } from 'react';
1821
import { useAppDispatch, useAppSelector } from '../../app/hooks';
19-
import { addFilter, selectFilterList, selectFilterString, toggleAddFilterDialog } from '../ui/uiSlice';
22+
import { selectFilterList, selectFilterString, toggleAddFilterDialog, upsertFilter } from '../ui/uiSlice';
23+
import { isValidFilterToken } from './model/filterFactory';
2024

2125
export const SaveFilterDialog: React.FC = function () {
2226
const dispatch = useAppDispatch();
23-
const filter = useAppSelector(selectFilterString);
2427
const savedFilters = useAppSelector(selectFilterList);
28+
2529
const [filterName, setFilterName] = useState('');
30+
const [filterString, setFilterString] = useState(useAppSelector(selectFilterString));
2631

27-
const alreadyIncluded: boolean = savedFilters.some((it) => {
32+
const alreadyIncluded = savedFilters.some((it) => {
2833
return it.name === filterName;
2934
});
35+
const invalidTokens = filterString.split(' ').filter((token) => token !== '' && !isValidFilterToken(token));
36+
const filterStringIsValid = invalidTokens.length === 0;
3037

3138
const submit = () => {
32-
if (filterName !== '' && !alreadyIncluded) {
33-
dispatch(addFilter({ filter, name: filterName }));
39+
if (filterName.trim() !== '' && filterStringIsValid) {
40+
dispatch(upsertFilter({ filter: filterString, name: filterName }));
3441
dispatch(toggleAddFilterDialog());
3542
}
3643
};
@@ -46,33 +53,53 @@ export const SaveFilterDialog: React.FC = function () {
4653
<Heading>Save Filter</Heading>
4754
</ModalHeader>
4855
<ModalBody>
49-
<FormControl isInvalid={alreadyIncluded || filterName.trim() === ''}>
50-
<FormLabel htmlFor="newFilterName">
51-
Name for the current filter <Code>{filter}</Code>:
52-
</FormLabel>
53-
<Input
54-
type="text"
55-
id="newFilterName"
56-
value={filterName}
57-
onChange={(event) => setFilterName(event.target.value)}
58-
spellCheck={false}
59-
/>
60-
{alreadyIncluded && (
61-
<FormErrorMessage>A filter with this name is saved already.</FormErrorMessage>
62-
)}
63-
{filterName.trim() === '' && (
64-
<FormErrorMessage>The filter name must not be blank.</FormErrorMessage>
65-
)}
66-
</FormControl>
56+
<VStack spacing={4}>
57+
<FormControl isInvalid={filterName.trim() === ''}>
58+
<FormLabel htmlFor="newFilterName">Filter Name:</FormLabel>
59+
<Input
60+
type="text"
61+
id="newFilterName"
62+
value={filterName}
63+
onChange={(event) => setFilterName(event.target.value)}
64+
spellCheck={false}
65+
/>
66+
{filterName.trim() === '' && (
67+
<FormErrorMessage>The filter name must not be blank.</FormErrorMessage>
68+
)}
69+
</FormControl>
70+
71+
<FormControl isInvalid={!filterStringIsValid}>
72+
<FormLabel htmlFor="newFilterString">Filter String:</FormLabel>
73+
<Textarea
74+
id="newFilterString"
75+
value={filterString}
76+
onChange={(event) => setFilterString(event.target.value)}
77+
spellCheck={false}
78+
/>
79+
{!filterStringIsValid && (
80+
<FormErrorMessage>
81+
<ChakraText>
82+
Filter has invalid tokens:{' '}
83+
{invalidTokens.map((token, index) => (
84+
<>
85+
<Code>{token}</Code>
86+
{index < invalidTokens.length - 1 && ', '}
87+
</>
88+
))}
89+
</ChakraText>
90+
</FormErrorMessage>
91+
)}
92+
</FormControl>
93+
</VStack>
6794
</ModalBody>
6895
<ModalFooter>
6996
<HStack spacing={4}>
7097
<Button
7198
colorScheme="blue"
7299
onClick={submit}
73-
isDisabled={alreadyIncluded || filterName.trim() === ''}
100+
isDisabled={filterName.trim() === '' || !filterStringIsValid}
74101
>
75-
Submit
102+
{alreadyIncluded ? 'Replace' : 'Add'}
76103
</Button>
77104
<Button colorScheme="red" onClick={close}>
78105
Cancel

api-editor/gui/src/features/ui/uiSlice.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,11 @@ const uiSlice = createSlice({
320320
setFilterString(state, action: PayloadAction<string>) {
321321
state.filterString = action.payload;
322322
},
323-
addFilter(state, action: PayloadAction<Filter>) {
324-
state.filterList.push(action.payload);
323+
upsertFilter(state, action: PayloadAction<Filter>) {
324+
state.filterList = [
325+
...state.filterList.filter((filter) => filter.name !== action.payload.name),
326+
action.payload,
327+
];
325328
},
326329
removeFilter(state, action: PayloadAction<string>) {
327330
state.filterList = state.filterList.filter((filter) => filter.filter !== action.payload);
@@ -372,7 +375,7 @@ export const {
372375
setTreeViewScrollOffset,
373376
setHeatMapMode,
374377
setFilterString,
375-
addFilter,
378+
upsertFilter,
376379
removeFilter,
377380
setSortingMode,
378381
setBatchMode,

0 commit comments

Comments
 (0)