@rytass/bpm-core-react 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/chunks/compose-DYmvSyVR.cjs +2 -0
  3. package/dist/chunks/compose-DYmvSyVR.cjs.map +1 -0
  4. package/dist/chunks/{compose-PMrmi-LE.js → compose-Dmp3vP-j.js} +50 -46
  5. package/dist/chunks/compose-Dmp3vP-j.js.map +1 -0
  6. package/dist/chunks/designer-CEw0v0sY.cjs +65 -0
  7. package/dist/chunks/designer-CEw0v0sY.cjs.map +1 -0
  8. package/dist/chunks/{designer-mOMxJ0Py.js → designer-yYAdrQDt.js} +19 -2
  9. package/dist/chunks/designer-yYAdrQDt.js.map +1 -0
  10. package/dist/chunks/orgs-BbniWPB_.cjs +2 -0
  11. package/dist/chunks/orgs-BbniWPB_.cjs.map +1 -0
  12. package/dist/chunks/{orgs-Cc18umVt.js → orgs-BywlqXaG.js} +341 -331
  13. package/dist/chunks/orgs-BywlqXaG.js.map +1 -0
  14. package/dist/pages/admin/orgs/index.cjs +1 -1
  15. package/dist/pages/admin/orgs/index.js +1 -1
  16. package/dist/pages/templates/compose/index.cjs +1 -1
  17. package/dist/pages/templates/compose/index.cjs.map +1 -1
  18. package/dist/pages/templates/compose/index.d.ts +13 -1
  19. package/dist/pages/templates/compose/index.js +9 -5
  20. package/dist/pages/templates/compose/index.js.map +1 -1
  21. package/dist/pages/templates/designer/index.cjs +1 -1
  22. package/dist/pages/templates/designer/index.js +1 -1
  23. package/dist/views/admin/index.cjs +1 -1
  24. package/dist/views/admin/index.js +1 -1
  25. package/dist/views/admin/orgs/index.cjs +1 -1
  26. package/dist/views/admin/orgs/index.js +1 -1
  27. package/dist/views/templates/compose/TemplateComposeWizardView.d.ts +13 -1
  28. package/dist/views/templates/compose/index.cjs +1 -1
  29. package/dist/views/templates/compose/index.js +1 -1
  30. package/dist/views/templates/compose/steps/ComposeWorkflowStep.d.ts +12 -1
  31. package/dist/views/templates/designer/TemplateDesignerView.d.ts +4 -2
  32. package/dist/views/templates/designer/index.cjs +1 -1
  33. package/dist/views/templates/designer/index.js +1 -1
  34. package/package.json +3 -3
  35. package/dist/chunks/compose-PMrmi-LE.js.map +0 -1
  36. package/dist/chunks/compose-ziVbRYdo.cjs +0 -2
  37. package/dist/chunks/compose-ziVbRYdo.cjs.map +0 -1
  38. package/dist/chunks/designer-DCn6_v4b.cjs +0 -65
  39. package/dist/chunks/designer-DCn6_v4b.cjs.map +0 -1
  40. package/dist/chunks/designer-mOMxJ0Py.js.map +0 -1
  41. package/dist/chunks/orgs-BIiqzHvb.cjs +0 -2
  42. package/dist/chunks/orgs-BIiqzHvb.cjs.map +0 -1
  43. package/dist/chunks/orgs-Cc18umVt.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"designer-yYAdrQDt.js","names":[],"sources":["../../src/views/templates/designer/use-workflow-designer-controller.ts","../../src/views/templates/designer/use-workflow-chat.ts","../../src/views/templates/designer/chrome-workflow-chat.ts","../../src/views/templates/designer/workflow-chat-drawer.tsx","../../src/views/templates/designer/TemplateDesignerView.tsx"],"sourcesContent":["import { useCallback, useMemo, useRef, useState } from 'react';\nimport {\n WorkflowCommand,\n WorkflowCommandResult,\n WorkflowDesignerState,\n WorkflowMacroCommand,\n WorkflowDirectory,\n WorkflowSnapshot,\n WORKFLOW_TOOLSET,\n WorkflowTool,\n WorkflowToolResult,\n applyWorkflowCommand,\n applyWorkflowMacroCommand,\n executeWorkflowTool,\n readWorkflowSnapshot,\n} from '@rytass/bpm-core-shared';\nimport { WorkflowDefinition } from '@rytass/bpm-core-shared/workflow';\n\n/**\n * Bridges the pure, framework-agnostic workflow command layer\n * (`@rytass/bpm-core-shared`) to React. It owns the {@link WorkflowDesignerState}\n * and is the single dispatch path through which both the designer UI and the\n * LLM assistant mutate the workflow — guaranteeing the assistant can do exactly\n * what a user can.\n *\n * The pure reducer only describes logical structure; this hook injects the\n * pixel concern: whenever a command reports `effects.layout`, the supplied\n * `layout` function (dagre) recomputes node positions, and `onLayout` is invoked\n * so the host can refit the viewport.\n */\nexport interface UseWorkflowDesignerControllerOptions {\n readonly initialState: WorkflowDesignerState;\n /** Recompute node pixel positions (dagre) — runs after topology changes. */\n readonly layout: (definition: WorkflowDefinition) => WorkflowDefinition;\n /** Notified with the laid-out definition so the host can refit the viewport. */\n readonly onLayout?: (definition: WorkflowDefinition) => void;\n /** Org directory backing the LLM's member/org lookup query tools. */\n readonly directory?: WorkflowDirectory;\n}\n\nexport interface WorkflowDesignerController {\n readonly state: WorkflowDesignerState;\n readonly snapshot: WorkflowSnapshot;\n /** The advertised LLM tool catalog (JSON Schema input contracts). */\n readonly tools: readonly WorkflowTool[];\n /** Dispatch a single primitive command. */\n readonly dispatch: (command: WorkflowCommand) => WorkflowCommandResult;\n /** Dispatch a high-level macro command. */\n readonly dispatchMacro: (\n command: WorkflowMacroCommand,\n ) => WorkflowCommandResult;\n /** Execute an LLM tool call by name; mutations commit + relayout. Async\n * because directory query tools may fetch from the host. */\n readonly executeTool: (\n toolName: string,\n input: unknown,\n ) => Promise<WorkflowToolResult>;\n /** Replace the whole state (e.g. after loading a draft from the server). */\n readonly replaceState: (\n next:\n | WorkflowDesignerState\n | ((current: WorkflowDesignerState) => WorkflowDesignerState),\n ) => void;\n /** Imperatively read the latest committed state (avoids stale closures). */\n readonly getState: () => WorkflowDesignerState;\n}\n\nexport function useWorkflowDesignerController({\n directory,\n initialState,\n layout,\n onLayout,\n}: UseWorkflowDesignerControllerOptions): WorkflowDesignerController {\n const [state, setState] = useState<WorkflowDesignerState>(initialState);\n // Mirror state in a ref so dispatch reads the freshest value even when called\n // multiple times within one React batch (e.g. a macro fold by the UI).\n const stateRef = useRef<WorkflowDesignerState>(initialState);\n // Latest directory, read at tool-call time (avoids re-creating executeTool).\n const directoryRef = useRef<WorkflowDirectory | undefined>(directory);\n directoryRef.current = directory;\n\n const commit = useCallback(\n (result: WorkflowCommandResult): WorkflowCommandResult => {\n if (!result.changed && !result.error) {\n return result;\n }\n\n const committedDefinition = result.effects.layout\n ? layout(result.state.definition)\n : result.state.definition;\n const committedState: WorkflowDesignerState = {\n ...result.state,\n definition: committedDefinition,\n };\n\n stateRef.current = committedState;\n setState(committedState);\n\n if (result.effects.layout) {\n onLayout?.(committedDefinition);\n }\n\n return { ...result, state: committedState };\n },\n [layout, onLayout],\n );\n\n const dispatch = useCallback(\n (command: WorkflowCommand): WorkflowCommandResult =>\n commit(applyWorkflowCommand(stateRef.current, command)),\n [commit],\n );\n\n const dispatchMacro = useCallback(\n (command: WorkflowMacroCommand): WorkflowCommandResult =>\n commit(applyWorkflowMacroCommand(stateRef.current, command)),\n [commit],\n );\n\n const executeTool = useCallback(\n async (toolName: string, input: unknown): Promise<WorkflowToolResult> => {\n const result = await executeWorkflowTool(\n stateRef.current,\n toolName,\n input,\n { directory: directoryRef.current },\n );\n\n if (result.ok && (result.kind === 'mutation' || result.kind === 'macro')) {\n const committed = commit(result.result);\n\n return {\n ...result,\n result: committed,\n snapshot: readWorkflowSnapshot(committed.state),\n };\n }\n\n return result;\n },\n [commit],\n );\n\n const replaceState = useCallback(\n (\n next:\n | WorkflowDesignerState\n | ((current: WorkflowDesignerState) => WorkflowDesignerState),\n ): void => {\n const resolved =\n typeof next === 'function' ? next(stateRef.current) : next;\n\n stateRef.current = resolved;\n setState(resolved);\n },\n [],\n );\n\n const getState = useCallback((): WorkflowDesignerState => stateRef.current, []);\n\n const snapshot = useMemo((): WorkflowSnapshot => readWorkflowSnapshot(state), [\n state,\n ]);\n\n return useMemo(\n (): WorkflowDesignerController => ({\n dispatch,\n dispatchMacro,\n executeTool,\n getState,\n replaceState,\n snapshot,\n state,\n tools: WORKFLOW_TOOLSET,\n }),\n [\n dispatch,\n dispatchMacro,\n executeTool,\n getState,\n replaceState,\n snapshot,\n state,\n ],\n );\n}\n","'use client';\n\nimport { useMemo } from 'react';\nimport { useChat, type UseChatHelpers } from '@ai-sdk/react';\nimport {\n DefaultChatTransport,\n lastAssistantMessageIsCompleteWithToolCalls,\n type UIMessage,\n} from 'ai';\nimport type { WorkflowDesignerController } from './use-workflow-designer-controller';\n\n/**\n * Connects the workflow designer chat UI to the LLM.\n *\n * The server route (`@rytass/bpm-core-react/next/workflow-chat-route`) advertises\n * the workflow tools with no `execute`, so every tool call is forwarded here.\n * `onToolCall` runs it against the same {@link WorkflowDesignerController} the UI\n * uses — so the assistant draws on the canvas exactly as a user would — and feeds\n * the resulting snapshot back to the model, forming the observe→act loop.\n *\n * All tools are dynamic on the client (their names are not statically wired into\n * `useChat`), so we handle (not skip) `toolCall.dynamic`.\n */\nexport interface UseWorkflowChatOptions {\n readonly controller: WorkflowDesignerController;\n /** Chat API route. Defaults to same-origin `/api/chat`. */\n readonly api?: string;\n}\n\nexport function useWorkflowChat({\n controller,\n api = '/api/chat',\n}: UseWorkflowChatOptions): UseChatHelpers<UIMessage> {\n const transport = useMemo(\n (): DefaultChatTransport<UIMessage> =>\n new DefaultChatTransport<UIMessage>({ api }),\n [api],\n );\n\n const chat = useChat<UIMessage>({\n transport,\n sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,\n async onToolCall({ toolCall }): Promise<void> {\n const result = await controller.executeTool(\n toolCall.toolName,\n toolCall.input,\n );\n\n if (result.ok) {\n chat.addToolOutput({\n output: result.kind === 'query' ? result.data : result.snapshot,\n tool: toolCall.toolName,\n toolCallId: toolCall.toolCallId,\n });\n\n return;\n }\n\n chat.addToolOutput({\n errorText: result.error,\n state: 'output-error',\n tool: toolCall.toolName,\n toolCallId: toolCall.toolCallId,\n });\n },\n });\n\n return chat;\n}\n","'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { UIMessage } from 'ai';\nimport { WORKFLOW_TOOLSET } from '@rytass/bpm-core-shared';\nimport type { WorkflowDesignerController } from './use-workflow-designer-controller';\n\n/**\n * EXPERIMENTAL offline fallback that drives the workflow toolset with Chrome's\n * built-in on-device model (Prompt API / `LanguageModel`, Gemini Nano).\n *\n * The Prompt API has **no native tool-calling**, so this runs a hand-written\n * observe→act loop: each step the model is constrained (JSON Schema) to emit a\n * single decision — call a tool (name + input) or reply with a message. Tool\n * calls run against the same {@link WorkflowDesignerController} the UI and the\n * online assistant use; the resulting snapshot is fed back for the next step.\n *\n * This path is capability-gated: when `available` is false the UI hides offline\n * mode entirely, so unsupported browsers never see it. It cannot be verified in\n * CI (needs a flag-enabled Chrome + downloaded model).\n */\n\nconst MAX_STEPS = 12;\n\ntype ChromeAvailability =\n | 'unavailable'\n | 'downloadable'\n | 'downloading'\n | 'available';\n\ninterface ChromeLanguageModelSession {\n prompt(\n input: string,\n options?: { readonly responseConstraint?: unknown },\n ): Promise<string>;\n destroy(): void;\n}\n\ninterface ChromeLanguageModelStatic {\n availability(): Promise<ChromeAvailability>;\n create(options?: {\n readonly initialPrompts?: readonly {\n readonly role: 'system' | 'user' | 'assistant';\n readonly content: string;\n }[];\n }): Promise<ChromeLanguageModelSession>;\n}\n\nfunction readChromeLanguageModel(): ChromeLanguageModelStatic | null {\n const candidate = (globalThis as { readonly LanguageModel?: unknown })\n .LanguageModel;\n\n return candidate && typeof candidate === 'object'\n ? (candidate as ChromeLanguageModelStatic)\n : null;\n}\n\n/** One structured decision per loop step (enforced via responseConstraint). */\ninterface ChromeStepDecision {\n readonly action: 'tool' | 'message';\n readonly tool?: string;\n readonly input?: Readonly<Record<string, unknown>>;\n readonly text?: string;\n}\n\nconst DECISION_SCHEMA = {\n additionalProperties: false,\n properties: {\n action: { enum: ['tool', 'message'], type: 'string' },\n input: { type: 'object' },\n text: { type: 'string' },\n tool: { type: 'string' },\n },\n required: ['action'],\n type: 'object',\n} as const;\n\nfunction readOfflineSystemPrompt(): string {\n const toolLines = WORKFLOW_TOOLSET.map(\n (tool) =>\n `- ${tool.name}(${JSON.stringify(\n (tool.inputSchema as { readonly properties?: unknown }).properties ?? {},\n )}): ${tool.description}`,\n ).join('\\n');\n\n return `你是「簽核流程設計器」頁面的離線 AI 助理。只能透過下列工具操作這個流程畫布,其他請求一律婉拒並引導回流程設計。\n\n每一步只輸出一個 JSON 決策物件:\n- 呼叫工具:{\"action\":\"tool\",\"tool\":\"<工具名>\",\"input\":{...}}\n- 回覆使用者(完成或詢問):{\"action\":\"message\",\"text\":\"<繁體中文訊息>\"}\n\n規則:先用 get_workflow_snapshot 了解現況再規劃;完成後用 validate_workflow 檢查並以 message 說明做了什麼。\n\n可用工具:\n${toolLines}`;\n}\n\nexport interface UseChromeWorkflowChatResult {\n /** True only when the on-device model is usable in this browser. */\n readonly available: boolean;\n readonly messages: readonly UIMessage[];\n readonly status: 'ready' | 'submitted' | 'streaming' | 'error';\n readonly send: (text: string) => void;\n}\n\nexport function useChromeWorkflowChat({\n controller,\n}: {\n readonly controller: WorkflowDesignerController;\n}): UseChromeWorkflowChatResult {\n const [available, setAvailable] = useState(false);\n const [messages, setMessages] = useState<readonly UIMessage[]>([]);\n const [status, setStatus] =\n useState<UseChromeWorkflowChatResult['status']>('ready');\n const idRef = useRef(0);\n\n useEffect((): void => {\n const model = readChromeLanguageModel();\n\n if (!model) {\n return;\n }\n\n void model\n .availability()\n .then((availability): void => {\n setAvailable(availability !== 'unavailable');\n })\n .catch((): void => setAvailable(false));\n }, []);\n\n const appendMessage = useCallback(\n (role: UIMessage['role'], text: string): void => {\n idRef.current += 1;\n setMessages((current) => [\n ...current,\n {\n id: `chrome-${idRef.current}`,\n parts: [{ text, type: 'text' }],\n role,\n } as UIMessage,\n ]);\n },\n [],\n );\n\n const send = useCallback(\n (text: string): void => {\n const model = readChromeLanguageModel();\n\n if (!model || status !== 'ready') {\n return;\n }\n\n appendMessage('user', text);\n setStatus('submitted');\n\n void runOfflineLoop({\n appendMessage,\n controller,\n model,\n userText: text,\n })\n .then((): void => setStatus('ready'))\n .catch((error: unknown): void => {\n appendMessage('assistant', readErrorMessage(error));\n setStatus('error');\n });\n },\n [appendMessage, controller, status],\n );\n\n return { available, messages, send, status };\n}\n\nasync function runOfflineLoop({\n appendMessage,\n controller,\n model,\n userText,\n}: {\n readonly appendMessage: (role: UIMessage['role'], text: string) => void;\n readonly controller: WorkflowDesignerController;\n readonly model: ChromeLanguageModelStatic;\n readonly userText: string;\n}): Promise<void> {\n const session = await model.create({\n initialPrompts: [{ content: readOfflineSystemPrompt(), role: 'system' }],\n });\n\n try {\n let nextPrompt = `使用者需求:${userText}\\n目前流程:${JSON.stringify(\n controller.snapshot,\n )}`;\n\n for (let step = 0; step < MAX_STEPS; step += 1) {\n const raw = await session.prompt(nextPrompt, {\n responseConstraint: DECISION_SCHEMA,\n });\n const decision = parseDecision(raw);\n\n if (!decision || decision.action === 'message') {\n appendMessage(\n 'assistant',\n decision?.text ?? '我已完成可處理的部分。',\n );\n\n return;\n }\n\n if (!decision.tool) {\n appendMessage('assistant', '我已完成可處理的部分。');\n\n return;\n }\n\n const result = await controller.executeTool(\n decision.tool,\n decision.input ?? {},\n );\n\n if (result.ok) {\n const observation =\n result.kind === 'query' ? result.data : result.snapshot;\n\n appendMessage('assistant', `⚙ ${decision.tool}`);\n nextPrompt = `工具 ${decision.tool} 已執行。最新流程:${JSON.stringify(\n observation,\n )}\\n請決定下一步。`;\n } else {\n nextPrompt = `工具 ${decision.tool} 失敗:${result.error}\\n請改用其他方式或回覆使用者。`;\n }\n }\n\n appendMessage('assistant', '已達到單次操作步數上限,請告訴我下一步。');\n } finally {\n session.destroy();\n }\n}\n\nfunction parseDecision(raw: string): ChromeStepDecision | null {\n try {\n const value: unknown = JSON.parse(raw);\n\n if (\n typeof value === 'object' &&\n value !== null &&\n (value as { action?: unknown }).action !== undefined\n ) {\n return value as ChromeStepDecision;\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error\n ? `離線模式發生錯誤:${error.message}`\n : '離線模式發生未知錯誤。';\n}\n","'use client';\n\nimport {\n Fragment,\n useCallback,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport Drawer from '@mezzanine-ui/react/Drawer';\nimport { Button, Textarea, Typography } from '@mezzanine-ui/react';\nimport { getToolName, isToolUIPart, type UIMessage } from 'ai';\nimport type { WorkflowDesignerController } from './use-workflow-designer-controller';\nimport { useWorkflowChat } from './use-workflow-chat';\nimport { useChromeWorkflowChat } from './chrome-workflow-chat';\n\ntype ChatMode = 'online' | 'offline';\n\ninterface ActiveChat {\n readonly messages: readonly UIMessage[];\n readonly status: 'ready' | 'submitted' | 'streaming' | 'error';\n readonly send: (text: string) => void;\n}\n\n/**\n * Right-side AI assistant drawer for the workflow designer. Users describe the\n * flow in natural language; the assistant draws it on the canvas by driving the\n * shared workflow toolset through {@link useWorkflowChat}. The layout (canvas +\n * 420px panel) is untouched — this slides over it.\n */\nexport interface WorkflowChatDrawerProps {\n readonly controller: WorkflowDesignerController;\n readonly open: boolean;\n readonly onClose: () => void;\n /** Chat API route. Defaults to same-origin `/api/chat`. */\n readonly api?: string;\n}\n\nconst BODY_STYLE: CSSProperties = {\n // No own padding — rely on Mezzanine's `mzn-drawer__content` native padding.\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n height: '100%',\n};\n\nconst MESSAGE_LIST_STYLE: CSSProperties = {\n display: 'flex',\n flex: 1,\n flexDirection: 'column',\n gap: 12,\n minHeight: 0,\n overflowY: 'auto',\n};\n\nconst MODE_ROW_STYLE: CSSProperties = {\n display: 'flex',\n gap: 8,\n paddingBottom: 4,\n};\n\nconst INPUT_ROW_STYLE: CSSProperties = {\n borderTop: '1px solid var(--mzn-color-border-neutral, #e5e7eb)',\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n paddingTop: 12,\n};\n\nconst SEND_ROW_STYLE: CSSProperties = {\n display: 'flex',\n justifyContent: 'flex-end',\n};\n\nconst TEXTAREA_STYLE: CSSProperties = {\n width: '100%',\n};\n\n// Mezzanine's `fullWidth` isn't reachable through `Textarea`'s props and its\n// modifier CSS isn't bundled here, so stretch the TextField host to full width\n// with one scoped rule (compound selector beats the base `.mzn-text-field`).\nconst CHAT_INPUT_CLASS_NAME = 'workflow-chat-input-field';\nconst CHAT_INPUT_GLOBAL_STYLE = `\n.${CHAT_INPUT_CLASS_NAME}.mzn-text-field {\n width: 100%;\n}\n`;\n\nconst TOOL_LINE_STYLE: CSSProperties = {\n color: 'var(--mzn-color-text-secondary, #6b7280)',\n fontSize: 12,\n padding: '2px 0',\n};\n\nconst TOOL_STATE_LABEL: Readonly<Record<string, string>> = {\n 'input-available': '執行中…',\n 'input-streaming': '準備中…',\n 'output-available': '完成',\n 'output-error': '失敗',\n};\n\nfunction readBubbleStyle(role: UIMessage['role']): CSSProperties {\n const isUser = role === 'user';\n\n return {\n alignSelf: isUser ? 'flex-end' : 'flex-start',\n background: isUser\n ? 'var(--mzn-color-primary, #2563eb)'\n : 'var(--mzn-color-surface, #f3f4f6)',\n borderRadius: 10,\n color: isUser ? '#fff' : 'var(--mzn-color-text-primary, #111827)',\n maxWidth: '85%',\n padding: '8px 12px',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n };\n}\n\nexport function WorkflowChatDrawer({\n api,\n controller,\n onClose,\n open,\n}: WorkflowChatDrawerProps): ReactElement {\n const online = useWorkflowChat({ api, controller });\n const offline = useChromeWorkflowChat({ controller });\n const [mode, setMode] = useState<ChatMode>('online');\n const [input, setInput] = useState('');\n\n const active: ActiveChat =\n mode === 'offline'\n ? {\n messages: offline.messages,\n send: offline.send,\n status: offline.status,\n }\n : {\n messages: online.messages,\n send: (text): void => {\n void online.sendMessage({ text });\n },\n status: online.status,\n };\n const { messages, send } = active;\n const busy = active.status === 'submitted' || active.status === 'streaming';\n\n const handleSend = useCallback((): void => {\n const text = input.trim();\n\n if (!text || busy) {\n return;\n }\n\n setInput('');\n send(text);\n }, [busy, input, send]);\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLTextAreaElement>): void => {\n // Never submit while an IME is composing (e.g. Enter that confirms a\n // Chinese candidate). Shift+Enter falls through to insert a newline.\n if (event.nativeEvent.isComposing) {\n return;\n }\n\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n handleSend();\n }\n },\n [handleSend],\n );\n\n return (\n <Drawer\n headerTitle=\"AI 流程助理\"\n isHeaderDisplay\n onClose={onClose}\n open={open}\n size=\"medium\"\n >\n <style>{CHAT_INPUT_GLOBAL_STYLE}</style>\n <div style={BODY_STYLE}>\n {offline.available ? (\n <div style={MODE_ROW_STYLE}>\n <Button\n onClick={(): void => setMode('online')}\n variant={mode === 'online' ? 'base-primary' : 'base-tertiary'}\n >\n 線上\n </Button>\n <Button\n onClick={(): void => setMode('offline')}\n variant={mode === 'offline' ? 'base-primary' : 'base-tertiary'}\n >\n 離線(裝置內,實驗)\n </Button>\n </div>\n ) : null}\n <div role=\"log\" style={MESSAGE_LIST_STYLE}>\n {messages.length === 0 ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 用一句話描述你想要的流程,例如:「建立三關簽核:部門主管 → 經理 → 財務,金額大於十萬走財務複核」。我會直接在畫布上幫你繪製。\n </Typography>\n ) : null}\n {messages.map((message) => (\n <Fragment key={message.id}>\n {renderMessageParts(message)}\n </Fragment>\n ))}\n {busy ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 思考中…\n </Typography>\n ) : null}\n </div>\n <div style={INPUT_ROW_STYLE}>\n <Textarea\n className={CHAT_INPUT_CLASS_NAME}\n disabled={busy}\n maxLength={2000}\n onChange={(event): void => setInput(event.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"描述你想要的流程…(Enter 送出,Shift + Enter 換行)\"\n rows={3}\n style={TEXTAREA_STYLE}\n value={input}\n />\n <div style={SEND_ROW_STYLE}>\n <Button\n disabled={busy || input.trim().length === 0}\n loading={busy}\n onClick={handleSend}\n type=\"button\"\n variant=\"base-primary\"\n >\n 送出\n </Button>\n </div>\n </div>\n </div>\n </Drawer>\n );\n}\n\nfunction renderMessageParts(message: UIMessage): ReactNode {\n return message.parts.map((part, index): ReactNode => {\n if (part.type === 'text') {\n return (\n <div key={`${message.id}-${index}`} style={readBubbleStyle(message.role)}>\n {part.text}\n </div>\n );\n }\n\n if (part.type === 'dynamic-tool' || isToolUIPart(part)) {\n const toolName = getToolName(part);\n const stateLabel = TOOL_STATE_LABEL[part.state] ?? part.state;\n\n return (\n <div key={`${message.id}-${index}`} style={TOOL_LINE_STYLE}>\n {`⚙ ${toolName} · ${stateLabel}`}\n </div>\n );\n }\n\n return null;\n });\n}\n","'use client';\n\nimport {\n ChangeEvent,\n CSSProperties,\n MouseEvent as ReactMouseEvent,\n ReactElement,\n SetStateAction,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useRouterAdapter } from '../../../lib/router-adapter';\nimport type { WorkflowDirectory } from '@rytass/bpm-core-shared';\nimport { useWorkflowDesignerController } from './use-workflow-designer-controller';\nimport { WorkflowChatDrawer } from './workflow-chat-drawer';\nimport { FormBuilderView } from '../../forms/builder/FormBuilderView';\nimport { useBPMRoutes } from '../../../lib/routes-config';\nimport {\n Background,\n ControlButton,\n Controls,\n Edge,\n Handle,\n MiniMap,\n Node,\n NodeProps,\n NodeTypes,\n Panel,\n Position,\n ReactFlow,\n applyNodeChanges,\n Connection,\n ConnectionMode,\n getViewportForBounds,\n type Handle as FlowHandle,\n type Viewport,\n} from '@xyflow/react';\nimport * as dagre from 'dagre';\nimport {\n AutoComplete,\n Button,\n Icon,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Select,\n Textarea,\n Toggle,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport Drawer from '@mezzanine-ui/react/Drawer';\nimport {\n CheckedIcon,\n DotGridIcon,\n EyeIcon,\n FilterIcon,\n MailIcon,\n SaveIcon,\n TrashIcon,\n UserIcon,\n type IconDefinition,\n} from '@mezzanine-ui/icons';\nimport {\n FormDefinitionSchema,\n FormFieldDefinition,\n FormUiSchema,\n} from '@rytass/bpm-core-shared/form';\nimport {\n ApproverResolver,\n ApproverResolverFallback,\n ServiceAction,\n WorkflowDefinition,\n WorkflowEdge,\n WorkflowEdgeConditionOperator,\n WorkflowEdgeData,\n WorkflowNode,\n WorkflowNodeTriggerMode,\n ReturnResubmitStrategy,\n} from '@rytass/bpm-core-shared/workflow';\nimport { readFormBuilder } from '@rytass/bpm-core-client/form';\nimport {\n OrgUnitOption,\n OrgUnitPicker,\n PositionOption,\n PositionPicker,\n readOrgUnitOption,\n readPositionOption,\n} from '../../../components/admin-pickers';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport {\n OrgUnitRecord,\n MembershipRecord,\n PositionRecord,\n readOrganizationDashboard,\n} from '@rytass/bpm-core-client/organization';\nimport {\n ApprovalTemplateVersionRecord,\n WorkflowDryRunResultRecord,\n composeApprovalTemplateWithForm,\n dryRunApprovalWorkflow,\n forkApprovalTemplate,\n MemberProfileRecord,\n publishApprovalTemplateVersion,\n PublishedFormVersionOption,\n readTemplateDesigner,\n resolveMemberOptions,\n searchMemberOptions,\n searchPublishedFormVersionOptions,\n TemplateDesignerRecord,\n updateApprovalTemplateDraft,\n} from '@rytass/bpm-core-client/template';\n\ntype FlowNodeData = Readonly<{\n approverLines: readonly string[] | null;\n approverSummary: string | null;\n hasInput: boolean;\n hasOutput: boolean;\n initiatorPolicySummary: string | null;\n label: string;\n nodeKind: WorkflowNode['type'];\n}>;\ntype FlowNode = Node<FlowNodeData, WorkflowNode['type']>;\ntype FlowNodeHandle = Omit<FlowHandle, 'nodeId'>;\ntype FlowEdgeData = Readonly<WorkflowEdgeData>;\ntype FlowEdge = Edge<FlowEdgeData>;\ntype NodePaletteType = 'exclusiveGateway' | 'serviceTask' | 'userTask';\ntype FormVersionSelectOption = Readonly<{\n formDefinitionId: string;\n formName: string;\n id: string;\n name: string;\n schema: FormDefinitionSchema;\n}>;\ntype ConditionFieldOption = Readonly<{\n fieldType: FormFieldDefinition['type'];\n id: string;\n name: string;\n}>;\ntype ConditionOperatorOption = Readonly<{\n id: WorkflowEdgeConditionOperator;\n name: string;\n}>;\ntype ConditionValueOption = Readonly<{\n id: string;\n name: string;\n}>;\ntype MemberSelectOption = Readonly<{\n displayName: string;\n email: string;\n id: string;\n memberId: string;\n name: string;\n}>;\ntype InitiatorPolicyMode =\n | 'ALL'\n | 'CUSTOM'\n | 'NONE'\n | 'ORG_UNIT'\n | 'ORG_UNIT_POSITION';\ntype InitiatorPolicyDraft = Readonly<{\n includeDescendants?: boolean;\n mode: InitiatorPolicyMode;\n orgUnitId?: string;\n positionId?: string;\n value: string;\n}>;\ntype InitiatorPolicyModeOption = Readonly<{\n id: InitiatorPolicyMode;\n name: string;\n}>;\ntype ReturnResubmitStrategyOption = Readonly<{\n id: ReturnResubmitStrategy;\n name: string;\n}>;\ntype ApproverResolverMode = Extract<\n ApproverResolver['type'],\n | 'DIRECT'\n | 'ORG_MANAGER'\n | 'ORG_UNIT_MANAGER'\n | 'ORG_UNIT_MEMBER'\n | 'ORG_UNIT_POSITION'\n | 'POSITION'\n>;\ntype ApproverResolverModeOption = Readonly<{\n id: ApproverResolverMode;\n name: string;\n}>;\ntype ManagerLevelOption = Readonly<{\n id: string;\n name: string;\n value: number;\n}>;\ntype ApproverFallbackMode = 'DIRECT' | 'NONE';\ntype ApproverFallbackModeOption = Readonly<{\n id: ApproverFallbackMode;\n name: string;\n}>;\ntype WorkflowConnectionCandidate = Readonly<{\n source?: string | null;\n sourceHandle?: string | null;\n target?: string | null;\n targetHandle?: string | null;\n}>;\n\nconst WORKSPACE_STYLE: CSSProperties = {\n display: 'grid',\n gap: 16,\n};\n\nconst TWO_COLUMN_STYLE: CSSProperties = {\n alignItems: 'start',\n display: 'grid',\n gap: 16,\n gridTemplateColumns: 'minmax(0, 1fr) 420px',\n};\n\nconst FLOW_CANVAS_STYLE: CSSProperties = {\n border: '1px solid var(--mzn-color-border-neutral)',\n borderRadius: 6,\n height: 620,\n minWidth: 0,\n overflow: 'hidden',\n};\n\nconst SELECTION_DELETE_CONTROL_BUTTON_STYLE: CSSProperties = {\n alignItems: 'center',\n boxSizing: 'border-box',\n color: 'var(--mzn-color-text-error)',\n display: 'flex',\n height: 26,\n justifyContent: 'center',\n lineHeight: 0,\n padding: 0,\n width: 26,\n};\n\nconst SELECTION_DELETE_CONTROL_ICON_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'flex',\n height: '100%',\n justifyContent: 'center',\n width: '100%',\n};\n\nconst SIDE_PANEL_CLASS_NAME = 'workflow-designer-side-panel';\nconst SIDE_PANEL_FORM_LABEL_WIDTH = 96;\nconst SIDE_PANEL_GLOBAL_STYLE = `\n.${SIDE_PANEL_CLASS_NAME} .mzn-form-field--stretch .mzn-form-field__label-area,\n.${SIDE_PANEL_CLASS_NAME} .mzn-form-field--horizontal .mzn-form-field__label-area {\n flex: 0 0 ${SIDE_PANEL_FORM_LABEL_WIDTH}px;\n width: ${SIDE_PANEL_FORM_LABEL_WIDTH}px;\n}\n\n.${SIDE_PANEL_CLASS_NAME} .mzn-form-field--stretch .mzn-form-field__data-entry,\n.${SIDE_PANEL_CLASS_NAME} .mzn-form-field--horizontal .mzn-form-field__data-entry {\n min-width: 0;\n}\n`;\n\nconst CONDITION_EDGE_COLOR = '#2563eb';\nconst DEFAULT_EDGE_COLOR = '#64748b';\nconst INCOMPLETE_CONDITION_EDGE_COLOR = 'var(--mzn-color-text-error, #dc2626)';\nconst SELECTED_EDGE_GLOW_FILTER =\n 'drop-shadow(0 0 3px rgba(0, 87, 255, 0.85)) drop-shadow(0 0 9px rgba(0, 87, 255, 0.36))';\nconst FLOW_CANVAS_GLOBAL_STYLE = `\n.workflow-selection-delete-control.react-flow__controls-button {\n align-items: center !important;\n display: flex !important;\n height: 26px !important;\n justify-content: center !important;\n padding: 0 !important;\n width: 26px !important;\n}\n\n.workflow-selection-delete-control .mzn-icon {\n align-items: center;\n display: flex;\n justify-content: center;\n}\n\n.workflow-selection-delete-control .mzn-icon svg {\n height: 16px !important;\n max-height: none !important;\n max-width: none !important;\n width: 16px !important;\n}\n\n.workflow-edge--selected .react-flow__edge-path,\n.react-flow__edge-path.workflow-edge--selected {\n filter: ${SELECTED_EDGE_GLOW_FILTER};\n opacity: 1 !important;\n stroke: ${DEFAULT_EDGE_COLOR} !important;\n stroke-opacity: 1 !important;\n stroke-width: 1.5px !important;\n}\n\n.workflow-edge--selected {\n --xy-edge-stroke: ${DEFAULT_EDGE_COLOR};\n --xy-edge-stroke-selected: ${DEFAULT_EDGE_COLOR};\n --xy-edge-stroke-width: 1.5px;\n}\n\n`;\n\nconst PANEL_STYLE: CSSProperties = {\n display: 'grid',\n gap: 12,\n};\n\nconst FORM_STACK_STYLE: CSSProperties = {\n display: 'grid',\n gap: 12,\n};\n\nconst DRY_RUN_RESULT_STYLE: CSSProperties = {\n border: '1px solid var(--mzn-color-border-neutral)',\n borderRadius: 6,\n display: 'grid',\n gap: 8,\n maxHeight: 360,\n overflow: 'auto',\n padding: 12,\n};\n\nconst DRY_RUN_STEP_STYLE: CSSProperties = {\n borderBottom: '1px solid var(--mzn-color-border-neutral)',\n display: 'grid',\n gap: 4,\n padding: '0 0 8px',\n};\n\nconst BUTTON_ROW_STYLE: CSSProperties = {\n display: 'flex',\n flexWrap: 'wrap',\n gap: 8,\n};\n\n// Keep the form-version dropdown and the \"編輯表單\" button on a single line\n// (dropdown grows, button hugs the right) to save vertical space.\nconst FORM_BIND_ROW_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'flex',\n gap: 8,\n};\n\nconst FORM_BIND_FIELD_STYLE: CSSProperties = {\n flex: '1 1 auto',\n minWidth: 0,\n};\n\nconst FORM_BIND_BUTTON_STYLE: CSSProperties = {\n flex: '0 0 auto',\n};\n\nconst TOOL_GROUP_STYLE: CSSProperties = {\n display: 'grid',\n gap: 8,\n};\n\nconst NODE_STYLE: CSSProperties = {\n alignContent: 'center',\n background: 'var(--mzn-color-bg-surface)',\n border: '1px solid var(--mzn-color-border-neutral)',\n borderRadius: 6,\n boxShadow: '0 8px 20px rgba(15, 23, 42, 0.08)',\n boxSizing: 'border-box',\n display: 'grid',\n gap: 4,\n height: '100%',\n minWidth: 132,\n overflow: 'visible',\n padding: '10px 12px',\n textAlign: 'center',\n width: '100%',\n};\nconst SELECTED_NODE_BOX_SHADOW =\n '0 8px 20px rgba(15, 23, 42, 0.08), 0 0 0 1px var(--mzn-color-primary, #0057ff), 0 0 10px rgba(0, 87, 255, 0.3)';\nconst FLOW_NODE_INITIAL_HEIGHT = 64;\nconst FLOW_NODE_INITIAL_WIDTH = 160;\nconst FLOW_NODE_ADDITIONAL_LINE_HEIGHT = 20;\nconst GATEWAY_NODE_INITIAL_HEIGHT = 64;\nconst GATEWAY_NODE_INITIAL_WIDTH = 180;\n\nconst GATEWAY_NODE_STYLE: CSSProperties = {\n ...NODE_STYLE,\n display: 'grid',\n gap: 8,\n padding: '10px 12px',\n};\n\nconst EXCLUSIVE_GATEWAY_NODE_STYLE: CSSProperties = {\n ...GATEWAY_NODE_STYLE,\n background: '#eff6ff',\n border: '1px solid #2563eb',\n};\n\nconst PARALLEL_GATEWAY_NODE_STYLE: CSSProperties = {\n ...GATEWAY_NODE_STYLE,\n background: '#f0fdfa',\n border: '1px solid #0f766e',\n};\n\nconst USER_TASK_NODE_STYLE: CSSProperties = {\n ...NODE_STYLE,\n background: '#ffffff',\n};\n\nconst START_NODE_STYLE: CSSProperties = {\n ...NODE_STYLE,\n background: '#ecfdf3',\n border: '1px solid #2f855a',\n};\n\nconst END_NODE_STYLE: CSSProperties = {\n ...NODE_STYLE,\n background: '#fff4ed',\n border: '1px solid #c2410c',\n};\n\nconst NODE_TEXT_STYLE: CSSProperties = {\n display: 'block',\n maxWidth: '100%',\n minWidth: 0,\n};\n\nconst NODE_PRIMARY_LABELS_STYLE: CSSProperties = {\n display: 'grid',\n gap: 2,\n minWidth: 0,\n};\n\nconst WORKFLOW_INPUT_HANDLE_ID = 'input';\nconst WORKFLOW_OUTPUT_HANDLE_ID = 'output';\n\nconst NODE_TYPE_LABELS: Readonly<Record<WorkflowNode['type'], string>> = {\n endEvent: '結束',\n exclusiveGateway: '條件分流',\n parallelGateway: '並行處理',\n serviceTask: '系統',\n startEvent: '開始',\n userTask: '簽核',\n};\n\nconst ACTION_NODE_PALETTE: readonly {\n readonly icon: IconDefinition;\n readonly label: string;\n readonly type: Extract<NodePaletteType, 'serviceTask' | 'userTask'>;\n}[] = [\n { icon: UserIcon, label: '簽核節點', type: 'userTask' },\n { icon: MailIcon, label: '知會節點', type: 'serviceTask' },\n];\nconst FLOW_CONTROL_PALETTE: readonly {\n readonly icon: IconDefinition;\n readonly label: string;\n readonly type: Extract<NodePaletteType, 'exclusiveGateway'>;\n}[] = [{ icon: FilterIcon, label: '條件分流', type: 'exclusiveGateway' }];\nconst NODE_TRIGGER_MODE_OPTIONS: readonly {\n readonly id: WorkflowNodeTriggerMode;\n readonly name: string;\n}[] = [\n { id: 'AND', name: '全部前置完成' },\n { id: 'OR', name: '任一前置完成' },\n];\nconst RETURN_RESUBMIT_STRATEGY_OPTIONS: readonly ReturnResubmitStrategyOption[] =\n [\n { id: 'RESTART', name: '重新送出後從開始重跑' },\n { id: 'FROM_RETURN_POINT', name: '重新送出後回到退回節點' },\n ];\nconst APPROVER_RESOLVER_MODE_OPTIONS: readonly ApproverResolverModeOption[] = [\n { id: 'DIRECT', name: '指定會員' },\n { id: 'ORG_MANAGER', name: '發起人主管' },\n { id: 'ORG_UNIT_MANAGER', name: '指定組織主管' },\n { id: 'ORG_UNIT_MEMBER', name: '組織任一人' },\n { id: 'ORG_UNIT_POSITION', name: '組織特定職位' },\n { id: 'POSITION', name: '指定職位' },\n];\nconst MANAGER_LEVEL_OPTIONS: readonly ManagerLevelOption[] = [\n { id: '1', name: '直屬主管', value: 1 },\n { id: '2', name: '第二層主管', value: 2 },\n { id: '3', name: '第三層主管', value: 3 },\n];\nconst APPROVER_FALLBACK_MODE_OPTIONS: readonly ApproverFallbackModeOption[] = [\n { id: 'NONE', name: '停止流程並提示' },\n { id: 'DIRECT', name: '固定改派' },\n];\nconst CONDITION_OPERATOR_OPTIONS: readonly ConditionOperatorOption[] = [\n { id: 'EQUALS', name: '等於' },\n { id: 'NOT_EQUALS', name: '不等於' },\n { id: 'GREATER_THAN', name: '大於' },\n { id: 'GREATER_THAN_OR_EQUALS', name: '大於等於' },\n { id: 'LESS_THAN', name: '小於' },\n { id: 'LESS_THAN_OR_EQUALS', name: '小於等於' },\n { id: 'IS_FILLED', name: '已填寫' },\n { id: 'IS_EMPTY', name: '未填寫' },\n];\nconst CONDITION_OPERATORS_REQUIRING_VALUE: readonly WorkflowEdgeConditionOperator[] =\n [\n 'EQUALS',\n 'GREATER_THAN',\n 'GREATER_THAN_OR_EQUALS',\n 'LESS_THAN',\n 'LESS_THAN_OR_EQUALS',\n 'NOT_EQUALS',\n ];\nconst INITIATOR_POLICY_MODE_OPTIONS: readonly InitiatorPolicyModeOption[] = [\n { id: 'NONE', name: '未設定' },\n { id: 'ALL', name: '所有人' },\n { id: 'ORG_UNIT', name: '指定組織' },\n { id: 'ORG_UNIT_POSITION', name: '指定組織職位' },\n];\nconst INITIATOR_POLICY_CUSTOM_OPTION: InitiatorPolicyModeOption = {\n id: 'CUSTOM',\n name: '既有自訂規則',\n};\nconst DRY_RUN_MEMBER_ID = 'member-001';\n\nconst FORM_EDIT_DRAWER_BODY_STYLE: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n};\n\nconst FORM_EDIT_DRAWER_CONTENT_STYLE: CSSProperties = {\n flex: 1,\n minHeight: 0,\n overflowY: 'auto',\n};\n\nconst FORM_EDIT_DRAWER_FOOTER_STYLE: CSSProperties = {\n borderTop: '1px solid var(--mzn-color-border-neutral)',\n display: 'flex',\n gap: 8,\n paddingTop: 12,\n};\n\nconst FORM_EDIT_EMPTY_SCHEMA: FormDefinitionSchema = {\n fields: [],\n schemaVersion: 1,\n};\n\nconst FORM_EDIT_EMPTY_UI_SCHEMA: FormUiSchema = {\n layout: [],\n schemaVersion: 1,\n};\n\ntype FormDraft = Readonly<{\n schema: FormDefinitionSchema;\n uiSchema: FormUiSchema;\n}>;\n\nconst nodeTypes: NodeTypes = {\n endEvent: WorkflowNodeCard,\n exclusiveGateway: WorkflowNodeCard,\n parallelGateway: WorkflowNodeCard,\n serviceTask: WorkflowNodeCard,\n startEvent: WorkflowNodeCard,\n userTask: WorkflowNodeCard,\n};\n\nexport interface TemplateDesignerViewProps {\n /**\n * Template id to load. Required in non-embedded mode; unused in embedded mode.\n */\n readonly templateId?: string;\n /**\n * When `true`, the component operates in embedded / wizard mode:\n * - No `readTemplateDesigner` call (no templateId needed).\n * - Only org data is loaded for approver pickers.\n * - PageHeader / ContentHeader, form-version binding, and dry-run are hidden.\n * - The AI assistant, when `showAiAssistant` is set, is offered through a\n * button in the side \"流程工具\" panel (the PageHeader button it normally\n * lives in is hidden here), and drives the same embedded canvas.\n * - Mutations flow out via `onWorkflowChange` / `onInitiatorPolicyChange`\n * rather than save-draft / publish actions.\n * Default `false`.\n */\n readonly embedded?: boolean;\n /**\n * In embedded mode: the formSchema used for condition-edge compilation,\n * injected from outside (e.g. the wizard already knows the form). Replaces\n * the \"bind form version\" picker. Pass `null` to clear.\n */\n readonly formSchemaOverride?: FormDefinitionSchema | null;\n /**\n * In embedded mode: the initial workflow definition to seed the canvas.\n * Falls back to an empty start→end workflow when omitted.\n */\n readonly initialWorkflowDefinition?: WorkflowDefinition;\n /**\n * In embedded mode: the initial initiator-policy CEL expression.\n * Falls back to `null` (no policy) when omitted.\n */\n readonly initialInitiatorPolicyCel?: string | null;\n /**\n * In embedded mode: called whenever the workflow definition changes so the\n * host can persist the current canvas state.\n */\n readonly onWorkflowChange?: (definition: WorkflowDefinition) => void;\n /**\n * In embedded mode: called whenever the initiator-policy CEL changes.\n */\n readonly onInitiatorPolicyChange?: (cel: string | null) => void;\n /**\n * Render the \"試跑流程\" (dry-run) button at all. Default `true`. Hosts can\n * pass `false` to hide it (e.g. deployments that don't expose dry-run).\n * Has no effect in embedded mode, where the PageHeader is hidden entirely.\n */\n readonly showDryRun?: boolean;\n /**\n * Render the AI assistant toggle at all. Default `false` — the feature is\n * hidden unless the host opts in (e.g. a deployment that has it configured).\n */\n readonly showAiAssistant?: boolean;\n /**\n * Whether the LLM backend is configured (e.g. the host has an API key set).\n * Default `true`. When `false`, the toggle is shown but disabled and labelled\n * as not configured — a placeholder rather than a broken feature.\n */\n readonly aiAssistantAvailable?: boolean;\n}\n\n/** Resolve a React SetStateAction against the current value (no `any`). */\nfunction resolveSetStateAction<T>(action: SetStateAction<T>, current: T): T {\n return typeof action === 'function'\n ? (action as (previous: T) => T)(current)\n : action;\n}\n\nexport function TemplateDesignerView({\n aiAssistantAvailable = true,\n embedded = false,\n formSchemaOverride,\n initialInitiatorPolicyCel,\n initialWorkflowDefinition,\n onInitiatorPolicyChange,\n onWorkflowChange,\n showAiAssistant = false,\n showDryRun = true,\n templateId,\n}: TemplateDesignerViewProps): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const [record, setRecord] = useState<TemplateDesignerRecord | null>(null);\n const [draft, setDraft] = useState<ApprovalTemplateVersionRecord | null>(\n null,\n );\n const [loadedDesignerSnapshot, setLoadedDesignerSnapshot] = useState('');\n const [initiatorPolicyModeDraft, setInitiatorPolicyModeDraft] =\n useState<Exclude<InitiatorPolicyMode, 'CUSTOM'> | null>(null);\n const [initiatorPolicyDraftOverride, setInitiatorPolicyDraftOverride] =\n useState<InitiatorPolicyDraft | null>(null);\n const flowCanvasRef = useRef<HTMLDivElement | null>(null);\n const [flowViewport, setFlowViewport] = useState<Viewport | undefined>(\n undefined,\n );\n\n // Org/position data is loaded further down; mirror it into refs so the stable\n // `directory` object below always reads the latest without re-creation.\n const orgUnitsRef = useRef<readonly OrgUnitRecord[]>([]);\n const positionsRef = useRef<readonly PositionRecord[]>([]);\n // Backs the assistant's member/org lookup query tools (search_members /\n // list_org_units / list_positions) — host data, injected into the toolset.\n const directory = useMemo<WorkflowDirectory>(\n () => ({\n listOrgUnits: async () =>\n orgUnitsRef.current.map((unit) => ({ id: unit.id, name: unit.name })),\n listPositions: async () =>\n positionsRef.current.map((position) => ({\n id: position.id,\n name: position.name,\n })),\n searchMembers: async (query) =>\n readMemberSelectOptions(await searchMemberOptions(query)).map(\n (member) => ({\n email: member.email,\n id: member.memberId,\n name: member.name,\n }),\n ),\n }),\n [],\n );\n\n // The pure command reducer (shared with the LLM toolset) owns the workflow\n // graph, selection, form binding, and initiator policy. Every logical\n // mutation flows through `controller.dispatch`; the dagre layout + viewport\n // are injected here so the pure layer stays free of DOM concerns.\n const controller = useWorkflowDesignerController({\n directory,\n initialState: {\n definition:\n embedded && initialWorkflowDefinition != null\n ? initialWorkflowDefinition\n : readFallbackWorkflowDefinition(),\n editingEdgeId: null,\n formDefinitionVersionId: null,\n formSchema: null,\n initiatorPolicyCel:\n embedded && initialInitiatorPolicyCel !== undefined\n ? initialInitiatorPolicyCel\n : null,\n selectedEdgeIds: [],\n selectedNodeId:\n embedded && initialWorkflowDefinition != null\n ? (initialWorkflowDefinition.nodes[0]?.id ?? 'start')\n : 'start',\n },\n layout: layoutWorkflowDefinition,\n onLayout: (definition): void => {\n const nextViewport = readWorkflowViewport(\n definition,\n flowCanvasRef.current,\n );\n\n if (nextViewport) {\n setFlowViewport(nextViewport);\n }\n },\n });\n const workflowDefinition = controller.state.definition;\n const formDefinitionVersionId = controller.state.formDefinitionVersionId;\n const initiatorPolicyCel = controller.state.initiatorPolicyCel;\n const selectedNodeId = controller.state.selectedNodeId;\n const selectedEdgeIds = controller.state.selectedEdgeIds;\n const editingEdgeId = controller.state.editingEdgeId;\n const setWorkflowDefinition = (\n action: SetStateAction<WorkflowDefinition>,\n ): void =>\n controller.replaceState((current) => ({\n ...current,\n definition: resolveSetStateAction(action, current.definition),\n }));\n const setFormDefinitionVersionId = (\n action: SetStateAction<string | null>,\n ): void =>\n controller.replaceState((current) => ({\n ...current,\n formDefinitionVersionId: resolveSetStateAction(\n action,\n current.formDefinitionVersionId,\n ),\n }));\n const setInitiatorPolicyCel = (action: SetStateAction<string | null>): void =>\n controller.replaceState((current) => ({\n ...current,\n initiatorPolicyCel: resolveSetStateAction(\n action,\n current.initiatorPolicyCel,\n ),\n }));\n const setSelectedNodeId = (action: SetStateAction<string | null>): void =>\n controller.replaceState((current) => ({\n ...current,\n selectedNodeId: resolveSetStateAction(action, current.selectedNodeId),\n }));\n const setSelectedEdgeIds = (\n action: SetStateAction<readonly string[]>,\n ): void =>\n controller.replaceState((current) => ({\n ...current,\n selectedEdgeIds: resolveSetStateAction(action, current.selectedEdgeIds),\n }));\n const setEditingEdgeId = (action: SetStateAction<string | null>): void =>\n controller.replaceState((current) => ({\n ...current,\n editingEdgeId: resolveSetStateAction(action, current.editingEdgeId),\n }));\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [formVersionLoading, setFormVersionLoading] = useState(false);\n const [formVersionOptions, setFormVersionOptions] = useState<\n readonly FormVersionSelectOption[]\n >([]);\n const currentDesignerSnapshot = useMemo(\n (): string =>\n JSON.stringify({\n formDefinitionVersionId,\n initiatorPolicyCel,\n workflowDefinition,\n }),\n [formDefinitionVersionId, initiatorPolicyCel, workflowDefinition],\n );\n const hasUnsavedChanges =\n Boolean(loadedDesignerSnapshot) &&\n currentDesignerSnapshot !== loadedDesignerSnapshot;\n const [memberLoading, setMemberLoading] = useState(false);\n const [memberOptions, setMemberOptions] = useState<\n readonly MemberSelectOption[]\n >([]);\n const [orgUnits, setOrgUnits] = useState<readonly OrgUnitRecord[]>([]);\n const [positions, setPositions] = useState<readonly PositionRecord[]>([]);\n const [memberships, setMemberships] = useState<readonly MembershipRecord[]>(\n [],\n );\n // Keep the directory's refs pointed at the latest loaded org data.\n orgUnitsRef.current = orgUnits;\n positionsRef.current = positions;\n const [dryRunModalOpen, setDryRunModalOpen] = useState(false);\n const [dryRunRunning, setDryRunRunning] = useState(false);\n const [dryRunFormDataJson, setDryRunFormDataJson] = useState('{}');\n const [dryRunResult, setDryRunResult] =\n useState<WorkflowDryRunResultRecord | null>(null);\n const [dryRunError, setDryRunError] = useState<string | null>(null);\n const [chatOpen, setChatOpen] = useState(false);\n const [formEditOpen, setFormEditOpen] = useState(false);\n const [formDraft, setFormDraft] = useState<FormDraft | null>(null);\n const [formDraftDirty, setFormDraftDirty] = useState(false);\n const [formDraftLoading, setFormDraftLoading] = useState(false);\n const publishButtonText =\n hasUnsavedChanges || formDraftDirty\n ? '保存並發布'\n : draft\n ? '發布草稿'\n : '已發布';\n\n useEffect((): void => {\n if (embedded) {\n void loadOrganizationData();\n } else {\n void refreshDesigner();\n }\n }, [embedded, templateId]);\n\n useEffect((): (() => void) => {\n function handleBeforeUnload(event: BeforeUnloadEvent): void {\n if (!hasUnsavedChanges) {\n return;\n }\n\n event.preventDefault();\n event.returnValue = '';\n }\n\n window.addEventListener('beforeunload', handleBeforeUnload);\n\n return (): void => {\n window.removeEventListener('beforeunload', handleBeforeUnload);\n };\n }, [hasUnsavedChanges]);\n\n useEffect((): void => {\n void resolveWorkflowMemberOptions(workflowDefinition);\n }, [workflowDefinition, memberOptions]);\n\n useEffect((): void => {\n setWorkflowDefinition((currentDefinition) =>\n normalizeDesignerWorkflowDefinition(currentDefinition),\n );\n }, [workflowDefinition.edges, workflowDefinition.nodes]);\n\n function handleBackToTemplates(): void {\n if (\n hasUnsavedChanges &&\n !window.confirm('目前有尚未儲存的流程草稿,確定要離開嗎?')\n ) {\n return;\n }\n\n router.push(routes.templates());\n }\n\n const selectedNode = useMemo(\n (): WorkflowNode | null =>\n workflowDefinition.nodes.find((node) => node.id === selectedNodeId) ??\n null,\n [selectedNodeId, workflowDefinition.nodes],\n );\n const selectedNodeCanDelete = selectedNode\n ? isWorkflowNodeRemovable(selectedNode)\n : false;\n const hasDeletableSelection =\n selectedEdgeIds.length > 0 || selectedNodeCanDelete;\n const removeSelectedWorkflowElements = useCallback((): void => {\n // Remove the selected edges first, then the selected node (which also drops\n // any edges still attached to it and resets selection). Both flow through\n // the same reducer the LLM toolset uses.\n controller\n .getState()\n .selectedEdgeIds.forEach((edgeId) =>\n controller.dispatch({ edgeId, type: 'deleteEdge' }),\n );\n\n if (selectedNode && isWorkflowNodeRemovable(selectedNode)) {\n controller.dispatch({ nodeId: selectedNode.id, type: 'deleteNode' });\n }\n }, [controller, selectedNode]);\n\n useEffect((): (() => void) | undefined => {\n if (!hasDeletableSelection) {\n return undefined;\n }\n\n function handleDeleteSelectedElements(event: KeyboardEvent): void {\n if (event.key !== 'Delete' && event.key !== 'Backspace') {\n return;\n }\n\n if (isEditableKeyboardTarget(event.target)) {\n return;\n }\n\n event.preventDefault();\n removeSelectedWorkflowElements();\n }\n\n window.addEventListener('keydown', handleDeleteSelectedElements);\n\n return (): void => {\n window.removeEventListener('keydown', handleDeleteSelectedElements);\n };\n }, [hasDeletableSelection, removeSelectedWorkflowElements]);\n\n const editingEdge = useMemo(\n (): WorkflowEdge | null =>\n workflowDefinition.edges.find((edge) => edge.id === editingEdgeId) ??\n null,\n [editingEdgeId, workflowDefinition.edges],\n );\n const selectedEdge = useMemo(\n (): WorkflowEdge | null =>\n selectedEdgeIds.length === 1\n ? (workflowDefinition.edges.find(\n (edge) => edge.id === selectedEdgeIds[0],\n ) ?? null)\n : null,\n [selectedEdgeIds, workflowDefinition.edges],\n );\n const selectedEdges = useMemo(\n (): readonly WorkflowEdge[] =>\n selectedEdgeIds\n .map(\n (edgeId) =>\n workflowDefinition.edges.find((edge) => edge.id === edgeId) ?? null,\n )\n .filter((edge): edge is WorkflowEdge => Boolean(edge)),\n [selectedEdgeIds, workflowDefinition.edges],\n );\n const initiatorPolicyDraft = useMemo(\n (): InitiatorPolicyDraft =>\n initiatorPolicyDraftOverride ??\n readInitiatorPolicyUiDraft(initiatorPolicyCel, initiatorPolicyModeDraft),\n [\n initiatorPolicyCel,\n initiatorPolicyDraftOverride,\n initiatorPolicyModeDraft,\n ],\n );\n const flowNodes = useMemo(\n (): FlowNode[] =>\n workflowDefinition.nodes.map((node) =>\n readFlowNode(\n node,\n memberOptions,\n orgUnits,\n positions,\n node.id === selectedNodeId,\n initiatorPolicyDraft,\n ),\n ),\n [\n initiatorPolicyDraft,\n memberOptions,\n orgUnits,\n positions,\n selectedNodeId,\n workflowDefinition.nodes,\n ],\n );\n const flowEdges = useMemo(\n (): FlowEdge[] =>\n workflowDefinition.edges.map((edge) =>\n readFlowEdge(\n edge,\n workflowDefinition.nodes,\n selectedEdgeIds.includes(edge.id),\n ),\n ),\n [selectedEdgeIds, workflowDefinition.edges, workflowDefinition.nodes],\n );\n\n const selectedFormVersionOption = useMemo(\n (): FormVersionSelectOption | null =>\n readSelectOption(formVersionOptions, formDefinitionVersionId) ??\n readSelectOption(\n readFormVersionSelectOptions(record?.formVersions ?? []),\n formDefinitionVersionId,\n ),\n [formDefinitionVersionId, formVersionOptions, record?.formVersions],\n );\n const visibleFormVersionOptions = useMemo(\n (): readonly FormVersionSelectOption[] =>\n mergeSelectedOption(formVersionOptions, selectedFormVersionOption),\n [formVersionOptions, selectedFormVersionOption],\n );\n const selectedFormSchema = selectedFormVersionOption?.schema ?? null;\n\n // Keep the reducer's form schema in sync with the effective schema source:\n // - embedded mode: driven by `formSchemaOverride` (wizard owns the form).\n // - non-embedded mode: driven by the selected published form version.\n const effectiveFormSchema: FormDefinitionSchema | null = embedded\n ? (formSchemaOverride ?? null)\n : selectedFormSchema;\n\n useEffect((): void => {\n if (controller.getState().formSchema !== effectiveFormSchema) {\n controller.replaceState((current) => ({\n ...current,\n formSchema: effectiveFormSchema,\n }));\n }\n }, [controller, effectiveFormSchema]);\n const workflowIssue = useMemo(\n (): string | null => readWorkflowDefinitionIssue(workflowDefinition),\n [workflowDefinition],\n );\n const formVersionBindingLocked = useMemo(\n (): boolean => hasConfiguredConditionEdges(workflowDefinition),\n [workflowDefinition],\n );\n const initiatorPolicyIssue = useMemo(\n (): string | null => readInitiatorPolicyIssue(initiatorPolicyDraft),\n [initiatorPolicyDraft],\n );\n\n // Embedded mode: propagate workflow / initiatorPolicy changes to the host.\n useEffect((): void => {\n if (embedded) {\n onWorkflowChange?.(workflowDefinition);\n }\n // onWorkflowChange is intentionally omitted from deps — we only track the\n // value change, not the callback identity.\n }, [embedded, workflowDefinition]);\n\n useEffect((): void => {\n if (embedded) {\n onInitiatorPolicyChange?.(initiatorPolicyCel);\n }\n }, [embedded, initiatorPolicyCel]);\n\n /**\n * Embedded mode: load only the organisation data needed for approver pickers.\n * Does not touch the workflow / form-version / snapshot state.\n */\n async function loadOrganizationData(): Promise<void> {\n setLoading(true);\n setError(null);\n\n try {\n const organizationDashboard = await readOrganizationDashboard();\n\n setOrgUnits(organizationDashboard.orgUnits);\n setPositions(organizationDashboard.positions);\n setMemberships(organizationDashboard.memberships);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n /**\n * Non-embedded mode: load both the template record and the organisation data,\n * then seed the controller with the draft / latest version.\n */\n async function refreshDesigner(): Promise<void> {\n setLoading(true);\n setError(null);\n\n try {\n const [nextRecord, organizationDashboard] = await Promise.all([\n readTemplateDesigner(templateId as string),\n readOrganizationDashboard(),\n ]);\n const nextDraft =\n nextRecord.versions.find((version) => version.status === 'DRAFT') ??\n null;\n const sourceVersion = nextDraft ?? nextRecord.versions[0] ?? null;\n\n setRecord(nextRecord);\n setDraft(nextDraft);\n setOrgUnits(organizationDashboard.orgUnits);\n setPositions(organizationDashboard.positions);\n setMemberships(organizationDashboard.memberships);\n setFormVersionOptions(\n readFormVersionSelectOptions(nextRecord.formVersions),\n );\n const nextWorkflowDefinition =\n sourceVersion?.workflowDefinition ?? readFallbackWorkflowDefinition();\n const nextFormDefinitionVersionId =\n sourceVersion?.formDefinitionVersionId ??\n nextRecord.formVersions[0]?.id ??\n null;\n const nextInitiatorPolicyCel = sourceVersion?.initiatorPolicyCel ?? null;\n\n setWorkflowDefinition(nextWorkflowDefinition);\n setFormDefinitionVersionId(nextFormDefinitionVersionId);\n setInitiatorPolicyCel(nextInitiatorPolicyCel);\n setLoadedDesignerSnapshot(\n JSON.stringify({\n formDefinitionVersionId: nextFormDefinitionVersionId,\n initiatorPolicyCel: nextInitiatorPolicyCel,\n workflowDefinition: nextWorkflowDefinition,\n }),\n );\n setInitiatorPolicyModeDraft(\n sourceVersion &&\n !nextRecord.template.currentVersionId &&\n !sourceVersion.initiatorPolicyCel &&\n isEmptyDesignerWorkflowDefinition(sourceVersion.workflowDefinition)\n ? 'NONE'\n : null,\n );\n setInitiatorPolicyDraftOverride(null);\n setSelectedNodeId(\n sourceVersion?.workflowDefinition.nodes[0]?.id ?? 'start',\n );\n setSelectedEdgeIds([]);\n setEditingEdgeId(null);\n // Reset form draft so next open of the drawer reloads the latest version.\n setFormDraft(null);\n setFormDraftDirty(false);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function handleSearchFormVersions(searchText: string): Promise<void> {\n setFormVersionLoading(true);\n setError(null);\n\n try {\n const options = await searchPublishedFormVersionOptions(searchText);\n setFormVersionOptions(\n mergeSelectedOption(\n readFormVersionSelectOptions(options),\n selectedFormVersionOption,\n ),\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setFormVersionLoading(false);\n }\n }\n\n async function handleSearchMembers(searchText: string): Promise<void> {\n setMemberLoading(true);\n setError(null);\n\n try {\n const options = await searchMemberOptions(searchText);\n setMemberOptions((currentOptions) =>\n mergeMemberOptions(currentOptions, readMemberSelectOptions(options)),\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setMemberLoading(false);\n }\n }\n\n async function resolveWorkflowMemberOptions(\n definition: WorkflowDefinition,\n ): Promise<void> {\n const memberIds = readWorkflowDirectMemberIds(definition);\n const missingMemberIds = memberIds.filter(\n (memberId) =>\n !memberOptions.some((option) => option.memberId === memberId),\n );\n\n if (missingMemberIds.length === 0) {\n return;\n }\n\n try {\n const options = await resolveMemberOptions(missingMemberIds);\n setMemberOptions((currentOptions) =>\n mergeMemberOptions(currentOptions, readMemberSelectOptions(options)),\n );\n } catch {\n setMemberOptions((currentOptions) =>\n mergeMemberOptions(\n currentOptions,\n missingMemberIds.map(readFallbackMemberSelectOption),\n ),\n );\n }\n }\n\n async function commitDesigner(publish: boolean): Promise<void> {\n setSaving(true);\n setError(null);\n\n try {\n const validationIssue = readWorkflowDefinitionIssue(workflowDefinition);\n const policyIssue = readInitiatorPolicyIssue(initiatorPolicyDraft);\n\n if (validationIssue || policyIssue) {\n const issue = validationIssue ?? policyIssue ?? '流程設定未完成';\n\n setError(issue);\n throw new Error(issue);\n }\n\n if (formDraftDirty && formDraft !== null) {\n await composeApprovalTemplateWithForm({\n category: record?.template.category ?? null,\n categoryId: record?.template.categoryId ?? null,\n formDefinitionId: selectedFormVersionOption?.formDefinitionId ?? null,\n formDescription: null,\n formName:\n selectedFormVersionOption?.formName ??\n record?.template.name ??\n '表單',\n initiatorPolicyCel,\n notificationConfig: null,\n publish,\n schema: formDraft.schema,\n slaDefaults: null,\n templateDescription: null,\n templateId: templateId ?? null,\n templateName: record?.template.name ?? '模板',\n uiSchema: formDraft.uiSchema,\n workflowDefinition,\n });\n setFormDraftDirty(false);\n setFormDraft(null);\n await refreshDesigner();\n } else {\n const targetDraft =\n draft ?? (await forkApprovalTemplate(templateId as string));\n\n const nextDraft = await updateApprovalTemplateDraft({\n formDefinitionVersionId,\n initiatorPolicyCel,\n versionId: targetDraft.id,\n workflowDefinition,\n });\n\n setDraft(nextDraft);\n\n if (publish) {\n await publishApprovalTemplateVersion(nextDraft.id);\n }\n\n await refreshDesigner();\n }\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n throw requestError;\n } finally {\n setSaving(false);\n }\n }\n\n async function handleSaveDraft(): Promise<void> {\n await commitDesigner(false);\n }\n\n async function handlePublish(): Promise<void> {\n await commitDesigner(true);\n }\n\n function openDryRunModal(): void {\n setDryRunFormDataJson(\n JSON.stringify(\n readDryRunSampleFormData(selectedFormVersionOption),\n null,\n 2,\n ),\n );\n setDryRunResult(null);\n setDryRunError(null);\n setDryRunModalOpen(true);\n }\n\n function closeDryRunModal(): void {\n if (dryRunRunning) {\n return;\n }\n\n setDryRunModalOpen(false);\n }\n\n async function handleDryRun(): Promise<void> {\n setDryRunRunning(true);\n setDryRunError(null);\n setDryRunResult(null);\n\n try {\n const formData = parseDryRunFormData(dryRunFormDataJson);\n const result = await dryRunApprovalWorkflow({\n formData,\n initiatorMemberId: DRY_RUN_MEMBER_ID,\n initiatorMetadataSnapshot: readDryRunInitiatorMetadataSnapshot(\n DRY_RUN_MEMBER_ID,\n memberships,\n ),\n workflowDefinition,\n });\n\n setDryRunResult(result);\n } catch (requestError: unknown) {\n setDryRunError(readErrorMessage(requestError));\n } finally {\n setDryRunRunning(false);\n }\n }\n\n async function openFormEditDrawer(): Promise<void> {\n setFormEditOpen(true);\n\n if (formDraft !== null) {\n return;\n }\n\n const boundFormDefinitionId =\n selectedFormVersionOption?.formDefinitionId ?? null;\n\n if (!boundFormDefinitionId) {\n setFormDraft({\n schema: FORM_EDIT_EMPTY_SCHEMA,\n uiSchema: FORM_EDIT_EMPTY_UI_SCHEMA,\n });\n\n return;\n }\n\n setFormDraftLoading(true);\n\n try {\n const builderRecord = await readFormBuilder(boundFormDefinitionId);\n const draftVersion =\n builderRecord.versions.find((v) => v.status === 'DRAFT') ??\n builderRecord.versions.find(\n (v) => v.id === builderRecord.definition.currentVersionId,\n ) ??\n builderRecord.versions[0] ??\n null;\n\n setFormDraft({\n schema: draftVersion?.schema ?? FORM_EDIT_EMPTY_SCHEMA,\n uiSchema: draftVersion?.uiSchema ?? FORM_EDIT_EMPTY_UI_SCHEMA,\n });\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setFormDraftLoading(false);\n }\n }\n\n function handleNodeChanges(\n changes: Parameters<typeof applyNodeChanges>[0],\n ): void {\n const nextFlowNodes = applyNodeChanges(changes, flowNodes);\n\n setWorkflowDefinition((currentDefinition) => ({\n ...currentDefinition,\n nodes: currentDefinition.nodes.map((node) => {\n const flowNode = nextFlowNodes.find(\n (candidate) => candidate.id === node.id,\n );\n\n return flowNode ? { ...node, position: flowNode.position } : node;\n }),\n }));\n }\n\n function handleConnect(connection: Connection): void {\n if (\n !isWorkflowConnectionValid(connection, workflowDefinition.nodes) ||\n !connection.source ||\n !connection.target\n ) {\n return;\n }\n\n controller.dispatch({\n source: connection.source,\n target: connection.target,\n type: 'connectEdge',\n });\n }\n\n function handleEdgeClick(event: ReactMouseEvent, edge: FlowEdge): void {\n event.stopPropagation();\n\n setSelectedEdgeIds((currentEdgeIds) =>\n event.shiftKey || event.metaKey || event.ctrlKey\n ? toggleSelectedEdgeId(currentEdgeIds, edge.id)\n : [edge.id],\n );\n setSelectedNodeId(null);\n }\n\n function closeEdgeSettingsModal(): void {\n setEditingEdgeId(null);\n }\n\n function addWorkflowNode(type: NodePaletteType): void {\n // The reducer derives the insertion anchor from the current selection and\n // flags `effects.layout`, so the controller re-runs dagre + viewport.\n controller.dispatch({ nodeType: type, type: 'addNode' });\n }\n\n function updateSelectedNodeLabel(label: string): void {\n if (!selectedNode) {\n return;\n }\n\n controller.dispatch({ label, nodeId: selectedNode.id, type: 'renameNode' });\n }\n\n function updateUserTaskResolver(approverResolver: ApproverResolver): void {\n if (!selectedNode || selectedNode.type !== 'userTask') {\n return;\n }\n\n controller.dispatch({\n approverResolver,\n nodeId: selectedNode.id,\n type: 'setUserTaskApprover',\n });\n }\n\n function updateUserTaskReturnResubmitStrategy(\n resubmitStrategy: ReturnResubmitStrategy,\n ): void {\n if (!selectedNode || selectedNode.type !== 'userTask') {\n return;\n }\n\n controller.dispatch({\n nodeId: selectedNode.id,\n resubmitStrategy,\n type: 'setUserTaskReturnResubmitStrategy',\n });\n }\n\n function updateServiceAction(action: ServiceAction): void {\n if (!selectedNode || selectedNode.type !== 'serviceTask') {\n return;\n }\n\n controller.dispatch({\n action,\n nodeId: selectedNode.id,\n type: 'setServiceAction',\n });\n }\n\n function updateInitiatorPolicyDraft(\n draft: InitiatorPolicyDraft,\n ): void {\n setInitiatorPolicyDraftOverride(\n draft.mode === 'ALL' || draft.mode === 'CUSTOM' ? null : draft,\n );\n setInitiatorPolicyModeDraft(\n draft.mode === 'ALL' || draft.mode === 'CUSTOM' ? null : draft.mode,\n );\n setInitiatorPolicyCel(readInitiatorPolicyCel(draft, orgUnits));\n }\n\n function updateSelectedNodeTriggerMode(\n triggerMode: WorkflowNodeTriggerMode,\n ): void {\n if (!selectedNode || selectedNode.type === 'startEvent') {\n return;\n }\n\n controller.dispatch({\n nodeId: selectedNode.id,\n triggerMode,\n type: 'setNodeTriggerMode',\n });\n }\n\n function updateSelectedEdgeDefault(edgeId: string, checked: boolean): void {\n controller.dispatch({ edgeId, isDefault: checked, type: 'setEdgeDefault' });\n }\n\n function updateSelectedEdgeConditionState({\n edgeId,\n fieldKey,\n operator,\n value,\n }: {\n readonly edgeId: string;\n readonly fieldKey?: string | null;\n readonly operator?: WorkflowEdgeConditionOperator | null;\n readonly value?: string | null;\n }): void {\n // The reducer compiles the condition against the synced `formSchema`.\n controller.dispatch({\n edgeId,\n fieldKey,\n operator,\n type: 'setEdgeCondition',\n value,\n });\n }\n\n function applyAutoLayout(): void {\n controller.dispatch({ type: 'autoLayout' });\n }\n\n return (\n <>\n <style>{SIDE_PANEL_GLOBAL_STYLE}</style>\n {!embedded ? (\n <PageHeader>\n <ContentHeader\n description={`${draft ? `草稿 v${draft.version}` : '尚未建立草稿'} ·${\n record?.template.currentVersionId ? ' 已發布版本' : ' 尚未發布'\n }`}\n onBackClick={handleBackToTemplates}\n title={record?.template.name ?? '流程設計器'}\n >\n {showAiAssistant ? (\n <Button\n disabled={!aiAssistantAvailable}\n onClick={(): void => setChatOpen((current) => !current)}\n variant={chatOpen ? 'base-primary' : 'base-secondary'}\n >\n {aiAssistantAvailable ? 'AI 助理' : 'AI 助理(未設定)'}\n </Button>\n ) : null}\n <Button\n aria-label=\"儲存草稿\"\n disabled={\n saving ||\n Boolean(workflowIssue) ||\n Boolean(initiatorPolicyIssue)\n }\n icon={SaveIcon}\n iconType=\"icon-only\"\n onClick={(): void => void handleSaveDraft()}\n variant=\"base-secondary\"\n >\n 儲存草稿\n </Button>\n {showDryRun ? (\n <Button\n disabled={\n loading ||\n Boolean(workflowIssue) ||\n Boolean(initiatorPolicyIssue)\n }\n icon={EyeIcon}\n iconType=\"leading\"\n onClick={openDryRunModal}\n variant=\"base-secondary\"\n >\n 試跑流程\n </Button>\n ) : null}\n <Button\n disabled={\n saving ||\n (!draft && !hasUnsavedChanges && !formDraftDirty) ||\n Boolean(workflowIssue) ||\n Boolean(initiatorPolicyIssue)\n }\n icon={CheckedIcon}\n iconType=\"leading\"\n onClick={(): void => void handlePublish()}\n variant=\"base-primary\"\n >\n {publishButtonText}\n </Button>\n </ContentHeader>\n </PageHeader>\n ) : null}\n\n <SectionGroup>\n <Section>\n <div style={WORKSPACE_STYLE}>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {workflowIssue ? (\n <Typography color=\"text-error\" variant=\"body\">\n {workflowIssue}\n </Typography>\n ) : null}\n {initiatorPolicyIssue ? (\n <Typography color=\"text-error\" variant=\"body\">\n {initiatorPolicyIssue}\n </Typography>\n ) : null}\n {!embedded ? (\n <div style={FORM_STACK_STYLE}>\n <BPMFormField\n hintText={\n formVersionBindingLocked\n ? '已設定條件分流條件。請先移除所有條件,才能更換綁定表單版本。'\n : undefined\n }\n label=\"綁定表單版本\"\n name=\"formDefinitionVersionId\"\n required\n >\n <div style={FORM_BIND_ROW_STYLE}>\n <div style={FORM_BIND_FIELD_STYLE}>\n <AutoComplete\n asyncData\n disabled={loading || formVersionBindingLocked}\n disabledOptionsFilter\n emptyText=\"沒有符合的已發布表單版本\"\n isForceClearable={\n Boolean(formDefinitionVersionId) &&\n !formVersionBindingLocked\n }\n loading={formVersionLoading}\n loadingText=\"搜尋表單版本中...\"\n mode=\"single\"\n onChange={(option): void => {\n if (!formVersionBindingLocked) {\n setFormDefinitionVersionId(option?.id ?? null);\n }\n }}\n onClear={(): void => {\n if (!formVersionBindingLocked) {\n setFormDefinitionVersionId(null);\n }\n }}\n onSearch={handleSearchFormVersions}\n onVisibilityChange={(open): void => {\n if (open && !formVersionBindingLocked) {\n void handleSearchFormVersions('');\n }\n }}\n options={[...visibleFormVersionOptions]}\n placeholder=\"選擇已發布表單版本\"\n searchDebounceTime={300}\n value={selectedFormVersionOption}\n />\n </div>\n <Button\n disabled={loading}\n onClick={(): void => {\n void openFormEditDrawer();\n }}\n style={FORM_BIND_BUTTON_STYLE}\n variant=\"base-secondary\"\n >\n 編輯表單\n </Button>\n </div>\n </BPMFormField>\n </div>\n ) : null}\n <div style={TWO_COLUMN_STYLE}>\n <div ref={flowCanvasRef} style={FLOW_CANVAS_STYLE}>\n <ReactFlow\n connectionMode={ConnectionMode.Strict}\n edges={flowEdges}\n fitView\n isValidConnection={(connection): boolean =>\n isWorkflowConnectionValid(\n connection,\n workflowDefinition.nodes,\n )\n }\n nodeTypes={nodeTypes}\n nodes={flowNodes}\n deleteKeyCode={null}\n multiSelectionKeyCode={['Shift', 'Meta', 'Control']}\n onConnect={handleConnect}\n onEdgeClick={handleEdgeClick}\n onNodeClick={(_, node): void => {\n setSelectedNodeId(node.id);\n setSelectedEdgeIds([]);\n }}\n onNodesChange={handleNodeChanges}\n onPaneClick={(): void => {\n setSelectedNodeId(null);\n setSelectedEdgeIds([]);\n }}\n onViewportChange={setFlowViewport}\n viewport={flowViewport}\n >\n <Background />\n <style>{FLOW_CANVAS_GLOBAL_STYLE}</style>\n <Controls>\n {hasDeletableSelection ? (\n <ControlButton\n aria-label=\"刪除選取項目\"\n className=\"workflow-selection-delete-control\"\n onClick={removeSelectedWorkflowElements}\n style={SELECTION_DELETE_CONTROL_BUTTON_STYLE}\n title=\"刪除選取項目\"\n >\n <span style={SELECTION_DELETE_CONTROL_ICON_STYLE}>\n <Icon color=\"error\" icon={TrashIcon} size={16} />\n </span>\n </ControlButton>\n ) : null}\n </Controls>\n <AutoLayoutPanel onApplyAutoLayout={applyAutoLayout} />\n <MiniMap />\n </ReactFlow>\n </div>\n <div className={SIDE_PANEL_CLASS_NAME} style={PANEL_STYLE}>\n <Typography component=\"h2\" variant=\"h3\">\n 流程工具\n </Typography>\n {embedded && showAiAssistant ? (\n <div style={TOOL_GROUP_STYLE}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n AI 協助\n </Typography>\n <div style={BUTTON_ROW_STYLE}>\n <Button\n disabled={!aiAssistantAvailable}\n onClick={(): void =>\n setChatOpen((current) => !current)\n }\n size=\"sub\"\n variant={chatOpen ? 'base-primary' : 'base-secondary'}\n >\n {aiAssistantAvailable\n ? 'AI 助理'\n : 'AI 助理(未設定)'}\n </Button>\n </div>\n </div>\n ) : null}\n <div style={TOOL_GROUP_STYLE}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 動作節點\n </Typography>\n <div style={BUTTON_ROW_STYLE}>\n {ACTION_NODE_PALETTE.map((item) => (\n <Button\n icon={item.icon}\n iconType=\"leading\"\n key={item.type}\n onClick={(): void => addWorkflowNode(item.type)}\n size=\"sub\"\n variant=\"base-secondary\"\n >\n {item.label}\n </Button>\n ))}\n </div>\n </div>\n <div style={TOOL_GROUP_STYLE}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 流程控制\n </Typography>\n <div style={BUTTON_ROW_STYLE}>\n {FLOW_CONTROL_PALETTE.map((item) => (\n <Button\n icon={item.icon}\n iconType=\"leading\"\n key={item.type}\n onClick={(): void => addWorkflowNode(item.type)}\n size=\"sub\"\n variant=\"base-secondary\"\n >\n {item.label}\n </Button>\n ))}\n </div>\n </div>\n {selectedEdges.length > 1\n ? renderSelectedEdgesPanel(selectedEdges)\n : null}\n {selectedEdges.length === 1 && selectedEdge\n ? renderEdgePanel(selectedEdge)\n : null}\n {selectedEdges.length === 0 && selectedNode\n ? renderNodePanel(selectedNode)\n : null}\n </div>\n </div>\n </div>\n </Section>\n </SectionGroup>\n {renderEdgeSettingsModal(editingEdge)}\n {!embedded && showDryRun ? renderDryRunModal() : null}\n {showAiAssistant && aiAssistantAvailable ? (\n <WorkflowChatDrawer\n controller={controller}\n onClose={(): void => setChatOpen(false)}\n open={chatOpen}\n />\n ) : null}\n {!embedded ? (\n <Drawer\n headerTitle=\"編輯表單\"\n isHeaderDisplay\n onClose={(): void => setFormEditOpen(false)}\n open={formEditOpen}\n size=\"wide\"\n >\n <div style={FORM_EDIT_DRAWER_BODY_STYLE}>\n <div style={FORM_EDIT_DRAWER_CONTENT_STYLE}>\n {formDraftLoading ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中…\n </Typography>\n ) : (\n <FormBuilderView\n onChange={(next): void => {\n setFormDraft(next);\n }}\n value={\n formDraft ?? {\n schema: FORM_EDIT_EMPTY_SCHEMA,\n uiSchema: FORM_EDIT_EMPTY_UI_SCHEMA,\n }\n }\n />\n )}\n </div>\n <div style={FORM_EDIT_DRAWER_FOOTER_STYLE}>\n <Button\n disabled={formDraftLoading}\n onClick={(): void => {\n if (formDraft !== null) {\n setFormDraftDirty(true);\n controller.replaceState((current) => ({\n ...current,\n formSchema: formDraft.schema,\n }));\n }\n\n setFormEditOpen(false);\n }}\n variant=\"base-primary\"\n >\n 套用\n </Button>\n <Button\n onClick={(): void => setFormEditOpen(false)}\n variant=\"base-secondary\"\n >\n 取消\n </Button>\n </div>\n </div>\n </Drawer>\n ) : null}\n </>\n );\n\n function renderDryRunModal(): ReactElement {\n return (\n <Modal\n cancelText=\"關閉\"\n confirmText=\"執行試跑\"\n loading={dryRunRunning}\n modalType=\"standard\"\n onCancel={closeDryRunModal}\n onClose={closeDryRunModal}\n onConfirm={(): void => void handleDryRun()}\n open={dryRunModalOpen}\n showModalFooter\n showModalHeader\n size=\"wide\"\n supportingText={`使用 ${DRY_RUN_MEMBER_ID} 與範例表單資料模擬目前畫布流程,不會建立案件。`}\n title=\"試跑流程\"\n >\n <div style={FORM_STACK_STYLE}>\n <BPMFormField\n label=\"表單資料 JSON\"\n name=\"dryRunFormDataJson\"\n required\n >\n <Textarea\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void =>\n setDryRunFormDataJson(event.target.value)\n }\n resize=\"vertical\"\n rows={8}\n value={dryRunFormDataJson}\n />\n </BPMFormField>\n {dryRunError ? (\n <Typography color=\"text-error\" variant=\"body\">\n {dryRunError}\n </Typography>\n ) : null}\n {dryRunResult ? (\n <div style={DRY_RUN_RESULT_STYLE}>\n <Typography\n color={dryRunResult.valid ? 'text-success' : 'text-error'}\n variant=\"label-primary-highlight\"\n >\n {dryRunResult.valid ? '試跑通過' : '試跑失敗'}\n </Typography>\n {dryRunResult.errors.map((resultError) => (\n <Typography color=\"text-error\" key={resultError} variant=\"body\">\n {resultError}\n </Typography>\n ))}\n {dryRunResult.steps.map((step) => (\n <div key={step.id} style={DRY_RUN_STEP_STYLE}>\n <Typography variant=\"label-primary-highlight\">\n {step.nodeLabel} · {readDryRunStatusLabel(step.status)}\n </Typography>\n <Typography color=\"text-neutral\" variant=\"caption\">\n {readWorkflowNodeTypeLabel(step.nodeType)}\n {step.assigneeMemberId\n ? ` · 處理者:${step.assigneeMemberId}`\n : ''}\n {step.edgeLabel ? ` · 來源線段:${step.edgeLabel}` : ''}\n </Typography>\n {step.edgeReason ? (\n <Typography color=\"text-neutral\" variant=\"caption\">\n {step.edgeReason}\n </Typography>\n ) : null}\n {step.entryCondition ? (\n <Typography color=\"text-neutral\" variant=\"caption\">\n 進入條件:\n {step.entryConditionMatched ? '符合' : '不符合'} ·{' '}\n {step.entryCondition}\n </Typography>\n ) : null}\n <Typography color=\"text-neutral\" variant=\"body\">\n {step.message}\n </Typography>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n </Modal>\n );\n }\n\n function renderNodePanel(node: WorkflowNode): ReactElement {\n return (\n <div style={FORM_STACK_STYLE}>\n <Typography component=\"h2\" variant=\"h3\">\n 節點屬性\n </Typography>\n <Typography color=\"text-neutral\" variant=\"body\">\n {NODE_TYPE_LABELS[node.type]} · {node.id}\n </Typography>\n <BPMFormField label=\"顯示名稱\" name=\"nodeLabel\" required>\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateSelectedNodeLabel(event.target.value)\n }\n value={node.data.label}\n variant=\"base\"\n />\n </BPMFormField>\n {node.type === 'startEvent' ? renderStartEventPanel() : null}\n {node.type !== 'startEvent' ? renderNodeTriggerModePanel(node) : null}\n {node.type === 'userTask' ? renderUserTaskPanel(node) : null}\n {node.type === 'serviceTask' ? renderServiceTaskPanel(node) : null}\n </div>\n );\n }\n\n function renderStartEventPanel(): ReactElement {\n const policyModeOptions =\n initiatorPolicyDraft.mode === 'CUSTOM'\n ? [...INITIATOR_POLICY_MODE_OPTIONS, INITIATOR_POLICY_CUSTOM_OPTION]\n : [...INITIATOR_POLICY_MODE_OPTIONS];\n const selectedInitiatorOrgUnit =\n initiatorPolicyDraft.mode === 'ORG_UNIT' ||\n initiatorPolicyDraft.mode === 'ORG_UNIT_POSITION'\n ? readSelectedOrgUnitOption(\n orgUnits,\n initiatorPolicyDraft.orgUnitId ?? '',\n )\n : null;\n const selectedInitiatorPosition =\n initiatorPolicyDraft.mode === 'ORG_UNIT_POSITION'\n ? readSelectedPositionOption(\n positions,\n initiatorPolicyDraft.positionId ?? '',\n )\n : null;\n const initiatorScopedPositions =\n initiatorPolicyDraft.mode === 'ORG_UNIT_POSITION'\n ? readOrgScopedPositions({\n includeDescendants: Boolean(\n initiatorPolicyDraft.includeDescendants,\n ),\n memberships,\n orgUnitId: initiatorPolicyDraft.orgUnitId ?? '',\n orgUnits,\n positions,\n })\n : [];\n\n return (\n <>\n <BPMFormField\n hintText={\n initiatorPolicyDraft.mode === 'CUSTOM'\n ? '這是舊版表達式規則;切換成標準選項後會改由 UI 管理。'\n : undefined\n }\n label=\"發起權限\"\n name=\"initiatorPolicyMode\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void => {\n if (option?.id === 'CUSTOM') {\n setInitiatorPolicyModeDraft(null);\n setInitiatorPolicyDraftOverride(null);\n\n return;\n }\n\n const mode = readInitiatorPolicyMode(option?.id ?? null);\n const draft = readDefaultInitiatorPolicyDraft(mode);\n\n setInitiatorPolicyModeDraft(mode === 'ALL' ? null : mode);\n setInitiatorPolicyDraftOverride(mode === 'ALL' ? null : draft);\n setInitiatorPolicyCel(\n readInitiatorPolicyCel(draft, orgUnits),\n );\n }}\n options={policyModeOptions}\n placeholder=\"選擇誰可以發起\"\n value={readSelectOption(\n policyModeOptions,\n initiatorPolicyDraft.mode,\n )}\n />\n </BPMFormField>\n {initiatorPolicyDraft.mode === 'ORG_UNIT' ||\n initiatorPolicyDraft.mode === 'ORG_UNIT_POSITION' ? (\n <BPMFormField label=\"組織\" name=\"initiatorOrgUnitId\" required>\n <OrgUnitPicker\n name=\"initiatorOrgUnitId\"\n onChange={(option): void =>\n updateInitiatorPolicyDraft({\n ...initiatorPolicyDraft,\n orgUnitId: option?.id ?? '',\n positionId: '',\n value: option?.id ?? '',\n })\n }\n orgUnits={orgUnits}\n placeholder=\"選擇組織\"\n value={selectedInitiatorOrgUnit}\n />\n </BPMFormField>\n ) : null}\n {initiatorPolicyDraft.mode === 'ORG_UNIT' ||\n initiatorPolicyDraft.mode === 'ORG_UNIT_POSITION' ? (\n <BPMFormField label=\"包含下層\" name=\"initiatorIncludeDescendants\">\n <Toggle\n checked={Boolean(initiatorPolicyDraft.includeDescendants)}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateInitiatorPolicyDraft({\n ...initiatorPolicyDraft,\n includeDescendants: event.target.checked,\n ...(initiatorPolicyDraft.mode === 'ORG_UNIT_POSITION'\n ? { positionId: '' }\n : {}),\n })\n }\n />\n </BPMFormField>\n ) : null}\n {initiatorPolicyDraft.mode === 'ORG_UNIT_POSITION' ? (\n <BPMFormField label=\"職位\" name=\"initiatorPositionId\" required>\n <PositionPicker\n disabled={!initiatorPolicyDraft.orgUnitId?.trim()}\n name=\"initiatorPositionId\"\n onChange={(option): void =>\n updateInitiatorPolicyDraft({\n ...initiatorPolicyDraft,\n positionId: option?.id ?? '',\n })\n }\n placeholder={\n initiatorPolicyDraft.orgUnitId?.trim()\n ? '選擇職位'\n : '請先選擇組織'\n }\n positions={initiatorScopedPositions}\n value={selectedInitiatorPosition}\n />\n </BPMFormField>\n ) : null}\n </>\n );\n }\n\n function renderNodeTriggerModePanel(\n node: Exclude<WorkflowNode, { type: 'startEvent' }>,\n ): ReactElement {\n const incomingEdgeCount = workflowDefinition.edges.filter(\n (edge) => edge.target === node.id,\n ).length;\n const triggerModeLocked = incomingEdgeCount < 2;\n const triggerMode = triggerModeLocked\n ? 'AND'\n : (node.data.triggerMode ?? 'AND');\n\n return (\n <BPMFormField\n hintText={\n triggerModeLocked\n ? '需要至少兩條前置連線,才可切換為任一前置完成。'\n : incomingEdgeCount > 1\n ? `${incomingEdgeCount} 條前置連線會依此規則觸發。`\n : '只有一條前置連線時,兩種設定效果相同。'\n }\n label=\"前置條件\"\n name=\"triggerMode\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n triggerModeLocked\n ? undefined\n : updateSelectedNodeTriggerMode(\n readWorkflowNodeTriggerMode(option?.id ?? null),\n )\n }\n options={[...NODE_TRIGGER_MODE_OPTIONS]}\n readOnly={triggerModeLocked}\n value={readSelectOption(NODE_TRIGGER_MODE_OPTIONS, triggerMode)}\n />\n </BPMFormField>\n );\n }\n\n function renderUserTaskPanel(\n node: Extract<WorkflowNode, { type: 'userTask' }>,\n ): ReactElement {\n const resolver = node.data.approverResolver;\n const resolverMode = readApproverResolverMode(resolver.type);\n const selectedMember =\n resolver.type === 'DIRECT'\n ? readPrimaryMemberOption(resolver.memberIds, memberOptions)\n : null;\n const selectedOrgUnit =\n resolver.type === 'ORG_UNIT_MANAGER' ||\n resolver.type === 'ORG_UNIT_MEMBER' ||\n resolver.type === 'ORG_UNIT_POSITION'\n ? readSelectedOrgUnitOption(orgUnits, resolver.orgUnitId)\n : null;\n const selectedPosition =\n resolver.type === 'POSITION' || resolver.type === 'ORG_UNIT_POSITION'\n ? readSelectedPositionOption(positions, resolver.positionId)\n : null;\n const orgScopedPositions =\n resolver.type === 'ORG_UNIT_POSITION'\n ? readOrgScopedPositions({\n includeDescendants: Boolean(resolver.includeDescendants),\n memberships,\n orgUnitId: resolver.orgUnitId,\n orgUnits,\n positions,\n })\n : [];\n const selectedManagerLevel =\n resolver.type === 'ORG_MANAGER'\n ? readManagerLevelOption(resolver.levelsUp)\n : MANAGER_LEVEL_OPTIONS[0];\n const fallback =\n resolver.type === 'ORG_MANAGER' || resolver.type === 'ORG_UNIT_MANAGER'\n ? (resolver.fallback ?? { type: 'NONE' as const })\n : { type: 'NONE' as const };\n const fallbackMember =\n fallback.type === 'DIRECT'\n ? readMemberSelectOption(memberOptions, fallback.memberId)\n : null;\n const resubmitStrategy =\n node.data.returnBehavior.resubmitStrategy ?? 'RESTART';\n\n return (\n <>\n <BPMFormField label=\"簽核來源\" name=\"approverResolverType\" required>\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskResolver(\n readDefaultApproverResolver(option?.id ?? null),\n )\n }\n options={[...APPROVER_RESOLVER_MODE_OPTIONS]}\n value={readSelectOption(\n APPROVER_RESOLVER_MODE_OPTIONS,\n resolverMode,\n )}\n />\n </BPMFormField>\n {resolver.type === 'DIRECT' ? (\n <BPMFormField label=\"簽核者\" name=\"memberId\" required>\n <AutoComplete\n asyncData\n disabledOptionsFilter\n emptyText=\"沒有符合的成員\"\n inputProps={{\n autoCapitalize: 'none',\n autoCorrect: 'off',\n name: 'workflow-approver-search',\n spellCheck: false,\n }}\n loading={memberLoading}\n loadingText=\"搜尋成員中...\"\n mode=\"single\"\n onChange={(option): void =>\n updateUserTaskResolver({\n memberIds: option?.id ? [option.id] : [],\n type: 'DIRECT',\n })\n }\n onSearch={handleSearchMembers}\n onVisibilityChange={(open): void => {\n if (open) {\n void handleSearchMembers('');\n }\n }}\n options={[...memberOptions]}\n placeholder=\"搜尋姓名或信箱\"\n searchDebounceTime={300}\n value={selectedMember}\n />\n </BPMFormField>\n ) : null}\n {resolver.type === 'ORG_MANAGER' ? (\n <BPMFormField\n hintText=\"依發起人的有效會員歸屬與主管解析規則決定簽核人。\"\n label=\"主管層級\"\n name=\"managerLevelsUp\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskResolver({\n baseFromInitiator: true,\n levelsUp: readManagerLevelOptionById(option?.id ?? null)\n .value,\n type: 'ORG_MANAGER',\n })\n }\n options={[...MANAGER_LEVEL_OPTIONS]}\n value={selectedManagerLevel}\n />\n </BPMFormField>\n ) : null}\n {resolver.type === 'ORG_UNIT_MANAGER' ||\n resolver.type === 'ORG_UNIT_MEMBER' ||\n resolver.type === 'ORG_UNIT_POSITION' ? (\n <BPMFormField\n hintText={\n resolver.type === 'ORG_UNIT_MANAGER'\n ? '依指定組織或其上層的主管解析規則決定簽核人。'\n : '依指定組織目前有效會員歸屬建立候選簽核人。'\n }\n label=\"組織\"\n name=\"orgUnitId\"\n required\n >\n <OrgUnitPicker\n name=\"orgUnitId\"\n onChange={(option): void =>\n updateUserTaskResolver(\n resolver.type === 'ORG_UNIT_MEMBER'\n ? {\n includeDescendants: resolver.includeDescendants,\n orgUnitId: option?.id ?? '',\n type: 'ORG_UNIT_MEMBER',\n }\n : resolver.type === 'ORG_UNIT_POSITION'\n ? {\n includeDescendants: resolver.includeDescendants,\n orgUnitId: option?.id ?? '',\n positionId: '',\n type: 'ORG_UNIT_POSITION',\n }\n : {\n fallback: resolver.fallback,\n orgUnitId: option?.id ?? '',\n type: 'ORG_UNIT_MANAGER',\n },\n )\n }\n orgUnits={orgUnits}\n placeholder=\"選擇組織\"\n value={selectedOrgUnit}\n />\n </BPMFormField>\n ) : null}\n {resolver.type === 'ORG_MANAGER' ||\n resolver.type === 'ORG_UNIT_MANAGER' ? (\n <>\n <BPMFormField\n hintText=\"預設會停止流程並提示;若設定固定人,找不到主管時會改派給該會員。\"\n label=\"無主管時\"\n name=\"approverFallbackMode\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskResolver(\n updateApproverResolverFallback(\n resolver,\n readApproverFallbackMode(option?.id ?? null) === 'DIRECT'\n ? { memberId: '', type: 'DIRECT' }\n : { type: 'NONE' },\n ),\n )\n }\n options={[...APPROVER_FALLBACK_MODE_OPTIONS]}\n value={readSelectOption(\n APPROVER_FALLBACK_MODE_OPTIONS,\n fallback.type,\n )}\n />\n </BPMFormField>\n {fallback.type === 'DIRECT' ? (\n <>\n <BPMFormField\n label=\"改派人員\"\n name=\"approverFallbackMemberId\"\n required\n >\n <AutoComplete\n asyncData\n disabledOptionsFilter\n emptyText=\"沒有符合的成員\"\n inputProps={{\n autoCapitalize: 'none',\n autoCorrect: 'off',\n name: 'workflow-approver-fallback-search',\n spellCheck: false,\n }}\n loading={memberLoading}\n loadingText=\"搜尋成員中...\"\n mode=\"single\"\n onChange={(option): void =>\n updateUserTaskResolver(\n updateApproverResolverFallback(resolver, {\n allowInitiatorSelfApproval:\n fallback.allowInitiatorSelfApproval,\n memberId: option?.id ?? '',\n type: 'DIRECT',\n }),\n )\n }\n onSearch={handleSearchMembers}\n onVisibilityChange={(open): void => {\n if (open) {\n void handleSearchMembers('');\n }\n }}\n options={[...memberOptions]}\n placeholder=\"搜尋姓名或信箱\"\n searchDebounceTime={300}\n value={fallbackMember}\n />\n </BPMFormField>\n <BPMFormField\n hintText=\"預設禁止申請人簽自己的案件;只有此流程允許自簽時才開啟。\"\n label=\"允許自簽\"\n name=\"allowInitiatorSelfApproval\"\n >\n <Toggle\n checked={Boolean(fallback.allowInitiatorSelfApproval)}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskResolver(\n updateApproverResolverFallback(resolver, {\n allowInitiatorSelfApproval: event.target.checked,\n memberId: fallback.memberId,\n type: 'DIRECT',\n }),\n )\n }\n />\n </BPMFormField>\n </>\n ) : null}\n </>\n ) : null}\n {resolver.type === 'ORG_UNIT_MEMBER' ||\n resolver.type === 'ORG_UNIT_POSITION' ? (\n <BPMFormField label=\"包含下層\" name=\"includeDescendants\">\n <Toggle\n checked={Boolean(resolver.includeDescendants)}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskResolver({\n ...resolver,\n includeDescendants: event.target.checked,\n ...(resolver.type === 'ORG_UNIT_POSITION'\n ? { positionId: '' }\n : {}),\n })\n }\n />\n </BPMFormField>\n ) : null}\n {resolver.type === 'POSITION' ? (\n <BPMFormField\n hintText=\"指派給目前有效歸屬中擁有此職位的會員;主要歸屬優先。\"\n label=\"職位\"\n name=\"positionId\"\n required\n >\n <PositionPicker\n name=\"positionId\"\n onChange={(option): void =>\n updateUserTaskResolver({\n positionId: option?.id ?? '',\n type: 'POSITION',\n })\n }\n placeholder=\"選擇職位\"\n positions={positions}\n value={selectedPosition}\n />\n </BPMFormField>\n ) : null}\n {resolver.type === 'ORG_UNIT_POSITION' ? (\n <BPMFormField\n hintText=\"只納入指定組織範圍內擁有此職位的有效會員。\"\n label=\"職位\"\n name=\"orgUnitPositionId\"\n required\n >\n <PositionPicker\n disabled={!resolver.orgUnitId.trim()}\n name=\"orgUnitPositionId\"\n onChange={(option): void =>\n updateUserTaskResolver({\n includeDescendants: resolver.includeDescendants,\n orgUnitId: resolver.orgUnitId,\n positionId: option?.id ?? '',\n type: 'ORG_UNIT_POSITION',\n })\n }\n placeholder={\n resolver.orgUnitId.trim() ? '選擇職位' : '請先選擇組織'\n }\n positions={orgScopedPositions}\n value={selectedPosition}\n />\n </BPMFormField>\n ) : null}\n {node.data.returnBehavior.allowReturn ? (\n <BPMFormField\n hintText=\"退回發起人後,重新送出時要從流程開始重跑,或直接回到退回的簽核節點。\"\n label=\"重送策略\"\n name=\"returnResubmitStrategy\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskReturnResubmitStrategy(\n readReturnResubmitStrategy(option?.id ?? null),\n )\n }\n options={[...RETURN_RESUBMIT_STRATEGY_OPTIONS]}\n value={readSelectOption(\n RETURN_RESUBMIT_STRATEGY_OPTIONS,\n resubmitStrategy,\n )}\n />\n </BPMFormField>\n ) : null}\n </>\n );\n }\n\n function renderServiceTaskPanel(\n node: Extract<WorkflowNode, { type: 'serviceTask' }>,\n ): ReactElement {\n const selectedMembers = readServiceTaskMemberIds(node.data.action).map(\n (memberId) => readMemberSelectOption(memberOptions, memberId),\n );\n\n return (\n <BPMFormField label=\"知會對象\" name=\"notifyMemberIds\" required>\n <AutoComplete\n asyncData\n disabledOptionsFilter\n emptyText=\"沒有符合的成員\"\n loading={memberLoading}\n loadingText=\"搜尋成員中...\"\n mode=\"multiple\"\n onChange={(options): void =>\n updateServiceAction({\n channels: ['IN_APP'],\n recipients: {\n memberIds: options.map((option) => option.id),\n type: 'DIRECT',\n },\n type: 'NOTIFY',\n })\n }\n onSearch={handleSearchMembers}\n onVisibilityChange={(open): void => {\n if (open) {\n void handleSearchMembers('');\n }\n }}\n options={[...memberOptions]}\n overflowStrategy=\"wrap\"\n placeholder=\"搜尋姓名或信箱\"\n searchDebounceTime={300}\n value={[...selectedMembers]}\n />\n </BPMFormField>\n );\n }\n\n function renderSelectedEdgesPanel(\n edges: readonly WorkflowEdge[],\n ): ReactElement {\n return (\n <div style={FORM_STACK_STYLE}>\n <Typography component=\"h2\" variant=\"h3\">\n 已選取線段\n </Typography>\n <Typography color=\"text-neutral\" variant=\"body\">\n 已選取 {edges.length} 條線段,可使用 Delete 或控制面板刪除。\n </Typography>\n </div>\n );\n }\n\n function renderEdgePanel(edge: WorkflowEdge): ReactElement {\n const isConditionPath = isExclusiveGatewaySourceEdge(\n edge,\n workflowDefinition.nodes,\n );\n\n return (\n <div style={FORM_STACK_STYLE}>\n <Typography component=\"h2\" variant=\"h3\">\n {isConditionPath ? '條件設定' : '線段屬性'}\n </Typography>\n <Typography color=\"text-neutral\" variant=\"body\">\n {edge.source} → {edge.target}\n </Typography>\n {isConditionPath ? (\n renderConditionEdgeSettingsForm(edge)\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 這條線會直接把流程送到下一個節點。\n </Typography>\n )}\n </div>\n );\n }\n\n function renderEdgeSettingsModal(\n edge: WorkflowEdge | null,\n ): ReactElement | null {\n if (!edge) {\n return null;\n }\n\n const isConditionPath = isExclusiveGatewaySourceEdge(\n edge,\n workflowDefinition.nodes,\n );\n\n if (!isConditionPath) {\n return null;\n }\n\n return (\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{\n disabled: !edge.data.isDefault && !edge.data.condition,\n }}\n confirmText=\"完成\"\n modalType=\"standard\"\n onCancel={closeEdgeSettingsModal}\n onClose={closeEdgeSettingsModal}\n onConfirm={closeEdgeSettingsModal}\n open={Boolean(editingEdgeId)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n supportingText=\"條件分流的輸出連線需要指定條件,條件會直接顯示在線上。\"\n title=\"條件設定\"\n >\n {renderConditionEdgeSettingsForm(edge)}\n </Modal>\n );\n }\n\n function renderConditionEdgeSettingsForm(edge: WorkflowEdge): ReactElement {\n const pathLabelPreview = readEdgeCanvasLabel(\n edge,\n workflowDefinition.nodes,\n );\n const conditionFieldOptions = readConditionFieldOptions(\n selectedFormVersionOption?.schema ?? null,\n );\n const selectedConditionField = readConditionField(\n selectedFormVersionOption?.schema ?? null,\n edge.data.conditionFieldKey ?? null,\n );\n const conditionOperatorOptions = readConditionOperatorOptions(\n selectedConditionField,\n );\n const conditionValueOptions = readConditionValueOptions(\n selectedConditionField,\n );\n const selectedConditionOperator = readSelectOption(\n conditionOperatorOptions,\n edge.data.conditionOperator ?? null,\n );\n const pathLabelIsIncomplete = !edge.data.isDefault && !edge.data.condition;\n\n return (\n <div style={FORM_STACK_STYLE}>\n <Typography color=\"text-neutral\" variant=\"body\">\n 畫布上的這條線目前會顯示「\n <span\n style={{\n color: pathLabelIsIncomplete\n ? INCOMPLETE_CONDITION_EDGE_COLOR\n : undefined,\n }}\n >\n {pathLabelPreview ?? '請設定條件'}\n </span>\n 」。\n </Typography>\n <Toggle\n checked={Boolean(edge.data.isDefault)}\n label=\"其他情況走這條\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateSelectedEdgeDefault(edge.id, event.target.checked)\n }\n />\n {edge.data.isDefault ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 其他條件都不符合時,流程會走這條線。\n </Typography>\n ) : (\n <>\n {!selectedFormVersionOption ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 請先綁定表單版本,才能選擇條件欄位。\n </Typography>\n ) : null}\n <BPMFormField label=\"條件欄位\" name=\"edgeConditionField\" required>\n <Select\n clearable={false}\n onChange={(option): void =>\n updateSelectedEdgeConditionState({\n edgeId: edge.id,\n fieldKey: option?.id ?? null,\n operator: null,\n value: null,\n })\n }\n options={[...conditionFieldOptions]}\n placeholder=\"選擇條件欄位\"\n value={readSelectOption(\n conditionFieldOptions,\n edge.data.conditionFieldKey ?? null,\n )}\n />\n </BPMFormField>\n <BPMFormField\n label=\"條件判斷\"\n name=\"edgeConditionOperator\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateSelectedEdgeConditionState({\n edgeId: edge.id,\n operator: readConditionOperator(option?.id ?? null),\n value: null,\n })\n }\n options={[...conditionOperatorOptions]}\n placeholder=\"選擇判斷方式\"\n value={selectedConditionOperator}\n />\n </BPMFormField>\n {selectedConditionOperator &&\n shouldConditionOperatorUseValue(selectedConditionOperator.id) ? (\n <BPMFormField label=\"條件值\" name=\"edgeConditionValue\" required>\n {conditionValueOptions.length > 0 ? (\n <Select\n clearable={false}\n onChange={(option): void =>\n updateSelectedEdgeConditionState({\n edgeId: edge.id,\n value: option?.id ?? null,\n })\n }\n options={[...conditionValueOptions]}\n placeholder=\"選擇條件值\"\n value={readSelectOption(\n conditionValueOptions,\n edge.data.conditionValue ?? null,\n )}\n />\n ) : (\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateSelectedEdgeConditionState({\n edgeId: edge.id,\n value: event.target.value,\n })\n }\n placeholder=\"輸入要比對的值\"\n value={edge.data.conditionValue ?? ''}\n variant=\"base\"\n />\n )}\n </BPMFormField>\n ) : null}\n </>\n )}\n </div>\n );\n }\n}\n\nfunction AutoLayoutPanel({\n onApplyAutoLayout,\n}: {\n readonly onApplyAutoLayout: () => void;\n}): ReactElement {\n function handleAutoLayout(): void {\n onApplyAutoLayout();\n }\n\n return (\n <Panel position=\"top-right\">\n <Button\n icon={DotGridIcon}\n iconType=\"leading\"\n onClick={handleAutoLayout}\n size=\"sub\"\n variant=\"base-secondary\"\n >\n 自動排版\n </Button>\n </Panel>\n );\n}\n\nfunction WorkflowNodeCard({\n data,\n selected,\n type,\n}: NodeProps<FlowNode>): ReactElement {\n const primaryLabels = data.approverLines ?? [\n data.approverSummary ?? data.label,\n ];\n const secondaryLabel = readWorkflowNodeSecondaryLabel(data);\n const nodeStyle = readWorkflowNodeCardStyle(type, selected);\n\n return (\n <div style={nodeStyle}>\n {renderWorkflowNodeHandles(data)}\n <div style={NODE_PRIMARY_LABELS_STYLE}>\n {primaryLabels.map((primaryLabel, index) => (\n <Typography\n component=\"span\"\n ellipsis\n key={`${primaryLabel}_${index}`}\n style={NODE_TEXT_STYLE}\n title={primaryLabel}\n variant=\"label-primary\"\n >\n {primaryLabel}\n </Typography>\n ))}\n </div>\n <Typography\n color=\"text-neutral\"\n component=\"span\"\n ellipsis\n style={NODE_TEXT_STYLE}\n title={secondaryLabel}\n variant=\"caption\"\n >\n {secondaryLabel}\n </Typography>\n </div>\n );\n}\n\nfunction readWorkflowNodeSecondaryLabel(data: FlowNodeData): string {\n if (data.nodeKind === 'startEvent') {\n return data.initiatorPolicySummary ?? '所有人';\n }\n\n if (data.approverSummary || data.approverLines) {\n return data.label;\n }\n\n if (data.nodeKind === 'exclusiveGateway') {\n return '條件在線上';\n }\n\n if (data.nodeKind === 'parallelGateway') {\n return '多條路徑同時進行';\n }\n\n return NODE_TYPE_LABELS[data.nodeKind];\n}\n\nfunction readWorkflowNodeCardStyle(\n type: WorkflowNode['type'],\n selected: boolean,\n): CSSProperties {\n const baseStyle = readWorkflowNodeBaseCardStyle(type);\n\n return selected\n ? {\n ...baseStyle,\n border: '1px solid var(--mzn-color-primary, #0057ff)',\n boxShadow: SELECTED_NODE_BOX_SHADOW,\n }\n : baseStyle;\n}\n\nfunction readWorkflowNodeBaseCardStyle(\n type: WorkflowNode['type'],\n): CSSProperties {\n if (type === 'exclusiveGateway') {\n return EXCLUSIVE_GATEWAY_NODE_STYLE;\n }\n\n if (type === 'parallelGateway') {\n return PARALLEL_GATEWAY_NODE_STYLE;\n }\n\n if (type === 'startEvent') {\n return START_NODE_STYLE;\n }\n\n if (type === 'endEvent') {\n return END_NODE_STYLE;\n }\n\n if (type === 'userTask') {\n return USER_TASK_NODE_STYLE;\n }\n\n return NODE_STYLE;\n}\n\nfunction renderWorkflowNodeHandles(\n data: FlowNodeData,\n): ReactElement | readonly ReactElement[] | null {\n if (!data.hasInput && data.hasOutput) {\n return (\n <Handle\n id={WORKFLOW_OUTPUT_HANDLE_ID}\n position={Position.Right}\n type=\"source\"\n />\n );\n }\n\n if (data.hasInput && !data.hasOutput) {\n return (\n <Handle\n id={WORKFLOW_INPUT_HANDLE_ID}\n position={Position.Left}\n type=\"target\"\n />\n );\n }\n\n if (!data.hasInput && !data.hasOutput) {\n return null;\n }\n\n return [\n <Handle\n id={WORKFLOW_INPUT_HANDLE_ID}\n key=\"target\"\n position={Position.Left}\n type=\"target\"\n />,\n <Handle\n id={WORKFLOW_OUTPUT_HANDLE_ID}\n key=\"source\"\n position={Position.Right}\n type=\"source\"\n />,\n ];\n}\n\nfunction readFlowNode(\n node: WorkflowNode,\n memberOptions: readonly MemberSelectOption[],\n orgUnits: readonly OrgUnitRecord[],\n positions: readonly PositionRecord[],\n selected: boolean,\n initiatorPolicyDraft: InitiatorPolicyDraft,\n): FlowNode {\n const dimensions = readWorkflowNodeDimensions(node);\n\n return {\n data: {\n approverLines: readNodeApproverLines(node, memberOptions),\n approverSummary: readNodeApproverSummary(\n node,\n memberOptions,\n orgUnits,\n positions,\n ),\n hasInput: isWorkflowNodeInputConnectable(node),\n hasOutput: isWorkflowNodeOutputConnectable(node),\n initiatorPolicySummary:\n node.type === 'startEvent'\n ? readInitiatorPolicySummary(\n initiatorPolicyDraft,\n orgUnits,\n positions,\n )\n : null,\n label: node.data.label,\n nodeKind: node.type,\n },\n height: dimensions.height,\n handles: readFlowNodeHandles(node),\n id: node.id,\n initialHeight: dimensions.height,\n initialWidth: dimensions.width,\n position: node.position,\n selected,\n sourcePosition: Position.Right,\n targetPosition: Position.Left,\n type: node.type,\n width: dimensions.width,\n };\n}\n\nfunction readWorkflowNodeDimensions(\n node: WorkflowNode,\n): Readonly<{ height: number; width: number }> {\n if (node.type === 'exclusiveGateway' || node.type === 'parallelGateway') {\n return {\n height: GATEWAY_NODE_INITIAL_HEIGHT,\n width: GATEWAY_NODE_INITIAL_WIDTH,\n };\n }\n\n if (node.type === 'serviceTask') {\n const memberCount = Math.max(\n 1,\n readServiceTaskMemberIds(node.data.action).length,\n );\n\n return {\n height:\n FLOW_NODE_INITIAL_HEIGHT +\n (memberCount - 1) * FLOW_NODE_ADDITIONAL_LINE_HEIGHT,\n width: FLOW_NODE_INITIAL_WIDTH,\n };\n }\n\n return {\n height: FLOW_NODE_INITIAL_HEIGHT,\n width: FLOW_NODE_INITIAL_WIDTH,\n };\n}\n\nfunction readFlowNodeHandles(node: WorkflowNode): FlowNodeHandle[] {\n const dimensions = readWorkflowNodeDimensions(node);\n\n return [\n ...(isWorkflowNodeInputConnectable(node)\n ? [readTargetFlowNodeHandle(dimensions)]\n : []),\n ...(isWorkflowNodeOutputConnectable(node)\n ? [readSourceFlowNodeHandle(dimensions)]\n : []),\n ];\n}\n\nfunction readTargetFlowNodeHandle({\n height,\n}: Readonly<{ height: number; width: number }>): FlowNodeHandle {\n const handleSize = 9;\n const centeredHandleY = height / 2 - handleSize / 2;\n\n return {\n height: handleSize,\n id: WORKFLOW_INPUT_HANDLE_ID,\n position: Position.Left,\n type: 'target',\n width: handleSize,\n x: -handleSize / 2,\n y: centeredHandleY,\n };\n}\n\nfunction readSourceFlowNodeHandle({\n height,\n width,\n}: Readonly<{ height: number; width: number }>): FlowNodeHandle {\n const handleSize = 9;\n const centeredHandleY = height / 2 - handleSize / 2;\n\n return {\n height: handleSize,\n id: WORKFLOW_OUTPUT_HANDLE_ID,\n position: Position.Right,\n type: 'source',\n width: handleSize,\n x: width - handleSize / 2,\n y: centeredHandleY,\n };\n}\n\nfunction readFlowEdge(\n edge: WorkflowEdge,\n nodes: readonly WorkflowNode[],\n selected: boolean,\n): FlowEdge {\n const label = readEdgeCanvasLabel(edge, nodes);\n const isConditionEdge = isExclusiveGatewaySourceEdge(edge, nodes);\n const isIncompleteConditionEdge =\n isConditionEdge && !edge.data.isDefault && !edge.data.condition;\n const labelColor = isIncompleteConditionEdge\n ? INCOMPLETE_CONDITION_EDGE_COLOR\n : isConditionEdge\n ? CONDITION_EDGE_COLOR\n : '#475569';\n const labelBackgroundColor = isIncompleteConditionEdge\n ? '#fef2f2'\n : isConditionEdge\n ? '#eff6ff'\n : '#ffffff';\n const labelBorderColor = isIncompleteConditionEdge\n ? INCOMPLETE_CONDITION_EDGE_COLOR\n : isConditionEdge\n ? CONDITION_EDGE_COLOR\n : DEFAULT_EDGE_COLOR;\n\n return {\n className: selected ? 'workflow-edge--selected' : undefined,\n data: edge.data,\n id: edge.id,\n label,\n labelBgBorderRadius: 6,\n labelBgPadding: [8, 4],\n labelBgStyle: {\n fill: labelBackgroundColor,\n stroke: labelBorderColor,\n strokeWidth: 1,\n },\n labelShowBg: Boolean(label),\n labelStyle: {\n fill: labelColor,\n fontSize: 12,\n fontWeight: 600,\n },\n selected,\n source: edge.source,\n sourceHandle: edge.sourceHandle,\n style: {\n filter: selected ? SELECTED_EDGE_GLOW_FILTER : undefined,\n opacity: 1,\n stroke: DEFAULT_EDGE_COLOR,\n strokeOpacity: 1,\n strokeWidth: 1.5,\n },\n target: edge.target,\n targetHandle: edge.targetHandle,\n type: edge.type ?? 'smoothstep',\n };\n}\n\nfunction applyWorkflowNodeTriggerMode(\n node: WorkflowNode,\n triggerMode: WorkflowNodeTriggerMode,\n): WorkflowNode {\n if (node.type === 'startEvent') {\n return node;\n }\n\n if (node.type === 'endEvent') {\n return { ...node, data: { ...node.data, triggerMode } };\n }\n\n if (node.type === 'userTask') {\n return { ...node, data: { ...node.data, triggerMode } };\n }\n\n if (node.type === 'serviceTask') {\n return { ...node, data: { ...node.data, triggerMode } };\n }\n\n if (node.type === 'exclusiveGateway') {\n return { ...node, data: { ...node.data, triggerMode } };\n }\n\n return { ...node, data: { ...node.data, triggerMode } };\n}\n\nfunction normalizeDesignerWorkflowDefinition(\n definition: WorkflowDefinition,\n): WorkflowDefinition {\n return normalizeSingleIncomingTriggerModes(\n removeAsyncNotifyOutgoingEdges(definition),\n );\n}\n\nfunction removeAsyncNotifyOutgoingEdges(\n definition: WorkflowDefinition,\n): WorkflowDefinition {\n const asyncNotifyNodeIds = new Set(\n definition.nodes\n .filter((node) => isAsyncNotifyServiceTask(node))\n .map((node) => node.id),\n );\n const edges = definition.edges.filter(\n (edge) => !asyncNotifyNodeIds.has(edge.source),\n );\n\n return edges.length === definition.edges.length\n ? definition\n : { ...definition, edges };\n}\n\nfunction normalizeSingleIncomingTriggerModes(\n definition: WorkflowDefinition,\n): WorkflowDefinition {\n const incomingEdgeCounts = definition.edges.reduce<Record<string, number>>(\n (counts, edge) => ({\n ...counts,\n [edge.target]: (counts[edge.target] ?? 0) + 1,\n }),\n {},\n );\n const nodes = definition.nodes.map((node) => {\n if (node.type === 'startEvent') {\n return node;\n }\n\n const incomingEdgeCount = incomingEdgeCounts[node.id] ?? 0;\n\n return incomingEdgeCount < 2 && node.data.triggerMode !== 'AND'\n ? applyWorkflowNodeTriggerMode(node, 'AND')\n : node;\n });\n const hasNodeChanges = nodes.some(\n (node, index) => node !== definition.nodes[index],\n );\n\n return hasNodeChanges ? { ...definition, nodes } : definition;\n}\n\nfunction readFallbackWorkflowDefinition(): WorkflowDefinition {\n return {\n edges: [],\n meta: { schemaVersion: 1 },\n nodes: [\n {\n data: { label: '開始' },\n id: 'start',\n position: { x: 80, y: 160 },\n type: 'startEvent',\n },\n {\n data: { endState: 'APPROVED', label: '完成', triggerMode: 'AND' },\n id: 'end',\n position: { x: 560, y: 160 },\n type: 'endEvent',\n },\n ],\n };\n}\n\nfunction isEmptyDesignerWorkflowDefinition(\n definition: WorkflowDefinition,\n): boolean {\n return (\n definition.edges.length === 0 &&\n definition.nodes.length === 2 &&\n definition.nodes.some((node) => node.type === 'startEvent') &&\n definition.nodes.some((node) => node.type === 'endEvent')\n );\n}\n\nfunction layoutWorkflowDefinition(\n definition: WorkflowDefinition,\n): WorkflowDefinition {\n const graph = new dagre.graphlib.Graph();\n graph.setDefaultEdgeLabel(() => ({}));\n graph.setGraph({ rankdir: 'LR', ranksep: 120 });\n definition.nodes.forEach((node): void => {\n graph.setNode(node.id, readWorkflowNodeDimensions(node));\n });\n definition.edges.forEach((edge): void => {\n graph.setEdge(edge.source, edge.target);\n });\n dagre.layout(graph);\n\n return {\n ...definition,\n nodes: definition.nodes.map((node) => {\n const positionedNode = graph.node(node.id) as\n | { readonly x: number; readonly y: number }\n | undefined;\n\n return positionedNode\n ? {\n ...node,\n position: {\n x: positionedNode.x - readWorkflowNodeDimensions(node).width / 2,\n y: positionedNode.y - readWorkflowNodeDimensions(node).height / 2,\n },\n }\n : node;\n }),\n };\n}\n\nfunction readSelectOption<TOption extends { readonly id: string }>(\n options: readonly TOption[],\n id: string | null,\n): TOption | null {\n return id ? (options.find((option) => option.id === id) ?? null) : null;\n}\n\nfunction readWorkflowNodeTriggerMode(\n value: string | null,\n): WorkflowNodeTriggerMode {\n return value === 'OR' ? 'OR' : 'AND';\n}\n\nfunction readReturnResubmitStrategy(\n value: string | null,\n): ReturnResubmitStrategy {\n return value === 'FROM_RETURN_POINT' ? 'FROM_RETURN_POINT' : 'RESTART';\n}\n\nfunction readApproverResolverMode(value: string): ApproverResolverMode {\n return value === 'ORG_MANAGER' ||\n value === 'ORG_UNIT_MANAGER' ||\n value === 'ORG_UNIT_MEMBER' ||\n value === 'ORG_UNIT_POSITION' ||\n value === 'POSITION'\n ? value\n : 'DIRECT';\n}\n\nfunction readDefaultApproverResolver(value: string | null): ApproverResolver {\n const mode = readApproverResolverMode(value ?? 'DIRECT');\n\n if (mode === 'ORG_MANAGER') {\n return { baseFromInitiator: true, levelsUp: 1, type: 'ORG_MANAGER' };\n }\n\n if (mode === 'ORG_UNIT_MANAGER') {\n return { orgUnitId: '', type: 'ORG_UNIT_MANAGER' };\n }\n\n if (mode === 'ORG_UNIT_MEMBER') {\n return {\n includeDescendants: false,\n orgUnitId: '',\n type: 'ORG_UNIT_MEMBER',\n };\n }\n\n if (mode === 'ORG_UNIT_POSITION') {\n return {\n includeDescendants: false,\n orgUnitId: '',\n positionId: '',\n type: 'ORG_UNIT_POSITION',\n };\n }\n\n if (mode === 'POSITION') {\n return { positionId: '', type: 'POSITION' };\n }\n\n return { memberIds: [], type: 'DIRECT' };\n}\n\nfunction readApproverFallbackMode(value: string | null): ApproverFallbackMode {\n return value === 'DIRECT' ? 'DIRECT' : 'NONE';\n}\n\nfunction updateApproverResolverFallback(\n resolver: ApproverResolver,\n fallback: ApproverResolverFallback,\n): ApproverResolver {\n if (resolver.type === 'ORG_MANAGER') {\n return { ...resolver, fallback };\n }\n\n if (resolver.type === 'ORG_UNIT_MANAGER') {\n return { ...resolver, fallback };\n }\n\n return resolver;\n}\n\nfunction readManagerLevelOption(levelsUp: number): ManagerLevelOption {\n return (\n MANAGER_LEVEL_OPTIONS.find((option) => option.value === levelsUp) ??\n MANAGER_LEVEL_OPTIONS[0]\n );\n}\n\nfunction readManagerLevelOptionById(id: string | null): ManagerLevelOption {\n return (\n MANAGER_LEVEL_OPTIONS.find((option) => option.id === id) ??\n MANAGER_LEVEL_OPTIONS[0]\n );\n}\n\nfunction readInitiatorPolicyMode(\n value: string | null,\n): Exclude<InitiatorPolicyMode, 'CUSTOM'> {\n if (\n value === 'ORG_UNIT' ||\n value === 'ORG_UNIT_POSITION' ||\n value === 'NONE'\n ) {\n return value;\n }\n\n return 'ALL';\n}\n\nfunction readInitiatorPolicyDraft(\n initiatorPolicyCel: string | null,\n): InitiatorPolicyDraft {\n const expression = initiatorPolicyCel?.trim();\n\n if (!expression) {\n return { mode: 'ALL', value: '' };\n }\n\n const orgUnitIds = readCelStringListOperands(\n expression,\n /\"([^\"]+)\" in subject\\.orgUnitIds/gu,\n );\n const positionIds = readCelStringListOperands(\n expression,\n /\"([^\"]+)\" in subject\\.positionIds/gu,\n );\n\n if (orgUnitIds.length > 0 && positionIds.length > 0) {\n return {\n includeDescendants: orgUnitIds.length > 1,\n mode: 'ORG_UNIT_POSITION',\n orgUnitId: orgUnitIds[0],\n positionId: positionIds[0],\n value: orgUnitIds[0] ?? '',\n };\n }\n\n if (orgUnitIds.length > 0) {\n return {\n includeDescendants: orgUnitIds.length > 1,\n mode: 'ORG_UNIT',\n orgUnitId: orgUnitIds[0],\n value: orgUnitIds[0] ?? '',\n };\n }\n\n return { mode: 'CUSTOM', value: expression };\n}\n\nfunction readInitiatorPolicyUiDraft(\n initiatorPolicyCel: string | null,\n modeDraft: Exclude<InitiatorPolicyMode, 'CUSTOM'> | null,\n): InitiatorPolicyDraft {\n const persistedDraft = readInitiatorPolicyDraft(initiatorPolicyCel);\n\n if (!modeDraft || modeDraft === 'ALL' || modeDraft === 'NONE') {\n return modeDraft === 'ALL' || modeDraft === 'NONE'\n ? { mode: modeDraft, value: '' }\n : persistedDraft;\n }\n\n return persistedDraft.mode === modeDraft\n ? persistedDraft\n : readDefaultInitiatorPolicyDraft(modeDraft);\n}\n\nfunction readInitiatorPolicyIssue(\n policyDraft: InitiatorPolicyDraft,\n): string | null {\n if (policyDraft.mode === 'NONE') {\n return '發起權限需要選擇誰可以發起。';\n }\n\n if (\n (policyDraft.mode === 'ORG_UNIT' ||\n policyDraft.mode === 'ORG_UNIT_POSITION') &&\n !policyDraft.orgUnitId?.trim()\n ) {\n return '指定組織發起時,需要選擇組織。';\n }\n\n if (\n policyDraft.mode === 'ORG_UNIT_POSITION' &&\n !policyDraft.positionId?.trim()\n ) {\n return '指定組織職位發起時,需要選擇職位。';\n }\n\n return null;\n}\n\nfunction readCelStringListOperands(\n expression: string,\n pattern: RegExp,\n): readonly string[] {\n return [...expression.matchAll(pattern)]\n .map((match) => match[1])\n .filter((value): value is string => Boolean(value));\n}\n\nfunction readInitiatorPolicyCel(\n draft: InitiatorPolicyDraft,\n orgUnits: readonly OrgUnitRecord[],\n): string | null {\n if (draft.mode === 'ALL' || draft.mode === 'NONE') {\n return null;\n }\n\n const orgUnitId = draft.orgUnitId?.trim() ?? '';\n\n if (!orgUnitId) {\n return null;\n }\n\n const orgUnitIds = readOrgUnitScopeIds(\n orgUnits,\n orgUnitId,\n Boolean(draft.includeDescendants),\n );\n const orgUnitExpression = orgUnitIds\n .map((id) => `${JSON.stringify(id)} in subject.orgUnitIds`)\n .join(' || ');\n\n if (draft.mode === 'ORG_UNIT') {\n return orgUnitExpression ? `(${orgUnitExpression})` : null;\n }\n\n const positionId = draft.positionId?.trim() ?? '';\n\n if (!positionId) {\n return null;\n }\n\n return orgUnitExpression\n ? `(${orgUnitExpression}) && ${JSON.stringify(positionId)} in subject.positionIds`\n : null;\n}\n\nfunction readInitiatorPolicySummary(\n policyDraft: InitiatorPolicyDraft,\n orgUnits: readonly OrgUnitRecord[],\n positions: readonly PositionRecord[],\n): string {\n if (policyDraft.mode === 'NONE') {\n return '未設定';\n }\n\n if (policyDraft.mode === 'ORG_UNIT') {\n return policyDraft.orgUnitId\n ? `組織:${readOrgUnitDisplayName(orgUnits, policyDraft.orgUnitId)}`\n : '指定組織';\n }\n\n if (policyDraft.mode === 'ORG_UNIT_POSITION') {\n return policyDraft.orgUnitId && policyDraft.positionId\n ? `組織職位:${readOrgUnitDisplayName(\n orgUnits,\n policyDraft.orgUnitId,\n )} / ${readPositionDisplayName(positions, policyDraft.positionId)}`\n : '指定組織職位';\n }\n\n if (policyDraft.mode === 'CUSTOM') {\n return '既有自訂規則';\n }\n\n return '所有人';\n}\n\nfunction readDefaultInitiatorPolicyDraft(\n mode: Exclude<InitiatorPolicyMode, 'CUSTOM'>,\n): InitiatorPolicyDraft {\n return {\n includeDescendants: true,\n mode,\n orgUnitId: '',\n positionId: '',\n value: '',\n };\n}\n\nfunction isWorkflowConnectionValid(\n connection: WorkflowConnectionCandidate,\n nodes: readonly WorkflowNode[],\n): boolean {\n const sourceNode = connection.source\n ? (nodes.find((node) => node.id === connection.source) ?? null)\n : null;\n const targetNode = connection.target\n ? (nodes.find((node) => node.id === connection.target) ?? null)\n : null;\n\n return (\n Boolean(sourceNode) &&\n Boolean(targetNode) &&\n connection.source !== connection.target &&\n connection.sourceHandle === WORKFLOW_OUTPUT_HANDLE_ID &&\n connection.targetHandle === WORKFLOW_INPUT_HANDLE_ID &&\n Boolean(sourceNode && isWorkflowNodeOutputConnectable(sourceNode)) &&\n Boolean(targetNode && isWorkflowNodeInputConnectable(targetNode))\n );\n}\n\nfunction toggleSelectedEdgeId(\n edgeIds: readonly string[],\n edgeId: string,\n): readonly string[] {\n return edgeIds.includes(edgeId)\n ? edgeIds.filter((currentEdgeId) => currentEdgeId !== edgeId)\n : [...edgeIds, edgeId];\n}\n\nfunction isWorkflowNodeRemovable(node: WorkflowNode): boolean {\n return node.type !== 'startEvent' && node.type !== 'endEvent';\n}\n\nfunction isWorkflowNodeInputConnectable(node: WorkflowNode): boolean {\n return node.type !== 'startEvent';\n}\n\nfunction isWorkflowNodeOutputConnectable(node: WorkflowNode): boolean {\n return node.type !== 'endEvent' && !isAsyncNotifyServiceTask(node);\n}\n\nfunction isAsyncNotifyServiceTask(node: WorkflowNode): boolean {\n return node.type === 'serviceTask' && node.data.action.type === 'NOTIFY';\n}\n\nfunction isEditableKeyboardTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) {\n return false;\n }\n\n return (\n target.isContentEditable ||\n target.tagName === 'INPUT' ||\n target.tagName === 'TEXTAREA' ||\n target.tagName === 'SELECT' ||\n Boolean(target.closest('[contenteditable=\"true\"]'))\n );\n}\n\nfunction readFormVersionSelectOptions(\n options: readonly PublishedFormVersionOption[],\n): readonly FormVersionSelectOption[] {\n return options.map((option) => ({\n formDefinitionId: option.formDefinitionId,\n formName: option.formName,\n id: option.id,\n name: `${option.formName} | v${option.version}`,\n schema: option.schema,\n }));\n}\n\nfunction readDryRunSampleFormData(\n option: FormVersionSelectOption | null,\n): Readonly<Record<string, unknown>> {\n return (option?.schema.fields ?? []).reduce<\n Readonly<Record<string, unknown>>\n >(\n (formData, field) => ({\n ...formData,\n [field.fieldKey]: readDryRunSampleFieldValue(field),\n }),\n {},\n );\n}\n\nfunction readDryRunSampleFieldValue(field: FormFieldDefinition): unknown {\n if (field.type === 'number') {\n return 1000;\n }\n\n if (field.type === 'boolean') {\n return true;\n }\n\n if (field.type === 'select') {\n return field.options[0]?.value ?? '';\n }\n\n if (field.type === 'checkbox') {\n return field.options[0] ? [field.options[0].value] : [];\n }\n\n if (field.type === 'date') {\n return '2026-05-08';\n }\n\n if (field.type === 'datetime') {\n return '2026-05-08T09:00:00+08:00';\n }\n\n return field.placeholder ?? field.label;\n}\n\nfunction parseDryRunFormData(value: string): Readonly<Record<string, unknown>> {\n const parsedValue = JSON.parse(value) as unknown;\n\n if (!isRecord(parsedValue)) {\n throw new Error('表單資料 JSON 必須是物件。');\n }\n\n return parsedValue;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction readDryRunStatusLabel(status: string): string {\n if (status === 'COMPLETED') {\n return '完成';\n }\n\n if (status === 'PASSED') {\n return '通過';\n }\n\n if (status === 'SKIPPED') {\n return '略過';\n }\n\n if (status === 'STOPPED') {\n return '已停止';\n }\n\n if (status === 'WAITING') {\n return '將等待簽核';\n }\n\n return status;\n}\n\nfunction readWorkflowNodeTypeLabel(nodeType: string): string {\n return nodeType in NODE_TYPE_LABELS\n ? NODE_TYPE_LABELS[nodeType as WorkflowNode['type']]\n : nodeType;\n}\n\nfunction mergeSelectedOption(\n options: readonly FormVersionSelectOption[],\n selectedOption: FormVersionSelectOption | null,\n): readonly FormVersionSelectOption[] {\n return selectedOption &&\n !options.some((option) => option.id === selectedOption.id)\n ? [selectedOption, ...options]\n : options;\n}\n\nfunction readMemberSelectOptions(\n options: readonly MemberProfileRecord[],\n): readonly MemberSelectOption[] {\n return options.map((option) => ({\n displayName: option.name,\n email: option.email,\n id: option.memberId,\n memberId: option.memberId,\n name: formatMemberDisplayName(option.name, option.email),\n }));\n}\n\nfunction readFallbackMemberSelectOption(memberId: string): MemberSelectOption {\n return {\n displayName: '未知會員',\n email: '',\n id: memberId,\n memberId,\n name: '未知會員',\n };\n}\n\nfunction readMemberSelectOption(\n options: readonly MemberSelectOption[],\n memberId: string,\n): MemberSelectOption {\n return (\n options.find((option) => option.memberId === memberId) ??\n readFallbackMemberSelectOption(memberId)\n );\n}\n\nfunction readPrimaryMemberOption(\n memberIds: readonly string[],\n memberOptions: readonly MemberSelectOption[],\n): MemberSelectOption | null {\n const memberId = memberIds[0];\n\n return memberId ? readMemberSelectOption(memberOptions, memberId) : null;\n}\n\nfunction readSelectedOrgUnitOption(\n orgUnits: readonly OrgUnitRecord[],\n orgUnitId: string,\n): OrgUnitOption | null {\n const orgUnit = orgUnits.find((candidate) => candidate.id === orgUnitId);\n\n return orgUnit ? readOrgUnitOption(orgUnit) : null;\n}\n\nfunction readSelectedPositionOption(\n positions: readonly PositionRecord[],\n positionId: string,\n): PositionOption | null {\n const position = positions.find((candidate) => candidate.id === positionId);\n\n return position ? readPositionOption(position) : null;\n}\n\nfunction readOrgUnitDisplayName(\n orgUnits: readonly OrgUnitRecord[],\n orgUnitId: string,\n): string {\n return readSelectedOrgUnitOption(orgUnits, orgUnitId)?.name ?? '未指定組織';\n}\n\nfunction readPositionDisplayName(\n positions: readonly PositionRecord[],\n positionId: string,\n): string {\n return (\n readSelectedPositionOption(positions, positionId)?.name ?? '未指定職位'\n );\n}\n\nfunction readDryRunInitiatorMetadataSnapshot(\n memberId: string,\n memberships: readonly MembershipRecord[],\n): Readonly<Record<string, unknown>> {\n const today = readTodayDateOnlyString();\n const activeMemberships = memberships.filter(\n (membership) =>\n membership.memberId === memberId &&\n isMembershipActiveOn(membership, today),\n );\n const primaryMembership = activeMemberships.reduce<MembershipRecord | null>(\n (currentPrimary, membership) =>\n currentPrimary &&\n compareMembershipRecord(currentPrimary, membership) <= 0\n ? currentPrimary\n : membership,\n null,\n );\n\n return {\n customFields: {},\n managerMemberId: 'member-002',\n memberId,\n orgCode: 'HQ',\n orgUnitIds: readUniqueTexts(\n activeMemberships.map((membership) => membership.orgUnitId),\n ),\n positionId: primaryMembership?.positionId ?? null,\n positionIds: readUniqueTexts(\n activeMemberships.map((membership) => membership.positionId),\n ),\n primaryOrgUnitId: primaryMembership?.orgUnitId ?? null,\n roles: ['manager'],\n };\n}\n\nfunction readTodayDateOnlyString(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nfunction isMembershipActiveOn(\n membership: MembershipRecord,\n date: string,\n): boolean {\n return (\n membership.effectiveFrom <= date &&\n (!membership.effectiveTo || membership.effectiveTo >= date)\n );\n}\n\nfunction compareMembershipRecord(\n left: MembershipRecord,\n right: MembershipRecord,\n): number {\n if (left.isPrimary !== right.isPrimary) {\n return left.isPrimary ? -1 : 1;\n }\n\n return right.effectiveFrom.localeCompare(left.effectiveFrom);\n}\n\nfunction readUniqueTexts(\n values: readonly (string | null | undefined)[],\n): readonly string[] {\n return values.reduce<readonly string[]>(\n (currentValues, value) =>\n value && !currentValues.includes(value)\n ? [...currentValues, value]\n : currentValues,\n [],\n );\n}\n\nfunction readOrgScopedPositions({\n includeDescendants,\n memberships,\n orgUnitId,\n orgUnits,\n positions,\n}: {\n readonly includeDescendants: boolean;\n readonly memberships: readonly MembershipRecord[];\n readonly orgUnitId: string;\n readonly orgUnits: readonly OrgUnitRecord[];\n readonly positions: readonly PositionRecord[];\n}): readonly PositionRecord[] {\n const orgUnitIds = new Set(\n readOrgUnitScopeIds(orgUnits, orgUnitId, includeDescendants),\n );\n const positionIds = new Set(\n memberships\n .filter((membership) => orgUnitIds.has(membership.orgUnitId))\n .map((membership) => membership.positionId)\n .filter((positionId): positionId is string => Boolean(positionId)),\n );\n\n return positions.filter((position) => positionIds.has(position.id));\n}\n\nfunction readOrgUnitScopeIds(\n orgUnits: readonly OrgUnitRecord[],\n orgUnitId: string,\n includeDescendants: boolean,\n): readonly string[] {\n const orgUnit = orgUnits.find((candidate) => candidate.id === orgUnitId);\n\n if (!orgUnit) {\n return orgUnitId.trim() ? [orgUnitId] : [];\n }\n\n if (!includeDescendants) {\n return [orgUnit.id];\n }\n\n return orgUnits\n .filter(\n (candidate) =>\n candidate.id === orgUnit.id ||\n candidate.path.startsWith(`${orgUnit.path}.`),\n )\n .map((candidate) => candidate.id);\n}\n\nfunction mergeMemberOptions(\n currentOptions: readonly MemberSelectOption[],\n nextOptions: readonly MemberSelectOption[],\n): readonly MemberSelectOption[] {\n const currentOptionIds = new Set(\n currentOptions.map((option) => option.memberId),\n );\n const newOptions = nextOptions.filter(\n (option) => !currentOptionIds.has(option.memberId),\n );\n\n return [...currentOptions, ...newOptions];\n}\n\nfunction readWorkflowDirectMemberIds(\n definition: WorkflowDefinition,\n): readonly string[] {\n return [\n ...new Set(\n definition.nodes.flatMap((node) => {\n if (node.type === 'userTask') {\n return node.data.approverResolver.type === 'DIRECT'\n ? node.data.approverResolver.memberIds\n : [];\n }\n\n if (node.type === 'serviceTask') {\n return readServiceTaskMemberIds(node.data.action);\n }\n\n return [];\n }),\n ),\n ];\n}\n\nfunction readNodeApproverSummary(\n node: WorkflowNode,\n memberOptions: readonly MemberSelectOption[],\n orgUnits: readonly OrgUnitRecord[],\n positions: readonly PositionRecord[],\n): string | null {\n if (node.type === 'userTask') {\n return readApproverResolverSummary(\n node.data.approverResolver,\n memberOptions,\n orgUnits,\n positions,\n );\n }\n\n return null;\n}\n\nfunction readApproverResolverSummary(\n resolver: ApproverResolver,\n memberOptions: readonly MemberSelectOption[],\n orgUnits: readonly OrgUnitRecord[],\n positions: readonly PositionRecord[],\n): string {\n if (resolver.type === 'DIRECT') {\n return readMemberEmailSummary(\n resolver.memberIds,\n memberOptions,\n '未指定簽核者',\n );\n }\n\n if (resolver.type === 'ORG_MANAGER') {\n return readManagerLevelOption(resolver.levelsUp).name;\n }\n\n if (resolver.type === 'ORG_UNIT_MANAGER') {\n return `組織主管:${readOrgUnitDisplayName(orgUnits, resolver.orgUnitId)}`;\n }\n\n if (resolver.type === 'ORG_UNIT_MEMBER') {\n return `組織任一人:${readOrgUnitDisplayName(orgUnits, resolver.orgUnitId)}`;\n }\n\n if (resolver.type === 'ORG_UNIT_POSITION') {\n return `組織職位:${readOrgUnitDisplayName(\n orgUnits,\n resolver.orgUnitId,\n )} / ${readPositionDisplayName(positions, resolver.positionId)}`;\n }\n\n if (resolver.type === 'POSITION') {\n return `職位:${readPositionDisplayName(positions, resolver.positionId)}`;\n }\n\n if (resolver.type === 'DYNAMIC_FORM') {\n return `表單欄位:${resolver.formPath || '未設定'}`;\n }\n\n return '自訂表達式';\n}\n\nfunction readNodeApproverLines(\n node: WorkflowNode,\n memberOptions: readonly MemberSelectOption[],\n): readonly string[] | null {\n if (node.type !== 'serviceTask') {\n return null;\n }\n\n const memberIds = readServiceTaskMemberIds(node.data.action);\n\n return memberIds.length === 0\n ? ['未指定知會對象']\n : memberIds.map(\n (memberId) => readMemberSelectOption(memberOptions, memberId).name,\n );\n}\n\nfunction readMemberEmailSummary(\n memberIds: readonly string[],\n memberOptions: readonly MemberSelectOption[],\n emptyLabel: string,\n): string {\n const memberLabels = memberIds.map(\n (memberId) => readMemberSelectOption(memberOptions, memberId).name,\n );\n\n if (memberLabels.length === 0) {\n return emptyLabel;\n }\n\n if (memberLabels.length <= 2) {\n return memberLabels.join('、');\n }\n\n return `${memberLabels.slice(0, 2).join('、')} 等 ${memberLabels.length} 人`;\n}\n\nfunction formatMemberDisplayName(name: string, email: string): string {\n return `${name} (${email})`;\n}\n\nfunction readWorkflowViewport(\n definition: WorkflowDefinition,\n canvasElement: HTMLDivElement | null,\n): Viewport | null {\n const canvasRect = canvasElement?.getBoundingClientRect();\n\n if (!canvasRect || definition.nodes.length === 0) {\n return null;\n }\n\n const bounds = definition.nodes.reduce(\n (currentBounds, node) => {\n const dimensions = readWorkflowNodeDimensions(node);\n\n return {\n maxX: Math.max(currentBounds.maxX, node.position.x + dimensions.width),\n maxY: Math.max(currentBounds.maxY, node.position.y + dimensions.height),\n minX: Math.min(currentBounds.minX, node.position.x),\n minY: Math.min(currentBounds.minY, node.position.y),\n };\n },\n {\n maxX: Number.NEGATIVE_INFINITY,\n maxY: Number.NEGATIVE_INFINITY,\n minX: Number.POSITIVE_INFINITY,\n minY: Number.POSITIVE_INFINITY,\n },\n );\n\n return getViewportForBounds(\n {\n height: bounds.maxY - bounds.minY,\n width: bounds.maxX - bounds.minX,\n x: bounds.minX,\n y: bounds.minY,\n },\n canvasRect.width,\n canvasRect.height,\n 0.1,\n 1,\n 0.2,\n );\n}\n\nfunction readWorkflowDefinitionIssue(\n definition: WorkflowDefinition,\n): string | null {\n const incompleteUserTaskNode = definition.nodes.find(\n (node) =>\n node.type === 'userTask' &&\n Boolean(readApproverResolverIssue(node.data.approverResolver)),\n );\n const incompleteNotifyNode = definition.nodes.find(\n (node) =>\n node.type === 'serviceTask' &&\n node.data.action.type === 'NOTIFY' &&\n readServiceTaskMemberIds(node.data.action).length === 0,\n );\n const incompleteConditionEdge = definition.edges.find(\n (edge) =>\n isExclusiveGatewaySourceEdge(edge, definition.nodes) &&\n !edge.data.isDefault &&\n !edge.data.condition,\n );\n\n if (incompleteUserTaskNode && incompleteUserTaskNode.type === 'userTask') {\n return readApproverResolverIssue(\n incompleteUserTaskNode.data.approverResolver,\n );\n }\n\n if (incompleteNotifyNode) {\n return '知會節點需要至少一位知會對象。';\n }\n\n if (incompleteConditionEdge) {\n return '條件分流的每條輸出連線都需要先設定條件。';\n }\n\n return null;\n}\n\nfunction readApproverResolverIssue(resolver: ApproverResolver): string | null {\n if (resolver.type === 'DIRECT' && resolver.memberIds.length === 0) {\n return '簽核節點需要指定簽核會員。';\n }\n\n if (resolver.type === 'ORG_MANAGER' && resolver.levelsUp < 1) {\n return '簽核節點需要指定有效的主管層級。';\n }\n\n if (resolver.type === 'ORG_UNIT_MANAGER' && !resolver.orgUnitId.trim()) {\n return '簽核節點需要指定組織。';\n }\n\n if (resolver.type === 'ORG_UNIT_MEMBER' && !resolver.orgUnitId.trim()) {\n return '簽核節點需要指定組織。';\n }\n\n if (\n resolver.type === 'ORG_UNIT_POSITION' &&\n (!resolver.orgUnitId.trim() || !resolver.positionId.trim())\n ) {\n return '簽核節點需要指定組織與職位。';\n }\n\n if (\n (resolver.type === 'ORG_MANAGER' || resolver.type === 'ORG_UNIT_MANAGER') &&\n resolver.fallback?.type === 'DIRECT' &&\n !resolver.fallback.memberId.trim()\n ) {\n return '簽核節點需要指定改派固定人。';\n }\n\n if (resolver.type === 'POSITION' && !resolver.positionId.trim()) {\n return '簽核節點需要指定職位。';\n }\n\n return null;\n}\n\nfunction hasConfiguredConditionEdges(definition: WorkflowDefinition): boolean {\n return definition.edges.some(\n (edge) =>\n isExclusiveGatewaySourceEdge(edge, definition.nodes) &&\n Boolean(\n edge.data.condition ||\n edge.data.conditionFieldKey ||\n edge.data.conditionOperator ||\n edge.data.conditionValue,\n ),\n );\n}\n\nfunction readConditionFieldOptions(\n schema: FormDefinitionSchema | null,\n): readonly ConditionFieldOption[] {\n return (\n schema?.fields.map((field) => ({\n fieldType: field.type,\n id: field.fieldKey,\n name: `${field.label} (${field.fieldKey})`,\n })) ?? []\n );\n}\n\nfunction readConditionField(\n schema: FormDefinitionSchema | null,\n fieldKey: string | null,\n): FormFieldDefinition | null {\n return fieldKey\n ? (schema?.fields.find((field) => field.fieldKey === fieldKey) ?? null)\n : null;\n}\n\nfunction readConditionOperatorOptions(\n field: FormFieldDefinition | null,\n): readonly ConditionOperatorOption[] {\n if (!field) {\n return [];\n }\n\n const operatorIds = readConditionOperatorIds(field);\n\n return CONDITION_OPERATOR_OPTIONS.filter((option) =>\n operatorIds.includes(option.id),\n );\n}\n\nfunction readConditionOperator(\n value: string | null,\n): WorkflowEdgeConditionOperator | null {\n return CONDITION_OPERATOR_OPTIONS.some((option) => option.id === value)\n ? (value as WorkflowEdgeConditionOperator)\n : null;\n}\n\nfunction readConditionOperatorIds(\n field: FormFieldDefinition,\n): readonly WorkflowEdgeConditionOperator[] {\n if (field.type === 'file_upload') {\n return ['IS_FILLED', 'IS_EMPTY'];\n }\n\n if (field.type === 'boolean') {\n return ['EQUALS', 'NOT_EQUALS', 'IS_FILLED', 'IS_EMPTY'];\n }\n\n if (\n field.type === 'date' ||\n field.type === 'datetime' ||\n field.type === 'money' ||\n field.type === 'number'\n ) {\n return [\n 'EQUALS',\n 'NOT_EQUALS',\n 'GREATER_THAN',\n 'GREATER_THAN_OR_EQUALS',\n 'LESS_THAN',\n 'LESS_THAN_OR_EQUALS',\n 'IS_FILLED',\n 'IS_EMPTY',\n ];\n }\n\n return ['EQUALS', 'NOT_EQUALS', 'IS_FILLED', 'IS_EMPTY'];\n}\n\nfunction readConditionValueOptions(\n field: FormFieldDefinition | null,\n): readonly ConditionValueOption[] {\n if (!field) {\n return [];\n }\n\n if (field.type === 'boolean') {\n return [\n { id: 'true', name: '是' },\n { id: 'false', name: '否' },\n ];\n }\n\n if (\n field.type === 'checkbox' ||\n field.type === 'radio' ||\n field.type === 'select'\n ) {\n return field.options.map((option) => ({\n id: option.value,\n name: option.label,\n }));\n }\n\n return [];\n}\n\nfunction shouldConditionOperatorUseValue(\n operator: WorkflowEdgeConditionOperator,\n): boolean {\n return CONDITION_OPERATORS_REQUIRING_VALUE.includes(operator);\n}\n\nfunction readEdgeCanvasLabel(\n edge: WorkflowEdge,\n nodes: readonly WorkflowNode[],\n): string | undefined {\n if (edge.data.label) {\n return edge.data.label;\n }\n\n if (isExclusiveGatewaySourceEdge(edge, nodes)) {\n return readExclusiveGatewayPathLabel(edge);\n }\n\n if (isParallelGatewaySourceEdge(edge, nodes)) {\n return '同時進行';\n }\n\n return undefined;\n}\n\nfunction readExclusiveGatewayPathLabel(edge: WorkflowEdge): string {\n if (edge.data.isDefault) {\n return '其他情況';\n }\n\n return '請設定條件';\n}\n\nfunction isExclusiveGatewaySourceEdge(\n edge: WorkflowEdge,\n nodes: readonly WorkflowNode[],\n): boolean {\n return nodes.some(\n (node) => node.id === edge.source && node.type === 'exclusiveGateway',\n );\n}\n\nfunction isParallelGatewaySourceEdge(\n edge: WorkflowEdge,\n nodes: readonly WorkflowNode[],\n): boolean {\n return nodes.some(\n (node) => node.id === edge.source && node.type === 'parallelGateway',\n );\n}\n\nfunction readServiceTaskMemberIds(action: ServiceAction): readonly string[] {\n return action.type === 'NOTIFY' && action.recipients.type === 'DIRECT'\n ? action.recipients.memberIds\n : [];\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}