diff --git a/virtweb_frontend/src/widgets/forms/NWFSelectReferencedFilters.tsx b/virtweb_frontend/src/widgets/forms/NWFSelectReferencedFilters.tsx new file mode 100644 index 0000000..12c9722 --- /dev/null +++ b/virtweb_frontend/src/widgets/forms/NWFSelectReferencedFilters.tsx @@ -0,0 +1,54 @@ +import React from "react"; +import { NWFilter } from "../../api/NWFilterApi"; +import { NWFilterSelectInput } from "./NWFilterSelectInput"; +import { NWFilterItem } from "../nwfilter/NWFilterItem"; + +export function NWFSelectReferencedFilters(p: { + editable: boolean; + selected: string[]; + nwFiltersList: NWFilter[]; + onChange?: () => void; + excludedFilters?: string[]; +}): React.ReactElement { + const nwfilters = React.useMemo( + () => + p.excludedFilters + ? p.nwFiltersList.filter((f) => !p.excludedFilters!.includes(f.name)) + : p.nwFiltersList, + [p.excludedFilters] + ); + + const selectedFilters = React.useMemo( + () => p.selected.map((f) => p.nwFiltersList.find((s) => s.name === f)), + [p.selected.length] + ); + + return ( + <> + {selectedFilters.map((entry, n) => ( + { + p.selected.splice(n, 1); + p.onChange?.(); + }} + /> + ))} + + {p.editable && ( + { + p.selected.push(f!); + p.onChange?.(); + }} + /> + )} + + ); +} diff --git a/virtweb_frontend/src/widgets/forms/NWFilterSelectInput.tsx b/virtweb_frontend/src/widgets/forms/NWFilterSelectInput.tsx index 0be290d..71806f2 100644 --- a/virtweb_frontend/src/widgets/forms/NWFilterSelectInput.tsx +++ b/virtweb_frontend/src/widgets/forms/NWFilterSelectInput.tsx @@ -1,6 +1,7 @@ import { Autocomplete, TextField } from "@mui/material"; import { NWFilter } from "../../api/NWFilterApi"; import { NWFilterItem } from "../nwfilter/NWFilterItem"; +import React from "react"; export function NWFilterSelectInput(p: { editable: boolean; @@ -10,6 +11,8 @@ export function NWFilterSelectInput(p: { onChange?: (name?: string) => void; canBeNull: boolean; }): React.ReactElement { + const [open, setOpen] = React.useState(false); + const selectedValue = p.nwfilters.find((o) => o.name === p.value); if (!p.editable && !selectedValue) return <>; @@ -23,7 +26,14 @@ export function NWFilterSelectInput(p: { return ( { + setOpen(true); + }} + onClose={() => { + setOpen(false); + }} + readOnly={!p.editable} options={[...(p.canBeNull ? [undefined] : []), ...p.nwfilters]} getOptionLabel={(o) => o?.name ?? "Unspecified"} value={selectedValue} @@ -32,7 +42,11 @@ export function NWFilterSelectInput(p: { )} renderOption={(_props, option, _state) => ( p.onChange?.(option?.name)} + dense + onClick={() => { + p.onChange?.(option?.name); + setOpen(false); + }} value={option} /> )} diff --git a/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx b/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx index 43829d8..09103f4 100644 --- a/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx +++ b/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx @@ -16,6 +16,7 @@ import { EditSection } from "../forms/EditSection"; import { TextInput } from "../forms/TextInput"; import { ServerApi } from "../../api/ServerApi"; import { SelectInput } from "../forms/SelectInput"; +import { NWFSelectReferencedFilters } from "../forms/NWFSelectReferencedFilters"; interface DetailsProps { nwfilter: NWFilter; @@ -143,6 +144,17 @@ function NetworkFilterDetailsTabGeneral( size={ServerApi.Config.constraints.nwfilter_priority} /> + + {/* Referenced filters */} + {(p.editable || p.nwfilter.join_filters.length > 0) && ( + + + + )} ); } diff --git a/virtweb_frontend/src/widgets/nwfilter/NWFilterItem.tsx b/virtweb_frontend/src/widgets/nwfilter/NWFilterItem.tsx index e1d17f2..337c1a8 100644 --- a/virtweb_frontend/src/widgets/nwfilter/NWFilterItem.tsx +++ b/virtweb_frontend/src/widgets/nwfilter/NWFilterItem.tsx @@ -20,7 +20,6 @@ export function NWFilterItem(p: { }): React.ReactElement { const inner = ( <> - {" "}