"use client" import { useState, type PointerEvent as ReactPointerEvent } from "react" import { XIcon } from "lucide-react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import type { AIWorkflowDefinition, AIWorkflowNodeSpec } from "@/lib/api/admin" import type { SelectedWorkflowBranch } from "./workflow-branch-selection" import { ConditionBranchConfigPanel, NodeConfigPanel } from "./node-config-panel" import { WorkflowNodeIcon } from "./workflow-node-icon" import { getAvailableVariables, normalizeNodeConfig, type WorkflowNodeData, } from "./workflow-utils" const PANEL_DEFAULT_WIDTH = 380 const PANEL_MIN_WIDTH = 320 const PANEL_MAX_WIDTH = 560 export function WorkflowConfigPanel({ definition, nodeSpecs, selectedNodeId, selectedBranch, onClose, onSelectBranch, onChangeNodeData, onDeleteNode, }: { definition: AIWorkflowDefinition nodeSpecs: AIWorkflowNodeSpec[] selectedNodeId: string selectedBranch: SelectedWorkflowBranch | null onClose: () => void onSelectBranch: (branch: SelectedWorkflowBranch | null) => void onChangeNodeData: (nodeId: string, data: WorkflowNodeData) => void onDeleteNode: (nodeId: string) => void }) { const [panelWidth, setPanelWidth] = useState(PANEL_DEFAULT_WIDTH) const selectedNode = definition.nodes.find((node) => node.id === selectedNodeId) ?? null const selectedNodeSpec = selectedNode ? nodeSpecs.find((spec) => spec.type === selectedNode.type) : undefined const availableVariables = selectedNode ? getAvailableVariables(definition, selectedNode.id, nodeSpecs) : [] const selectedBranchItem = selectedNode && selectedBranch?.nodeId === selectedNode.id ? normalizeNodeConfig(selectedNode.data?.config).branches?.find((branch) => branch.id === selectedBranch.branchId) ?? null : null const panelTitle = selectedBranchItem ? selectedBranchItem.name || selectedBranchItem.id : selectedNode?.data?.title || selectedNodeSpec?.title || selectedNode?.type || "" const panelMeta = selectedBranchItem ? "条件分支" : selectedNode?.type || "" const panelDescription = selectedBranchItem ? "" : selectedNodeSpec?.description || "" const panelIcon = selectedBranchItem ? "GitBranchIcon" : selectedNodeSpec?.icon if (!selectedNode) { return null } const deleteSelectedBranch = (branchId: string) => { const config = normalizeNodeConfig(selectedNode.data?.config) onChangeNodeData(selectedNode.id, { ...(selectedNode.data ?? {}), config: { ...config, branches: (config.branches ?? []).filter((branch) => branch.id !== branchId), }, }) onSelectBranch(null) } const updatePanelTitle = (title: string) => { if (selectedBranchItem && selectedBranch) { const config = normalizeNodeConfig(selectedNode.data?.config) onChangeNodeData(selectedNode.id, { ...(selectedNode.data ?? {}), config: { ...config, branches: (config.branches ?? []).map((branch) => ( branch.id === selectedBranch.branchId ? { ...branch, name: title } : branch )), }, }) return } onChangeNodeData(selectedNode.id, { ...(selectedNode.data ?? {}), title, }) } const startResize = (event: ReactPointerEvent) => { event.preventDefault() const startX = event.clientX const startWidth = panelWidth const maxWidth = Math.max(PANEL_MIN_WIDTH, Math.min(PANEL_MAX_WIDTH, window.innerWidth - 320)) const resize = (moveEvent: PointerEvent) => { const nextWidth = startWidth + startX - moveEvent.clientX setPanelWidth(Math.min(Math.max(nextWidth, PANEL_MIN_WIDTH), maxWidth)) } const stopResize = () => { window.removeEventListener("pointermove", resize) window.removeEventListener("pointerup", stopResize) } window.addEventListener("pointermove", resize) window.addEventListener("pointerup", stopResize) } return (
updatePanelTitle(event.target.value)} />
{panelDescription ? (
{panelDescription}
) : null}
{panelMeta ? (
{panelMeta}
) : null}
{selectedBranchItem && selectedBranch ? ( ) : ( )}
) }