import { useCallback, useMemo, useState, type ChangeEvent } from "react"; import { Checkbox, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@arronqzy/ui"; import type { ExecutionTraceEntry, StorageKind, StorageReadConfig, StorageSetConfig, } from "@arronqzy/blueprint-dsl"; import { latestTraceOutputsByNode, resolveFetchIncomingScope, resolveFetchScopeAutocompleteRoot, uniqueStorageKinds, } from "@arronqzy/blueprint-dsl"; import { useI18n } from "@arronqzy/i18n/react"; import type { BlueprintGraphEdge, BlueprintGraphNode } from "../graph/document"; import { resolveNodeStorageConfig } from "../graph/document"; import { ConfigFieldLabel, ConfigSectionTitle } from "./ConfigHintIcon"; import { ScopeTemplateAutocompleteHost } from "./ScopeTemplateAutocompleteHost"; export type StorageNodeConfigPanelProps = { node: BlueprintGraphNode; graphNodes?: BlueprintGraphNode[]; graphEdges?: BlueprintGraphEdge[]; traceEntries?: ExecutionTraceEntry[]; onUpdateNode: ( nodeId: string, patch: Partial> ) => void; }; function patchStorageConfig( node: BlueprintGraphNode, patch: { read?: Partial; set?: Partial; } ) { const current = resolveNodeStorageConfig(node); return { storageConfig: { read: { ...current.read, ...patch.read }, set: { ...current.set, ...patch.set }, }, configSource: "storage" as const, }; } export function StorageNodeConfigPanel({ node, graphNodes = [], graphEdges = [], traceEntries = [], onUpdateNode, }: StorageNodeConfigPanelProps) { const { t } = useI18n(); const [formEl, setFormEl] = useState(null); const storageConfig = resolveNodeStorageConfig(node); const incomingScope = useMemo(() => { const outputs = latestTraceOutputsByNode(traceEntries); return resolveFetchIncomingScope({ fetchNodeId: node.id, nodes: graphNodes, edges: graphEdges, getOutput: (sourceId, port) => outputs[sourceId]?.[port], }); }, [graphEdges, graphNodes, node.id, traceEntries]); const autocompleteScope = resolveFetchScopeAutocompleteRoot(incomingScope); const handleReadStorageChange = useCallback( (value: string) => { onUpdateNode( node.id, patchStorageConfig(node, { read: { storage: value === "session" ? "session" : "local" }, }) ); }, [node, onUpdateNode] ); const handleReadKeyChange = useCallback( (e: ChangeEvent) => { onUpdateNode( node.id, patchStorageConfig(node, { read: { key: e.target.value } }) ); }, [node, onUpdateNode] ); const handleSetStorageToggle = useCallback( (kind: StorageKind, checked: boolean) => { const next = new Set(storageConfig.set.storages); if (checked) next.add(kind); else next.delete(kind); onUpdateNode( node.id, patchStorageConfig(node, { set: { storages: uniqueStorageKinds([...next]) }, }) ); }, [node, onUpdateNode, storageConfig.set.storages] ); const handleSetKeyChange = useCallback( (e: ChangeEvent) => { onUpdateNode( node.id, patchStorageConfig(node, { set: { key: e.target.value } }) ); }, [node, onUpdateNode] ); const handleSetValueChange = useCallback( (e: ChangeEvent) => { onUpdateNode( node.id, patchStorageConfig(node, { set: { value: e.target.value } }) ); }, [node, onUpdateNode] ); return (
{(["session", "local"] as const).map((kind) => { const checked = storageConfig.set.storages.includes(kind); return ( ); })}
); }