@rytass/bpm-core-react 0.21.1 → 0.21.3

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 (76) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/chunks/{FormBuilderView-CGKkuVFi.cjs → FormBuilderView-Bq4TXdxF.cjs} +2 -2
  3. package/dist/chunks/{FormBuilderView-CGKkuVFi.cjs.map → FormBuilderView-Bq4TXdxF.cjs.map} +1 -1
  4. package/dist/chunks/{FormBuilderView-6KdApi-D.js → FormBuilderView-DNsFwZgk.js} +2 -2
  5. package/dist/chunks/{FormBuilderView-6KdApi-D.js.map → FormBuilderView-DNsFwZgk.js.map} +1 -1
  6. package/dist/chunks/{FormRendererView-BcQKUi1A.js → FormRendererView-BF8Ge0Zk.js} +178 -153
  7. package/dist/chunks/FormRendererView-BF8Ge0Zk.js.map +1 -0
  8. package/dist/chunks/FormRendererView-ZIfSRWPi.cjs +6 -0
  9. package/dist/chunks/FormRendererView-ZIfSRWPi.cjs.map +1 -0
  10. package/dist/chunks/admin-pickers-BjbkBpSJ.cjs.map +1 -1
  11. package/dist/chunks/admin-pickers-DfGxsjpp.js.map +1 -1
  12. package/dist/chunks/approval-instance-list-page-BI5fIXc-.js.map +1 -1
  13. package/dist/chunks/approval-instance-list-page-Cv5I1YPX.cjs.map +1 -1
  14. package/dist/chunks/auth-provider-4BeCw7cI.cjs.map +1 -1
  15. package/dist/chunks/auth-provider-C2b-5mGt.js.map +1 -1
  16. package/dist/chunks/categories-CyyqG6wG.cjs.map +1 -1
  17. package/dist/chunks/categories-f7E-RJEc.js.map +1 -1
  18. package/dist/chunks/{compose-DFuLPmOA.js → compose-C_Y38ENa.js} +4 -4
  19. package/dist/chunks/{compose-DFuLPmOA.js.map → compose-C_Y38ENa.js.map} +1 -1
  20. package/dist/chunks/{compose-DK3ocWwG.cjs → compose-NHbyjV73.cjs} +2 -2
  21. package/dist/chunks/{compose-DK3ocWwG.cjs.map → compose-NHbyjV73.cjs.map} +1 -1
  22. package/dist/chunks/dashboard-page-BoqNhjT_.js.map +1 -1
  23. package/dist/chunks/dashboard-page-D7YJ3udk.cjs.map +1 -1
  24. package/dist/chunks/delegations-ClRCwD1I.cjs.map +1 -1
  25. package/dist/chunks/delegations-CqND-Qtz.js.map +1 -1
  26. package/dist/chunks/delegations-D43VDSz1.cjs.map +1 -1
  27. package/dist/chunks/delegations-zisffLwk.js.map +1 -1
  28. package/dist/chunks/{designer-CCy5EbOe.js → designer-BRYIpeTC.js} +300 -298
  29. package/dist/chunks/designer-BRYIpeTC.js.map +1 -0
  30. package/dist/chunks/designer-oDGvHWBJ.cjs +69 -0
  31. package/dist/chunks/designer-oDGvHWBJ.cjs.map +1 -0
  32. package/dist/chunks/{detail-C5KrUC7s.cjs → detail-BLhZp1mO.cjs} +2 -2
  33. package/dist/chunks/detail-BLhZp1mO.cjs.map +1 -0
  34. package/dist/chunks/{detail-Dnc4PPWO.js → detail-CkRgfU7l.js} +2 -2
  35. package/dist/chunks/detail-CkRgfU7l.js.map +1 -0
  36. package/dist/chunks/login-D6cc3bo7.js.map +1 -1
  37. package/dist/chunks/login-uvVcltrS.cjs.map +1 -1
  38. package/dist/chunks/notifications-Bc4mgSds.cjs.map +1 -1
  39. package/dist/chunks/notifications-Cvme5Qbl.js.map +1 -1
  40. package/dist/chunks/orgs-B_2J2tLX.cjs.map +1 -1
  41. package/dist/chunks/orgs-DqxMds26.js.map +1 -1
  42. package/dist/chunks/users-BBtiZ9QQ.js.map +1 -1
  43. package/dist/chunks/users-EqSzDhuj.cjs.map +1 -1
  44. package/dist/index.cjs.map +1 -1
  45. package/dist/index.js.map +1 -1
  46. package/dist/pages/instances/detail/index.cjs +1 -1
  47. package/dist/pages/instances/detail/index.js +1 -1
  48. package/dist/pages/templates/compose/index.cjs +1 -1
  49. package/dist/pages/templates/compose/index.js +1 -1
  50. package/dist/pages/templates/designer/index.cjs +1 -1
  51. package/dist/pages/templates/designer/index.js +1 -1
  52. package/dist/views/forms/builder/index.cjs +1 -1
  53. package/dist/views/forms/builder/index.js +1 -1
  54. package/dist/views/forms/renderer/form-control-menu.d.cts +7 -0
  55. package/dist/views/forms/renderer/form-control-menu.d.ts +7 -0
  56. package/dist/views/forms/renderer/form-data-source-field.d.cts +12 -0
  57. package/dist/views/forms/renderer/form-data-source-field.d.ts +12 -0
  58. package/dist/views/forms/renderer/index.cjs +1 -1
  59. package/dist/views/forms/renderer/index.js +1 -1
  60. package/dist/views/instances/detail/index.cjs +1 -1
  61. package/dist/views/instances/detail/index.js +1 -1
  62. package/dist/views/instances/new/index.cjs +1 -1
  63. package/dist/views/instances/new/index.js +1 -1
  64. package/dist/views/templates/compose/index.cjs +1 -1
  65. package/dist/views/templates/compose/index.js +1 -1
  66. package/dist/views/templates/designer/index.cjs +1 -1
  67. package/dist/views/templates/designer/index.js +1 -1
  68. package/package.json +3 -3
  69. package/dist/chunks/FormRendererView-B-xycC9S.cjs +0 -6
  70. package/dist/chunks/FormRendererView-B-xycC9S.cjs.map +0 -1
  71. package/dist/chunks/FormRendererView-BcQKUi1A.js.map +0 -1
  72. package/dist/chunks/designer-CAUWEKJ4.cjs +0 -69
  73. package/dist/chunks/designer-CAUWEKJ4.cjs.map +0 -1
  74. package/dist/chunks/designer-CCy5EbOe.js.map +0 -1
  75. package/dist/chunks/detail-C5KrUC7s.cjs.map +0 -1
  76. package/dist/chunks/detail-Dnc4PPWO.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"designer-CAUWEKJ4.cjs","names":["isMemberFieldDefinition","isOrgUnitFieldDefinition","isFallbackCapableApproverResolverType","readUnsupportedApproverResolverType","readOrgUnitOption","readPositionOption","isOrgManagerChainStartedFromInitiator","readUnsupportedOrgManagerChainStartType","readOrgManagerChainStartPositionLevel","useState","useRef","useCallback","applyWorkflowCommand","applyWorkflowMacroCommand","executeWorkflowTool","readWorkflowSnapshot","useMemo","WORKFLOW_TOOLSET","useMemo","DefaultChatTransport","useChat","lastAssistantMessageIsCompleteWithToolCalls","WORKFLOW_TOOLSET","WORKFLOW_CHAT_EXPRESSION_GUIDANCE","useState","useRef","useCallback","BODY_STYLE","useState","useCallback","Drawer","Button","Typography","Fragment","Textarea","isToolUIPart","getToolName","readNodeFieldAccess","STACK_STYLE","readNodeFieldAccess","isFieldAccessEntryValid","readFieldAccessEntryForChoice","applyWorkflowCommand","readFieldAccessMatrix","FIELD_ACCESS_CHOICES","useState","useMemo","readWorkflowLintMessage","Typography","Badge","Select","Drawer","InlineMessage","Toggle","Table","readNodeFieldAccessIssues","readWorkflowLintMessage","Typography","Button","_Fragment","InlineMessage","Badge","readWorkflowLintMessage","readFormSchemaLintMessage","canUserTaskHaveMultipleApprovers","readSingleApproverSourceIssues","readNodeActorSourceSkipReasons","readReachableWorkflowNodeIds","readNodeActorSourceIssues","readExcludeNodeActorsIssues","DEFAULT_BPM_ORGANIZATION_TIME_ZONE","useBPMOrganizationTimeZone","isFormFieldCompatibleWithWebhookParameter","readNotifyWebhookStructureIssues","readNotifyWebhookTargetCatalogIssues","readNotifyWebhookTargets","readNotifyWebhookCatalogIssueMessage","NOTIFY_WEBHOOK_CONTEXT_PATHS","Typography","InlineMessage","createNotifyWebhookTarget","Button","NOTIFY_WEBHOOK_TARGET_LIMIT","PlusIcon","TrashIcon","BPMFormField","Select","isNotifyWebhookContextPath","Textarea","useState","Input","isFormOptionFieldDefinition","isFormStaticOptionFieldDefinition","readFormFieldSelectionMode","isNotifyRecipientResolverType","STACK_STYLE","previewWorkflowDialectUpgrade","useState","Modal","InlineMessage","_Fragment","Typography","Table","readExpressionLabelLocation","readExpressionIssueMessage","DEFAULT_API","previewExpression","readExpressionCatalog","useState","useRef","useMemo","BPMFormField","Textarea","Badge","Typography","Select","InlineMessage","readExpressionIssueMessage","Button","analyzeWorkflowExpressions","useState","useRef","useMemo","readExpressionFieldReferences","useCallback","previewExpression","readExpressionCatalog","readExpressionIssueMessage","parseOrgManagerChainPlaceholder","UserIcon","MailIcon","FilterIcon","useRouterAdapter","useBPMRoutes","useBPMLanguage","useState","useRef","useMemo","searchMemberOptions","useCallback","readFieldAccessMatrix","readWorkflowLintMessage","hasConfiguredConditionEdges","readOrganizationDirectory","readTemplateDesigner","searchPublishedFormVersionOptions","excludeFailedMemberIds","resolveMemberProfilesPerIdOnFailure","resolveMemberOptions","composeApprovalTemplateWithForm","forkApprovalTemplate","updateApprovalTemplateDraft","publishApprovalTemplateVersion","dryRunApprovalWorkflow","readFormBuilder","applyNodeChanges","isOrgManagerChainDecisionPolicyInvalid","isDecisionPolicyUnsatisfiable","readDesignTimeApproverCount","composeQuorumThreshold","_Fragment","PageHeader","ContentHeader","Button","SaveIcon","EyeIcon","CheckedIcon","SectionGroup","Section","Typography","BPMFormField","AutoComplete","ReactFlow","ConnectionMode","Background","Controls","ControlButton","Icon","TrashIcon","MiniMap","Drawer","FormBuilderView","InlineMessage","Modal","Textarea","Input","Select","OrgUnitPicker","Toggle","PositionPicker","readUnsupportedApproverFallbackType","readSlaDurationParts","DEFAULT_SLA_CONFIG","SLA_DURATION_UNIT_OPTIONS","SLA_CALENDAR_MODE_OPTIONS","SLA_TIMEOUT_ACTION_OPTIONS","readNotifyWebhookTargets","readConditionOperatorOptionsForField","readConditionOperator","Panel","DotGridIcon","Tag","Handle","Position","DEFAULT_QUORUM_THRESHOLD","composeSlaDuration","formatMemberLabel","getViewportForBounds","readApproverResolverIssue","readExcludeInitiatorIssue","readExcludeNodeActorsShapeIssue","readNotifyServiceTaskIssue","isFormStaticOptionFieldDefinition","require_rolldown_runtime","require_format_member_label","require_router_adapter","require_workflow_chat_prompt","require_FormBuilderView","require_routes_config","require_organization_time_zone_provider","require_admin_pickers","require_bpm_form_field","require_FormRendererView","react","_mezzanine_ui_react","react_jsx_runtime","_rytass_bpm_core_shared","_mezzanine_ui_react_Drawer","_mezzanine_ui_react_ContentHeader","_rytass_bpm_core_client_template","_rytass_bpm_core_client_form","_mezzanine_ui_icons","ai","_rytass_bpm_core_shared_form","_rytass_bpm_core_client_organization","_xyflow_react","dagre","_rytass_bpm_core_shared_workflow_graph","_rytass_bpm_core_shared_workflow","_ai_sdk_react","readMinPositionLevelOptions","levels","positions","position","currentLevel","right","left","names","level","readDefaultMinPositionLevel","highest","NO_MEMBER_FIELD_HINT","NO_SINGLE_MEMBER_FIELD_HINT","NO_ORG_UNIT_FIELD_HINT","STALE_FIELD_HINT","STALE_SINGLE_MEMBER_FIELD_HINT","STALE_ORG_UNIT_FIELD_HINT","OPTIONAL_FIELD_WARNING","HIDDEN_FIELD_WARNING","STORE_ONLY_FIELD_WARNING","UNPUBLISHABLE_SUFFIX","ORG_UNPUBLISHABLE_SUFFIX","readMemberFieldWarning","warnings","field","suffix","readMemberFieldNameSuffix","readMemberFieldOption","warning","readMemberFieldOptions","schema","readFieldChoice","matched","options","option","formPath","stale","hints","readDynamicFormFieldChoice","readSingleMemberFieldOptions","readFormMemberManagerFieldChoice","readOrgUnitFieldOptions","readFormOrgUnitFieldChoice","readFormFieldDisplayName","candidate","readDynamicFormSummary","readManagerFieldSummary","describe","readFormMemberManagerSummary","name","levelName","readFormOrgUnitManagerSummary","APPROVER_RESOLVER_MODE_OPTIONS","MANAGER_LEVEL_OPTIONS","FORM_MEMBER_SUBJECT_OPTIONS","NODE_ACTOR_SUBJECT_OPTIONS","ORG_UNIT_SOURCE_OPTIONS","readApproverSubjectOption","levelsUp","readStoredManagerLevelOption","readApproverResolverMode","value","readDefaultApproverResolver","mode","isFallbackCapableResolver","resolver","updateApproverResolverFallback","readManagerLevelOption","readManagerLevelOptionById","id","readApproverResolverMemberIds","readApproverResolverSummary","readMemberEmailSummary","memberOptions","readOrgManagerChainSummary","formSchema","nodes","readOrgUnitDisplayName","orgUnits","readPositionDisplayName","readStageSummary","readUnsupportedApproverSourceLabel","nodeIds","node","nodeId","memberLabels","memberIds","readMemberSelectOption","memberId","emptyLabel","readSelectedOrgUnitOption","orgUnitId","readSelectedPositionOption","positionId","orgUnit","readFallbackMemberSelectOption","type","readApproverResolverDetail","readManagerRule","readApproverResolverEditorState","buildApproverResolver","state","withApproverSubject","withOrgUnitSource","source","UNSUPPORTED_APPROVER_SOURCE_OPTION_ID","UNSUPPORTED_APPROVER_SOURCE_HINT","readApproverSourceChoice","selected","modeId","readApproverSourcePick","optionId","readApproverSubjectChoice","readApproverSubjectPick","choice","picked","readApproverManagerRule","withPreferClosestOrgUnit","ORG_MANAGER_CHAIN_START_OPTIONS","UNSUPPORTED_ORG_MANAGER_CHAIN_START_OPTION_ID","UNSUPPORTED_ORG_MANAGER_CHAIN_START_HINT","NO_START_POSITION_LEVEL_OPTION","INVALID_START_POSITION_LEVEL_OPTION_ID","START_POSITION_LEVEL_ABOVE_MIN_HINT","ORG_MANAGER_CHAIN_START_HINTS","readStoredStartType","startFrom","readOrgManagerChainStartMode","readOrgManagerChainStartChoice","readUnsupportedOrgManagerChainStartLabel","omitOrgManagerChainKey","key","omitted","withOrgManagerChainStart","base","readOrgManagerChainStartPick","readOrgManagerChainStartFormPath","readOrgManagerChainStartNodeIds","withOrgManagerChainStartFormPath","withOrgManagerChainStartNodeIds","readValidOrgManagerChainStartLevel","withOrgManagerChainMinPositionLevel","readOrgManagerChainStartLevelChoice","stored","levelOptions","invalid","readOrgManagerChainStartLevelPick","current","readOrgManagerChainStartLevelProblem","readOrgManagerChainStartSummary","ORG_MANAGER_CHAIN_FALLBACK_HINT","readOrgManagerChainFallbackHint","emptyChainCases","start","startLevel","DECISION_POLICY_OPTIONS","readDecisionPolicyHint","policy","thresholdUnit","readDecisionPolicyOption","item","useWorkflowDesignerController","setState","initialState","stateRef","directoryRef","directory","expressionToolsRef","expressionTools","commit","result","committedDefinition","layout","committedState","onLayout","dispatch","command","dispatchMacro","toolQueueRef","runTool","before","toolName","input","committed","executeTool","run","replaceState","resolved","next","getState","snapshot","useWorkflowChat","transport","api","chat","controller","toolCall","MAX_STEPS","readChromeLanguageModel","DECISION_SCHEMA","readOfflineSystemPrompt","toolLines","tool","useChromeWorkflowChat","available","setAvailable","messages","setMessages","status","setStatus","idRef","model","availability","appendMessage","text","runOfflineLoop","readErrorMessage","error","session","nextPrompt","userText","step","decision","parseDecision","observation","raw","BODY_STYLE$1","MESSAGE_LIST_STYLE","MODE_ROW_STYLE","INPUT_ROW_STYLE","SEND_ROW_STYLE","TEXTAREA_STYLE","CHAT_INPUT_CLASS_NAME","CHAT_INPUT_GLOBAL_STYLE","TOOL_LINE_STYLE","TOOL_STATE_LABEL","readBubbleStyle","isUser","role","WorkflowChatDrawer","online","offline","setMode","setInput","active","busy","handleSend","send","handleKeyDown","event","renderMessageParts","message","part","index","stateLabel","FIELD_ACCESS_CHOICE_LABELS","FIELD_ACCESS_EFFECTIVE_LABELS","FIELD_ACCESS_FILL_BLOCKER_LABELS","FIELD_ACCESS_BOOLEAN_REQUIRED_NOTE","FIELD_ACCESS_HIDE_NOTE","readFieldAccessStageLabel","column","readFieldAccessNodeCounts","entries","entry","readFieldAccessNodeTag","parts","fill","hidden","FILL_CONFLICT_CODES","isFillConflictIssue","issue","BODY_STYLE","STACK_STYLE$2","FIELD_CELL_STYLE","readDefinitionEntries","definition","setFieldAccessDraftEntry","fieldKey","candidateIndex","updateFieldAccessDraft","readEntryKey","rebaseFieldAccessDraft","initialByKey","initial","draftByKey","draft","all","userTaskIds","readUserTaskIds","readDraftDefinition","isStoredAsRead","readStoredEntriesKey","readStoredEntryKey","display","isSameEntries","EMPTY_MATRIX","readMatrixSession","isRowRelevant","row","cell","readCellOptions","readApplicantText","stages","columns","FieldAccessMatrixDrawer","setSession","onlyRelevant","setOnlyRelevant","applyError","setApplyError","open","opened","draftDefinition","matrix","pinnedFieldKeys","translate","language","visibleRows","collapsedCount","rowFieldKeys","unplacedIssues","changeCell","apply","onApply","onClose","expressionReferences","columnIndex","renderCheck","notices","notice","blockers","label","SECTION_STYLE","HEADING_ROW_STYLE","FieldAccessNodeSection","counts","conflictMessages","openDisabledReason","onOpenMatrix","onRemoveLegacy","UNKNOWN_ERROR_MESSAGES","WEBHOOK_LINT_PREFIXES","readTemplateErrorMessage","submittedDefinition","NO_UPSTREAM_USER_TASK_HINT","NODE_ACTOR_STAGE_HINT","ORG_MANAGER_CHAIN_STAGE_HINT","ORG_MANAGER_CHAIN_ONLY_MULTI_APPROVER_STAGES_HINT","UNUSABLE_STAGE_SUFFIX","MISSING_STAGE_SUFFIX","isUserTaskNode","readNodeName","readNodeActorStageChoice","readStageChoice","selectedIds","readOrgManagerChainStageChoice","ids","offered","isOfferable","readExtraIssues","readNodeActorGraphIssues","readGraphCheckedNodeIds","EXCLUDE_NODE_ACTORS_STAGE_HINT","NO_EXCLUDABLE_STAGE_HINT","readExcludeNodeActorStageChoice","readExcludeNodeActorsGraphIssues","readTodayDateOnlyString","byType","now","useOrganizationTodayDateOnlyString","isMembershipActiveOn","membership","date","readActivePositionIds","memberships","readOrgScopedPositions","orgUnitIds","readOrgUnitScopeIds","includeDescendants","positionIds","readOrgPositionPickerState","isInactive","scopedPositions","NOTIFY_WEBHOOK_CONTEXT_PATH_LABELS","NOTIFY_WEBHOOK_PARAMETER_TYPE_LABELS","readNotifyWebhookEndpointOptionId","endpoint","findNotifyWebhookEndpoint","endpoints","reference","readNotifyWebhookBindingKinds","readCompatibleFormFields","formFields","createNotifyWebhookBindingSource","kind","parameter","canBindNotifyWebhookExpression","DECIMAL_PATTERN","readNotifyWebhookConstantValue","trimmed","isNotifyWebhookListEditable","webhooks","UNRENDERABLE_STRUCTURE_CODES","setNotifyWebhookBinding","others","target","binding","from","currentIndex","switchNotifyWebhookEndpoint","readNotifyWebhookDesignerIssues","EDITOR_STYLE","TARGET_STYLE","TARGET_HEADER_STYLE","BINDING_ROW_STYLE","NONE_OPTION","BINDING_KIND_OPTIONS","BOOLEAN_OPTIONS","CONTEXT_PATH_OPTIONS","path","NOTIFY_WEBHOOK_NO_ENDPOINTS_MESSAGE","NotifyWebhookTargetsEditor","activeEndpoints","catalog","targets","catalogState","replaceTarget","onChange","targetIndex","addTarget","NotifyWebhookTargetEditor","currentOptionId","endpointOptions","readEndpointOptionName","declaredKeys","undeclaredBindings","onRemove","NotifyWebhookBindingEditor","canBindField","kindOptions","typeLabel","targetId","readBindingKind","NotifyWebhookBindingValue","compatibleOptions","fieldOptions","NotifyWebhookConstantInput","setText","notes","readDryRunSampleFormData","formData","readDryRunSampleFieldValue","readDryRunFormMemberPlaceholder","readDryRunFormOrgUnitPlaceholder","placeholder","firstOption","NOTIFY_RECIPIENT_EDITABLE_TYPES","isNotifyRecipientEditableType","NOTIFY_RECIPIENT_MODE_OPTIONS","READ_ONLY_NOTIFY_RECIPIENT_OPTION_ID","readReadOnlyNotifyRecipientName","READ_ONLY_NOTIFY_RECIPIENT_HINT","UNSUPPORTED_NOTIFY_RECIPIENT_HINT","EMPTY_NOTIFY_RECIPIENTS","readNotifyRecipients","action","readNotifyRecipientSourceChoice","editable","recipients","known","readNotifyRecipientSourcePick","withNotifyRecipients","readIncludeDescendantsKey","withNotifyOrgUnit","withNotifyIncludeDescendants","withNotifyPosition","withNotifyFormPath","STACK_STYLE$1","readDialectOutcomeText","outcome","SAMPLE_LABELS","canConfirmDialectUpgrade","DialectUpgradeModal","setResult","failed","setFailed","cancelled","preview","onCancel","difference","DEFAULT_API$1","STACK_STYLE","NOTE_LIST_STYLE","ROW_STYLE","readExpressionCatalogOptions","root","fn","readExpressionCatalogFunctionNotes","appendExpressionSnippet","snippet","readExpressionFieldStatusText","STATUS_BADGE_VARIANT","readExpressionSample","parsed","json","readExpressionEvaluationText","evaluation","ExpressionField","lint","setLint","setCatalog","sampleJson","setSampleJson","setEvaluation","evaluating","setEvaluating","onLintChangeRef","onLintChange","formDefinitionVersionId","usagePoint","expression","publish","timer","debounceMs","dialect","edgeSourceNodeType","targetFieldKey","catalogOptions","functionNotes","statusText","runEvaluation","sample","disabled","note","evaluable","useWorkflowExpressionReferences","analysis","setAnalysis","latestRef","enabled","analyze","references","resolveCurrentReferences","latest","record","DEFAULT_API","toPreviewInput","request","createWorkflowExpressionTools","hasWorkflowEntryCondition","setWorkflowNodeEntryCondition","rest","condition","isWorkflowEdgeExpressionCondition","edge","setWorkflowEdgeExpressionCondition","edgeId","readWorkflowEdgeSourceNodeType","readRemovedExpressionFields","after","afterFieldKeys","beforeFieldKeys","checkFormEditExpressionFields","removed","resolveReferences","fields","MANAGER_LEVEL_NAMES","managerLevelName","readDryRunAssigneeLabel","assignee","orgUnitName","positionName","formFieldName","nodeNames","idList","chain","levelSplit","leading","hasLevel","readTemplateVersionDescription","readTemplateHeaderDescription","versionDescription","expressionDialect","readFormVersionLabel","formName","version","ORG_POSITION_INACTIVE_HINT","WORKSPACE_STYLE","TWO_COLUMN_STYLE","FLOW_CANVAS_STYLE","SELECTION_DELETE_CONTROL_BUTTON_STYLE","SELECTION_DELETE_CONTROL_ICON_STYLE","SIDE_PANEL_CLASS_NAME","SIDE_PANEL_FORM_LABEL_WIDTH","SIDE_PANEL_GLOBAL_STYLE","CONDITION_EDGE_COLOR","DEFAULT_EDGE_COLOR","INCOMPLETE_CONDITION_EDGE_COLOR","SELECTED_EDGE_GLOW_FILTER","FLOW_CANVAS_GLOBAL_STYLE","PANEL_STYLE","FORM_STACK_STYLE","DRY_RUN_RESULT_STYLE","DRY_RUN_STEP_STYLE","BUTTON_ROW_STYLE","FORM_BIND_ROW_STYLE","FORM_BIND_FIELD_STYLE","FORM_BIND_BUTTON_STYLE","TOOL_GROUP_STYLE","NODE_STYLE","SELECTED_NODE_BOX_SHADOW","FLOW_NODE_INITIAL_HEIGHT","FLOW_NODE_INITIAL_WIDTH","FLOW_NODE_ADDITIONAL_LINE_HEIGHT","FLOW_NODE_FIELD_ACCESS_TAG_HEIGHT","FIELD_ACCESS_NO_FORM_REASON","GATEWAY_NODE_INITIAL_HEIGHT","GATEWAY_NODE_INITIAL_WIDTH","GATEWAY_NODE_STYLE","EXCLUSIVE_GATEWAY_NODE_STYLE","PARALLEL_GATEWAY_NODE_STYLE","USER_TASK_NODE_STYLE","START_NODE_STYLE","END_NODE_STYLE","NODE_TEXT_STYLE","NODE_PRIMARY_LABELS_STYLE","WORKFLOW_INPUT_HANDLE_ID","WORKFLOW_OUTPUT_HANDLE_ID","NODE_TYPE_LABELS","ACTION_NODE_PALETTE","FLOW_CONTROL_PALETTE","NODE_TRIGGER_MODE_OPTIONS","RETURN_ALLOWED_TARGETS_OPTIONS","RETURN_RESUBMIT_STRATEGY_OPTIONS","SLA_WARNING_AT_OPTIONS","QUORUM_THRESHOLD_TYPE_OPTIONS","APPROVER_FALLBACK_MODE_OPTIONS","APPROVER_FALLBACK_UNSUPPORTED_OPTION","EXCLUDE_INITIATOR_WHEN_EMPTY_OPTIONS","DEFAULT_EXCLUDE_INITIATOR_CONFIG","DEFAULT_EXCLUDE_NODE_ACTORS_CONFIG","CONDITION_OPERATORS_REQUIRING_VALUE","INITIATOR_POLICY_MODE_OPTIONS","INITIATOR_POLICY_CUSTOM_OPTION","SERVICE_ACTION_TYPE_OPTIONS","DRY_RUN_MEMBER_ID","PUBLISH_ERROR_STYLE","FORM_EDIT_DRAWER_BODY_STYLE","FORM_EDIT_DRAWER_CONTENT_STYLE","FORM_EDIT_DRAWER_FOOTER_STYLE","FORM_EDIT_EMPTY_SCHEMA","FORM_EDIT_EMPTY_UI_SCHEMA","nodeTypes","WorkflowNodeCard","resolveSetStateAction","TemplateDesignerView","router","routes","organizationToday","setRecord","setDraft","loadedDesignerSnapshot","setLoadedDesignerSnapshot","initiatorPolicyModeDraft","setInitiatorPolicyModeDraft","initiatorPolicyDraftOverride","setInitiatorPolicyDraftOverride","initiatorPolicyCustomDraft","setInitiatorPolicyCustomDraft","expressionEdgeId","setExpressionEdgeId","flowCanvasRef","flowViewport","setFlowViewport","orgUnitsRef","positionsRef","unit","readMemberSelectOptions","query","member","embedded","initialWorkflowDefinition","normalizeDesignerWorkflowDefinition","readFallbackWorkflowDefinition","initialInitiatorPolicyCel","layoutWorkflowDefinition","nextViewport","readWorkflowViewport","workflowDefinition","initiatorPolicyCel","selectedNodeId","selectedEdgeIds","editingEdgeId","setWorkflowDefinition","setFormDefinitionVersionId","setInitiatorPolicyCel","updateWorkflowDefinitionDirectly","update","setSelectedNodeId","setSelectedEdgeIds","setEditingEdgeId","setError","policyNotice","setPolicyNotice","loading","setLoading","saving","setSaving","formVersionLoading","setFormVersionLoading","formVersionOptions","setFormVersionOptions","currentDesignerSnapshot","hasUnsavedChanges","memberLoading","setMemberLoading","setMemberOptions","memberSearchResults","setMemberSearchResults","memberSearchSequenceRef","designerLoadSequenceRef","unresolvableMemberIdsRef","setOrgUnits","setPositions","setMemberships","dryRunModalOpen","setDryRunModalOpen","dialectUpgradeOpen","setDialectUpgradeOpen","fieldAccessMatrixOpen","setFieldAccessMatrixOpen","dryRunRunning","setDryRunRunning","dryRunFormDataJson","setDryRunFormDataJson","dryRunResult","setDryRunResult","dryRunError","setDryRunError","webhookCatalog","setWebhookCatalog","webhookCatalogState","setWebhookCatalogState","chatOpen","setChatOpen","formEditOpen","setFormEditOpen","formDraft","setFormDraft","appliedFormDraft","setAppliedFormDraft","formDraftDirty","formDraftLoading","setFormDraftLoading","formEditChecking","setFormEditChecking","publishButtonText","loadOrganizationData","refreshDesigner","templateId","handleBeforeUnload","resolveWorkflowMemberOptions","currentDefinition","handleBackToTemplates","selectedNode","selectedNodeCanDelete","isWorkflowNodeRemovable","hasDeletableSelection","removeSelectedWorkflowElements","handleDeleteSelectedElements","isEditableKeyboardTarget","editingEdge","selectedEdge","selectedEdges","initiatorPolicyDraft","readInitiatorPolicyUiDraft","flowEdges","readFlowEdge","selectedFormVersionOption","readSelectOption","readFormVersionSelectOptions","visibleFormVersionOptions","mergeSelectedOption","selectedFormSchema","effectiveFormSchema","formSchemaOverride","workflowIssue","readWorkflowDefinitionIssue","webhookFormSchema","expressionFieldReferences","resolveExpressionFieldReferences","formEditBlockedMessage","setFormEditBlockedMessage","webhookPublishIssue","fieldAccessPublishIssue","nodeActorPublishIssue","excludeNodeActorsPublishIssue","publishIssue","flowNodes","readFlowNode","formVersionBindingLocked","initiatorPolicyIssue","readInitiatorPolicyIssue","onWorkflowChange","onInitiatorPolicyChange","organizationDirectory","requestError","loadSequence","nextRecord","nextDraft","sourceVersion","nextWorkflowDefinition","nextFormDefinitionVersionId","nextInitiatorPolicyCel","isEmptyDesignerWorkflowDefinition","handleSearchFormVersions","searchText","handleSearchMembers","searchSequence","nextOptions","mergeMemberOptions","currentOptions","readWorkflowDirectMemberIds","missingMemberIds","resolvedIds","profiles","profile","unresolvableIds","skippedIds","commitDesigner","validationIssue","policyIssue","blockingPublishIssue","targetDraft","handleSaveDraft","handlePublish","openDryRunModal","closeDryRunModal","handleDryRun","parseDryRunFormData","readDryRunInitiatorMetadataSnapshot","openFormEditDrawer","boundFormDefinitionId","builderRecord","draftVersion","v","discardFormEdit","applyFormEdit","check","handleNodeChanges","nextFlowNodes","changes","flowNode","handleConnect","isWorkflowConnectionValid","connection","handleEdgeClick","toggleSelectedEdgeId","currentEdgeIds","closeEdgeSettingsModal","addWorkflowNode","updateSelectedNodeLabel","updateUserTaskResolver","decisionPolicy","approverResolver","updateUserTaskReturnAllowedTargets","updateUserTaskReturnResubmitStrategy","updateUserTaskReturnRequireComment","updateUserTaskRequireApprovalComment","updateUserTaskSla","updateUserTaskExcludeInitiator","updateUserTaskExcludeNodeActors","updateUserTaskDecisionPolicy","sanitisedDecisionPolicy","updateUserTaskOptions","updateServiceAction","updateInitiatorPolicyDraft","readInitiatorPolicyCel","updateSelectedNodeTriggerMode","updateSelectedEdgeDefault","checked","updateSelectedEdgeConditionState","applyAutoLayout","showAiAssistant","aiAssistantAvailable","showDryRun","AutoLayoutPanel","renderSelectedEdgesPanel","renderEdgePanel","renderNodePanel","renderEdgeSettingsModal","renderDryRunModal","dryRunAssigneeDirectory","resultError","readDryRunStatusLabel","readWorkflowNodeTypeLabel","readDryRunWebhookLabels","webhookLabel","renderStartEventPanel","renderNodeTriggerModePanel","renderUserTaskPanel","renderServiceTaskPanel","policyModeOptions","selectedInitiatorOrgUnit","selectedInitiatorPosition","initiatorScopedPositions","initiatorPositionPicker","readInitiatorPolicyMode","readDefaultInitiatorPolicyDraft","incomingEdgeCount","triggerModeLocked","triggerMode","readWorkflowNodeTriggerMode","editorState","sourceChoice","subjectChoice","managerRule","selectedMembers","selectedOrgUnit","selectedPosition","orgScopedPositions","orgPositionPicker","dynamicFormChoice","orgFieldChoice","selectedManagerOrgUnit","nodeActorChoice","selectedManagerLevel","fallback","unsupportedFallbackType","approverFallbackModeOptions","minPositionLevelOptions","chainResolver","chainStartMode","chainStartChoice","chainFormChoice","chainStageChoice","chainStartLevelChoice","chainStartLevelProblem","fallbackMember","fallbackPosition","resubmitStrategy","sla","excludeInitiator","excludeNodeActors","excludeNodeActorChoice","slaDurationParts","slaDurationUnit","slaWarningAtOption","readSlaWarningAtOption","slaEscalateLevel","decisionPolicyType","readDecisionPolicyType","quorum","readQuorumParts","renderApproverSubjectField","readApproverFallbackModeDraft","readDecisionPolicyFromOptionId","readQuorumThresholdType","readReturnAllowedTargets","readReturnResubmitStrategy","withSlaDuration","readSlaDurationUnit","readSlaCalendarMode","withSlaTimeoutAction","readSlaTimeoutAction","withSlaWarningAt","readSlaWarningAtOptionById","sourceHint","readServiceTaskMemberIds","selectedRecipientOrgUnit","selectedRecipientPosition","activeRecipientPositionIds","isRecipientPositionInactive","recipientPositionOptions","recipientOrgScopedPositions","recipientOrgPositionPicker","recipientFormChoice","updateNotifyRecipients","updateNotifyWebhooks","actionTypePicker","targetFieldOptions","readConditionFieldOptions","edges","isConditionPath","isExclusiveGatewaySourceEdge","renderConditionEdgeSettingsForm","pathLabelPreview","readEdgeCanvasLabel","conditionFieldOptions","selectedConditionField","readConditionField","conditionOperatorOptions","conditionValueOptions","readConditionValueOptions","selectedConditionOperator","pathLabelIsIncomplete","expressionCondition","shouldConditionOperatorUseValue","handleAutoLayout","onApplyAutoLayout","primaryLabels","data","secondaryLabel","readWorkflowNodeSecondaryLabel","nodeStyle","readWorkflowNodeCardStyle","renderWorkflowNodeHandles","primaryLabel","baseStyle","readWorkflowNodeBaseCardStyle","dimensions","readWorkflowNodeDimensions","readNodeApproverLines","readNodeApproverSummary","isWorkflowNodeInputConnectable","isWorkflowNodeOutputConnectable","readInitiatorPolicySummary","readFlowNodeHandles","readServiceTaskLineCount","readTargetFlowNodeHandle","readSourceFlowNodeHandle","centeredHandleY","height","width","isConditionEdge","isIncompleteConditionEdge","labelColor","labelBackgroundColor","labelBorderColor","applyWorkflowNodeTriggerMode","normalizeSingleIncomingTriggerModes","normalizeUserTaskPolicies","removeAsyncNotifyOutgoingEdges","normalizeDesignerEdgeData","allowAddSigner","allowReject","allowTransfer","decisionPolicyIsMissing","asyncNotifyNodeIds","isAsyncNotifyServiceTask","incomingEdgeCounts","graph","positionedNode","duration","onTimeout","omitSlaKey","warningAt","entryKey","readApproverFallbackMode","readInitiatorPolicyDraft","readCelStringListOperands","persistedDraft","modeDraft","policyDraft","pattern","match","orgUnitExpression","sourceNode","targetNode","edgeIds","currentEdgeId","parsedValue","isRecord","nodeType","selectedOption","formatMemberDisplayName","activeMemberships","today","primaryMembership","currentPrimary","compareMembershipRecord","readUniqueTexts","values","currentValues","resolvedById","currentOptionIds","newOptions","upgradedOptions","recipientLines","webhookCount","lines","webhookLines","email","canvasRect","canvasElement","bounds","currentBounds","incompleteUserTaskNode","excludeInitiatorNode","excludeNodeActorsShapeIssue","notifyNodeIssue","incompleteConditionEdge","chainPolicyNode","operator","readExclusiveGatewayPathLabel","isParallelGatewaySourceEdge"],"sources":["../../src/views/templates/designer/position-level-options.ts","../../src/views/templates/designer/dynamic-form-resolver-options.ts","../../src/views/templates/designer/approver-resolver-model.ts","../../src/views/templates/designer/decision-policy-options.ts","../../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/field-access-matrix/field-access-copy.ts","../../src/views/templates/designer/field-access-matrix/FieldAccessMatrixDrawer.tsx","../../src/views/templates/designer/field-access-matrix/FieldAccessNodeSection.tsx","../../src/views/templates/template-error-message.ts","../../src/views/templates/designer/node-actor-resolver-options.ts","../../src/views/templates/designer/position-scope.ts","../../src/views/templates/designer/notify-webhook-designer.ts","../../src/views/templates/designer/NotifyWebhookTargetsEditor.tsx","../../src/views/templates/designer/dry-run-sample-data.ts","../../src/views/templates/designer/notify-recipient-options.ts","../../src/views/templates/designer/expression/DialectUpgradeModal.tsx","../../src/views/templates/designer/expression/ExpressionField.tsx","../../src/views/templates/designer/expression/use-workflow-expression-references.ts","../../src/views/templates/designer/expression/workflow-expression-tools.ts","../../src/views/templates/designer/expression/workflow-expression-edits.ts","../../src/views/templates/designer/dry-run-assignee-label.ts","../../src/views/templates/designer/designer-version-labels.ts","../../src/views/templates/designer/TemplateDesignerView.tsx"],"sourcesContent":["import { PositionRecord } from '@rytass/bpm-core-client/organization';\n\nexport type PositionLevelOption = Readonly<{\n id: string;\n name: string;\n value: number;\n}>;\n\ntype PositionLevelSource = Pick<PositionRecord, 'level' | 'name'>;\n\n/**\n * One option per distinct position level in the directory, highest first, each\n * labelled with the positions sitting on that level. A saved level that no\n * position carries (positions deleted or not loaded yet) is still offered so\n * the select never renders blank and the stored value is not silently changed.\n * `currentLevel` is that saved level; `null` offers only the directory's own\n * levels, for a field that has no value yet.\n */\nexport function readMinPositionLevelOptions(\n positions: readonly PositionLevelSource[],\n currentLevel: number | null,\n): readonly PositionLevelOption[] {\n const levels = [...new Set(positions.map((position) => position.level))];\n const allLevels =\n currentLevel === null || levels.includes(currentLevel)\n ? levels\n : [...levels, currentLevel];\n\n return [...allLevels]\n .sort((left, right) => right - left)\n .map((level) => {\n const names = positions\n .filter((position) => position.level === level)\n .map((position) => position.name);\n\n return {\n id: String(level),\n name:\n names.length > 0\n ? `職等 ${level}(${names.join('、')})`\n : `職等 ${level}`,\n value: level,\n };\n });\n}\n\n/** The highest level in the directory, or `1` when there are no positions. */\nexport function readDefaultMinPositionLevel(\n positions: readonly PositionLevelSource[],\n): number {\n return positions.reduce(\n (highest, position) => Math.max(highest, position.level),\n 1,\n );\n}\n","import {\n FormDefinitionSchema,\n FormFieldDefinition,\n isMemberFieldDefinition,\n isOrgUnitFieldDefinition,\n} from '@rytass/bpm-core-shared/form';\n\nexport type MemberFieldOption = Readonly<{\n id: string;\n name: string;\n /**\n * Set when the field can be empty at submit time (optional, hidden by a\n * visibility rule, or a store-only hidden field); the node would then find no\n * approver, so publishing refuses it. Still selectable, so the stored choice\n * stays visible until the form or the node is fixed.\n */\n warning?: string;\n}>;\n\nexport type DynamicFormFieldChoice = Readonly<{\n /** What the picker offers; includes the stale stored key when there is one. */\n options: readonly MemberFieldOption[];\n /** Hint under the picker, or `null` when nothing needs saying. */\n problem: string | null;\n selected: MemberFieldOption | null;\n}>;\n\nexport const NO_MEMBER_FIELD_HINT =\n '表單中沒有「人員選擇」欄位,請先到表單設計加入';\n\nexport const NO_SINGLE_MEMBER_FIELD_HINT =\n '表單中沒有單選的「人員選擇」欄位,請先到表單設計加入';\n\nexport const NO_ORG_UNIT_FIELD_HINT =\n '表單中沒有「組織選擇」欄位,請先到表單設計加入';\n\nconst STALE_FIELD_HINT =\n '原本指定的欄位已不在表單中,或已不是「人員選擇」欄位,請重新選擇。';\nconst STALE_SINGLE_MEMBER_FIELD_HINT =\n '原本指定的欄位已不在表單中,或已不是單選的「人員選擇」欄位,請重新選擇。';\nconst STALE_ORG_UNIT_FIELD_HINT =\n '原本指定的欄位已不在表單中,或已不是「組織選擇」欄位,請重新選擇。';\n\nconst OPTIONAL_FIELD_WARNING = '此欄位非必填';\nconst HIDDEN_FIELD_WARNING = '此欄位可能被條件隱藏';\nconst STORE_ONLY_FIELD_WARNING = '此欄位為隱藏欄位,申請人無法填寫';\nconst UNPUBLISHABLE_SUFFIX =\n ',空白時此關會找不到人員,發佈時會被拒絕;請在表單設計將它設為必填且不隱藏';\nconst ORG_UNPUBLISHABLE_SUFFIX =\n ',空白時此關會找不到組織主管,發佈時會被拒絕;請在表單設計將它設為必填且不隱藏';\n\nfunction readMemberFieldWarning(\n field: FormFieldDefinition,\n suffix: string = UNPUBLISHABLE_SUFFIX,\n): string | undefined {\n const warnings = [\n ...(field.required ? [] : [OPTIONAL_FIELD_WARNING]),\n ...(field.visibleWhen?.trim() ? [HIDDEN_FIELD_WARNING] : []),\n ...(field.hidden ? [STORE_ONLY_FIELD_WARNING] : []),\n ];\n\n return warnings.length > 0 ? `${warnings.join('、')}${suffix}` : undefined;\n}\n\nfunction readMemberFieldNameSuffix(field: FormFieldDefinition): string {\n return `${field.required ? '' : '(非必填)'}${\n field.visibleWhen?.trim() ? '(可能被條件隱藏)' : ''\n }${field.hidden ? '(隱藏欄位)' : ''}`;\n}\n\nfunction readMemberFieldOption(field: FormFieldDefinition): MemberFieldOption {\n const warning = readMemberFieldWarning(field);\n\n return {\n id: field.fieldKey,\n name: `${field.label} (${field.fieldKey})${readMemberFieldNameSuffix(field)}`,\n ...(warning ? { warning } : {}),\n };\n}\n\n/** Only member fields can feed a 依表單欄位指定 approver resolver. */\nexport function readMemberFieldOptions(\n schema: FormDefinitionSchema | null,\n): readonly MemberFieldOption[] {\n return (schema?.fields ?? [])\n .filter(isMemberFieldDefinition)\n .map(readMemberFieldOption);\n}\n\nfunction readFieldChoice(\n options: readonly MemberFieldOption[],\n formPath: string,\n hints: Readonly<{ empty: string; stale: string }>,\n): DynamicFormFieldChoice {\n const matched = options.find((option) => option.id === formPath) ?? null;\n\n if (matched) {\n return { options, problem: matched.warning ?? null, selected: matched };\n }\n\n if (formPath.trim()) {\n const stale: MemberFieldOption = {\n id: formPath,\n name: `${formPath}(無效欄位)`,\n };\n\n return {\n options: [...options, stale],\n problem: hints.stale,\n selected: stale,\n };\n }\n\n return {\n options,\n problem: options.length === 0 ? hints.empty : null,\n selected: null,\n };\n}\n\n/**\n * The member-field picker for the 依表單欄位指定 resolver. A stored `formPath`\n * that no longer names a member field of the bound form (the form was switched\n * or edited, or the template came from the API) stays visible as its own\n * option together with a warning, instead of being cleared behind the user's\n * back — the resolver stays invalid until a real field is chosen.\n */\nexport function readDynamicFormFieldChoice(\n schema: FormDefinitionSchema | null,\n formPath: string,\n): DynamicFormFieldChoice {\n return readFieldChoice(readMemberFieldOptions(schema), formPath, {\n empty: NO_MEMBER_FIELD_HINT,\n stale: STALE_FIELD_HINT,\n });\n}\n\n/**\n * Member fields a manager can be looked up from: one person per submission,\n * so a multi-select member field is not offered (SPEC 5.2). Same warnings as\n * {@link readMemberFieldOptions}.\n */\nexport function readSingleMemberFieldOptions(\n schema: FormDefinitionSchema | null,\n): readonly MemberFieldOption[] {\n return (schema?.fields ?? [])\n .filter(isMemberFieldDefinition)\n .filter((field) => !field.multiple)\n .map(readMemberFieldOption);\n}\n\n/** The field picker for 簽核人 = 直屬/第二層/第三層主管 of a form person. */\nexport function readFormMemberManagerFieldChoice(\n schema: FormDefinitionSchema | null,\n formPath: string,\n): DynamicFormFieldChoice {\n return readFieldChoice(readSingleMemberFieldOptions(schema), formPath, {\n empty: NO_SINGLE_MEMBER_FIELD_HINT,\n stale: STALE_SINGLE_MEMBER_FIELD_HINT,\n });\n}\n\n/**\n * Every 組織選擇 field of the form, optional or hidden ones included; the\n * ones that cannot be published carry the reason as `warning`, the way member\n * fields do.\n */\nexport function readOrgUnitFieldOptions(\n schema: FormDefinitionSchema | null,\n): readonly MemberFieldOption[] {\n return (schema?.fields ?? [])\n .filter(isOrgUnitFieldDefinition)\n .map((field) => {\n const warning = readMemberFieldWarning(field, ORG_UNPUBLISHABLE_SUFFIX);\n\n return {\n id: field.fieldKey,\n name: `${field.label} (${field.fieldKey})${readMemberFieldNameSuffix(field)}`,\n ...(warning ? { warning } : {}),\n };\n });\n}\n\n/** The field picker for 組織 = 表單欄位 of 指定組織主管. */\nexport function readFormOrgUnitFieldChoice(\n schema: FormDefinitionSchema | null,\n formPath: string,\n): DynamicFormFieldChoice {\n return readFieldChoice(readOrgUnitFieldOptions(schema), formPath, {\n empty: NO_ORG_UNIT_FIELD_HINT,\n stale: STALE_ORG_UNIT_FIELD_HINT,\n });\n}\n\n/**\n * What a form field is called in a sentence: its label, or the field key when\n * the form has no such field (any more) or the field has no label.\n */\nexport function readFormFieldDisplayName(\n schema: FormDefinitionSchema | null,\n formPath: string,\n): string {\n return (\n schema?.fields.find((candidate) => candidate.fieldKey === formPath)\n ?.label || formPath\n );\n}\n\n/**\n * 依表單欄位:<label>; the field key when the form does not have it (any\n * more), and a marker when the key names something that is not a member field.\n */\nexport function readDynamicFormSummary(\n schema: FormDefinitionSchema | null,\n formPath: string,\n): string {\n if (!formPath.trim()) {\n return '依表單欄位:未設定';\n }\n\n const field = schema?.fields.find(\n (candidate) => candidate.fieldKey === formPath,\n );\n\n if (field && !isMemberFieldDefinition(field)) {\n return `依表單欄位:${field.label || formPath}(非人員選擇欄位)`;\n }\n\n return `依表單欄位:${field?.label || formPath}`;\n}\n\nfunction readManagerFieldSummary(\n schema: FormDefinitionSchema | null,\n formPath: string,\n describe: (field: FormFieldDefinition | undefined, name: string) => string,\n): string {\n if (!formPath.trim()) {\n return '依表單欄位:未設定';\n }\n\n const field = schema?.fields.find(\n (candidate) => candidate.fieldKey === formPath,\n );\n\n return describe(field, field?.label || formPath);\n}\n\n/**\n * 依表單欄位:<label>的<level>; marks a field that cannot feed a manager lookup\n * (not a member field, or one that takes several people).\n */\nexport function readFormMemberManagerSummary(\n schema: FormDefinitionSchema | null,\n formPath: string,\n levelName: string,\n): string {\n return readManagerFieldSummary(schema, formPath, (field, name) => {\n if (field && !isMemberFieldDefinition(field)) {\n return `依表單欄位:${name}(非人員選擇欄位)`;\n }\n\n if (field && isMemberFieldDefinition(field) && field.multiple) {\n return `依表單欄位:${name}(需為單選人員欄位)`;\n }\n\n return `依表單欄位:${name}的${levelName}`;\n });\n}\n\n/** 依表單欄位:<label>所選組織的主管, with a marker for a non-org field. */\nexport function readFormOrgUnitManagerSummary(\n schema: FormDefinitionSchema | null,\n formPath: string,\n): string {\n return readManagerFieldSummary(schema, formPath, (field, name) =>\n field && !isOrgUnitFieldDefinition(field)\n ? `依表單欄位:${name}(非組織選擇欄位)`\n : `依表單欄位:${name}所選組織的主管`,\n );\n}\n","import {\n ApproverResolver,\n ApproverResolverFallback,\n OrgManagerChainStart,\n isFallbackCapableApproverResolverType,\n isOrgManagerChainStartedFromInitiator,\n readOrgManagerChainStartPositionLevel,\n readUnsupportedApproverResolverType,\n readUnsupportedOrgManagerChainStartType,\n} from '@rytass/bpm-core-shared/workflow';\nimport { FormDefinitionSchema } from '@rytass/bpm-core-shared/form';\nimport {\n OrgUnitRecord,\n PositionRecord,\n} from '@rytass/bpm-core-client/organization';\nimport {\n OrgUnitOption,\n PositionOption,\n readOrgUnitOption,\n readPositionOption,\n} from '../../../components/admin-picker-options';\nimport {\n readDefaultMinPositionLevel,\n readMinPositionLevelOptions,\n} from './position-level-options';\nimport {\n readDynamicFormSummary,\n readFormFieldDisplayName,\n readFormMemberManagerSummary,\n readFormOrgUnitManagerSummary,\n} from './dynamic-form-resolver-options';\n\nexport type ApproverResolverMode = Extract<\n ApproverResolver['type'],\n | 'DIRECT'\n | 'DYNAMIC_FORM'\n | 'NODE_ACTOR'\n | 'ORG_MANAGER'\n | 'ORG_MANAGER_CHAIN'\n | 'ORG_UNIT_MANAGER'\n | 'ORG_UNIT_MEMBER'\n | 'ORG_UNIT_POSITION'\n | 'POSITION'\n>;\n\nexport type ApproverResolverModeOption = Readonly<{\n id: ApproverResolverMode;\n name: string;\n}>;\n\nexport type ManagerLevelOption = Readonly<{\n id: string;\n name: string;\n value: number;\n}>;\n\nexport type MemberSelectOption = Readonly<{\n displayName: string;\n email: string;\n id: string;\n memberId: string;\n name: string;\n /**\n * Set on the placeholder written when a member's profile could not be\n * fetched. Marking it explicitly lets {@link mergeMemberOptions} replace the\n * placeholder once the real profile turns up, instead of the \"未知會員\"\n * sentinel sticking for the rest of the session.\n */\n unresolved?: boolean;\n}>;\n\nexport const APPROVER_RESOLVER_MODE_OPTIONS: readonly ApproverResolverModeOption[] =\n [\n { id: 'DIRECT', name: '指定會員' },\n { id: 'DYNAMIC_FORM', name: '依表單欄位指定' },\n { id: 'NODE_ACTOR', name: '依前面關卡的簽核者' },\n { id: 'ORG_MANAGER', name: '發起人主管' },\n { id: 'ORG_MANAGER_CHAIN', name: '主管鏈(簽到指定職等)' },\n { id: 'ORG_UNIT_MANAGER', name: '指定組織主管' },\n { id: 'ORG_UNIT_MEMBER', name: '組織任一人' },\n { id: 'ORG_UNIT_POSITION', name: '組織特定職位' },\n { id: 'POSITION', name: '指定職位' },\n ];\n\nexport const MANAGER_LEVEL_OPTIONS: readonly ManagerLevelOption[] = [\n { id: '1', name: '直屬主管', value: 1 },\n { id: '2', name: '第二層主管', value: 2 },\n { id: '3', name: '第三層主管', value: 3 },\n];\n\nexport type NodeNameRecord = Readonly<{ id: string; name: string }>;\n\n/**\n * The 簽核人 choices of the two sources that start from \"someone\": the person\n * the source names, or their manager one to three levels up. `value` 0 is the\n * person themselves; it is what the select stores for a source with no\n * manager level.\n */\nexport const FORM_MEMBER_SUBJECT_OPTIONS: readonly ManagerLevelOption[] = [\n { id: '0', name: '欄位裡的人', value: 0 },\n ...MANAGER_LEVEL_OPTIONS,\n];\nexport const NODE_ACTOR_SUBJECT_OPTIONS: readonly ManagerLevelOption[] = [\n { id: '0', name: '關卡的簽核者', value: 0 },\n ...MANAGER_LEVEL_OPTIONS,\n];\n\nexport type OrgUnitManagerSource = 'FIXED' | 'FORM_FIELD';\n\nexport const ORG_UNIT_SOURCE_OPTIONS: readonly Readonly<{\n id: OrgUnitManagerSource;\n name: string;\n}>[] = [\n { id: 'FIXED', name: '固定組織' },\n { id: 'FORM_FIELD', name: '表單欄位' },\n];\n\n/**\n * The option for a stored level. A level this screen has no option for (a\n * hand-written or AI-written definition) is shown as itself rather than\n * mistaken for another one.\n */\nexport function readApproverSubjectOption(\n options: readonly ManagerLevelOption[],\n levelsUp: number,\n): ManagerLevelOption {\n return (\n options.find((option) => option.value === levelsUp) ?? {\n id: String(levelsUp),\n name: `第 ${levelsUp} 層主管`,\n value: levelsUp,\n }\n );\n}\n\n/**\n * The option for the manager level a FORM_MEMBER_MANAGER / NODE_ACTOR_MANAGER\n * definition stores. Those types always name a manager, so a level below 1 (or\n * not a whole number) is a broken definition: it is shown as an invalid level\n * rather than as the option whose `value` happens to be 0 (本人). The stored\n * JSON is never touched by this read; the publish lint is what blocks it.\n */\nexport function readStoredManagerLevelOption(\n options: readonly ManagerLevelOption[],\n levelsUp: number,\n): ManagerLevelOption {\n if (!Number.isInteger(levelsUp) || levelsUp < 1) {\n return {\n id: `invalid:${levelsUp}`,\n name: `第 ${levelsUp} 層主管(無效)`,\n value: levelsUp,\n };\n }\n\n return readApproverSubjectOption(options, levelsUp);\n}\n\nexport function readApproverResolverMode(value: string): ApproverResolverMode {\n // The new sources share a screen option with the source they extend: 依表單\n // 欄位指定 holds the person's manager, 指定組織主管 the form-field org, and\n // 依前面關卡的簽核者 holds both of its 簽核人 choices.\n if (value === 'FORM_MEMBER_MANAGER') {\n return 'DYNAMIC_FORM';\n }\n\n if (value === 'FORM_ORG_UNIT_MANAGER') {\n return 'ORG_UNIT_MANAGER';\n }\n\n if (value === 'NODE_ACTOR_MANAGER') {\n return 'NODE_ACTOR';\n }\n\n return value === 'DYNAMIC_FORM' ||\n value === 'NODE_ACTOR' ||\n value === 'ORG_MANAGER' ||\n value === 'ORG_MANAGER_CHAIN' ||\n value === 'ORG_UNIT_MANAGER' ||\n value === 'ORG_UNIT_MEMBER' ||\n value === 'ORG_UNIT_POSITION' ||\n value === 'POSITION'\n ? value\n : 'DIRECT';\n}\n\nexport function readDefaultApproverResolver(\n value: string | null,\n positions: readonly PositionRecord[],\n): ApproverResolver {\n const mode = readApproverResolverMode(value ?? 'DIRECT');\n\n if (mode === 'DYNAMIC_FORM') {\n return { formPath: '', type: 'DYNAMIC_FORM' };\n }\n\n if (mode === 'NODE_ACTOR') {\n return { nodeIds: [], type: 'NODE_ACTOR' };\n }\n\n if (mode === 'ORG_MANAGER') {\n return { baseFromInitiator: true, levelsUp: 1, type: 'ORG_MANAGER' };\n }\n\n if (mode === 'ORG_MANAGER_CHAIN') {\n return {\n minPositionLevel: readDefaultMinPositionLevel(positions),\n type: 'ORG_MANAGER_CHAIN',\n };\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\ntype FallbackCapableApproverResolver = Extract<\n ApproverResolver,\n { readonly fallback?: ApproverResolverFallback }\n>;\n\n// The shared table decides which types look a manager up; a type this build\n// does not know is never one of them, so it passes through untouched.\nfunction isFallbackCapableResolver(\n resolver: ApproverResolver,\n): resolver is FallbackCapableApproverResolver {\n return isFallbackCapableApproverResolverType(resolver.type);\n}\n\nexport function updateApproverResolverFallback(\n resolver: ApproverResolver,\n fallback: ApproverResolverFallback,\n): ApproverResolver {\n if (isFallbackCapableResolver(resolver)) {\n return { ...resolver, fallback };\n }\n\n return resolver;\n}\n\nexport function readManagerLevelOption(levelsUp: number): ManagerLevelOption {\n return (\n MANAGER_LEVEL_OPTIONS.find((option) => option.value === levelsUp) ??\n MANAGER_LEVEL_OPTIONS[0]\n );\n}\n\nexport function readManagerLevelOptionById(\n id: string | null,\n): ManagerLevelOption {\n return (\n MANAGER_LEVEL_OPTIONS.find((option) => option.id === id) ??\n MANAGER_LEVEL_OPTIONS[0]\n );\n}\n\n/**\n * Every member id a resolver names outright, so the designer can pre-fetch\n * their display names on load.\n *\n * The manager resolvers' `DIRECT` fallback (\"固定改派\") counts: it is a member\n * the author picked and the property form renders it through\n * `readMemberSelectOption`, which falls back to the \"未知會員\" sentinel for any\n * id it cannot find. Leaving it out meant a saved fallback always rendered as\n * 未知會員 until an unrelated search happened to return that member.\n */\nexport function readApproverResolverMemberIds(\n resolver: ApproverResolver,\n): readonly string[] {\n if (resolver.type === 'DIRECT') {\n return resolver.memberIds;\n }\n\n if (isFallbackCapableResolver(resolver)) {\n return resolver.fallback?.type === 'DIRECT' && resolver.fallback.memberId\n ? [resolver.fallback.memberId]\n : [];\n }\n\n return [];\n}\n\nexport function readApproverResolverSummary(\n resolver: ApproverResolver,\n memberOptions: readonly MemberSelectOption[],\n orgUnits: readonly OrgUnitRecord[],\n positions: readonly PositionRecord[],\n formSchema: FormDefinitionSchema | null,\n nodes?: readonly NodeNameRecord[],\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_MANAGER_CHAIN') {\n return readOrgManagerChainSummary(resolver, formSchema, nodes);\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 readDynamicFormSummary(formSchema, resolver.formPath);\n }\n\n if (resolver.type === 'FORM_MEMBER_MANAGER') {\n return readFormMemberManagerSummary(\n formSchema,\n resolver.formPath,\n readStoredManagerLevelOption(\n FORM_MEMBER_SUBJECT_OPTIONS,\n resolver.levelsUp,\n ).name,\n );\n }\n\n if (resolver.type === 'FORM_ORG_UNIT_MANAGER') {\n return readFormOrgUnitManagerSummary(formSchema, resolver.formPath);\n }\n\n if (resolver.type === 'NODE_ACTOR') {\n return `前面關卡的簽核者:${readStageSummary(resolver.nodeIds, nodes)}`;\n }\n\n if (resolver.type === 'NODE_ACTOR_MANAGER') {\n return `前面關卡簽核者的${\n readStoredManagerLevelOption(\n NODE_ACTOR_SUBJECT_OPTIONS,\n resolver.levelsUp,\n ).name\n }:${readStageSummary(resolver.nodeIds, nodes)}`;\n }\n\n if (resolver.type === 'EXPRESSION') {\n return '自訂表達式';\n }\n\n // A type saved by a newer BPMCore: say so rather than call it an expression.\n return readUnsupportedApproverSourceLabel(\n readUnsupportedApproverResolverType(resolver) ?? '',\n );\n}\n\nfunction readStageSummary(\n nodeIds: readonly string[],\n nodes: readonly NodeNameRecord[] | undefined,\n): string {\n if (nodeIds.length === 0) {\n return '未指定關卡';\n }\n\n if (!nodes) {\n return `${nodeIds.length} 個關卡`;\n }\n\n const names = nodeIds.map(\n (nodeId) =>\n nodes.find((node) => node.id === nodeId)?.name ?? `${nodeId}(已不存在)`,\n );\n\n return names.length <= 2\n ? names.join('、')\n : `${names.slice(0, 2).join('、')} 等 ${names.length} 關`;\n}\n\nexport function 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\nexport function readOrgUnitDisplayName(\n orgUnits: readonly OrgUnitRecord[],\n orgUnitId: string,\n): string {\n return readSelectedOrgUnitOption(orgUnits, orgUnitId)?.name ?? '未指定組織';\n}\n\nexport function readPositionDisplayName(\n positions: readonly PositionRecord[],\n positionId: string,\n): string {\n return (\n readSelectedPositionOption(positions, positionId)?.name ?? '未指定職位'\n );\n}\n\nexport function 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\nexport function 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\nexport function 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\nexport function readFallbackMemberSelectOption(\n memberId: string,\n): MemberSelectOption {\n return {\n displayName: '未知會員',\n email: '',\n id: memberId,\n memberId,\n name: '未知會員',\n unresolved: true,\n };\n}\n\n/**\n * The one label for a resolver `type` this build does not know (a definition\n * saved by a newer BPMCore): the designer's read-only 簽核來源 entry, the node\n * summary and the compose review table all say it with this.\n */\nexport function readUnsupportedApproverSourceLabel(type: string): string {\n return `不支援的簽核來源(${type})`;\n}\n\n/**\n * The short 簽核方式 label the compose review table shows for a user task.\n */\nexport function readApproverResolverDetail(resolver: ApproverResolver): string {\n switch (resolver.type) {\n case 'DIRECT':\n return '指定成員';\n case 'POSITION':\n return '指定職位';\n case 'ORG_UNIT_MEMBER':\n return '單位成員';\n case 'ORG_UNIT_POSITION':\n return '單位職位';\n case 'ORG_MANAGER':\n return '主管';\n case 'ORG_MANAGER_CHAIN':\n return '主管鏈';\n case 'ORG_UNIT_MANAGER':\n return '單位主管';\n case 'DYNAMIC_FORM':\n return '依表單欄位指定';\n case 'EXPRESSION':\n return '運算式';\n case 'FORM_MEMBER_MANAGER':\n return '表單欄位人員的主管';\n case 'FORM_ORG_UNIT_MANAGER':\n return '表單欄位組織的主管';\n case 'NODE_ACTOR':\n return '前面關卡的簽核者';\n case 'NODE_ACTOR_MANAGER':\n return '前面關卡簽核者的主管';\n default:\n return readUnsupportedApproverSourceLabel(\n readUnsupportedApproverResolverType(resolver) ?? '',\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Screen state <-> JSON for the sources that share a screen option.\n// ---------------------------------------------------------------------------\n\ntype ManagerRule = Readonly<{\n fallback?: ApproverResolverFallback;\n preferClosestOrgUnit?: boolean;\n}>;\n\n/**\n * What the 簽核來源 panel edits. The three sources with two stored types each\n * (本人/主管, 固定組織/表單欄位) carry the screen's own choice instead of the\n * JSON type; every other known type is held as saved and edited field by\n * field, and a type this build does not know is held as saved, read-only.\n *\n * `levelsUp` is `null` for the 本人 choice (no manager level), otherwise the\n * stored level.\n */\nexport type ApproverResolverEditorState =\n | (Readonly<{\n formPath: string;\n levelsUp: number | null;\n mode: 'DYNAMIC_FORM';\n }> &\n ManagerRule)\n | (Readonly<{\n formPath: string;\n mode: 'ORG_UNIT_MANAGER';\n orgSource: OrgUnitManagerSource;\n orgUnitId: string;\n }> &\n ManagerRule)\n | (Readonly<{\n levelsUp: number | null;\n mode: 'NODE_ACTOR';\n nodeIds: readonly string[];\n }> &\n ManagerRule)\n | Readonly<{ mode: 'AS_STORED'; resolver: ApproverResolver }>\n | Readonly<{\n mode: 'UNSUPPORTED';\n resolver: ApproverResolver;\n type: string;\n }>;\n\n// Only the keys the definition actually has, so reading then building a saved\n// resolver reproduces it exactly (no `undefined` keys, no invented defaults).\nfunction readManagerRule(resolver: ManagerRule): ManagerRule {\n return {\n ...(resolver.fallback !== undefined ? { fallback: resolver.fallback } : {}),\n ...(resolver.preferClosestOrgUnit !== undefined\n ? { preferClosestOrgUnit: resolver.preferClosestOrgUnit }\n : {}),\n };\n}\n\nexport function readApproverResolverEditorState(\n resolver: ApproverResolver,\n): ApproverResolverEditorState {\n if (readUnsupportedApproverResolverType(resolver) !== null) {\n return { mode: 'UNSUPPORTED', resolver, type: resolver.type };\n }\n\n switch (resolver.type) {\n case 'DYNAMIC_FORM':\n return {\n formPath: resolver.formPath,\n levelsUp: null,\n mode: resolver.type,\n };\n case 'FORM_MEMBER_MANAGER':\n return {\n ...readManagerRule(resolver),\n formPath: resolver.formPath,\n levelsUp: resolver.levelsUp,\n mode: 'DYNAMIC_FORM',\n };\n case 'ORG_UNIT_MANAGER':\n return {\n ...readManagerRule(resolver),\n formPath: '',\n mode: resolver.type,\n orgSource: 'FIXED',\n orgUnitId: resolver.orgUnitId,\n };\n case 'FORM_ORG_UNIT_MANAGER':\n return {\n ...readManagerRule(resolver),\n formPath: resolver.formPath,\n mode: 'ORG_UNIT_MANAGER',\n orgSource: 'FORM_FIELD',\n orgUnitId: '',\n };\n case 'NODE_ACTOR':\n return { levelsUp: null, mode: resolver.type, nodeIds: resolver.nodeIds };\n case 'NODE_ACTOR_MANAGER':\n return {\n ...readManagerRule(resolver),\n levelsUp: resolver.levelsUp,\n mode: 'NODE_ACTOR',\n nodeIds: resolver.nodeIds,\n };\n default:\n return { mode: 'AS_STORED', resolver };\n }\n}\n\n/**\n * The JSON for a screen state. Only the fields that belong to the chosen type\n * are written, so a field left over from the choice the author switched away\n * from (the manager level after 回到欄位裡的人, the formPath after 改選固定組織)\n * never reaches the saved definition.\n */\nexport function buildApproverResolver(\n state: ApproverResolverEditorState,\n): ApproverResolver {\n if (state.mode === 'AS_STORED' || state.mode === 'UNSUPPORTED') {\n return state.resolver;\n }\n\n if (state.mode === 'DYNAMIC_FORM') {\n return state.levelsUp === null\n ? { formPath: state.formPath, type: 'DYNAMIC_FORM' }\n : {\n ...readManagerRule(state),\n formPath: state.formPath,\n levelsUp: state.levelsUp,\n type: 'FORM_MEMBER_MANAGER',\n };\n }\n\n if (state.mode === 'ORG_UNIT_MANAGER') {\n return state.orgSource === 'FIXED'\n ? {\n ...readManagerRule(state),\n orgUnitId: state.orgUnitId,\n type: 'ORG_UNIT_MANAGER',\n }\n : {\n ...readManagerRule(state),\n formPath: state.formPath,\n type: 'FORM_ORG_UNIT_MANAGER',\n };\n }\n\n return state.levelsUp === null\n ? { nodeIds: state.nodeIds, type: 'NODE_ACTOR' }\n : {\n ...readManagerRule(state),\n levelsUp: state.levelsUp,\n nodeIds: state.nodeIds,\n type: 'NODE_ACTOR_MANAGER',\n };\n}\n\n/**\n * Applies the 簽核人 select: 0 is the person themselves, 1-3 their manager.\n * Sources with no such choice come back as the same state.\n */\nexport function withApproverSubject(\n state: ApproverResolverEditorState,\n value: number,\n): ApproverResolverEditorState {\n if (state.mode === 'DYNAMIC_FORM' || state.mode === 'NODE_ACTOR') {\n return { ...state, levelsUp: value > 0 ? value : null };\n }\n\n return state;\n}\n\n/**\n * Applies the 組織 choice of 指定組織主管. A form-field org starts with 只取最近\n * 一層主管 on (SPEC 3.3) unless the author already chose; a fixed org keeps the\n * stored choice as it is. Switching back does not take the default off again:\n * the toggle keeps whatever value the resolver has, and stays visible.\n */\nexport function withOrgUnitSource(\n state: ApproverResolverEditorState,\n source: OrgUnitManagerSource,\n): ApproverResolverEditorState {\n if (state.mode !== 'ORG_UNIT_MANAGER') {\n return state;\n }\n\n return {\n ...state,\n orgSource: source,\n ...(source === 'FORM_FIELD' && state.preferClosestOrgUnit === undefined\n ? { preferClosestOrgUnit: true }\n : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Screen gating: what the 簽核來源 panel may show and write.\n// ---------------------------------------------------------------------------\n\n/** The id of the read-only entry an unknown resolver type is shown as. */\nexport const UNSUPPORTED_APPROVER_SOURCE_OPTION_ID = 'UNSUPPORTED';\n\nconst UNSUPPORTED_APPROVER_SOURCE_HINT =\n '此引擎版本不支援這種簽核來源;這裡選擇其他簽核來源會覆寫原設定';\n\nexport type ApproverSourceChoice = Readonly<{\n /** Hint under the select, `null` when nothing needs saying. */\n hint: string | null;\n options: readonly Readonly<{ id: string; name: string }>[];\n selected: Readonly<{ id: string; name: string }>;\n}>;\n\n/**\n * The 簽核來源 select: the source options, plus, for a type this build does\n * not know, a read-only entry carrying its name that is the current value: it\n * is shown, never edited, and nothing is written unless the author explicitly\n * picks a different source (which replaces the stored one).\n * `readApproverResolverMode` would call such a type 指定會員.\n */\nexport function readApproverSourceChoice(\n state: ApproverResolverEditorState,\n): ApproverSourceChoice {\n if (state.mode === 'UNSUPPORTED') {\n const selected = {\n id: UNSUPPORTED_APPROVER_SOURCE_OPTION_ID,\n name: readUnsupportedApproverSourceLabel(state.type),\n };\n\n return {\n hint: UNSUPPORTED_APPROVER_SOURCE_HINT,\n options: [...APPROVER_RESOLVER_MODE_OPTIONS, selected],\n selected,\n };\n }\n\n const modeId =\n state.mode === 'AS_STORED'\n ? readApproverResolverMode(state.resolver.type)\n : state.mode;\n\n return {\n hint: null,\n options: APPROVER_RESOLVER_MODE_OPTIONS,\n selected:\n APPROVER_RESOLVER_MODE_OPTIONS.find((option) => option.id === modeId) ??\n APPROVER_RESOLVER_MODE_OPTIONS[0],\n };\n}\n\n/**\n * The resolver a 簽核來源 pick produces, or `null` when the pick must change\n * nothing: no option, an id that is not an option (the read-only unsupported\n * entry included), or the source already stored. Re-picking the shown source\n * used to rebuild a clean default and wipe what the author had filled in.\n *\n * \"Already stored\" is the state's own mode, not the displayed option: an\n * EXPRESSION resolver is displayed as 指定會員 but is not one, so picking 指定會員\n * still switches it.\n */\nexport function readApproverSourcePick(\n resolver: ApproverResolver,\n optionId: string | null,\n positions: readonly PositionRecord[],\n): ApproverResolver | null {\n if (\n optionId === null ||\n !APPROVER_RESOLVER_MODE_OPTIONS.some((option) => option.id === optionId)\n ) {\n return null;\n }\n\n const state = readApproverResolverEditorState(resolver);\n const storedId =\n state.mode === 'AS_STORED'\n ? state.resolver.type\n : state.mode === 'UNSUPPORTED'\n ? null\n : state.mode;\n\n return optionId === storedId\n ? null\n : readDefaultApproverResolver(optionId, positions);\n}\n\nexport type ApproverSubjectChoice = Readonly<{\n /** The stored level is below 1 (or fractional): shown, not offered again. */\n invalid: boolean;\n options: readonly ManagerLevelOption[];\n selected: ManagerLevelOption;\n}>;\n\n/**\n * The 簽核人 select of ② and ③. A stored manager level the list has no option\n * for (invalid, or a level above 3) is appended so the select can show it.\n */\nexport function readApproverSubjectChoice(\n state: ApproverResolverEditorState,\n): ApproverSubjectChoice | null {\n if (state.mode !== 'DYNAMIC_FORM' && state.mode !== 'NODE_ACTOR') {\n return null;\n }\n\n const options =\n state.mode === 'DYNAMIC_FORM'\n ? FORM_MEMBER_SUBJECT_OPTIONS\n : NODE_ACTOR_SUBJECT_OPTIONS;\n\n if (state.levelsUp === null) {\n return { invalid: false, options, selected: options[0] };\n }\n\n const selected = readStoredManagerLevelOption(options, state.levelsUp);\n\n return {\n invalid: selected.id.startsWith('invalid:'),\n options: options.some((option) => option.id === selected.id)\n ? options\n : [...options, selected],\n selected,\n };\n}\n\n/**\n * The state a 簽核人 pick produces, or `null` for a no-op (the shown choice\n * picked again, the invalid-level entry, an id that is not an option).\n */\nexport function readApproverSubjectPick(\n state: ApproverResolverEditorState,\n optionId: string | null,\n): ApproverResolverEditorState | null {\n const choice = readApproverSubjectChoice(state);\n const picked = choice?.options.find((option) => option.id === optionId);\n\n if (\n !choice ||\n !picked ||\n picked.id.startsWith('invalid:') ||\n picked.id === choice.selected.id\n ) {\n return null;\n }\n\n return withApproverSubject(state, picked.value);\n}\n\nexport type ApproverManagerRuleView = Readonly<{\n fallback: ApproverResolverFallback;\n preferClosestOrgUnit: boolean;\n /** 主管鏈 has no 只取最近一層主管. */\n showPreferClosestOrgUnit: boolean;\n}>;\n\n/**\n * The 只取最近一層主管 / 無主管時 pair of a resolver that looks a manager up,\n * `null` for one that does not (so 本人 shows neither).\n */\nexport function readApproverManagerRule(\n resolver: ApproverResolver,\n): ApproverManagerRuleView | null {\n if (!isFallbackCapableResolver(resolver)) {\n return null;\n }\n\n return {\n fallback: resolver.fallback ?? { type: 'NONE' },\n preferClosestOrgUnit:\n 'preferClosestOrgUnit' in resolver\n ? Boolean(resolver.preferClosestOrgUnit)\n : false,\n showPreferClosestOrgUnit: resolver.type !== 'ORG_MANAGER_CHAIN',\n };\n}\n\nexport function withPreferClosestOrgUnit(\n resolver: ApproverResolver,\n preferClosestOrgUnit: boolean,\n): ApproverResolver {\n if (\n !isFallbackCapableResolver(resolver) ||\n resolver.type === 'ORG_MANAGER_CHAIN'\n ) {\n return resolver;\n }\n\n return { ...resolver, preferClosestOrgUnit };\n}\n\n// ---------------------------------------------------------------------------\n// 主管鏈: where the chain starts and from which position level it signs.\n// ---------------------------------------------------------------------------\n\ntype OrgManagerChainResolver = Extract<\n ApproverResolver,\n { readonly type: 'ORG_MANAGER_CHAIN' }\n>;\n\nexport type OrgManagerChainStartMode = OrgManagerChainStart['type'];\n\nexport type OrgManagerChainStartOption = Readonly<{\n id: string;\n name: string;\n}>;\n\n/** The choices of 從誰的主管開始. Today's behaviour is the first one. */\nexport const ORG_MANAGER_CHAIN_START_OPTIONS: readonly Readonly<{\n id: OrgManagerChainStartMode;\n name: string;\n}>[] = [\n { id: 'INITIATOR', name: '發起人' },\n { id: 'FORM_MEMBER', name: '表單欄位的人' },\n { id: 'NODE_ACTOR', name: '前面關卡的簽核者' },\n];\n\n/** The id of the read-only entry an unknown start is shown as. */\nexport const UNSUPPORTED_ORG_MANAGER_CHAIN_START_OPTION_ID = 'UNSUPPORTED';\n\nconst UNSUPPORTED_ORG_MANAGER_CHAIN_START_HINT =\n '此引擎版本不支援這種主管鏈起點;這裡選擇其他起點會覆寫原設定';\n\n/** The 從職等幾開始簽 choice that leaves the setting out. */\nexport const NO_START_POSITION_LEVEL_OPTION_ID = 'NONE';\n\nconst NO_START_POSITION_LEVEL_OPTION: OrgManagerChainStartOption = {\n id: NO_START_POSITION_LEVEL_OPTION_ID,\n name: '不指定(從鏈上第一位有職等的主管開始簽)',\n};\n\nconst INVALID_START_POSITION_LEVEL_OPTION_ID = 'invalid';\n\nexport const START_POSITION_LEVEL_HINT =\n '職等低於這裡的主管只會被略過、不簽核;留白則從鏈上第一位有職等的主管開始簽。不可高於「簽到職等」。';\n\nexport const START_POSITION_LEVEL_ABOVE_MIN_HINT =\n '起始職等不可高於簽到職等,發布前必須修正。';\n\nconst ORG_MANAGER_CHAIN_START_HINTS: Readonly<\n Record<OrgManagerChainStartMode, string>\n> = {\n FORM_MEMBER: '依申請人送出表單時在該欄位選的人員,從他的主管開始往上簽。',\n INITIATOR: '從發起人的直屬主管開始往上簽。',\n NODE_ACTOR: '從所選前面關卡實際簽核的那一位開始,往上找他的主管。',\n};\n\n// The `type` of a start as saved, or `''` for anything that is not a start\n// object (raw JSON nothing has linted): `readUnsupportedOrgManagerChainStartType`\n// names that `(缺少型別)`.\nfunction readStoredStartType(startFrom: unknown): string {\n const type =\n typeof startFrom === 'object' && startFrom !== null\n ? (startFrom as { readonly type?: unknown }).type\n : undefined;\n\n return typeof type === 'string' ? type : '';\n}\n\n/**\n * Where the chain starts, or `null` for a start this build does not know (a\n * definition saved by a newer BPMCore): shown read-only, never rewritten.\n * No `startFrom` is the initiator.\n */\nexport function readOrgManagerChainStartMode(\n resolver: OrgManagerChainResolver,\n): OrgManagerChainStartMode | null {\n if (isOrgManagerChainStartedFromInitiator(resolver)) {\n return 'INITIATOR';\n }\n\n return readUnsupportedOrgManagerChainStartType({\n type: readStoredStartType(resolver.startFrom),\n }) === null\n ? (resolver.startFrom?.type ?? 'INITIATOR')\n : null;\n}\n\nexport type OrgManagerChainStartChoice = Readonly<{\n /** Hint under the select: what the chosen start means. */\n hint: string;\n options: readonly OrgManagerChainStartOption[];\n selected: OrgManagerChainStartOption;\n}>;\n\n/**\n * The 從誰的主管開始 select. A start this build does not know is the current\n * value as an extra read-only entry; picking it writes nothing\n * ({@link readOrgManagerChainStartPick}).\n */\nexport function readOrgManagerChainStartChoice(\n resolver: OrgManagerChainResolver,\n): OrgManagerChainStartChoice {\n const mode = readOrgManagerChainStartMode(resolver);\n\n if (mode === null) {\n const selected = {\n id: UNSUPPORTED_ORG_MANAGER_CHAIN_START_OPTION_ID,\n name: readUnsupportedOrgManagerChainStartLabel(resolver),\n };\n\n return {\n hint: UNSUPPORTED_ORG_MANAGER_CHAIN_START_HINT,\n options: [...ORG_MANAGER_CHAIN_START_OPTIONS, selected],\n selected,\n };\n }\n\n return {\n hint: ORG_MANAGER_CHAIN_START_HINTS[mode],\n options: ORG_MANAGER_CHAIN_START_OPTIONS,\n selected:\n ORG_MANAGER_CHAIN_START_OPTIONS.find((option) => option.id === mode) ??\n ORG_MANAGER_CHAIN_START_OPTIONS[0],\n };\n}\n\nfunction readUnsupportedOrgManagerChainStartLabel(\n resolver: OrgManagerChainResolver,\n): string {\n const type =\n readUnsupportedOrgManagerChainStartType({\n type: readStoredStartType(resolver.startFrom),\n }) ?? '';\n\n // The shared name of a start with no type already carries its own brackets.\n return type.startsWith('(')\n ? `不支援的起點${type}`\n : `不支援的起點(${type})`;\n}\n\n// A copy of the resolver without one key, so that no `undefined` key is written\n// and whatever else the definition carries is kept as it is.\nfunction omitOrgManagerChainKey(\n resolver: OrgManagerChainResolver,\n omitted: 'startFrom' | 'startPositionLevel',\n): OrgManagerChainResolver {\n return Object.fromEntries(\n Object.entries(resolver).filter(([key]) => key !== omitted),\n ) as OrgManagerChainResolver;\n}\n\n/**\n * The resolver after 從誰的主管開始 is set to `mode`: the initiator drops the\n * `startFrom` key (the same as never having set it), a form field or earlier\n * stages starts empty for the author to fill. The start level and the rest of\n * the resolver are kept.\n */\nexport function withOrgManagerChainStart(\n resolver: OrgManagerChainResolver,\n mode: OrgManagerChainStartMode,\n): OrgManagerChainResolver {\n const base = omitOrgManagerChainKey(resolver, 'startFrom');\n\n if (mode === 'FORM_MEMBER') {\n return { ...base, startFrom: { formPath: '', type: 'FORM_MEMBER' } };\n }\n\n if (mode === 'NODE_ACTOR') {\n return { ...base, startFrom: { nodeIds: [], type: 'NODE_ACTOR' } };\n }\n\n return base;\n}\n\n/**\n * The resolver a 從誰的主管開始 pick produces, or `null` when the pick must\n * change nothing: no option, the read-only unsupported entry, or the start the\n * resolver already has (re-picking it used to clear the field or stages\n * already chosen).\n */\nexport function readOrgManagerChainStartPick(\n resolver: ApproverResolver,\n optionId: string | null,\n): OrgManagerChainResolver | null {\n const picked = ORG_MANAGER_CHAIN_START_OPTIONS.find(\n (option) => option.id === optionId,\n );\n\n if (\n resolver.type !== 'ORG_MANAGER_CHAIN' ||\n !picked ||\n picked.id === readOrgManagerChainStartMode(resolver)\n ) {\n return null;\n }\n\n return withOrgManagerChainStart(resolver, picked.id);\n}\n\n/** The form field a `FORM_MEMBER` start names, else `null`. */\nexport function readOrgManagerChainStartFormPath(\n resolver: OrgManagerChainResolver,\n): string | null {\n return resolver.startFrom?.type === 'FORM_MEMBER'\n ? resolver.startFrom.formPath\n : null;\n}\n\n/** The stages a `NODE_ACTOR` start names, else `null`. */\nexport function readOrgManagerChainStartNodeIds(\n resolver: OrgManagerChainResolver,\n): readonly string[] | null {\n return resolver.startFrom?.type === 'NODE_ACTOR'\n ? resolver.startFrom.nodeIds\n : null;\n}\n\n/**\n * The resolver with the field of a `FORM_MEMBER` start set. Any other start\n * comes back as the same object: there is no field to write.\n */\nexport function withOrgManagerChainStartFormPath(\n resolver: OrgManagerChainResolver,\n formPath: string,\n): OrgManagerChainResolver {\n return resolver.startFrom?.type === 'FORM_MEMBER'\n ? { ...resolver, startFrom: { formPath, type: 'FORM_MEMBER' } }\n : resolver;\n}\n\n/**\n * The resolver with the stages of a `NODE_ACTOR` start set. Any other start\n * comes back as the same object.\n */\nexport function withOrgManagerChainStartNodeIds(\n resolver: OrgManagerChainResolver,\n nodeIds: readonly string[],\n): OrgManagerChainResolver {\n return resolver.startFrom?.type === 'NODE_ACTOR'\n ? { ...resolver, startFrom: { nodeIds, type: 'NODE_ACTOR' } }\n : resolver;\n}\n\n// The stored start level when it is a whole number, `null` otherwise. The\n// publish check (`readOrgManagerChainIssue`) refuses a level that is not an\n// integer (2.5) the same as one that is not a number, so the designer reads\n// both as one problem.\nfunction readValidOrgManagerChainStartLevel(\n resolver: OrgManagerChainResolver,\n): number | null {\n const level = readOrgManagerChainStartPositionLevel(resolver);\n\n return level !== null && Number.isInteger(level) ? level : null;\n}\n\n/**\n * The resolver after 簽到職等 is set to `minPositionLevel`: `startFrom`,\n * `startPositionLevel` and `fallback` stay as they were.\n */\nexport function withOrgManagerChainMinPositionLevel(\n resolver: OrgManagerChainResolver,\n minPositionLevel: number,\n): OrgManagerChainResolver {\n return { ...resolver, minPositionLevel };\n}\n\nexport type OrgManagerChainStartLevelChoice = Readonly<{\n /** The stored level is not a whole number: shown, not offered. */\n invalid: boolean;\n options: readonly OrgManagerChainStartOption[];\n selected: OrgManagerChainStartOption;\n}>;\n\n/**\n * The 從職等幾開始簽 select: 不指定 plus the position levels at or below\n * 簽到職等 (a start above it cannot be published, so it is not offered). A\n * stored level the directory has no position for, or one above 簽到職等, stays\n * in the list so the select can show it; a stored value that is not a number\n * is shown as invalid rather than as 不指定.\n */\nexport function readOrgManagerChainStartLevelChoice(\n resolver: OrgManagerChainResolver,\n positions: readonly PositionRecord[],\n): OrgManagerChainStartLevelChoice {\n const level = readValidOrgManagerChainStartLevel(resolver);\n const stored: unknown = resolver.startPositionLevel;\n const levelOptions = readMinPositionLevelOptions(positions, level)\n .filter(\n (option) =>\n option.value <= resolver.minPositionLevel || option.value === level,\n )\n .map(({ id, name }) => ({ id, name }));\n const options = [NO_START_POSITION_LEVEL_OPTION, ...levelOptions];\n\n if (level !== null) {\n return {\n invalid: false,\n options,\n selected:\n levelOptions.find((option) => option.id === String(level)) ??\n NO_START_POSITION_LEVEL_OPTION,\n };\n }\n\n if (stored === undefined || stored === null) {\n return {\n invalid: false,\n options,\n selected: NO_START_POSITION_LEVEL_OPTION,\n };\n }\n\n const invalid = {\n id: INVALID_START_POSITION_LEVEL_OPTION_ID,\n name: '起始職等無效',\n };\n\n return { invalid: true, options: [...options, invalid], selected: invalid };\n}\n\n/**\n * The resolver a 從職等幾開始簽 pick produces, or `null` when the pick must\n * change nothing: no option, the invalid entry, or the level already stored.\n * 不指定 drops the `startPositionLevel` key (never writes `undefined`).\n */\nexport function readOrgManagerChainStartLevelPick(\n resolver: ApproverResolver,\n optionId: string | null,\n): OrgManagerChainResolver | null {\n if (resolver.type !== 'ORG_MANAGER_CHAIN' || optionId === null) {\n return null;\n }\n\n const current = readOrgManagerChainStartPositionLevel(resolver);\n\n if (optionId === NO_START_POSITION_LEVEL_OPTION_ID) {\n return current === null && resolver.startPositionLevel === undefined\n ? null\n : omitOrgManagerChainKey(resolver, 'startPositionLevel');\n }\n\n const level = Number(optionId);\n\n return Number.isFinite(level) && level !== current\n ? { ...resolver, startPositionLevel: level }\n : null;\n}\n\n/**\n * Why the chosen 簽到職等 and 從職等幾開始簽 cannot be published together, or\n * `null`. The same rule as the publish check (`readOrgManagerChainIssue`),\n * said under the select as the author picks.\n */\nexport function readOrgManagerChainStartLevelProblem(\n resolver: OrgManagerChainResolver,\n): string | null {\n const level = readValidOrgManagerChainStartLevel(resolver);\n\n return level !== null && level > resolver.minPositionLevel\n ? START_POSITION_LEVEL_ABOVE_MIN_HINT\n : null;\n}\n\nfunction readOrgManagerChainStartSummary(\n resolver: OrgManagerChainResolver,\n formSchema: FormDefinitionSchema | null,\n nodes: readonly NodeNameRecord[] | undefined,\n): string | null {\n const mode = readOrgManagerChainStartMode(resolver);\n\n if (mode === null) {\n return readUnsupportedOrgManagerChainStartLabel(resolver);\n }\n\n if (mode === 'FORM_MEMBER') {\n const formPath = readOrgManagerChainStartFormPath(resolver) ?? '';\n\n return formPath.trim()\n ? `從表單欄位「${readFormFieldDisplayName(formSchema, formPath)}」的主管起算`\n : '從表單欄位(未指定)的主管起算';\n }\n\n if (mode === 'NODE_ACTOR') {\n const nodeIds = readOrgManagerChainStartNodeIds(resolver) ?? [];\n\n return nodeIds.length > 0\n ? `從前面關卡「${readStageSummary(nodeIds, nodes)}」簽核者的主管起算`\n : '從前面關卡(未指定)簽核者的主管起算';\n }\n\n return null;\n}\n\n// The 無主管時 hint a manager chain has always shown.\nconst ORG_MANAGER_CHAIN_FALLBACK_HINT =\n '預設會停止流程並提示;若設定固定人,主管鏈在達到簽核職等前就結束時,會再加上該會員作為最後一關。';\n\n/**\n * The hint under 無主管時 for a manager chain. With neither the start nor the\n * start level set it is the text it always was. Otherwise it adds the two ways\n * the engine ends up at the fallback with nobody on the chain: no start person\n * (`resolveOrgManagerChainStart` returns no member) and no manager at or above\n * the start level (the chain stays empty and `resolveFallbackAssignees` runs).\n */\nexport function readOrgManagerChainFallbackHint(\n resolver: OrgManagerChainResolver,\n): string {\n const mode = readOrgManagerChainStartMode(resolver);\n const emptyChainCases = [\n ...(mode === 'FORM_MEMBER' ? ['找不到起點(表單欄位沒選人)'] : []),\n ...(mode === 'NODE_ACTOR' ? ['找不到起點(前面關卡沒有同意紀錄)'] : []),\n ...(readOrgManagerChainStartPositionLevel(resolver) !== null\n ? ['鏈上沒有人達到起始職等']\n : []),\n ];\n\n return emptyChainCases.length > 0\n ? `${ORG_MANAGER_CHAIN_FALLBACK_HINT.slice(0, -1)};${emptyChainCases.join(',或')}時,則改派給該會員。`\n : ORG_MANAGER_CHAIN_FALLBACK_HINT;\n}\n\n/**\n * 主管鏈:簽到職等 N, with the start and the start level only when they are\n * set: 主管鏈:從表單欄位「X」的主管起算,簽到職等 N(從職等 M 開始).\n * A chain with neither setting reads as it always did.\n */\nfunction readOrgManagerChainSummary(\n resolver: OrgManagerChainResolver,\n formSchema: FormDefinitionSchema | null,\n nodes: readonly NodeNameRecord[] | undefined,\n): string {\n const start = readOrgManagerChainStartSummary(resolver, formSchema, nodes);\n const startLevel = readOrgManagerChainStartPositionLevel(resolver);\n\n return `主管鏈:${start ? `${start},` : ''}簽到職等 ${resolver.minPositionLevel}${\n startLevel === null ? '' : `(從職等 ${startLevel} 開始)`\n }`;\n}\n","import { DecisionPolicy } from '@rytass/bpm-core-shared/workflow';\n\nexport type DecisionPolicyOption = Readonly<{\n id: DecisionPolicy['type'];\n name: string;\n}>;\n\nexport const DECISION_POLICY_OPTIONS: readonly DecisionPolicyOption[] = [\n { id: 'SINGLE', name: '單人簽核' },\n { id: 'PARALLEL_ANY', name: '任一人同意' },\n { id: 'PARALLEL_ALL', name: '全部同意' },\n { id: 'SEQUENTIAL', name: '依序簽核' },\n { id: 'QUORUM', name: '達到指定門檻' },\n];\n\nexport function readDecisionPolicyHint(\n policy: DecisionPolicy | undefined,\n): string {\n if (!policy || policy.type === 'SINGLE' || policy.type === 'PARALLEL_ANY') {\n return '可指定多位;多位時所有人都會收到待辦,任一人同意即可通過。';\n }\n\n if (policy.type === 'PARALLEL_ALL') {\n return '可指定多位;多位時所有人都會收到待辦,全部同意後才會通過。';\n }\n\n if (policy.type === 'SEQUENTIAL') {\n return '依簽核人順序一次開放一位,前一位核准後才輪到下一位;任一位拒絕或退回即結束此關。';\n }\n\n const thresholdUnit =\n policy.thresholdType === 'PERCENTAGE' ? '%' : ' 位簽核者';\n\n return `可指定多位;需達到 ${policy.threshold}${thresholdUnit} 才會通過。`;\n}\n\nexport function readDecisionPolicyOption(\n type: DecisionPolicy['type'],\n): DecisionPolicyOption {\n const option = DECISION_POLICY_OPTIONS.find((item) => item.id === type);\n\n if (option) {\n return option;\n }\n\n // Any other stored value falls outside `DecisionPolicy['type']`'s own\n // union — it can only have come from an untyped source (API payload, an\n // older schema) this form was never told about. Echo it verbatim instead\n // of mislabelling it as a specific known policy.\n return { id: type, name: `未知決策方式(${type})` };\n}\n","import { useCallback, useMemo, useRef, useState } from 'react';\nimport {\n WorkflowCommand,\n WorkflowCommandResult,\n WorkflowDesignerState,\n WorkflowMacroCommand,\n WorkflowDirectory,\n WorkflowExpressionTools,\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 * Backend expression lint / preview / catalog for the assistant (Phase 23\n * P4). Read per tool call with the state the call runs against. Without it\n * every tool call that writes an expression is refused.\n */\n readonly expressionTools?: (\n state: WorkflowDesignerState,\n ) => WorkflowExpressionTools;\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 expressionTools,\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 const expressionToolsRef = useRef(expressionTools);\n expressionToolsRef.current = expressionTools;\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 // Tool calls run one after another: each reads the state the previous one\n // committed, so parallel calls from one assistant turn cannot overwrite\n // each other while one waits on the backend lint.\n const toolQueueRef = useRef<Promise<unknown>>(Promise.resolve());\n\n const runTool = useCallback(\n async (toolName: string, input: unknown): Promise<WorkflowToolResult> => {\n const before = stateRef.current;\n const result = await executeWorkflowTool(before, toolName, input, {\n directory: directoryRef.current,\n expressions: expressionToolsRef.current?.(before),\n });\n\n if (result.ok && (result.kind === 'mutation' || result.kind === 'macro')) {\n // An expression write waits on the backend lint; committing a result\n // computed from a state the user has since edited would drop that edit.\n if (stateRef.current !== before) {\n return {\n error: '檢查運算式期間畫布已被修改,這次變更沒有套用,請重新讀取 snapshot 後再試。',\n ok: false,\n };\n }\n\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 executeTool = useCallback(\n (toolName: string, input: unknown): Promise<WorkflowToolResult> => {\n const run = toolQueueRef.current.then(\n (): Promise<WorkflowToolResult> => runTool(toolName, input),\n );\n\n toolQueueRef.current = run.catch((): void => undefined);\n\n return run;\n },\n [runTool],\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';\nimport { WORKFLOW_CHAT_EXPRESSION_GUIDANCE } from './workflow-chat-prompt';\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${WORKFLOW_CHAT_EXPRESSION_GUIDANCE}\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","import {\n readNodeFieldAccess,\n type FieldAccessChoice,\n type FieldAccessEffective,\n type FieldAccessIssue,\n type FieldAccessIssueCode,\n type FieldAccessMatrixColumn,\n} from '@rytass/bpm-core-shared';\nimport type { UserTaskNode } from '@rytass/bpm-core-shared/workflow';\n\nexport const FIELD_ACCESS_CHOICE_LABELS: Readonly<\n Record<FieldAccessChoice, string>\n> = {\n DEFAULT: '預設',\n FILL_OPTIONAL: '補填(選填)',\n FILL_REQUIRED: '補填(必填)',\n HIDE: '隱藏',\n SHOW: '顯示',\n};\n\nexport const FIELD_ACCESS_EFFECTIVE_LABELS: Readonly<\n Record<FieldAccessEffective, string>\n> = {\n FILL: '填寫',\n FILL_OPTIONAL: '補填(選填)',\n FILL_REQUIRED: '補填(必填)',\n HIDDEN: '隱藏',\n NOT_SHOWN: '不顯示',\n READ_ONLY: '唯讀',\n};\n\n/**\n * Why the form will not let an approver fill a field in, short enough for the\n * matrix's check column. The full lint line is shown once the field is\n * actually set to be filled in.\n */\nexport const FIELD_ACCESS_FILL_BLOCKER_LABELS: Readonly<\n Partial<Record<FieldAccessIssueCode, string>>\n> = {\n approverFilledFieldDataSource: '選項來自資料來源,不能補填',\n approverFilledFieldFileUpload: '檔案上傳欄位不能補填',\n approverFilledFieldFormRule: '表單已設定必填、顯示或預設值等規則,不能補填',\n approverFilledTableDataSourceColumn: '表格含資料來源欄,不能補填',\n};\n\nexport const FIELD_ACCESS_BOOLEAN_REQUIRED_NOTE =\n '開關欄位只能選填補填:開關關著也是答案,不能要求必填。';\n\nexport const FIELD_ACCESS_HIDE_NOTE =\n '「隱藏」只影響這一關的畫面,不是權限:資料查詢仍拿得到值,不能用來保密。';\n\nexport function readFieldAccessStageLabel(\n column: Pick<FieldAccessMatrixColumn, 'stage'>,\n): string {\n return `關卡 ${column.stage}`;\n}\n\nexport interface FieldAccessNodeCounts {\n readonly fill: number;\n readonly hidden: number;\n readonly required: number;\n}\n\nexport function readFieldAccessNodeCounts(\n node: UserTaskNode,\n): FieldAccessNodeCounts {\n const entries = readNodeFieldAccess(node);\n\n return {\n fill: entries.filter((entry) => entry.fill !== 'NONE').length,\n hidden: entries.filter(\n (entry) => entry.fill === 'NONE' && entry.display === 'HIDE',\n ).length,\n required: entries.filter((entry) => entry.fill === 'REQUIRED').length,\n };\n}\n\n/** The node card's tag, e.g. 「補填 2 · 隱藏 1」; `null` with nothing set. */\nexport function readFieldAccessNodeTag(node: UserTaskNode): string | null {\n const { fill, hidden } = readFieldAccessNodeCounts(node);\n const parts = [\n ...(fill > 0 ? [`補填 ${fill}`] : []),\n ...(hidden > 0 ? [`隱藏 ${hidden}`] : []),\n ];\n\n return parts.length ? parts.join(' · ') : null;\n}\n\nconst FILL_CONFLICT_CODES: ReadonlySet<FieldAccessIssueCode> = new Set([\n 'fieldAccessAutoApprove',\n 'fieldAccessGroupPolicy',\n 'fieldAccessSkipNode',\n]);\n\nexport function isFillConflictIssue(issue: FieldAccessIssue): boolean {\n return FILL_CONFLICT_CODES.has(issue.code);\n}\n","import {\n useMemo,\n useState,\n type CSSProperties,\n type ReactElement,\n} from 'react';\nimport {\n Badge,\n InlineMessage,\n Select,\n Table,\n Toggle,\n Typography,\n} from '@mezzanine-ui/react';\nimport Drawer from '@mezzanine-ui/react/Drawer';\nimport type { TableColumn } from '@mezzanine-ui/core/table';\nimport {\n FIELD_ACCESS_CHOICES,\n applyWorkflowCommand,\n isFieldAccessEntryValid,\n readFieldAccessEntryForChoice,\n readFieldAccessMatrix,\n readNodeFieldAccess,\n type FieldAccessChoice,\n type FieldAccessMatrix,\n type FieldAccessMatrixCell,\n type FieldAccessMatrixColumn,\n type FieldAccessMatrixEntry,\n type FieldAccessMatrixRow,\n} from '@rytass/bpm-core-shared';\nimport type { FormDefinitionSchema } from '@rytass/bpm-core-shared/form';\nimport type {\n UserTaskNode,\n WorkflowDefinition,\n} from '@rytass/bpm-core-shared/workflow';\nimport { readWorkflowLintMessage } from '@rytass/bpm-core-client/template';\nimport type { BPMLanguage } from '../../../../lib/language-provider';\nimport {\n FIELD_ACCESS_BOOLEAN_REQUIRED_NOTE,\n FIELD_ACCESS_CHOICE_LABELS,\n FIELD_ACCESS_EFFECTIVE_LABELS,\n FIELD_ACCESS_FILL_BLOCKER_LABELS,\n FIELD_ACCESS_HIDE_NOTE,\n readFieldAccessStageLabel,\n} from './field-access-copy';\n\nexport interface FieldAccessMatrixDrawerProps {\n readonly definition: WorkflowDefinition;\n /**\n * Phase 23 P4: per field key, the labels of the expressions that read it\n * (from `analyzeWorkflowExpressions`). Such a field cannot be renamed or\n * deleted while they do; the matrix marks it.\n */\n readonly expressionReferences?: ReadonlyMap<string, readonly string[]>;\n readonly formSchema: FormDefinitionSchema | null;\n readonly language: BPMLanguage;\n /**\n * Called with the whole matrix, only when it differs from `definition`.\n * Answers why it could not be applied, or `null` once it was.\n */\n readonly onApply: (\n entries: readonly FieldAccessMatrixEntry[],\n ) => string | null;\n readonly onClose: () => void;\n readonly open: boolean;\n}\n\n// A type literal, not the row interface: Table wants an index signature.\ntype MatrixTableRow = {\n readonly key: string;\n readonly row: FieldAccessMatrixRow;\n};\n\nconst BODY_STYLE: CSSProperties = {\n display: 'grid',\n gap: 12,\n // Keeps the wide table inside the drawer, scrolling in its own area,\n // instead of stretching the column past the drawer's edge.\n gridTemplateColumns: 'minmax(0, 1fr)',\n padding:\n 'var(--mzn-spacing-padding-vertical-spacious) var(--mzn-spacing-padding-horizontal-spacious)',\n};\n\nconst STACK_STYLE: CSSProperties = {\n display: 'grid',\n gap: 4,\n};\n\nconst FIELD_CELL_STYLE: CSSProperties = {\n display: 'grid',\n};\n\n/**\n * Every user task's entries in definition order, unknown field keys included:\n * the matrix only has rows for the form's fields, and applying must not drop\n * an entry nobody was shown. An entry the publish lint rejects (a blank field\n * key) is left out, so applying clears it instead of being refused for it.\n */\nfunction readDefinitionEntries(\n definition: WorkflowDefinition,\n): readonly FieldAccessMatrixEntry[] {\n return definition.nodes\n .filter((node): node is UserTaskNode => node.type === 'userTask')\n .flatMap((node) =>\n readNodeFieldAccess(node)\n .filter(isFieldAccessEntryValid)\n .map((entry): FieldAccessMatrixEntry => ({\n ...entry,\n nodeId: node.id,\n })),\n );\n}\n\n/**\n * Puts `next` in the place of the node's entry for the field, so untouched\n * nodes keep their order; a new one goes last and `null` removes it.\n */\nfunction setFieldAccessDraftEntry(\n entries: readonly FieldAccessMatrixEntry[],\n nodeId: string,\n fieldKey: string,\n next: FieldAccessMatrixEntry | null,\n): readonly FieldAccessMatrixEntry[] {\n const index = entries.findIndex(\n (candidate) =>\n candidate.nodeId === nodeId && candidate.fieldKey === fieldKey,\n );\n\n if (index === -1) {\n return next === null ? entries : [...entries, next];\n }\n\n return entries.flatMap((candidate, candidateIndex) =>\n candidateIndex === index ? (next === null ? [] : [next]) : [candidate],\n );\n}\n\n/** Sets one cell of the draft; `DEFAULT` removes its entry. */\nexport function updateFieldAccessDraft(\n entries: readonly FieldAccessMatrixEntry[],\n nodeId: string,\n fieldKey: string,\n choice: FieldAccessChoice,\n): readonly FieldAccessMatrixEntry[] {\n const entry = readFieldAccessEntryForChoice(fieldKey, choice);\n\n return setFieldAccessDraftEntry(\n entries,\n nodeId,\n fieldKey,\n entry === null ? null : { ...entry, nodeId },\n );\n}\n\nfunction readEntryKey(entry: FieldAccessMatrixEntry): string {\n return `${entry.nodeId}\\u0000${entry.fieldKey}`;\n}\n\n/**\n * The cells edited in the drawer (`draft` against `initial`), laid onto the\n * entries the flow holds now. An undo or an assistant edit made while the\n * drawer was open keeps every cell the drawer did not touch, and a node that\n * stopped being a user task meanwhile is dropped.\n */\nexport function rebaseFieldAccessDraft(\n current: readonly FieldAccessMatrixEntry[],\n initial: readonly FieldAccessMatrixEntry[],\n draft: readonly FieldAccessMatrixEntry[],\n userTaskIds: ReadonlySet<string>,\n): readonly FieldAccessMatrixEntry[] {\n const initialByKey = new Map(\n initial.map((entry) => [readEntryKey(entry), entry] as const),\n );\n const draftByKey = new Map(\n draft.map((entry) => [readEntryKey(entry), entry] as const),\n );\n const edited = [...initial, ...draft].filter(\n (entry, index, all) =>\n all.findIndex(\n (candidate) => readEntryKey(candidate) === readEntryKey(entry),\n ) === index &&\n JSON.stringify(initialByKey.get(readEntryKey(entry))) !==\n JSON.stringify(draftByKey.get(readEntryKey(entry))),\n );\n\n return edited\n .reduce(\n (entries, entry) =>\n setFieldAccessDraftEntry(\n entries,\n entry.nodeId,\n entry.fieldKey,\n draftByKey.get(readEntryKey(entry)) ?? null,\n ),\n current,\n )\n .filter((entry) => userTaskIds.has(entry.nodeId));\n}\n\nfunction readUserTaskIds(definition: WorkflowDefinition): ReadonlySet<string> {\n return new Set(\n definition.nodes\n .filter((node) => node.type === 'userTask')\n .map((node) => node.id),\n );\n}\n\n/** The definition with the draft applied, through the same command `套用` dispatches. */\nfunction readDraftDefinition(\n definition: WorkflowDefinition,\n formSchema: FormDefinitionSchema | null,\n entries: readonly FieldAccessMatrixEntry[],\n): WorkflowDefinition {\n return applyWorkflowCommand(\n {\n definition,\n editingEdgeId: null,\n formDefinitionVersionId: null,\n formSchema,\n initiatorPolicyCel: null,\n selectedEdgeIds: [],\n selectedNodeId: null,\n },\n { entries, type: 'setFieldAccessMatrix' },\n ).state.definition;\n}\n\n/**\n * Whether every user task stores exactly what the matrix reads. An entry the\n * reader repairs or skips (an unknown `fill`, a blank or repeated field key)\n * reads like a valid one, so only a rewrite clears what blocks publishing.\n */\nfunction isStoredAsRead(definition: WorkflowDefinition): boolean {\n return definition.nodes.every(\n (node) =>\n node.type !== 'userTask' ||\n node.data.fieldAccess === undefined ||\n readStoredEntriesKey(node.data.fieldAccess) ===\n readStoredEntriesKey(\n readDefinitionEntries({ ...definition, nodes: [node] }),\n ),\n );\n}\n\n// Key order and extra keys are not a difference worth rewriting.\nfunction readStoredEntriesKey(value: unknown): string {\n return JSON.stringify(\n Array.isArray(value) ? value.map(readStoredEntryKey) : value,\n );\n}\n\nfunction readStoredEntryKey(entry: unknown): unknown {\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {\n return entry;\n }\n\n const { display, fieldKey, fill } = entry as {\n readonly display?: unknown;\n readonly fieldKey?: unknown;\n readonly fill?: unknown;\n };\n\n return [display, fieldKey, fill];\n}\n\nfunction isSameEntries(\n left: readonly FieldAccessMatrixEntry[],\n right: readonly FieldAccessMatrixEntry[],\n): boolean {\n return JSON.stringify(left) === JSON.stringify(right);\n}\n\n/**\n * One opening of the drawer: the entries it opened with, the draft, and the\n * rows the filter keeps however they read now — the rows that had a setting\n * or an issue on opening, and every row edited since, so a row set back to\n * 預設 does not vanish under the cursor.\n */\ninterface MatrixSession {\n readonly draft: readonly FieldAccessMatrixEntry[];\n readonly initial: readonly FieldAccessMatrixEntry[];\n readonly pinnedFieldKeys: ReadonlySet<string>;\n}\n\nconst EMPTY_MATRIX: FieldAccessMatrix = { columns: [], issues: [], rows: [] };\n\nfunction readMatrixSession(\n definition: WorkflowDefinition,\n formSchema: FormDefinitionSchema | null,\n): MatrixSession {\n const entries = readDefinitionEntries(definition);\n\n return {\n draft: entries,\n initial: entries,\n pinnedFieldKeys: new Set(\n readFieldAccessMatrix(definition, formSchema)\n .rows.filter(isRowRelevant)\n .map((row) => row.fieldKey),\n ),\n };\n}\n\nfunction isRowRelevant(row: FieldAccessMatrixRow): boolean {\n return (\n row.cells.some((cell) => cell.explicit !== null) ||\n row.issues.length > 0 ||\n row.notices.length > 0\n );\n}\n\n/**\n * The choices a cell offers. Mezzanine's Select has no per-option disabled\n * state, so a choice the field or node cannot take is left out — except the\n * one already chosen, which an old draft may hold and which has to stay\n * readable (its check column says why it blocks publishing).\n */\nfunction readCellOptions(\n cell: FieldAccessMatrixCell,\n): readonly { readonly id: FieldAccessChoice; readonly name: string }[] {\n return FIELD_ACCESS_CHOICES.filter(\n (choice) =>\n choice === cell.choice || !cell.disabledChoices.includes(choice),\n ).map((choice) => ({\n id: choice,\n name:\n choice === 'DEFAULT' && cell.choice === 'DEFAULT'\n ? `預設:${FIELD_ACCESS_EFFECTIVE_LABELS[cell.effective]}`\n : FIELD_ACCESS_CHOICE_LABELS[choice],\n }));\n}\n\nfunction readApplicantText(\n row: FieldAccessMatrixRow,\n columns: readonly FieldAccessMatrixColumn[],\n): string {\n if (row.applicant.effective === 'FILL') {\n return FIELD_ACCESS_EFFECTIVE_LABELS.FILL;\n }\n\n const stages = row.fillNodeIds\n .map((nodeId) => columns.find((column) => column.nodeId === nodeId))\n .filter((column): column is FieldAccessMatrixColumn => Boolean(column))\n .map(readFieldAccessStageLabel)\n .join('、');\n\n return `${FIELD_ACCESS_EFFECTIVE_LABELS.NOT_SHOWN}(${stages} 補填)`;\n}\n\n/**\n * The 欄位與關卡總覽 (ADR 20 §3.3): one row per form field, one column per\n * user task in flow order, edited as a draft and written in one\n * `setFieldAccessMatrix` on 套用. The checks are recomputed from the draft\n * with the publish lint's own rules, so a conflict shows before applying.\n */\nexport function FieldAccessMatrixDrawer({\n definition,\n expressionReferences,\n formSchema,\n language,\n onApply,\n onClose,\n open,\n}: FieldAccessMatrixDrawerProps): ReactElement {\n const [session, setSession] = useState<MatrixSession | null>(null);\n const [onlyRelevant, setOnlyRelevant] = useState(true);\n const [applyError, setApplyError] = useState<string | null>(null);\n\n // Started while rendering the opening, not in an effect, so the first frame\n // already shows the draft. Rebuilt on every opening: an undo or an\n // assistant edit made while the drawer was closed is what it starts from,\n // and edits behind an open drawer do not reset it.\n if (open && session === null) {\n const opened = readMatrixSession(definition, formSchema);\n\n setSession(opened);\n // With nothing set yet the filter would hide every field and the matrix\n // would open empty, so it starts collapsed only once something is set.\n setOnlyRelevant(opened.pinnedFieldKeys.size > 0);\n setApplyError(null);\n }\n\n if (!open && session !== null) {\n setSession(null);\n }\n\n // What 套用 would write: the drawer's edits over the flow as it is now.\n const entries = useMemo(\n () =>\n session === null\n ? null\n : rebaseFieldAccessDraft(\n readDefinitionEntries(definition),\n session.initial,\n session.draft,\n readUserTaskIds(definition),\n ),\n [definition, session],\n );\n const draftDefinition = useMemo(\n () =>\n entries === null\n ? definition\n : readDraftDefinition(definition, formSchema, entries),\n [definition, entries, formSchema],\n );\n const matrix: FieldAccessMatrix = useMemo(\n () =>\n entries === null\n ? EMPTY_MATRIX\n : readFieldAccessMatrix(draftDefinition, formSchema),\n [draftDefinition, entries, formSchema],\n );\n const pinnedFieldKeys = session?.pinnedFieldKeys ?? new Set<string>();\n // Against the draft: an issue the draft raises names fill nodes the\n // applied flow does not have yet, and only the draft can translate them.\n const translate = (message: string): string =>\n readWorkflowLintMessage(message, draftDefinition, language);\n const visibleRows = matrix.rows.filter(\n (row) =>\n !onlyRelevant || pinnedFieldKeys.has(row.fieldKey) || isRowRelevant(row),\n );\n const collapsedCount = matrix.rows.length - visibleRows.length;\n const rowFieldKeys = new Set(matrix.rows.map((row) => row.fieldKey));\n // Issues no row can show: node-level ones and field keys the form lacks.\n const unplacedIssues = matrix.issues.filter(\n (issue) => !issue.fieldKeys.some((fieldKey) => rowFieldKeys.has(fieldKey)),\n );\n\n function changeCell(\n nodeId: string,\n fieldKey: string,\n choice: FieldAccessChoice,\n ): void {\n setApplyError(null);\n setSession((current) =>\n current === null\n ? null\n : {\n ...current,\n draft: updateFieldAccessDraft(\n current.draft,\n nodeId,\n fieldKey,\n choice,\n ),\n pinnedFieldKeys: new Set([...current.pinnedFieldKeys, fieldKey]),\n },\n );\n }\n\n function apply(): void {\n const error =\n entries === null ||\n (isSameEntries(entries, readDefinitionEntries(definition)) &&\n isStoredAsRead(definition))\n ? null\n : onApply(entries);\n\n if (error !== null) {\n // The drawer stays open on its draft, so nothing edited is lost.\n setApplyError(error);\n\n return;\n }\n\n onClose();\n }\n\n const columns: TableColumn<MatrixTableRow>[] = [\n {\n ellipsis: false,\n fixed: 'start',\n key: 'field',\n render: ({ row }): ReactElement => (\n <div style={FIELD_CELL_STYLE}>\n <Typography variant=\"label-primary\">{row.field.label}</Typography>\n <Typography color=\"text-neutral\" variant=\"caption\">\n {row.fieldKey}\n </Typography>\n {expressionReferences?.get(row.fieldKey)?.length ? (\n <Badge\n text={`運算式引用 ${expressionReferences.get(row.fieldKey)?.length ?? 0}`}\n variant=\"dot-info\"\n />\n ) : null}\n </div>\n ),\n title: '欄位',\n width: 180,\n },\n {\n ellipsis: false,\n key: 'applicant',\n render: ({ row }): string => readApplicantText(row, matrix.columns),\n title: '申請人',\n width: 160,\n },\n ...matrix.columns.map(\n (column, columnIndex): TableColumn<MatrixTableRow> => ({\n ellipsis: false,\n key: `node:${column.nodeId}`,\n render: ({ row }): ReactElement => {\n const cell = row.cells[columnIndex];\n const options = readCellOptions(cell);\n\n return (\n <Select\n clearable={false}\n inputProps={{\n 'aria-label': `${row.field.label} 在${readFieldAccessStageLabel(column)}的設定`,\n }}\n onChange={(option): void =>\n changeCell(\n column.nodeId,\n row.fieldKey,\n options.find((candidate) => candidate.id === option?.id)\n ?.id ?? 'DEFAULT',\n )\n }\n options={[...options]}\n size=\"sub\"\n value={\n options.find((option) => option.id === cell.choice) ?? null\n }\n />\n );\n },\n title: (\n <div style={STACK_STYLE}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n {readFieldAccessStageLabel(column)}\n {column.branchLabel ? ` · 分支:${column.branchLabel}` : ''}\n </Typography>\n <Typography variant=\"label-primary\">{column.label}</Typography>\n </div>\n ),\n width: 224,\n }),\n ),\n {\n ellipsis: false,\n key: 'check',\n render: ({ row }): ReactElement => renderCheck(row),\n title: '檢查',\n width: 280,\n },\n ];\n\n function renderCheck(row: FieldAccessMatrixRow): ReactElement {\n const warnings = row.issues.map((issue) => translate(issue.message));\n const notices = row.notices.map((notice) => {\n const column = matrix.columns.find(\n (candidate) => candidate.nodeId === notice.nodeId,\n );\n\n return `${column ? readFieldAccessStageLabel(column) : notice.nodeId} 會看到空白欄位:這一關之前還沒有人補填。`;\n });\n // Reasons a fill choice is unavailable; once the field is filled in\n // anyway, the warning above already names the same rule.\n const blockers =\n row.fillNodeIds.length === 0\n ? [\n ...row.fillBlockers.flatMap((issue) => {\n const label = FIELD_ACCESS_FILL_BLOCKER_LABELS[issue.code];\n\n return label ? [label] : [];\n }),\n ...(row.field.type === 'boolean'\n ? [FIELD_ACCESS_BOOLEAN_REQUIRED_NOTE]\n : []),\n ]\n : [];\n\n if (warnings.length + notices.length + blockers.length === 0) {\n return <Badge text=\"沒有問題\" variant=\"dot-success\" />;\n }\n\n return (\n <div style={STACK_STYLE}>\n {warnings.map((text) => (\n <Badge key={`warning:${text}`} text={text} variant=\"dot-warning\" />\n ))}\n {notices.map((text) => (\n <Badge key={`notice:${text}`} text={text} variant=\"dot-info\" />\n ))}\n {[...new Set(blockers)].map((text) => (\n <Badge key={`blocker:${text}`} text={text} variant=\"dot-info\" />\n ))}\n </div>\n );\n }\n\n return (\n <Drawer\n bottomGhostActionText=\"取消\"\n bottomOnGhostActionClick={onClose}\n bottomOnPrimaryActionClick={apply}\n bottomPrimaryActionText=\"套用\"\n headerTitle=\"欄位與關卡總覽\"\n isBottomDisplay\n isHeaderDisplay\n onClose={onClose}\n open={open}\n size=\"wide\"\n >\n <div style={BODY_STYLE}>\n {/* InlineMessage keeps to one line, so each headline is short and\n the detail goes underneath, where it can wrap. */}\n {applyError === null ? null : (\n <div style={STACK_STYLE}>\n <InlineMessage\n content=\"無法套用,編輯內容仍保留。\"\n severity=\"error\"\n />\n <Badge text={applyError} variant=\"dot-error\" />\n </div>\n )}\n <div style={STACK_STYLE}>\n {matrix.issues.length > 0 ? (\n <InlineMessage\n content={`有 ${matrix.issues.length} 個欄位設定問題,處理完才能發布。`}\n severity=\"warning\"\n />\n ) : (\n <InlineMessage\n content=\"補填由該關的簽核人在核准時填寫。\"\n severity=\"info\"\n />\n )}\n <Typography color=\"text-neutral\" variant=\"caption\">\n {matrix.issues.length > 0\n ? '問題標示在各欄位的「檢查」欄。'\n : `申請人送出時看不到補填欄位。${FIELD_ACCESS_HIDE_NOTE}發布時還會檢查條件是否在補填前就讀取這些欄位。`}\n </Typography>\n {unplacedIssues.map((issue) => (\n <Badge\n key={issue.message}\n text={translate(issue.message)}\n variant=\"dot-warning\"\n />\n ))}\n </div>\n <Toggle\n checked={onlyRelevant}\n inputProps={{ 'aria-label': '只看有設定或有問題的欄位' }}\n label=\"只看有設定或有問題的欄位\"\n onChange={(event): void => setOnlyRelevant(event.target.checked)}\n size=\"sub\"\n />\n {collapsedCount > 0 ? (\n <Typography color=\"text-neutral\" variant=\"caption\">\n 已收起 {collapsedCount} 個沒有設定也沒有問題的欄位。\n </Typography>\n ) : null}\n {formSchema === null ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 尚未綁定表單,沒有可設定的欄位。\n </Typography>\n ) : (\n <Table\n columns={columns}\n dataSource={visibleRows.map((row): MatrixTableRow => ({\n key: row.fieldKey,\n row,\n }))}\n fullWidth\n />\n )}\n </div>\n </Drawer>\n );\n}\n","import type { CSSProperties, ReactElement } from 'react';\nimport { Badge, Button, InlineMessage, Typography } from '@mezzanine-ui/react';\nimport { readNodeFieldAccessIssues } from '@rytass/bpm-core-shared';\nimport type {\n UserTaskNode,\n WorkflowDefinition,\n} from '@rytass/bpm-core-shared/workflow';\nimport { readWorkflowLintMessage } from '@rytass/bpm-core-client/template';\nimport type { BPMLanguage } from '../../../../lib/language-provider';\nimport {\n FIELD_ACCESS_HIDE_NOTE,\n isFillConflictIssue,\n readFieldAccessNodeCounts,\n} from './field-access-copy';\n\nexport interface FieldAccessNodeSectionProps {\n readonly definition: WorkflowDefinition;\n readonly language: BPMLanguage;\n readonly node: UserTaskNode;\n /** Why the overview cannot open (no form bound), else `null`. */\n readonly openDisabledReason: string | null;\n readonly onOpenMatrix: () => void;\n readonly onRemoveLegacy: () => void;\n}\n\nconst SECTION_STYLE: CSSProperties = {\n borderTop: '1px solid var(--mzn-color-border-neutral)',\n display: 'grid',\n gap: 8,\n paddingTop: 12,\n};\n\nconst HEADING_ROW_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'flex',\n gap: 8,\n justifyContent: 'space-between',\n};\n\n/**\n * The node panel's summary of the node's field access (ADR 20 §3.3: the\n * overview is the only place to set it, so the panel only counts and points\n * there). It also carries the two warnings that belong to the node itself:\n * a leftover `fieldPermissions` key, and a node setting that cannot let its\n * approver fill fields in.\n */\nexport function FieldAccessNodeSection({\n definition,\n language,\n node,\n onOpenMatrix,\n onRemoveLegacy,\n openDisabledReason,\n}: FieldAccessNodeSectionProps): ReactElement {\n const counts = readFieldAccessNodeCounts(node);\n const conflictMessages = readNodeFieldAccessIssues(node)\n .filter(isFillConflictIssue)\n .map((issue) =>\n readWorkflowLintMessage(issue.message, definition, language),\n );\n\n return (\n <section aria-label=\"欄位顯示與補填\" style={SECTION_STYLE}>\n <div style={HEADING_ROW_STYLE}>\n <Typography component=\"h3\" variant=\"h3\">\n 欄位顯示與補填\n </Typography>\n <Button\n disabled={openDisabledReason !== null}\n onClick={onOpenMatrix}\n size=\"sub\"\n title={openDisabledReason ?? undefined}\n variant=\"base-secondary\"\n >\n 開啟欄位總覽\n </Button>\n </div>\n <Typography color=\"text-neutral\" variant=\"body\">\n 本關補填 {counts.fill} 個(必填 {counts.required})\n </Typography>\n <Typography color=\"text-neutral\" variant=\"body\">\n 本關隱藏 {counts.hidden} 個\n </Typography>\n <Typography color=\"text-neutral\" variant=\"body\">\n 其他欄位依預設\n </Typography>\n {openDisabledReason ? (\n <Typography color=\"text-neutral\" variant=\"caption\">\n {openDisabledReason}\n </Typography>\n ) : null}\n <Typography color=\"text-neutral\" variant=\"caption\">\n {FIELD_ACCESS_HIDE_NOTE}\n </Typography>\n {node.data.fieldPermissions !== undefined ? (\n <>\n <InlineMessage\n content=\"含已停用的舊欄位權限設定\"\n severity=\"warning\"\n />\n <Typography color=\"text-neutral\" variant=\"caption\">\n 舊設定(fieldPermissions)從未生效,也不會自動轉換;移除後才能發布,需要的設定請在欄位總覽重新指定。\n </Typography>\n <div>\n <Button\n onClick={onRemoveLegacy}\n size=\"sub\"\n variant=\"base-secondary\"\n >\n 移除舊設定\n </Button>\n </div>\n </>\n ) : null}\n {conflictMessages.map((message) => (\n <Badge key={message} text={message} variant=\"dot-warning\" />\n ))}\n </section>\n );\n}\n","import type { WorkflowDefinition } from '@rytass/bpm-core-shared/workflow';\nimport { readFormSchemaLintMessage } from '@rytass/bpm-core-client/form';\nimport { readWorkflowLintMessage } from '@rytass/bpm-core-client/template';\nimport type { BPMLanguage } from '../../lib/language-provider';\n\nconst UNKNOWN_ERROR_MESSAGES: Readonly<Record<BPMLanguage, string>> = {\n en: 'An unknown error occurred',\n 'zh-TW': '發生未知錯誤',\n};\n\nconst WEBHOOK_LINT_PREFIXES: Readonly<Record<BPMLanguage, string>> = {\n en: 'Webhook settings failed the publish check: ',\n 'zh-TW': 'Webhook 設定未通過發布檢查:',\n};\n\n/**\n * The message the template designer and the compose wizard show for a failed\n * request, in `language`. Publish failures can carry structural lint lines\n * that name nodes by id and stable `FORM_DATA_SOURCE_*` codes; both are mapped\n * to readable copy and every other message is left untouched.\n */\nexport function readTemplateErrorMessage(\n error: unknown,\n language: BPMLanguage,\n submittedDefinition?: WorkflowDefinition,\n): string {\n if (!(error instanceof Error)) {\n return UNKNOWN_ERROR_MESSAGES[language];\n }\n\n // Structural publish-lint lines name nodes by id; the definition that was\n // just submitted lets them name the node the way the canvas does.\n const message = submittedDefinition\n ? readWorkflowLintMessage(error.message, submittedDefinition, language)\n : error.message;\n\n // The backend publish lint speaks in paths and codes; say what failed\n // before it, since the designer's own check only runs once the catalog\n // has loaded.\n return message.includes('WORKFLOW_WEBHOOK_')\n ? `${WEBHOOK_LINT_PREFIXES[language]}${message}`\n : readFormSchemaLintMessage(message, language);\n}\n","import { readReachableWorkflowNodeIds } from '@rytass/bpm-core-shared';\nimport {\n ApproverResolver,\n ExcludeInitiatorWhenEmpty,\n WorkflowDefinition,\n WorkflowNode,\n} from '@rytass/bpm-core-shared/workflow';\nimport {\n canUserTaskHaveMultipleApprovers,\n readExcludeNodeActorsIssues,\n readNodeActorSourceIssues,\n readNodeActorSourceSkipReasons,\n readSingleApproverSourceIssues,\n} from '@rytass/bpm-core-shared/workflow-graph';\n\nexport type NodeActorOption = Readonly<{\n id: string;\n name: string;\n}>;\n\nexport type NodeActorStageChoice = Readonly<{\n /** What the 關卡 picker offers, with any stale stored choice appended. */\n options: readonly NodeActorOption[];\n /**\n * Live problems of the whole selection (coverage, parallel branches, a stage\n * that can be skipped, ...), or the hint that nothing can be picked.\n */\n problems: readonly string[];\n selected: readonly NodeActorOption[];\n}>;\n\nexport const NO_UPSTREAM_USER_TASK_HINT =\n '這個節點前面沒有可以選的簽核關卡,請先在它前面加入簽核節點(沒有進入條件、沒設跳過此關,也沒設逾時自動核准)';\n\n/** The 關卡 picker's hint while the selection has no problem to report. */\nexport const NODE_ACTOR_STAGE_HINT =\n '簽核人取自你選的前面關卡實際簽核的人;可複選,整組要涵蓋每條路徑。複選多個關卡時,取最近實際走到的那一關的簽核人,不是全部關卡的簽核人。';\n\n/**\n * The 關卡 picker's hint for a manager chain's 前面關卡的簽核者 start, while\n * the selection has no problem to report.\n */\nexport const ORG_MANAGER_CHAIN_STAGE_HINT =\n '起點是你選的前面關卡實際簽核的那一位,從他的主管開始往上簽;只能選每次只會有一位簽核人的關卡。可複選,整組要涵蓋每條路徑,取最近實際走到的那一關的簽核者。';\n\n/**\n * The 關卡 picker's hint when every stage upstream of a manager chain may end\n * with several signers, so none can be the start.\n */\nexport const ORG_MANAGER_CHAIN_ONLY_MULTI_APPROVER_STAGES_HINT =\n '前面的簽核關卡都可能有多位簽核人,所以不能當主管鏈的起點;請改用只有一位簽核人的關卡,或改選其他起點。';\n\nconst UNUSABLE_STAGE_SUFFIX = '(無法使用)';\nconst MISSING_STAGE_SUFFIX = '(已不存在)';\n\ntype UserTaskNode = Extract<WorkflowNode, { type: 'userTask' }>;\n\nfunction isUserTaskNode(node: WorkflowNode): node is UserTaskNode {\n return node.type === 'userTask';\n}\n\nfunction readNodeName(node: WorkflowNode): string {\n return node.data.label || node.id;\n}\n\n/**\n * The 關卡 picker of 依前面關卡的簽核者: the user tasks upstream of `nodeId`\n * that always end with a real signer (`readNodeActorSourceSkipReasons` is\n * empty: no entry condition, no 跳過此關, no 逾時自動核准). Whether the whole group\n * covers every path, or straddles a parallel split, is a property of the\n * selection, not of one stage, so it is reported as `problems` and never used\n * to filter the list (SPEC 5.2: the 154 CF_HR_0002 cases rest on two mutually\n * exclusive stages that would each fail the coverage test alone).\n *\n * A stored stage that no longer qualifies stays in the list, marked, so the\n * stored choice stays visible until the author fixes it.\n */\nexport function readNodeActorStageChoice(\n definition: WorkflowDefinition,\n nodeId: string,\n selectedIds: readonly string[],\n): NodeActorStageChoice {\n return readStageChoice(\n definition,\n nodeId,\n selectedIds,\n () => true,\n () => [],\n );\n}\n\n/**\n * The 關卡 picker of a manager chain's 前面關卡的簽核者 start: the same stages\n * as {@link readNodeActorStageChoice} offers, minus the ones that may end with\n * several signers. The chain climbs from one person, so a stage that\n * `canUserTaskHaveMultipleApprovers` is not offered (a 並行全部同意 stage still\n * is for 依前面關卡的簽核者, which takes everyone). A stored stage of that kind\n * stays in the list, marked, and the selection's problems include the\n * single-signer rule the publish lint runs (`readSingleApproverSourceIssues`).\n */\nexport function readOrgManagerChainStageChoice(\n definition: WorkflowDefinition,\n nodeId: string,\n selectedIds: readonly string[],\n): NodeActorStageChoice {\n const choice = readStageChoice(\n definition,\n nodeId,\n selectedIds,\n (node) => !canUserTaskHaveMultipleApprovers(node),\n (ids) => readSingleApproverSourceIssues(definition, ids),\n );\n\n // Empty only because of the single-signer filter: saying \"add an approval\n // node\" would be wrong, there are some, just none that can start a chain.\n const onlyMultiApproverStages =\n choice.options.length === 0 &&\n selectedIds.length === 0 &&\n readNodeActorStageChoice(definition, nodeId, []).options.length > 0;\n\n return onlyMultiApproverStages\n ? {\n ...choice,\n problems: [ORG_MANAGER_CHAIN_ONLY_MULTI_APPROVER_STAGES_HINT],\n }\n : choice;\n}\n\nfunction readStageChoice(\n definition: WorkflowDefinition,\n nodeId: string,\n selectedIds: readonly string[],\n isOfferable: (node: UserTaskNode) => boolean,\n readExtraIssues: (selectedIds: readonly string[]) => readonly string[],\n): NodeActorStageChoice {\n const offered: readonly NodeActorOption[] = definition.nodes\n .filter(isUserTaskNode)\n .filter(\n (node) =>\n node.id !== nodeId &&\n readNodeActorSourceSkipReasons(node).length === 0 &&\n isOfferable(node) &&\n readReachableWorkflowNodeIds(definition.edges, [node.id]).has(nodeId),\n )\n .map((node) => ({ id: node.id, name: readNodeName(node) }));\n const stale: readonly NodeActorOption[] = selectedIds\n .filter((id) => !offered.some((option) => option.id === id))\n .map((id) => {\n const node = definition.nodes.find((candidate) => candidate.id === id);\n\n return {\n id,\n name: node\n ? `${readNodeName(node)}${UNUSABLE_STAGE_SUFFIX}`\n : `${id}${MISSING_STAGE_SUFFIX}`,\n };\n });\n const options = [...offered, ...stale];\n const selected = selectedIds.flatMap((id): readonly NodeActorOption[] => {\n const option = options.find((candidate) => candidate.id === id);\n\n return option ? [option] : [];\n });\n\n return {\n options,\n problems:\n selectedIds.length > 0\n ? [\n ...readNodeActorSourceIssues(definition, nodeId, selectedIds),\n ...readExtraIssues(selectedIds),\n ]\n : options.length === 0\n ? [NO_UPSTREAM_USER_TASK_HINT]\n : [],\n selected,\n };\n}\n\n/**\n * The graph problems of every 依前面關卡的簽核者 node, naming the node: the\n * checks the backend publish lint runs (`readNodeActorSourceIssues`), for the\n * designer to show before publish. An empty stage list is left to\n * `readApproverResolverIssue`, which owns that message.\n */\nexport function readNodeActorGraphIssues(\n definition: WorkflowDefinition,\n): readonly string[] {\n return definition.nodes.filter(isUserTaskNode).flatMap((node) => {\n const resolver = node.data.approverResolver;\n const nodeIds = readGraphCheckedNodeIds(resolver);\n\n if (nodeIds.length === 0) {\n return [];\n }\n\n return [\n ...readNodeActorSourceIssues(definition, node.id, nodeIds),\n // A manager chain starting from a stage also needs that stage to end\n // with one person; `NODE_ACTOR`/`NODE_ACTOR_MANAGER` take everyone.\n ...(resolver.type === 'ORG_MANAGER_CHAIN'\n ? readSingleApproverSourceIssues(definition, nodeIds)\n : []),\n ].map((issue) => `簽核節點「${readNodeName(node)}」:${issue}`);\n });\n}\n\n// The stages a resolver reads its signers from, when it is one of the three\n// that name earlier stages (a manager chain only with a `NODE_ACTOR` start).\nfunction readGraphCheckedNodeIds(\n resolver: ApproverResolver,\n): readonly string[] {\n if (\n resolver.type === 'NODE_ACTOR' ||\n resolver.type === 'NODE_ACTOR_MANAGER'\n ) {\n return resolver.nodeIds;\n }\n\n if (\n resolver.type === 'ORG_MANAGER_CHAIN' &&\n resolver.startFrom?.type === 'NODE_ACTOR' &&\n Array.isArray(resolver.startFrom.nodeIds)\n ) {\n return resolver.startFrom.nodeIds;\n }\n\n return [];\n}\n\n/** The hint under the 不可與前面關卡同一人 picker while it has no problem to report. */\nexport const EXCLUDE_NODE_ACTORS_STAGE_HINT =\n '此關的簽核人不會是你選的前面關卡實際簽核的人(含其代理人),也不能被轉簽或加簽到此關;可複選,每個關卡都會排除。只能選每條路徑都會經過、而且一定有人實際簽核的關卡(沒有進入條件、沒設跳過此關、沒設逾時自動核准);條件式的關卡、平行分支上的關卡都不支援,條件式的請改用分流把兩關放在同一條路線上,平行分支上的請改成先後串接。';\n\n/** Shown when no earlier stage can be picked. */\nexport const NO_EXCLUDABLE_STAGE_HINT =\n '這個節點前面沒有可以選的簽核關卡,請先在它前面加入簽核節點(每條路徑都會經過、沒有進入條件、沒設跳過此關,也沒設逾時自動核准)';\n\n/**\n * The 不可與前面關卡同一人 picker: the user tasks that pass the publish\n * check on their own (`readExcludeNodeActorsIssues` with just that stage\n * listed: upstream of `nodeId`, on every path to it, not skippable, a real\n * signer every time). Each listed stage has to pass alone, so unlike the\n * `NODE_ACTOR` picker nothing is left to the selection as a whole. A stored\n * stage that does not qualify (gone, no longer upstream, or skippable) stays in\n * the list, marked, and the selection's `problems` say why, so the stored\n * choice is never dropped silently.\n */\nexport function readExcludeNodeActorStageChoice(\n definition: WorkflowDefinition,\n nodeId: string,\n selectedIds: readonly string[],\n whenEmpty: ExcludeInitiatorWhenEmpty,\n): NodeActorStageChoice {\n const offered: readonly NodeActorOption[] = definition.nodes\n .filter(isUserTaskNode)\n .filter(\n (node) =>\n node.id !== nodeId &&\n readExcludeNodeActorsIssues(definition, nodeId, {\n nodeIds: [node.id],\n whenEmpty: 'FAIL',\n }).length === 0,\n )\n .map((node) => ({ id: node.id, name: readNodeName(node) }));\n const stale: readonly NodeActorOption[] = selectedIds\n .filter((id) => !offered.some((option) => option.id === id))\n .map((id) => {\n const node = definition.nodes.find((candidate) => candidate.id === id);\n\n return {\n id,\n name: node\n ? `${readNodeName(node)}${UNUSABLE_STAGE_SUFFIX}`\n : `${id}${MISSING_STAGE_SUFFIX}`,\n };\n });\n const options = [...offered, ...stale];\n const selected = selectedIds.flatMap((id): readonly NodeActorOption[] => {\n const option = options.find((candidate) => candidate.id === id);\n\n return option ? [option] : [];\n });\n\n return {\n options,\n problems:\n selectedIds.length > 0\n ? readExcludeNodeActorsIssues(definition, nodeId, {\n nodeIds: selectedIds,\n whenEmpty,\n })\n : options.length === 0\n ? [NO_EXCLUDABLE_STAGE_HINT]\n : [],\n selected,\n };\n}\n\n/**\n * The graph problems of every node with 不可與前面關卡同一人, naming the node:\n * the checks the backend publish lint runs (`readExcludeNodeActorsIssues`),\n * for the designer to show before publish. The shape of the setting (no stage\n * chosen, no 排除後沒有簽核人時) is left to `readExcludeNodeActorsShapeIssue`,\n * which blocks saving.\n */\nexport function readExcludeNodeActorsGraphIssues(\n definition: WorkflowDefinition,\n): readonly string[] {\n return definition.nodes.filter(isUserTaskNode).flatMap((node) =>\n readExcludeNodeActorsIssues(\n definition,\n node.id,\n node.data.excludeNodeActors,\n ).map((issue) => `簽核節點「${readNodeName(node)}」:${issue}`),\n );\n}\n","import {\n MembershipRecord,\n OrgUnitRecord,\n PositionRecord,\n} from '@rytass/bpm-core-client/organization';\nimport { DEFAULT_BPM_ORGANIZATION_TIME_ZONE } from '@rytass/bpm-core-shared';\nimport { useBPMOrganizationTimeZone } from '../../../lib/organization-time-zone-provider';\n\n/**\n * Today as `YYYY-MM-DD` in the organization zone, the clock the designer's\n * pickers and dry run share. Mirrors the engine's `formatDateOnlyInTimeZone`;\n * a UTC date is one day behind Taipei between 00:00 and 08:00. `timeZone`\n * must already be resolved (see `useBPMOrganizationTimeZone`).\n */\nexport function readTodayDateOnlyString(\n now: Date = new Date(),\n timeZone: string = DEFAULT_BPM_ORGANIZATION_TIME_ZONE,\n): string {\n const byType = new Map(\n new Intl.DateTimeFormat('en-CA', {\n day: '2-digit',\n month: '2-digit',\n timeZone,\n year: 'numeric',\n })\n .formatToParts(now)\n .map((part): readonly [string, string] => [part.type, part.value]),\n );\n\n return `${byType.get('year')}-${byType.get('month')}-${byType.get('day')}`;\n}\n\n/**\n * Today in the host's organization zone (`organizationTimeZone` on the BPM\n * providers, the value the engine's `BPMRootModule` is given), read on every\n * render, so the designer judges effective dates on the engine's day.\n */\nexport function useOrganizationTodayDateOnlyString(): string {\n return readTodayDateOnlyString(new Date(), useBPMOrganizationTimeZone());\n}\n\nexport function isMembershipActiveOn(\n membership: Pick<MembershipRecord, 'effectiveFrom' | 'effectiveTo'>,\n date: string,\n): boolean {\n return (\n membership.effectiveFrom <= date &&\n (!membership.effectiveTo || membership.effectiveTo >= date)\n );\n}\n\n/**\n * The positions at least one member holds through a membership that is in\n * effect on `date`. The engine resolves a position or an organization position\n * only through such members, so a position outside this set has nobody to\n * notify or assign.\n */\nexport function readActivePositionIds(\n memberships: readonly MembershipRecord[],\n date: string,\n): ReadonlySet<string> {\n return new Set(\n memberships\n .filter((membership) => isMembershipActiveOn(membership, date))\n .map((membership) => membership.positionId)\n .filter((positionId): positionId is string => Boolean(positionId)),\n );\n}\n\n/**\n * The positions an organization-scoped picker offers: those held by a member\n * effective on `date` inside the organization scope. Memberships that have\n * ended or not started yet do not count, the same rule the engine applies.\n */\nexport function readOrgScopedPositions({\n date,\n includeDescendants,\n memberships,\n orgUnitId,\n orgUnits,\n positions,\n}: {\n readonly date: string;\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 = readActivePositionIds(\n memberships.filter((membership) => orgUnitIds.has(membership.orgUnitId)),\n date,\n );\n\n return positions.filter((position) => positionIds.has(position.id));\n}\n\n/**\n * Options for an organization-scoped position picker, and whether the stored\n * position has no effective holder in that scope. A stored position outside\n * the scope stays in the options (and so selected), as the POSITION picker\n * keeps an inactive one, so the author sees what the engine will not resolve.\n */\nexport function readOrgPositionPickerState({\n orgUnitId,\n positionId,\n positions,\n scopedPositions,\n}: {\n readonly orgUnitId: string;\n readonly positionId: string;\n readonly positions: readonly PositionRecord[];\n readonly scopedPositions: readonly PositionRecord[];\n}): {\n readonly isInactive: boolean;\n readonly options: readonly PositionRecord[];\n} {\n const isInactive =\n Boolean(orgUnitId.trim()) &&\n Boolean(positionId) &&\n !scopedPositions.some((position) => position.id === positionId);\n\n return {\n isInactive,\n options: isInactive\n ? [\n ...scopedPositions,\n ...positions.filter((position) => position.id === positionId),\n ]\n : scopedPositions,\n };\n}\n\nexport function 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","import { FormFieldDefinition } from '@rytass/bpm-core-shared/form';\nimport {\n NotifyWebhookBindingSource,\n NotifyWebhookContextPath,\n NotifyWebhookParameterType,\n NotifyWebhookTarget,\n WorkflowDefinition,\n} from '@rytass/bpm-core-shared/workflow';\nimport {\n NotifyWebhookEndpointContract,\n isFormFieldCompatibleWithWebhookParameter,\n readNotifyWebhookCatalogIssueMessage,\n readNotifyWebhookStructureIssues,\n readNotifyWebhookTargetCatalogIssues,\n readNotifyWebhookTargets,\n} from '@rytass/bpm-core-shared/workflow-graph';\n\nexport type NotifyWebhookBindingKind = NotifyWebhookBindingSource['kind'];\n\n/** The catalog fields the designer reads; a subset of the client record. */\nexport interface NotifyWebhookDesignerEndpoint extends NotifyWebhookEndpointContract {\n readonly deprecated: boolean;\n readonly description: string | null;\n /** Switched off by an administrator (database endpoints). */\n readonly disabled?: boolean;\n readonly key: string;\n readonly label: string;\n readonly parameters: readonly {\n readonly description: string | null;\n readonly key: string;\n readonly label: string;\n readonly required: boolean;\n readonly type: NotifyWebhookParameterType;\n }[];\n /** `DATABASE` endpoints are maintained in the back office. */\n readonly source?: 'DATABASE' | 'REGISTRY';\n readonly version: number;\n}\n\ntype DesignerParameter = NotifyWebhookDesignerEndpoint['parameters'][number];\n\nexport const NOTIFY_WEBHOOK_CONTEXT_PATH_LABELS: Readonly<\n Record<NotifyWebhookContextPath, string>\n> = {\n 'initiator.memberId': '發起人會員編號',\n 'instance.id': '案件編號',\n 'instance.templateId': '模板編號',\n 'instance.templateVersionId': '模板版本編號',\n 'instance.title': '案件主旨',\n 'node.id': '節點編號',\n 'node.label': '節點名稱',\n};\n\nexport const NOTIFY_WEBHOOK_PARAMETER_TYPE_LABELS: Readonly<\n Record<NotifyWebhookParameterType, string>\n> = {\n boolean: '是/否',\n json: 'JSON',\n number: '數字',\n string: '文字',\n stringArray: '文字清單',\n};\n\nexport function readNotifyWebhookEndpointOptionId(endpoint: {\n readonly key: string;\n readonly version: number;\n}): string {\n return `${endpoint.key}@${endpoint.version}`;\n}\n\nexport function findNotifyWebhookEndpoint(\n endpoints: readonly NotifyWebhookDesignerEndpoint[],\n reference: { readonly key: string; readonly version: number },\n): NotifyWebhookDesignerEndpoint | null {\n return (\n endpoints.find(\n (endpoint) =>\n endpoint.key === reference.key &&\n endpoint.version === reference.version,\n ) ?? null\n );\n}\n\n/**\n * The sources a parameter can take. A `CONTEXT` path is always a string, and\n * a `CONSTANT` cannot hold a list, so those are only offered where they fit.\n */\nexport function readNotifyWebhookBindingKinds(\n type: NotifyWebhookParameterType,\n): readonly NotifyWebhookBindingKind[] {\n return [\n 'FIELD',\n ...(type === 'stringArray' ? [] : (['CONSTANT'] as const)),\n ...(type === 'string' || type === 'json' ? (['CONTEXT'] as const) : []),\n ];\n}\n\nexport function readCompatibleFormFields(\n formFields: readonly FormFieldDefinition[],\n type: NotifyWebhookParameterType,\n): readonly FormFieldDefinition[] {\n return formFields.filter((field) =>\n isFormFieldCompatibleWithWebhookParameter(field, type),\n );\n}\n\n/** The value a binding starts with when its source kind is picked. */\nexport function createNotifyWebhookBindingSource(\n kind: NotifyWebhookBindingKind,\n parameter: DesignerParameter,\n formFields: readonly FormFieldDefinition[],\n): NotifyWebhookBindingSource {\n if (kind === 'FIELD') {\n return {\n fieldKey:\n readCompatibleFormFields(formFields, parameter.type)[0]?.fieldKey ?? '',\n kind: 'FIELD',\n };\n }\n\n if (kind === 'CONTEXT') {\n return { kind: 'CONTEXT', path: 'instance.title' };\n }\n\n // Starts from a field that fits, the way `FIELD` does, so the draft is\n // never left with a blank expression the structural check refuses.\n if (kind === 'EXPRESSION') {\n const field =\n readCompatibleFormFields(formFields, parameter.type)[0] ?? formFields[0];\n\n return { expression: field ? `form.${field.fieldKey}` : '', kind };\n }\n\n // A number starts empty rather than at 0, so typing does not append to a\n // value nobody chose; a required one is flagged until it is filled in.\n return {\n kind: 'CONSTANT',\n value:\n parameter.type === 'boolean'\n ? true\n : parameter.type === 'number'\n ? null\n : '',\n };\n}\n\n/**\n * Whether a parameter can be bound to a cel-v2 expression over `form`\n * (ADR 22 §3.7). An expression yields a scalar, so never a `stringArray`, and\n * it reads the bound form, so not before one is bound. Kept apart from\n * {@link readNotifyWebhookBindingKinds}, which lists the sources that need no\n * backend check.\n */\nexport function canBindNotifyWebhookExpression(\n type: NotifyWebhookParameterType,\n formFields: readonly FormFieldDefinition[] | null,\n): boolean {\n return type !== 'stringArray' && Boolean(formFields?.length);\n}\n\nconst DECIMAL_PATTERN = /^-?\\d+(\\.\\d+)?$/;\n\n/**\n * Reads a typed constant from a text input. A number parameter takes plain\n * decimals only (no `0x1f`, no exponent); anything else, including a number\n * still being typed such as `1.`, stays text so the publish check can point\n * at it instead of the input silently changing what was typed.\n */\nexport function readNotifyWebhookConstantValue(\n type: NotifyWebhookParameterType,\n raw: string,\n): boolean | number | string | null {\n if (type !== 'number') {\n return raw;\n }\n\n const trimmed = raw.trim();\n\n if (!trimmed) {\n return null;\n }\n\n return DECIMAL_PATTERN.test(trimmed) ? Number(trimmed) : raw;\n}\n\n/**\n * Whether the editor can render a node's `webhooks` at all. Parsed JSON is\n * saved as a draft without the structural lint, so a hand-edited list may\n * hold values the editor would throw on.\n */\nexport function isNotifyWebhookListEditable(webhooks: unknown): boolean {\n return !readNotifyWebhookStructureIssues(webhooks).some((issue) =>\n UNRENDERABLE_STRUCTURE_CODES.has(issue.code),\n );\n}\n\nconst UNRENDERABLE_STRUCTURE_CODES: ReadonlySet<string> = new Set([\n 'BINDING_INVALID',\n 'BINDING_SOURCE_INVALID',\n 'BINDINGS_NOT_ARRAY',\n 'ENDPOINT_KEY_REQUIRED',\n 'ENDPOINT_VERSION_INVALID',\n 'TARGET_ID_REQUIRED',\n 'TARGET_INVALID',\n 'WEBHOOKS_NOT_ARRAY',\n]);\n\n/** Sets, or with `null` removes, the binding for one parameter. */\nexport function setNotifyWebhookBinding(\n target: NotifyWebhookTarget,\n parameter: string,\n from: NotifyWebhookBindingSource | null,\n): NotifyWebhookTarget {\n const others = target.bindings.filter(\n (binding) => binding.parameter !== parameter,\n );\n const index = target.bindings.findIndex(\n (binding) => binding.parameter === parameter,\n );\n\n if (!from) {\n return { ...target, bindings: others };\n }\n\n const binding = { from, parameter };\n\n return {\n ...target,\n bindings:\n index === -1\n ? [...target.bindings, binding]\n : target.bindings.map((current, currentIndex) =>\n currentIndex === index ? binding : current,\n ),\n };\n}\n\n/**\n * Points a target at another endpoint, keeping the id (deliveries are keyed\n * by it) and every binding whose parameter the new endpoint still declares\n * with a type the bound value fits.\n */\nexport function switchNotifyWebhookEndpoint(\n target: NotifyWebhookTarget,\n endpoint: NotifyWebhookDesignerEndpoint,\n formFields: readonly FormFieldDefinition[],\n): NotifyWebhookTarget {\n const bindings = target.bindings.filter((binding) => {\n const parameter = endpoint.parameters.find(\n (candidate) => candidate.key === binding.parameter,\n );\n\n return (\n parameter !== undefined &&\n !readNotifyWebhookTargetCatalogIssues({\n endpoint: {\n parameters: [{ ...parameter, required: false }],\n },\n formFields,\n target: { ...target, bindings: [binding] },\n }).length\n );\n });\n\n return {\n bindings,\n endpoint: { key: endpoint.key, version: endpoint.version },\n id: target.id,\n };\n}\n\n/**\n * The publish check the backend runs against the catalog, worded for the\n * designer. Only structurally valid targets are checked; shape problems are\n * already reported by the shared structural lint.\n */\nexport function readNotifyWebhookDesignerIssues({\n definition,\n endpoints,\n formFields,\n}: {\n readonly definition: WorkflowDefinition;\n readonly endpoints: readonly NotifyWebhookDesignerEndpoint[];\n readonly formFields: readonly FormFieldDefinition[];\n}): readonly string[] {\n return definition.nodes.flatMap((node) => {\n if (node.type !== 'serviceTask' || node.data.action.type !== 'NOTIFY') {\n return [];\n }\n\n const structureIssues = readNotifyWebhookStructureIssues(\n node.data.action.webhooks,\n );\n\n if (structureIssues.length) {\n return [];\n }\n\n return readNotifyWebhookTargets(node.data.action).flatMap(\n (target, targetIndex) => {\n const endpoint = findNotifyWebhookEndpoint(endpoints, target.endpoint);\n\n return readNotifyWebhookTargetCatalogIssues({\n endpoint,\n formFields,\n target,\n }).map((issue) =>\n readNotifyWebhookCatalogIssueMessage({\n endpointLabel:\n endpoint?.label ??\n readNotifyWebhookEndpointOptionId(target.endpoint),\n issue,\n nodeLabel: node.data.label,\n targetIndex,\n }),\n );\n },\n );\n });\n}\n","'use client';\n\nimport {\n ChangeEvent,\n CSSProperties,\n ReactElement,\n useEffect,\n useState,\n} from 'react';\nimport {\n Button,\n InlineMessage,\n Input,\n Select,\n Textarea,\n Typography,\n} from '@mezzanine-ui/react';\nimport { PlusIcon, TrashIcon } from '@mezzanine-ui/icons';\nimport { FormFieldDefinition } from '@rytass/bpm-core-shared/form';\nimport {\n NotifyWebhookBindingSource,\n NotifyWebhookTarget,\n} from '@rytass/bpm-core-shared/workflow';\nimport {\n NOTIFY_WEBHOOK_CONTEXT_PATHS,\n NOTIFY_WEBHOOK_TARGET_LIMIT,\n createNotifyWebhookTarget,\n isNotifyWebhookContextPath,\n} from '@rytass/bpm-core-shared/workflow-graph';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport {\n NOTIFY_WEBHOOK_CONTEXT_PATH_LABELS,\n NOTIFY_WEBHOOK_PARAMETER_TYPE_LABELS,\n NotifyWebhookBindingKind,\n NotifyWebhookDesignerEndpoint,\n canBindNotifyWebhookExpression,\n createNotifyWebhookBindingSource,\n findNotifyWebhookEndpoint,\n readCompatibleFormFields,\n readNotifyWebhookBindingKinds,\n readNotifyWebhookConstantValue,\n readNotifyWebhookEndpointOptionId,\n setNotifyWebhookBinding,\n switchNotifyWebhookEndpoint,\n} from './notify-webhook-designer';\n\nexport type NotifyWebhookCatalogState = 'loading' | 'ready' | 'unavailable';\n\ntype SelectOption = Readonly<{ id: string; name: string }>;\n\nconst EDITOR_STYLE: CSSProperties = {\n display: 'grid',\n gap: 'var(--mzn-spacing-gap-base)',\n};\n\nconst TARGET_STYLE: CSSProperties = {\n borderColor: 'var(--mzn-color-border-neutral)',\n borderRadius: 'var(--mzn-radius-base)',\n borderStyle: 'solid',\n borderWidth: 1,\n display: 'grid',\n gap: 'var(--mzn-spacing-gap-base)',\n padding: 'var(--mzn-spacing-padding-horizontal-base)',\n};\n\nconst TARGET_HEADER_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'flex',\n gap: 'var(--mzn-spacing-gap-base)',\n justifyContent: 'space-between',\n};\n\nconst BINDING_ROW_STYLE: CSSProperties = {\n display: 'grid',\n gap: 'var(--mzn-spacing-gap-base)',\n gridTemplateColumns: 'minmax(0, 2fr) minmax(0, 3fr)',\n};\n\nconst NONE_OPTION: SelectOption = { id: 'NONE', name: '不傳送' };\n\nconst BINDING_KIND_OPTIONS: Readonly<\n Record<NotifyWebhookBindingKind, SelectOption>\n> = {\n CONSTANT: { id: 'CONSTANT', name: '固定值' },\n CONTEXT: { id: 'CONTEXT', name: '案件資訊' },\n EXPRESSION: { id: 'EXPRESSION', name: '運算式' },\n FIELD: { id: 'FIELD', name: '表單欄位' },\n};\n\nconst BOOLEAN_OPTIONS: readonly SelectOption[] = [\n { id: 'true', name: '是' },\n { id: 'false', name: '否' },\n];\n\nconst CONTEXT_PATH_OPTIONS: readonly SelectOption[] =\n NOTIFY_WEBHOOK_CONTEXT_PATHS.map((path) => ({\n id: path,\n name: NOTIFY_WEBHOOK_CONTEXT_PATH_LABELS[path],\n }));\n\nexport interface NotifyWebhookTargetsEditorProps {\n /** Every endpoint the catalog lists, deprecated ones included. */\n readonly catalog: readonly NotifyWebhookDesignerEndpoint[];\n readonly catalogState: NotifyWebhookCatalogState;\n /** `null` when no form is bound yet, so fields cannot be picked. */\n readonly formFields: readonly FormFieldDefinition[] | null;\n readonly onChange: (targets: readonly NotifyWebhookTarget[]) => void;\n readonly targets: readonly NotifyWebhookTarget[];\n}\n\n/** Shown in place of the editor when the catalog has no usable endpoint. */\nexport const NOTIFY_WEBHOOK_NO_ENDPOINTS_MESSAGE =\n '目前沒有可用的 Webhook 端點,請洽 BPM 管理者或系統整合人員新增端點後再設定。';\n\n/**\n * Edits a NOTIFY node's webhook targets (ADR 18 §3.3). Parameters come from\n * the endpoint catalog, so the author only picks an endpoint and binds each\n * parameter; a URL, header or secret is never shown or entered here.\n */\nexport function NotifyWebhookTargetsEditor({\n catalog,\n catalogState,\n formFields,\n onChange,\n targets,\n}: NotifyWebhookTargetsEditorProps): ReactElement | null {\n const activeEndpoints = catalog.filter((endpoint) => !endpoint.deprecated);\n\n // A catalog that could not be loaded (a host without the webhook module,\n // or a member the query refuses) hides the section. A draft that already\n // has targets keeps it either way, so they can still be read and removed.\n if (!targets.length && catalogState === 'unavailable') {\n return null;\n }\n\n // Loaded but empty: say so, rather than hiding the feature from an author\n // who is looking for it. Endpoints come from the host's code or its back\n // office, neither of which this lib can name, so the hint stays generic.\n if (!targets.length && catalogState === 'ready' && !activeEndpoints.length) {\n return (\n <div style={EDITOR_STYLE}>\n <Typography variant=\"label-primary-highlight\">Webhook</Typography>\n <InlineMessage\n content={NOTIFY_WEBHOOK_NO_ENDPOINTS_MESSAGE}\n severity=\"info\"\n />\n </div>\n );\n }\n\n function replaceTarget(index: number, next: NotifyWebhookTarget): void {\n onChange(\n targets.map((target, targetIndex) =>\n targetIndex === index ? next : target,\n ),\n );\n }\n\n function addTarget(): void {\n const [endpoint] = activeEndpoints;\n\n if (endpoint) {\n onChange([\n ...targets,\n createNotifyWebhookTarget({\n key: endpoint.key,\n version: endpoint.version,\n }),\n ]);\n }\n }\n\n return (\n <div style={EDITOR_STYLE}>\n <Typography variant=\"label-primary-highlight\">Webhook</Typography>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 知會節點抵達時,將指定的表單欄位或案件資訊送到外部系統。\n </Typography>\n {catalogState === 'loading' ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 正在載入可用的 Webhook 端點…\n </Typography>\n ) : null}\n {catalogState === 'unavailable' ? (\n <Typography color=\"text-error\" variant=\"body\">\n 目前無法載入 Webhook 端點,已設定的內容會保留,請稍後重試。\n </Typography>\n ) : null}\n {targets.map((target, index): ReactElement => (\n <NotifyWebhookTargetEditor\n activeEndpoints={activeEndpoints}\n catalog={catalog}\n catalogState={catalogState}\n formFields={formFields}\n index={index}\n key={target.id}\n onChange={(next): void => replaceTarget(index, next)}\n onRemove={(): void =>\n onChange(\n targets.filter((_target, targetIndex) => targetIndex !== index),\n )\n }\n target={target}\n />\n ))}\n <div>\n <Button\n disabled={\n catalogState !== 'ready' ||\n !activeEndpoints.length ||\n targets.length >= NOTIFY_WEBHOOK_TARGET_LIMIT\n }\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={addTarget}\n variant=\"base-dashed\"\n >\n 新增 Webhook\n </Button>\n </div>\n {targets.length >= NOTIFY_WEBHOOK_TARGET_LIMIT ? (\n <Typography color=\"text-neutral\" variant=\"caption\">\n 每個知會節點最多 {NOTIFY_WEBHOOK_TARGET_LIMIT} 個 Webhook。\n </Typography>\n ) : null}\n </div>\n );\n}\n\nfunction NotifyWebhookTargetEditor({\n activeEndpoints,\n catalog,\n catalogState,\n formFields,\n index,\n onChange,\n onRemove,\n target,\n}: {\n readonly activeEndpoints: readonly NotifyWebhookDesignerEndpoint[];\n readonly catalog: readonly NotifyWebhookDesignerEndpoint[];\n readonly catalogState: NotifyWebhookCatalogState;\n readonly formFields: readonly FormFieldDefinition[] | null;\n readonly index: number;\n readonly onChange: (target: NotifyWebhookTarget) => void;\n readonly onRemove: () => void;\n readonly target: NotifyWebhookTarget;\n}): ReactElement {\n const endpoint = findNotifyWebhookEndpoint(catalog, target.endpoint);\n const currentOptionId = readNotifyWebhookEndpointOptionId(target.endpoint);\n const endpointOptions: readonly SelectOption[] = [\n ...activeEndpoints.map((candidate) => ({\n id: readNotifyWebhookEndpointOptionId(candidate),\n name: readEndpointOptionName(candidate),\n })),\n // Kept selectable-as-shown so a deprecated, disabled or removed endpoint\n // is named rather than the Select silently looking empty.\n ...(endpoint && !endpoint.deprecated\n ? []\n : [\n {\n id: currentOptionId,\n name: endpoint\n ? readEndpointOptionName(endpoint)\n : `${currentOptionId}(找不到端點)`,\n },\n ]),\n ];\n const declaredKeys = new Set(\n (endpoint?.parameters ?? []).map((parameter) => parameter.key),\n );\n const undeclaredBindings = endpoint\n ? target.bindings.filter((binding) => !declaredKeys.has(binding.parameter))\n : [];\n\n return (\n <div style={TARGET_STYLE}>\n <div style={TARGET_HEADER_STYLE}>\n <Typography variant=\"label-primary\">\n 第 {index + 1} 個 Webhook\n </Typography>\n <Button\n icon={TrashIcon}\n iconType=\"leading\"\n onClick={onRemove}\n variant=\"destructive-text-link\"\n >\n 移除\n </Button>\n </div>\n <BPMFormField label=\"端點\" name={`webhookEndpoint-${target.id}`} required>\n <Select\n clearable={false}\n disabled={catalogState !== 'ready'}\n onChange={(option): void => {\n const next = activeEndpoints.find(\n (candidate) =>\n readNotifyWebhookEndpointOptionId(candidate) === option?.id,\n );\n\n if (next) {\n onChange(\n switchNotifyWebhookEndpoint(target, next, formFields ?? []),\n );\n }\n }}\n options={[...endpointOptions]}\n placeholder=\"選擇端點\"\n value={\n endpointOptions.find((option) => option.id === currentOptionId) ??\n null\n }\n />\n </BPMFormField>\n {catalogState === 'ready' && !endpoint ? (\n <Typography color=\"text-warning\" variant=\"body\">\n 找不到這個端點,設定會保留;請改選其他端點或移除,否則無法發布。\n </Typography>\n ) : null}\n {endpoint?.disabled ? (\n <Typography color=\"text-warning\" variant=\"body\">\n 這個端點已被管理者停用,不會再送出;設定會保留,請改選其他端點,否則無法發布。\n </Typography>\n ) : endpoint?.deprecated ? (\n <Typography color=\"text-warning\" variant=\"body\">\n 這個端點不建議再使用,設定會保留;請改選其他端點,否則無法發布。\n </Typography>\n ) : null}\n {endpoint?.description ? (\n <Typography color=\"text-neutral\" variant=\"caption\">\n {endpoint.description}\n </Typography>\n ) : null}\n {endpoint && !endpoint.parameters.length ? (\n <Typography color=\"text-neutral\" variant=\"caption\">\n 這個端點不需要參數。\n </Typography>\n ) : null}\n {(endpoint?.parameters ?? []).map((parameter): ReactElement => (\n <NotifyWebhookBindingEditor\n formFields={formFields}\n key={parameter.key}\n onChange={(from): void =>\n onChange(setNotifyWebhookBinding(target, parameter.key, from))\n }\n parameter={parameter}\n source={\n target.bindings.find(\n (binding) => binding.parameter === parameter.key,\n )?.from ?? null\n }\n targetId={target.id}\n />\n ))}\n {undeclaredBindings.map((binding): ReactElement => (\n <div key={binding.parameter} style={TARGET_HEADER_STYLE}>\n <Typography color=\"text-warning\" variant=\"body\">\n 參數「{binding.parameter}」已不在端點定義中。\n </Typography>\n <Button\n onClick={(): void =>\n onChange(setNotifyWebhookBinding(target, binding.parameter, null))\n }\n variant=\"base-text-link\"\n >\n 移除設定\n </Button>\n </div>\n ))}\n </div>\n );\n}\n\nfunction NotifyWebhookBindingEditor({\n formFields,\n onChange,\n parameter,\n source,\n targetId,\n}: {\n readonly formFields: readonly FormFieldDefinition[] | null;\n readonly onChange: (from: NotifyWebhookBindingSource | null) => void;\n readonly parameter: NotifyWebhookDesignerEndpoint['parameters'][number];\n readonly source: NotifyWebhookBindingSource | null;\n readonly targetId: string;\n}): ReactElement {\n // Picking a form field with none to pick would store an empty key, which\n // the structural check refuses even for a draft; so the source is only\n // offered when there is a field that fits (or it is already the source).\n const canBindField =\n source?.kind === 'FIELD' ||\n readCompatibleFormFields(formFields ?? [], parameter.type).length > 0;\n const kindOptions: readonly SelectOption[] = [\n ...(parameter.required ? [] : [NONE_OPTION]),\n ...readNotifyWebhookBindingKinds(parameter.type)\n .filter((kind) => kind !== 'FIELD' || canBindField)\n .map((kind) => BINDING_KIND_OPTIONS[kind]),\n // A stored expression stays selectable even where a new one would not be\n // offered, so the Select never looks unset over it.\n ...(source?.kind === 'EXPRESSION' ||\n canBindNotifyWebhookExpression(parameter.type, formFields)\n ? [BINDING_KIND_OPTIONS.EXPRESSION]\n : []),\n ];\n const typeLabel = NOTIFY_WEBHOOK_PARAMETER_TYPE_LABELS[parameter.type];\n\n return (\n <BPMFormField\n hintText={[parameter.key, typeLabel, parameter.description]\n .filter(Boolean)\n .join(' · ')}\n label={parameter.label}\n name={`webhookBinding-${targetId}-${parameter.key}`}\n required={parameter.required}\n >\n <div style={BINDING_ROW_STYLE}>\n <Select\n clearable={false}\n onChange={(option): void => {\n const kind = readBindingKind(option?.id ?? null);\n\n onChange(\n kind\n ? createNotifyWebhookBindingSource(\n kind,\n parameter,\n formFields ?? [],\n )\n : null,\n );\n }}\n options={[...kindOptions]}\n placeholder=\"選擇來源\"\n value={\n source\n ? BINDING_KIND_OPTIONS[source.kind]\n : parameter.required\n ? null\n : NONE_OPTION\n }\n />\n {source ? (\n <NotifyWebhookBindingValue\n formFields={formFields}\n onChange={onChange}\n parameter={parameter}\n source={source}\n />\n ) : null}\n </div>\n </BPMFormField>\n );\n}\n\nfunction NotifyWebhookBindingValue({\n formFields,\n onChange,\n parameter,\n source,\n}: {\n readonly formFields: readonly FormFieldDefinition[] | null;\n readonly onChange: (from: NotifyWebhookBindingSource) => void;\n readonly parameter: NotifyWebhookDesignerEndpoint['parameters'][number];\n readonly source: NotifyWebhookBindingSource;\n}): ReactElement {\n if (source.kind === 'FIELD') {\n if (!formFields) {\n return (\n <Typography color=\"text-neutral\" variant=\"caption\">\n 請先綁定表單版本,才能選擇表單欄位。\n </Typography>\n );\n }\n\n const compatibleOptions: readonly SelectOption[] = readCompatibleFormFields(\n formFields,\n parameter.type,\n ).map((field) => ({\n id: field.fieldKey,\n name: `${field.label}(${field.fieldKey})`,\n }));\n // A key the form no longer offers (removed, or retyped) stays visible\n // instead of the Select looking unset.\n const fieldOptions: readonly SelectOption[] =\n source.fieldKey &&\n !compatibleOptions.some((option) => option.id === source.fieldKey)\n ? [\n ...compatibleOptions,\n {\n id: source.fieldKey,\n name: `${source.fieldKey}(找不到相容欄位)`,\n },\n ]\n : compatibleOptions;\n\n return (\n <Select\n clearable={false}\n onChange={(option): void =>\n onChange({ fieldKey: option?.id ?? '', kind: 'FIELD' })\n }\n options={[...fieldOptions]}\n placeholder={\n fieldOptions.length ? '選擇表單欄位' : '沒有型別相容的欄位'\n }\n value={\n fieldOptions.find((option) => option.id === source.fieldKey) ?? null\n }\n />\n );\n }\n\n if (source.kind === 'CONTEXT') {\n return (\n <Select\n clearable={false}\n onChange={(option): void => {\n if (isNotifyWebhookContextPath(option?.id)) {\n onChange({ kind: 'CONTEXT', path: option.id });\n }\n }}\n options={[...CONTEXT_PATH_OPTIONS]}\n value={\n CONTEXT_PATH_OPTIONS.find((option) => option.id === source.path) ??\n null\n }\n />\n );\n }\n\n if (source.kind === 'EXPRESSION') {\n // Text only: the backend parses and lints it at publish (cel-v2, `form`\n // only, built-in functions only); the browser never parses CEL.\n return (\n <Textarea\n aria-label={`${parameter.label}運算式`}\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void =>\n onChange({ expression: event.target.value, kind: 'EXPRESSION' })\n }\n placeholder=\"例如 form.amount * 2(只能讀 form,只能用內建函式)\"\n resize=\"vertical\"\n rows={2}\n value={source.expression}\n />\n );\n }\n\n if (parameter.type === 'boolean') {\n return (\n <Select\n clearable={false}\n onChange={(option): void =>\n onChange({ kind: 'CONSTANT', value: option?.id === 'true' })\n }\n options={[...BOOLEAN_OPTIONS]}\n value={\n typeof source.value === 'boolean'\n ? (BOOLEAN_OPTIONS.find(\n (option) => option.id === String(source.value),\n ) ?? null)\n : null\n }\n />\n );\n }\n\n return (\n <NotifyWebhookConstantInput\n onChange={(value): void => onChange({ kind: 'CONSTANT', value })}\n type={parameter.type}\n value={source.value}\n />\n );\n}\n\n/**\n * Keeps what was typed, not what it parses to: Mezzanine's `Input` is\n * controlled, so writing `1.` back as `1` would eat the decimal point while\n * the author is still typing `1.5`.\n */\nfunction NotifyWebhookConstantInput({\n onChange,\n type,\n value,\n}: {\n readonly onChange: (value: boolean | number | string | null) => void;\n readonly type: NotifyWebhookDesignerEndpoint['parameters'][number]['type'];\n readonly value: boolean | number | string | null;\n}): ReactElement {\n const [text, setText] = useState(value === null ? '' : String(value));\n\n // Follow a value changed from outside (another endpoint, the assistant),\n // but never overwrite text that already parses to the current value.\n useEffect((): void => {\n setText((current) =>\n readNotifyWebhookConstantValue(type, current) === value\n ? current\n : value === null\n ? ''\n : String(value),\n );\n }, [type, value]);\n\n return (\n <Input\n inputProps={{ inputMode: type === 'number' ? 'decimal' : undefined }}\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setText(event.target.value);\n onChange(readNotifyWebhookConstantValue(type, event.target.value));\n }}\n placeholder={type === 'number' ? '輸入數字' : '輸入固定值'}\n value={text}\n variant=\"base\"\n />\n );\n}\n\nfunction readEndpointOptionName(\n endpoint: NotifyWebhookDesignerEndpoint,\n): string {\n const notes = [\n `v${endpoint.version}`,\n ...(endpoint.source === 'DATABASE' ? ['後台維護'] : []),\n ...(endpoint.disabled\n ? ['已停用']\n : endpoint.deprecated\n ? ['不建議使用']\n : []),\n ];\n\n return `${endpoint.label}(${notes.join(',')})`;\n}\n\nfunction readBindingKind(id: string | null): NotifyWebhookBindingKind | null {\n return id === 'FIELD' ||\n id === 'CONSTANT' ||\n id === 'CONTEXT' ||\n id === 'EXPRESSION'\n ? id\n : null;\n}\n","import {\n FormDefinitionSchema,\n FormFieldDefinition,\n isFormOptionFieldDefinition,\n isFormStaticOptionFieldDefinition,\n readFormFieldSelectionMode,\n} from '@rytass/bpm-core-shared/form';\n\nexport function readDryRunSampleFormData(\n schema: FormDefinitionSchema | null,\n): Readonly<Record<string, unknown>> {\n return (schema?.fields ?? []).reduce<Readonly<Record<string, unknown>>>(\n (formData, field) => ({\n ...formData,\n [field.fieldKey]: readDryRunSampleFieldValue(field),\n }),\n {},\n );\n}\n\n/**\n * Sample value of a member field: a placeholder the dry-run result labels as\n * \"whoever this field names\", never the dry-run initiator — a real submitter\n * picks someone else, and sampling the initiator would make a node that\n * excludes the initiator look skipped or stopped when it would not be.\n */\nexport function readDryRunFormMemberPlaceholder(fieldKey: string): string {\n return `formMember:${fieldKey}`;\n}\n\n/**\n * Sample value of an org_unit field: a placeholder, since the dry run has no\n * way to know which organization a submitter would pick. The engine reports\n * 依表單欄位的組織主管 by field key, not by this value.\n */\nexport function readDryRunFormOrgUnitPlaceholder(fieldKey: string): string {\n return `formOrgUnit:${fieldKey}`;\n}\n\nfunction readDryRunSampleFieldValue(field: FormFieldDefinition): unknown {\n // `money` is numeric too: edge conditions compare it with a number literal\n // (`readConditionExpressionValue`), so a text sample fails CEL with\n // \"lessOrEqualThan operation cannot be applied to (string, uint)\".\n if (field.type === 'number' || field.type === 'money') {\n return 1000;\n }\n\n if (field.type === 'boolean') {\n return true;\n }\n\n // A non-empty member placeholder, so a 依表單欄位指定 node resolves to\n // someone instead of failing on a free-text sample.\n if (field.type === 'member') {\n const placeholder = readDryRunFormMemberPlaceholder(field.fieldKey);\n\n return field.multiple ? [placeholder] : placeholder;\n }\n\n if (field.type === 'org_unit') {\n return readDryRunFormOrgUnitPlaceholder(field.fieldKey);\n }\n\n // The sample must have the shape a real submission stores: an array for any\n // multiple-selection field (checkbox, or select/autocomplete with\n // `mode: 'multiple'`, static or data-source options alike), a single value\n // otherwise. A string where an array belongs lets `form.x == \"a\"` pass the\n // dry run while the real case, holding `[\"a\"]`, never matches.\n if (isFormOptionFieldDefinition(field)) {\n const firstOption = isFormStaticOptionFieldDefinition(field)\n ? field.options[0]?.value\n : undefined;\n\n if (readFormFieldSelectionMode(field) === 'multiple') {\n return firstOption === undefined ? [] : [firstOption];\n }\n\n if (isFormStaticOptionFieldDefinition(field)) {\n return firstOption ?? '';\n }\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","import {\n ApproverResolver,\n ServiceAction,\n isNotifyRecipientResolverType,\n} from '@rytass/bpm-core-shared/workflow';\nimport { PositionRecord } from '@rytass/bpm-core-client/organization';\nimport {\n APPROVER_RESOLVER_MODE_OPTIONS,\n ApproverResolverModeOption,\n buildApproverResolver,\n readApproverResolverEditorState,\n readDefaultApproverResolver,\n} from './approver-resolver-model';\n\n/**\n * The 知會對象 sources the designer can edit. The engine accepts more for a\n * notify node (`isNotifyRecipientResolverType`): 發起人主管, 主管鏈 and 運算式\n * stay readable and are kept as saved, but the designer does not edit them.\n *\n * Keyed by the JSON `type`, not by the approver panel's screen option: that\n * option folds FORM_MEMBER_MANAGER into 依表單欄位指定 and\n * FORM_ORG_UNIT_MANAGER into 指定組織主管, neither of which a notify node\n * may use.\n */\nexport type NotifyRecipientMode = Extract<\n ApproverResolver['type'],\n | 'DIRECT'\n | 'DYNAMIC_FORM'\n | 'ORG_UNIT_MANAGER'\n | 'ORG_UNIT_MEMBER'\n | 'ORG_UNIT_POSITION'\n | 'POSITION'\n>;\n\nconst NOTIFY_RECIPIENT_EDITABLE_TYPES: Readonly<\n Record<NotifyRecipientMode, true>\n> = {\n DIRECT: true,\n DYNAMIC_FORM: true,\n ORG_UNIT_MANAGER: true,\n ORG_UNIT_MEMBER: true,\n ORG_UNIT_POSITION: true,\n POSITION: true,\n};\n\nexport function isNotifyRecipientEditableType(\n type: string,\n): type is NotifyRecipientMode {\n return Object.prototype.hasOwnProperty.call(\n NOTIFY_RECIPIENT_EDITABLE_TYPES,\n type,\n );\n}\n\n/**\n * The editable sources, worded exactly as the 簽核來源 select words them so\n * the two panels never name one source two ways.\n */\nexport const NOTIFY_RECIPIENT_MODE_OPTIONS: readonly ApproverResolverModeOption[] =\n APPROVER_RESOLVER_MODE_OPTIONS.filter((option) =>\n isNotifyRecipientEditableType(option.id),\n );\n\n/** The id of the read-only entry a source the designer does not edit is shown as. */\nexport const READ_ONLY_NOTIFY_RECIPIENT_OPTION_ID = 'READ_ONLY';\n\nfunction readReadOnlyNotifyRecipientName(type: string): string {\n switch (type) {\n case 'ORG_MANAGER':\n return '發起人主管';\n case 'ORG_MANAGER_CHAIN':\n return '主管鏈(簽到指定職等)';\n case 'EXPRESSION':\n return '運算式';\n default:\n return type;\n }\n}\n\nconst READ_ONLY_NOTIFY_RECIPIENT_HINT =\n '這種知會來源只能在範本 JSON 設定;這裡選擇其他來源會覆寫原設定。';\nconst UNSUPPORTED_NOTIFY_RECIPIENT_HINT =\n '知會節點不支援這種來源,儲存前必須改選其他來源;這裡選擇其他來源會覆寫原設定。';\n\n/** The recipients of a notify action; the empty 指定會員 when it has none. */\nexport const EMPTY_NOTIFY_RECIPIENTS: ApproverResolver = {\n memberIds: [],\n type: 'DIRECT',\n};\n\n/**\n * A notify action's recipients, or the empty 指定會員 for an action that is\n * not a notify yet (the panel is also what turns one into a notify) or that\n * carries no readable recipients (raw JSON that has not been linted).\n */\nexport function readNotifyRecipients(action: ServiceAction): ApproverResolver {\n return action.type === 'NOTIFY' && action.recipients?.type\n ? action.recipients\n : EMPTY_NOTIFY_RECIPIENTS;\n}\n\nexport type NotifyRecipientSourceChoice = Readonly<{\n /** Hint under the select, `null` when nothing needs saying. */\n hint: string | null;\n options: readonly Readonly<{ id: string; name: string }>[];\n /** `true` when the stored source is not one the designer edits. */\n readOnly: boolean;\n selected: Readonly<{ id: string; name: string }>;\n}>;\n\n/**\n * The 知會對象來源 select. A stored source the designer does not edit\n * (發起人主管, 主管鏈, 運算式, one a notify node may not use, or one a newer\n * BPMCore saved) is shown as a read-only entry that is the current value:\n * nothing is written unless the author explicitly picks another source.\n */\nexport function readNotifyRecipientSourceChoice(\n recipients: ApproverResolver,\n): NotifyRecipientSourceChoice {\n const editable = NOTIFY_RECIPIENT_MODE_OPTIONS.find(\n (option) => option.id === recipients.type,\n );\n\n if (editable) {\n return {\n hint: null,\n options: NOTIFY_RECIPIENT_MODE_OPTIONS,\n readOnly: false,\n selected: editable,\n };\n }\n\n const known = isNotifyRecipientResolverType(recipients.type);\n const selected = {\n id: READ_ONLY_NOTIFY_RECIPIENT_OPTION_ID,\n name: known\n ? readReadOnlyNotifyRecipientName(recipients.type)\n : `不支援的知會來源(${recipients.type})`,\n };\n\n return {\n hint: known\n ? READ_ONLY_NOTIFY_RECIPIENT_HINT\n : UNSUPPORTED_NOTIFY_RECIPIENT_HINT,\n options: [...NOTIFY_RECIPIENT_MODE_OPTIONS, selected],\n readOnly: true,\n selected,\n };\n}\n\n/**\n * The recipients a 知會對象來源 pick produces, or `null` when the pick must\n * change nothing: no option, an id that is not an editable source (the\n * read-only entry included), or the source already stored. Re-picking the\n * shown source would otherwise rebuild a clean default and wipe what the\n * author had filled in.\n */\nexport function readNotifyRecipientSourcePick(\n recipients: ApproverResolver,\n optionId: string | null,\n positions: readonly PositionRecord[],\n): ApproverResolver | null {\n if (optionId === null || !isNotifyRecipientEditableType(optionId)) {\n return null;\n }\n\n return optionId === recipients.type\n ? null\n : readDefaultApproverResolver(optionId, positions);\n}\n\n/**\n * The action with new recipients. Only the recipients change: channels,\n * template and webhooks belong to the same action and survive. An action that\n * is not a notify yet becomes one with the default channel.\n */\nexport function withNotifyRecipients(\n action: ServiceAction,\n recipients: ApproverResolver,\n): ServiceAction {\n return action.type === 'NOTIFY'\n ? { ...action, recipients }\n : { channels: ['IN_APP'], recipients, type: 'NOTIFY' };\n}\n\ntype OrgScopedRecipients = Extract<\n ApproverResolver,\n { readonly type: 'ORG_UNIT_MEMBER' | 'ORG_UNIT_POSITION' }\n>;\n\nfunction readIncludeDescendantsKey(\n recipients: OrgScopedRecipients,\n): Readonly<{ includeDescendants?: boolean }> {\n return recipients.includeDescendants === undefined\n ? {}\n : { includeDescendants: recipients.includeDescendants };\n}\n\n/**\n * Picks the organization. 組織特定職位 clears its position (it may not belong\n * to the new organization); 指定組織主管 goes through the approver editor\n * state so its 無主管時 and 只取最近一層主管 settings survive.\n */\nexport function withNotifyOrgUnit(\n recipients: ApproverResolver,\n orgUnitId: string,\n): ApproverResolver {\n if (recipients.type === 'ORG_UNIT_MEMBER') {\n return {\n ...readIncludeDescendantsKey(recipients),\n orgUnitId,\n type: 'ORG_UNIT_MEMBER',\n };\n }\n\n if (recipients.type === 'ORG_UNIT_POSITION') {\n return {\n ...readIncludeDescendantsKey(recipients),\n orgUnitId,\n positionId: '',\n type: 'ORG_UNIT_POSITION',\n };\n }\n\n if (recipients.type === 'ORG_UNIT_MANAGER') {\n const state = readApproverResolverEditorState(recipients);\n\n return state.mode === 'ORG_UNIT_MANAGER'\n ? buildApproverResolver({ ...state, orgUnitId })\n : recipients;\n }\n\n return recipients;\n}\n\n/**\n * Switches 包含下層 of 組織任一人 or 組織特定職位; the latter clears its\n * position, the way the 簽核來源 panel does, because the positions on offer\n * change with the scope.\n */\nexport function withNotifyIncludeDescendants(\n recipients: ApproverResolver,\n includeDescendants: boolean,\n): ApproverResolver {\n if (recipients.type === 'ORG_UNIT_MEMBER') {\n return { ...recipients, includeDescendants };\n }\n\n if (recipients.type === 'ORG_UNIT_POSITION') {\n return { ...recipients, includeDescendants, positionId: '' };\n }\n\n return recipients;\n}\n\n/** Picks the position of 指定職位 or 組織特定職位. */\nexport function withNotifyPosition(\n recipients: ApproverResolver,\n positionId: string,\n): ApproverResolver {\n if (recipients.type === 'POSITION') {\n return { positionId, type: 'POSITION' };\n }\n\n if (recipients.type === 'ORG_UNIT_POSITION') {\n return { ...recipients, positionId };\n }\n\n return recipients;\n}\n\n/** Picks the member field of 依表單欄位指定 (the person in the field only). */\nexport function withNotifyFormPath(\n recipients: ApproverResolver,\n formPath: string,\n): ApproverResolver {\n if (recipients.type !== 'DYNAMIC_FORM') {\n return recipients;\n }\n\n const state = readApproverResolverEditorState(recipients);\n\n return state.mode === 'DYNAMIC_FORM'\n ? buildApproverResolver({ ...state, formPath })\n : recipients;\n}\n","'use client';\n\nimport {\n type CSSProperties,\n type ReactElement,\n useEffect,\n useState,\n} from 'react';\nimport type { TableColumn } from '@mezzanine-ui/core/table';\nimport {\n InlineMessage,\n Modal,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport {\n WorkflowDialectDifferenceRecord,\n WorkflowDialectUpgradePreviewRecord,\n WorkflowExpressionsDraft,\n previewWorkflowDialectUpgrade,\n readExpressionIssueMessage,\n readExpressionLabelLocation,\n} from '@rytass/bpm-core-client/template';\n\nexport interface DialectUpgradeModalProps {\n /** The draft to check: the designer's current state, saved or not. */\n readonly draft: WorkflowExpressionsDraft;\n readonly onCancel: () => void;\n /** The user confirmed; the host switches the draft to cel-v2. */\n readonly onConfirm: () => void;\n readonly open: boolean;\n /** Injectable for tests and Storybook. */\n readonly preview?: (\n draft: WorkflowExpressionsDraft,\n ) => Promise<WorkflowDialectUpgradePreviewRecord>;\n}\n\n// A type literal, not an interface: Table wants an index signature.\ntype DifferenceRow = {\n readonly difference: WorkflowDialectDifferenceRecord;\n readonly key: string;\n};\n\nconst STACK_STYLE: CSSProperties = {\n display: 'grid',\n gap: 'var(--mzn-spacing-gap-base)',\n};\n\n/** `ok:<json>` / `err:<code>` as the designer reads it. */\nexport function readDialectOutcomeText(outcome: string): string {\n if (outcome.startsWith('ok:')) {\n return `結果 ${outcome.slice(3)}`;\n }\n\n if (outcome.startsWith('err:')) {\n return `錯誤 ${outcome.slice(4)}`;\n }\n\n return outcome;\n}\n\nconst SAMPLE_LABELS: Readonly<Record<string, string>> = {\n EMPTY: '欄位都沒填',\n FILLED: '欄位都有值',\n};\n\n/** Whether the check lets the user upgrade on it. */\nexport function canConfirmDialectUpgrade(\n result: WorkflowDialectUpgradePreviewRecord | null,\n): boolean {\n return result !== null && result.complete;\n}\n\n/**\n * The whole-draft dialect upgrade (Phase 23 P4, docs/24 §1): before a draft\n * moves from cel-legacy to cel-v2 the backend runs every expression under\n * both engines on sample data and lists where the answers differ, e.g.\n * `7 / 2` is 3.5 on legacy and an integer division on cel-v2. Nothing is\n * changed here; confirming hands the decision back to the designer, which\n * sets the dialect on the draft and saves it the usual way.\n */\nexport function DialectUpgradeModal({\n draft,\n onCancel,\n onConfirm,\n open,\n preview = previewWorkflowDialectUpgrade,\n}: DialectUpgradeModalProps): ReactElement {\n const [result, setResult] =\n useState<WorkflowDialectUpgradePreviewRecord | null>(null);\n const [failed, setFailed] = useState(false);\n\n useEffect((): (() => void) => {\n let cancelled = false;\n\n setResult(null);\n setFailed(false);\n\n if (open) {\n preview(draft)\n .then((next): void => {\n if (!cancelled) {\n setResult(next);\n }\n })\n .catch((): void => {\n if (!cancelled) {\n setFailed(true);\n }\n });\n }\n\n return (): void => {\n cancelled = true;\n };\n // The draft is read when the modal opens; edits behind it do not rerun it.\n }, [open]);\n\n const columns: TableColumn<DifferenceRow>[] = [\n {\n ellipsis: false,\n key: 'label',\n render: ({ difference }): string =>\n readExpressionLabelLocation(difference.label, draft.workflowDefinition) ??\n difference.label,\n title: '位置',\n },\n {\n key: 'sample',\n render: ({ difference }): string =>\n SAMPLE_LABELS[difference.sample] ?? difference.sample,\n title: '試算資料',\n width: 120,\n },\n {\n ellipsis: false,\n key: 'legacy',\n render: ({ difference }): string =>\n readDialectOutcomeText(difference.legacyOutcome),\n title: '目前(cel-legacy)',\n },\n {\n ellipsis: false,\n key: 'v2',\n render: ({ difference }): string =>\n readDialectOutcomeText(difference.v2Outcome),\n title: '升級後(cel-v2)',\n },\n ];\n\n return (\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{ disabled: !canConfirmDialectUpgrade(result) }}\n confirmText=\"確認升級\"\n loading={open && result === null && !failed}\n modalType=\"standard\"\n onCancel={onCancel}\n onClose={onCancel}\n onConfirm={onConfirm}\n open={open}\n showModalFooter\n showModalHeader\n size=\"wide\"\n supportingText=\"升級只改這份草稿,儲存並發布後才會影響新案件;已發布的版本維持原本的方言。\"\n title=\"升級運算式方言到 cel-v2\"\n >\n <div style={STACK_STYLE}>\n {failed ? (\n <InlineMessage\n content=\"無法完成升級前的比對,請稍後再試。\"\n severity=\"error\"\n />\n ) : null}\n {result === null ? null : (\n <>\n <Typography variant=\"body\">\n {`共 ${result.expressionCount} 個運算式,已比對 ${result.checkedCount} 個;${\n result.differences.length === 0\n ? '兩種方言的結果都相同。'\n : `${result.differences.length} 處結果不同,請逐一確認。`\n }`}\n </Typography>\n {result.complete ? null : (\n <InlineMessage\n content=\"比對逾時、沒有全部完成,不能據此升級。\"\n severity=\"error\"\n />\n )}\n {result.differences.length > 0 ? (\n <Table\n columns={columns}\n dataSource={result.differences.map(\n (difference, index): DifferenceRow => ({\n difference,\n key: `${difference.label}:${difference.sample}:${index}`,\n }),\n )}\n fullWidth\n />\n ) : null}\n {result.v2Issues.map((issue, index) => (\n <InlineMessage\n content={readExpressionIssueMessage(\n issue,\n draft.workflowDefinition,\n )}\n key={`${issue.label}:${issue.code}:${index}`}\n severity={issue.severity === 'ERROR' ? 'error' : 'warning'}\n />\n ))}\n </>\n )}\n </div>\n </Modal>\n );\n}\n","'use client';\n\nimport {\n type ChangeEvent,\n type CSSProperties,\n type ReactElement,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n Badge,\n Button,\n InlineMessage,\n Select,\n Textarea,\n Typography,\n} from '@mezzanine-ui/react';\nimport type { ExpressionUsagePoint } from '@rytass/bpm-core-shared';\nimport type { WorkflowExpressionDialect } from '@rytass/bpm-core-shared/workflow';\nimport type { GraphQlRequestOptions } from '@rytass/bpm-core-client';\nimport {\n ExpressionCatalogRecord,\n ExpressionEvaluationRecord,\n ExpressionIssueRecord,\n ExpressionPreviewRecord,\n PreviewExpressionInput,\n previewExpression,\n readExpressionCatalog,\n readExpressionIssueMessage,\n} from '@rytass/bpm-core-client/template';\nimport { BPMFormField } from '../../../../components/bpm-form-field';\n\n/**\n * Where the backend check of one expression stands. `UNAVAILABLE`: the check\n * itself failed (network, 403); the field cannot vouch for the expression.\n */\nexport type ExpressionFieldStatus =\n | 'CHECKING'\n | 'EMPTY'\n | 'INVALID'\n | 'UNAVAILABLE'\n | 'VALID';\n\nexport interface ExpressionFieldLint {\n readonly issues: readonly ExpressionIssueRecord[];\n readonly status: ExpressionFieldStatus;\n}\n\n/** The backend calls the field makes; injectable for tests and Storybook. */\nexport interface ExpressionFieldApi {\n readonly preview: (\n input: PreviewExpressionInput,\n options?: GraphQlRequestOptions,\n ) => Promise<ExpressionPreviewRecord>;\n readonly readCatalog: (\n input: Readonly<{\n formDefinitionVersionId?: string | null;\n usagePoint: ExpressionUsagePoint;\n }>,\n options?: GraphQlRequestOptions,\n ) => Promise<ExpressionCatalogRecord>;\n}\n\nexport interface ExpressionFieldProps {\n readonly api?: ExpressionFieldApi;\n /** Lint delay after the last keystroke. */\n readonly debounceMs?: number;\n readonly dialect: WorkflowExpressionDialect;\n readonly disabled?: boolean;\n /** FLOW_CONDITION: the type of the node the edge leaves. */\n readonly edgeSourceNodeType?: string | null;\n /** Offer a sample-data trial run (EVALUATE) under the field. */\n readonly evaluable?: boolean;\n readonly formDefinitionVersionId?: string | null;\n readonly hintText?: string;\n readonly label: string;\n readonly name: string;\n readonly onChange: (value: string) => void;\n /** Every change of the backend check, so a host can block applying. */\n readonly onLintChange?: (lint: ExpressionFieldLint) => void;\n readonly required?: boolean;\n readonly rows?: number;\n /** SERVICE_FORM_FIELD_VALUE: the field the value is written to. */\n readonly targetFieldKey?: string | null;\n readonly usagePoint: ExpressionUsagePoint;\n readonly value: string;\n}\n\nconst DEFAULT_API: ExpressionFieldApi = {\n preview: previewExpression,\n readCatalog: readExpressionCatalog,\n};\n\n// `minmax(0, 1fr)` and `minWidth: 0` let the field shrink to the column it\n// sits in: the designer's side panel is a fixed-width grid column, and a grid\n// item's automatic minimum (its widest content) pushed it past the viewport.\nconst STACK_STYLE: CSSProperties = {\n display: 'grid',\n gap: 'var(--mzn-spacing-gap-base)',\n gridTemplateColumns: 'minmax(0, 1fr)',\n minWidth: 0,\n};\n\nconst NOTE_LIST_STYLE: CSSProperties = {\n display: 'grid',\n gap: 'var(--mzn-spacing-gap-tight)',\n gridTemplateColumns: 'minmax(0, 1fr)',\n minWidth: 0,\n overflowWrap: 'anywhere',\n};\n\nconst ROW_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'flex',\n flexWrap: 'wrap',\n gap: 'var(--mzn-spacing-gap-base)',\n minWidth: 0,\n};\n\ninterface CatalogOption {\n readonly id: string;\n readonly name: string;\n}\n\n/** Catalog entries as insertable snippets: field paths, then `name(`. */\nexport function readExpressionCatalogOptions(\n catalog: ExpressionCatalogRecord | null,\n): readonly CatalogOption[] {\n if (!catalog) {\n return [];\n }\n\n return [\n ...catalog.roots.map((root) => ({ id: root, name: `${root}(根)` })),\n ...catalog.fields.map((field) => ({\n id: field.path,\n name: `${field.path}(${field.label})`,\n })),\n ...catalog.functions.map((fn) => ({\n id: `${fn.name}(`,\n name: `${fn.name}(${fn.parameters.map((parameter) => parameter.name).join(', ')})${fn.label ? `(${fn.label})` : ''}`,\n })),\n ];\n}\n\nexport interface ExpressionCatalogFunctionNote {\n readonly id: string;\n readonly text: string;\n}\n\n/**\n * What each catalog function does, as plain lines under the picker. The\n * picker's options carry only a name (Mezzanine `DropdownOption` has no\n * secondary text), so a function's `description` was never shown. Functions\n * without one are left out; the text is rendered as text, never as HTML.\n */\nexport function readExpressionCatalogFunctionNotes(\n catalog: ExpressionCatalogRecord | null,\n): readonly ExpressionCatalogFunctionNote[] {\n if (!catalog) {\n return [];\n }\n\n return catalog.functions\n .filter((fn) => fn.description.trim().length > 0)\n .map((fn) => ({\n id: fn.name,\n text: `${fn.name}${fn.label ? `(${fn.label})` : ''}:${fn.description.trim()}`,\n }));\n}\n\n/** Appends a snippet, separated by a space unless the text already ends in one. */\nexport function appendExpressionSnippet(value: string, snippet: string): string {\n if (value.length === 0 || /[\\s(]$/u.test(value)) {\n return `${value}${snippet}`;\n }\n\n return `${value} ${snippet}`;\n}\n\n/** The status badge copy; the issues themselves are listed underneath. */\nexport function readExpressionFieldStatusText(\n status: ExpressionFieldStatus,\n): string | null {\n switch (status) {\n case 'CHECKING':\n return '後端檢查中';\n case 'INVALID':\n return '未通過檢查';\n case 'UNAVAILABLE':\n return '無法檢查';\n case 'VALID':\n return '通過檢查';\n default:\n return null;\n }\n}\n\nconst STATUS_BADGE_VARIANT = {\n CHECKING: 'dot-info',\n INVALID: 'dot-error',\n UNAVAILABLE: 'dot-warning',\n VALID: 'dot-success',\n} as const;\n\n/** The parsed trial-run sample, or why it cannot be one. */\nexport function readExpressionSample(\n json: string,\n): Readonly<Record<string, unknown>> | string {\n try {\n const parsed: unknown = JSON.parse(json);\n\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return '樣本資料必須是 JSON 物件,例如 { \"form\": { \"amount\": 1200 } }。';\n }\n\n return parsed as Readonly<Record<string, unknown>>;\n } catch {\n return '樣本資料不是有效的 JSON。';\n }\n}\n\n/** One trial-run outcome as plain text (rendered as text, never as HTML). */\nexport function readExpressionEvaluationText(\n evaluation: ExpressionEvaluationRecord,\n): string {\n if (evaluation.outcome === 'ERROR') {\n return `試算失敗(${evaluation.errorCode ?? '未知錯誤'})`;\n }\n\n return `試算結果:${evaluation.resultJson ?? 'null'}${evaluation.resultType ? `(${evaluation.resultType})` : ''}`;\n}\n\n/**\n * A CEL expression input (Phase 23 P4, ADR 22 §3.8): Mezzanine Textarea plus\n * a catalog picker, with the backend's lint findings listed underneath. The\n * browser only sends text; parsing, linting and the optional trial run all\n * happen on the backend (`previewExpression`, designer-only).\n */\nexport function ExpressionField({\n api = DEFAULT_API,\n debounceMs = 400,\n dialect,\n disabled = false,\n edgeSourceNodeType = null,\n evaluable = false,\n formDefinitionVersionId = null,\n hintText,\n label,\n name,\n onChange,\n onLintChange,\n required = false,\n rows = 3,\n targetFieldKey = null,\n usagePoint,\n value,\n}: ExpressionFieldProps): ReactElement {\n const [lint, setLint] = useState<ExpressionFieldLint>({\n issues: [],\n status: 'EMPTY',\n });\n const [catalog, setCatalog] = useState<ExpressionCatalogRecord | null>(null);\n const [sampleJson, setSampleJson] = useState('{\\n \"form\": {}\\n}');\n const [evaluation, setEvaluation] = useState<string | null>(null);\n const [evaluating, setEvaluating] = useState(false);\n const onLintChangeRef = useRef(onLintChange);\n onLintChangeRef.current = onLintChange;\n\n useEffect((): (() => void) => {\n const controller = new AbortController();\n\n api\n .readCatalog({ formDefinitionVersionId, usagePoint }, { signal: controller.signal })\n .then((next): void => setCatalog(next))\n .catch((): void => {\n if (!controller.signal.aborted) {\n setCatalog(null);\n }\n });\n\n return (): void => controller.abort();\n }, [api, formDefinitionVersionId, usagePoint]);\n\n useEffect((): (() => void) => {\n const expression = value.trim();\n const publish = (next: ExpressionFieldLint): void => {\n setLint(next);\n onLintChangeRef.current?.(next);\n };\n\n setEvaluation(null);\n\n if (expression.length === 0) {\n publish({ issues: [], status: 'EMPTY' });\n\n return (): void => undefined;\n }\n\n publish({ issues: [], status: 'CHECKING' });\n\n const controller = new AbortController();\n const timer = setTimeout((): void => {\n api\n .preview(\n {\n dialect,\n edgeSourceNodeType,\n expression,\n formDefinitionVersionId,\n mode: 'LINT',\n targetFieldKey,\n usagePoint,\n },\n { signal: controller.signal },\n )\n .then((preview): void =>\n publish({\n issues: preview.issues,\n status: preview.valid ? 'VALID' : 'INVALID',\n }),\n )\n .catch((): void => {\n if (!controller.signal.aborted) {\n publish({ issues: [], status: 'UNAVAILABLE' });\n }\n });\n }, debounceMs);\n\n return (): void => {\n clearTimeout(timer);\n controller.abort();\n };\n }, [\n api,\n debounceMs,\n dialect,\n edgeSourceNodeType,\n formDefinitionVersionId,\n targetFieldKey,\n usagePoint,\n value,\n ]);\n\n const catalogOptions = useMemo(\n (): readonly CatalogOption[] => readExpressionCatalogOptions(catalog),\n [catalog],\n );\n const functionNotes = useMemo(\n (): readonly ExpressionCatalogFunctionNote[] =>\n readExpressionCatalogFunctionNotes(catalog),\n [catalog],\n );\n const statusText = readExpressionFieldStatusText(lint.status);\n const runEvaluation = async (): Promise<void> => {\n const sample = readExpressionSample(sampleJson);\n\n if (typeof sample === 'string') {\n setEvaluation(sample);\n\n return;\n }\n\n setEvaluating(true);\n\n try {\n const preview = await api.preview({\n dialect,\n edgeSourceNodeType,\n expression: value.trim(),\n formDefinitionVersionId,\n mode: 'EVALUATE',\n sampleContext: sample,\n targetFieldKey,\n usagePoint,\n });\n\n setEvaluation(\n preview.evaluation\n ? readExpressionEvaluationText(preview.evaluation)\n : '運算式未通過檢查,沒有試算。',\n );\n } catch {\n setEvaluation('無法試算,請稍後再試。');\n } finally {\n setEvaluating(false);\n }\n };\n\n return (\n <BPMFormField\n hintText={hintText}\n label={label}\n name={name}\n required={required}\n severity={lint.status === 'INVALID' ? 'error' : 'info'}\n >\n <div style={STACK_STYLE}>\n <Textarea\n disabled={disabled}\n name={name}\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void =>\n onChange(event.target.value)\n }\n resize=\"vertical\"\n rows={rows}\n value={value}\n />\n <div style={ROW_STYLE}>\n {statusText && lint.status !== 'EMPTY' ? (\n <Badge\n text={statusText}\n variant={STATUS_BADGE_VARIANT[lint.status]}\n />\n ) : null}\n {catalog && !catalog.functionsAvailable ? (\n <Typography variant=\"caption\">\n 宿主函式目錄暫時讀不到,只列出欄位。\n </Typography>\n ) : null}\n </div>\n {catalogOptions.length > 0 && !disabled ? (\n // Full width on its own line: the dropdown takes the trigger's\n // width, so it stays inside the column instead of growing with\n // the longest option.\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void => {\n if (option) {\n onChange(appendExpressionSnippet(value, option.id));\n }\n }}\n options={[...catalogOptions]}\n placeholder=\"插入欄位或函式\"\n value={null}\n />\n ) : null}\n {functionNotes.length > 0 && !disabled ? (\n <div aria-label=\"函式說明\" role=\"list\" style={NOTE_LIST_STYLE}>\n {functionNotes.map((note) => (\n <Typography\n color=\"text-neutral\"\n key={note.id}\n role=\"listitem\"\n variant=\"caption\"\n >\n {note.text}\n </Typography>\n ))}\n </div>\n ) : null}\n {lint.status === 'UNAVAILABLE' ? (\n <InlineMessage\n content=\"無法向後端檢查這個運算式,發布時仍會再檢查。\"\n severity=\"warning\"\n />\n ) : null}\n {lint.issues.map((issue) => (\n <InlineMessage\n content={readExpressionIssueMessage(issue)}\n key={`${issue.code}:${issue.subject ?? ''}`}\n severity={issue.severity === 'ERROR' ? 'error' : 'warning'}\n />\n ))}\n {evaluable ? (\n <div style={STACK_STYLE}>\n <Textarea\n aria-label={`${label}試算樣本`}\n disabled={disabled}\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void =>\n setSampleJson(event.target.value)\n }\n resize=\"vertical\"\n rows={3}\n value={sampleJson}\n />\n <div style={ROW_STYLE}>\n <Button\n disabled={disabled || evaluating || lint.status !== 'VALID'}\n onClick={(): void => {\n void runEvaluation();\n }}\n type=\"button\"\n variant=\"base-secondary\"\n >\n 以樣本試算\n </Button>\n {evaluation === null ? null : (\n <Typography variant=\"body\">{evaluation}</Typography>\n )}\n </div>\n </div>\n ) : null}\n </div>\n </BPMFormField>\n );\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n WorkflowExpressionsDraft,\n WorkflowExpressionsRecord,\n analyzeWorkflowExpressions,\n readExpressionFieldReferences,\n} from '@rytass/bpm-core-client/template';\nimport type { GraphQlRequestOptions } from '@rytass/bpm-core-client';\n\nexport interface WorkflowExpressionReferences {\n readonly analysis: WorkflowExpressionsRecord | null;\n /** Field key → labels of the expressions reading it. */\n readonly references: ReadonlyMap<string, readonly string[]>;\n /**\n * The references of the draft as it is now. Answers from the last analysis\n * when it was made for this very draft, otherwise asks the backend at once.\n * Resolves to `null` when the backend cannot answer, so a caller guarding a\n * destructive edit can refuse it instead of letting it through.\n */\n readonly resolveCurrentReferences: () => Promise<ReadonlyMap<\n string,\n readonly string[]\n > | null>;\n}\n\ninterface KeyedAnalysis {\n readonly key: string;\n readonly record: WorkflowExpressionsRecord;\n}\n\n/**\n * The backend's reading of the draft's expressions (Phase 23 P4), refreshed a\n * moment after the draft stops changing. Field references come from the\n * backend's AST, never from parsing CEL in the browser. A failed analysis\n * leaves the last answer in place for display; `resolveCurrentReferences`\n * never answers from a stale or missing analysis.\n */\nexport function useWorkflowExpressionReferences(\n draft: WorkflowExpressionsDraft,\n enabled: boolean,\n analyze: (\n draft: WorkflowExpressionsDraft,\n options?: GraphQlRequestOptions,\n ) => Promise<WorkflowExpressionsRecord> = analyzeWorkflowExpressions,\n debounceMs = 800,\n): WorkflowExpressionReferences {\n const [analysis, setAnalysis] = useState<KeyedAnalysis | null>(null);\n const key = JSON.stringify(draft);\n // The latest draft and analysis, for the imperative resolver below.\n const latestRef = useRef<{\n readonly analysis: KeyedAnalysis | null;\n readonly draft: WorkflowExpressionsDraft;\n readonly key: string;\n }>({ analysis, draft, key });\n\n latestRef.current = { analysis, draft, key };\n\n useEffect((): (() => void) => {\n if (!enabled) {\n return (): void => undefined;\n }\n\n const controller = new AbortController();\n const timer = setTimeout((): void => {\n analyze(draft, { signal: controller.signal })\n .then((record): void => setAnalysis({ key, record }))\n .catch((): void => undefined);\n }, debounceMs);\n\n return (): void => {\n clearTimeout(timer);\n controller.abort();\n };\n // `key` stands for the draft's content.\n }, [analyze, debounceMs, enabled, key]);\n\n const references = useMemo(\n (): ReadonlyMap<string, readonly string[]> =>\n readExpressionFieldReferences(analysis?.record ?? null),\n [analysis],\n );\n\n const resolveCurrentReferences = useCallback(async (): Promise<ReadonlyMap<\n string,\n readonly string[]\n > | null> => {\n const latest = latestRef.current;\n\n if (latest.analysis !== null && latest.analysis.key === latest.key) {\n return readExpressionFieldReferences(latest.analysis.record);\n }\n\n try {\n const record = await analyze(latest.draft);\n\n setAnalysis({ key: latest.key, record });\n\n return readExpressionFieldReferences(record);\n } catch {\n return null;\n }\n }, [analyze]);\n\n return {\n analysis: analysis?.record ?? null,\n references,\n resolveCurrentReferences,\n };\n}\n","import type {\n WorkflowDesignerState,\n WorkflowExpressionFinding,\n WorkflowExpressionRequest,\n WorkflowExpressionTools,\n} from '@rytass/bpm-core-shared';\nimport {\n ExpressionPreviewRecord,\n PreviewExpressionInput,\n previewExpression,\n readExpressionCatalog,\n readExpressionIssueMessage,\n} from '@rytass/bpm-core-client/template';\n\n/** The client calls the tools make; injectable for tests. */\nexport interface WorkflowExpressionToolsApi {\n readonly preview: (\n input: PreviewExpressionInput,\n ) => Promise<ExpressionPreviewRecord>;\n readonly readCatalog: typeof readExpressionCatalog;\n}\n\nconst DEFAULT_API: WorkflowExpressionToolsApi = {\n preview: (input): Promise<ExpressionPreviewRecord> => previewExpression(input),\n readCatalog: readExpressionCatalog,\n};\n\nconst toPreviewInput = (\n state: WorkflowDesignerState,\n request: WorkflowExpressionRequest,\n): Omit<PreviewExpressionInput, 'mode'> => ({\n dialect: request.dialect,\n edgeSourceNodeType: request.edgeSourceNodeType,\n expression: request.expression,\n formDefinitionVersionId: state.formDefinitionVersionId,\n targetFieldKey: request.targetFieldKey,\n usagePoint: request.usagePoint,\n});\n\n/**\n * The assistant's expression tools (Phase 23 P4, ADR 22 §3.8), backed by the\n * designer-only GraphQL operations. Every answer comes from the backend; the\n * browser neither parses nor evaluates CEL. Findings are written as designer\n * sentences so the model can relay them to the user.\n */\nexport function createWorkflowExpressionTools(\n state: WorkflowDesignerState,\n api: WorkflowExpressionToolsApi = DEFAULT_API,\n): WorkflowExpressionTools {\n return {\n catalog: (usagePoint): Promise<unknown> =>\n api.readCatalog({\n formDefinitionVersionId: state.formDefinitionVersionId,\n usagePoint,\n }),\n evaluate: async (request, sample): Promise<unknown> => {\n const preview = await api.preview({\n ...toPreviewInput(state, request),\n mode: 'EVALUATE',\n sampleContext: sample,\n });\n\n return preview.evaluation;\n },\n lint: async (request): Promise<readonly WorkflowExpressionFinding[]> => {\n const preview = await api.preview({\n ...toPreviewInput(state, request),\n mode: 'LINT',\n });\n\n return preview.issues.map(\n (issue): WorkflowExpressionFinding => ({\n code: issue.code,\n message: readExpressionIssueMessage(issue, state.definition),\n severity: issue.severity,\n }),\n );\n },\n };\n}\n","import type {\n WorkflowDefinition,\n WorkflowEdge,\n WorkflowNode,\n} from '@rytass/bpm-core-shared/workflow';\n\n/**\n * Pure designer edits for the free-text expressions the command layer has no\n * primitive for (Phase 23 P4): a node's entry condition and an edge's\n * hand-written CEL condition. The designer applies them through\n * `controller.replaceState`; the assistant cannot reach them (its toolset\n * offers `set_edge_condition`, the structured builder, instead).\n */\n\n/** Nodes that may carry `entryCondition`. */\nexport function hasWorkflowEntryCondition(\n node: WorkflowNode,\n): node is Extract<WorkflowNode, { type: 'serviceTask' | 'userTask' }> {\n return node.type === 'userTask' || node.type === 'serviceTask';\n}\n\n/** Sets (or, for blank text, removes) a node's entry condition. */\nexport function setWorkflowNodeEntryCondition(\n definition: WorkflowDefinition,\n nodeId: string,\n condition: string,\n): WorkflowDefinition {\n return {\n ...definition,\n nodes: definition.nodes.map((node): WorkflowNode => {\n if (node.id !== nodeId || !hasWorkflowEntryCondition(node)) {\n return node;\n }\n\n const rest = Object.fromEntries(\n Object.entries(node.data).filter(([key]) => key !== 'entryCondition'),\n );\n\n return {\n ...node,\n data: condition.trim() ? { ...rest, entryCondition: condition } : rest,\n } as WorkflowNode;\n }),\n };\n}\n\n/**\n * An edge whose condition was written by hand rather than by the structured\n * builder (field + operator + value).\n */\nexport function isWorkflowEdgeExpressionCondition(edge: WorkflowEdge): boolean {\n return Boolean(edge.data.condition?.trim()) && !edge.data.conditionFieldKey;\n}\n\n/**\n * Writes a hand-written condition on an edge, dropping the builder's\n * field / operator / value and the default flag (a conditional edge is not\n * the else path).\n */\nexport function setWorkflowEdgeExpressionCondition(\n definition: WorkflowDefinition,\n edgeId: string,\n condition: string,\n): WorkflowDefinition {\n return {\n ...definition,\n edges: definition.edges.map((edge): WorkflowEdge => {\n if (edge.id !== edgeId) {\n return edge;\n }\n\n // The builder's field / operator / value and the default flag go;\n // nothing else lives on edge data.\n return {\n ...edge,\n data: { condition, isDefault: false, label: '自訂條件' },\n };\n }),\n };\n}\n\n/** The type of the node an edge leaves, for the `lastDecision` check. */\nexport function readWorkflowEdgeSourceNodeType(\n definition: WorkflowDefinition,\n edgeId: string,\n): string | null {\n const edge = definition.edges.find((candidate) => candidate.id === edgeId);\n\n return (\n definition.nodes.find((node) => node.id === edge?.source)?.type ?? null\n );\n}\n\n/**\n * Fields a form edit would rename or delete while expressions still read\n * them (docs/24 §1): keys present before the edit, missing after it, and\n * referenced. Each comes with the labels of the expressions reading it.\n */\nexport function readRemovedExpressionFields(\n beforeFieldKeys: readonly string[],\n afterFieldKeys: readonly string[],\n references: ReadonlyMap<string, readonly string[]>,\n): readonly { readonly fieldKey: string; readonly labels: readonly string[] }[] {\n const after = new Set(afterFieldKeys);\n\n return beforeFieldKeys\n .filter((fieldKey) => !after.has(fieldKey))\n .map((fieldKey) => ({ fieldKey, labels: references.get(fieldKey) ?? [] }))\n .filter((entry) => entry.labels.length > 0);\n}\n\nexport type FormEditExpressionCheck =\n | { readonly kind: 'allowed' }\n | {\n readonly kind: 'blocked';\n readonly fields: readonly {\n readonly fieldKey: string;\n readonly labels: readonly string[];\n }[];\n }\n | { readonly kind: 'unverified'; readonly fieldKeys: readonly string[] };\n\n/**\n * Whether a form edit may be applied (docs/24 §1: renaming or deleting a\n * field an expression reads is refused). An edit that removes no field needs\n * no answer from the backend. One that does is checked against the references\n * of the draft as it is now; when those cannot be had (analysis not run yet,\n * request failed, 403) the edit is refused as `unverified` rather than let\n * through — cel-legacy's publish lint does not check field existence, so this\n * is the only guard such a template has.\n */\nexport async function checkFormEditExpressionFields(\n beforeFieldKeys: readonly string[],\n afterFieldKeys: readonly string[],\n resolveReferences: () => Promise<ReadonlyMap<\n string,\n readonly string[]\n > | null>,\n): Promise<FormEditExpressionCheck> {\n const after = new Set(afterFieldKeys);\n const removed = beforeFieldKeys.filter((fieldKey) => !after.has(fieldKey));\n\n if (removed.length === 0) {\n return { kind: 'allowed' };\n }\n\n const references = await resolveReferences();\n\n if (references === null) {\n return { kind: 'unverified', fieldKeys: removed };\n }\n\n const fields = readRemovedExpressionFields(\n beforeFieldKeys,\n afterFieldKeys,\n references,\n );\n\n return fields.length > 0 ? { kind: 'blocked', fields } : { kind: 'allowed' };\n}\n","import { parseOrgManagerChainPlaceholder } from '@rytass/bpm-core-shared/workflow';\n\ntype NamedRecord = Readonly<{ id: string; name: string }>;\n\nconst MANAGER_LEVEL_NAMES: Readonly<Record<number, string>> = {\n 1: '直屬主管',\n 2: '第二層主管',\n 3: '第三層主管',\n};\n\nfunction managerLevelName(level: number): string {\n return MANAGER_LEVEL_NAMES[level] ?? `第 ${level} 層主管`;\n}\n\ntype FormFieldRecord = Readonly<{ fieldKey: string; label: string }>;\n\nexport type DryRunAssigneeDirectory = Readonly<{\n /** Fields of the schema the dry run samples, to name a member placeholder. */\n formFields: readonly FormFieldRecord[];\n /** Display name of a real member id, or `null` when it is not known. */\n memberName: (memberId: string) => string | null;\n /** Nodes of the workflow, to name the stages a `nodeActor:` placeholder lists. */\n nodes: readonly NamedRecord[];\n orgUnits: readonly NamedRecord[];\n positions: readonly NamedRecord[];\n}>;\n\n/**\n * The dry run cannot know who a position / org-unit / manager-chain resolver\n * would pick (that depends on the submitter and the directory at submit\n * time), so the engine reports a `<kind>:<ids>` placeholder instead of a\n * member id. This turns each placeholder into a sentence a template author can\n * read; a real member id becomes the member's name, and anything else is\n * returned untouched so an unexpected value stays visible.\n *\n * The placeholder shapes mirror `resolveDryRunAssigneeMemberId` in the engine.\n */\nexport function readDryRunAssigneeLabel(\n assignee: string,\n directory: DryRunAssigneeDirectory,\n): string {\n const [kind, ...ids] = assignee.split(':');\n const orgUnitName = (id: string): string =>\n directory.orgUnits.find((orgUnit) => orgUnit.id === id)?.name ?? id;\n const positionName = (id: string): string =>\n directory.positions.find((position) => position.id === id)?.name ?? id;\n const formFieldName = (fieldKey: string): string =>\n directory.formFields.find((field) => field.fieldKey === fieldKey)?.label ||\n fieldKey;\n const nodeNames = (idList: string): string =>\n idList\n .split(',')\n .map((id) => directory.nodes.find((node) => node.id === id)?.name ?? id)\n .join('、');\n\n if (kind === 'position' && ids.length === 1 && ids[0]) {\n return `職位:${positionName(ids[0])}(送出時依當下人員決定)`;\n }\n\n if (kind === 'orgUnitMember' && ids.length === 1 && ids[0]) {\n return `組織任一人:${orgUnitName(ids[0])}`;\n }\n\n if (kind === 'orgUnitPosition' && ids.length === 2 && ids[0] && ids[1]) {\n return `組織職位:${orgUnitName(ids[0])}/${positionName(ids[1])}`;\n }\n\n if (kind === 'orgUnitManager' && ids.length === 1 && ids[0]) {\n return `組織主管:${orgUnitName(ids[0])}`;\n }\n\n // The dry-run sample for a member field (`readDryRunFormMemberPlaceholder`).\n if (kind === 'formMember' && ids.length === 1 && ids[0]) {\n return `表單欄位「${formFieldName(ids[0])}」選的人(送出時依填寫內容決定)`;\n }\n\n // `parseOrgManagerChainPlaceholder` reads what the engine's\n // `formatOrgManagerChainPlaceholder` wrote: the level, plus the start and the\n // start level when the chain has them.\n const chain = parseOrgManagerChainPlaceholder(assignee);\n\n if (chain) {\n const from =\n chain.startFrom?.type === 'FORM_MEMBER'\n ? `從表單欄位「${formFieldName(chain.startFrom.formPath)}」的主管起算,`\n : chain.startFrom?.type === 'NODE_ACTOR'\n ? `從前面關卡「${nodeNames(chain.startFrom.nodeIds.join(','))}」簽核者的主管起算,`\n : '';\n const startLevel =\n chain.startPositionLevel === null\n ? ''\n : `(從職等 ${chain.startPositionLevel} 開始)`;\n\n return `主管鏈:${from}簽到職等 ${chain.minPositionLevel}${startLevel}(送出時依組織決定實際主管)`;\n }\n\n // A malformed chain placeholder that still has a single part keeps the\n // wording it always had.\n if (kind === 'orgManagerChain' && ids.length === 1 && ids[0]) {\n return `主管鏈:簽到職等 ${ids[0]}(送出時依組織決定實際主管)`;\n }\n\n // The four placeholders of the form-field and prior-stage sources\n // (`readDryRunPlaceholderAssignee` in the engine). A form key or node id may\n // itself hold a colon, so the level is the last segment and the rest is the\n // key / id list.\n const rest = ids.join(':');\n const levelSplit = rest.lastIndexOf(':');\n const leading = levelSplit > 0 ? rest.slice(0, levelSplit) : '';\n const level =\n levelSplit > 0 ? Number(rest.slice(levelSplit + 1)) : Number.NaN;\n const hasLevel = leading !== '' && Number.isInteger(level) && level >= 1;\n\n if (kind === 'formMemberManager' && hasLevel) {\n return `表單欄位「${formFieldName(leading)}」選的人的${managerLevelName(level)}(送出時依填寫內容與組織決定)`;\n }\n\n if (kind === 'formOrgUnitManager' && rest) {\n return `表單欄位「${formFieldName(rest)}」所選組織的主管(送出時依填寫內容決定)`;\n }\n\n if (kind === 'nodeActor' && rest) {\n return `前面關卡「${nodeNames(rest)}」的簽核者(送出時依實際簽核者決定)`;\n }\n\n if (kind === 'nodeActorManager' && hasLevel) {\n return `前面關卡「${nodeNames(leading)}」簽核者的${managerLevelName(level)}(送出時依實際簽核者決定)`;\n }\n\n return directory.memberName(assignee) ?? assignee;\n}\n","/**\n * Header line of the designer. A published template version is named\n * explicitly because the bound form's own version sits right below it, and a\n * reader seeing only \"v1\" there takes it for the template's version.\n */\nexport function readTemplateVersionDescription(input: {\n draftVersion: number | null;\n hasPublishedVersion: boolean;\n publishedVersion: number | null;\n}): string {\n const draftPart =\n input.draftVersion === null\n ? '尚未建立草稿'\n : `草稿 v${input.draftVersion}`;\n const publishedPart =\n input.publishedVersion !== null\n ? `已發布 v${input.publishedVersion}`\n : input.hasPublishedVersion\n ? '已發布版本'\n : '尚未發布';\n\n return `${draftPart} · ${publishedPart}`;\n}\n\n/**\n * The designer header's description line: the version line plus the\n * definition's expression dialect. `ContentHeader` drops any child that is not\n * a button, filter or back link, so a dialect `Tag` there never rendered; its\n * `description` string is the slot it does show.\n */\nexport function readTemplateHeaderDescription(\n versionDescription: string,\n expressionDialect: string,\n): string {\n return `${versionDescription} · 運算式方言 ${expressionDialect}`;\n}\n\n/** The bound form's version, labelled so it is not mistaken for the template's. */\nexport function readFormVersionLabel(\n formName: string,\n version: number,\n): string {\n return `表單:${formName} v${version}`;\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 { formatMemberLabel } from '../../../lib/format-member-label';\nimport { useRouterAdapter } from '../../../lib/router-adapter';\nimport {\n readFieldAccessMatrix,\n type WorkflowDirectory,\n} from '@rytass/bpm-core-shared';\nimport {\n DECISION_POLICY_OPTIONS,\n readDecisionPolicyHint,\n readDecisionPolicyOption,\n} from './decision-policy-options';\nimport { useWorkflowDesignerController } from './use-workflow-designer-controller';\nimport { WorkflowChatDrawer } from './workflow-chat-drawer';\nimport { FieldAccessMatrixDrawer } from './field-access-matrix/FieldAccessMatrixDrawer';\nimport { FieldAccessNodeSection } from './field-access-matrix/FieldAccessNodeSection';\nimport { readFieldAccessNodeTag } from './field-access-matrix/field-access-copy';\nimport { FormBuilderView } from '../../forms/builder/FormBuilderView';\nimport { useBPMRoutes } from '../../../lib/routes-config';\nimport { useBPMLanguage } from '../../../lib/language-provider';\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';\n// xyflow v12 ships no runtime style injection — the stylesheet must be bundled\n// or every ReactFlow surface renders unpositioned. See org-unit-tree-draft-editor.\nimport '@xyflow/react/dist/style.css';\nimport * as dagre from 'dagre';\nimport {\n AutoComplete,\n Button,\n Icon,\n InlineMessage,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Select,\n Tag,\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 isFormStaticOptionFieldDefinition,\n} from '@rytass/bpm-core-shared/form';\nimport {\n ApproverResolver,\n ApproverResolverFallback,\n DecisionPolicy,\n ExcludeInitiatorConfig,\n ExcludeInitiatorWhenEmpty,\n ExcludeNodeActorsConfig,\n NotifyWebhookTarget,\n readUnsupportedApproverFallbackType,\n ServiceAction,\n SlaCalendarMode,\n SlaConfig,\n WorkflowDefinition,\n WorkflowEdge,\n WorkflowEdgeConditionOperator,\n WorkflowEdgeData,\n WorkflowExpressionDialect,\n WorkflowNode,\n WorkflowNodeTriggerMode,\n ReturnBehavior,\n ReturnResubmitStrategy,\n} from '@rytass/bpm-core-shared/workflow';\nimport {\n DEFAULT_QUORUM_THRESHOLD,\n DEFAULT_SLA_CONFIG,\n SLA_CALENDAR_MODE_OPTIONS,\n SLA_DURATION_UNIT_OPTIONS,\n SLA_TIMEOUT_ACTION_OPTIONS,\n SlaDurationParts,\n SlaDurationUnit,\n composeQuorumThreshold,\n composeSlaDuration,\n hasConfiguredConditionEdges,\n isDecisionPolicyUnsatisfiable,\n isOrgManagerChainDecisionPolicyInvalid,\n readApproverResolverIssue,\n readConditionOperator,\n readConditionOperatorOptionsForField,\n readDesignTimeApproverCount,\n readExcludeInitiatorIssue,\n readExcludeNodeActorsShapeIssue,\n readNotifyServiceTaskIssue,\n readNotifyWebhookTargets,\n readSlaDurationParts,\n} from '@rytass/bpm-core-shared/workflow-graph';\nimport { readFormBuilder } from '@rytass/bpm-core-client/form';\nimport { readTemplateErrorMessage } from '../template-error-message';\nimport {\n OrgUnitPicker,\n PositionPicker,\n} from '../../../components/admin-pickers';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport {\n EXCLUDE_NODE_ACTORS_STAGE_HINT,\n NODE_ACTOR_STAGE_HINT,\n ORG_MANAGER_CHAIN_STAGE_HINT,\n readExcludeNodeActorsGraphIssues,\n readExcludeNodeActorStageChoice,\n readNodeActorGraphIssues,\n readNodeActorStageChoice,\n readOrgManagerChainStageChoice,\n} from './node-actor-resolver-options';\nimport { readMinPositionLevelOptions } from './position-level-options';\nimport {\n isMembershipActiveOn,\n readActivePositionIds,\n readOrgPositionPickerState,\n readOrgScopedPositions,\n readOrgUnitScopeIds,\n useOrganizationTodayDateOnlyString,\n} from './position-scope';\n\nconst ORG_POSITION_INACTIVE_HINT =\n '這個組織範圍內目前沒有擁有此職位的有效會員,請改選其他職位。';\nimport {\n OrgUnitRecord,\n MembershipRecord,\n PositionRecord,\n readOrganizationDirectory,\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 readWorkflowLintMessage,\n resolveMemberOptions,\n listWorkflowWebhookEndpoints,\n searchMemberOptions,\n searchPublishedFormVersionOptions,\n TemplateDesignerRecord,\n updateApprovalTemplateDraft,\n WorkflowWebhookEndpointRecord,\n} from '@rytass/bpm-core-client/template';\nimport {\n NotifyWebhookCatalogState,\n NotifyWebhookTargetsEditor,\n} from './NotifyWebhookTargetsEditor';\nimport {\n APPROVER_RESOLVER_MODE_OPTIONS,\n MANAGER_LEVEL_OPTIONS,\n MemberSelectOption,\n NodeNameRecord,\n ORG_UNIT_SOURCE_OPTIONS,\n START_POSITION_LEVEL_HINT,\n buildApproverResolver,\n readApproverManagerRule,\n readApproverResolverEditorState,\n readApproverResolverMemberIds,\n readApproverResolverSummary,\n readApproverSourceChoice,\n readApproverSourcePick,\n readApproverSubjectChoice,\n readApproverSubjectPick,\n readFallbackMemberSelectOption,\n readManagerLevelOption,\n readManagerLevelOptionById,\n readMemberSelectOption,\n readOrgManagerChainFallbackHint,\n readOrgManagerChainStartChoice,\n readOrgManagerChainStartFormPath,\n readOrgManagerChainStartLevelChoice,\n readOrgManagerChainStartLevelPick,\n readOrgManagerChainStartLevelProblem,\n readOrgManagerChainStartMode,\n readOrgManagerChainStartNodeIds,\n readOrgManagerChainStartPick,\n readOrgUnitDisplayName,\n readPositionDisplayName,\n readSelectedOrgUnitOption,\n readSelectedPositionOption,\n updateApproverResolverFallback,\n withOrgManagerChainMinPositionLevel,\n withOrgManagerChainStartFormPath,\n withOrgManagerChainStartNodeIds,\n withOrgUnitSource,\n withPreferClosestOrgUnit,\n} from './approver-resolver-model';\nimport { readDryRunSampleFormData } from './dry-run-sample-data';\nimport {\n readNotifyRecipients,\n readNotifyRecipientSourceChoice,\n readNotifyRecipientSourcePick,\n withNotifyFormPath,\n withNotifyIncludeDescendants,\n withNotifyOrgUnit,\n withNotifyPosition,\n withNotifyRecipients,\n} from './notify-recipient-options';\nimport { DialectUpgradeModal } from './expression/DialectUpgradeModal';\nimport { ExpressionField } from './expression/ExpressionField';\nimport { useWorkflowExpressionReferences } from './expression/use-workflow-expression-references';\nimport { createWorkflowExpressionTools } from './expression/workflow-expression-tools';\nimport {\n checkFormEditExpressionFields,\n hasWorkflowEntryCondition,\n isWorkflowEdgeExpressionCondition,\n readWorkflowEdgeSourceNodeType,\n setWorkflowEdgeExpressionCondition,\n setWorkflowNodeEntryCondition,\n} from './expression/workflow-expression-edits';\nimport {\n DryRunAssigneeDirectory,\n readDryRunAssigneeLabel,\n} from './dry-run-assignee-label';\nimport {\n readDynamicFormFieldChoice,\n readFormMemberManagerFieldChoice,\n readFormOrgUnitFieldChoice,\n} from './dynamic-form-resolver-options';\nimport {\n readFormVersionLabel,\n readTemplateHeaderDescription,\n readTemplateVersionDescription,\n} from './designer-version-labels';\nimport {\n excludeFailedMemberIds,\n resolveMemberProfilesPerIdOnFailure,\n} from '../../../lib/member-profile-resolution';\nimport {\n findNotifyWebhookEndpoint,\n isNotifyWebhookListEditable,\n readNotifyWebhookDesignerIssues,\n readNotifyWebhookEndpointOptionId,\n} from './notify-webhook-designer';\n\ntype FlowNodeData = Readonly<{\n approverLines: readonly string[] | null;\n approverSummary: string | null;\n fieldAccessTag: 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 ConditionValueOption = Readonly<{\n id: string;\n name: string;\n}>;\ntype InitiatorPolicyMode =\n 'ALL' | 'CUSTOM' | 'NONE' | 'ORG_UNIT' | '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 ReturnAllowedTargetsOption = Readonly<{\n id: ReturnBehavior['allowedTargets'];\n name: string;\n}>;\ntype QuorumThresholdTypeOption = Readonly<{\n id: 'COUNT' | 'PERCENTAGE';\n name: string;\n}>;\ntype ApproverFallbackMode = 'DIRECT' | 'NONE' | 'POSITION';\ntype ApproverFallbackModeOption = Readonly<{\n id: ApproverFallbackMode | 'UNSUPPORTED';\n name: string;\n}>;\ntype ExcludeInitiatorWhenEmptyOption = Readonly<{\n id: ExcludeInitiatorWhenEmpty;\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\n// The side panel sits in a fixed 420px grid column. A grid item's automatic\n// minimum width is its widest content, so without `minWidth: 0` and a\n// shrinkable track a long line in the edge condition form (the expression\n// field and its catalog) widened the panel past the viewport's right edge.\nconst PANEL_STYLE: CSSProperties = {\n display: 'grid',\n gap: 12,\n gridTemplateColumns: 'minmax(0, 1fr)',\n minWidth: 0,\n};\n\nconst FORM_STACK_STYLE: CSSProperties = {\n display: 'grid',\n gap: 12,\n gridTemplateColumns: 'minmax(0, 1fr)',\n minWidth: 0,\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;\n// The 補填 / 隱藏 tag under a user task's labels.\nconst FLOW_NODE_FIELD_ACCESS_TAG_HEIGHT = 24;\n\nconst FIELD_ACCESS_NO_FORM_REASON =\n '先綁定表單版本,才能設定欄位在各關的顯示與補填。';\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_ALLOWED_TARGETS_OPTIONS: readonly ReturnAllowedTargetsOption[] = [\n { id: 'INITIATOR', name: '退回申請人' },\n { id: 'PREVIOUS', name: '退回上一個節點' },\n { id: 'ANY', name: '由簽核者選擇(申請人或之前的簽核節點)' },\n];\nconst RETURN_RESUBMIT_STRATEGY_OPTIONS: readonly ReturnResubmitStrategyOption[] =\n [\n { id: 'RESTART', name: '重新送出後從開始重跑' },\n { id: 'FROM_RETURN_POINT', name: '重新送出後回到退回節點' },\n ];\nconst SLA_WARNING_AT_OPTIONS: readonly {\n readonly id: string;\n readonly name: string;\n readonly value: number | null;\n}[] = [\n { id: 'NONE', name: '不提醒', value: null },\n { id: '0.5', name: '過半時提醒', value: 0.5 },\n { id: '0.75', name: '剩四分之一時提醒', value: 0.75 },\n { id: '0.9', name: '剩十分之一時提醒', value: 0.9 },\n];\nconst QUORUM_THRESHOLD_TYPE_OPTIONS: readonly QuorumThresholdTypeOption[] = [\n { id: 'COUNT', name: '人數' },\n { id: 'PERCENTAGE', name: '百分比' },\n];\nconst APPROVER_FALLBACK_MODE_OPTIONS: readonly ApproverFallbackModeOption[] = [\n { id: 'NONE', name: '停止流程並提示' },\n { id: 'DIRECT', name: '固定改派' },\n { id: 'POSITION', name: '指定職位' },\n];\n// Shown only for a fallback type this build does not know (saved by a newer\n// engine). It is a label, not a choice: picking it changes nothing.\nconst APPROVER_FALLBACK_UNSUPPORTED_OPTION: ApproverFallbackModeOption = {\n id: 'UNSUPPORTED',\n name: '不支援的備援設定',\n};\nconst EXCLUDE_INITIATOR_WHEN_EMPTY_OPTIONS: readonly ExcludeInitiatorWhenEmptyOption[] =\n [\n { id: 'INITIATOR_MANAGER', name: '改由申請人的直屬主管簽核' },\n { id: 'SKIP_NODE', name: '跳過此關' },\n { id: 'FAIL', name: '停止流程並提示' },\n ];\nconst DEFAULT_EXCLUDE_INITIATOR_CONFIG: ExcludeInitiatorConfig = {\n whenEmpty: 'INITIATOR_MANAGER',\n};\n// Stopping loudly is the safe default for a stage-to-stage exclusion: handing\n// the seat to the initiator's manager is a choice the author makes on purpose.\nconst DEFAULT_EXCLUDE_NODE_ACTORS_CONFIG: ExcludeNodeActorsConfig = {\n nodeIds: [],\n whenEmpty: 'FAIL',\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 SERVICE_ACTION_TYPE_OPTIONS: readonly {\n readonly id: 'NOTIFY' | 'SET_FORM_FIELD';\n readonly name: string;\n}[] = [\n { id: 'NOTIFY', name: '知會' },\n { id: 'SET_FORM_FIELD', name: '寫入表單欄位' },\n];\nconst DRY_RUN_MEMBER_ID = 'member-001';\n\n// Publish conflicts are multi-line (one line per conflicting version or\n// instance); keep the line breaks instead of collapsing them into one line.\nconst PUBLISH_ERROR_STYLE: CSSProperties = {\n whiteSpace: 'pre-line',\n};\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 language = useBPMLanguage();\n // \"Today\" in the host's organizationTimeZone, the day the engine judges\n // membership effective dates on; pickers and the dry run share it.\n const organizationToday = useOrganizationTodayDateOnlyString();\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 // Phase 23 P4: the designer picked \"自訂運算式\" and edits the CEL directly,\n // even when it still parses as one of the standard modes.\n const [initiatorPolicyCustomDraft, setInitiatorPolicyCustomDraft] =\n useState(false);\n // The edge switched to a hand-written condition before any text was typed.\n const [expressionEdgeId, setExpressionEdgeId] = useState<string | 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 expressionTools: createWorkflowExpressionTools,\n initialState: {\n definition:\n embedded && initialWorkflowDefinition != null\n ? normalizeDesignerWorkflowDefinition(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 expressionDialect: WorkflowExpressionDialect =\n workflowDefinition.expressionDialect === 'cel-v2' ? 'cel-v2' : 'cel-legacy';\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 // Free-text expression edits the command layer has no primitive for (entry\n // conditions, hand-written edge conditions). Designer UI only.\n const updateWorkflowDefinitionDirectly = (\n update: (definition: WorkflowDefinition) => WorkflowDefinition,\n ): void =>\n controller.replaceState((current) => ({\n ...current,\n definition: update(current.definition),\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 // Kept out of `error` on purpose. `error` is the request-failure banner, and\n // every request path clears it on entry — `handleSearchMembers` starts with\n // `setError(null)`, and editing a DIRECT approver list runs a member search\n // on the very next keystroke. Reporting a dropped decision policy through\n // `error` meant the notice was wiped before the author could read it, in\n // exactly the flow that produces it.\n const [policyNotice, setPolicyNotice] = useState<Readonly<{\n message: string;\n nodeId: string;\n // The policy the reducer replaced it with; the notice is only true while\n // the node still carries that policy.\n policyType: DecisionPolicy['type'];\n }> | null>(null);\n // A notice describes one editing moment on one node, so it must not outlive\n // that node staying selected. `nodeId` alone is not identity: node ids are\n // recycled — `readNextWorkflowNodeIndex` hands out the lowest unused index —\n // so deleting the node the notice was about and adding a fresh one mints the\n // same id, and the stale notice would reattach to a node it never described.\n // Every add and delete moves the selection (`applyDeleteNode` resets it to\n // `start`), so clearing here covers both without each dispatcher remembering.\n useEffect((): void => {\n setPolicyNotice(null);\n }, [selectedNodeId]);\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 // `memberOptions` accumulates every member the designer has ever seen,\n // because it doubles as the id → display-name lookup for nodes elsewhere on\n // the canvas. The pickers must not offer that accumulation as search\n // results, so the latest response is tracked on its own.\n const [memberSearchResults, setMemberSearchResults] = useState<\n readonly MemberSelectOption[]\n >([]);\n // Guards `memberSearchResults` against out-of-order responses: typing\n // narrows a search text while a broader, slower request for an earlier\n // text is still in flight, and that stale response must not overwrite a\n // response for a more recent search. `memberOptions` accumulation is\n // order-insensitive (it only ever adds), so it does not need this guard.\n const memberSearchSequenceRef = useRef(0);\n // Guards a designer load the same way: only the latest `refreshDesigner()`\n // may seed the controller. Two loads overlap whenever the mount effect runs\n // twice (React's development double-invoke) or a save lands while an earlier\n // load is still out; the older answer arriving last used to reset the\n // selection to the start node — dropping the edge the user had just opened.\n const designerLoadSequenceRef = useRef(0);\n // Member ids the directory could not resolve, even asked for on their own.\n // They keep their 「未知會員」 placeholder and are not requested again for\n // the rest of the session, a transient failure included, unless a later\n // member search returns them (the merge then replaces the placeholder).\n const unresolvableMemberIdsRef = useRef<Set<string>>(new Set());\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 [dialectUpgradeOpen, setDialectUpgradeOpen] = useState(false);\n const [fieldAccessMatrixOpen, setFieldAccessMatrixOpen] = 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 [webhookCatalog, setWebhookCatalog] = useState<\n readonly WorkflowWebhookEndpointRecord[]\n >([]);\n const [webhookCatalogState, setWebhookCatalogState] =\n useState<NotifyWebhookCatalogState>('loading');\n const [chatOpen, setChatOpen] = useState(false);\n const [formEditOpen, setFormEditOpen] = useState(false);\n const [formDraft, setFormDraft] = useState<FormDraft | null>(null);\n // The form edit last applied from the drawer and not saved yet. `formDraft`\n // is the drawer's working copy; only an applied copy reaches publish and\n // the field-removal check compares against it.\n const [appliedFormDraft, setAppliedFormDraft] = useState<FormDraft | null>(\n null,\n );\n const formDraftDirty = appliedFormDraft !== null;\n const [formDraftLoading, setFormDraftLoading] = useState(false);\n const [formEditChecking, setFormEditChecking] = 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 initiatorPolicyCustomDraft\n ? { mode: 'CUSTOM', value: initiatorPolicyCel ?? '' }\n : (initiatorPolicyDraftOverride ??\n readInitiatorPolicyUiDraft(\n initiatorPolicyCel,\n initiatorPolicyModeDraft,\n )),\n [\n initiatorPolicyCel,\n initiatorPolicyCustomDraft,\n initiatorPolicyDraftOverride,\n initiatorPolicyModeDraft,\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\n // Deprecated endpoints are loaded too: a draft that already points at one\n // must still show its name. The editor only offers active ones.\n useEffect((): (() => void) => {\n let active = true;\n\n listWorkflowWebhookEndpoints({ includeDeprecated: true })\n .then((endpoints): void => {\n if (active) {\n setWebhookCatalog(endpoints);\n setWebhookCatalogState('ready');\n }\n })\n .catch((): void => {\n if (active) {\n setWebhookCatalogState('unavailable');\n }\n });\n\n return (): void => {\n active = false;\n };\n }, []);\n\n // An applied but unsaved form edit is what publish sends, so webhook field\n // choices and the publish check read that schema rather than the bound one.\n const webhookFormSchema: FormDefinitionSchema | null =\n appliedFormDraft?.schema ?? effectiveFormSchema;\n // Phase 23 P4: which form fields the draft's expressions read (backend AST).\n const {\n references: expressionFieldReferences,\n resolveCurrentReferences: resolveExpressionFieldReferences,\n } = useWorkflowExpressionReferences(\n { formDefinitionVersionId, initiatorPolicyCel, workflowDefinition },\n !embedded && !loading,\n );\n const [formEditBlockedMessage, setFormEditBlockedMessage] = useState<\n string | null\n >(null);\n\n // Publish-only: an incomplete webhook can be saved as a draft, but the\n // backend would refuse to publish it (ADR 18 §4).\n const webhookPublishIssue = useMemo(\n (): string | null =>\n webhookCatalogState === 'ready'\n ? (readNotifyWebhookDesignerIssues({\n definition: workflowDefinition,\n endpoints: webhookCatalog,\n formFields: webhookFormSchema?.fields ?? [],\n })[0] ?? null)\n : null,\n [\n webhookCatalog,\n webhookCatalogState,\n webhookFormSchema,\n workflowDefinition,\n ],\n );\n // Publish-only as well: the field access matrix runs the publish lint's own\n // rules (ADR 20 §4), and a draft that breaks them can still be saved.\n const fieldAccessPublishIssue = useMemo((): string | null => {\n const [issue] = readFieldAccessMatrix(\n workflowDefinition,\n webhookFormSchema,\n ).issues;\n\n return issue\n ? readWorkflowLintMessage(issue.message, workflowDefinition, language)\n : null;\n }, [language, webhookFormSchema, workflowDefinition]);\n // Publish-only too: the backend publish lint refuses a 依前面關卡的簽核者 node\n // whose stages can be skipped, sit after it, or straddle a parallel split,\n // while the draft can still be saved with that unfinished.\n const nodeActorPublishIssue = useMemo(\n (): string | null =>\n readNodeActorGraphIssues(workflowDefinition)[0] ?? null,\n [workflowDefinition],\n );\n // Publish-only as well: every stage of 不可與前面關卡同一人 must sit upstream,\n // be on every path to the node and always have a person sign.\n const excludeNodeActorsPublishIssue = useMemo(\n (): string | null =>\n readExcludeNodeActorsGraphIssues(workflowDefinition)[0] ?? null,\n [workflowDefinition],\n );\n const publishIssue =\n webhookPublishIssue ??\n fieldAccessPublishIssue ??\n nodeActorPublishIssue ??\n excludeNodeActorsPublishIssue;\n const flowNodes = useMemo((): FlowNode[] => {\n // Stage names for the 依前面關卡的簽核者 cards, instead of a count.\n const nodeNames = workflowDefinition.nodes.map((candidate) => ({\n id: candidate.id,\n name: candidate.data.label || candidate.id,\n }));\n\n return workflowDefinition.nodes.map((node) =>\n readFlowNode(\n node,\n memberOptions,\n orgUnits,\n positions,\n node.id === selectedNodeId,\n initiatorPolicyDraft,\n webhookFormSchema,\n nodeNames,\n ),\n );\n }, [\n initiatorPolicyDraft,\n memberOptions,\n orgUnits,\n positions,\n selectedNodeId,\n webhookFormSchema,\n workflowDefinition.nodes,\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 organizationDirectory = await readOrganizationDirectory();\n\n setOrgUnits(organizationDirectory.orgUnits);\n setPositions(organizationDirectory.positions);\n setMemberships(organizationDirectory.memberships);\n } catch (requestError: unknown) {\n setError(readTemplateErrorMessage(requestError, language));\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 const loadSequence = ++designerLoadSequenceRef.current;\n\n setLoading(true);\n setError(null);\n // The notice describes an unsaved edit to the definition being replaced.\n // This runs after every save and publish, and again whenever `templateId`\n // changes without the view remounting, so a surviving notice would either\n // linger past the edit it reported or surface against another template's\n // node — ids like `userTask_1` are not template-specific.\n setPolicyNotice(null);\n\n try {\n const [nextRecord, organizationDirectory] = await Promise.all([\n readTemplateDesigner(templateId as string),\n readOrganizationDirectory(),\n ]);\n\n if (loadSequence !== designerLoadSequenceRef.current) {\n return;\n }\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(organizationDirectory.orgUnits);\n setPositions(organizationDirectory.positions);\n setMemberships(organizationDirectory.memberships);\n setFormVersionOptions(\n readFormVersionSelectOptions(nextRecord.formVersions),\n );\n const nextWorkflowDefinition = normalizeDesignerWorkflowDefinition(\n sourceVersion?.workflowDefinition ?? readFallbackWorkflowDefinition(),\n );\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 setInitiatorPolicyCustomDraft(false);\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 setAppliedFormDraft(null);\n } catch (requestError: unknown) {\n if (loadSequence === designerLoadSequenceRef.current) {\n setError(readTemplateErrorMessage(requestError, language));\n }\n } finally {\n if (loadSequence === designerLoadSequenceRef.current) {\n setLoading(false);\n }\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(readTemplateErrorMessage(requestError, language));\n } finally {\n setFormVersionLoading(false);\n }\n }\n\n async function handleSearchMembers(searchText: string): Promise<void> {\n setMemberLoading(true);\n setError(null);\n\n const searchSequence = ++memberSearchSequenceRef.current;\n\n try {\n const options = await searchMemberOptions(searchText);\n const nextOptions = readMemberSelectOptions(options);\n\n // The id → name accumulation takes every response, fresh or not: those\n // members exist regardless of which request asked for them, and the\n // canvas reads names out of it.\n setMemberOptions((currentOptions) =>\n mergeMemberOptions(currentOptions, nextOptions),\n );\n\n // Everything the picker *shows*, though, belongs to the freshest\n // request only.\n if (searchSequence === memberSearchSequenceRef.current) {\n setMemberSearchResults(nextOptions);\n }\n } catch (requestError: unknown) {\n // A superseded request must not paint the error banner either. The\n // newest request is still in flight and will report its own outcome.\n if (searchSequence === memberSearchSequenceRef.current) {\n setError(readTemplateErrorMessage(requestError, language));\n }\n } finally {\n // Same for the spinner: clearing it from a superseded request drops the\n // \"搜尋成員中...\" text while the newest one is still running, so the\n // picker shows \"沒有符合的成員\" over a list it has just cleared.\n if (searchSequence === memberSearchSequenceRef.current) {\n setMemberLoading(false);\n }\n }\n }\n\n async function resolveWorkflowMemberOptions(\n definition: WorkflowDefinition,\n ): Promise<void> {\n const memberIds = readWorkflowDirectMemberIds(definition);\n // An unresolved placeholder counts as missing, not as cached. It carries\n // the member id, so a plain presence check treats a failed fetch as a hit\n // and never asks again — the \"未知會員\" sentinel would then survive every\n // later definition load for the rest of the session.\n //\n // The exception is an id the directory already failed to resolve on its\n // own: it stays 「未知會員」 for the session. Counting it as missing again\n // would re-request it (and re-run the whole per-id retry) every time\n // `memberOptions` changes, which the placeholder merge itself triggers.\n const missingMemberIds = excludeFailedMemberIds(\n memberIds.filter(\n (memberId) =>\n !memberOptions.some(\n (option) => option.memberId === memberId && !option.unresolved,\n ),\n ),\n unresolvableMemberIdsRef.current,\n );\n\n if (missingMemberIds.length === 0) {\n return;\n }\n\n // One bad id (a foreign id stored in the template) makes the host fail the\n // whole batch, so a failed batch is retried per id: the members that do\n // resolve keep their names and only the failing ids show 「未知會員」.\n const { profiles, skippedIds } = await resolveMemberProfilesPerIdOnFailure(\n missingMemberIds,\n resolveMemberOptions,\n );\n const resolvedIds = new Set(profiles.map((profile) => profile.memberId));\n const unresolvableIds = missingMemberIds.filter(\n (memberId) =>\n !resolvedIds.has(memberId) && !skippedIds.includes(memberId),\n );\n\n // Ids the directory answered without (or failed on their own) are given\n // up on for this session; skipped ids were never asked and stay eligible.\n unresolvableIds.forEach((memberId) =>\n unresolvableMemberIdsRef.current.add(memberId),\n );\n\n setMemberOptions((currentOptions) =>\n mergeMemberOptions(currentOptions, [\n ...readMemberSelectOptions(profiles),\n ...[...unresolvableIds, ...skippedIds].map(\n 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 const blockingPublishIssue = publish ? publishIssue : null;\n\n if (validationIssue || policyIssue || blockingPublishIssue) {\n const issue =\n validationIssue ??\n policyIssue ??\n blockingPublishIssue ??\n '流程設定未完成';\n\n setError(issue);\n throw new Error(issue);\n }\n\n if (appliedFormDraft !== 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: appliedFormDraft.schema,\n slaDefaults: null,\n templateDescription: null,\n templateId: templateId ?? null,\n templateName: record?.template.name ?? '模板',\n uiSchema: appliedFormDraft.uiSchema,\n workflowDefinition,\n });\n setAppliedFormDraft(null);\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 // Shown on the page; the buttons call this fire-and-forget, so a\n // rethrow would only surface as an unhandled rejection.\n setError(\n readTemplateErrorMessage(requestError, language, workflowDefinition),\n );\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 // The schema publish would send (an applied form edit included), the\n // same one the 依表單欄位指定 picker reads, so a member field just added\n // to the draft gets a sample value.\n readDryRunSampleFormData(webhookFormSchema),\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 organizationToday,\n ),\n workflowDefinition,\n });\n\n setDryRunResult(result);\n } catch (requestError: unknown) {\n setDryRunError(readTemplateErrorMessage(requestError, language));\n } finally {\n setDryRunRunning(false);\n }\n }\n\n async function openFormEditDrawer(): Promise<void> {\n setFormEditBlockedMessage(null);\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(readTemplateErrorMessage(requestError, language));\n } finally {\n setFormDraftLoading(false);\n }\n }\n\n /**\n * Closes the form drawer without applying: the working copy falls back to\n * the last applied edit (or is reloaded on the next open), so a discarded\n * edit can neither be published nor become the baseline of the next\n * field-removal check.\n */\n function discardFormEdit(): void {\n setFormDraft(appliedFormDraft);\n setFormEditBlockedMessage(null);\n setFormEditOpen(false);\n }\n\n async function applyFormEdit(): Promise<void> {\n if (formDraft === null) {\n setFormEditOpen(false);\n\n return;\n }\n\n const nextDraft = formDraft;\n\n setFormEditChecking(true);\n\n try {\n const check = await checkFormEditExpressionFields(\n webhookFormSchema?.fields.map((field) => field.fieldKey) ?? [],\n nextDraft.schema.fields.map((field) => field.fieldKey),\n resolveExpressionFieldReferences,\n );\n\n if (check.kind === 'blocked') {\n setFormEditBlockedMessage(\n `運算式還在讀取這些欄位,不能改名或刪除:${check.fields\n .map((entry) => entry.fieldKey)\n .join('、')}。請先修改引用它們的運算式。`,\n );\n\n return;\n }\n\n if (check.kind === 'unverified') {\n setFormEditBlockedMessage(\n `無法確認運算式是否還在讀取這些欄位:${check.fieldKeys.join(\n '、',\n )}。為避免運算式讀不到欄位,暫不套用改名或刪除,請稍後再試。`,\n );\n\n return;\n }\n\n setFormEditBlockedMessage(null);\n setAppliedFormDraft(nextDraft);\n controller.replaceState((current) => ({\n ...current,\n formSchema: nextDraft.schema,\n }));\n setFormEditOpen(false);\n } finally {\n setFormEditChecking(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 const nodeId = selectedNode.id;\n const decisionPolicy = selectedNode.data.decisionPolicy;\n\n controller.dispatch({\n approverResolver,\n nodeId,\n type: 'setUserTaskApprover',\n });\n\n // `applySetUserTaskApprover` (libs/shared/workflow-command.ts) decides\n // whether the policy survives the new approver set, so that the assistant\n // gets the same answer as this form. All that is left here is explaining a\n // drop the author would otherwise have to notice on their own: the reducer\n // has no way to talk to them.\n //\n // Any approver change re-decides the question, so retire the previous\n // answer before working out the new one.\n setPolicyNotice(null);\n\n if (\n isOrgManagerChainDecisionPolicyInvalid(approverResolver, decisionPolicy)\n ) {\n setPolicyNotice({\n message: '主管鏈會依序加入多位主管,簽核方式已改為「依序簽核」。',\n nodeId,\n policyType: 'SEQUENTIAL',\n });\n\n return;\n }\n\n if (!isDecisionPolicyUnsatisfiable(decisionPolicy, approverResolver)) {\n return;\n }\n\n setPolicyNotice({\n message:\n `簽核者已變更為 ${readDesignTimeApproverCount(approverResolver)} 位,` +\n `不足原本設定的 ${decisionPolicy?.type === 'QUORUM' ? decisionPolicy.threshold : 0} 位門檻,` +\n '簽核政策已重設為單人簽核,請重新設定。',\n nodeId,\n policyType: 'SINGLE',\n });\n }\n\n function updateUserTaskReturnAllowedTargets(\n allowedTargets: ReturnBehavior['allowedTargets'],\n ): void {\n if (!selectedNode || selectedNode.type !== 'userTask') {\n return;\n }\n\n controller.dispatch({\n allowedTargets,\n nodeId: selectedNode.id,\n type: 'setUserTaskReturnAllowedTargets',\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 updateUserTaskReturnRequireComment(requireComment: boolean): void {\n if (!selectedNode || selectedNode.type !== 'userTask') {\n return;\n }\n\n controller.dispatch({\n nodeId: selectedNode.id,\n requireComment,\n type: 'setUserTaskReturnRequireComment',\n });\n }\n\n function updateUserTaskRequireApprovalComment(\n requireApprovalComment: boolean,\n ): void {\n if (!selectedNode || selectedNode.type !== 'userTask') {\n return;\n }\n\n controller.dispatch({\n nodeId: selectedNode.id,\n requireApprovalComment,\n type: 'setUserTaskRequireApprovalComment',\n });\n }\n\n function updateUserTaskSla(sla: SlaConfig | null): void {\n if (!selectedNode || selectedNode.type !== 'userTask') {\n return;\n }\n\n controller.dispatch({\n nodeId: selectedNode.id,\n sla,\n type: 'setUserTaskSla',\n });\n }\n\n function updateUserTaskExcludeInitiator(\n excludeInitiator: ExcludeInitiatorConfig | null,\n ): void {\n if (!selectedNode || selectedNode.type !== 'userTask') {\n return;\n }\n\n controller.dispatch({\n excludeInitiator,\n nodeId: selectedNode.id,\n type: 'setUserTaskExcludeInitiator',\n });\n }\n\n function updateUserTaskExcludeNodeActors(\n excludeNodeActors: ExcludeNodeActorsConfig | null,\n ): void {\n if (!selectedNode || selectedNode.type !== 'userTask') {\n return;\n }\n\n controller.dispatch({\n excludeNodeActors,\n nodeId: selectedNode.id,\n type: 'setUserTaskExcludeNodeActors',\n });\n }\n\n function updateUserTaskDecisionPolicy(decisionPolicy: DecisionPolicy): void {\n if (!selectedNode || selectedNode.type !== 'userTask') {\n return;\n }\n\n // The author has answered the notice by setting a policy themselves.\n setPolicyNotice(null);\n\n // Every `BPMFormField` that writes a `QUORUM` policy — the threshold\n // input, and the `quorumThresholdType` switch which carries the existing\n // `threshold` across unchanged when only the type toggles — funnels\n // through this one function. Re-sanitising `threshold` here, rather than\n // trusting each call site to have clamped it against the *new*\n // `thresholdType`, is what stops a `COUNT` value entered while\n // unbounded (e.g. 500) from surviving a switch to `PERCENTAGE` and\n // becoming an unreachable engine threshold; it also means a future\n // caller of this function does not need to remember to clamp on its own.\n const sanitisedDecisionPolicy: DecisionPolicy =\n decisionPolicy.type === 'QUORUM'\n ? {\n ...decisionPolicy,\n threshold: composeQuorumThreshold(\n decisionPolicy.threshold,\n decisionPolicy.thresholdType,\n ),\n }\n : decisionPolicy;\n\n controller.dispatch({\n decisionPolicy: sanitisedDecisionPolicy,\n nodeId: selectedNode.id,\n type: 'setUserTaskDecisionPolicy',\n });\n }\n\n function updateUserTaskOptions(\n options: Readonly<{\n allowAddSigner?: boolean;\n allowReject?: boolean;\n allowTransfer?: boolean;\n }>,\n ): void {\n if (!selectedNode || selectedNode.type !== 'userTask') {\n return;\n }\n\n controller.dispatch({\n ...options,\n nodeId: selectedNode.id,\n type: 'setUserTaskOptions',\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(draft: InitiatorPolicyDraft): 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 renders only buttons, filters and a back link\n as children and drops anything else (a Tag included), so the\n dialect rides on its `description` line instead. */}\n <ContentHeader\n description={readTemplateHeaderDescription(\n readTemplateVersionDescription({\n draftVersion: draft?.version ?? null,\n hasPublishedVersion: Boolean(record?.template.currentVersionId),\n publishedVersion:\n record?.versions.find(\n (version) =>\n version.id === record.template.currentVersionId,\n )?.version ?? null,\n }),\n expressionDialect,\n )}\n onBackClick={handleBackToTemplates}\n title={record?.template.name ?? '流程設計器'}\n >\n {expressionDialect === 'cel-legacy' ? (\n <Button\n disabled={loading || saving}\n onClick={(): void => setDialectUpgradeOpen(true)}\n variant=\"base-secondary\"\n >\n 升級到 cel-v2\n </Button>\n ) : null}\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 Boolean(publishIssue)\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\n color=\"text-error\"\n style={PUBLISH_ERROR_STYLE}\n variant=\"body\"\n >\n {error}\n </Typography>\n ) : null}\n {/* Scoped to its node, and dropped as soon as that node carries\n a policy again — the assistant can set one through the\n toolset without going through `updateUserTaskDecisionPolicy`,\n and a notice saying the policy was reset while the panel\n shows a quorum is worse than no notice at all. */}\n {policyNotice &&\n policyNotice.nodeId === selectedNode?.id &&\n selectedNode.type === 'userTask' &&\n (selectedNode.data.decisionPolicy?.type ?? 'SINGLE') ===\n policyNotice.policyType ? (\n <Typography color=\"text-warning\" variant=\"body\">\n {policyNotice.message}\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 {!workflowIssue && publishIssue ? (\n <Typography color=\"text-error\" variant=\"body\">\n 發布前需修正:{publishIssue}\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 => setChatOpen((current) => !current)}\n size=\"sub\"\n variant={chatOpen ? 'base-primary' : 'base-secondary'}\n >\n {aiAssistantAvailable ? 'AI 助理' : '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 <div style={TOOL_GROUP_STYLE}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 表單欄位\n </Typography>\n <div style={BUTTON_ROW_STYLE}>\n <Button\n disabled={webhookFormSchema === null}\n onClick={(): void => setFieldAccessMatrixOpen(true)}\n size=\"sub\"\n title={\n webhookFormSchema === null\n ? FIELD_ACCESS_NO_FORM_REASON\n : undefined\n }\n variant=\"base-secondary\"\n >\n 欄位總覽\n </Button>\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 {!embedded ? (\n <DialectUpgradeModal\n draft={{\n formDefinitionVersionId,\n initiatorPolicyCel,\n workflowDefinition,\n }}\n onCancel={(): void => setDialectUpgradeOpen(false)}\n onConfirm={(): void => {\n setDialectUpgradeOpen(false);\n updateWorkflowDefinitionDirectly((definition) => ({\n ...definition,\n expressionDialect: 'cel-v2',\n }));\n }}\n open={dialectUpgradeOpen}\n />\n ) : null}\n <FieldAccessMatrixDrawer\n definition={workflowDefinition}\n expressionReferences={expressionFieldReferences}\n formSchema={webhookFormSchema}\n language={language}\n onApply={(entries): string | null =>\n controller.dispatch({ entries, type: 'setFieldAccessMatrix' }).error\n }\n onClose={(): void => setFieldAccessMatrixOpen(false)}\n open={fieldAccessMatrixOpen}\n />\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={discardFormEdit}\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 formDefinitionId={\n selectedFormVersionOption?.formDefinitionId ?? null\n }\n onChange={(next): void => {\n setFormDraft(next);\n }}\n templateId={templateId ?? null}\n value={\n formDraft ?? {\n schema: FORM_EDIT_EMPTY_SCHEMA,\n uiSchema: FORM_EDIT_EMPTY_UI_SCHEMA,\n }\n }\n />\n )}\n </div>\n {formEditBlockedMessage ? (\n <InlineMessage\n content={formEditBlockedMessage}\n severity=\"error\"\n />\n ) : null}\n <div style={FORM_EDIT_DRAWER_FOOTER_STYLE}>\n <Button\n disabled={formDraftLoading || formEditChecking}\n loading={formEditChecking}\n onClick={(): void => {\n void applyFormEdit();\n }}\n variant=\"base-primary\"\n >\n 套用\n </Button>\n <Button\n disabled={formEditChecking}\n onClick={discardFormEdit}\n variant=\"base-secondary\"\n >\n 取消\n </Button>\n </div>\n </div>\n </Drawer>\n ) : null}\n </>\n );\n\n function renderDryRunModal(): ReactElement {\n const dryRunAssigneeDirectory: DryRunAssigneeDirectory = {\n formFields: webhookFormSchema?.fields ?? [],\n memberName: (memberId) =>\n memberOptions.find(\n (option) => option.memberId === memberId && !option.unresolved,\n )?.displayName ?? null,\n nodes: workflowDefinition.nodes.map((node) => ({\n id: node.id,\n name: node.data.label || node.id,\n })),\n orgUnits,\n positions,\n };\n\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 ? ` · 處理者:${readDryRunAssigneeLabel(\n step.assigneeMemberId,\n dryRunAssigneeDirectory,\n )}`\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 {(step.status === 'SKIPPED'\n ? []\n : readDryRunWebhookLabels(\n workflowDefinition,\n step.nodeId,\n webhookCatalog,\n )\n ).map((webhookLabel) => (\n <Typography\n color=\"text-neutral\"\n key={webhookLabel.key}\n variant=\"caption\"\n >\n 將送出 Webhook:{webhookLabel.label}\n </Typography>\n ))}\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 {hasWorkflowEntryCondition(node) ? (\n <ExpressionField\n dialect={expressionDialect}\n evaluable\n formDefinitionVersionId={formDefinitionVersionId}\n hintText=\"不符合時跳過這個節點;空白代表一律執行。\"\n label=\"進入條件\"\n name=\"entryCondition\"\n onChange={(condition): void =>\n updateWorkflowDefinitionDirectly((definition) =>\n setWorkflowNodeEntryCondition(definition, node.id, condition),\n )\n }\n usagePoint=\"ENTRY_CONDITION\"\n value={node.data.entryCondition ?? ''}\n />\n ) : 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 ...INITIATOR_POLICY_MODE_OPTIONS,\n INITIATOR_POLICY_CUSTOM_OPTION,\n ];\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 date: organizationToday,\n includeDescendants: Boolean(\n initiatorPolicyDraft.includeDescendants,\n ),\n memberships,\n orgUnitId: initiatorPolicyDraft.orgUnitId ?? '',\n orgUnits,\n positions,\n })\n : [];\n const initiatorPositionPicker = readOrgPositionPickerState({\n orgUnitId: initiatorPolicyDraft.orgUnitId ?? '',\n positionId: initiatorPolicyDraft.positionId ?? '',\n positions,\n scopedPositions: initiatorScopedPositions,\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 setInitiatorPolicyCustomDraft(true);\n\n return;\n }\n\n setInitiatorPolicyCustomDraft(false);\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(readInitiatorPolicyCel(draft, orgUnits));\n }}\n options={policyModeOptions}\n placeholder=\"選擇誰可以發起\"\n value={readSelectOption(\n policyModeOptions,\n initiatorPolicyDraft.mode,\n )}\n />\n </BPMFormField>\n {initiatorPolicyDraft.mode === 'CUSTOM' ? (\n <ExpressionField\n dialect={expressionDialect}\n formDefinitionVersionId={formDefinitionVersionId}\n hintText=\"可讀 subject(發起人的組織、職位);空白代表所有人都能發起。\"\n label=\"發起權限運算式\"\n name=\"initiatorPolicyCel\"\n onChange={(value): void =>\n setInitiatorPolicyCel(value.trim() ? value : null)\n }\n usagePoint=\"INITIATOR_POLICY\"\n value={initiatorPolicyCel ?? ''}\n />\n ) : null}\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\n hintText={\n initiatorPositionPicker.isInactive\n ? ORG_POSITION_INACTIVE_HINT\n : undefined\n }\n label=\"職位\"\n name=\"initiatorPositionId\"\n required\n >\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={initiatorPositionPicker.options}\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 // The panel edits the screen state, not the JSON type: ②本人/主管 and\n // ①固定組織/表單欄位 are one option each, and a type this build does not\n // know is held read-only: no editor renders for it and the JSON is not\n // rewritten, but saving the draft is blocked (readApproverResolverIssue)\n // until the author picks another 簽核來源 or deletes the node.\n const editorState = readApproverResolverEditorState(resolver);\n const sourceChoice = readApproverSourceChoice(editorState);\n const subjectChoice = readApproverSubjectChoice(editorState);\n const managerRule = readApproverManagerRule(resolver);\n const selectedMembers =\n resolver.type === 'DIRECT'\n ? resolver.memberIds.map((memberId) =>\n readMemberSelectOption(memberOptions, memberId),\n )\n : [];\n const selectedOrgUnit =\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 date: organizationToday,\n includeDescendants: Boolean(resolver.includeDescendants),\n memberships,\n orgUnitId: resolver.orgUnitId,\n orgUnits,\n positions,\n })\n : [];\n const orgPositionPicker = readOrgPositionPickerState({\n orgUnitId:\n resolver.type === 'ORG_UNIT_POSITION' ? resolver.orgUnitId : '',\n positionId:\n resolver.type === 'ORG_UNIT_POSITION' ? resolver.positionId : '',\n positions,\n scopedPositions: orgScopedPositions,\n });\n const dynamicFormChoice =\n editorState.mode === 'DYNAMIC_FORM'\n ? editorState.levelsUp === null\n ? readDynamicFormFieldChoice(webhookFormSchema, editorState.formPath)\n : readFormMemberManagerFieldChoice(\n webhookFormSchema,\n editorState.formPath,\n )\n : null;\n const orgFieldChoice =\n editorState.mode === 'ORG_UNIT_MANAGER' &&\n editorState.orgSource === 'FORM_FIELD'\n ? readFormOrgUnitFieldChoice(webhookFormSchema, editorState.formPath)\n : null;\n const selectedManagerOrgUnit =\n editorState.mode === 'ORG_UNIT_MANAGER' &&\n editorState.orgSource === 'FIXED'\n ? readSelectedOrgUnitOption(orgUnits, editorState.orgUnitId)\n : null;\n const nodeActorChoice =\n editorState.mode === 'NODE_ACTOR'\n ? readNodeActorStageChoice(\n workflowDefinition,\n node.id,\n editorState.nodeIds,\n )\n : null;\n const selectedManagerLevel =\n resolver.type === 'ORG_MANAGER'\n ? readManagerLevelOption(resolver.levelsUp)\n : MANAGER_LEVEL_OPTIONS[0];\n const fallback = managerRule?.fallback ?? { type: 'NONE' as const };\n const unsupportedFallbackType =\n readUnsupportedApproverFallbackType(fallback);\n const approverFallbackModeOptions =\n unsupportedFallbackType === null\n ? APPROVER_FALLBACK_MODE_OPTIONS\n : [\n ...APPROVER_FALLBACK_MODE_OPTIONS,\n APPROVER_FALLBACK_UNSUPPORTED_OPTION,\n ];\n // An empty `memberId` means no one has been picked yet (the just-switched\n // default). `readMemberSelectOption` never returns null, so without this\n // guard it would resolve to the \"未知會員\" sentinel and offer that\n // sentinel as a selectable, phantom row.\n const minPositionLevelOptions =\n resolver.type === 'ORG_MANAGER_CHAIN'\n ? readMinPositionLevelOptions(positions, resolver.minPositionLevel)\n : [];\n // The two settings that make a manager chain start somewhere other than\n // at the initiator, or sign only from some position level up.\n const chainResolver =\n resolver.type === 'ORG_MANAGER_CHAIN' ? resolver : null;\n const chainStartMode = chainResolver\n ? readOrgManagerChainStartMode(chainResolver)\n : null;\n const chainStartChoice = chainResolver\n ? readOrgManagerChainStartChoice(chainResolver)\n : null;\n const chainFormChoice =\n chainResolver && chainStartMode === 'FORM_MEMBER'\n ? readFormMemberManagerFieldChoice(\n webhookFormSchema,\n readOrgManagerChainStartFormPath(chainResolver) ?? '',\n )\n : null;\n const chainStageChoice =\n chainResolver && chainStartMode === 'NODE_ACTOR'\n ? readOrgManagerChainStageChoice(\n workflowDefinition,\n node.id,\n readOrgManagerChainStartNodeIds(chainResolver) ?? [],\n )\n : null;\n const chainStartLevelChoice = chainResolver\n ? readOrgManagerChainStartLevelChoice(chainResolver, positions)\n : null;\n const chainStartLevelProblem = chainResolver\n ? readOrgManagerChainStartLevelProblem(chainResolver)\n : null;\n const fallbackMember =\n fallback.type === 'DIRECT' && fallback.memberId\n ? readMemberSelectOption(memberOptions, fallback.memberId)\n : null;\n const fallbackPosition =\n fallback.type === 'POSITION'\n ? readSelectedPositionOption(positions, fallback.positionId)\n : null;\n const resubmitStrategy =\n node.data.returnBehavior.resubmitStrategy ?? 'RESTART';\n const sla = node.data.sla ?? null;\n const excludeInitiator = node.data.excludeInitiator ?? null;\n const excludeNodeActors = node.data.excludeNodeActors ?? null;\n const excludeNodeActorChoice = excludeNodeActors\n ? readExcludeNodeActorStageChoice(\n workflowDefinition,\n node.id,\n excludeNodeActors.nodeIds,\n excludeNodeActors.whenEmpty,\n )\n : null;\n // A hand-authored or AI-authored template may carry a mixed duration such\n // as `P1DT4H`, which this form cannot represent. Keep it visible and\n // read-only rather than silently rewriting it.\n const slaDurationParts = sla ? readSlaDurationParts(sla.duration) : null;\n const slaDurationUnit = slaDurationParts?.unit ?? 'DAY';\n const slaWarningAtOption = readSlaWarningAtOption(sla?.warningAt ?? null);\n const slaEscalateLevel = readManagerLevelOption(sla?.escalateLevelsUp ?? 1);\n // The schema types `decisionPolicy` as required, but templates authored\n // before the field existed carry no such key at runtime, so every read goes\n // through helpers that tolerate `undefined` — same stance as\n // `readDecisionPolicyHint`.\n const decisionPolicyType = readDecisionPolicyType(node.data.decisionPolicy);\n const quorum = readQuorumParts(node.data.decisionPolicy);\n\n function renderApproverSubjectField(): ReactElement | null {\n if (!subjectChoice) {\n return null;\n }\n\n return (\n <BPMFormField\n hintText={\n subjectChoice.invalid\n ? '原本儲存的主管層級無效(需為第 1 層以上),請重新選擇;發布前必須修正。'\n : editorState.mode === 'NODE_ACTOR'\n ? '選「關卡的簽核者」就是簽核者本人;選主管則往上找他的主管,不會是簽核者自己。'\n : '選「欄位裡的人」就是欄位選的人;選主管則往上找他的主管,不會是欄位裡的人自己。'\n }\n label=\"簽核人\"\n name=\"approverSubject\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void => {\n const next = readApproverSubjectPick(\n editorState,\n option?.id ?? null,\n );\n\n if (next) {\n updateUserTaskResolver(buildApproverResolver(next));\n }\n }}\n options={[...subjectChoice.options]}\n value={subjectChoice.selected}\n />\n </BPMFormField>\n );\n }\n\n return (\n <>\n <BPMFormField\n hintText={sourceChoice.hint ?? undefined}\n label=\"簽核來源\"\n name=\"approverResolverType\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void => {\n // Re-picking the source already stored, or the read-only entry of\n // an unsupported type, writes nothing. An EXPRESSION resolver is\n // shown as 指定會員 but is not one, so picking 指定會員 on it still\n // switches (and replaces the expression).\n const next = readApproverSourcePick(\n resolver,\n option?.id ?? null,\n positions,\n );\n\n if (next) {\n updateUserTaskResolver(next);\n }\n }}\n options={[...sourceChoice.options]}\n value={sourceChoice.selected}\n />\n </BPMFormField>\n <BPMFormField\n hintText=\"以運算式算出簽核人 id;結果必須是會員 id 的清單。\"\n label=\"以運算式指定\"\n name=\"approverResolverExpressionMode\"\n >\n <Toggle\n checked={resolver.type === 'EXPRESSION'}\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n const next = event.target.checked\n ? ({ expression: '', type: 'EXPRESSION' } as const)\n : readApproverSourcePick(resolver, 'DIRECT', positions);\n\n if (next) {\n updateUserTaskResolver(next);\n }\n }}\n />\n </BPMFormField>\n {resolver.type === 'EXPRESSION' ? (\n <ExpressionField\n dialect={expressionDialect}\n formDefinitionVersionId={formDefinitionVersionId}\n label=\"簽核人運算式\"\n name=\"approverResolverExpression\"\n onChange={(expression): void =>\n updateUserTaskResolver({ expression, type: 'EXPRESSION' })\n }\n required\n usagePoint=\"APPROVER_RESOLVER\"\n value={resolver.expression}\n />\n ) : null}\n {resolver.type === 'DIRECT' ? (\n <BPMFormField\n hintText={readDecisionPolicyHint(node.data.decisionPolicy)}\n label=\"簽核者\"\n name=\"memberId\"\n required\n >\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=\"multiple\"\n onChange={(options): void =>\n updateUserTaskResolver({\n memberIds: options.map((option) => option.id),\n type: 'DIRECT',\n })\n }\n onSearch={handleSearchMembers}\n onVisibilityChange={(open): void => {\n if (open) {\n // Clear synchronously so the window between opening and the\n // fetch landing never shows a different node's stale\n // results.\n setMemberSearchResults([]);\n void handleSearchMembers('');\n }\n }}\n // Selected members are merged in so they stay untickable from\n // the dropdown: AutoComplete resolves a click back through\n // `options`, so an already-picked member missing from the list\n // could only be removed via its tag. The tags themselves render\n // from `value` and do not need this.\n options={[\n ...mergeMemberOptions(selectedMembers, memberSearchResults),\n ]}\n placeholder=\"搜尋姓名或信箱\"\n searchDebounceTime={300}\n value={selectedMembers}\n />\n </BPMFormField>\n ) : null}\n {editorState.mode === 'DYNAMIC_FORM' ? (\n <>\n <BPMFormField\n hintText={\n dynamicFormChoice?.problem ??\n (editorState.levelsUp === null\n ? '簽核人取自申請人送出表單時在該欄位選的人員。'\n : '依申請人送出表單時在該欄位選的人員,往上找他的主管。')\n }\n label=\"表單欄位\"\n name=\"approverFormPath\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskResolver(\n buildApproverResolver({\n ...editorState,\n formPath: option?.id ?? '',\n }),\n )\n }\n options={[...(dynamicFormChoice?.options ?? [])]}\n placeholder=\"選擇人員選擇欄位\"\n value={dynamicFormChoice?.selected ?? undefined}\n />\n </BPMFormField>\n {renderApproverSubjectField()}\n </>\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 // Changing the level must not drop the fallback the user\n // configured (or one this build cannot read).\n ...(resolver.fallback ? { fallback: resolver.fallback } : {}),\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_MANAGER_CHAIN' ? (\n <>\n <BPMFormField\n hintText={\n chainStartMode === 'INITIATOR'\n ? '從發起人的直屬主管開始往上,職等比前一位高的主管依序加入,簽到職等達此值的主管為止。沒有職位的主管會略過。'\n : '從起點的直屬主管開始往上,職等比前一位高的主管依序加入,簽到職等達此值的主管為止。沒有職位的主管會略過。'\n }\n label=\"簽到職等\"\n name=\"minPositionLevel\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskResolver(\n withOrgManagerChainMinPositionLevel(\n resolver,\n Number(option?.id ?? resolver.minPositionLevel),\n ),\n )\n }\n options={[...minPositionLevelOptions]}\n value={readSelectOption(\n minPositionLevelOptions,\n String(resolver.minPositionLevel),\n )}\n />\n </BPMFormField>\n {chainStartChoice ? (\n <BPMFormField\n hintText={chainStartChoice.hint}\n label=\"從誰的主管開始\"\n name=\"orgManagerChainStart\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void => {\n const next = readOrgManagerChainStartPick(\n resolver,\n option?.id ?? null,\n );\n\n if (next) {\n updateUserTaskResolver(next);\n }\n }}\n options={[...chainStartChoice.options]}\n value={chainStartChoice.selected}\n />\n </BPMFormField>\n ) : null}\n {chainFormChoice ? (\n <BPMFormField\n hintText={\n chainFormChoice.problem ??\n '只能選單選的人員欄位;欄位要必填、不被條件隱藏,否則送出時可能找不到起點。'\n }\n label=\"表單欄位\"\n name=\"orgManagerChainStartFormPath\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskResolver(\n withOrgManagerChainStartFormPath(\n resolver,\n option?.id ?? '',\n ),\n )\n }\n options={[...chainFormChoice.options]}\n placeholder=\"選擇人員選擇欄位\"\n value={chainFormChoice.selected ?? undefined}\n />\n </BPMFormField>\n ) : null}\n {chainStageChoice ? (\n <BPMFormField\n hintText={\n chainStageChoice.problems.length > 0\n ? chainStageChoice.problems.join(';')\n : ORG_MANAGER_CHAIN_STAGE_HINT\n }\n label=\"關卡\"\n name=\"orgManagerChainStartNodeIds\"\n required\n >\n <Select\n clearable\n mode=\"multiple\"\n onChange={(options): void =>\n updateUserTaskResolver(\n withOrgManagerChainStartNodeIds(\n resolver,\n options.map((option) => option.id),\n ),\n )\n }\n options={[...chainStageChoice.options]}\n overflowStrategy=\"wrap\"\n placeholder=\"選擇前面的簽核關卡\"\n value={[...chainStageChoice.selected]}\n />\n </BPMFormField>\n ) : null}\n {chainStartLevelChoice ? (\n <BPMFormField\n hintText={\n chainStartLevelProblem ??\n (chainStartLevelChoice.invalid\n ? '原本儲存的起始職等無效,請重新選擇;發布前必須修正。'\n : START_POSITION_LEVEL_HINT)\n }\n label=\"從職等幾開始簽\"\n name=\"startPositionLevel\"\n >\n <Select\n clearable={false}\n onChange={(option): void => {\n const next = readOrgManagerChainStartLevelPick(\n resolver,\n option?.id ?? null,\n );\n\n if (next) {\n updateUserTaskResolver(next);\n }\n }}\n options={[...chainStartLevelChoice.options]}\n value={chainStartLevelChoice.selected}\n />\n </BPMFormField>\n ) : null}\n </>\n ) : null}\n {editorState.mode === 'ORG_UNIT_MANAGER' ? (\n <>\n <BPMFormField\n hintText=\"固定組織:每張單都找同一個組織的主管;表單欄位:找申請人在表單上選的組織的主管。\"\n label=\"組織\"\n name=\"orgUnitSource\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void => {\n if (!option || option.id === editorState.orgSource) {\n return;\n }\n\n updateUserTaskResolver(\n buildApproverResolver(\n withOrgUnitSource(\n editorState,\n option.id === 'FORM_FIELD' ? 'FORM_FIELD' : 'FIXED',\n ),\n ),\n );\n }}\n options={[...ORG_UNIT_SOURCE_OPTIONS]}\n value={readSelectOption(\n ORG_UNIT_SOURCE_OPTIONS,\n editorState.orgSource,\n )}\n />\n </BPMFormField>\n {editorState.orgSource === 'FIXED' ? (\n <BPMFormField\n hintText=\"依指定組織或其上層的主管解析規則決定簽核人。\"\n label=\"指定組織\"\n name=\"orgUnitId\"\n required\n >\n <OrgUnitPicker\n name=\"orgUnitId\"\n onChange={(option): void =>\n updateUserTaskResolver(\n buildApproverResolver({\n ...editorState,\n orgUnitId: option?.id ?? '',\n }),\n )\n }\n orgUnits={orgUnits}\n placeholder=\"選擇組織\"\n value={selectedManagerOrgUnit}\n />\n </BPMFormField>\n ) : (\n <BPMFormField\n hintText={\n orgFieldChoice?.problem ??\n '依申請人送出表單時在該欄位選的組織,找該組織的主管。'\n }\n label=\"表單欄位\"\n name=\"approverOrgFormPath\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskResolver(\n buildApproverResolver({\n ...editorState,\n formPath: option?.id ?? '',\n }),\n )\n }\n options={[...(orgFieldChoice?.options ?? [])]}\n placeholder=\"選擇組織選擇欄位\"\n value={orgFieldChoice?.selected ?? undefined}\n />\n </BPMFormField>\n )}\n </>\n ) : null}\n {editorState.mode === 'NODE_ACTOR' ? (\n <>\n <BPMFormField\n hintText={\n nodeActorChoice && nodeActorChoice.problems.length > 0\n ? nodeActorChoice.problems.join(';')\n : NODE_ACTOR_STAGE_HINT\n }\n label=\"關卡\"\n name=\"approverNodeIds\"\n required\n >\n <Select\n clearable\n mode=\"multiple\"\n onChange={(options): void =>\n updateUserTaskResolver(\n buildApproverResolver({\n ...editorState,\n nodeIds: options.map((option) => option.id),\n }),\n )\n }\n options={[...(nodeActorChoice?.options ?? [])]}\n overflowStrategy=\"wrap\"\n placeholder=\"選擇前面的簽核關卡\"\n value={[...(nodeActorChoice?.selected ?? [])]}\n />\n </BPMFormField>\n {renderApproverSubjectField()}\n </>\n ) : null}\n {resolver.type === 'ORG_UNIT_MEMBER' ||\n resolver.type === 'ORG_UNIT_POSITION' ? (\n <BPMFormField\n hintText=\"依指定組織目前有效會員歸屬建立候選簽核人。\"\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 : {\n includeDescendants: resolver.includeDescendants,\n orgUnitId: option?.id ?? '',\n positionId: '',\n type: 'ORG_UNIT_POSITION',\n },\n )\n }\n orgUnits={orgUnits}\n placeholder=\"選擇組織\"\n value={selectedOrgUnit}\n />\n </BPMFormField>\n ) : null}\n {managerRule !== null ? (\n <>\n {managerRule.showPreferClosestOrgUnit ? (\n <BPMFormField\n hintText=\"開啟後只取離該員最近一層的主管規則;掛在上層單位、涵蓋範圍較大的規則不會再一併加入簽核人。\"\n label=\"只取最近一層主管\"\n name=\"preferClosestOrgUnit\"\n >\n <Toggle\n checked={managerRule.preferClosestOrgUnit}\n inputProps={{\n id: 'preferClosestOrgUnit',\n name: 'preferClosestOrgUnit',\n }}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskResolver(\n withPreferClosestOrgUnit(resolver, event.target.checked),\n )\n }\n />\n </BPMFormField>\n ) : null}\n <BPMFormField\n hintText={\n unsupportedFallbackType !== null\n ? '此改派設定來自較新版本的 BPMCore,本版本無法執行也無法編輯;請升級後再編輯。這裡選擇其他模式會覆寫原設定。'\n : resolver.type === 'ORG_MANAGER_CHAIN'\n ? readOrgManagerChainFallbackHint(resolver)\n : '預設會停止流程並提示;若設定固定人,找不到主管時會改派給該會員。'\n }\n label=\"無主管時\"\n name=\"approverFallbackMode\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void => {\n // The unsupported label is display-only; leave the saved\n // definition untouched.\n if (option?.id === 'UNSUPPORTED') {\n return;\n }\n\n updateUserTaskResolver(\n updateApproverResolverFallback(\n resolver,\n readApproverFallbackModeDraft(option?.id ?? null),\n ),\n );\n }}\n options={[...approverFallbackModeOptions]}\n value={\n unsupportedFallbackType !== null\n ? APPROVER_FALLBACK_UNSUPPORTED_OPTION\n : readSelectOption(\n APPROVER_FALLBACK_MODE_OPTIONS,\n fallback.type,\n )\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 // Clear synchronously so the window between opening\n // and the fetch landing never shows a different\n // node's stale results.\n setMemberSearchResults([]);\n void handleSearchMembers('');\n }\n }}\n options={[\n // The fallback member is pre-fetched by id on load (see\n // `readApproverResolverMemberIds`), so its entry is a\n // real profile rather than a sentinel. It is still\n // merged in — and still second, so a fresh search hit\n // wins the dedupe — so that it stays selectable when the\n // current search does not happen to return it.\n ...mergeMemberOptions(\n memberSearchResults,\n fallbackMember ? [fallbackMember] : [],\n ),\n ]}\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 inputProps={{\n id: 'allowInitiatorSelfApproval',\n name: 'allowInitiatorSelfApproval',\n }}\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 {fallback.type === 'POSITION' ? (\n <>\n <BPMFormField\n hintText=\"指派給目前有效歸屬中擁有此職位的會員;主要歸屬優先。多人時全部成為簽核人,依上方的決策政策處理。\"\n label=\"改派職位\"\n name=\"approverFallbackPositionId\"\n required\n >\n <PositionPicker\n name=\"approverFallbackPositionId\"\n onChange={(option): void =>\n updateUserTaskResolver(\n updateApproverResolverFallback(resolver, {\n allowInitiatorSelfApproval:\n fallback.allowInitiatorSelfApproval,\n positionId: option?.id ?? '',\n type: 'POSITION',\n }),\n )\n }\n placeholder=\"選擇職位\"\n positions={positions}\n value={fallbackPosition}\n />\n </BPMFormField>\n <BPMFormField\n hintText=\"預設禁止申請人簽自己的案件;只有此流程允許自簽時才開啟。\"\n label=\"允許自簽\"\n name=\"allowInitiatorSelfApproval\"\n >\n <Toggle\n checked={Boolean(fallback.allowInitiatorSelfApproval)}\n inputProps={{\n id: 'allowInitiatorSelfApproval',\n name: 'allowInitiatorSelfApproval',\n }}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskResolver(\n updateApproverResolverFallback(resolver, {\n allowInitiatorSelfApproval: event.target.checked,\n positionId: fallback.positionId,\n type: 'POSITION',\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 inputProps={{\n id: 'includeDescendants',\n name: 'includeDescendants',\n }}\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 orgPositionPicker.isInactive\n ? ORG_POSITION_INACTIVE_HINT\n : '只納入指定組織範圍內擁有此職位的有效會員。'\n }\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={orgPositionPicker.options}\n value={selectedPosition}\n />\n </BPMFormField>\n ) : null}\n <BPMFormField\n hintText=\"決定這一關要幾位簽核者同意才會通過;單人簽核與任一人同意的效果完全相同,皆為其中一人同意即通過。\"\n label=\"決策方式\"\n name=\"decisionPolicy\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskDecisionPolicy(\n readDecisionPolicyFromOptionId(\n option?.id ?? null,\n node.data.decisionPolicy,\n ),\n )\n }\n options={[\n // A chain needs every manager to sign, so only the policies the\n // validator accepts are offered; a stored one stays readable\n // through `readDecisionPolicyOption`.\n ...DECISION_POLICY_OPTIONS.filter(\n (option) =>\n resolver.type !== 'ORG_MANAGER_CHAIN' ||\n option.id === 'SEQUENTIAL' ||\n option.id === 'PARALLEL_ALL',\n ),\n ]}\n value={readDecisionPolicyOption(decisionPolicyType)}\n />\n </BPMFormField>\n {decisionPolicyType === 'QUORUM' ? (\n <>\n <BPMFormField\n label=\"門檻計算方式\"\n name=\"quorumThresholdType\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskDecisionPolicy({\n threshold: quorum.threshold,\n thresholdType: readQuorumThresholdType(option?.id ?? null),\n type: 'QUORUM',\n })\n }\n options={[...QUORUM_THRESHOLD_TYPE_OPTIONS]}\n value={readSelectOption(\n QUORUM_THRESHOLD_TYPE_OPTIONS,\n quorum.thresholdType,\n )}\n />\n </BPMFormField>\n <BPMFormField\n hintText={\n quorum.thresholdType === 'PERCENTAGE'\n ? '達到簽核者總數的這個百分比即通過,換算人數時無條件進位;超過 100 的輸入會自動夾至 100。'\n : '達到這個同意人數即通過;門檻超過實際簽核者人數時,這一關將永遠無法通過,請勿設定超過實際簽核者人數。'\n }\n label={\n quorum.thresholdType === 'PERCENTAGE'\n ? '門檻百分比'\n : '門檻人數'\n }\n name=\"quorumThreshold\"\n required\n >\n <Input\n id=\"quorumThreshold\"\n inputProps={\n quorum.thresholdType === 'PERCENTAGE'\n ? { max: 100, min: 1 }\n : { min: 1 }\n }\n inputType=\"number\"\n name=\"quorumThreshold\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskDecisionPolicy({\n threshold: composeQuorumThreshold(\n Number(event.target.value),\n quorum.thresholdType,\n ),\n thresholdType: quorum.thresholdType,\n type: 'QUORUM',\n })\n }\n value={String(quorum.threshold)}\n variant=\"base\"\n />\n </BPMFormField>\n </>\n ) : null}\n {node.data.returnBehavior.allowReturn ? (\n <BPMFormField\n hintText=\"簽核者按下退回時,單子要回到哪裡。選「由簽核者選擇」時,可以退回申請人,或這一關之前任一個簽核節點。\"\n label=\"可退回到\"\n name=\"returnAllowedTargets\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskReturnAllowedTargets(\n readReturnAllowedTargets(option?.id ?? null),\n )\n }\n options={[...RETURN_ALLOWED_TARGETS_OPTIONS]}\n value={readSelectOption(\n RETURN_ALLOWED_TARGETS_OPTIONS,\n node.data.returnBehavior.allowedTargets,\n )}\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 {node.data.returnBehavior.allowReturn ? (\n <BPMFormField\n hintText=\"開啟後,簽核者按下退回時必須填寫意見,未填寫會被擋下。\"\n label=\"退回時意見必填\"\n name=\"returnRequireComment\"\n >\n <Toggle\n checked={node.data.returnBehavior.requireComment === true}\n // FormField renders `<label htmlFor={name}>`, so the control needs\n // the matching id for the label to be clickable.\n inputProps={{\n id: 'returnRequireComment',\n name: 'returnRequireComment',\n }}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskReturnRequireComment(event.target.checked)\n }\n />\n </BPMFormField>\n ) : null}\n <BPMFormField\n hintText=\"開啟後,簽核者按下同意時必須填寫意見,未填寫會被擋下;逾時自動同意不受影響。\"\n label=\"核准時意見必填\"\n name=\"approvalRequireComment\"\n >\n <Toggle\n checked={node.data.requireApprovalComment === true}\n // FormField renders `<label htmlFor={name}>`, so the control needs\n // the matching id for the label to be clickable.\n inputProps={{\n id: 'approvalRequireComment',\n name: 'approvalRequireComment',\n }}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskRequireApprovalComment(event.target.checked)\n }\n />\n </BPMFormField>\n <BPMFormField\n hintText=\"開啟後可設定簽核期限,逾時將依下方設定處理。\"\n label=\"啟用時效\"\n name=\"slaEnabled\"\n >\n <Toggle\n checked={Boolean(sla)}\n inputProps={{ id: 'slaEnabled', name: 'slaEnabled' }}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskSla(\n event.target.checked ? DEFAULT_SLA_CONFIG : null,\n )\n }\n />\n </BPMFormField>\n {sla && !slaDurationParts ? (\n <BPMFormField\n hintText=\"此期限混用了日與時,無法在表單中編輯。請改以單一單位設定,或透過 API 維護。\"\n label=\"時效期限\"\n name=\"slaDurationRaw\"\n >\n <Input disabled value={sla.duration} variant=\"base\" />\n </BPMFormField>\n ) : null}\n {sla && slaDurationParts ? (\n <>\n <BPMFormField label=\"時效期限\" name=\"slaDurationValue\" required>\n <Input\n id=\"slaDurationValue\"\n inputProps={{ min: 1 }}\n inputType=\"number\"\n name=\"slaDurationValue\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskSla(\n withSlaDuration(sla, {\n unit: slaDurationUnit,\n value: Number(event.target.value),\n }),\n )\n }\n value={String(slaDurationParts.value)}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"期限單位\" name=\"slaDurationUnit\" required>\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskSla(\n withSlaDuration(sla, {\n unit: readSlaDurationUnit(option?.id ?? null),\n value: slaDurationParts.value,\n }),\n )\n }\n options={[...SLA_DURATION_UNIT_OPTIONS]}\n value={readSelectOption(\n SLA_DURATION_UNIT_OPTIONS,\n slaDurationUnit,\n )}\n />\n </BPMFormField>\n </>\n ) : null}\n {sla && slaDurationUnit === 'DAY' ? (\n <BPMFormField\n hintText=\"工作日會跳過週末與行事曆上的假日,補班日仍計為工作日;行事曆由系統管理者設定。\"\n label=\"計算方式\"\n name=\"slaCalendar\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskSla({\n ...sla,\n calendar: readSlaCalendarMode(option?.id ?? null),\n })\n }\n options={[...SLA_CALENDAR_MODE_OPTIONS]}\n value={readSelectOption(\n SLA_CALENDAR_MODE_OPTIONS,\n sla.calendar ?? 'CALENDAR',\n )}\n />\n </BPMFormField>\n ) : null}\n {sla ? (\n <BPMFormField label=\"逾時處理\" name=\"slaOnTimeout\" required>\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskSla(\n withSlaTimeoutAction(\n sla,\n readSlaTimeoutAction(option?.id ?? null),\n ),\n )\n }\n options={[...SLA_TIMEOUT_ACTION_OPTIONS]}\n value={readSelectOption(\n SLA_TIMEOUT_ACTION_OPTIONS,\n sla.onTimeout,\n )}\n />\n </BPMFormField>\n ) : null}\n {sla?.onTimeout === 'ESCALATE' ? (\n <BPMFormField\n hintText=\"逾時後改派給簽核者的上層主管,只會升級一次。\"\n label=\"升級層級\"\n name=\"slaEscalateLevelsUp\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskSla({\n ...sla,\n escalateLevelsUp: readManagerLevelOptionById(\n option?.id ?? null,\n ).value,\n })\n }\n options={[...MANAGER_LEVEL_OPTIONS]}\n value={slaEscalateLevel}\n />\n </BPMFormField>\n ) : null}\n {sla ? (\n <BPMFormField\n hintText=\"在期限到達前先送出一次提醒。\"\n label=\"預警提醒\"\n name=\"slaWarningAt\"\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskSla(\n withSlaWarningAt(\n sla,\n readSlaWarningAtOptionById(option?.id ?? null).value,\n ),\n )\n }\n options={[...SLA_WARNING_AT_OPTIONS]}\n value={slaWarningAtOption}\n />\n </BPMFormField>\n ) : null}\n <BPMFormField\n hintText=\"關閉後,簽核者在此關卡看不到「拒絕」按鈕。\"\n label=\"允許拒絕\"\n name=\"allowReject\"\n >\n <Toggle\n checked={node.data.allowReject}\n inputProps={{ id: 'allowReject', name: 'allowReject' }}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskOptions({ allowReject: event.target.checked })\n }\n />\n </BPMFormField>\n <BPMFormField\n hintText=\"關閉後,簽核者無法把此關卡的任務轉派給其他人。\"\n label=\"允許轉派\"\n name=\"allowTransfer\"\n >\n <Toggle\n checked={node.data.allowTransfer}\n inputProps={{ id: 'allowTransfer', name: 'allowTransfer' }}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskOptions({ allowTransfer: event.target.checked })\n }\n />\n </BPMFormField>\n <BPMFormField\n hintText=\"開啟後,簽核者可在此關卡臨時加入其他簽核人;會簽為平行處理,加簽則需等加入者簽完才往下。\"\n label=\"允許加簽\"\n name=\"allowAddSigner\"\n >\n <Toggle\n checked={node.data.allowAddSigner}\n inputProps={{ id: 'allowAddSigner', name: 'allowAddSigner' }}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskOptions({ allowAddSigner: event.target.checked })\n }\n />\n </BPMFormField>\n <BPMFormField\n hintText=\"開啟後,申請人本人(含其代理人)不會成為此關的簽核人,也不能被轉簽或加簽到此關。\"\n label=\"申請人不可簽核自己的單\"\n name=\"excludeInitiator\"\n >\n <Toggle\n checked={Boolean(excludeInitiator)}\n inputProps={{ id: 'excludeInitiator', name: 'excludeInitiator' }}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskExcludeInitiator(\n event.target.checked ? DEFAULT_EXCLUDE_INITIATOR_CONFIG : null,\n )\n }\n />\n </BPMFormField>\n {excludeInitiator ? (\n <BPMFormField\n label=\"排除後沒有簽核人時\"\n name=\"excludeInitiatorWhenEmpty\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskExcludeInitiator({\n whenEmpty:\n readSelectOption(\n EXCLUDE_INITIATOR_WHEN_EMPTY_OPTIONS,\n option?.id ?? null,\n )?.id ?? DEFAULT_EXCLUDE_INITIATOR_CONFIG.whenEmpty,\n })\n }\n options={[...EXCLUDE_INITIATOR_WHEN_EMPTY_OPTIONS]}\n value={readSelectOption(\n EXCLUDE_INITIATOR_WHEN_EMPTY_OPTIONS,\n excludeInitiator.whenEmpty,\n )}\n />\n </BPMFormField>\n ) : null}\n <BPMFormField\n hintText=\"開啟後,實際簽核過所選前面關卡的人(含其代理人)不會成為此關的簽核人,也不能被轉簽或加簽到此關。例:信管審核與會計審核不能是同一人。臨時加簽、會簽的同意者不在此限。\"\n label=\"不可與前面關卡同一人\"\n name=\"excludeNodeActors\"\n >\n <Toggle\n checked={Boolean(excludeNodeActors)}\n inputProps={{\n id: 'excludeNodeActors',\n name: 'excludeNodeActors',\n }}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateUserTaskExcludeNodeActors(\n event.target.checked ? DEFAULT_EXCLUDE_NODE_ACTORS_CONFIG : null,\n )\n }\n />\n </BPMFormField>\n {excludeNodeActors && excludeNodeActorChoice ? (\n <>\n <BPMFormField\n hintText={\n excludeNodeActorChoice.problems.length > 0\n ? excludeNodeActorChoice.problems.join(';')\n : EXCLUDE_NODE_ACTORS_STAGE_HINT\n }\n label=\"不能與以下關卡同一人\"\n name=\"excludeNodeActorsNodeIds\"\n required\n >\n <Select\n clearable\n mode=\"multiple\"\n onChange={(options): void =>\n updateUserTaskExcludeNodeActors({\n ...excludeNodeActors,\n nodeIds: options.map((option) => option.id),\n })\n }\n options={[...excludeNodeActorChoice.options]}\n overflowStrategy=\"wrap\"\n placeholder=\"選擇前面的簽核關卡\"\n value={[...excludeNodeActorChoice.selected]}\n />\n </BPMFormField>\n <BPMFormField\n label=\"排除後沒有簽核人時\"\n name=\"excludeNodeActorsWhenEmpty\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateUserTaskExcludeNodeActors({\n ...excludeNodeActors,\n whenEmpty:\n readSelectOption(\n EXCLUDE_INITIATOR_WHEN_EMPTY_OPTIONS,\n option?.id ?? null,\n )?.id ?? DEFAULT_EXCLUDE_NODE_ACTORS_CONFIG.whenEmpty,\n })\n }\n options={[...EXCLUDE_INITIATOR_WHEN_EMPTY_OPTIONS]}\n value={readSelectOption(\n EXCLUDE_INITIATOR_WHEN_EMPTY_OPTIONS,\n excludeNodeActors.whenEmpty,\n )}\n />\n </BPMFormField>\n </>\n ) : null}\n <FieldAccessNodeSection\n definition={workflowDefinition}\n language={language}\n node={node}\n onOpenMatrix={(): void => setFieldAccessMatrixOpen(true)}\n onRemoveLegacy={(): void => {\n controller.dispatch({\n nodeId: node.id,\n type: 'removeLegacyFieldPermissions',\n });\n }}\n openDisabledReason={\n webhookFormSchema === null ? FIELD_ACCESS_NO_FORM_REASON : null\n }\n />\n </>\n );\n }\n\n function renderServiceTaskPanel(\n node: Extract<WorkflowNode, { type: 'serviceTask' }>,\n ): ReactElement {\n const action = node.data.action;\n const recipients = readNotifyRecipients(action);\n const sourceChoice = readNotifyRecipientSourceChoice(recipients);\n // A source this panel does not edit shows what it currently resolves to,\n // so the author can read it without opening the template JSON.\n const sourceHint =\n sourceChoice.readOnly && sourceChoice.hint\n ? `目前知會對象為「${readApproverResolverSummary(\n recipients,\n memberOptions,\n orgUnits,\n positions,\n webhookFormSchema,\n )}${recipients.type === 'EXPRESSION' ? `:${recipients.expression}` : ''}」。${sourceChoice.hint}`\n : sourceChoice.hint;\n const selectedMembers = readServiceTaskMemberIds(action).map((memberId) =>\n readMemberSelectOption(memberOptions, memberId),\n );\n const selectedRecipientOrgUnit =\n recipients.type === 'ORG_UNIT_MEMBER' ||\n recipients.type === 'ORG_UNIT_POSITION' ||\n recipients.type === 'ORG_UNIT_MANAGER'\n ? readSelectedOrgUnitOption(orgUnits, recipients.orgUnitId)\n : null;\n const selectedRecipientPosition =\n recipients.type === 'POSITION' || recipients.type === 'ORG_UNIT_POSITION'\n ? readSelectedPositionOption(positions, recipients.positionId)\n : null;\n // The picker offers only positions someone holds through an effective\n // membership, the same set the engine can resolve. A stored position that\n // is no longer held stays selected, with a warning, so the author sees it.\n const activeRecipientPositionIds = readActivePositionIds(\n memberships,\n organizationToday,\n );\n const isRecipientPositionInactive =\n recipients.type === 'POSITION' &&\n Boolean(recipients.positionId) &&\n !activeRecipientPositionIds.has(recipients.positionId);\n const recipientPositionOptions = positions.filter(\n (position) =>\n activeRecipientPositionIds.has(position.id) ||\n (isRecipientPositionInactive && position.id === recipients.positionId),\n );\n const recipientOrgScopedPositions =\n recipients.type === 'ORG_UNIT_POSITION'\n ? readOrgScopedPositions({\n date: organizationToday,\n includeDescendants: Boolean(recipients.includeDescendants),\n memberships,\n orgUnitId: recipients.orgUnitId,\n orgUnits,\n positions,\n })\n : [];\n const recipientOrgPositionPicker = readOrgPositionPickerState({\n orgUnitId:\n recipients.type === 'ORG_UNIT_POSITION' ? recipients.orgUnitId : '',\n positionId:\n recipients.type === 'ORG_UNIT_POSITION' ? recipients.positionId : '',\n positions,\n scopedPositions: recipientOrgScopedPositions,\n });\n const recipientFormChoice =\n recipients.type === 'DYNAMIC_FORM'\n ? readDynamicFormFieldChoice(webhookFormSchema, recipients.formPath)\n : null;\n\n // Only the recipients change: channels, template and webhooks belong to\n // the same action and must survive a source or target being edited.\n function updateNotifyRecipients(next: ApproverResolver): void {\n updateServiceAction(withNotifyRecipients(action, next));\n }\n\n function updateNotifyWebhooks(\n webhooks: readonly NotifyWebhookTarget[],\n ): void {\n if (action.type === 'NOTIFY') {\n updateServiceAction({ ...action, webhooks });\n }\n }\n\n // Phase 23 P4: a SET_FORM_FIELD node gets its own editor, so the NOTIFY\n // pickers below can never rewrite its action into a notification.\n const actionTypePicker = (\n <BPMFormField label=\"系統動作\" name=\"serviceActionType\" required>\n <Select\n clearable={false}\n onChange={(option): void => {\n if (!option || option.id === action.type) {\n return;\n }\n\n updateServiceAction(\n option.id === 'SET_FORM_FIELD'\n ? { fieldPath: '', type: 'SET_FORM_FIELD', value: '' }\n : {\n channels: ['IN_APP'],\n recipients: { memberIds: [], type: 'DIRECT' },\n type: 'NOTIFY',\n },\n );\n }}\n options={[...SERVICE_ACTION_TYPE_OPTIONS]}\n value={readSelectOption(SERVICE_ACTION_TYPE_OPTIONS, action.type)}\n />\n </BPMFormField>\n );\n\n if (action.type === 'SET_FORM_FIELD') {\n const targetFieldOptions = readConditionFieldOptions(\n selectedFormVersionOption?.schema ?? null,\n );\n const targetFieldKey = action.fieldPath.replace(/^form\\./u, '');\n\n return (\n <>\n {actionTypePicker}\n <BPMFormField label=\"寫入欄位\" name=\"serviceFieldPath\" required>\n <Select\n clearable={false}\n onChange={(option): void =>\n updateServiceAction({\n ...action,\n fieldPath: option?.id ?? '',\n })\n }\n options={[...targetFieldOptions]}\n placeholder={\n selectedFormVersionOption ? '選擇欄位' : '請先綁定表單版本'\n }\n value={readSelectOption(\n targetFieldOptions,\n targetFieldKey || null,\n )}\n />\n </BPMFormField>\n <ExpressionField\n dialect={expressionDialect}\n evaluable\n formDefinitionVersionId={formDefinitionVersionId}\n hintText=\"運算結果會寫進上面的欄位;畫面上一律以文字顯示。\"\n label=\"寫入的值\"\n name=\"serviceFieldValue\"\n onChange={(value): void =>\n updateServiceAction({ ...action, value })\n }\n required\n targetFieldKey={targetFieldKey || null}\n usagePoint=\"SERVICE_FORM_FIELD_VALUE\"\n value={action.value}\n />\n </>\n );\n }\n\n return (\n <>\n {actionTypePicker}\n <BPMFormField\n hintText={sourceHint ?? undefined}\n label=\"知會對象來源\"\n name=\"notifyRecipientType\"\n >\n <Select\n clearable={false}\n onChange={(option): void => {\n // Re-picking the source already stored, or the read-only entry\n // of a source this panel does not edit, writes nothing.\n const next = readNotifyRecipientSourcePick(\n recipients,\n option?.id ?? null,\n positions,\n );\n\n if (next) {\n updateNotifyRecipients(next);\n }\n }}\n options={[...sourceChoice.options]}\n value={sourceChoice.selected}\n />\n </BPMFormField>\n {recipients.type === 'DIRECT' ? (\n <BPMFormField\n hintText={\n action.type === 'NOTIFY'\n ? '可只設定 Webhook,不指定知會對象。'\n : undefined\n }\n label=\"知會對象\"\n name=\"notifyMemberIds\"\n >\n <AutoComplete\n asyncData\n disabledOptionsFilter\n emptyText=\"沒有符合的成員\"\n loading={memberLoading}\n loadingText=\"搜尋成員中...\"\n mode=\"multiple\"\n onChange={(options): void =>\n updateNotifyRecipients({\n memberIds: options.map((option) => option.id),\n type: 'DIRECT',\n })\n }\n onSearch={handleSearchMembers}\n onVisibilityChange={(open): void => {\n if (open) {\n // Clear synchronously so the window between opening and the\n // fetch landing never shows a different node's stale results.\n setMemberSearchResults([]);\n void handleSearchMembers('');\n }\n }}\n // As in the approver picker: merged so an already-picked member can\n // still be unticked from the dropdown, which AutoComplete resolves\n // through `options`.\n options={[\n ...mergeMemberOptions(selectedMembers, memberSearchResults),\n ]}\n overflowStrategy=\"wrap\"\n placeholder=\"搜尋姓名或信箱\"\n searchDebounceTime={300}\n value={[...selectedMembers]}\n />\n </BPMFormField>\n ) : null}\n {recipients.type === 'DYNAMIC_FORM' ? (\n <BPMFormField\n hintText={\n recipientFormChoice?.problem ??\n '知會對象取自申請人送出表單時在該欄位選的人員。'\n }\n label=\"表單欄位\"\n name=\"notifyFormPath\"\n required\n >\n <Select\n clearable={false}\n onChange={(option): void =>\n updateNotifyRecipients(\n withNotifyFormPath(recipients, option?.id ?? ''),\n )\n }\n options={[...(recipientFormChoice?.options ?? [])]}\n placeholder=\"選擇人員選擇欄位\"\n value={recipientFormChoice?.selected ?? undefined}\n />\n </BPMFormField>\n ) : null}\n {recipients.type === 'ORG_UNIT_MEMBER' ||\n recipients.type === 'ORG_UNIT_POSITION' ||\n recipients.type === 'ORG_UNIT_MANAGER' ? (\n <BPMFormField\n hintText={\n recipients.type === 'ORG_UNIT_MANAGER'\n ? '依指定組織或其上層的主管解析規則決定知會對象;組織沒有主管、也沒有設定替代人時,流程走到這個知會節點會送出失敗。'\n : '依指定組織目前有效會員歸屬決定知會對象。'\n }\n label=\"組織\"\n name=\"notifyOrgUnitId\"\n required\n >\n <OrgUnitPicker\n name=\"notifyOrgUnitId\"\n onChange={(option): void =>\n updateNotifyRecipients(\n withNotifyOrgUnit(recipients, option?.id ?? ''),\n )\n }\n orgUnits={orgUnits}\n placeholder=\"選擇組織\"\n value={selectedRecipientOrgUnit}\n />\n </BPMFormField>\n ) : null}\n {recipients.type === 'ORG_UNIT_MEMBER' ||\n recipients.type === 'ORG_UNIT_POSITION' ? (\n <BPMFormField label=\"包含下層\" name=\"notifyIncludeDescendants\">\n <Toggle\n checked={Boolean(recipients.includeDescendants)}\n inputProps={{\n id: 'notifyIncludeDescendants',\n name: 'notifyIncludeDescendants',\n }}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateNotifyRecipients(\n withNotifyIncludeDescendants(\n recipients,\n event.target.checked,\n ),\n )\n }\n />\n </BPMFormField>\n ) : null}\n {recipients.type === 'POSITION' ? (\n <BPMFormField\n hintText={\n isRecipientPositionInactive\n ? '這個職位目前沒有任何有效歸屬的會員,送出時會找不到收件人,請改選其他職位。'\n : '通知目前有效歸屬中擁有此職位的會員。'\n }\n label=\"職位\"\n name=\"notifyPositionId\"\n required\n >\n <PositionPicker\n name=\"notifyPositionId\"\n onChange={(option): void =>\n updateNotifyRecipients(\n withNotifyPosition(recipients, option?.id ?? ''),\n )\n }\n placeholder=\"選擇職位\"\n positions={recipientPositionOptions}\n value={selectedRecipientPosition}\n />\n </BPMFormField>\n ) : null}\n {recipients.type === 'ORG_UNIT_POSITION' ? (\n <BPMFormField\n hintText={\n recipientOrgPositionPicker.isInactive\n ? ORG_POSITION_INACTIVE_HINT\n : '只通知指定組織範圍內擁有此職位的有效會員。'\n }\n label=\"職位\"\n name=\"notifyOrgUnitPositionId\"\n required\n >\n <PositionPicker\n disabled={!recipients.orgUnitId.trim()}\n name=\"notifyOrgUnitPositionId\"\n onChange={(option): void =>\n updateNotifyRecipients(\n withNotifyPosition(recipients, option?.id ?? ''),\n )\n }\n placeholder={\n recipients.orgUnitId.trim() ? '選擇職位' : '請先選擇組織'\n }\n positions={recipientOrgPositionPicker.options}\n value={selectedRecipientPosition}\n />\n </BPMFormField>\n ) : null}\n {action.type === 'NOTIFY' &&\n !isNotifyWebhookListEditable(action.webhooks) ? (\n <div style={FORM_STACK_STYLE}>\n <Typography color=\"text-warning\" variant=\"body\">\n 這個節點的 Webhook 設定格式錯誤,無法在此編輯。清除後可重新新增。\n </Typography>\n <div>\n <Button\n onClick={(): void => updateNotifyWebhooks([])}\n variant=\"destructive-secondary\"\n >\n 清除 Webhook 設定\n </Button>\n </div>\n </div>\n ) : null}\n {action.type === 'NOTIFY' &&\n isNotifyWebhookListEditable(action.webhooks) ? (\n <NotifyWebhookTargetsEditor\n catalog={webhookCatalog}\n catalogState={webhookCatalogState}\n formFields={webhookFormSchema?.fields ?? null}\n onChange={updateNotifyWebhooks}\n targets={readNotifyWebhookTargets(action)}\n />\n ) : null}\n </>\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 = readConditionOperatorOptionsForField(\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 const expressionCondition =\n !edge.data.isDefault &&\n (expressionEdgeId === edge.id || isWorkflowEdgeExpressionCondition(edge));\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 inputProps={{ 'aria-label': '其他情況走這條' }}\n label=\"其他情況走這條\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateSelectedEdgeDefault(edge.id, event.target.checked)\n }\n />\n {edge.data.isDefault ? null : (\n <Toggle\n checked={expressionCondition}\n // Mezzanine renders the label beside the switch, not as its\n // <label>, so the input needs its own accessible name.\n inputProps={{ 'aria-label': '進階:自訂運算式' }}\n label=\"進階:自訂運算式\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n if (event.target.checked) {\n setExpressionEdgeId(edge.id);\n updateWorkflowDefinitionDirectly((definition) =>\n setWorkflowEdgeExpressionCondition(\n definition,\n edge.id,\n edge.data.condition ?? '',\n ),\n );\n\n return;\n }\n\n setExpressionEdgeId(null);\n updateSelectedEdgeConditionState({\n edgeId: edge.id,\n fieldKey: null,\n operator: null,\n value: null,\n });\n }}\n />\n )}\n {expressionCondition ? (\n <ExpressionField\n dialect={expressionDialect}\n edgeSourceNodeType={readWorkflowEdgeSourceNodeType(\n workflowDefinition,\n edge.id,\n )}\n evaluable\n formDefinitionVersionId={formDefinitionVersionId}\n hintText=\"結構化條件(欄位+判斷+值)能表達時請優先使用;這裡的運算式由後端檢查。\"\n label=\"條件運算式\"\n name=\"edgeConditionExpression\"\n onChange={(condition): void =>\n updateWorkflowDefinitionDirectly((definition) =>\n setWorkflowEdgeExpressionCondition(\n definition,\n edge.id,\n condition,\n ),\n )\n }\n required\n usagePoint=\"FLOW_CONDITION\"\n value={edge.data.condition ?? ''}\n />\n ) : null}\n {edge.data.isDefault ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 其他條件都不符合時,流程會走這條線。\n </Typography>\n ) : expressionCondition ? null : (\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 {data.fieldAccessTag ? (\n <span>\n <Tag label={data.fieldAccessTag} readOnly size=\"minor\" />\n </span>\n ) : null}\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 formSchema: FormDefinitionSchema | null,\n nodes: readonly NodeNameRecord[],\n): FlowNode {\n const dimensions = readWorkflowNodeDimensions(node);\n\n return {\n data: {\n approverLines: readNodeApproverLines(\n node,\n memberOptions,\n orgUnits,\n positions,\n formSchema,\n ),\n approverSummary: readNodeApproverSummary(\n node,\n memberOptions,\n orgUnits,\n positions,\n formSchema,\n nodes,\n ),\n fieldAccessTag:\n node.type === 'userTask' ? readFieldAccessNodeTag(node) : null,\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 lineCount = readServiceTaskLineCount(node.data.action);\n\n return {\n height:\n FLOW_NODE_INITIAL_HEIGHT +\n (lineCount - 1) * FLOW_NODE_ADDITIONAL_LINE_HEIGHT,\n width: FLOW_NODE_INITIAL_WIDTH,\n };\n }\n\n return {\n height:\n FLOW_NODE_INITIAL_HEIGHT +\n (node.type === 'userTask' && readFieldAccessNodeTag(node) !== null\n ? FLOW_NODE_FIELD_ACCESS_TAG_HEIGHT\n : 0),\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 const withEdgeData = normalizeDesignerEdgeData(definition);\n const withoutAsyncNotifyEdges = removeAsyncNotifyOutgoingEdges(withEdgeData);\n\n return normalizeSingleIncomingTriggerModes(\n normalizeUserTaskPolicies(withoutAsyncNotifyEdges),\n );\n}\n\nfunction normalizeDesignerEdgeData(\n definition: WorkflowDefinition,\n): WorkflowDefinition {\n const edges = definition.edges.map((edge): WorkflowEdge => {\n const data = edge.data ?? {};\n\n return edge.data === data ? edge : { ...edge, data };\n });\n const hasEdgeChanges = edges.some(\n (edge, index) => edge !== definition.edges[index],\n );\n\n return hasEdgeChanges ? { ...definition, edges } : definition;\n}\n\nfunction normalizeUserTaskPolicies(\n definition: WorkflowDefinition,\n): WorkflowDefinition {\n const nodes = definition.nodes.map((node) => {\n if (node.type !== 'userTask') {\n return node;\n }\n\n const allowAddSigner = node.data.allowAddSigner ?? false;\n const allowReject = node.data.allowReject ?? true;\n const allowTransfer = node.data.allowTransfer ?? true;\n // The schema types `decisionPolicy` as required, but templates authored\n // before the field existed carry no such key at runtime (see\n // `readDecisionPolicyType`). Only the read side tolerated that until now,\n // so the field stayed permanently blank-but-required in the publish\n // validator (`decisionPolicy is required`). Write the same default here,\n // and only when it is actually missing — an already-set policy (whatever\n // its value) must not be touched.\n const decisionPolicyIsMissing = !node.data.decisionPolicy;\n\n if (\n node.data.allowAddSigner === allowAddSigner &&\n node.data.allowReject === allowReject &&\n node.data.allowTransfer === allowTransfer &&\n !decisionPolicyIsMissing\n ) {\n return node;\n }\n\n return {\n ...node,\n data: {\n ...node.data,\n allowAddSigner,\n allowReject,\n allowTransfer,\n decisionPolicy: node.data.decisionPolicy ?? { type: 'SINGLE' },\n },\n };\n });\n\n const hasNodeChanges = nodes.some(\n (node, index) => node !== definition.nodes[index],\n );\n\n return hasNodeChanges ? { ...definition, nodes } : definition;\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 // Phase 23 P4: a new template starts on cel-v2; an existing one keeps the\n // dialect it was saved with (no field means cel-legacy).\n return {\n edges: [],\n expressionDialect: 'cel-v2',\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 } | 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 readReturnAllowedTargets(\n value: string | null,\n): ReturnBehavior['allowedTargets'] {\n return value === 'PREVIOUS' || value === 'ANY' ? value : 'INITIATOR';\n}\n\nfunction readReturnResubmitStrategy(\n value: string | null,\n): ReturnResubmitStrategy {\n return value === 'FROM_RETURN_POINT' ? 'FROM_RETURN_POINT' : 'RESTART';\n}\n\nfunction readDecisionPolicyType(\n policy: DecisionPolicy | undefined,\n): DecisionPolicy['type'] {\n return policy?.type ?? 'SINGLE';\n}\n\nfunction readDecisionPolicyFromOptionId(\n id: string | null,\n current: DecisionPolicy | undefined,\n): DecisionPolicy {\n if (id === 'QUORUM') {\n // Re-picking the option the node already uses must not discard the\n // threshold the user typed.\n return current?.type === 'QUORUM'\n ? current\n : {\n threshold: DEFAULT_QUORUM_THRESHOLD,\n thresholdType: 'COUNT',\n type: 'QUORUM',\n };\n }\n\n if (id === 'PARALLEL_ALL' || id === 'PARALLEL_ANY' || id === 'SEQUENTIAL') {\n return { type: id };\n }\n\n return { type: 'SINGLE' };\n}\n\n/**\n * Reads the quorum controls' state out of a stored policy.\n *\n * `threshold` and `thresholdType` get the same tolerance the rest of this read\n * path already grants `type` (see `readDecisionPolicyType` /\n * `readDecisionPolicyOption`): the publish validator only checks\n * `decisionPolicy?.type`, so an API-authored template can store a bare\n * `{ type: 'QUORUM' }`. Trusting the declared types there would put\n * `String(undefined)` into the number input (rendering blank, with the field\n * silently unusable) and would write `thresholdType: undefined` straight back\n * into the policy on the next threshold keystroke.\n *\n * Only the *shape* is repaired here — a stored out-of-range value (e.g. a\n * `PERCENTAGE` threshold of 500 written before `composeQuorumThreshold` capped\n * it) is shown as-is, so the panel never displays a number that differs from\n * what is actually stored.\n */\nfunction readQuorumParts(policy: DecisionPolicy | undefined): Readonly<{\n threshold: number;\n thresholdType: 'COUNT' | 'PERCENTAGE';\n}> {\n if (policy?.type !== 'QUORUM') {\n return { threshold: DEFAULT_QUORUM_THRESHOLD, thresholdType: 'COUNT' };\n }\n\n return {\n threshold: Number.isFinite(policy.threshold)\n ? policy.threshold\n : DEFAULT_QUORUM_THRESHOLD,\n thresholdType: readQuorumThresholdType(policy.thresholdType ?? null),\n };\n}\n\nfunction readQuorumThresholdType(value: string | null): 'COUNT' | 'PERCENTAGE' {\n return value === 'PERCENTAGE' ? 'PERCENTAGE' : 'COUNT';\n}\n\nfunction readSlaDurationUnit(value: string | null): SlaDurationUnit {\n return value === 'HOUR' ? 'HOUR' : 'DAY';\n}\n\nfunction readSlaCalendarMode(value: string | null): SlaCalendarMode {\n return value === 'BUSINESS_DAY' ? 'BUSINESS_DAY' : 'CALENDAR';\n}\n\nfunction readSlaTimeoutAction(value: string | null): SlaConfig['onTimeout'] {\n return (\n SLA_TIMEOUT_ACTION_OPTIONS.find((option) => option.id === value)?.id ??\n 'REMIND'\n );\n}\n\nfunction readSlaWarningAtOption(\n value: number | null,\n): (typeof SLA_WARNING_AT_OPTIONS)[number] {\n return (\n SLA_WARNING_AT_OPTIONS.find((option) => option.value === value) ??\n SLA_WARNING_AT_OPTIONS[0]\n );\n}\n\nfunction readSlaWarningAtOptionById(\n id: string | null,\n): (typeof SLA_WARNING_AT_OPTIONS)[number] {\n return (\n SLA_WARNING_AT_OPTIONS.find((option) => option.id === id) ??\n SLA_WARNING_AT_OPTIONS[0]\n );\n}\n\n/**\n * Rewrites the SLA duration, dropping `BUSINESS_DAY` when the unit is no\n * longer days — a business calendar only advances whole days, so keeping the\n * mode on an hour-based SLA would claim a behaviour the engine does not apply.\n */\nfunction withSlaDuration(sla: SlaConfig, parts: SlaDurationParts): SlaConfig {\n const value = Number.isFinite(parts.value) ? Math.trunc(parts.value) : 1;\n const duration = composeSlaDuration({ unit: parts.unit, value });\n\n return {\n ...sla,\n calendar: parts.unit === 'DAY' ? (sla.calendar ?? 'CALENDAR') : 'CALENDAR',\n duration,\n };\n}\n\n/** Keeps `escalateLevelsUp` only while the timeout action is `ESCALATE`. */\nfunction withSlaTimeoutAction(\n sla: SlaConfig,\n onTimeout: SlaConfig['onTimeout'],\n): SlaConfig {\n return onTimeout === 'ESCALATE'\n ? { ...sla, escalateLevelsUp: sla.escalateLevelsUp ?? 1, onTimeout }\n : { ...omitSlaKey(sla, 'escalateLevelsUp'), onTimeout };\n}\n\nfunction withSlaWarningAt(sla: SlaConfig, warningAt: number | null): SlaConfig {\n return warningAt === null\n ? omitSlaKey(sla, 'warningAt')\n : { ...sla, warningAt };\n}\n\n/**\n * Drops an optional SLA key rather than storing `undefined`, keeping the saved\n * workflow definition JSON free of dead settings.\n */\nfunction omitSlaKey(\n sla: SlaConfig,\n key: 'escalateLevelsUp' | 'warningAt',\n): SlaConfig {\n return Object.fromEntries(\n Object.entries(sla).filter(([entryKey]) => entryKey !== key),\n ) as SlaConfig;\n}\n\nfunction readApproverFallbackMode(value: string | null): ApproverFallbackMode {\n if (value === 'DIRECT' || value === 'POSITION') {\n return value;\n }\n\n return 'NONE';\n}\n\n// Switching the mode to a fixed member or a position starts it empty, so the\n// user picks the target next; the self-approval flag starts off.\nfunction readApproverFallbackModeDraft(\n value: string | null,\n): ApproverResolverFallback {\n const mode = readApproverFallbackMode(value);\n\n if (mode === 'DIRECT') {\n return { memberId: '', type: 'DIRECT' };\n }\n\n if (mode === 'POSITION') {\n return { positionId: '', type: 'POSITION' };\n }\n\n return { type: 'NONE' };\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: readFormVersionLabel(option.formName, option.version),\n schema: option.schema,\n }));\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 readDryRunInitiatorMetadataSnapshot(\n memberId: string,\n memberships: readonly MembershipRecord[],\n today: string,\n): Readonly<Record<string, unknown>> {\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 && 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 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\n/**\n * Appends the ids not seen yet, and — the one case an existing entry is\n * overwritten — upgrades an unresolved placeholder once the real profile\n * arrives. Without that upgrade a single failed profile fetch pinned the\n * \"未知會員\" sentinel for the whole session: the id counts as \"seen\", so\n * `resolveWorkflowMemberOptions` never asks for it again and every later\n * search result for that member was discarded as a duplicate.\n *\n * A resolved entry is never replaced by another resolved one, so a stale\n * search response still cannot overwrite a fresher name.\n *\n * Returns `currentOptions` itself when the merge is a no-op. The effect that\n * drives `resolveWorkflowMemberOptions` lists `memberOptions` in its\n * dependencies, so handing back a fresh array of identical entries re-runs it,\n * which re-requests the same ids, which merges the same entries again. A\n * failing profile fetch would loop on the API forever; identity is what stops\n * it, not the contents.\n */\nfunction mergeMemberOptions(\n currentOptions: readonly MemberSelectOption[],\n nextOptions: readonly MemberSelectOption[],\n): readonly MemberSelectOption[] {\n const resolvedById = new Map(\n nextOptions\n .filter((option) => !option.unresolved)\n .map((option) => [option.memberId, option] as const),\n );\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 const upgradedOptions = currentOptions.map(\n (option) =>\n (option.unresolved ? resolvedById.get(option.memberId) : null) ?? option,\n );\n const changed =\n newOptions.length > 0 ||\n upgradedOptions.some((option, index) => option !== currentOptions[index]);\n\n return changed ? [...upgradedOptions, ...newOptions] : currentOptions;\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 readApproverResolverMemberIds(node.data.approverResolver);\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 formSchema: FormDefinitionSchema | null,\n nodes: readonly NodeNameRecord[],\n): string | null {\n if (node.type === 'userTask') {\n return readApproverResolverSummary(\n node.data.approverResolver,\n memberOptions,\n orgUnits,\n positions,\n formSchema,\n nodes,\n );\n }\n\n return null;\n}\n\nfunction readNodeApproverLines(\n node: WorkflowNode,\n memberOptions: readonly MemberSelectOption[],\n orgUnits: readonly OrgUnitRecord[],\n positions: readonly PositionRecord[],\n formSchema: FormDefinitionSchema | null,\n): readonly string[] | null {\n if (node.type !== 'serviceTask') {\n return null;\n }\n\n const action = node.data.action;\n const recipientLines =\n action.type === 'NOTIFY' && action.recipients.type !== 'DIRECT'\n ? [\n readApproverResolverSummary(\n action.recipients,\n memberOptions,\n orgUnits,\n positions,\n formSchema,\n ),\n ]\n : readServiceTaskMemberIds(action).map(\n (memberId) => readMemberSelectOption(memberOptions, memberId).name,\n );\n const webhookCount = readNotifyWebhookTargets(action).length;\n const lines = [\n ...recipientLines,\n ...(webhookCount ? [`Webhook ${webhookCount} 個`] : []),\n ];\n\n return lines.length ? lines : ['未指定知會對象'];\n}\n\n/** Must match the line count {@link readNodeApproverLines} produces. */\nfunction readServiceTaskLineCount(action: ServiceAction): number {\n const recipientLines =\n action.type === 'NOTIFY' && action.recipients.type !== 'DIRECT'\n ? 1\n : readServiceTaskMemberIds(action).length;\n const webhookLines = readNotifyWebhookTargets(action).length ? 1 : 0;\n\n return Math.max(1, recipientLines + webhookLines);\n}\n\nfunction readDryRunWebhookLabels(\n definition: WorkflowDefinition,\n nodeId: string,\n endpoints: readonly WorkflowWebhookEndpointRecord[],\n): readonly Readonly<{ key: string; label: string }>[] {\n const node = definition.nodes.find((candidate) => candidate.id === nodeId);\n\n return node?.type === 'serviceTask' &&\n node.data.action.type === 'NOTIFY' &&\n isNotifyWebhookListEditable(node.data.action.webhooks)\n ? readNotifyWebhookTargets(node.data.action).map((target) => ({\n key: target.id,\n label:\n findNotifyWebhookEndpoint(endpoints, target.endpoint)?.label ??\n readNotifyWebhookEndpointOptionId(target.endpoint),\n }))\n : [];\n}\n\nfunction formatMemberDisplayName(name: string, email: string): string {\n return formatMemberLabel(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 excludeInitiatorNode = definition.nodes.find(\n (node) =>\n node.type === 'userTask' &&\n Boolean(readExcludeInitiatorIssue(node.data.excludeInitiator)),\n );\n const excludeNodeActorsShapeIssue =\n definition.nodes\n .map((node) =>\n node.type === 'userTask'\n ? readExcludeNodeActorsShapeIssue(node.data.excludeNodeActors)\n : null,\n )\n .find((issue): issue is string => issue !== null) ?? null;\n // Shared with the backend lint and the AI toolset so a webhook-only or a\n // runtime-resolved (position, org unit, manager) NOTIFY node is judged the\n // same everywhere (ADR 18 P0).\n const notifyNodeIssue =\n definition.nodes\n .map((node) => readNotifyServiceTaskIssue(node))\n .find((issue): issue is string => issue !== null) ?? null;\n const incompleteConditionEdge = definition.edges.find(\n (edge) =>\n isExclusiveGatewaySourceEdge(edge, definition.nodes) &&\n !edge.data.isDefault &&\n !edge.data.condition,\n );\n const chainPolicyNode = definition.nodes.find(\n (node) =>\n node.type === 'userTask' &&\n isOrgManagerChainDecisionPolicyInvalid(\n node.data.approverResolver,\n node.data.decisionPolicy,\n ),\n );\n\n if (incompleteUserTaskNode && incompleteUserTaskNode.type === 'userTask') {\n return readApproverResolverIssue(\n incompleteUserTaskNode.data.approverResolver,\n );\n }\n\n if (chainPolicyNode && chainPolicyNode.type === 'userTask') {\n return `簽核節點「${chainPolicyNode.data.label}」使用「沿主管鏈簽核」時,決策方式必須是「依序簽核或全部同意」,否則任一位主管簽完就會結案。`;\n }\n\n if (excludeInitiatorNode && excludeInitiatorNode.type === 'userTask') {\n return readExcludeInitiatorIssue(\n excludeInitiatorNode.data.excludeInitiator,\n );\n }\n\n if (excludeNodeActorsShapeIssue) {\n return excludeNodeActorsShapeIssue;\n }\n\n if (notifyNodeIssue) {\n return notifyNodeIssue;\n }\n\n if (incompleteConditionEdge) {\n return '條件分流的每條輸出連線都需要先設定條件。';\n }\n\n return null;\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 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 (isFormStaticOptionFieldDefinition(field)) {\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"],"mappings":"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"}