import { Suspense } from "react"; import { useTranslation } from "react-i18next"; import { Loader } from "@mantine/core"; import { ToggleSwitch } from "@shared/components/ToggleSwitch"; import { Card } from "@shared/components/Card"; import LocalIcon from "@app/components/shared/LocalIcon"; import { Tooltip as AppTooltip } from "@app/components/shared/Tooltip"; import { PolicyRedactConfig } from "@app/components/policies/PolicyRedactConfig"; import { PolicyWatermarkConfig } from "@app/components/policies/PolicyWatermarkConfig"; import type { ToolRegistry } from "@app/data/toolsTaxonomy"; import type { ToolId } from "@app/types/toolId"; /** * Plain-language, non-technical descriptions shown by each tool's info button. * Stored as [i18n key, English default] pairs so they can be resolved with `t` * at render (the map lives at module scope, outside the component). */ const TOOL_PLAIN_INFO: Record = { redact: [ "policies.toolConfig.info.redact", "Automatically finds and blacks out sensitive details — like Social Security and card numbers — so they can't be read in the document.", ], sanitize: [ "policies.toolConfig.info.sanitize", "Removes hidden JavaScript from the file, so nothing can run automatically when someone opens it.", ], watermark: [ "policies.toolConfig.info.watermark", "Stamps a visible mark (e.g. “Confidential”) across every page.", ], }; /** One tool in a policy's fixed chain: whether it runs + its configured params. */ export interface PolicyToolState { /** Frontend tool-registry id (also the registry key + the thing we map to an endpoint). */ operation: string; /** Whether this tool runs as part of the policy (the per-tool on/off). */ enabled: boolean; /** Tool-specific parameters (the shape its endpoint accepts). */ parameters: Record; } interface PolicyToolConfigProps { /** The policy's fixed tool chain — locked (no add/remove), only configurable. */ tools: PolicyToolState[]; toolRegistry: Partial; onChange: (tools: PolicyToolState[]) => void; /** Read-only when the policy is managed / the user can't configure. */ editable?: boolean; } /** * Locked, configure-only tool panel for a policy. The chain is fixed (you can't * add or remove tools); each tool is a section that renders its OWN settings form * from the tool registry (`automationSettings`) — the same forms the automation * builder uses — so the config is generated from the tools in the workflow, not * hardcoded per policy. The parameters produced here are exactly what the backend * engine POSTs to each tool's endpoint. */ export function PolicyToolConfig({ tools, toolRegistry, onChange, editable = true, }: PolicyToolConfigProps) { const { t } = useTranslation(); const patchTool = (index: number, patch: Partial) => onChange(tools.map((t, i) => (i === index ? { ...t, ...patch } : t))); return (
{tools.map((tool, index) => { const entry = toolRegistry[tool.operation as ToolId]; const Settings = entry?.automationSettings ?? null; const toolName = entry?.name ?? tool.operation; const plainInfo = TOOL_PLAIN_INFO[tool.operation]; return (
{entry?.icon} {toolName} {plainInfo && ( )} patchTool(index, { enabled: checked })} aria-label={t("policies.toolConfig.enableAriaLabel", "Enable {{tool}}", { tool: toolName, })} />
{tool.enabled && (tool.operation === "redact" ? (
patchTool(index, { parameters })} disabled={!editable} />
) : tool.operation === "sanitize" ? ( // Sanitize is config-less: it only removes JavaScript (params // are fixed in the policy preset), so no settings are shown. <> ) : tool.operation === "watermark" ? ( // Watermark settings with flatten hidden + forced on (see // PolicyWatermarkConfig).
patchTool(index, { parameters })} disabled={!editable} />
) : Settings ? (
}> patchTool(index, { parameters: { ...tool.parameters, [key]: value }, }) } disabled={!editable} />
) : null)}
); })}
); }