Skip to content

Commit 5cc3f8a

Browse files
committed
Frontend: added ability to set custom resource (for using wildcard)
1 parent fb06f42 commit 5cc3f8a

File tree

5 files changed

+60
-6
lines changed

5 files changed

+60
-6
lines changed

Dockerfile.standalone

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ FROM nginx:1.23-alpine
3737

3838
ARG GRPC_SERVER_ADDR=:8081
3939
ARG HTTP_SERVER_ADDR=:8080
40-
ARG NGINX_VHOST=./frontend/.docker/vhost.demo.conf
40+
ARG NGINX_VHOST=./frontend/.docker/vhost.conf
4141

4242
ENV GRPC_SERVER_ADDR=$GRPC_SERVER_ADDR
4343
ENV HTTP_SERVER_ADDR=$HTTP_SERVER_ADDR

frontend/src/component/MultipleAutocompleteInput.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import * as React from 'react';
2-
import { InputAdornment, SxProps } from '@mui/material';
2+
import { FilterOptionsState, InputAdornment, SxProps } from '@mui/material';
33
import { useTheme } from '@mui/material/styles';
44
import CloseIcon from '@mui/icons-material/Close';
55
import SearchIcon from '@mui/icons-material/Search';
66
import Autocomplete, {
77
AutocompleteCloseReason,
8+
createFilterOptions,
89
} from '@mui/material/Autocomplete';
910
import Box from '@mui/material/Box';
1011
import { Button, List, ListItem, ListItemText, TextField } from '@mui/material';
@@ -22,6 +23,7 @@ type SetValueFunc = (items: ItemType[]) => void;
2223

