diff --git a/frontend/src/components/config/ActionForm.tsx b/frontend/src/components/config/ActionForm.tsx new file mode 100644 index 0000000..8903744 --- /dev/null +++ b/frontend/src/components/config/ActionForm.tsx @@ -0,0 +1,328 @@ +/** + * ActionForm — structured form editor for a single ``action.d/*.conf`` file. + * + * Displays parsed fields grouped into collapsible sections: + * - Includes (before / after) + * - Lifecycle commands (actionstart, actionstop, actioncheck, actionban, + * actionunban, actionflush) + * - Definition variables (extra [Definition] key-value pairs) + * - Init variables ([Init] section key-value pairs) + * + * Provides a Save button and shows saving/error state. + */ + +import { useEffect, useMemo, useState } from "react"; +import { + Accordion, + AccordionHeader, + AccordionItem, + AccordionPanel, + Button, + Field, + Input, + MessageBar, + MessageBarBody, + Skeleton, + SkeletonItem, + Text, + Textarea, +} from "@fluentui/react-components"; +import { Add24Regular, Delete24Regular } from "@fluentui/react-icons"; +import type { ActionConfig, ActionConfigUpdate } from "../../types/config"; +import { useActionConfig } from "../../hooks/useActionConfig"; +import { useAutoSave } from "../../hooks/useAutoSave"; +import { AutoSaveIndicator } from "./AutoSaveIndicator"; +import { useConfigStyles } from "./configStyles"; + +// --------------------------------------------------------------------------- +// Internal helpers +// --------------------------------------------------------------------------- + +/** Editable key-value table for definition_vars / init_vars. */ +interface KVEditorProps { + entries: Record; + onChange: (next: Record) => void; +} + +function KVEditor({ entries, onChange }: KVEditorProps): React.JSX.Element { + const styles = useConfigStyles(); + const rows = Object.entries(entries); + + const handleKeyChange = (oldKey: string, newKey: string): void => { + const next: Record = {}; + for (const [k, v] of Object.entries(entries)) { + next[k === oldKey ? newKey : k] = v; + } + onChange(next); + }; + + const handleValueChange = (key: string, value: string): void => { + onChange({ ...entries, [key]: value }); + }; + + const handleDelete = (key: string): void => { + const { [key]: _removed, ...rest } = entries; + onChange(rest); + }; + + const handleAdd = (): void => { + let newKey = "new_var"; + let n = 1; + while (newKey in entries) { + newKey = `new_var_${String(n)}`; + n++; + } + onChange({ ...entries, [newKey]: "" }); + }; + + return ( +
+ {rows.map(([key, value]) => ( +
+ { handleKeyChange(key, d.value); }} + /> +