import { Button, Select } from "@digdir/designsystemet-react"; import { FolderPlusIcon, TrashIcon } from "@navikt/aksel-icons"; import { addGroupAtPath, createExpression, type FieldMetadata, type FilterExpression, type FilterGroup, type FilterNode, type FilterPath, type FilterTree, getLocalizedString, getNodeAtPath, insertNodeAtPath, isExpression, isGroup, removeNodeAtPath, setGroupMode, updateNodeAtPath, } from "@olenbetong/appframe-core"; import { Combobox } from "@olenbetong/appframe-ds"; import { FilterRow, getFieldLabel } from "./FilterRow.js"; import type { FilterEditorSize, GetFieldOptions } from "./types.js"; export type FilterGroupEditorProps = { /** The whole tree. Groups edit it through their own `path`. */ filter: FilterTree; /** Path to the group this editor renders. The root group is the empty path. */ path: FilterPath; fields: FieldMetadata[]; onChange: (filter: FilterTree) => void; getFieldOptions?: GetFieldOptions; readOnly?: boolean; "data-size"?: FilterEditorSize; }; /** * One group of the filter tree. Groups can be nested and each one combines its * items with either `and` or `or`, matching the advanced (DevExpress) filter * editor in the Windows client. * * A blank row is always rendered at the end; picking a field in it appends a * real condition to the group. */ export function FilterGroupEditor({ filter, path, fields, onChange, getFieldOptions, readOnly, "data-size": size = "sm", }: FilterGroupEditorProps) { let node = getNodeAtPath(filter, path); if (!node || !isGroup(node)) return null; let group: FilterGroup = node; let isRoot = path.length === 0; return (
{!readOnly && ( <> {!isRoot && ( )} )}
{group.items.map((item, index) => isExpression(item) ? ( onChange(replaceNode(filter, [...path, index], next))} onRemove={() => onChange(removeNodeAtPath(filter, [...path, index]))} /> ) : ( ), )} {!readOnly && (
option.name} isOptionEqualToValue={(a, b) => a.name === b.name} value={null} onChange={(_event, field) => { if (field) onChange(insertNodeAtPath(filter, path, createExpression(field))); }} />
)}
); } function replaceNode(filter: FilterTree, path: FilterPath, node: FilterExpression): FilterTree { return updateNodeAtPath(filter, path, () => node) as FilterTree; }