2324
type AutocompleteInputProps = {
2425
disabled?: boolean
26+
allowAdd?: boolean
2527
defaultValues?: ItemType[]
2628
errorField?: any
2729
fetcher: FetcherFunc
@@ -34,6 +36,7 @@ type AutocompleteInputProps = {
3436

3537
export default function MultipleAutocompleteInput({
3638
disabled,
39+
allowAdd,
3740
defaultValues,
3841
errorField,
3942
fetcher,
@@ -89,16 +92,37 @@ export default function MultipleAutocompleteInput({
8992
setItems(defaultValues);
9093
}, [defaultValues]);
9194

95+
const filter = createFilterOptions<ItemType>();
96+
97+
const filterOptions = (options: ItemType[], params: FilterOptionsState<ItemType>) => {
98+
const filtered = filter(options, params);
99+
100+
const { inputValue } = params;
101+
const isExisting = options.some((option) => inputValue === option.id);
102+
if (inputValue !== '' && !isExisting) {
103+
filtered.push({
104+
id: inputValue,
105+
label: inputValue,
106+
});
107+
}
108+
109+
return filtered;
110+
};
111+
92112
return (
93113
<div style={style}>
94114
<Autocomplete
95115
disabled={disabled}
96116
multiple
97117
openOnFocus
118+
freeSolo={allowAdd}
119+
selectOnFocus
120+
clearOnBlur
98121
onClose={handleOnClose}
99122
value={items}
100123
onChange={handleOnChange}
101124
disableCloseOnSelect
125+
filterOptions={allowAdd ? filterOptions : undefined}
102126
isOptionEqualToValue={(option: ItemType, value: ItemType): boolean => {
103127
return option.id === value.id;
104128
}}
@@ -124,7 +148,7 @@ export default function MultipleAutocompleteInput({
124148
</li>
125149
)}
126150
options={[...listItems]}
127-
getOptionLabel={(option) => option.label}
151+
getOptionLabel={(option) => typeof(option) === 'string' ? option : option.label}
128152
onFocus={handleOnKeyUp}
129153
onKeyUp={handleOnKeyUp}
130154
renderInput={(params) => (

frontend/src/component/SingleAutocompleteInput.tsx

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import * as React from 'react';
2-
import { InputAdornment, SxProps } from '@mui/material';
2+
import { InputAdornment, SxProps, FilterOptionsState } from '@mui/material';
33
import { useTheme } from '@mui/material/styles';
44
import SearchIcon from '@mui/icons-material/Search';
55
import Autocomplete, {
66
AutocompleteCloseReason,
7+
createFilterOptions,
78
} from '@mui/material/Autocomplete';
89
import Box from '@mui/material/Box';
910
import { TextField } from '@mui/material';
@@ -14,6 +15,7 @@ type SetValueFunc = (items: ItemType) => void;
1415

1516
type AutocompleteInputProps = {
1617
disabled?: boolean
18+
allowAdd?: boolean
1719
defaultValue?: ItemType
1820
errorField?: any
1921
fetcher: FetcherFunc
@@ -26,6 +28,7 @@ type AutocompleteInputProps = {
2628

2729
export default function SingleAutocompleteInput({
2830
disabled,
31+
allowAdd,
2932
defaultValue,
3033
errorField,
3134
fetcher,
@@ -57,18 +60,39 @@ export default function SingleAutocompleteInput({
5760
}
5861
};
5962

60-
const handleOnChange = (event: React.SyntheticEvent, newItem: ItemType | null, reason: string) => {
63+
const handleOnChange = (event: React.SyntheticEvent, newItem: NonNullable<string | ItemType>, reason: string) => {
6164
if (event.type === 'keydown' &&
6265
(event as React.KeyboardEvent).key === 'Backspace' &&
6366
reason === 'removeOption') {
6467
return;
6568
}
6669

70+
if (typeof(newItem) === 'string') {
71+
return;
72+
}
73+
6774
if (newItem !== null) {
6875
setValue(newItem);
6976
}
7077
};
7178

79+
const filter = createFilterOptions<ItemType>();
80+
81+
const filterOptions = (options: ItemType[], params: FilterOptionsState<ItemType>) => {
82+
const filtered = filter(options, params);
83+
84+
const { inputValue } = params;
85+
const isExisting = options.some((option) => inputValue === option.id);
86+
if (inputValue !== '' && !isExisting) {
87+
filtered.push({
88+
id: inputValue,
89+
label: inputValue,
90+
});
91+
}
92+
93+
return filtered;
94+
};
95+
7296
React.useEffect(() => {
7397
if (defaultValue === undefined) {
7498
return;
@@ -82,10 +106,14 @@ export default function SingleAutocompleteInput({
82106
<Autocomplete
83107
disabled={disabled}
84108
openOnFocus
109+
freeSolo={allowAdd}
110+
selectOnFocus
111+
clearOnBlur
85112
onClose={handleOnClose}
86113
onChange={handleOnChange}
87114
disableClearable
88115
defaultValue={defaultValue}
116+
filterOptions={allowAdd ? filterOptions : undefined}
89117
isOptionEqualToValue={(option: ItemType, value: ItemType): boolean => {
90118
return option.id === value.id;
91119
}}
@@ -106,7 +134,7 @@ export default function SingleAutocompleteInput({
106134
</li>
107135
)}
108136
options={[...listItems]}
109-
getOptionLabel={(option) => option.label}
137+
getOptionLabel={(option) => typeof(option) === 'string' ? option : option.label}
110138
onFocus={handleOnKeyUp}
111139
onKeyUp={handleOnKeyUp}
112140
renderInput={(params) => (

frontend/src/page/check/component/Check.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ export default function Check() {
128128
<Grid container spacing={2}>
129129
<Grid item xs={12} md={12}>
130130
<SingleAutocompleteInput
131+
allowAdd
131132
label='Resource'
132133
placeholder='Search for a resource...'
133134
defaultValue={defaultValues?.resource as any}

frontend/src/page/policies/component/PolicyCreateOrEdit.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ export default function PolicyCreateOrEdit() {
173173
<Grid container spacing={2}>
174174
<Grid item xs={12} md={6}>
175175
<MultipleAutocompleteInput
176+
allowAdd
176177
label='Associated resources'
177178
placeholder='Search for a resource...'
178179
defaultValues={defaultValues?.resources as any}

0 commit comments

Comments
 (0)