@rytass/bpm-core-react 0.15.0 → 0.17.0

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 (230) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +54 -6
  3. package/dist/chunks/{FormBuilderView-CLg-JYmu.js → FormBuilderView-BYL42M0d.js} +13 -33
  4. package/dist/chunks/FormBuilderView-BYL42M0d.js.map +1 -0
  5. package/dist/chunks/FormBuilderView-aBcA-_tt.cjs +3 -0
  6. package/dist/chunks/FormBuilderView-aBcA-_tt.cjs.map +1 -0
  7. package/dist/chunks/FormRendererView-DRFi_IH7.cjs +4 -0
  8. package/dist/chunks/FormRendererView-DRFi_IH7.cjs.map +1 -0
  9. package/dist/chunks/{FormRendererView-DU9LLrOF.js → FormRendererView-cZGOOjU5.js} +319 -332
  10. package/dist/chunks/FormRendererView-cZGOOjU5.js.map +1 -0
  11. package/dist/chunks/{admin-pickers-DLlG_1du.js → admin-pickers-DxhzECkD.js} +52 -51
  12. package/dist/chunks/admin-pickers-DxhzECkD.js.map +1 -0
  13. package/dist/chunks/admin-pickers-qe3j--gX.cjs +2 -0
  14. package/dist/chunks/admin-pickers-qe3j--gX.cjs.map +1 -0
  15. package/dist/chunks/approval-instance-list-page-CPXMP3PL.js.map +1 -1
  16. package/dist/chunks/approval-instance-list-page-ax0pm8bt.cjs.map +1 -1
  17. package/dist/chunks/auth-provider-4BeCw7cI.cjs.map +1 -1
  18. package/dist/chunks/auth-provider-B5oPmvk2.js.map +1 -1
  19. package/dist/chunks/bpm-form-field-Bc6k4ZEO.cjs.map +1 -1
  20. package/dist/chunks/bpm-form-field-Cao0rMol.js.map +1 -1
  21. package/dist/chunks/{categories-DGlxuC6X.js → categories-1gKxeEqw.js} +4 -10
  22. package/dist/chunks/categories-1gKxeEqw.js.map +1 -0
  23. package/dist/chunks/{categories-Yid05WAX.cjs → categories-DjENouRm.cjs} +2 -2
  24. package/dist/chunks/categories-DjENouRm.cjs.map +1 -0
  25. package/dist/chunks/{compose-BtQPBd1Q.js → compose-Crklayzy.js} +4 -4
  26. package/dist/chunks/compose-Crklayzy.js.map +1 -0
  27. package/dist/chunks/{compose-DZhTQOt4.cjs → compose-DZ7RKvUp.cjs} +2 -2
  28. package/dist/chunks/compose-DZ7RKvUp.cjs.map +1 -0
  29. package/dist/chunks/dashboard-page-BWQBSGDq.cjs +2 -0
  30. package/dist/chunks/dashboard-page-BWQBSGDq.cjs.map +1 -0
  31. package/dist/chunks/{dashboard-page-CeCLV1tp.js → dashboard-page-DdBvV6YI.js} +15 -16
  32. package/dist/chunks/dashboard-page-DdBvV6YI.js.map +1 -0
  33. package/dist/chunks/delegations-Ckf03icM.cjs +2 -0
  34. package/dist/chunks/delegations-Ckf03icM.cjs.map +1 -0
  35. package/dist/chunks/{delegations-DRupxJ4_.js → delegations-MxF3uJGW.js} +205 -215
  36. package/dist/chunks/delegations-MxF3uJGW.js.map +1 -0
  37. package/dist/chunks/delegations-V9HIe3_P.cjs +2 -0
  38. package/dist/chunks/delegations-V9HIe3_P.cjs.map +1 -0
  39. package/dist/chunks/{delegations-B8gLSt0i.js → delegations-xUt1tj8d.js} +168 -173
  40. package/dist/chunks/delegations-xUt1tj8d.js.map +1 -0
  41. package/dist/chunks/{designer-CrbBRPUU.js → designer-D9eFma1W.js} +1180 -1134
  42. package/dist/chunks/designer-D9eFma1W.js.map +1 -0
  43. package/dist/chunks/designer-sJGTGYOf.cjs +65 -0
  44. package/dist/chunks/designer-sJGTGYOf.cjs.map +1 -0
  45. package/dist/chunks/detail-DRCTnuKm.cjs +2 -0
  46. package/dist/chunks/detail-DRCTnuKm.cjs.map +1 -0
  47. package/dist/chunks/{detail-_c21WQla.js → detail-DScLf42P.js} +849 -836
  48. package/dist/chunks/detail-DScLf42P.js.map +1 -0
  49. package/dist/chunks/format-date-time-CB-LxzqT.js.map +1 -1
  50. package/dist/chunks/format-date-time-D-cx5M8z.cjs.map +1 -1
  51. package/dist/chunks/format-member-label-DudVI55w.js +13 -0
  52. package/dist/chunks/format-member-label-DudVI55w.js.map +1 -0
  53. package/dist/chunks/format-member-label-t7ANTF62.cjs +2 -0
  54. package/dist/chunks/format-member-label-t7ANTF62.cjs.map +1 -0
  55. package/dist/chunks/login-AtVxZBsC.cjs.map +1 -1
  56. package/dist/chunks/login-C6qlTC6F.js.map +1 -1
  57. package/dist/chunks/notifications-Bc4mgSds.cjs.map +1 -1
  58. package/dist/chunks/notifications-DJ5wzCye.js.map +1 -1
  59. package/dist/chunks/{orgs-BpqVu5ka.js → orgs-CY0i1fie.js} +787 -766
  60. package/dist/chunks/orgs-CY0i1fie.js.map +1 -0
  61. package/dist/chunks/orgs-Dr0FFoZo.cjs +2 -0
  62. package/dist/chunks/orgs-Dr0FFoZo.cjs.map +1 -0
  63. package/dist/chunks/providers-DHtDZFNA.cjs.map +1 -1
  64. package/dist/chunks/providers-J5eyByQj.js.map +1 -1
  65. package/dist/chunks/router-adapter--gYs13E8.cjs.map +1 -1
  66. package/dist/chunks/router-adapter-DftlFTOd.js.map +1 -1
  67. package/dist/chunks/routes-config-C1j_vFKo.cjs.map +1 -1
  68. package/dist/chunks/routes-config-yZbESPlw.js.map +1 -1
  69. package/dist/chunks/task-node-label-BF6UllxP.cjs.map +1 -1
  70. package/dist/chunks/task-node-label-CWZgOBj0.js.map +1 -1
  71. package/dist/chunks/use-bpm-member-D57LKe_u.js.map +1 -1
  72. package/dist/chunks/use-bpm-member-DpNAQtNC.cjs.map +1 -1
  73. package/dist/chunks/users-BCyePbwB.js +422 -0
  74. package/dist/chunks/users-BCyePbwB.js.map +1 -0
  75. package/dist/chunks/users-DVBJluFR.cjs +2 -0
  76. package/dist/chunks/users-DVBJluFR.cjs.map +1 -0
  77. package/dist/index.cjs +1 -1
  78. package/dist/index.cjs.map +1 -1
  79. package/dist/index.js +2 -2
  80. package/dist/index.js.map +1 -1
  81. package/dist/lib/format-member-label.d.ts +12 -0
  82. package/dist/next/index.cjs.map +1 -1
  83. package/dist/next/index.js.map +1 -1
  84. package/dist/next/workflow-chat-route.cjs.map +1 -1
  85. package/dist/next/workflow-chat-route.js.map +1 -1
  86. package/dist/pages/admin/delegations/index.cjs +1 -1
  87. package/dist/pages/admin/delegations/index.cjs.map +1 -1
  88. package/dist/pages/admin/delegations/index.js +1 -1
  89. package/dist/pages/admin/delegations/index.js.map +1 -1
  90. package/dist/pages/admin/orgs/index.cjs +1 -1
  91. package/dist/pages/admin/orgs/index.cjs.map +1 -1
  92. package/dist/pages/admin/orgs/index.js +1 -1
  93. package/dist/pages/admin/orgs/index.js.map +1 -1
  94. package/dist/pages/admin/users/index.cjs +1 -1
  95. package/dist/pages/admin/users/index.cjs.map +1 -1
  96. package/dist/pages/admin/users/index.js +1 -1
  97. package/dist/pages/admin/users/index.js.map +1 -1
  98. package/dist/pages/admin/webhook-endpoints/index.cjs.map +1 -1
  99. package/dist/pages/admin/webhook-endpoints/index.js.map +1 -1
  100. package/dist/pages/cc/index.cjs.map +1 -1
  101. package/dist/pages/cc/index.js.map +1 -1
  102. package/dist/pages/dashboard/index.cjs.map +1 -1
  103. package/dist/pages/dashboard/index.js.map +1 -1
  104. package/dist/pages/delegations/index.cjs +1 -1
  105. package/dist/pages/delegations/index.cjs.map +1 -1
  106. package/dist/pages/delegations/index.js +1 -1
  107. package/dist/pages/delegations/index.js.map +1 -1
  108. package/dist/pages/inbox/index.cjs.map +1 -1
  109. package/dist/pages/inbox/index.js.map +1 -1
  110. package/dist/pages/instances/detail/index.cjs +1 -1
  111. package/dist/pages/instances/detail/index.cjs.map +1 -1
  112. package/dist/pages/instances/detail/index.js +1 -1
  113. package/dist/pages/instances/detail/index.js.map +1 -1
  114. package/dist/pages/instances/new/index.cjs.map +1 -1
  115. package/dist/pages/instances/new/index.js.map +1 -1
  116. package/dist/pages/login/index.cjs.map +1 -1
  117. package/dist/pages/login/index.js.map +1 -1
  118. package/dist/pages/root/index.cjs.map +1 -1
  119. package/dist/pages/root/index.js.map +1 -1
  120. package/dist/pages/search/index.cjs.map +1 -1
  121. package/dist/pages/search/index.js.map +1 -1
  122. package/dist/pages/sent/index.cjs.map +1 -1
  123. package/dist/pages/sent/index.js.map +1 -1
  124. package/dist/pages/settings/notifications/index.cjs.map +1 -1
  125. package/dist/pages/settings/notifications/index.js.map +1 -1
  126. package/dist/pages/templates/categories/index.cjs +1 -1
  127. package/dist/pages/templates/categories/index.cjs.map +1 -1
  128. package/dist/pages/templates/categories/index.js +1 -1
  129. package/dist/pages/templates/categories/index.js.map +1 -1
  130. package/dist/pages/templates/compose/index.cjs +1 -1
  131. package/dist/pages/templates/compose/index.cjs.map +1 -1
  132. package/dist/pages/templates/compose/index.js +1 -1
  133. package/dist/pages/templates/compose/index.js.map +1 -1
  134. package/dist/pages/templates/designer/index.cjs +1 -1
  135. package/dist/pages/templates/designer/index.cjs.map +1 -1
  136. package/dist/pages/templates/designer/index.js +1 -1
  137. package/dist/pages/templates/designer/index.js.map +1 -1
  138. package/dist/pages/templates/index.cjs.map +1 -1
  139. package/dist/pages/templates/index.js.map +1 -1
  140. package/dist/pages/templates/versions/index.cjs.map +1 -1
  141. package/dist/pages/templates/versions/index.js.map +1 -1
  142. package/dist/views/admin/delegations/index.cjs +1 -1
  143. package/dist/views/admin/delegations/index.js +1 -2
  144. package/dist/views/admin/index.cjs +1 -1
  145. package/dist/views/admin/index.js +3 -3
  146. package/dist/views/admin/orgs/index.cjs +1 -1
  147. package/dist/views/admin/orgs/index.js +1 -2
  148. package/dist/views/admin/users/MemberTaskReassignModal.d.ts +13 -0
  149. package/dist/views/admin/users/index.cjs +1 -1
  150. package/dist/views/admin/users/index.js +1 -2
  151. package/dist/views/admin/webhook-endpoints/index.cjs.map +1 -1
  152. package/dist/views/admin/webhook-endpoints/index.js.map +1 -1
  153. package/dist/views/cc/index.cjs.map +1 -1
  154. package/dist/views/cc/index.js.map +1 -1
  155. package/dist/views/dashboard/index.cjs +1 -1
  156. package/dist/views/dashboard/index.cjs.map +1 -1
  157. package/dist/views/dashboard/index.js +1 -1
  158. package/dist/views/dashboard/index.js.map +1 -1
  159. package/dist/views/delegations/index.cjs +1 -1
  160. package/dist/views/delegations/index.js +1 -2
  161. package/dist/views/forms/builder/index.cjs +1 -1
  162. package/dist/views/forms/builder/index.js +1 -2
  163. package/dist/views/forms/renderer/index.cjs +1 -1
  164. package/dist/views/forms/renderer/index.js +1 -2
  165. package/dist/views/inbox/index.cjs +1 -1
  166. package/dist/views/inbox/index.cjs.map +1 -1
  167. package/dist/views/inbox/index.js +1 -5
  168. package/dist/views/inbox/index.js.map +1 -1
  169. package/dist/views/instances/detail/index.cjs +1 -1
  170. package/dist/views/instances/detail/index.js +1 -2
  171. package/dist/views/instances/index.js +1 -2
  172. package/dist/views/instances/new/index.cjs +1 -1
  173. package/dist/views/instances/new/index.cjs.map +1 -1
  174. package/dist/views/instances/new/index.js +4 -11
  175. package/dist/views/instances/new/index.js.map +1 -1
  176. package/dist/views/login/index.js +1 -2
  177. package/dist/views/search/index.cjs.map +1 -1
  178. package/dist/views/search/index.js.map +1 -1
  179. package/dist/views/sent/index.cjs.map +1 -1
  180. package/dist/views/sent/index.js.map +1 -1
  181. package/dist/views/settings/index.js +1 -2
  182. package/dist/views/settings/notifications/index.js +1 -2
  183. package/dist/views/templates/categories/index.cjs +1 -1
  184. package/dist/views/templates/categories/index.js +1 -2
  185. package/dist/views/templates/compose/index.cjs +1 -1
  186. package/dist/views/templates/compose/index.js +1 -2
  187. package/dist/views/templates/designer/index.cjs +1 -1
  188. package/dist/views/templates/designer/index.js +1 -2
  189. package/dist/views/templates/index.cjs +1 -1
  190. package/dist/views/templates/index.cjs.map +1 -1
  191. package/dist/views/templates/index.js +1 -1
  192. package/dist/views/templates/index.js.map +1 -1
  193. package/dist/views/templates/versions/index.cjs.map +1 -1
  194. package/dist/views/templates/versions/index.js.map +1 -1
  195. package/package.json +5 -5
  196. package/dist/chunks/FormBuilderView-6bCbIkz6.cjs +0 -3
  197. package/dist/chunks/FormBuilderView-6bCbIkz6.cjs.map +0 -1
  198. package/dist/chunks/FormBuilderView-CLg-JYmu.js.map +0 -1
  199. package/dist/chunks/FormRendererView-DU9LLrOF.js.map +0 -1
  200. package/dist/chunks/FormRendererView-gctFIqwC.cjs +0 -4
  201. package/dist/chunks/FormRendererView-gctFIqwC.cjs.map +0 -1
  202. package/dist/chunks/admin-pickers-Btvij1at.cjs +0 -2
  203. package/dist/chunks/admin-pickers-Btvij1at.cjs.map +0 -1
  204. package/dist/chunks/admin-pickers-DLlG_1du.js.map +0 -1
  205. package/dist/chunks/categories-DGlxuC6X.js.map +0 -1
  206. package/dist/chunks/categories-Yid05WAX.cjs.map +0 -1
  207. package/dist/chunks/compose-BtQPBd1Q.js.map +0 -1
  208. package/dist/chunks/compose-DZhTQOt4.cjs.map +0 -1
  209. package/dist/chunks/dashboard-page-CeCLV1tp.js.map +0 -1
  210. package/dist/chunks/dashboard-page-DooFJsxM.cjs +0 -2
  211. package/dist/chunks/dashboard-page-DooFJsxM.cjs.map +0 -1
  212. package/dist/chunks/delegations-8LsxcQM4.cjs +0 -2
  213. package/dist/chunks/delegations-8LsxcQM4.cjs.map +0 -1
  214. package/dist/chunks/delegations-B8gLSt0i.js.map +0 -1
  215. package/dist/chunks/delegations-DRupxJ4_.js.map +0 -1
  216. package/dist/chunks/delegations-DlYwMiAW.cjs +0 -2
  217. package/dist/chunks/delegations-DlYwMiAW.cjs.map +0 -1
  218. package/dist/chunks/designer-CrbBRPUU.js.map +0 -1
  219. package/dist/chunks/designer-D3_lWmfa.cjs +0 -65
  220. package/dist/chunks/designer-D3_lWmfa.cjs.map +0 -1
  221. package/dist/chunks/detail-CVXb5Vy8.cjs +0 -2
  222. package/dist/chunks/detail-CVXb5Vy8.cjs.map +0 -1
  223. package/dist/chunks/detail-_c21WQla.js.map +0 -1
  224. package/dist/chunks/orgs-BpqVu5ka.js.map +0 -1
  225. package/dist/chunks/orgs-D0-5BaHT.cjs +0 -2
  226. package/dist/chunks/orgs-D0-5BaHT.cjs.map +0 -1
  227. package/dist/chunks/users-C9LA-Rd7.cjs +0 -2
  228. package/dist/chunks/users-C9LA-Rd7.cjs.map +0 -1
  229. package/dist/chunks/users-FWrb3ehW.js +0 -214
  230. package/dist/chunks/users-FWrb3ehW.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"compose-DZhTQOt4.cjs","names":[],"sources":["../../src/views/templates/compose/steps/ComposeFormStep.tsx","../../src/views/templates/compose/steps/ComposeReviewStep.tsx","../../src/views/templates/compose/steps/ComposeWorkflowStep.tsx","../../src/views/templates/compose/use-template-compose-wizard.ts","../../src/views/templates/compose/TemplateComposeWizardView.tsx"],"sourcesContent":["'use client';\n\nimport type { ChangeEvent, ReactElement } from 'react';\nimport { useEffect, useState } from 'react';\nimport { FormField, Input, Select, Typography } from '@mezzanine-ui/react';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { SelectValue } from '@mezzanine-ui/react/Select';\nimport type {\n FormDefinitionSchema,\n FormUiSchema,\n} from '@rytass/bpm-core-shared/form';\nimport {\n ApprovalTemplateCategoryRecord,\n listApprovalTemplateCategoriesPage,\n} from '@rytass/bpm-core-client/template';\nimport { FormBuilderView } from '../../../forms/builder';\n\nconst UNCATEGORIZED_OPTION: SelectValue = {\n id: 'UNCATEGORIZED',\n name: '未分類',\n};\n\nconst CATEGORY_PAGE_SIZE = 100;\n\nexport interface ComposeFormStepProps {\n readonly name: string;\n readonly categoryId: string | null;\n readonly formSchema: FormDefinitionSchema;\n readonly formUiSchema: FormUiSchema;\n readonly onNameChange: (value: string) => void;\n readonly onCategoryIdChange: (value: string | null) => void;\n readonly onFormChange: (next: {\n readonly schema: FormDefinitionSchema;\n readonly uiSchema: FormUiSchema;\n }) => void;\n}\n\nexport function ComposeFormStep({\n categoryId,\n formSchema,\n formUiSchema,\n name,\n onCategoryIdChange,\n onFormChange,\n onNameChange,\n}: ComposeFormStepProps): ReactElement {\n const [categoryOptions, setCategoryOptions] = useState<\n readonly ApprovalTemplateCategoryRecord[]\n >([]);\n\n useEffect((): (() => void) => {\n let active = true;\n\n void (async (): Promise<void> => {\n try {\n const result = await listApprovalTemplateCategoriesPage({\n page: 1,\n pageSize: CATEGORY_PAGE_SIZE,\n searchText: '',\n status: 'ACTIVE',\n });\n\n if (active) {\n setCategoryOptions(result.categories);\n }\n } catch {\n if (active) {\n setCategoryOptions([]);\n }\n }\n })();\n\n return (): void => {\n active = false;\n };\n }, []);\n\n const selectOptions: SelectValue[] = [\n UNCATEGORIZED_OPTION,\n ...categoryOptions.map((category) => ({\n id: category.id,\n name: category.name,\n })),\n ];\n const selectedOption =\n selectOptions.find((option) => option.id === categoryId) ??\n UNCATEGORIZED_OPTION;\n\n return (\n <>\n <div style={BASICS_GRID_STYLE}>\n <FormField\n label=\"名稱\"\n layout={FormFieldLayout.VERTICAL}\n name=\"composeName\"\n >\n <Input\n fullWidth\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onNameChange(event.target.value)\n }\n placeholder=\"例如:請款簽核\"\n value={name}\n />\n </FormField>\n <FormField\n label=\"分類(選填)\"\n layout={FormFieldLayout.VERTICAL}\n name=\"composeCategory\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void =>\n onCategoryIdChange(\n option && option.id !== UNCATEGORIZED_OPTION.id\n ? option.id\n : null,\n )\n }\n options={selectOptions}\n placeholder=\"未分類\"\n value={selectedOption}\n />\n </FormField>\n </div>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 先設計表單欄位,下一步的流程條件分流即可直接引用這些欄位。\n </Typography>\n <FormBuilderView\n onChange={onFormChange}\n value={{ schema: formSchema, uiSchema: formUiSchema }}\n />\n </>\n );\n}\n\nconst BASICS_GRID_STYLE = {\n display: 'grid',\n gap: 16,\n gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))',\n} as const;\n","'use client';\n\nimport type { CSSProperties, ReactElement } from 'react';\nimport { Empty, Table, Tag, Typography } from '@mezzanine-ui/react';\nimport type { TableColumn } from '@mezzanine-ui/core/table';\nimport type {\n FormDefinitionSchema,\n FormUiSchema,\n} from '@rytass/bpm-core-shared/form';\nimport type {\n WorkflowDefinition,\n WorkflowNode,\n} from '@rytass/bpm-core-shared/workflow';\nimport { FormRenderer } from '../../../forms/renderer/FormRendererView';\n\ntype FlowNodeRow = Readonly<\n Record<string, unknown> & {\n detail: string;\n key: string;\n label: string;\n typeLabel: string;\n }\n>;\n\ntype BranchRow = Readonly<\n Record<string, unknown> & {\n condition: string;\n key: string;\n source: string;\n target: string;\n }\n>;\n\nexport interface ComposeReviewStepProps {\n readonly name: string;\n readonly formSchema: FormDefinitionSchema;\n readonly formUiSchema: FormUiSchema;\n readonly workflowDefinition: WorkflowDefinition | null;\n readonly initiatorPolicyCel: string | null;\n readonly publishError: string | null;\n}\n\nexport function ComposeReviewStep({\n formSchema,\n formUiSchema,\n initiatorPolicyCel,\n name,\n publishError,\n workflowDefinition,\n}: ComposeReviewStepProps): ReactElement {\n const nodes = workflowDefinition?.nodes ?? [];\n const edges = workflowDefinition?.edges ?? [];\n const fieldCount = formSchema.fields.length;\n const nodeLabelById = new Map(\n nodes.map((node) => [node.id, node.data.label] as const),\n );\n const nodeRows: FlowNodeRow[] = nodes.map((node) => ({\n detail: readNodeDetail(node) ?? '—',\n key: node.id,\n label: node.data.label,\n typeLabel: readNodeTypeLabel(node),\n }));\n const branchRows: BranchRow[] = edges\n .filter((edge) => Boolean(edge.data.condition))\n .map((edge) => ({\n condition: edge.data.condition ?? '',\n key: edge.id,\n source: nodeLabelById.get(edge.source) ?? edge.source,\n target: nodeLabelById.get(edge.target) ?? edge.target,\n }));\n\n return (\n <div style={STACK_STYLE}>\n <Typography component=\"h2\" style={TITLE_STYLE} variant=\"h2\">\n {name || '(未命名)'}\n </Typography>\n\n <div style={STACK_STYLE}>\n <Typography variant=\"h3\">表單預覽</Typography>\n {fieldCount > 0 ? (\n <FormRenderer\n dataSourceContext={{ kind: 'preview' }}\n readonly\n schema={formSchema}\n uiSchema={formUiSchema}\n />\n ) : (\n <Empty title=\"尚未設計表單欄位\" />\n )}\n </div>\n\n <div style={STACK_STYLE}>\n <Typography variant=\"h3\">流程概覽</Typography>\n {nodes.length > 0 ? (\n <Table columns={NODE_COLUMNS} dataSource={nodeRows} fullWidth />\n ) : (\n <Empty title=\"尚未設計流程節點\" />\n )}\n {branchRows.length > 0 ? (\n <>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 條件分流\n </Typography>\n <Table columns={BRANCH_COLUMNS} dataSource={branchRows} fullWidth />\n </>\n ) : null}\n {initiatorPolicyCel ? (\n <Typography color=\"text-neutral\" variant=\"caption\">\n 發起權限:{initiatorPolicyCel}\n </Typography>\n ) : null}\n </div>\n\n {publishError ? (\n <Typography color=\"text-error\" variant=\"body\">\n {publishError}\n </Typography>\n ) : null}\n </div>\n );\n}\n\nconst NODE_COLUMNS: TableColumn<FlowNodeRow>[] = [\n {\n key: 'type',\n render: (record: FlowNodeRow): ReactElement => (\n <Tag label={record.typeLabel} size=\"sub\" type=\"static\" />\n ),\n title: '類型',\n width: 130,\n },\n { dataIndex: 'label', key: 'label', title: '節點' },\n { dataIndex: 'detail', key: 'detail', title: '簽核方式', width: 160 },\n];\n\nconst BRANCH_COLUMNS: TableColumn<BranchRow>[] = [\n { dataIndex: 'source', key: 'source', title: '來源', width: 180 },\n { dataIndex: 'target', key: 'target', title: '目標', width: 180 },\n { dataIndex: 'condition', key: 'condition', title: '條件' },\n];\n\nfunction readNodeTypeLabel(node: WorkflowNode): string {\n switch (node.type) {\n case 'startEvent':\n return '開始';\n case 'endEvent':\n return node.data.endState === 'REJECTED' ? '結束(駁回)' : '結束(核准)';\n case 'userTask':\n return '簽核';\n case 'serviceTask':\n return '服務';\n case 'exclusiveGateway':\n return '條件閘道';\n case 'parallelGateway':\n return '平行閘道';\n default:\n return '節點';\n }\n}\n\nfunction readNodeDetail(node: WorkflowNode): string | null {\n if (node.type !== 'userTask') {\n return null;\n }\n\n switch (node.data.approverResolver.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 default:\n return '簽核人';\n }\n}\n\nconst STACK_STYLE: CSSProperties = {\n display: 'grid',\n gap: 12,\n};\n\n// Match the breathing room between the stepper and the PageHeader, which is the\n// Section's top padding token.\nconst TITLE_STYLE: CSSProperties = {\n marginTop: 'var(--mzn-spacing-padding-vertical-spacious)',\n};\n","'use client';\n\nimport type { ReactElement } from 'react';\nimport { Typography } from '@mezzanine-ui/react';\nimport type { FormDefinitionSchema } from '@rytass/bpm-core-shared/form';\nimport type { WorkflowDefinition } from '@rytass/bpm-core-shared/workflow';\nimport { TemplateDesignerView } from '../../designer';\n\nexport interface ComposeWorkflowStepProps {\n readonly formSchema: FormDefinitionSchema;\n readonly workflowDefinition: WorkflowDefinition | null;\n readonly initiatorPolicyCel: string | null;\n readonly onWorkflowChange: (definition: WorkflowDefinition) => void;\n readonly onInitiatorPolicyChange: (cel: string | null) => void;\n /**\n * Show the AI assistant button inside the embedded designer's side panel.\n * Follows the same opt-in contract as the standalone designer page; default\n * hidden. Wired up the stack from the server page's `BPM_AI_ASSISTANT_ENABLED`.\n */\n readonly showAiAssistant?: boolean;\n /**\n * Whether the LLM backend is configured (host has an API key). When `false`\n * the AI button shows disabled as a placeholder. Default `false`.\n */\n readonly aiAssistantAvailable?: boolean;\n}\n\nexport function ComposeWorkflowStep({\n aiAssistantAvailable = false,\n formSchema,\n initiatorPolicyCel,\n onInitiatorPolicyChange,\n onWorkflowChange,\n showAiAssistant = false,\n workflowDefinition,\n}: ComposeWorkflowStepProps): ReactElement {\n return (\n <>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 設計簽核節點與條件分流;條件可直接引用上一步設計的表單欄位。\n </Typography>\n <TemplateDesignerView\n aiAssistantAvailable={aiAssistantAvailable}\n embedded\n formSchemaOverride={formSchema}\n initialInitiatorPolicyCel={initiatorPolicyCel}\n initialWorkflowDefinition={workflowDefinition ?? undefined}\n onInitiatorPolicyChange={onInitiatorPolicyChange}\n onWorkflowChange={onWorkflowChange}\n showAiAssistant={showAiAssistant}\n />\n </>\n );\n}\n","'use client';\n\nimport { useCallback, useState } from 'react';\nimport type {\n FormDefinitionSchema,\n FormUiSchema,\n} from '@rytass/bpm-core-shared/form';\nimport type { WorkflowDefinition } from '@rytass/bpm-core-shared/workflow';\nimport { readFormSchemaLintMessage } from '@rytass/bpm-core-client/form';\nimport {\n ComposeApprovalTemplateWithFormResult,\n composeApprovalTemplateWithForm,\n} from '@rytass/bpm-core-client/template';\n\nexport type ComposeWizardStep = 0 | 1 | 2;\n\nexport type ComposePublishPhase = 'error' | 'idle' | 'submitting' | 'success';\n\nexport const EMPTY_COMPOSE_FORM_SCHEMA: FormDefinitionSchema = {\n fields: [],\n schemaVersion: 1,\n};\n\nexport const EMPTY_COMPOSE_FORM_UI_SCHEMA: FormUiSchema = {\n layout: [],\n schemaVersion: 1,\n};\n\nexport interface TemplateComposeWizard {\n readonly currentStep: ComposeWizardStep;\n /**\n * Single user-facing name. Persisted to both the template and the form\n * (`templateName` / `formName`) at the `composeApprovalTemplateWithForm`\n * boundary — the DB keeps two columns, the UI keeps one field.\n */\n readonly name: string;\n readonly categoryId: string | null;\n readonly formSchema: FormDefinitionSchema;\n readonly formUiSchema: FormUiSchema;\n readonly workflowDefinition: WorkflowDefinition | null;\n readonly initiatorPolicyCel: string | null;\n readonly publishPhase: ComposePublishPhase;\n readonly publishError: string | null;\n readonly canLeaveBasics: boolean;\n readonly goToStep: (step: ComposeWizardStep) => void;\n readonly goNext: () => void;\n readonly goBack: () => void;\n readonly setName: (value: string) => void;\n readonly setCategoryId: (value: string | null) => void;\n readonly setFormValue: (next: {\n readonly schema: FormDefinitionSchema;\n readonly uiSchema: FormUiSchema;\n }) => void;\n readonly setWorkflowDefinition: (definition: WorkflowDefinition) => void;\n readonly setInitiatorPolicyCel: (cel: string | null) => void;\n readonly publish: () => Promise<ComposeApprovalTemplateWithFormResult | null>;\n}\n\n/**\n * Owns the cross-step state for the unified \"form + flow\" template wizard.\n *\n * Step 0 (表單) edits `formSchema`/`formUiSchema`; that same in-memory schema\n * feeds Step 1 (流程) as the field source for condition branches, so the\n * embedded designer never needs a published form version. Step 2 (檢視發佈)\n * submits everything through the atomic `composeApprovalTemplateWithForm`\n * mutation.\n */\nexport function useTemplateComposeWizard(): TemplateComposeWizard {\n const [currentStep, setCurrentStep] = useState<ComposeWizardStep>(0);\n const [name, setName] = useState('');\n const [categoryId, setCategoryId] = useState<string | null>(null);\n const [formSchema, setFormSchema] = useState<FormDefinitionSchema>(\n EMPTY_COMPOSE_FORM_SCHEMA,\n );\n const [formUiSchema, setFormUiSchema] = useState<FormUiSchema>(\n EMPTY_COMPOSE_FORM_UI_SCHEMA,\n );\n const [workflowDefinition, setWorkflowDefinitionState] =\n useState<WorkflowDefinition | null>(null);\n const [initiatorPolicyCel, setInitiatorPolicyCelState] = useState<\n string | null\n >(null);\n const [publishPhase, setPublishPhase] = useState<ComposePublishPhase>('idle');\n const [publishError, setPublishError] = useState<string | null>(null);\n\n const canLeaveBasics = name.trim().length > 0 && formSchema.fields.length > 0;\n\n const goToStep = useCallback((step: ComposeWizardStep): void => {\n setCurrentStep(step);\n }, []);\n\n const goNext = useCallback((): void => {\n setCurrentStep((step) =>\n step < 2 ? ((step + 1) as ComposeWizardStep) : step,\n );\n }, []);\n\n const goBack = useCallback((): void => {\n setCurrentStep((step) =>\n step > 0 ? ((step - 1) as ComposeWizardStep) : step,\n );\n }, []);\n\n const setFormValue = useCallback(\n (next: {\n readonly schema: FormDefinitionSchema;\n readonly uiSchema: FormUiSchema;\n }): void => {\n setFormSchema(next.schema);\n setFormUiSchema(next.uiSchema);\n },\n [],\n );\n\n const setWorkflowDefinition = useCallback(\n (definition: WorkflowDefinition): void => {\n setWorkflowDefinitionState(definition);\n },\n [],\n );\n\n const setInitiatorPolicyCel = useCallback((cel: string | null): void => {\n setInitiatorPolicyCelState(cel);\n }, []);\n\n const publish =\n useCallback(async (): Promise<ComposeApprovalTemplateWithFormResult | null> => {\n setPublishPhase('submitting');\n setPublishError(null);\n\n try {\n const result = await composeApprovalTemplateWithForm({\n category: null,\n categoryId,\n formDefinitionId: null,\n formDescription: null,\n // One UI name fans out to both persisted columns.\n formName: name,\n initiatorPolicyCel,\n notificationConfig: null,\n publish: true,\n schema: formSchema,\n slaDefaults: null,\n templateDescription: null,\n templateId: null,\n templateName: name,\n uiSchema: formUiSchema,\n workflowDefinition: workflowDefinition ?? EMPTY_WORKFLOW_DEFINITION,\n });\n\n setPublishPhase('success');\n\n return result;\n } catch (requestError: unknown) {\n setPublishError(readErrorMessage(requestError));\n setPublishPhase('error');\n\n return null;\n }\n }, [\n categoryId,\n formSchema,\n formUiSchema,\n initiatorPolicyCel,\n name,\n workflowDefinition,\n ]);\n\n return {\n canLeaveBasics,\n categoryId,\n currentStep,\n formSchema,\n formUiSchema,\n goBack,\n goNext,\n goToStep,\n initiatorPolicyCel,\n name,\n publish,\n publishError,\n publishPhase,\n setCategoryId,\n setFormValue,\n setInitiatorPolicyCel,\n setName,\n setWorkflowDefinition,\n workflowDefinition,\n };\n}\n\nconst EMPTY_WORKFLOW_DEFINITION: WorkflowDefinition = {\n edges: [],\n meta: { schemaVersion: 1 },\n nodes: [\n {\n data: { label: '開始' },\n id: 'start',\n position: { x: 80, y: 160 },\n type: 'startEvent',\n },\n {\n data: { endState: 'APPROVED', label: '完成', triggerMode: 'AND' },\n id: 'end',\n position: { x: 560, y: 160 },\n type: 'endEvent',\n },\n ],\n};\n\nfunction readErrorMessage(error: unknown): string {\n // Publish failures can carry stable `FORM_DATA_SOURCE_*` codes; map them to\n // readable copy and leave every other message untouched.\n return error instanceof Error\n ? readFormSchemaLintMessage(error.message)\n : '發生未知錯誤';\n}\n","'use client';\n\nimport type { ReactElement } from 'react';\nimport {\n Button,\n PageHeader,\n Section,\n SectionGroup,\n Step,\n Stepper,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { useRouterAdapter } from '../../../lib/router-adapter';\nimport { useBPMRoutes } from '../../../lib/routes-config';\nimport { ComposeFormStep } from './steps/ComposeFormStep';\nimport { ComposeReviewStep } from './steps/ComposeReviewStep';\nimport { ComposeWorkflowStep } from './steps/ComposeWorkflowStep';\nimport { useTemplateComposeWizard } from './use-template-compose-wizard';\n\nexport interface TemplateComposeWizardViewProps {\n /**\n * Show the workflow designer AI assistant inside Step 1 (流程設計). Opt-in,\n * default hidden — the server page maps `BPM_AI_ASSISTANT_ENABLED` to it.\n */\n readonly showAiAssistant?: boolean;\n /**\n * Whether the LLM backend is configured (host has an API key). When `false`\n * the AI button shows disabled as a placeholder. Default `false`.\n */\n readonly aiAssistantAvailable?: boolean;\n}\n\n/**\n * Unified \"form + flow\" template creation wizard. Walks the user through\n * Step 0 表單設計 → Step 1 流程設計 → Step 2 檢視並發佈, then commits both\n * sides atomically through `composeApprovalTemplateWithForm`. This is the\n * template entry point; the form builder is intentionally controlled here\n * instead of exposed as a standalone `/forms` page.\n */\nexport function TemplateComposeWizardView({\n aiAssistantAvailable = false,\n showAiAssistant = false,\n}: TemplateComposeWizardViewProps = {}): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const wizard = useTemplateComposeWizard();\n const submitting = wizard.publishPhase === 'submitting';\n\n async function handlePublish(): Promise<void> {\n const result = await wizard.publish();\n\n if (result) {\n router.push(routes.templateDesigner(result.templateId));\n }\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"一次完成表單與流程設計,發佈後即可直接發起。\"\n title=\"建立模板(表單 + 流程)\"\n >\n <Button\n disabled={submitting}\n onClick={(): void => router.push(routes.templates())}\n variant=\"base-secondary\"\n >\n 返回模板列表\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <Stepper currentStep={wizard.currentStep}>\n <Step description=\"設計欄位與版面\" title=\"表單設計\" />\n <Step description=\"設計簽核節點與條件\" title=\"流程設計\" />\n <Step description=\"確認後發佈\" title=\"檢視並發佈\" />\n </Stepper>\n\n {wizard.currentStep === 0 ? (\n <ComposeFormStep\n categoryId={wizard.categoryId}\n formSchema={wizard.formSchema}\n formUiSchema={wizard.formUiSchema}\n name={wizard.name}\n onCategoryIdChange={wizard.setCategoryId}\n onFormChange={wizard.setFormValue}\n onNameChange={wizard.setName}\n />\n ) : null}\n\n {wizard.currentStep === 1 ? (\n <ComposeWorkflowStep\n aiAssistantAvailable={aiAssistantAvailable}\n formSchema={wizard.formSchema}\n initiatorPolicyCel={wizard.initiatorPolicyCel}\n onInitiatorPolicyChange={wizard.setInitiatorPolicyCel}\n onWorkflowChange={wizard.setWorkflowDefinition}\n showAiAssistant={showAiAssistant}\n workflowDefinition={wizard.workflowDefinition}\n />\n ) : null}\n\n {wizard.currentStep === 2 ? (\n <ComposeReviewStep\n formSchema={wizard.formSchema}\n formUiSchema={wizard.formUiSchema}\n initiatorPolicyCel={wizard.initiatorPolicyCel}\n name={wizard.name}\n publishError={wizard.publishError}\n workflowDefinition={wizard.workflowDefinition}\n />\n ) : null}\n\n <div style={FOOTER_STYLE}>\n {wizard.currentStep === 0 && !wizard.canLeaveBasics ? (\n <Typography color=\"text-neutral\" variant=\"caption\">\n 請填寫模板名稱、表單名稱,並至少新增一個表單欄位。\n </Typography>\n ) : (\n <span />\n )}\n <div style={FOOTER_ACTIONS_STYLE}>\n <Button\n disabled={wizard.currentStep === 0 || submitting}\n onClick={wizard.goBack}\n variant=\"base-secondary\"\n >\n 上一步\n </Button>\n {wizard.currentStep < 2 ? (\n <Button\n disabled={wizard.currentStep === 0 && !wizard.canLeaveBasics}\n onClick={wizard.goNext}\n variant=\"base-primary\"\n >\n 下一步\n </Button>\n ) : (\n <Button\n disabled={submitting}\n loading={submitting}\n onClick={(): void => {\n void handlePublish();\n }}\n variant=\"base-primary\"\n >\n 發佈\n </Button>\n )}\n </div>\n </div>\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nconst FOOTER_STYLE = {\n alignItems: 'center',\n display: 'flex',\n // Match the breathing room used elsewhere (the Section's top padding token).\n marginTop: 'var(--mzn-spacing-padding-vertical-spacious)',\n justifyContent: 'space-between',\n gap: 16,\n} as const;\n\nconst FOOTER_ACTIONS_STYLE = {\n display: 'flex',\n gap: 8,\n} as const;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"dashboard-page-CeCLV1tp.js","names":[],"sources":["../../src/components/dashboard-page.module.scss","../../src/components/dashboard-page.tsx"],"sourcesContent":[".metricCard {\n color: inherit;\n cursor: pointer;\n text-decoration: none;\n}\n\n.metricCard:hover {\n text-decoration: none;\n}\n","'use client';\n\nimport type { KeyboardEvent, ReactElement } from 'react';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport {\n BaseCard,\n Button,\n CardGroup,\n PageHeader,\n Section,\n SectionGroup,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { PlusIcon } from '@mezzanine-ui/icons';\nimport {\n readWorkflowDashboardSummary,\n type WorkflowDashboardSummaryRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { useAuth } from '../lib/auth-provider';\nimport { useRouterAdapter } from '../lib/router-adapter';\nimport { useBPMRoutes } from '../lib/routes-config';\nimport styles from './dashboard-page.module.scss';\n\n\ninterface Metric {\n readonly caption: string;\n readonly href: string;\n readonly label: string;\n readonly value: string;\n}\n\nconst EMPTY_DASHBOARD_SUMMARY: WorkflowDashboardSummaryRecord = {\n activeInstanceCount: 0,\n completedInstanceCount: 0,\n overdueTaskCount: 0,\n pendingTaskCount: 0,\n rejectedInstanceCount: 0,\n totalInstanceCount: 0,\n unreadNotificationCount: 0,\n};\n\n/**\n * Operator dashboard — shows pending/unread/active counts for the\n * currently-authenticated member. Reads {@link readWorkflowDashboardSummary}\n * and renders five metric tiles that navigate via {@link useRouterAdapter}.\n */\nexport function DashboardPage(): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [summary, setSummary] = useState<WorkflowDashboardSummaryRecord>(\n EMPTY_DASHBOARD_SUMMARY,\n );\n\n const refreshSummary = useCallback(async (): Promise<void> => {\n if (!currentMemberId) {\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n setSummary(\n await readWorkflowDashboardSummary({\n currentMemberId,\n from: null,\n to: null,\n }),\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [currentMemberId]);\n\n useEffect((): void => {\n void refreshSummary();\n }, [refreshSummary]);\n\n const metrics = useMemo(\n (): readonly Metric[] => [\n {\n caption: '目前需要你處理的任務',\n href: routes.inbox(),\n label: '待處理簽核',\n value: readMetricValue(summary.pendingTaskCount, loading),\n },\n {\n // 未讀通知 — clicking the tile routes to inbox where pending\n // tasks are the most actionable next step. The notification\n // drawer bell stays available globally for in-place review.\n // (Hosts that want a dedicated /notifications page can override\n // `routes.notifications` and swap this href accordingly.)\n caption: '尚未讀取的站內通知',\n href: routes.inbox(),\n label: '未讀通知',\n value: readMetricValue(summary.unreadNotificationCount, loading),\n },\n {\n caption: '目前仍在流程中的案件',\n href: routes.search(),\n label: '進行中案件',\n value: readMetricValue(summary.activeInstanceCount, loading),\n },\n {\n caption: '已超過 SLA 的待處理任務',\n href: routes.inbox(),\n label: '逾時任務',\n value: readMetricValue(summary.overdueTaskCount, loading),\n },\n {\n caption: '你有權限查看的全部案件',\n href: routes.search(),\n label: '案件總數',\n value: readMetricValue(summary.totalInstanceCount, loading),\n },\n ],\n [loading, routes, summary],\n );\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"查看待處理簽核、近期通知與你發起的案件進度。\"\n title=\"工作台\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => router.push(routes.caseNew())}\n variant=\"base-primary\"\n >\n 發起簽核\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <CardGroup>\n {metrics.map((metric) => (\n <BaseCard\n aria-label={`前往${metric.label}`}\n className={styles.metricCard}\n description={metric.value}\n key={metric.label}\n onClick={(): void => router.push(metric.href)}\n onKeyDown={(event: KeyboardEvent<HTMLElement>): void => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n router.push(metric.href);\n }\n }}\n role=\"link\"\n tabIndex={0}\n title={metric.label}\n >\n <Typography color=\"text-neutral\" variant=\"caption\">\n {metric.caption}\n </Typography>\n </BaseCard>\n ))}\n </CardGroup>\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction readMetricValue(value: number, loading: boolean): string {\n return loading ? '-' : String(value);\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '讀取工作台摘要失敗。';\n}\n"],"mappings":";;;;;;;;;;gDCgCM,IAA0D;CAC9D,qBAAqB;CACrB,wBAAwB;CACxB,kBAAkB;CAClB,kBAAkB;CAClB,uBAAuB;CACvB,oBAAoB;CACpB,yBAAyB;AAC3B;AAOA,SAAgB,IAA8B;CAC5C,IAAM,IAAS,EAAiB,GAC1B,IAAS,EAAa,GACtB,EAAE,cAAW,EAAQ,GACrB,IAAkB,GAAQ,YAAY,MACtC,CAAC,GAAO,KAAY,EAAwB,IAAI,GAChD,CAAC,GAAS,KAAc,EAAS,EAAI,GACrC,CAAC,GAAS,KAAc,EAC5B,CACF,GAEM,IAAiB,EAAY,YAA2B;EAC5D,IAAI,CAAC,GAAiB;GACpB,EAAW,EAAK;GAChB;EACF;EAGA,AADA,EAAW,EAAI,GACf,EAAS,IAAI;EAEb,IAAI;GACF,EACE,MAAM,EAA6B;IACjC;IACA,MAAM;IACN,IAAI;GACN,CAAC,CACH;EACF,SAAS,GAAuB;GAC9B,EAAS,EAAiB,CAAY,CAAC;EACzC,UAAU;GACR,EAAW,EAAK;EAClB;CACF,GAAG,CAAC,CAAe,CAAC;CAEpB,QAAsB;EACpB,EAAoB;CACtB,GAAG,CAAC,CAAc,CAAC;CAEnB,IAAM,IAAU,QACW;EACvB;GACE,SAAS;GACT,MAAM,EAAO,MAAM;GACnB,OAAO;GACP,OAAO,EAAgB,EAAQ,kBAAkB,CAAO;EAC1D;EACA;GAME,SAAS;GACT,MAAM,EAAO,MAAM;GACnB,OAAO;GACP,OAAO,EAAgB,EAAQ,yBAAyB,CAAO;EACjE;EACA;GACE,SAAS;GACT,MAAM,EAAO,OAAO;GACpB,OAAO;GACP,OAAO,EAAgB,EAAQ,qBAAqB,CAAO;EAC7D;EACA;GACE,SAAS;GACT,MAAM,EAAO,MAAM;GACnB,OAAO;GACP,OAAO,EAAgB,EAAQ,kBAAkB,CAAO;EAC1D;EACA;GACE,SAAS;GACT,MAAM,EAAO,OAAO;GACpB,OAAO;GACP,OAAO,EAAgB,EAAQ,oBAAoB,CAAO;EAC5D;CACF,GACA;EAAC;EAAS;EAAQ;CAAO,CAC3B;CAEA,OACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EACE,aAAY;EACZ,OAAM;EAEN,UAAA,kBAAC,GAAD;GACE,MAAM;GACN,UAAS;GACT,eAAqB,EAAO,KAAK,EAAO,QAAQ,CAAC;GACjD,SAAQ;GACT,UAAA;EAEO,CAAA;CACK,CAAA,EACL,CAAA,GAEZ,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAA,CACG,IACC,kBAAC,GAAD;EAAY,OAAM;EAAa,SAAQ;EACpC,UAAA;CACS,CAAA,IACV,MACJ,kBAAC,GAAD,EAAA,UACG,EAAQ,KAAK,MACZ,kBAAC,GAAD;EACE,cAAY,KAAK,EAAO;EACxB,WAAW,EAAO;EAClB,aAAa,EAAO;EAEpB,eAAqB,EAAO,KAAK,EAAO,IAAI;EAC5C,YAAY,MAA4C;GACtD,CAAI,EAAM,QAAQ,WAAW,EAAM,QAAQ,SACzC,EAAM,eAAe,GACrB,EAAO,KAAK,EAAO,IAAI;EAE3B;EACA,MAAK;EACL,UAAU;EACV,OAAO,EAAO;EAEd,UAAA,kBAAC,GAAD;GAAY,OAAM;GAAe,SAAQ;GACtC,UAAA,EAAO;EACE,CAAA;CACJ,GAfH,EAAO,KAeJ,CACX,EACQ,CAAA,CACJ,EAAA,CAAA,EACG,CAAA,CACd,EAAA,CAAA;AAEN;AAEA,SAAS,EAAgB,GAAe,GAA0B;CAChE,OAAO,IAAU,MAAM,OAAO,CAAK;AACrC;AAEA,SAAS,EAAiB,GAAwB;CAChD,OAAO,aAAiB,QAAQ,EAAM,UAAU;AAClD"}
@@ -1,2 +0,0 @@
1
- "use client";require('../dashboard-page.css');const e=require("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./router-adapter--gYs13E8.cjs"),n=require("./auth-provider-4BeCw7cI.cjs"),r=require("./routes-config-C1j_vFKo.cjs");let i=require("react"),a=require("@mezzanine-ui/react"),o=require("react/jsx-runtime"),s=require("@rytass/bpm-core-client/workflow"),c=require("@mezzanine-ui/react/ContentHeader");c=e.t(c,1);let l=require("@mezzanine-ui/icons");var u={metricCard:`bpm_metricCard_vp2qC`},d={activeInstanceCount:0,completedInstanceCount:0,overdueTaskCount:0,pendingTaskCount:0,rejectedInstanceCount:0,totalInstanceCount:0,unreadNotificationCount:0};function f(){let e=t.r(),f=r.r(),{member:h}=n.n(),g=h?.memberId??null,[_,v]=(0,i.useState)(null),[y,b]=(0,i.useState)(!0),[x,S]=(0,i.useState)(d),C=(0,i.useCallback)(async()=>{if(!g){b(!1);return}b(!0),v(null);try{S(await(0,s.readWorkflowDashboardSummary)({currentMemberId:g,from:null,to:null}))}catch(e){v(m(e))}finally{b(!1)}},[g]);(0,i.useEffect)(()=>{C()},[C]);let w=(0,i.useMemo)(()=>[{caption:`目前需要你處理的任務`,href:f.inbox(),label:`待處理簽核`,value:p(x.pendingTaskCount,y)},{caption:`尚未讀取的站內通知`,href:f.inbox(),label:`未讀通知`,value:p(x.unreadNotificationCount,y)},{caption:`目前仍在流程中的案件`,href:f.search(),label:`進行中案件`,value:p(x.activeInstanceCount,y)},{caption:`已超過 SLA 的待處理任務`,href:f.inbox(),label:`逾時任務`,value:p(x.overdueTaskCount,y)},{caption:`你有權限查看的全部案件`,href:f.search(),label:`案件總數`,value:p(x.totalInstanceCount,y)}],[y,f,x]);return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(a.PageHeader,{children:(0,o.jsx)(c.default,{description:`查看待處理簽核、近期通知與你發起的案件進度。`,title:`工作台`,children:(0,o.jsx)(a.Button,{icon:l.PlusIcon,iconType:`leading`,onClick:()=>e.push(f.caseNew()),variant:`base-primary`,children:`發起簽核`})})}),(0,o.jsx)(a.SectionGroup,{children:(0,o.jsxs)(a.Section,{children:[_?(0,o.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:_}):null,(0,o.jsx)(a.CardGroup,{children:w.map(t=>(0,o.jsx)(a.BaseCard,{"aria-label":`前往${t.label}`,className:u.metricCard,description:t.value,onClick:()=>e.push(t.href),onKeyDown:n=>{(n.key===`Enter`||n.key===` `)&&(n.preventDefault(),e.push(t.href))},role:`link`,tabIndex:0,title:t.label,children:(0,o.jsx)(a.Typography,{color:`text-neutral`,variant:`caption`,children:t.caption})},t.label))})]})})]})}function p(e,t){return t?`-`:String(e)}function m(e){return e instanceof Error?e.message:`讀取工作台摘要失敗。`}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return f}});
2
- //# sourceMappingURL=dashboard-page-DooFJsxM.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dashboard-page-DooFJsxM.cjs","names":[],"sources":["../../src/components/dashboard-page.module.scss","../../src/components/dashboard-page.tsx"],"sourcesContent":[".metricCard {\n color: inherit;\n cursor: pointer;\n text-decoration: none;\n}\n\n.metricCard:hover {\n text-decoration: none;\n}\n","'use client';\n\nimport type { KeyboardEvent, ReactElement } from 'react';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport {\n BaseCard,\n Button,\n CardGroup,\n PageHeader,\n Section,\n SectionGroup,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { PlusIcon } from '@mezzanine-ui/icons';\nimport {\n readWorkflowDashboardSummary,\n type WorkflowDashboardSummaryRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { useAuth } from '../lib/auth-provider';\nimport { useRouterAdapter } from '../lib/router-adapter';\nimport { useBPMRoutes } from '../lib/routes-config';\nimport styles from './dashboard-page.module.scss';\n\n\ninterface Metric {\n readonly caption: string;\n readonly href: string;\n readonly label: string;\n readonly value: string;\n}\n\nconst EMPTY_DASHBOARD_SUMMARY: WorkflowDashboardSummaryRecord = {\n activeInstanceCount: 0,\n completedInstanceCount: 0,\n overdueTaskCount: 0,\n pendingTaskCount: 0,\n rejectedInstanceCount: 0,\n totalInstanceCount: 0,\n unreadNotificationCount: 0,\n};\n\n/**\n * Operator dashboard — shows pending/unread/active counts for the\n * currently-authenticated member. Reads {@link readWorkflowDashboardSummary}\n * and renders five metric tiles that navigate via {@link useRouterAdapter}.\n */\nexport function DashboardPage(): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [summary, setSummary] = useState<WorkflowDashboardSummaryRecord>(\n EMPTY_DASHBOARD_SUMMARY,\n );\n\n const refreshSummary = useCallback(async (): Promise<void> => {\n if (!currentMemberId) {\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n setSummary(\n await readWorkflowDashboardSummary({\n currentMemberId,\n from: null,\n to: null,\n }),\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [currentMemberId]);\n\n useEffect((): void => {\n void refreshSummary();\n }, [refreshSummary]);\n\n const metrics = useMemo(\n (): readonly Metric[] => [\n {\n caption: '目前需要你處理的任務',\n href: routes.inbox(),\n label: '待處理簽核',\n value: readMetricValue(summary.pendingTaskCount, loading),\n },\n {\n // 未讀通知 — clicking the tile routes to inbox where pending\n // tasks are the most actionable next step. The notification\n // drawer bell stays available globally for in-place review.\n // (Hosts that want a dedicated /notifications page can override\n // `routes.notifications` and swap this href accordingly.)\n caption: '尚未讀取的站內通知',\n href: routes.inbox(),\n label: '未讀通知',\n value: readMetricValue(summary.unreadNotificationCount, loading),\n },\n {\n caption: '目前仍在流程中的案件',\n href: routes.search(),\n label: '進行中案件',\n value: readMetricValue(summary.activeInstanceCount, loading),\n },\n {\n caption: '已超過 SLA 的待處理任務',\n href: routes.inbox(),\n label: '逾時任務',\n value: readMetricValue(summary.overdueTaskCount, loading),\n },\n {\n caption: '你有權限查看的全部案件',\n href: routes.search(),\n label: '案件總數',\n value: readMetricValue(summary.totalInstanceCount, loading),\n },\n ],\n [loading, routes, summary],\n );\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"查看待處理簽核、近期通知與你發起的案件進度。\"\n title=\"工作台\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => router.push(routes.caseNew())}\n variant=\"base-primary\"\n >\n 發起簽核\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <CardGroup>\n {metrics.map((metric) => (\n <BaseCard\n aria-label={`前往${metric.label}`}\n className={styles.metricCard}\n description={metric.value}\n key={metric.label}\n onClick={(): void => router.push(metric.href)}\n onKeyDown={(event: KeyboardEvent<HTMLElement>): void => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n router.push(metric.href);\n }\n }}\n role=\"link\"\n tabIndex={0}\n title={metric.label}\n >\n <Typography color=\"text-neutral\" variant=\"caption\">\n {metric.caption}\n </Typography>\n </BaseCard>\n ))}\n </CardGroup>\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction readMetricValue(value: number, loading: boolean): string {\n return loading ? '-' : String(value);\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '讀取工作台摘要失敗。';\n}\n"],"mappings":"6cCgCM,EAA0D,CAC9D,oBAAqB,EACrB,uBAAwB,EACxB,iBAAkB,EAClB,iBAAkB,EAClB,sBAAuB,EACvB,mBAAoB,EACpB,wBAAyB,CAC3B,EAOA,SAAgB,GAA8B,CAC5C,IAAM,EAAS,EAAA,EAAiB,EAC1B,EAAS,EAAA,EAAa,EACtB,CAAE,UAAW,EAAA,EAAQ,EACrB,EAAkB,GAAQ,UAAY,KACtC,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAwB,IAAI,EAChD,CAAC,EAAS,IAAA,EAAc,EAAA,SAAA,CAAS,EAAI,EACrC,CAAC,EAAS,IAAA,EAAc,EAAA,SAAA,CAC5B,CACF,EAEM,GAAA,EAAiB,EAAA,YAAA,CAAY,SAA2B,CAC5D,GAAI,CAAC,EAAiB,CACpB,EAAW,EAAK,EAChB,MACF,CAEA,EAAW,EAAI,EACf,EAAS,IAAI,EAEb,GAAI,CACF,EACE,MAAA,EAAM,EAAA,6BAAA,CAA6B,CACjC,kBACA,KAAM,KACN,GAAI,IACN,CAAC,CACH,CACF,OAAS,EAAuB,CAC9B,EAAS,EAAiB,CAAY,CAAC,CACzC,QAAU,CACR,EAAW,EAAK,CAClB,CACF,EAAG,CAAC,CAAe,CAAC,GAEpB,EAAA,EAAA,UAAA,KAAsB,CACpB,EAAoB,CACtB,EAAG,CAAC,CAAc,CAAC,EAEnB,IAAM,GAAA,EAAU,EAAA,QAAA,KACW,CACvB,CACE,QAAS,aACT,KAAM,EAAO,MAAM,EACnB,MAAO,QACP,MAAO,EAAgB,EAAQ,iBAAkB,CAAO,CAC1D,EACA,CAME,QAAS,YACT,KAAM,EAAO,MAAM,EACnB,MAAO,OACP,MAAO,EAAgB,EAAQ,wBAAyB,CAAO,CACjE,EACA,CACE,QAAS,aACT,KAAM,EAAO,OAAO,EACpB,MAAO,QACP,MAAO,EAAgB,EAAQ,oBAAqB,CAAO,CAC7D,EACA,CACE,QAAS,iBACT,KAAM,EAAO,MAAM,EACnB,MAAO,OACP,MAAO,EAAgB,EAAQ,iBAAkB,CAAO,CAC1D,EACA,CACE,QAAS,cACT,KAAM,EAAO,OAAO,EACpB,MAAO,OACP,MAAO,EAAgB,EAAQ,mBAAoB,CAAO,CAC5D,CACF,EACA,CAAC,EAAS,EAAQ,CAAO,CAC3B,EAEA,OACE,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAA,WAAD,CAAA,UACE,EAAA,EAAA,IAAA,CAAC,EAAA,QAAD,CACE,YAAY,yBACZ,MAAM,MAEN,UAAA,EAAA,EAAA,IAAA,CAAC,EAAA,OAAD,CACE,KAAM,EAAA,SACN,SAAS,UACT,YAAqB,EAAO,KAAK,EAAO,QAAQ,CAAC,EACjD,QAAQ,eACT,SAAA,MAEO,CAAA,CACK,CAAA,CACL,CAAA,GAEZ,EAAA,EAAA,IAAA,CAAC,EAAA,aAAD,CAAA,UACE,EAAA,EAAA,KAAA,CAAC,EAAA,QAAD,CAAA,SAAA,CACG,GACC,EAAA,EAAA,IAAA,CAAC,EAAA,WAAD,CAAY,MAAM,aAAa,QAAQ,OACpC,SAAA,CACS,CAAA,EACV,MACJ,EAAA,EAAA,IAAA,CAAC,EAAA,UAAD,CAAA,SACG,EAAQ,IAAK,IACZ,EAAA,EAAA,IAAA,CAAC,EAAA,SAAD,CACE,aAAY,KAAK,EAAO,QACxB,UAAW,EAAO,WAClB,YAAa,EAAO,MAEpB,YAAqB,EAAO,KAAK,EAAO,IAAI,EAC5C,UAAY,GAA4C,EAClD,EAAM,MAAQ,SAAW,EAAM,MAAQ,OACzC,EAAM,eAAe,EACrB,EAAO,KAAK,EAAO,IAAI,EAE3B,EACA,KAAK,OACL,SAAU,EACV,MAAO,EAAO,MAEd,UAAA,EAAA,EAAA,IAAA,CAAC,EAAA,WAAD,CAAY,MAAM,eAAe,QAAQ,UACtC,SAAA,EAAO,OACE,CAAA,CACJ,EAfH,EAAO,KAeJ,CACX,CACQ,CAAA,CACJ,CAAA,CAAA,CACG,CAAA,CACd,CAAA,CAAA,CAEN,CAEA,SAAS,EAAgB,EAAe,EAA0B,CAChE,OAAO,EAAU,IAAM,OAAO,CAAK,CACrC,CAEA,SAAS,EAAiB,EAAwB,CAChD,OAAO,aAAiB,MAAQ,EAAM,QAAU,YAClD"}
@@ -1,2 +0,0 @@
1
- "use client";require('../delegations2.css');const e=require("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./auth-provider-4BeCw7cI.cjs"),n=require("./format-date-time-D-cx5M8z.cjs"),r=require("./bpm-form-field-Bc6k4ZEO.cjs");let i=require("react"),a=require("@mezzanine-ui/react"),o=require("react/jsx-runtime"),s=require("@rytass/bpm-core-client/workflow"),c=require("@mezzanine-ui/core/form"),l=require("@mezzanine-ui/react/ContentHeader");l=e.t(l,1);let ee=require("@mezzanine-ui/icons"),te=require("@rytass/bpm-core-client/template");var u={delegationFilterArea:`bpm_delegationFilterArea_hAA4C`,delegationModalFields:`bpm_delegationModalFields_1aOVW`,memberNameWithTooltip:`bpm_memberNameWithTooltip_6Mojc`},d=c.FormFieldLayout.HORIZONTAL,ne=[10,20,50],re=[{key:`ALL`,label:`全部`},{key:`ACTIVE`,label:`啟用中`},{key:`REVOKED`,label:`已撤銷`},{key:`EXPIRED`,label:`已過期`}],f=[{id:`ALL_SCOPES`,name:`全部範圍`,scopeType:null},{id:`ALL`,name:`全部簽核`,scopeType:`ALL`},{id:`TEMPLATE_LIST`,name:`指定模板`,scopeType:`TEMPLATE_LIST`}],p=[{id:`ALL`,name:`全部簽核`},{id:`TEMPLATE_LIST`,name:`指定模板`}];function m(){let{member:e}=t.n(),d=e?.memberId??null,[m,g]=(0,i.useState)(null),[_,y]=(0,i.useState)(``),[S,C]=(0,i.useState)(null),[w,E]=(0,i.useState)(!0),[he,D]=(0,i.useState)(!1),[O,k]=(0,i.useState)([]),[ge,A]=(0,i.useState)(!1),[j,M]=(0,i.useState)(1),[N,_e]=(0,i.useState)(10),[P,ve]=(0,i.useState)(`ALL`),[ye,be]=(0,i.useState)(0),[F,xe]=(0,i.useState)([]),[I,L]=(0,i.useState)(!1),[R,Se]=(0,i.useState)(f[0]),[z,B]=(0,i.useState)([]),[Ce,V]=(0,i.useState)(p[0]),[H,U]=(0,i.useState)(``),[we,W]=(0,i.useState)(!1),[Te,G]=(0,i.useState)([]),K=(0,i.useRef)(0),q=(0,i.useCallback)(async()=>{let e=K.current+1;if(K.current=e,!d){E(!1);return}E(!0),C(null);try{let[t,n]=await Promise.all([(0,s.listDelegationRulesPage)({includeInactive:!0,page:j,pageSize:N,principalMemberId:d,scopeType:R.scopeType,status:P===`ALL`?null:P}),(0,s.searchMembers)(``)]);e===K.current&&(xe(t.rules),be(t.totalCount),k(n.map(h)))}catch(t){e===K.current&&C(T(t))}finally{e===K.current&&E(!1)}},[d,j,N,P,R]);(0,i.useEffect)(()=>{q()},[q]);let J=(0,i.useMemo)(()=>new Map(O.map(e=>[e.id,e])),[O]),Ee=(0,i.useMemo)(()=>F.map(e=>({...e,agentEmail:J.get(e.agentMemberId)?.email??null,agentName:J.get(e.agentMemberId)?.displayName??e.agentMemberId,key:e.id,scopeLabel:ue(e)})),[J,F]),Y=p.find(e=>e.id===Ce.id)??p[0],X=(0,i.useMemo)(()=>[{key:`agent`,render:e=>(0,o.jsx)(ae,{email:e.agentEmail,name:e.agentName}),title:`代理人`,width:220},{dataIndex:`scopeLabel`,key:`scope`,title:`代理範圍`,width:220},{key:`status`,render:e=>(0,o.jsx)(fe,{status:e.status}),title:`狀態`,width:120},{key:`startAt`,render:e=>(0,o.jsx)(a.Typography,{component:`span`,variant:`body`,children:n.t(e.startAt)}),title:`開始時間`,width:220},{key:`endAt`,render:e=>(0,o.jsx)(a.Typography,{component:`span`,variant:`body`,children:e.endAt?n.t(e.endAt):`-`}),title:`結束時間`,width:220}],[]),Z=(0,i.useCallback)(async e=>{if(d){C(null);try{await(0,s.revokeDelegationRule)({id:e,revokedByMemberId:d}),await q()}catch(e){C(T(e))}}},[d,q]),De=(0,i.useMemo)(()=>({render:e=>e.status===`ACTIVE`?[{name:`撤銷`,onClick:()=>void Z(e.id)}]:[],variant:`destructive-secondary`,width:88}),[Z]);async function Oe(e){D(!0);try{k((await(0,s.searchMembers)(e)).map(h))}catch(e){C(T(e))}finally{D(!1)}}async function Q(e,t=z){W(!0);try{let n=(await(0,te.listApprovalTemplates)()).map(oe);G(v(t,ce(n,e)))}catch(e){C(T(e))}finally{W(!1)}}function ke(){g(null),y(``),B([]),V(p[0]),U(``),G([]),Q(``,[]),A(!0)}function $(){I||A(!1)}async function Ae(){if(d){if(!m){C(`請選擇代理人`);return}if(m.id===d){C(`代理人不可設定為自己`);return}if(Y.id===`TEMPLATE_LIST`&&z.length<1){C(`請選擇至少一個簽核模板`);return}if(me(H,_)){C(`結束時間必須晚於起始時間`);return}L(!0),C(null);try{await(0,s.createDelegationRule)({agentMemberId:m.id,createdByMemberId:d,endAt:_||null,principalMemberId:d,priority:100,requiresConfirmation:!1,scopeConditionCel:null,scopeTemplateIds:Y.id===`TEMPLATE_LIST`?z.map(e=>e.id):[],scopeType:Y.id,startAt:H||null}),A(!1),j===1?await q():M(1)}catch(e){C(T(e))}finally{L(!1)}}}return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(a.PageHeader,{children:(0,o.jsx)(l.default,{description:`設定自己的簽核代理,讓指定期間內的新待簽任務自動交由代理人處理。`,title:`我的代理`,children:(0,o.jsx)(a.Button,{icon:ee.PlusIcon,iconType:`leading`,onClick:ke,variant:`base-primary`,children:`建立代理`})})}),(0,o.jsx)(a.SectionGroup,{children:(0,o.jsxs)(a.Section,{filterArea:(0,o.jsx)(a.FilterArea,{className:u.delegationFilterArea,size:`sub`,children:(0,o.jsx)(a.FilterLine,{children:(0,o.jsx)(a.Filter,{span:2,children:(0,o.jsx)(a.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`scopeFilterType`,children:(0,o.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>{Se(le(e)),M(1)},options:[...f],placeholder:`代理範圍`,size:`sub`,value:R})})})})}),tab:(0,o.jsx)(a.Tab,{activeKey:P,onChange:e=>{ve(pe(e)),M(1)},children:re.map(e=>(0,o.jsx)(a.TabItem,{children:e.label},e.key))}),children:[S?(0,o.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:S}):null,(0,o.jsx)(a.Table,{actions:De,columns:X,dataSource:Ee,fullWidth:!0,loading:w,pagination:{current:j,onChange:e=>{M(e)},onChangePageSize:e=>{M(1),_e(e)},pageSize:N,pageSizeLabel:`每頁筆數`,pageSizeOptions:ne,renderResultSummary:(e,t,n)=>`顯示 ${e}-${t} 筆,共 ${n} 筆`,showPageSizeOptions:!0,total:ye}})]})}),(0,o.jsx)(a.Modal,{cancelText:`取消`,confirmButtonProps:{disabled:!m},confirmText:`建立代理`,loading:I,modalType:`standard`,onCancel:$,onClose:$,onConfirm:()=>void Ae(),open:ge,showModalFooter:!0,showModalHeader:!0,size:`regular`,supportingText:`代理生效後,後續建立的待簽任務會依範圍自動指派給代理人。`,title:`建立個人代理`,children:(0,o.jsxs)(`div`,{className:u.delegationModalFields,children:[(0,o.jsx)(ie,{label:`代理人`,loading:he,name:`agentMemberId`,onChange:g,onSearch:Oe,options:O,value:m}),(0,o.jsx)(r.t,{label:`代理範圍`,name:`scopeType`,required:!0,children:(0,o.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>V(de(e)),options:[...p],placeholder:`選擇代理範圍`,value:Y})}),Y.id===`TEMPLATE_LIST`?(0,o.jsx)(r.t,{label:`簽核模板`,name:`scopeTemplateIds`,required:!0,children:(0,o.jsx)(a.AutoComplete,{asyncData:!0,disabledOptionsFilter:!0,emptyText:`沒有符合的模板`,inputProps:{autoCapitalize:`none`,autoCorrect:`off`,name:`scopeTemplateIds`,spellCheck:!1},loading:we,loadingText:`搜尋模板中...`,mode:`multiple`,onChange:e=>{let t=se(e);B(t),G(e=>v(t,e))},onSearch:Q,onVisibilityChange:e=>{e&&Q(``)},options:[...Te],overflowStrategy:`wrap`,placeholder:`搜尋並選取簽核模板`,searchDebounceTime:300,value:[...z]})}):null,(0,o.jsx)(r.t,{label:`起始時間`,name:`startAt`,children:(0,o.jsx)(a.DateTimePicker,{formatDate:`YYYY-MM-DD`,formatTime:`HH:mm`,fullWidth:!0,hideSecond:!0,onChange:e=>U(x(e)),placeholderLeft:`留空立即生效`,placeholderRight:`選擇時間`,value:b(H)})}),(0,o.jsx)(r.t,{label:`結束時間`,name:`endAt`,children:(0,o.jsx)(a.DateTimePicker,{formatDate:`YYYY-MM-DD`,formatTime:`HH:mm`,fullWidth:!0,hideSecond:!0,onChange:e=>y(x(e)),placeholderLeft:`可留空`,placeholderRight:`選擇時間`,value:b(_)})})]})})]})}function ie({label:e,loading:t,name:n,onChange:i,onSearch:s,options:c,value:l}){return(0,o.jsx)(r.t,{label:e,layout:d,name:n,required:!0,children:(0,o.jsx)(a.AutoComplete,{asyncData:!0,disabledOptionsFilter:!0,emptyText:`沒有符合的成員`,inputProps:{autoCapitalize:`none`,autoCorrect:`off`,name:n,spellCheck:!1},loading:t,loadingText:`搜尋成員中...`,mode:`single`,onChange:e=>i(g(e)),onSearch:s,onSearchTextChange:e=>i(_(e,c)),onVisibilityChange:e=>{e&&s(``)},options:[...c],placeholder:`搜尋姓名或信箱`,searchDebounceTime:300,value:l})})}function ae({email:e,name:t}){return e?(0,o.jsx)(a.Tooltip,{title:e,children:({ref:e,...n})=>(0,o.jsx)(`span`,{...n,className:u.memberNameWithTooltip,ref:e,children:t})}):(0,o.jsx)(`span`,{children:t})}function h(e){return{displayName:e.name,email:e.email,id:e.memberId,name:`${e.name} (${e.email})`}}function g(e){if(!E(e))return null;let t=e.displayName,n=e.email,r=e.id,i=e.name;return typeof r==`string`&&typeof i==`string`?{displayName:typeof t==`string`?t:i,email:typeof n==`string`?n:null,id:r,name:i}:null}function _(e,t){let n=e.trim().toLocaleLowerCase();if(!n)return null;let r=t.filter(e=>[e.id,e.name,e.email??``].some(e=>e.toLocaleLowerCase().includes(n)));return r.length===1?r[0]??null:null}function oe(e){return{id:e.id,name:e.name}}function se(e){return e.flatMap(e=>{if(!E(e))return[];let t=e.id,n=e.name;return typeof t==`string`&&typeof n==`string`?[{id:t,name:n}]:[]})}function ce(e,t){let n=t.trim().toLocaleLowerCase();return n?e.filter(e=>[e.id,e.name].some(e=>e.toLocaleLowerCase().includes(n))):e}function v(e,t){return[...e,...t].reduce((e,t)=>e.some(e=>e.id===t.id)?e:[...e,t],[])}function le(e){if(!E(e))return f[0];let t=e.id;return f.find(e=>e.id===t)??f[0]}function ue(e){return e.scopeType===`ALL`?`全部簽核`:e.scopeType===`TEMPLATE_LIST`?`指定模板:${e.scopeTemplateIds.length}`:e.scopeConditionCel?`條件:${e.scopeConditionCel}`:`條件式`}function de(e){return!E(e)||!y(e.id)?p[0]:p.find(t=>t.id===e.id)??p[0]}function y(e){return e===`ALL`||e===`TEMPLATE_LIST`}function fe({status:e}){return e===`ACTIVE`?(0,o.jsx)(a.Badge,{size:`sub`,text:`啟用中`,variant:`dot-success`}):e===`REVOKED`?(0,o.jsx)(a.Badge,{size:`sub`,text:`已撤銷`,variant:`dot-inactive`}):e===`EXPIRED`?(0,o.jsx)(a.Badge,{size:`sub`,text:`已過期`,variant:`dot-warning`}):(0,o.jsx)(a.Badge,{size:`sub`,text:e,variant:`dot-info`})}function pe(e){return e===`ACTIVE`||e===`REVOKED`||e===`EXPIRED`?e:`ALL`}function b(e){let t=e?S(e):null;return t?`${C(t)}T${w(t.getHours())}:${w(t.getMinutes())}`:void 0}function x(e){let t=e?S(e):null;return t?t.toISOString():``}function me(e,t){if(!e||!t)return!1;let n=S(e),r=S(t);return!!n&&!!r&&r.getTime()<=n.getTime()}function S(e){if(e.endsWith(`Z`)||/[+-]\d{2}:\d{2}$/.test(e)){let t=new Date(e);return Number.isNaN(t.getTime())?null:t}let[t=``,n=`00:00`]=e.split(`T`),[r=0,i=1,a=1]=t.split(`-`).map(Number),[o=0,s=0]=n.split(`:`).map(Number),c=new Date(r,i-1,a,o,s);return Number.isNaN(c.getTime())?null:c}function C(e){return`${e.getFullYear()}-${w(e.getMonth()+1)}-${w(e.getDate())}`}function w(e){return String(e).padStart(2,`0`)}function T(e){return e instanceof Error?e.message:`發生未知錯誤`}function E(e){return typeof e==`object`&&!!e}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return m}});
2
- //# sourceMappingURL=delegations-8LsxcQM4.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"delegations-8LsxcQM4.cjs","names":[],"sources":["../../src/views/delegations/delegations.module.scss","../../src/views/delegations/DelegationsView.tsx"],"sourcesContent":[".delegationFilterArea {\n :global(.mzn-filter-area__actions) {\n display: none;\n }\n\n :global(.mzn-form-field__label-area) {\n display: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n}\n\n.delegationModalFields {\n display: grid;\n gap: 12px;\n width: 100%;\n\n :global(.mzn-form-field--horizontal) {\n align-items: flex-start;\n }\n\n :global(.mzn-form-field--horizontal .mzn-form-field__label-area) {\n flex: 0 0 112px;\n width: 112px;\n min-width: 112px;\n white-space: nowrap;\n }\n\n :global(.mzn-form-field--horizontal .mzn-form-field__label) {\n flex-wrap: nowrap;\n white-space: nowrap;\n }\n\n :global(.mzn-form-field--horizontal .mzn-form-field__data-entry) {\n flex: 1 1 auto;\n align-items: stretch;\n min-width: 0;\n max-width: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n\n :global(.mzn-autocomplete) {\n width: 100%;\n min-width: 0;\n }\n\n :global(.mzn-input),\n :global(.mzn-input-container),\n :global(.mzn-picker),\n :global(.mzn-select),\n :global(.mzn-select-trigger),\n :global(.mzn-text-field) {\n width: 100%;\n min-width: 0 !important;\n }\n\n :global(.mzn-select-trigger__input) {\n width: 100%;\n min-width: 0 !important;\n text-overflow: ellipsis;\n }\n}\n\n.memberNameWithTooltip {\n cursor: help;\n text-decoration: underline dotted;\n text-underline-offset: 3px;\n}\n","'use client';\n\nimport {\n Key,\n ReactElement,\n RefCallback,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n AutoComplete,\n Badge,\n Button,\n DateTimePicker,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Select,\n Tab,\n TabItem,\n Table,\n Tooltip,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { PlusIcon } from '@mezzanine-ui/icons';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { BPMFormField } from '../../components/bpm-form-field';\nimport { formatDateTime } from '../../lib/format-date-time';\nimport { useAuth } from '../../lib/auth-provider';\nimport {\n DelegationRuleRecord,\n DelegationRuleStatus,\n DelegationScopeType,\n MemberProfileRecord,\n createDelegationRule,\n listDelegationRulesPage,\n revokeDelegationRule,\n searchMembers,\n} from '@rytass/bpm-core-client/workflow';\nimport {\n ApprovalTemplateRecord,\n listApprovalTemplates,\n} from '@rytass/bpm-core-client/template';\nimport styles from './delegations.module.scss';\n\ntype DelegationStatusTabKey = 'ALL' | DelegationRuleStatus;\n\ntype MemberOption = Readonly<{\n displayName: string;\n email: string | null;\n id: string;\n name: string;\n}>;\n\ntype ScopeOption = Readonly<{\n id: DelegationScopeType;\n name: string;\n}>;\n\ntype ScopeFilterOption = Readonly<{\n id: 'ALL_SCOPES' | DelegationScopeType;\n name: string;\n scopeType: DelegationScopeType | null;\n}>;\n\ntype TemplateOption = Readonly<{\n id: string;\n name: string;\n}>;\n\ntype DelegationRuleRow = Readonly<\n Record<string, unknown> &\n DelegationRuleRecord & {\n agentEmail: string | null;\n agentName: string;\n key: string;\n scopeLabel: string;\n }\n>;\n\nconst DELEGATION_MODAL_FIELD_LAYOUT = FormFieldLayout.HORIZONTAL;\nconst DELEGATION_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst DELEGATION_STATUS_TABS: readonly {\n readonly key: DelegationStatusTabKey;\n readonly label: string;\n}[] = [\n { key: 'ALL', label: '全部' },\n { key: 'ACTIVE', label: '啟用中' },\n { key: 'REVOKED', label: '已撤銷' },\n { key: 'EXPIRED', label: '已過期' },\n];\nconst SCOPE_FILTER_OPTIONS: readonly ScopeFilterOption[] = [\n { id: 'ALL_SCOPES', name: '全部範圍', scopeType: null },\n { id: 'ALL', name: '全部簽核', scopeType: 'ALL' },\n { id: 'TEMPLATE_LIST', name: '指定模板', scopeType: 'TEMPLATE_LIST' },\n];\nconst SCOPE_OPTIONS: readonly ScopeOption[] = [\n { id: 'ALL', name: '全部簽核' },\n { id: 'TEMPLATE_LIST', name: '指定模板' },\n];\n\nexport function DelegationsView(): ReactElement {\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [agentMember, setAgentMember] = useState<MemberOption | null>(null);\n const [endAt, setEndAt] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [memberLoading, setMemberLoading] = useState(false);\n const [memberOptions, setMemberOptions] = useState<readonly MemberOption[]>(\n [],\n );\n const [modalOpen, setModalOpen] = useState(false);\n const [rulePage, setRulePage] = useState(1);\n const [rulePageSize, setRulePageSize] = useState(10);\n const [ruleStatus, setRuleStatus] = useState<DelegationStatusTabKey>('ALL');\n const [ruleTotalCount, setRuleTotalCount] = useState(0);\n const [rules, setRules] = useState<readonly DelegationRuleRecord[]>([]);\n const [saving, setSaving] = useState(false);\n const [scopeFilterType, setScopeFilterType] = useState<ScopeFilterOption>(\n SCOPE_FILTER_OPTIONS[0],\n );\n const [scopeTemplates, setScopeTemplates] = useState<\n readonly TemplateOption[]\n >([]);\n const [scopeType, setScopeType] = useState<ScopeOption>(SCOPE_OPTIONS[0]);\n const [startAt, setStartAt] = useState('');\n const [templateLoading, setTemplateLoading] = useState(false);\n const [templateOptions, setTemplateOptions] = useState<\n readonly TemplateOption[]\n >([]);\n const refreshRequestIdRef = useRef(0);\n\n const refreshRules = useCallback(async (): Promise<void> => {\n const requestId = refreshRequestIdRef.current + 1;\n refreshRequestIdRef.current = requestId;\n\n if (!currentMemberId) {\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const [rulePageResult, members] = await Promise.all([\n listDelegationRulesPage({\n includeInactive: true,\n page: rulePage,\n pageSize: rulePageSize,\n principalMemberId: currentMemberId,\n scopeType: scopeFilterType.scopeType,\n status: ruleStatus === 'ALL' ? null : ruleStatus,\n }),\n searchMembers(''),\n ]);\n\n if (requestId === refreshRequestIdRef.current) {\n setRules(rulePageResult.rules);\n setRuleTotalCount(rulePageResult.totalCount);\n setMemberOptions(members.map(readMemberOption));\n }\n } catch (requestError: unknown) {\n if (requestId === refreshRequestIdRef.current) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (requestId === refreshRequestIdRef.current) {\n setLoading(false);\n }\n }\n }, [currentMemberId, rulePage, rulePageSize, ruleStatus, scopeFilterType]);\n\n useEffect((): void => {\n void refreshRules();\n }, [refreshRules]);\n\n const membersById = useMemo(\n (): ReadonlyMap<string, MemberOption> =>\n new Map(memberOptions.map((option) => [option.id, option])),\n [memberOptions],\n );\n const rows = useMemo(\n (): DelegationRuleRow[] =>\n rules.map((rule) => ({\n ...rule,\n agentEmail: membersById.get(rule.agentMemberId)?.email ?? null,\n agentName:\n membersById.get(rule.agentMemberId)?.displayName ??\n rule.agentMemberId,\n key: rule.id,\n scopeLabel: readScopeLabel(rule),\n })),\n [membersById, rules],\n );\n const selectedScopeType =\n SCOPE_OPTIONS.find((option) => option.id === scopeType.id) ??\n SCOPE_OPTIONS[0];\n const columns = useMemo(\n (): TableColumn<DelegationRuleRow>[] => [\n {\n key: 'agent',\n render: (record: DelegationRuleRow): ReactElement => (\n <MemberNameWithEmailTooltip\n email={record.agentEmail}\n name={record.agentName}\n />\n ),\n title: '代理人',\n width: 220,\n },\n { dataIndex: 'scopeLabel', key: 'scope', title: '代理範圍', width: 220 },\n {\n key: 'status',\n render: (record: DelegationRuleRow): ReactElement => (\n <DelegationStatusBadge status={record.status} />\n ),\n title: '狀態',\n width: 120,\n },\n {\n key: 'startAt',\n render: (record: DelegationRuleRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.startAt)}\n </Typography>\n ),\n title: '開始時間',\n width: 220,\n },\n {\n key: 'endAt',\n render: (record: DelegationRuleRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {record.endAt ? formatDateTime(record.endAt) : '-'}\n </Typography>\n ),\n title: '結束時間',\n width: 220,\n },\n ],\n [],\n );\n const handleRevoke = useCallback(\n async (id: string): Promise<void> => {\n if (!currentMemberId) {\n return;\n }\n\n setError(null);\n\n try {\n await revokeDelegationRule({\n id,\n revokedByMemberId: currentMemberId,\n });\n await refreshRules();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n }\n },\n [currentMemberId, refreshRules],\n );\n const tableActions = useMemo(\n (): TableActions<DelegationRuleRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<DelegationRuleRow>['render']> =>\n record.status === 'ACTIVE'\n ? [\n {\n name: '撤銷',\n onClick: (): void => void handleRevoke(record.id),\n },\n ]\n : [],\n variant: 'destructive-secondary',\n width: 88,\n }),\n [handleRevoke],\n );\n\n async function handleSearchMembers(searchText: string): Promise<void> {\n setMemberLoading(true);\n\n try {\n setMemberOptions((await searchMembers(searchText)).map(readMemberOption));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setMemberLoading(false);\n }\n }\n\n async function handleSearchTemplates(\n searchText: string,\n selectedOptions: readonly TemplateOption[] = scopeTemplates,\n ): Promise<void> {\n setTemplateLoading(true);\n\n try {\n const nextOptions = (await listApprovalTemplates()).map(\n readTemplateOption,\n );\n\n setTemplateOptions(\n mergeTemplateOptions(\n selectedOptions,\n filterTemplateOptions(nextOptions, searchText),\n ),\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setTemplateLoading(false);\n }\n }\n\n function openCreateModal(): void {\n setAgentMember(null);\n setEndAt('');\n setScopeTemplates([]);\n setScopeType(SCOPE_OPTIONS[0]);\n setStartAt('');\n setTemplateOptions([]);\n void handleSearchTemplates('', []);\n setModalOpen(true);\n }\n\n function closeCreateModal(): void {\n if (saving) {\n return;\n }\n\n setModalOpen(false);\n }\n\n async function handleCreate(): Promise<void> {\n if (!currentMemberId) {\n return;\n }\n\n if (!agentMember) {\n setError('請選擇代理人');\n return;\n }\n\n if (agentMember.id === currentMemberId) {\n setError('代理人不可設定為自己');\n return;\n }\n\n if (selectedScopeType.id === 'TEMPLATE_LIST' && scopeTemplates.length < 1) {\n setError('請選擇至少一個簽核模板');\n return;\n }\n\n if (isInvalidDelegationDateRange(startAt, endAt)) {\n setError('結束時間必須晚於起始時間');\n return;\n }\n\n setSaving(true);\n setError(null);\n\n try {\n await createDelegationRule({\n agentMemberId: agentMember.id,\n createdByMemberId: currentMemberId,\n endAt: endAt || null,\n principalMemberId: currentMemberId,\n priority: 100,\n requiresConfirmation: false,\n scopeConditionCel: null,\n scopeTemplateIds:\n selectedScopeType.id === 'TEMPLATE_LIST'\n ? scopeTemplates.map((template) => template.id)\n : [],\n scopeType: selectedScopeType.id,\n startAt: startAt || null,\n });\n setModalOpen(false);\n\n if (rulePage === 1) {\n await refreshRules();\n } else {\n setRulePage(1);\n }\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSaving(false);\n }\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"設定自己的簽核代理,讓指定期間內的新待簽任務自動交由代理人處理。\"\n title=\"我的代理\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={openCreateModal}\n variant=\"base-primary\"\n >\n 建立代理\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.delegationFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"scopeFilterType\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void => {\n setScopeFilterType(readScopeFilterOption(option));\n setRulePage(1);\n }}\n options={[...SCOPE_FILTER_OPTIONS]}\n placeholder=\"代理範圍\"\n size=\"sub\"\n value={scopeFilterType}\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n tab={\n <Tab\n activeKey={ruleStatus}\n onChange={(activeKey): void => {\n setRuleStatus(readDelegationStatusTabKey(activeKey));\n setRulePage(1);\n }}\n >\n {DELEGATION_STATUS_TABS.map((statusTab) => (\n <TabItem key={statusTab.key}>{statusTab.label}</TabItem>\n ))}\n </Tab>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n pagination={{\n current: rulePage,\n onChange: (page): void => {\n setRulePage(page);\n },\n onChangePageSize: (pageSize): void => {\n setRulePage(1);\n setRulePageSize(pageSize);\n },\n pageSize: rulePageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: DELEGATION_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: ruleTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{\n disabled: !agentMember,\n }}\n confirmText=\"建立代理\"\n loading={saving}\n modalType=\"standard\"\n onCancel={closeCreateModal}\n onClose={closeCreateModal}\n onConfirm={(): void => void handleCreate()}\n open={modalOpen}\n showModalFooter\n showModalHeader\n size=\"regular\"\n supportingText=\"代理生效後,後續建立的待簽任務會依範圍自動指派給代理人。\"\n title=\"建立個人代理\"\n >\n <div className={styles.delegationModalFields}>\n <MemberAutoCompleteField\n label=\"代理人\"\n loading={memberLoading}\n name=\"agentMemberId\"\n onChange={setAgentMember}\n onSearch={handleSearchMembers}\n options={memberOptions}\n value={agentMember}\n />\n <BPMFormField label=\"代理範圍\" name=\"scopeType\" required>\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void =>\n setScopeType(readScopeOptionFromValue(option))\n }\n options={[...SCOPE_OPTIONS]}\n placeholder=\"選擇代理範圍\"\n value={selectedScopeType}\n />\n </BPMFormField>\n {selectedScopeType.id === 'TEMPLATE_LIST' ? (\n <BPMFormField label=\"簽核模板\" name=\"scopeTemplateIds\" required>\n <AutoComplete\n asyncData\n disabledOptionsFilter\n emptyText=\"沒有符合的模板\"\n inputProps={{\n autoCapitalize: 'none',\n autoCorrect: 'off',\n name: 'scopeTemplateIds',\n spellCheck: false,\n }}\n loading={templateLoading}\n loadingText=\"搜尋模板中...\"\n mode=\"multiple\"\n onChange={(nextTemplates): void => {\n const selectedTemplates =\n readTemplateOptionsFromValue(nextTemplates);\n\n setScopeTemplates(selectedTemplates);\n setTemplateOptions((currentOptions) =>\n mergeTemplateOptions(selectedTemplates, currentOptions),\n );\n }}\n onSearch={handleSearchTemplates}\n onVisibilityChange={(open): void => {\n if (open) {\n void handleSearchTemplates('');\n }\n }}\n options={[...templateOptions]}\n overflowStrategy=\"wrap\"\n placeholder=\"搜尋並選取簽核模板\"\n searchDebounceTime={300}\n value={[...scopeTemplates]}\n />\n </BPMFormField>\n ) : null}\n <BPMFormField label=\"起始時間\" name=\"startAt\">\n <DateTimePicker\n formatDate=\"YYYY-MM-DD\"\n formatTime=\"HH:mm\"\n fullWidth\n hideSecond\n onChange={(nextValue): void =>\n setStartAt(formatDelegationDateTimePickerValue(nextValue))\n }\n placeholderLeft=\"留空立即生效\"\n placeholderRight=\"選擇時間\"\n value={readDelegationDateTimePickerValue(startAt)}\n />\n </BPMFormField>\n <BPMFormField label=\"結束時間\" name=\"endAt\">\n <DateTimePicker\n formatDate=\"YYYY-MM-DD\"\n formatTime=\"HH:mm\"\n fullWidth\n hideSecond\n onChange={(nextValue): void =>\n setEndAt(formatDelegationDateTimePickerValue(nextValue))\n }\n placeholderLeft=\"可留空\"\n placeholderRight=\"選擇時間\"\n value={readDelegationDateTimePickerValue(endAt)}\n />\n </BPMFormField>\n </div>\n </Modal>\n </>\n );\n}\n\nfunction MemberAutoCompleteField({\n label,\n loading,\n name,\n onChange,\n onSearch,\n options,\n value,\n}: {\n readonly label: string;\n readonly loading: boolean;\n readonly name: string;\n readonly onChange: (option: MemberOption | null) => void;\n readonly onSearch: (searchText: string) => Promise<void>;\n readonly options: readonly MemberOption[];\n readonly value: MemberOption | null;\n}): ReactElement {\n return (\n <BPMFormField\n label={label}\n layout={DELEGATION_MODAL_FIELD_LAYOUT}\n name={name}\n required\n >\n <AutoComplete\n asyncData\n disabledOptionsFilter\n emptyText=\"沒有符合的成員\"\n inputProps={{\n autoCapitalize: 'none',\n autoCorrect: 'off',\n name,\n spellCheck: false,\n }}\n loading={loading}\n loadingText=\"搜尋成員中...\"\n mode=\"single\"\n onChange={(option): void => onChange(readMemberOptionFromValue(option))}\n onSearch={onSearch}\n onSearchTextChange={(searchText): void =>\n onChange(readUniqueMemberOption(searchText, options))\n }\n onVisibilityChange={(open): void => {\n if (open) {\n void onSearch('');\n }\n }}\n options={[...options]}\n placeholder=\"搜尋姓名或信箱\"\n searchDebounceTime={300}\n value={value}\n />\n </BPMFormField>\n );\n}\n\nfunction MemberNameWithEmailTooltip({\n email,\n name,\n}: {\n readonly email: string | null;\n readonly name: string;\n}): ReactElement {\n if (!email) {\n return <span>{name}</span>;\n }\n\n return (\n <Tooltip title={email}>\n {({ ref, ...tooltipProps }): ReactElement => (\n // Spread the whole payload, as `TooltipProps` asks: picking only the\n // mouse handlers drops `aria-describedby`, so assistive tech never\n // learns the open tooltip describes this name.\n <span\n {...tooltipProps}\n className={styles.memberNameWithTooltip}\n ref={ref as RefCallback<HTMLSpanElement>}\n >\n {name}\n </span>\n )}\n </Tooltip>\n );\n}\n\nfunction readMemberOption(member: MemberProfileRecord): MemberOption {\n return {\n displayName: member.name,\n email: member.email,\n id: member.memberId,\n name: `${member.name} (${member.email})`,\n };\n}\n\nfunction readMemberOptionFromValue(value: unknown): MemberOption | null {\n if (!isRecord(value)) {\n return null;\n }\n\n const displayName = value.displayName;\n const email = value.email;\n const id = value.id;\n const name = value.name;\n\n return typeof id === 'string' && typeof name === 'string'\n ? {\n displayName: typeof displayName === 'string' ? displayName : name,\n email: typeof email === 'string' ? email : null,\n id,\n name,\n }\n : null;\n}\n\nfunction readUniqueMemberOption(\n searchText: string,\n options: readonly MemberOption[],\n): MemberOption | null {\n const normalizedSearchText = searchText.trim().toLocaleLowerCase();\n\n if (!normalizedSearchText) {\n return null;\n }\n\n const matches = options.filter((option) =>\n [option.id, option.name, option.email ?? ''].some((value) =>\n value.toLocaleLowerCase().includes(normalizedSearchText),\n ),\n );\n\n return matches.length === 1 ? (matches[0] ?? null) : null;\n}\n\nfunction readTemplateOption(template: ApprovalTemplateRecord): TemplateOption {\n return {\n id: template.id,\n name: template.name,\n };\n}\n\nfunction readTemplateOptionsFromValue(\n value: readonly unknown[],\n): readonly TemplateOption[] {\n return value.flatMap((item): readonly TemplateOption[] => {\n if (!isRecord(item)) {\n return [];\n }\n\n const id = item.id;\n const name = item.name;\n\n return typeof id === 'string' && typeof name === 'string'\n ? [{ id, name }]\n : [];\n });\n}\n\nfunction filterTemplateOptions(\n options: readonly TemplateOption[],\n searchText: string,\n): readonly TemplateOption[] {\n const normalizedSearchText = searchText.trim().toLocaleLowerCase();\n\n if (!normalizedSearchText) {\n return options;\n }\n\n return options.filter((option) =>\n [option.id, option.name].some((value) =>\n value.toLocaleLowerCase().includes(normalizedSearchText),\n ),\n );\n}\n\nfunction mergeTemplateOptions(\n selectedOptions: readonly TemplateOption[],\n availableOptions: readonly TemplateOption[],\n): readonly TemplateOption[] {\n return [...selectedOptions, ...availableOptions].reduce<TemplateOption[]>(\n (options, option) =>\n options.some((currentOption) => currentOption.id === option.id)\n ? options\n : [...options, option],\n [],\n );\n}\n\nfunction readScopeFilterOption(value: unknown): ScopeFilterOption {\n if (!isRecord(value)) {\n return SCOPE_FILTER_OPTIONS[0];\n }\n\n const id = value.id;\n\n return (\n SCOPE_FILTER_OPTIONS.find((option) => option.id === id) ??\n SCOPE_FILTER_OPTIONS[0]\n );\n}\n\nfunction readScopeLabel(rule: DelegationRuleRecord): string {\n if (rule.scopeType === 'ALL') {\n return '全部簽核';\n }\n\n if (rule.scopeType === 'TEMPLATE_LIST') {\n return `指定模板:${rule.scopeTemplateIds.length}`;\n }\n\n return rule.scopeConditionCel ? `條件:${rule.scopeConditionCel}` : '條件式';\n}\n\nfunction readScopeOptionFromValue(value: unknown): ScopeOption {\n if (!isRecord(value) || !isSelectableDelegationScopeType(value.id)) {\n return SCOPE_OPTIONS[0];\n }\n\n return (\n SCOPE_OPTIONS.find((option) => option.id === value.id) ?? SCOPE_OPTIONS[0]\n );\n}\n\nfunction isSelectableDelegationScopeType(\n value: unknown,\n): value is ScopeOption['id'] {\n return value === 'ALL' || value === 'TEMPLATE_LIST';\n}\n\nfunction DelegationStatusBadge({\n status,\n}: {\n readonly status: DelegationRuleRecord['status'];\n}): ReactElement {\n if (status === 'ACTIVE') {\n return <Badge size=\"sub\" text=\"啟用中\" variant=\"dot-success\" />;\n }\n\n if (status === 'REVOKED') {\n return <Badge size=\"sub\" text=\"已撤銷\" variant=\"dot-inactive\" />;\n }\n\n if (status === 'EXPIRED') {\n return <Badge size=\"sub\" text=\"已過期\" variant=\"dot-warning\" />;\n }\n\n return <Badge size=\"sub\" text={status} variant=\"dot-info\" />;\n}\n\nfunction readDelegationStatusTabKey(activeKey: Key): DelegationStatusTabKey {\n if (\n activeKey === 'ACTIVE' ||\n activeKey === 'REVOKED' ||\n activeKey === 'EXPIRED'\n ) {\n return activeKey;\n }\n\n return 'ALL';\n}\n\nfunction readDelegationDateTimePickerValue(value: string): string | undefined {\n const date = value ? parseDelegationDateTimeValue(value) : null;\n\n return date\n ? `${formatDateParts(date)}T${padDatePart(date.getHours())}:${padDatePart(\n date.getMinutes(),\n )}`\n : undefined;\n}\n\nfunction formatDelegationDateTimePickerValue(\n value: string | undefined,\n): string {\n const date = value ? parseDelegationDateTimeValue(value) : null;\n\n return date ? date.toISOString() : '';\n}\n\nfunction isInvalidDelegationDateRange(startAt: string, endAt: string): boolean {\n if (!startAt || !endAt) {\n return false;\n }\n\n const startDate = parseDelegationDateTimeValue(startAt);\n const endDate = parseDelegationDateTimeValue(endAt);\n\n return !!startDate && !!endDate && endDate.getTime() <= startDate.getTime();\n}\n\nfunction parseDelegationDateTimeValue(value: string): Date | null {\n if (value.endsWith('Z') || /[+-]\\d{2}:\\d{2}$/.test(value)) {\n const parsedDate = new Date(value);\n\n return Number.isNaN(parsedDate.getTime()) ? null : parsedDate;\n }\n\n const [datePart = '', timePart = '00:00'] = value.split('T');\n const [year = 0, month = 1, day = 1] = datePart.split('-').map(Number);\n const [hour = 0, minute = 0] = timePart.split(':').map(Number);\n const parsedDate = new Date(year, month - 1, day, hour, minute);\n\n return Number.isNaN(parsedDate.getTime()) ? null : parsedDate;\n}\n\nfunction formatDateParts(date: Date): string {\n return `${date.getFullYear()}-${padDatePart(date.getMonth() + 1)}-${padDatePart(\n date.getDate(),\n )}`;\n}\n\nfunction padDatePart(value: number): string {\n return String(value).padStart(2, '0');\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null;\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"delegations-B8gLSt0i.js","names":[],"sources":["../../src/views/admin/delegations/delegations.module.scss","../../src/views/admin/delegations/AdminDelegationsView.tsx"],"sourcesContent":[".delegationModalFields {\n display: grid;\n gap: 12px;\n width: 100%;\n\n :global(.mzn-form-field--horizontal) {\n align-items: flex-start;\n }\n\n :global(.mzn-form-field--horizontal .mzn-form-field__label-area) {\n flex: 0 0 112px;\n width: 112px;\n min-width: 112px;\n white-space: nowrap;\n }\n\n :global(.mzn-form-field--horizontal .mzn-form-field__label) {\n flex-wrap: nowrap;\n white-space: nowrap;\n }\n\n :global(.mzn-form-field--horizontal .mzn-form-field__data-entry) {\n flex: 1 1 auto;\n align-items: stretch;\n min-width: 0;\n max-width: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n\n :global(.mzn-auto-complete) {\n width: 100%;\n min-width: 0;\n }\n\n :global(.mzn-input),\n :global(.mzn-input-container),\n :global(.mzn-select),\n :global(.mzn-select-trigger),\n :global(.mzn-text-field) {\n width: 100%;\n min-width: 0 !important;\n }\n\n :global(.mzn-select-trigger__input) {\n width: 100%;\n min-width: 0 !important;\n text-overflow: ellipsis;\n }\n}\n\n.delegationFilterArea {\n width: calc(100vw - 272px);\n\n :global(.mzn-filter-area__actions) {\n display: none;\n }\n\n :global(.mzn-filter-area__row) {\n align-items: flex-start;\n }\n\n :global(.mzn-form-field__label-area) {\n display: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n\n :global(.mzn-auto-complete) {\n width: 100%;\n }\n}\n\n.memberNameWithTooltip {\n cursor: help;\n text-decoration: underline dotted;\n text-underline-offset: 3px;\n}\n","'use client';\n\nimport {\n ChangeEvent,\n Key,\n ReactElement,\n RefCallback,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n AutoComplete,\n Badge,\n Button,\n DateTimePicker,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Select,\n Tab,\n TabItem,\n Table,\n Tooltip,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { PlusIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport styles from './delegations.module.scss';\nimport { formatDateTime } from '../../../lib/format-date-time';\nimport { useAuth } from '../../../lib/auth-provider';\nimport {\n DelegationRuleRecord,\n DelegationRuleStatus,\n DelegationScopeType,\n MemberProfileRecord,\n createDelegationRule,\n listDelegationRulesPage,\n revokeDelegationRule,\n searchMembers,\n} from '@rytass/bpm-core-client/workflow';\nimport {\n ApprovalTemplateRecord,\n listApprovalTemplates,\n} from '@rytass/bpm-core-client/template';\n\ntype MemberOption = Readonly<{\n displayName: string;\n email: string | null;\n id: string;\n name: string;\n}>;\n\ntype TemplateOption = Readonly<{\n id: string;\n name: string;\n}>;\n\ntype ScopeOption = Readonly<{\n id: DelegationScopeType;\n name: string;\n}>;\n\ntype ScopeFilterOption = Readonly<{\n id: 'ALL_SCOPES' | DelegationScopeType;\n name: string;\n scopeType: DelegationScopeType | null;\n}>;\n\ntype DelegationRuleRow = Readonly<\n Record<string, unknown> &\n DelegationRuleRecord & {\n agentEmail: string | null;\n agentName: string;\n key: string;\n principalEmail: string | null;\n principalName: string;\n scopeLabel: string;\n }\n>;\n\nconst DELEGATION_MODAL_FIELD_LAYOUT = FormFieldLayout.HORIZONTAL;\nconst DELEGATION_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst DELEGATION_STATUS_TABS: readonly {\n readonly key: DelegationStatusTabKey;\n readonly label: string;\n}[] = [\n { key: 'ALL', label: '全部' },\n { key: 'ACTIVE', label: '啟用中' },\n { key: 'REVOKED', label: '已撤銷' },\n { key: 'EXPIRED', label: '已過期' },\n];\n\ntype DelegationStatusTabKey = 'ALL' | DelegationRuleStatus;\n\nconst SCOPE_OPTIONS: readonly ScopeOption[] = [\n { id: 'ALL', name: '全部簽核' },\n { id: 'TEMPLATE_LIST', name: '指定模板' },\n];\n\nconst SCOPE_FILTER_OPTIONS: readonly ScopeFilterOption[] = [\n { id: 'ALL_SCOPES', name: '全部範圍', scopeType: null },\n { id: 'ALL', name: '全部簽核', scopeType: 'ALL' },\n { id: 'TEMPLATE_LIST', name: '指定模板', scopeType: 'TEMPLATE_LIST' },\n];\n\n\nexport function AdminDelegationsView(): ReactElement {\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [agentMember, setAgentMember] = useState<MemberOption | null>(null);\n const [endAt, setEndAt] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [memberLoading, setMemberLoading] = useState(false);\n const [memberOptions, setMemberOptions] = useState<readonly MemberOption[]>(\n [],\n );\n const [principalFilterMember, setPrincipalFilterMember] =\n useState<MemberOption | null>(null);\n const [agentFilterMember, setAgentFilterMember] =\n useState<MemberOption | null>(null);\n const [modalOpen, setModalOpen] = useState(false);\n const [principalMember, setPrincipalMember] = useState<MemberOption | null>(\n null,\n );\n const [priority, setPriority] = useState('100');\n const [rulePage, setRulePage] = useState(1);\n const [rulePageSize, setRulePageSize] = useState(10);\n const [ruleStatus, setRuleStatus] = useState<DelegationStatusTabKey>('ALL');\n const [ruleTotalCount, setRuleTotalCount] = useState(0);\n const [rules, setRules] = useState<readonly DelegationRuleRecord[]>([]);\n const [saving, setSaving] = useState(false);\n const [scopeTemplates, setScopeTemplates] = useState<\n readonly TemplateOption[]\n >([]);\n const [scopeFilterType, setScopeFilterType] = useState<ScopeFilterOption>(\n SCOPE_FILTER_OPTIONS[0],\n );\n const [scopeType, setScopeType] = useState<ScopeOption>(SCOPE_OPTIONS[0]);\n const [startAt, setStartAt] = useState('');\n const [templateLoading, setTemplateLoading] = useState(false);\n const [templateOptions, setTemplateOptions] = useState<\n readonly TemplateOption[]\n >([]);\n\n const refreshRules = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const [rulePageResult, members] = await Promise.all([\n listDelegationRulesPage({\n agentMemberId: agentFilterMember?.id ?? null,\n includeInactive: true,\n page: rulePage,\n pageSize: rulePageSize,\n principalMemberId: principalFilterMember?.id ?? null,\n scopeType: scopeFilterType.scopeType,\n status: ruleStatus === 'ALL' ? null : ruleStatus,\n }),\n searchMembers(''),\n ]);\n\n setRules(rulePageResult.rules);\n setRuleTotalCount(rulePageResult.totalCount);\n setMemberOptions(members.map(readMemberOption));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [\n agentFilterMember,\n principalFilterMember,\n rulePage,\n rulePageSize,\n ruleStatus,\n scopeFilterType,\n ]);\n\n useEffect((): void => {\n void refreshRules();\n }, [refreshRules]);\n\n const membersById = useMemo(\n (): ReadonlyMap<string, MemberOption> =>\n new Map(memberOptions.map((option) => [option.id, option])),\n [memberOptions],\n );\n const rows = useMemo(\n (): DelegationRuleRow[] =>\n rules.map((rule) => ({\n ...rule,\n agentEmail: membersById.get(rule.agentMemberId)?.email ?? null,\n agentName:\n membersById.get(rule.agentMemberId)?.displayName ??\n rule.agentMemberId,\n key: rule.id,\n principalEmail: membersById.get(rule.principalMemberId)?.email ?? null,\n principalName:\n membersById.get(rule.principalMemberId)?.displayName ??\n rule.principalMemberId,\n scopeLabel: readScopeLabel(rule),\n })),\n [membersById, rules],\n );\n const selectedScopeType =\n SCOPE_OPTIONS.find((option) => option.id === scopeType.id) ??\n SCOPE_OPTIONS[0];\n const columns = useMemo(\n (): TableColumn<DelegationRuleRow>[] => [\n {\n key: 'principal',\n render: (record: DelegationRuleRow): ReactElement => (\n <MemberNameWithEmailTooltip\n email={record.principalEmail}\n name={record.principalName}\n />\n ),\n title: '原簽核人',\n width: 220,\n },\n {\n key: 'agent',\n render: (record: DelegationRuleRow): ReactElement => (\n <MemberNameWithEmailTooltip\n email={record.agentEmail}\n name={record.agentName}\n />\n ),\n title: '代理人',\n width: 220,\n },\n { dataIndex: 'scopeLabel', key: 'scope', title: '代理範圍', width: 220 },\n {\n key: 'status',\n render: (record: DelegationRuleRow): ReactElement => (\n <DelegationStatusBadge status={record.status} />\n ),\n title: '狀態',\n width: 120,\n },\n { dataIndex: 'priority', key: 'priority', title: '優先序', width: 100 },\n {\n key: 'startAt',\n render: (record: DelegationRuleRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.startAt)}\n </Typography>\n ),\n title: '開始時間',\n width: 220,\n },\n {\n key: 'endAt',\n render: (record: DelegationRuleRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {record.endAt ? formatDateTime(record.endAt) : '-'}\n </Typography>\n ),\n title: '結束時間',\n width: 220,\n },\n ],\n [],\n );\n const handleRevoke = useCallback(\n async (id: string): Promise<void> => {\n if (!currentMemberId) {\n return;\n }\n\n setError(null);\n\n try {\n await revokeDelegationRule({\n id,\n revokedByMemberId: currentMemberId,\n });\n await refreshRules();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n }\n },\n [currentMemberId, refreshRules],\n );\n const tableActions = useMemo(\n (): TableActions<DelegationRuleRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<DelegationRuleRow>['render']> =>\n record.status === 'ACTIVE'\n ? [\n {\n name: '撤銷',\n onClick: (): void => void handleRevoke(record.id),\n },\n ]\n : [],\n variant: 'destructive-secondary',\n width: 88,\n }),\n [handleRevoke],\n );\n\n async function handleSearchMembers(searchText: string): Promise<void> {\n setMemberLoading(true);\n\n try {\n setMemberOptions((await searchMembers(searchText)).map(readMemberOption));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setMemberLoading(false);\n }\n }\n\n async function handleSearchTemplates(\n searchText: string,\n selectedOptions: readonly TemplateOption[] = scopeTemplates,\n ): Promise<void> {\n setTemplateLoading(true);\n\n try {\n const nextOptions = (await listApprovalTemplates()).map(\n readTemplateOption,\n );\n\n setTemplateOptions(\n mergeTemplateOptions(\n selectedOptions,\n filterTemplateOptions(nextOptions, searchText),\n ),\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setTemplateLoading(false);\n }\n }\n\n function openCreateModal(): void {\n setAgentMember(null);\n setEndAt('');\n setPrincipalMember(null);\n setPriority('100');\n setScopeTemplates([]);\n setScopeType(SCOPE_OPTIONS[0]);\n setStartAt('');\n setTemplateOptions([]);\n void handleSearchTemplates('', []);\n setModalOpen(true);\n }\n\n function closeCreateModal(): void {\n if (saving) {\n return;\n }\n\n setModalOpen(false);\n }\n\n async function handleCreate(): Promise<void> {\n if (!currentMemberId) {\n return;\n }\n\n if (!principalMember || !agentMember) {\n setError('請選擇原簽核人與代理人');\n return;\n }\n\n if (selectedScopeType.id === 'TEMPLATE_LIST' && scopeTemplates.length < 1) {\n setError('請選擇至少一個簽核模板');\n return;\n }\n\n if (isInvalidDelegationDateRange(startAt, endAt)) {\n setError('結束時間必須晚於起始時間');\n return;\n }\n\n setSaving(true);\n setError(null);\n\n try {\n await createDelegationRule({\n agentMemberId: agentMember.id,\n createdByMemberId: currentMemberId,\n endAt: endAt || null,\n principalMemberId: principalMember.id,\n priority: Number(priority) || 100,\n requiresConfirmation: false,\n scopeConditionCel: null,\n scopeTemplateIds:\n selectedScopeType.id === 'TEMPLATE_LIST'\n ? scopeTemplates.map((template) => template.id)\n : [],\n scopeType: selectedScopeType.id,\n startAt: startAt || null,\n });\n setModalOpen(false);\n if (rulePage === 1) {\n await refreshRules();\n } else {\n setRulePage(1);\n }\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSaving(false);\n }\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"設定簽核代理規則,讓符合範圍的待簽任務自動改派給代理人。\"\n title=\"代理設定\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={openCreateModal}\n variant=\"base-primary\"\n >\n 建立代理\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.delegationFilterArea}>\n <FilterLine>\n <Filter span={2}>\n <MemberAutoCompleteField\n hideLabel\n label=\"原簽核人\"\n loading={memberLoading}\n name=\"principalFilterMemberId\"\n onChange={(option): void => {\n setPrincipalFilterMember(option);\n setRulePage(1);\n }}\n onSearch={handleSearchMembers}\n options={memberOptions}\n required={false}\n layout={FormFieldLayout.VERTICAL}\n size=\"sub\"\n value={principalFilterMember}\n />\n </Filter>\n <Filter span={2}>\n <MemberAutoCompleteField\n hideLabel\n label=\"代理人\"\n loading={memberLoading}\n name=\"agentFilterMemberId\"\n onChange={(option): void => {\n setAgentFilterMember(option);\n setRulePage(1);\n }}\n onSearch={handleSearchMembers}\n options={memberOptions}\n required={false}\n layout={FormFieldLayout.VERTICAL}\n size=\"sub\"\n value={agentFilterMember}\n />\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"scopeFilterType\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void => {\n setScopeFilterType(readScopeFilterOption(option));\n setRulePage(1);\n }}\n options={[...SCOPE_FILTER_OPTIONS]}\n placeholder=\"代理範圍\"\n size=\"sub\"\n value={scopeFilterType}\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n tab={\n <Tab\n activeKey={ruleStatus}\n onChange={(activeKey): void => {\n setRuleStatus(readDelegationStatusTabKey(activeKey));\n setRulePage(1);\n }}\n >\n {DELEGATION_STATUS_TABS.map((statusTab) => (\n <TabItem key={statusTab.key}>{statusTab.label}</TabItem>\n ))}\n </Tab>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n pagination={{\n current: rulePage,\n onChange: (page): void => {\n setRulePage(page);\n },\n onChangePageSize: (pageSize): void => {\n setRulePage(1);\n setRulePageSize(pageSize);\n },\n pageSize: rulePageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: DELEGATION_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: ruleTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{\n disabled: !principalMember || !agentMember,\n }}\n confirmText=\"建立代理\"\n loading={saving}\n modalType=\"standard\"\n onCancel={closeCreateModal}\n onClose={closeCreateModal}\n onConfirm={(): void => void handleCreate()}\n open={modalOpen}\n showModalFooter\n showModalHeader\n size=\"regular\"\n supportingText=\"代理生效後,後續建立的待簽任務會依範圍自動指派。\"\n title=\"建立代理\"\n >\n <div className={styles.delegationModalFields}>\n <MemberAutoCompleteField\n label=\"原簽核人\"\n loading={memberLoading}\n name=\"principalMemberId\"\n onChange={setPrincipalMember}\n onSearch={handleSearchMembers}\n options={memberOptions}\n value={principalMember}\n />\n <MemberAutoCompleteField\n label=\"代理人\"\n loading={memberLoading}\n name=\"agentMemberId\"\n onChange={setAgentMember}\n onSearch={handleSearchMembers}\n options={memberOptions}\n value={agentMember}\n />\n <BPMFormField label=\"代理範圍\" name=\"scopeType\" required>\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void =>\n setScopeType(readScopeOptionFromValue(option))\n }\n options={[...SCOPE_OPTIONS]}\n value={selectedScopeType}\n />\n </BPMFormField>\n {selectedScopeType.id === 'TEMPLATE_LIST' ? (\n <BPMFormField label=\"簽核模板\" name=\"scopeTemplateIds\" required>\n <AutoComplete\n asyncData\n disabledOptionsFilter\n emptyText=\"沒有符合的模板\"\n inputProps={{\n autoCapitalize: 'none',\n autoCorrect: 'off',\n name: 'scopeTemplateIds',\n spellCheck: false,\n }}\n loading={templateLoading}\n loadingText=\"搜尋模板中...\"\n mode=\"multiple\"\n onChange={(nextTemplates): void => {\n const selectedTemplates =\n readTemplateOptionsFromValue(nextTemplates);\n\n setScopeTemplates(selectedTemplates);\n setTemplateOptions((currentOptions) =>\n mergeTemplateOptions(selectedTemplates, currentOptions),\n );\n }}\n onSearch={handleSearchTemplates}\n onVisibilityChange={(open): void => {\n if (open) {\n void handleSearchTemplates('');\n }\n }}\n options={[...templateOptions]}\n overflowStrategy=\"wrap\"\n placeholder=\"搜尋並選取簽核模板\"\n searchDebounceTime={300}\n value={[...scopeTemplates]}\n />\n </BPMFormField>\n ) : null}\n <BPMFormField label=\"優先序\" name=\"priority\">\n <Input\n fullWidth\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n setPriority(event.target.value)\n }\n value={priority}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"起始時間\" name=\"startAt\">\n <DateTimePicker\n formatDate=\"YYYY-MM-DD\"\n formatTime=\"HH:mm\"\n fullWidth\n hideSecond\n onChange={(nextValue): void =>\n setStartAt(formatDelegationDateTimePickerValue(nextValue))\n }\n placeholderLeft=\"留空立即生效\"\n placeholderRight=\"選擇時間\"\n value={readDelegationDateTimePickerValue(startAt)}\n />\n </BPMFormField>\n <BPMFormField label=\"結束時間\" name=\"endAt\">\n <DateTimePicker\n formatDate=\"YYYY-MM-DD\"\n formatTime=\"HH:mm\"\n fullWidth\n hideSecond\n onChange={(nextValue): void =>\n setEndAt(formatDelegationDateTimePickerValue(nextValue))\n }\n placeholderLeft=\"可留空\"\n placeholderRight=\"選擇時間\"\n value={readDelegationDateTimePickerValue(endAt)}\n />\n </BPMFormField>\n </div>\n </Modal>\n </>\n );\n}\n\nfunction MemberAutoCompleteField({\n hideLabel = false,\n label,\n layout = DELEGATION_MODAL_FIELD_LAYOUT,\n loading,\n name,\n onChange,\n onSearch,\n options,\n required = true,\n size,\n value,\n}: {\n readonly hideLabel?: boolean;\n readonly label: string;\n readonly layout?: FormFieldLayout;\n readonly loading: boolean;\n readonly name: string;\n readonly onChange: (option: MemberOption | null) => void;\n readonly onSearch: (searchText: string) => Promise<void>;\n readonly options: readonly MemberOption[];\n readonly required?: boolean;\n readonly size?: 'main' | 'sub';\n readonly value: MemberOption | null;\n}): ReactElement {\n const autoComplete = (\n <AutoComplete\n asyncData\n disabledOptionsFilter\n emptyText=\"沒有符合的成員\"\n inputProps={{\n autoCapitalize: 'none',\n autoCorrect: 'off',\n name,\n spellCheck: false,\n }}\n loading={loading}\n loadingText=\"搜尋成員中...\"\n mode=\"single\"\n onChange={(option): void => onChange(readMemberOptionFromValue(option))}\n onSearch={onSearch}\n onSearchTextChange={(searchText): void =>\n onChange(readUniqueMemberOption(searchText, options))\n }\n onVisibilityChange={(open): void => {\n if (open) {\n void onSearch('');\n }\n }}\n options={[...options]}\n placeholder={hideLabel ? label : '搜尋姓名或信箱'}\n searchDebounceTime={300}\n size={size}\n value={value}\n />\n );\n\n if (hideLabel) {\n return (\n <FormField fullWidth layout={layout} name={name}>\n {autoComplete}\n </FormField>\n );\n }\n\n return (\n <BPMFormField label={label} layout={layout} name={name} required={required}>\n {autoComplete}\n </BPMFormField>\n );\n}\n\nfunction readMemberOption(member: MemberProfileRecord): MemberOption {\n return {\n displayName: member.name,\n email: member.email,\n id: member.memberId,\n name: `${member.name} · ${member.email}`,\n };\n}\n\nfunction readMemberOptionFromValue(value: unknown): MemberOption | null {\n if (!isRecord(value)) {\n return null;\n }\n\n const id = value.id;\n const name = value.name;\n const email = value.email;\n const displayName = value.displayName;\n\n return typeof id === 'string' && typeof name === 'string'\n ? {\n displayName: typeof displayName === 'string' ? displayName : name,\n email: typeof email === 'string' ? email : null,\n id,\n name,\n }\n : null;\n}\n\nfunction MemberNameWithEmailTooltip({\n email,\n name,\n}: {\n readonly email: string | null;\n readonly name: string;\n}): ReactElement {\n if (!email) {\n return <span>{name}</span>;\n }\n\n return (\n <Tooltip title={email}>\n {({ ref, ...tooltipProps }): ReactElement => (\n // Spread the whole payload, as `TooltipProps` asks: picking only the\n // mouse handlers drops `aria-describedby`, so assistive tech never\n // learns the open tooltip describes this name.\n <span\n {...tooltipProps}\n className={styles.memberNameWithTooltip}\n ref={ref as RefCallback<HTMLSpanElement>}\n >\n {name}\n </span>\n )}\n </Tooltip>\n );\n}\n\nfunction readUniqueMemberOption(\n searchText: string,\n options: readonly MemberOption[],\n): MemberOption | null {\n const normalizedSearchText = searchText.trim().toLocaleLowerCase();\n\n if (!normalizedSearchText) {\n return null;\n }\n\n const matches = options.filter((option) =>\n [option.id, option.name, option.email ?? ''].some((value) =>\n value.toLocaleLowerCase().includes(normalizedSearchText),\n ),\n );\n\n return matches.length === 1 ? (matches[0] ?? null) : null;\n}\n\nfunction readTemplateOption(template: ApprovalTemplateRecord): TemplateOption {\n return {\n id: template.id,\n name: template.name,\n };\n}\n\nfunction readTemplateOptionsFromValue(\n value: readonly unknown[],\n): readonly TemplateOption[] {\n return value.flatMap((item): readonly TemplateOption[] => {\n if (!isRecord(item)) {\n return [];\n }\n\n const id = item.id;\n const name = item.name;\n\n return typeof id === 'string' && typeof name === 'string'\n ? [{ id, name }]\n : [];\n });\n}\n\nfunction filterTemplateOptions(\n options: readonly TemplateOption[],\n searchText: string,\n): readonly TemplateOption[] {\n const normalizedSearchText = searchText.trim().toLocaleLowerCase();\n\n if (!normalizedSearchText) {\n return options;\n }\n\n return options.filter((option) =>\n [option.id, option.name].some((value) =>\n value.toLocaleLowerCase().includes(normalizedSearchText),\n ),\n );\n}\n\nfunction mergeTemplateOptions(\n selectedOptions: readonly TemplateOption[],\n availableOptions: readonly TemplateOption[],\n): readonly TemplateOption[] {\n return [...selectedOptions, ...availableOptions].reduce<TemplateOption[]>(\n (options, option) =>\n options.some((currentOption) => currentOption.id === option.id)\n ? options\n : [...options, option],\n [],\n );\n}\n\nfunction readScopeOptionFromValue(value: unknown): ScopeOption {\n if (!isRecord(value) || !isSelectableDelegationScopeType(value.id)) {\n return SCOPE_OPTIONS[0];\n }\n\n return (\n SCOPE_OPTIONS.find((option) => option.id === value.id) ?? SCOPE_OPTIONS[0]\n );\n}\n\nfunction readScopeFilterOption(value: unknown): ScopeFilterOption {\n if (!isRecord(value)) {\n return SCOPE_FILTER_OPTIONS[0];\n }\n\n const id = value.id;\n\n return (\n SCOPE_FILTER_OPTIONS.find((option) => option.id === id) ??\n SCOPE_FILTER_OPTIONS[0]\n );\n}\n\nfunction isSelectableDelegationScopeType(\n value: unknown,\n): value is ScopeOption['id'] {\n return value === 'ALL' || value === 'TEMPLATE_LIST';\n}\n\nfunction readScopeLabel(rule: DelegationRuleRecord): string {\n if (rule.scopeType === 'ALL') {\n return '全部簽核';\n }\n\n if (rule.scopeType === 'TEMPLATE_LIST') {\n return `指定模板:${rule.scopeTemplateIds.length}`;\n }\n\n return rule.scopeConditionCel ? `條件:${rule.scopeConditionCel}` : '條件式';\n}\n\nfunction DelegationStatusBadge({\n status,\n}: {\n readonly status: DelegationRuleRecord['status'];\n}): ReactElement {\n if (status === 'ACTIVE') {\n return <Badge size=\"sub\" text=\"啟用中\" variant=\"dot-success\" />;\n }\n\n if (status === 'REVOKED') {\n return <Badge size=\"sub\" text=\"已撤銷\" variant=\"dot-inactive\" />;\n }\n\n if (status === 'EXPIRED') {\n return <Badge size=\"sub\" text=\"已過期\" variant=\"dot-warning\" />;\n }\n\n return <Badge size=\"sub\" text={status} variant=\"dot-info\" />;\n}\n\nfunction readDelegationStatusTabKey(activeKey: Key): DelegationStatusTabKey {\n if (\n activeKey === 'ACTIVE' ||\n activeKey === 'REVOKED' ||\n activeKey === 'EXPIRED'\n ) {\n return activeKey;\n }\n\n return 'ALL';\n}\n\nfunction readDelegationDateTimePickerValue(value: string): string | undefined {\n const date = value ? parseDelegationDateTimeValue(value) : null;\n\n return date\n ? `${formatDateParts(date)}T${padDatePart(date.getHours())}:${padDatePart(\n date.getMinutes(),\n )}`\n : undefined;\n}\n\nfunction formatDelegationDateTimePickerValue(\n value: string | undefined,\n): string {\n const date = value ? parseDelegationDateTimeValue(value) : null;\n\n return date ? date.toISOString() : '';\n}\n\nfunction isInvalidDelegationDateRange(startAt: string, endAt: string): boolean {\n if (!startAt || !endAt) {\n return false;\n }\n\n const startDate = parseDelegationDateTimeValue(startAt);\n const endDate = parseDelegationDateTimeValue(endAt);\n\n return !!startDate && !!endDate && endDate.getTime() <= startDate.getTime();\n}\n\nfunction parseDelegationDateTimeValue(value: string): Date | null {\n if (value.endsWith('Z') || /[+-]\\d{2}:\\d{2}$/.test(value)) {\n const parsedDate = new Date(value);\n\n return Number.isNaN(parsedDate.getTime()) ? null : parsedDate;\n }\n\n const [datePart = '', timePart = '00:00'] = value.split('T');\n const [year = 0, month = 1, day = 1] = datePart.split('-').map(Number);\n const [hour = 0, minute = 0] = timePart.split(':').map(Number);\n const parsedDate = new Date(year, month - 1, day, hour, minute);\n\n return Number.isNaN(parsedDate.getTime()) ? null : parsedDate;\n}\n\nfunction formatDateParts(date: Date): string {\n return `${date.getFullYear()}-${padDatePart(date.getMonth() + 1)}-${padDatePart(\n date.getDate(),\n )}`;\n}\n\nfunction padDatePart(value: number): string {\n return String(value).padStart(2, '0');\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;GC2FM,IAAgC,EAAgB,YAChD,KAA+B;CAAC;CAAI;CAAI;AAAE,GAC1C,KAGA;CACJ;EAAE,KAAK;EAAO,OAAO;CAAK;CAC1B;EAAE,KAAK;EAAU,OAAO;CAAM;CAC9B;EAAE,KAAK;EAAW,OAAO;CAAM;CAC/B;EAAE,KAAK;EAAW,OAAO;CAAM;AACjC,GAIM,IAAwC,CAC5C;CAAE,IAAI;CAAO,MAAM;AAAO,GAC1B;CAAE,IAAI;CAAiB,MAAM;AAAO,CACtC,GAEM,IAAqD;CACzD;EAAE,IAAI;EAAc,MAAM;EAAQ,WAAW;CAAK;CAClD;EAAE,IAAI;EAAO,MAAM;EAAQ,WAAW;CAAM;CAC5C;EAAE,IAAI;EAAiB,MAAM;EAAQ,WAAW;CAAgB;AAClE;AAGA,SAAgB,IAAqC;CACnD,IAAM,EAAE,cAAW,EAAQ,GACrB,IAAkB,GAAQ,YAAY,MACtC,CAAC,GAAa,KAAkB,EAA8B,IAAI,GAClE,CAAC,GAAO,KAAY,EAAS,EAAE,GAC/B,CAAC,GAAO,KAAY,EAAwB,IAAI,GAChD,CAAC,IAAS,KAAc,EAAS,EAAI,GACrC,CAAC,GAAe,MAAoB,EAAS,EAAK,GAClD,CAAC,GAAe,MAAoB,EACxC,CAAC,CACH,GACM,CAAC,GAAuB,MAC5B,EAA8B,IAAI,GAC9B,CAAC,GAAmB,MACxB,EAA8B,IAAI,GAC9B,CAAC,IAAW,KAAgB,EAAS,EAAK,GAC1C,CAAC,GAAiB,MAAsB,EAC5C,IACF,GACM,CAAC,IAAU,MAAe,EAAS,KAAK,GACxC,CAAC,GAAU,KAAe,EAAS,CAAC,GACpC,CAAC,GAAc,MAAmB,EAAS,EAAE,GAC7C,CAAC,GAAY,MAAiB,EAAiC,KAAK,GACpE,CAAC,IAAgB,MAAqB,EAAS,CAAC,GAChD,CAAC,IAAO,MAAY,EAA0C,CAAC,CAAC,GAChE,CAAC,IAAQ,MAAa,EAAS,EAAK,GACpC,CAAC,GAAgB,MAAqB,EAE1C,CAAC,CAAC,GACE,CAAC,GAAiB,MAAsB,EAC5C,EAAqB,EACvB,GACM,CAAC,IAAW,MAAgB,EAAsB,EAAc,EAAE,GAClE,CAAC,GAAS,MAAc,EAAS,EAAE,GACnC,CAAC,IAAiB,MAAsB,EAAS,EAAK,GACtD,CAAC,IAAiB,KAAsB,EAE5C,CAAC,CAAC,GAEE,IAAe,EAAY,YAA2B;EAE1D,AADA,EAAW,EAAI,GACf,EAAS,IAAI;EAEb,IAAI;GACF,IAAM,CAAC,GAAgB,KAAW,MAAM,QAAQ,IAAI,CAClD,GAAwB;IACtB,eAAe,GAAmB,MAAM;IACxC,iBAAiB;IACjB,MAAM;IACN,UAAU;IACV,mBAAmB,GAAuB,MAAM;IAChD,WAAW,EAAgB;IAC3B,QAAQ,MAAe,QAAQ,OAAO;GACxC,CAAC,GACD,GAAc,EAAE,CAClB,CAAC;GAID,AAFA,GAAS,EAAe,KAAK,GAC7B,GAAkB,EAAe,UAAU,GAC3C,GAAiB,EAAQ,IAAI,EAAgB,CAAC;EAChD,SAAS,GAAuB;GAC9B,EAAS,EAAiB,CAAY,CAAC;EACzC,UAAU;GACR,EAAW,EAAK;EAClB;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,QAAsB;EACpB,EAAkB;CACpB,GAAG,CAAC,CAAY,CAAC;CAEjB,IAAM,IAAc,QAEhB,IAAI,IAAI,EAAc,KAAK,MAAW,CAAC,EAAO,IAAI,CAAM,CAAC,CAAC,GAC5D,CAAC,CAAa,CAChB,GACM,KAAO,QAET,GAAM,KAAK,OAAU;EACnB,GAAG;EACH,YAAY,EAAY,IAAI,EAAK,aAAa,CAAC,EAAE,SAAS;EAC1D,WACE,EAAY,IAAI,EAAK,aAAa,CAAC,EAAE,eACrC,EAAK;EACP,KAAK,EAAK;EACV,gBAAgB,EAAY,IAAI,EAAK,iBAAiB,CAAC,EAAE,SAAS;EAClE,eACE,EAAY,IAAI,EAAK,iBAAiB,CAAC,EAAE,eACzC,EAAK;EACP,YAAY,GAAe,CAAI;CACjC,EAAE,GACJ,CAAC,GAAa,EAAK,CACrB,GACM,IACJ,EAAc,MAAM,MAAW,EAAO,OAAO,GAAU,EAAE,KACzD,EAAc,IACV,KAAU,QAC0B;EACtC;GACE,KAAK;GACL,SAAS,MACP,kBAAC,IAAD;IACE,OAAO,EAAO;IACd,MAAM,EAAO;GACd,CAAA;GAEH,OAAO;GACP,OAAO;EACT;EACA;GACE,KAAK;GACL,SAAS,MACP,kBAAC,IAAD;IACE,OAAO,EAAO;IACd,MAAM,EAAO;GACd,CAAA;GAEH,OAAO;GACP,OAAO;EACT;EACA;GAAE,WAAW;GAAc,KAAK;GAAS,OAAO;GAAQ,OAAO;EAAI;EACnE;GACE,KAAK;GACL,SAAS,MACP,kBAAC,IAAD,EAAuB,QAAQ,EAAO,OAAS,CAAA;GAEjD,OAAO;GACP,OAAO;EACT;EACA;GAAE,WAAW;GAAY,KAAK;GAAY,OAAO;GAAO,OAAO;EAAI;EACnE;GACE,KAAK;GACL,SAAS,MACP,kBAAC,GAAD;IAAY,WAAU;IAAO,SAAQ;IAClC,UAAA,EAAe,EAAO,OAAO;GACpB,CAAA;GAEd,OAAO;GACP,OAAO;EACT;EACA;GACE,KAAK;GACL,SAAS,MACP,kBAAC,GAAD;IAAY,WAAU;IAAO,SAAQ;IAClC,UAAA,EAAO,QAAQ,EAAe,EAAO,KAAK,IAAI;GACrC,CAAA;GAEd,OAAO;GACP,OAAO;EACT;CACF,GACA,CAAC,CACH,GACM,KAAe,EACnB,OAAO,MAA8B;EAC9B,OAIL;KAAS,IAAI;GAEb,IAAI;IAKF,AAJA,MAAM,GAAqB;KACzB;KACA,mBAAmB;IACrB,CAAC,GACD,MAAM,EAAa;GACrB,SAAS,GAAuB;IAC9B,EAAS,EAAiB,CAAY,CAAC;GACzC;EAVa;CAWf,GACA,CAAC,GAAiB,CAAY,CAChC,GACM,KAAe,SACqB;EACtC,SACE,MAEA,EAAO,WAAW,WACd,CACE;GACE,MAAM;GACN,eAAqB,KAAK,GAAa,EAAO,EAAE;EAClD,CACF,IACA,CAAC;EACP,SAAS;EACT,OAAO;CACT,IACA,CAAC,EAAY,CACf;CAEA,eAAe,EAAoB,GAAmC;EACpE,GAAiB,EAAI;EAErB,IAAI;GACF,IAAkB,MAAM,GAAc,CAAU,EAAA,CAAG,IAAI,EAAgB,CAAC;EAC1E,SAAS,GAAuB;GAC9B,EAAS,EAAiB,CAAY,CAAC;EACzC,UAAU;GACR,GAAiB,EAAK;EACxB;CACF;CAEA,eAAe,EACb,GACA,IAA6C,GAC9B;EACf,GAAmB,EAAI;EAEvB,IAAI;GACF,IAAM,KAAe,MAAM,GAAsB,EAAA,CAAG,IAClD,EACF;GAEA,EACE,EACE,GACA,GAAsB,GAAa,CAAU,CAC/C,CACF;EACF,SAAS,GAAuB;GAC9B,EAAS,EAAiB,CAAY,CAAC;EACzC,UAAU;GACR,GAAmB,EAAK;EAC1B;CACF;CAEA,SAAS,KAAwB;EAU/B,AATA,EAAe,IAAI,GACnB,EAAS,EAAE,GACX,GAAmB,IAAI,GACvB,GAAY,KAAK,GACjB,GAAkB,CAAC,CAAC,GACpB,GAAa,EAAc,EAAE,GAC7B,GAAW,EAAE,GACb,EAAmB,CAAC,CAAC,GACrB,EAA2B,IAAI,CAAC,CAAC,GACjC,EAAa,EAAI;CACnB;CAEA,SAAS,IAAyB;EAC5B,MAIJ,EAAa,EAAK;CACpB;CAEA,eAAe,KAA8B;EACtC,OAIL;OAAI,CAAC,KAAmB,CAAC,GAAa;IACpC,EAAS,aAAa;IACtB;GACF;GAEA,IAAI,EAAkB,OAAO,mBAAmB,EAAe,SAAS,GAAG;IACzE,EAAS,aAAa;IACtB;GACF;GAEA,IAAI,GAA6B,GAAS,CAAK,GAAG;IAChD,EAAS,cAAc;IACvB;GACF;GAGA,AADA,GAAU,EAAI,GACd,EAAS,IAAI;GAEb,IAAI;IAiBF,AAhBA,MAAM,GAAqB;KACzB,eAAe,EAAY;KAC3B,mBAAmB;KACnB,OAAO,KAAS;KAChB,mBAAmB,EAAgB;KACnC,UAAU,OAAO,EAAQ,KAAK;KAC9B,sBAAsB;KACtB,mBAAmB;KACnB,kBACE,EAAkB,OAAO,kBACrB,EAAe,KAAK,MAAa,EAAS,EAAE,IAC5C,CAAC;KACP,WAAW,EAAkB;KAC7B,SAAS,KAAW;IACtB,CAAC,GACD,EAAa,EAAK,GACd,MAAa,IACf,MAAM,EAAa,IAEnB,EAAY,CAAC;GAEjB,SAAS,GAAuB;IAC9B,EAAS,EAAiB,CAAY,CAAC;GACzC,UAAU;IACR,GAAU,EAAK;GACjB;EAzCA;CA0CF;CAEA,OACE,kBAAA,IAAA,EAAA,UAAA;EACI,kBAAC,IAAD,EAAA,UACE,kBAAC,IAAD;GACE,aAAY;GACZ,OAAM;GAEN,UAAA,kBAAC,GAAD;IACE,MAAM;IACN,UAAS;IACT,SAAS;IACT,SAAQ;IACT,UAAA;GAEO,CAAA;EACK,CAAA,EACL,CAAA;EAEZ,kBAAC,IAAD,EAAA,UACE,kBAAC,IAAD;GACE,YACE,kBAAC,GAAD;IAAY,WAAW,EAAO;IAC5B,UAAA,kBAAC,GAAD,EAAA,UAAA;KACE,kBAAC,GAAD;MAAQ,MAAM;MACZ,UAAA,kBAAC,GAAD;OACE,WAAA;OACA,OAAM;OACN,SAAS;OACT,MAAK;OACL,WAAW,MAAiB;QAE1B,AADA,GAAyB,CAAM,GAC/B,EAAY,CAAC;OACf;OACA,UAAU;OACV,SAAS;OACT,UAAU;OACV,QAAQ,EAAgB;OACxB,MAAK;OACL,OAAO;MACR,CAAA;KACK,CAAA;KACR,kBAAC,GAAD;MAAQ,MAAM;MACZ,UAAA,kBAAC,GAAD;OACE,WAAA;OACA,OAAM;OACN,SAAS;OACT,MAAK;OACL,WAAW,MAAiB;QAE1B,AADA,GAAqB,CAAM,GAC3B,EAAY,CAAC;OACf;OACA,UAAU;OACV,SAAS;OACT,UAAU;OACV,QAAQ,EAAgB;OACxB,MAAK;OACL,OAAO;MACR,CAAA;KACK,CAAA;KACR,kBAAC,GAAD;MAAQ,MAAM;MACZ,UAAA,kBAAC,IAAD;OACE,WAAA;OACA,QAAQ,EAAgB;OACxB,MAAK;OAEL,UAAA,kBAAC,IAAD;QACE,WAAW;QACX,WAAA;QACA,WAAW,MAAiB;SAE1B,AADA,GAAmB,GAAsB,CAAM,CAAC,GAChD,EAAY,CAAC;QACf;QACA,SAAS,CAAC,GAAG,CAAoB;QACjC,aAAY;QACZ,MAAK;QACL,OAAO;OACR,CAAA;MACQ,CAAA;KACL,CAAA;IACE,EAAA,CAAA;GACF,CAAA;GAEd,KACE,kBAAC,IAAD;IACE,WAAW;IACX,WAAW,MAAoB;KAE7B,AADA,GAAc,GAA2B,CAAS,CAAC,GACnD,EAAY,CAAC;IACf;IAEC,UAAA,GAAuB,KAAK,MAC3B,kBAAC,IAAD,EAAA,UAA8B,EAAU,MAAe,GAAzC,EAAU,GAA+B,CACxD;GACE,CAAA;GA1ET,UAAA,CA6EG,IACC,kBAAC,GAAD;IAAY,OAAM;IAAa,SAAQ;IACpC,UAAA;GACS,CAAA,IACV,MACJ,kBAAC,IAAD;IACE,SAAS;IACA;IACT,YAAY;IACZ,WAAA;IACS;IACT,YAAY;KACV,SAAS;KACT,WAAW,MAAe;MACxB,EAAY,CAAI;KAClB;KACA,mBAAmB,MAAmB;MAEpC,AADA,EAAY,CAAC,GACb,GAAgB,CAAQ;KAC1B;KACA,UAAU;KACV,eAAe;KACf,iBAAiB;KACjB,sBAAsB,GAAM,GAAI,MAC9B,MAAM,EAAK,GAAG,EAAG,OAAO,EAAM;KAChC,qBAAqB;KACrB,OAAO;IACT;GACD,CAAA,CACM;EACG,CAAA,EAAA,CAAA;EAEd,kBAAC,IAAD;GACE,YAAW;GACX,oBAAoB,EAClB,UAAU,CAAC,KAAmB,CAAC,EACjC;GACA,aAAY;GACZ,SAAS;GACT,WAAU;GACV,UAAU;GACV,SAAS;GACT,iBAAuB,KAAK,GAAa;GACzC,MAAM;GACN,iBAAA;GACA,iBAAA;GACA,MAAK;GACL,gBAAe;GACf,OAAM;GAEN,UAAA,kBAAC,OAAD;IAAK,WAAW,EAAO;IAAvB,UAAA;KACE,kBAAC,GAAD;MACE,OAAM;MACN,SAAS;MACT,MAAK;MACL,UAAU;MACV,UAAU;MACV,SAAS;MACT,OAAO;KACR,CAAA;KACD,kBAAC,GAAD;MACE,OAAM;MACN,SAAS;MACT,MAAK;MACL,UAAU;MACV,UAAU;MACV,SAAS;MACT,OAAO;KACR,CAAA;KACD,kBAAC,GAAD;MAAc,OAAM;MAAO,MAAK;MAAY,UAAA;MAC1C,UAAA,kBAAC,IAAD;OACE,WAAW;OACX,WAAA;OACA,WAAW,MACT,GAAa,GAAyB,CAAM,CAAC;OAE/C,SAAS,CAAC,GAAG,CAAa;OAC1B,OAAO;MACR,CAAA;KACW,CAAA;KACb,EAAkB,OAAO,kBACxB,kBAAC,GAAD;MAAc,OAAM;MAAO,MAAK;MAAmB,UAAA;MACjD,UAAA,kBAAC,GAAD;OACE,WAAA;OACA,uBAAA;OACA,WAAU;OACV,YAAY;QACV,gBAAgB;QAChB,aAAa;QACb,MAAM;QACN,YAAY;OACd;OACA,SAAS;OACT,aAAY;OACZ,MAAK;OACL,WAAW,MAAwB;QACjC,IAAM,IACJ,GAA6B,CAAa;QAG5C,AADA,GAAkB,CAAiB,GACnC,GAAoB,MAClB,EAAqB,GAAmB,CAAc,CACxD;OACF;OACA,UAAU;OACV,qBAAqB,MAAe;QAClC,AAAI,KACF,EAA2B,EAAE;OAEjC;OACA,SAAS,CAAC,GAAG,EAAe;OAC5B,kBAAiB;OACjB,aAAY;OACZ,oBAAoB;OACpB,OAAO,CAAC,GAAG,CAAc;MAC1B,CAAA;KACW,CAAA,IACZ;KACJ,kBAAC,GAAD;MAAc,OAAM;MAAM,MAAK;MAC7B,UAAA,kBAAC,IAAD;OACE,WAAA;OACA,WAAW,MACT,GAAY,EAAM,OAAO,KAAK;OAEhC,OAAO;OACP,SAAQ;MACT,CAAA;KACW,CAAA;KACd,kBAAC,GAAD;MAAc,OAAM;MAAO,MAAK;MAC9B,UAAA,kBAAC,GAAD;OACE,YAAW;OACX,YAAW;OACX,WAAA;OACA,YAAA;OACA,WAAW,MACT,GAAW,EAAoC,CAAS,CAAC;OAE3D,iBAAgB;OAChB,kBAAiB;OACjB,OAAO,EAAkC,CAAO;MACjD,CAAA;KACW,CAAA;KACd,kBAAC,GAAD;MAAc,OAAM;MAAO,MAAK;MAC9B,UAAA,kBAAC,GAAD;OACE,YAAW;OACX,YAAW;OACX,WAAA;OACA,YAAA;OACA,WAAW,MACT,EAAS,EAAoC,CAAS,CAAC;OAEzD,iBAAgB;OAChB,kBAAiB;OACjB,OAAO,EAAkC,CAAK;MAC/C,CAAA;KACW,CAAA;IACX;;EACA,CAAA;CACP,EAAA,CAAA;AAER;AAEA,SAAS,EAAwB,EAC/B,eAAY,IACZ,UACA,YAAS,GACT,YACA,SACA,aACA,aACA,YACA,cAAW,IACX,SACA,YAae;CACf,IAAM,IACJ,kBAAC,GAAD;EACE,WAAA;EACA,uBAAA;EACA,WAAU;EACV,YAAY;GACV,gBAAgB;GAChB,aAAa;GACb;GACA,YAAY;EACd;EACS;EACT,aAAY;EACZ,MAAK;EACL,WAAW,MAAiB,EAAS,EAA0B,CAAM,CAAC;EAC5D;EACV,qBAAqB,MACnB,EAAS,EAAuB,GAAY,CAAO,CAAC;EAEtD,qBAAqB,MAAe;GAClC,AAAI,KACF,EAAc,EAAE;EAEpB;EACA,SAAS,CAAC,GAAG,CAAO;EACpB,aAAa,IAAY,IAAQ;EACjC,oBAAoB;EACd;EACC;CACR,CAAA;CAWH,OARI,IAEA,kBAAC,IAAD;EAAW,WAAA;EAAkB;EAAc;EACxC,UAAA;CACQ,CAAA,IAKb,kBAAC,GAAD;EAAqB;EAAe;EAAc;EAAgB;EAC/D,UAAA;CACW,CAAA;AAElB;AAEA,SAAS,GAAiB,GAA2C;CACnE,OAAO;EACL,aAAa,EAAO;EACpB,OAAO,EAAO;EACd,IAAI,EAAO;EACX,MAAM,GAAG,EAAO,KAAK,KAAK,EAAO;CACnC;AACF;AAEA,SAAS,EAA0B,GAAqC;CACtE,IAAI,CAAC,EAAS,CAAK,GACjB,OAAO;CAGT,IAAM,IAAK,EAAM,IACX,IAAO,EAAM,MACb,IAAQ,EAAM,OACd,IAAc,EAAM;CAE1B,OAAO,OAAO,KAAO,YAAY,OAAO,KAAS,WAC7C;EACE,aAAa,OAAO,KAAgB,WAAW,IAAc;EAC7D,OAAO,OAAO,KAAU,WAAW,IAAQ;EAC3C;EACA;CACF,IACA;AACN;AAEA,SAAS,GAA2B,EAClC,UACA,WAIe;CAKf,OAJK,IAKH,kBAAC,GAAD;EAAS,OAAO;EACZ,WAAA,EAAE,QAAK,GAAG,QAIV,kBAAC,QAAD;GACE,GAAI;GACJ,WAAW,EAAO;GACb;GAEJ,UAAA;EACG,CAAA;CAED,CAAA,IAjBF,kBAAC,QAAD,EAAA,UAAO,EAAW,CAAA;AAmB7B;AAEA,SAAS,EACP,GACA,GACqB;CACrB,IAAM,IAAuB,EAAW,KAAK,CAAC,CAAC,kBAAkB;CAEjE,IAAI,CAAC,GACH,OAAO;CAGT,IAAM,IAAU,EAAQ,QAAQ,MAC9B;EAAC,EAAO;EAAI,EAAO;EAAM,EAAO,SAAS;CAAE,CAAC,CAAC,MAAM,MACjD,EAAM,kBAAkB,CAAC,CAAC,SAAS,CAAoB,CACzD,CACF;CAEA,OAAO,EAAQ,WAAW,IAAK,EAAQ,MAAM,OAAQ;AACvD;AAEA,SAAS,GAAmB,GAAkD;CAC5E,OAAO;EACL,IAAI,EAAS;EACb,MAAM,EAAS;CACjB;AACF;AAEA,SAAS,GACP,GAC2B;CAC3B,OAAO,EAAM,SAAS,MAAoC;EACxD,IAAI,CAAC,EAAS,CAAI,GAChB,OAAO,CAAC;EAGV,IAAM,IAAK,EAAK,IACV,IAAO,EAAK;EAElB,OAAO,OAAO,KAAO,YAAY,OAAO,KAAS,WAC7C,CAAC;GAAE;GAAI;EAAK,CAAC,IACb,CAAC;CACP,CAAC;AACH;AAEA,SAAS,GACP,GACA,GAC2B;CAC3B,IAAM,IAAuB,EAAW,KAAK,CAAC,CAAC,kBAAkB;CAMjE,OAJK,IAIE,EAAQ,QAAQ,MACrB,CAAC,EAAO,IAAI,EAAO,IAAI,CAAC,CAAC,MAAM,MAC7B,EAAM,kBAAkB,CAAC,CAAC,SAAS,CAAoB,CACzD,CACF,IAPS;AAQX;AAEA,SAAS,EACP,GACA,GAC2B;CAC3B,OAAO,CAAC,GAAG,GAAiB,GAAG,CAAgB,CAAC,CAAC,QAC9C,GAAS,MACR,EAAQ,MAAM,MAAkB,EAAc,OAAO,EAAO,EAAE,IAC1D,IACA,CAAC,GAAG,GAAS,CAAM,GACzB,CAAC,CACH;AACF;AAEA,SAAS,GAAyB,GAA6B;CAK7D,OAJI,CAAC,EAAS,CAAK,KAAK,CAAC,EAAgC,EAAM,EAAE,IACxD,EAAc,KAIrB,EAAc,MAAM,MAAW,EAAO,OAAO,EAAM,EAAE,KAAK,EAAc;AAE5E;AAEA,SAAS,GAAsB,GAAmC;CAChE,IAAI,CAAC,EAAS,CAAK,GACjB,OAAO,EAAqB;CAG9B,IAAM,IAAK,EAAM;CAEjB,OACE,EAAqB,MAAM,MAAW,EAAO,OAAO,CAAE,KACtD,EAAqB;AAEzB;AAEA,SAAS,EACP,GAC4B;CAC5B,OAAO,MAAU,SAAS,MAAU;AACtC;AAEA,SAAS,GAAe,GAAoC;CAS1D,OARI,EAAK,cAAc,QACd,SAGL,EAAK,cAAc,kBACd,QAAQ,EAAK,iBAAiB,WAGhC,EAAK,oBAAoB,MAAM,EAAK,sBAAsB;AACnE;AAEA,SAAS,GAAsB,EAC7B,aAGe;CAaf,OAZI,MAAW,WACN,kBAAC,GAAD;EAAO,MAAK;EAAM,MAAK;EAAM,SAAQ;CAAe,CAAA,IAGzD,MAAW,YACN,kBAAC,GAAD;EAAO,MAAK;EAAM,MAAK;EAAM,SAAQ;CAAgB,CAAA,IAG1D,MAAW,YACN,kBAAC,GAAD;EAAO,MAAK;EAAM,MAAK;EAAM,SAAQ;CAAe,CAAA,IAGtD,kBAAC,GAAD;EAAO,MAAK;EAAM,MAAM;EAAQ,SAAQ;CAAY,CAAA;AAC7D;AAEA,SAAS,GAA2B,GAAwC;CAS1E,OAPE,MAAc,YACd,MAAc,aACd,MAAc,YAEP,IAGF;AACT;AAEA,SAAS,EAAkC,GAAmC;CAC5E,IAAM,IAAO,IAAQ,EAA6B,CAAK,IAAI;CAE3D,OAAO,IACH,GAAG,GAAgB,CAAI,EAAE,GAAG,EAAY,EAAK,SAAS,CAAC,EAAE,GAAG,EAC1D,EAAK,WAAW,CAClB,MACA,KAAA;AACN;AAEA,SAAS,EACP,GACQ;CACR,IAAM,IAAO,IAAQ,EAA6B,CAAK,IAAI;CAE3D,OAAO,IAAO,EAAK,YAAY,IAAI;AACrC;AAEA,SAAS,GAA6B,GAAiB,GAAwB;CAC7E,IAAI,CAAC,KAAW,CAAC,GACf,OAAO;CAGT,IAAM,IAAY,EAA6B,CAAO,GAChD,IAAU,EAA6B,CAAK;CAElD,OAAO,CAAC,CAAC,KAAa,CAAC,CAAC,KAAW,EAAQ,QAAQ,KAAK,EAAU,QAAQ;AAC5E;AAEA,SAAS,EAA6B,GAA4B;CAChE,IAAI,EAAM,SAAS,GAAG,KAAK,mBAAmB,KAAK,CAAK,GAAG;EACzD,IAAM,IAAa,IAAI,KAAK,CAAK;EAEjC,OAAO,OAAO,MAAM,EAAW,QAAQ,CAAC,IAAI,OAAO;CACrD;CAEA,IAAM,CAAC,IAAW,IAAI,IAAW,WAAW,EAAM,MAAM,GAAG,GACrD,CAAC,IAAO,GAAG,IAAQ,GAAG,IAAM,KAAK,EAAS,MAAM,GAAG,CAAC,CAAC,IAAI,MAAM,GAC/D,CAAC,IAAO,GAAG,IAAS,KAAK,EAAS,MAAM,GAAG,CAAC,CAAC,IAAI,MAAM,GACvD,IAAa,IAAI,KAAK,GAAM,IAAQ,GAAG,GAAK,GAAM,CAAM;CAE9D,OAAO,OAAO,MAAM,EAAW,QAAQ,CAAC,IAAI,OAAO;AACrD;AAEA,SAAS,GAAgB,GAAoB;CAC3C,OAAO,GAAG,EAAK,YAAY,EAAE,GAAG,EAAY,EAAK,SAAS,IAAI,CAAC,EAAE,GAAG,EAClE,EAAK,QAAQ,CACf;AACF;AAEA,SAAS,EAAY,GAAuB;CAC1C,OAAO,OAAO,CAAK,CAAC,CAAC,SAAS,GAAG,GAAG;AACtC;AAEA,SAAS,EAAiB,GAAwB;CAChD,OAAO,aAAiB,QAAQ,EAAM,UAAU;AAClD;AAEA,SAAS,EAAS,GAA4D;CAC5E,OAAO,OAAO,KAAU,cAAY;AACtC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"delegations-DRupxJ4_.js","names":[],"sources":["../../src/views/delegations/delegations.module.scss","../../src/views/delegations/DelegationsView.tsx"],"sourcesContent":[".delegationFilterArea {\n :global(.mzn-filter-area__actions) {\n display: none;\n }\n\n :global(.mzn-form-field__label-area) {\n display: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n}\n\n.delegationModalFields {\n display: grid;\n gap: 12px;\n width: 100%;\n\n :global(.mzn-form-field--horizontal) {\n align-items: flex-start;\n }\n\n :global(.mzn-form-field--horizontal .mzn-form-field__label-area) {\n flex: 0 0 112px;\n width: 112px;\n min-width: 112px;\n white-space: nowrap;\n }\n\n :global(.mzn-form-field--horizontal .mzn-form-field__label) {\n flex-wrap: nowrap;\n white-space: nowrap;\n }\n\n :global(.mzn-form-field--horizontal .mzn-form-field__data-entry) {\n flex: 1 1 auto;\n align-items: stretch;\n min-width: 0;\n max-width: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n\n :global(.mzn-autocomplete) {\n width: 100%;\n min-width: 0;\n }\n\n :global(.mzn-input),\n :global(.mzn-input-container),\n :global(.mzn-picker),\n :global(.mzn-select),\n :global(.mzn-select-trigger),\n :global(.mzn-text-field) {\n width: 100%;\n min-width: 0 !important;\n }\n\n :global(.mzn-select-trigger__input) {\n width: 100%;\n min-width: 0 !important;\n text-overflow: ellipsis;\n }\n}\n\n.memberNameWithTooltip {\n cursor: help;\n text-decoration: underline dotted;\n text-underline-offset: 3px;\n}\n","'use client';\n\nimport {\n Key,\n ReactElement,\n RefCallback,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n AutoComplete,\n Badge,\n Button,\n DateTimePicker,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Select,\n Tab,\n TabItem,\n Table,\n Tooltip,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { PlusIcon } from '@mezzanine-ui/icons';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { BPMFormField } from '../../components/bpm-form-field';\nimport { formatDateTime } from '../../lib/format-date-time';\nimport { useAuth } from '../../lib/auth-provider';\nimport {\n DelegationRuleRecord,\n DelegationRuleStatus,\n DelegationScopeType,\n MemberProfileRecord,\n createDelegationRule,\n listDelegationRulesPage,\n revokeDelegationRule,\n searchMembers,\n} from '@rytass/bpm-core-client/workflow';\nimport {\n ApprovalTemplateRecord,\n listApprovalTemplates,\n} from '@rytass/bpm-core-client/template';\nimport styles from './delegations.module.scss';\n\ntype DelegationStatusTabKey = 'ALL' | DelegationRuleStatus;\n\ntype MemberOption = Readonly<{\n displayName: string;\n email: string | null;\n id: string;\n name: string;\n}>;\n\ntype ScopeOption = Readonly<{\n id: DelegationScopeType;\n name: string;\n}>;\n\ntype ScopeFilterOption = Readonly<{\n id: 'ALL_SCOPES' | DelegationScopeType;\n name: string;\n scopeType: DelegationScopeType | null;\n}>;\n\ntype TemplateOption = Readonly<{\n id: string;\n name: string;\n}>;\n\ntype DelegationRuleRow = Readonly<\n Record<string, unknown> &\n DelegationRuleRecord & {\n agentEmail: string | null;\n agentName: string;\n key: string;\n scopeLabel: string;\n }\n>;\n\nconst DELEGATION_MODAL_FIELD_LAYOUT = FormFieldLayout.HORIZONTAL;\nconst DELEGATION_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst DELEGATION_STATUS_TABS: readonly {\n readonly key: DelegationStatusTabKey;\n readonly label: string;\n}[] = [\n { key: 'ALL', label: '全部' },\n { key: 'ACTIVE', label: '啟用中' },\n { key: 'REVOKED', label: '已撤銷' },\n { key: 'EXPIRED', label: '已過期' },\n];\nconst SCOPE_FILTER_OPTIONS: readonly ScopeFilterOption[] = [\n { id: 'ALL_SCOPES', name: '全部範圍', scopeType: null },\n { id: 'ALL', name: '全部簽核', scopeType: 'ALL' },\n { id: 'TEMPLATE_LIST', name: '指定模板', scopeType: 'TEMPLATE_LIST' },\n];\nconst SCOPE_OPTIONS: readonly ScopeOption[] = [\n { id: 'ALL', name: '全部簽核' },\n { id: 'TEMPLATE_LIST', name: '指定模板' },\n];\n\nexport function DelegationsView(): ReactElement {\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [agentMember, setAgentMember] = useState<MemberOption | null>(null);\n const [endAt, setEndAt] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [memberLoading, setMemberLoading] = useState(false);\n const [memberOptions, setMemberOptions] = useState<readonly MemberOption[]>(\n [],\n );\n const [modalOpen, setModalOpen] = useState(false);\n const [rulePage, setRulePage] = useState(1);\n const [rulePageSize, setRulePageSize] = useState(10);\n const [ruleStatus, setRuleStatus] = useState<DelegationStatusTabKey>('ALL');\n const [ruleTotalCount, setRuleTotalCount] = useState(0);\n const [rules, setRules] = useState<readonly DelegationRuleRecord[]>([]);\n const [saving, setSaving] = useState(false);\n const [scopeFilterType, setScopeFilterType] = useState<ScopeFilterOption>(\n SCOPE_FILTER_OPTIONS[0],\n );\n const [scopeTemplates, setScopeTemplates] = useState<\n readonly TemplateOption[]\n >([]);\n const [scopeType, setScopeType] = useState<ScopeOption>(SCOPE_OPTIONS[0]);\n const [startAt, setStartAt] = useState('');\n const [templateLoading, setTemplateLoading] = useState(false);\n const [templateOptions, setTemplateOptions] = useState<\n readonly TemplateOption[]\n >([]);\n const refreshRequestIdRef = useRef(0);\n\n const refreshRules = useCallback(async (): Promise<void> => {\n const requestId = refreshRequestIdRef.current + 1;\n refreshRequestIdRef.current = requestId;\n\n if (!currentMemberId) {\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const [rulePageResult, members] = await Promise.all([\n listDelegationRulesPage({\n includeInactive: true,\n page: rulePage,\n pageSize: rulePageSize,\n principalMemberId: currentMemberId,\n scopeType: scopeFilterType.scopeType,\n status: ruleStatus === 'ALL' ? null : ruleStatus,\n }),\n searchMembers(''),\n ]);\n\n if (requestId === refreshRequestIdRef.current) {\n setRules(rulePageResult.rules);\n setRuleTotalCount(rulePageResult.totalCount);\n setMemberOptions(members.map(readMemberOption));\n }\n } catch (requestError: unknown) {\n if (requestId === refreshRequestIdRef.current) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (requestId === refreshRequestIdRef.current) {\n setLoading(false);\n }\n }\n }, [currentMemberId, rulePage, rulePageSize, ruleStatus, scopeFilterType]);\n\n useEffect((): void => {\n void refreshRules();\n }, [refreshRules]);\n\n const membersById = useMemo(\n (): ReadonlyMap<string, MemberOption> =>\n new Map(memberOptions.map((option) => [option.id, option])),\n [memberOptions],\n );\n const rows = useMemo(\n (): DelegationRuleRow[] =>\n rules.map((rule) => ({\n ...rule,\n agentEmail: membersById.get(rule.agentMemberId)?.email ?? null,\n agentName:\n membersById.get(rule.agentMemberId)?.displayName ??\n rule.agentMemberId,\n key: rule.id,\n scopeLabel: readScopeLabel(rule),\n })),\n [membersById, rules],\n );\n const selectedScopeType =\n SCOPE_OPTIONS.find((option) => option.id === scopeType.id) ??\n SCOPE_OPTIONS[0];\n const columns = useMemo(\n (): TableColumn<DelegationRuleRow>[] => [\n {\n key: 'agent',\n render: (record: DelegationRuleRow): ReactElement => (\n <MemberNameWithEmailTooltip\n email={record.agentEmail}\n name={record.agentName}\n />\n ),\n title: '代理人',\n width: 220,\n },\n { dataIndex: 'scopeLabel', key: 'scope', title: '代理範圍', width: 220 },\n {\n key: 'status',\n render: (record: DelegationRuleRow): ReactElement => (\n <DelegationStatusBadge status={record.status} />\n ),\n title: '狀態',\n width: 120,\n },\n {\n key: 'startAt',\n render: (record: DelegationRuleRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.startAt)}\n </Typography>\n ),\n title: '開始時間',\n width: 220,\n },\n {\n key: 'endAt',\n render: (record: DelegationRuleRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {record.endAt ? formatDateTime(record.endAt) : '-'}\n </Typography>\n ),\n title: '結束時間',\n width: 220,\n },\n ],\n [],\n );\n const handleRevoke = useCallback(\n async (id: string): Promise<void> => {\n if (!currentMemberId) {\n return;\n }\n\n setError(null);\n\n try {\n await revokeDelegationRule({\n id,\n revokedByMemberId: currentMemberId,\n });\n await refreshRules();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n }\n },\n [currentMemberId, refreshRules],\n );\n const tableActions = useMemo(\n (): TableActions<DelegationRuleRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<DelegationRuleRow>['render']> =>\n record.status === 'ACTIVE'\n ? [\n {\n name: '撤銷',\n onClick: (): void => void handleRevoke(record.id),\n },\n ]\n : [],\n variant: 'destructive-secondary',\n width: 88,\n }),\n [handleRevoke],\n );\n\n async function handleSearchMembers(searchText: string): Promise<void> {\n setMemberLoading(true);\n\n try {\n setMemberOptions((await searchMembers(searchText)).map(readMemberOption));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setMemberLoading(false);\n }\n }\n\n async function handleSearchTemplates(\n searchText: string,\n selectedOptions: readonly TemplateOption[] = scopeTemplates,\n ): Promise<void> {\n setTemplateLoading(true);\n\n try {\n const nextOptions = (await listApprovalTemplates()).map(\n readTemplateOption,\n );\n\n setTemplateOptions(\n mergeTemplateOptions(\n selectedOptions,\n filterTemplateOptions(nextOptions, searchText),\n ),\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setTemplateLoading(false);\n }\n }\n\n function openCreateModal(): void {\n setAgentMember(null);\n setEndAt('');\n setScopeTemplates([]);\n setScopeType(SCOPE_OPTIONS[0]);\n setStartAt('');\n setTemplateOptions([]);\n void handleSearchTemplates('', []);\n setModalOpen(true);\n }\n\n function closeCreateModal(): void {\n if (saving) {\n return;\n }\n\n setModalOpen(false);\n }\n\n async function handleCreate(): Promise<void> {\n if (!currentMemberId) {\n return;\n }\n\n if (!agentMember) {\n setError('請選擇代理人');\n return;\n }\n\n if (agentMember.id === currentMemberId) {\n setError('代理人不可設定為自己');\n return;\n }\n\n if (selectedScopeType.id === 'TEMPLATE_LIST' && scopeTemplates.length < 1) {\n setError('請選擇至少一個簽核模板');\n return;\n }\n\n if (isInvalidDelegationDateRange(startAt, endAt)) {\n setError('結束時間必須晚於起始時間');\n return;\n }\n\n setSaving(true);\n setError(null);\n\n try {\n await createDelegationRule({\n agentMemberId: agentMember.id,\n createdByMemberId: currentMemberId,\n endAt: endAt || null,\n principalMemberId: currentMemberId,\n priority: 100,\n requiresConfirmation: false,\n scopeConditionCel: null,\n scopeTemplateIds:\n selectedScopeType.id === 'TEMPLATE_LIST'\n ? scopeTemplates.map((template) => template.id)\n : [],\n scopeType: selectedScopeType.id,\n startAt: startAt || null,\n });\n setModalOpen(false);\n\n if (rulePage === 1) {\n await refreshRules();\n } else {\n setRulePage(1);\n }\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSaving(false);\n }\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"設定自己的簽核代理,讓指定期間內的新待簽任務自動交由代理人處理。\"\n title=\"我的代理\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={openCreateModal}\n variant=\"base-primary\"\n >\n 建立代理\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.delegationFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"scopeFilterType\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void => {\n setScopeFilterType(readScopeFilterOption(option));\n setRulePage(1);\n }}\n options={[...SCOPE_FILTER_OPTIONS]}\n placeholder=\"代理範圍\"\n size=\"sub\"\n value={scopeFilterType}\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n tab={\n <Tab\n activeKey={ruleStatus}\n onChange={(activeKey): void => {\n setRuleStatus(readDelegationStatusTabKey(activeKey));\n setRulePage(1);\n }}\n >\n {DELEGATION_STATUS_TABS.map((statusTab) => (\n <TabItem key={statusTab.key}>{statusTab.label}</TabItem>\n ))}\n </Tab>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n pagination={{\n current: rulePage,\n onChange: (page): void => {\n setRulePage(page);\n },\n onChangePageSize: (pageSize): void => {\n setRulePage(1);\n setRulePageSize(pageSize);\n },\n pageSize: rulePageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: DELEGATION_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: ruleTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{\n disabled: !agentMember,\n }}\n confirmText=\"建立代理\"\n loading={saving}\n modalType=\"standard\"\n onCancel={closeCreateModal}\n onClose={closeCreateModal}\n onConfirm={(): void => void handleCreate()}\n open={modalOpen}\n showModalFooter\n showModalHeader\n size=\"regular\"\n supportingText=\"代理生效後,後續建立的待簽任務會依範圍自動指派給代理人。\"\n title=\"建立個人代理\"\n >\n <div className={styles.delegationModalFields}>\n <MemberAutoCompleteField\n label=\"代理人\"\n loading={memberLoading}\n name=\"agentMemberId\"\n onChange={setAgentMember}\n onSearch={handleSearchMembers}\n options={memberOptions}\n value={agentMember}\n />\n <BPMFormField label=\"代理範圍\" name=\"scopeType\" required>\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void =>\n setScopeType(readScopeOptionFromValue(option))\n }\n options={[...SCOPE_OPTIONS]}\n placeholder=\"選擇代理範圍\"\n value={selectedScopeType}\n />\n </BPMFormField>\n {selectedScopeType.id === 'TEMPLATE_LIST' ? (\n <BPMFormField label=\"簽核模板\" name=\"scopeTemplateIds\" required>\n <AutoComplete\n asyncData\n disabledOptionsFilter\n emptyText=\"沒有符合的模板\"\n inputProps={{\n autoCapitalize: 'none',\n autoCorrect: 'off',\n name: 'scopeTemplateIds',\n spellCheck: false,\n }}\n loading={templateLoading}\n loadingText=\"搜尋模板中...\"\n mode=\"multiple\"\n onChange={(nextTemplates): void => {\n const selectedTemplates =\n readTemplateOptionsFromValue(nextTemplates);\n\n setScopeTemplates(selectedTemplates);\n setTemplateOptions((currentOptions) =>\n mergeTemplateOptions(selectedTemplates, currentOptions),\n );\n }}\n onSearch={handleSearchTemplates}\n onVisibilityChange={(open): void => {\n if (open) {\n void handleSearchTemplates('');\n }\n }}\n options={[...templateOptions]}\n overflowStrategy=\"wrap\"\n placeholder=\"搜尋並選取簽核模板\"\n searchDebounceTime={300}\n value={[...scopeTemplates]}\n />\n </BPMFormField>\n ) : null}\n <BPMFormField label=\"起始時間\" name=\"startAt\">\n <DateTimePicker\n formatDate=\"YYYY-MM-DD\"\n formatTime=\"HH:mm\"\n fullWidth\n hideSecond\n onChange={(nextValue): void =>\n setStartAt(formatDelegationDateTimePickerValue(nextValue))\n }\n placeholderLeft=\"留空立即生效\"\n placeholderRight=\"選擇時間\"\n value={readDelegationDateTimePickerValue(startAt)}\n />\n </BPMFormField>\n <BPMFormField label=\"結束時間\" name=\"endAt\">\n <DateTimePicker\n formatDate=\"YYYY-MM-DD\"\n formatTime=\"HH:mm\"\n fullWidth\n hideSecond\n onChange={(nextValue): void =>\n setEndAt(formatDelegationDateTimePickerValue(nextValue))\n }\n placeholderLeft=\"可留空\"\n placeholderRight=\"選擇時間\"\n value={readDelegationDateTimePickerValue(endAt)}\n />\n </BPMFormField>\n </div>\n </Modal>\n </>\n );\n}\n\nfunction MemberAutoCompleteField({\n label,\n loading,\n name,\n onChange,\n onSearch,\n options,\n value,\n}: {\n readonly label: string;\n readonly loading: boolean;\n readonly name: string;\n readonly onChange: (option: MemberOption | null) => void;\n readonly onSearch: (searchText: string) => Promise<void>;\n readonly options: readonly MemberOption[];\n readonly value: MemberOption | null;\n}): ReactElement {\n return (\n <BPMFormField\n label={label}\n layout={DELEGATION_MODAL_FIELD_LAYOUT}\n name={name}\n required\n >\n <AutoComplete\n asyncData\n disabledOptionsFilter\n emptyText=\"沒有符合的成員\"\n inputProps={{\n autoCapitalize: 'none',\n autoCorrect: 'off',\n name,\n spellCheck: false,\n }}\n loading={loading}\n loadingText=\"搜尋成員中...\"\n mode=\"single\"\n onChange={(option): void => onChange(readMemberOptionFromValue(option))}\n onSearch={onSearch}\n onSearchTextChange={(searchText): void =>\n onChange(readUniqueMemberOption(searchText, options))\n }\n onVisibilityChange={(open): void => {\n if (open) {\n void onSearch('');\n }\n }}\n options={[...options]}\n placeholder=\"搜尋姓名或信箱\"\n searchDebounceTime={300}\n value={value}\n />\n </BPMFormField>\n );\n}\n\nfunction MemberNameWithEmailTooltip({\n email,\n name,\n}: {\n readonly email: string | null;\n readonly name: string;\n}): ReactElement {\n if (!email) {\n return <span>{name}</span>;\n }\n\n return (\n <Tooltip title={email}>\n {({ ref, ...tooltipProps }): ReactElement => (\n // Spread the whole payload, as `TooltipProps` asks: picking only the\n // mouse handlers drops `aria-describedby`, so assistive tech never\n // learns the open tooltip describes this name.\n <span\n {...tooltipProps}\n className={styles.memberNameWithTooltip}\n ref={ref as RefCallback<HTMLSpanElement>}\n >\n {name}\n </span>\n )}\n </Tooltip>\n );\n}\n\nfunction readMemberOption(member: MemberProfileRecord): MemberOption {\n return {\n displayName: member.name,\n email: member.email,\n id: member.memberId,\n name: `${member.name} (${member.email})`,\n };\n}\n\nfunction readMemberOptionFromValue(value: unknown): MemberOption | null {\n if (!isRecord(value)) {\n return null;\n }\n\n const displayName = value.displayName;\n const email = value.email;\n const id = value.id;\n const name = value.name;\n\n return typeof id === 'string' && typeof name === 'string'\n ? {\n displayName: typeof displayName === 'string' ? displayName : name,\n email: typeof email === 'string' ? email : null,\n id,\n name,\n }\n : null;\n}\n\nfunction readUniqueMemberOption(\n searchText: string,\n options: readonly MemberOption[],\n): MemberOption | null {\n const normalizedSearchText = searchText.trim().toLocaleLowerCase();\n\n if (!normalizedSearchText) {\n return null;\n }\n\n const matches = options.filter((option) =>\n [option.id, option.name, option.email ?? ''].some((value) =>\n value.toLocaleLowerCase().includes(normalizedSearchText),\n ),\n );\n\n return matches.length === 1 ? (matches[0] ?? null) : null;\n}\n\nfunction readTemplateOption(template: ApprovalTemplateRecord): TemplateOption {\n return {\n id: template.id,\n name: template.name,\n };\n}\n\nfunction readTemplateOptionsFromValue(\n value: readonly unknown[],\n): readonly TemplateOption[] {\n return value.flatMap((item): readonly TemplateOption[] => {\n if (!isRecord(item)) {\n return [];\n }\n\n const id = item.id;\n const name = item.name;\n\n return typeof id === 'string' && typeof name === 'string'\n ? [{ id, name }]\n : [];\n });\n}\n\nfunction filterTemplateOptions(\n options: readonly TemplateOption[],\n searchText: string,\n): readonly TemplateOption[] {\n const normalizedSearchText = searchText.trim().toLocaleLowerCase();\n\n if (!normalizedSearchText) {\n return options;\n }\n\n return options.filter((option) =>\n [option.id, option.name].some((value) =>\n value.toLocaleLowerCase().includes(normalizedSearchText),\n ),\n );\n}\n\nfunction mergeTemplateOptions(\n selectedOptions: readonly TemplateOption[],\n availableOptions: readonly TemplateOption[],\n): readonly TemplateOption[] {\n return [...selectedOptions, ...availableOptions].reduce<TemplateOption[]>(\n (options, option) =>\n options.some((currentOption) => currentOption.id === option.id)\n ? options\n : [...options, option],\n [],\n );\n}\n\nfunction readScopeFilterOption(value: unknown): ScopeFilterOption {\n if (!isRecord(value)) {\n return SCOPE_FILTER_OPTIONS[0];\n }\n\n const id = value.id;\n\n return (\n SCOPE_FILTER_OPTIONS.find((option) => option.id === id) ??\n SCOPE_FILTER_OPTIONS[0]\n );\n}\n\nfunction readScopeLabel(rule: DelegationRuleRecord): string {\n if (rule.scopeType === 'ALL') {\n return '全部簽核';\n }\n\n if (rule.scopeType === 'TEMPLATE_LIST') {\n return `指定模板:${rule.scopeTemplateIds.length}`;\n }\n\n return rule.scopeConditionCel ? `條件:${rule.scopeConditionCel}` : '條件式';\n}\n\nfunction readScopeOptionFromValue(value: unknown): ScopeOption {\n if (!isRecord(value) || !isSelectableDelegationScopeType(value.id)) {\n return SCOPE_OPTIONS[0];\n }\n\n return (\n SCOPE_OPTIONS.find((option) => option.id === value.id) ?? SCOPE_OPTIONS[0]\n );\n}\n\nfunction isSelectableDelegationScopeType(\n value: unknown,\n): value is ScopeOption['id'] {\n return value === 'ALL' || value === 'TEMPLATE_LIST';\n}\n\nfunction DelegationStatusBadge({\n status,\n}: {\n readonly status: DelegationRuleRecord['status'];\n}): ReactElement {\n if (status === 'ACTIVE') {\n return <Badge size=\"sub\" text=\"啟用中\" variant=\"dot-success\" />;\n }\n\n if (status === 'REVOKED') {\n return <Badge size=\"sub\" text=\"已撤銷\" variant=\"dot-inactive\" />;\n }\n\n if (status === 'EXPIRED') {\n return <Badge size=\"sub\" text=\"已過期\" variant=\"dot-warning\" />;\n }\n\n return <Badge size=\"sub\" text={status} variant=\"dot-info\" />;\n}\n\nfunction readDelegationStatusTabKey(activeKey: Key): DelegationStatusTabKey {\n if (\n activeKey === 'ACTIVE' ||\n activeKey === 'REVOKED' ||\n activeKey === 'EXPIRED'\n ) {\n return activeKey;\n }\n\n return 'ALL';\n}\n\nfunction readDelegationDateTimePickerValue(value: string): string | undefined {\n const date = value ? parseDelegationDateTimeValue(value) : null;\n\n return date\n ? `${formatDateParts(date)}T${padDatePart(date.getHours())}:${padDatePart(\n date.getMinutes(),\n )}`\n : undefined;\n}\n\nfunction formatDelegationDateTimePickerValue(\n value: string | undefined,\n): string {\n const date = value ? parseDelegationDateTimeValue(value) : null;\n\n return date ? date.toISOString() : '';\n}\n\nfunction isInvalidDelegationDateRange(startAt: string, endAt: string): boolean {\n if (!startAt || !endAt) {\n return false;\n }\n\n const startDate = parseDelegationDateTimeValue(startAt);\n const endDate = parseDelegationDateTimeValue(endAt);\n\n return !!startDate && !!endDate && endDate.getTime() <= startDate.getTime();\n}\n\nfunction parseDelegationDateTimeValue(value: string): Date | null {\n if (value.endsWith('Z') || /[+-]\\d{2}:\\d{2}$/.test(value)) {\n const parsedDate = new Date(value);\n\n return Number.isNaN(parsedDate.getTime()) ? null : parsedDate;\n }\n\n const [datePart = '', timePart = '00:00'] = value.split('T');\n const [year = 0, month = 1, day = 1] = datePart.split('-').map(Number);\n const [hour = 0, minute = 0] = timePart.split(':').map(Number);\n const parsedDate = new Date(year, month - 1, day, hour, minute);\n\n return Number.isNaN(parsedDate.getTime()) ? null : parsedDate;\n}\n\nfunction formatDateParts(date: Date): string {\n return `${date.getFullYear()}-${padDatePart(date.getMonth() + 1)}-${padDatePart(\n date.getDate(),\n )}`;\n}\n\nfunction padDatePart(value: number): string {\n return String(value).padStart(2, '0');\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null;\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use client";require('../delegations.css');const e=require("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./auth-provider-4BeCw7cI.cjs"),n=require("./format-date-time-D-cx5M8z.cjs"),r=require("./bpm-form-field-Bc6k4ZEO.cjs");let i=require("react"),a=require("@mezzanine-ui/react"),o=require("react/jsx-runtime"),s=require("@rytass/bpm-core-client/workflow"),c=require("@mezzanine-ui/core/form"),l=require("@mezzanine-ui/react/ContentHeader");l=e.t(l,1);let u=require("@mezzanine-ui/icons"),d=require("@rytass/bpm-core-client/template");var f={delegationModalFields:`bpm_delegationModalFields_gUlCQ`,delegationFilterArea:`bpm_delegationFilterArea_QDZkw`,memberNameWithTooltip:`bpm_memberNameWithTooltip_RggTW`},p=c.FormFieldLayout.HORIZONTAL,m=[10,20,50],h=[{key:`ALL`,label:`全部`},{key:`ACTIVE`,label:`啟用中`},{key:`REVOKED`,label:`已撤銷`},{key:`EXPIRED`,label:`已過期`}],g=[{id:`ALL`,name:`全部簽核`},{id:`TEMPLATE_LIST`,name:`指定模板`}],_=[{id:`ALL_SCOPES`,name:`全部範圍`,scopeType:null},{id:`ALL`,name:`全部簽核`,scopeType:`ALL`},{id:`TEMPLATE_LIST`,name:`指定模板`,scopeType:`TEMPLATE_LIST`}];function v(){let{member:e}=t.n(),p=e?.memberId??null,[v,x]=(0,i.useState)(null),[C,w]=(0,i.useState)(``),[E,D]=(0,i.useState)(null),[O,A]=(0,i.useState)(!0),[j,M]=(0,i.useState)(!1),[N,P]=(0,i.useState)([]),[F,de]=(0,i.useState)(null),[I,fe]=(0,i.useState)(null),[pe,L]=(0,i.useState)(!1),[R,z]=(0,i.useState)(null),[B,me]=(0,i.useState)(`100`),[V,H]=(0,i.useState)(1),[U,he]=(0,i.useState)(10),[W,ge]=(0,i.useState)(`ALL`),[_e,ve]=(0,i.useState)(0),[ye,be]=(0,i.useState)([]),[xe,Se]=(0,i.useState)(!1),[G,Ce]=(0,i.useState)([]),[K,we]=(0,i.useState)(_[0]),[Te,Ee]=(0,i.useState)(g[0]),[q,De]=(0,i.useState)(``),[Oe,ke]=(0,i.useState)(!1),[Ae,J]=(0,i.useState)([]),Y=(0,i.useCallback)(async()=>{A(!0),D(null);try{let[e,t]=await Promise.all([(0,s.listDelegationRulesPage)({agentMemberId:I?.id??null,includeInactive:!0,page:V,pageSize:U,principalMemberId:F?.id??null,scopeType:K.scopeType,status:W===`ALL`?null:W}),(0,s.searchMembers)(``)]);be(e.rules),ve(e.totalCount),P(t.map(b))}catch(e){D(k(e))}finally{A(!1)}},[I,F,V,U,W,K]);(0,i.useEffect)(()=>{Y()},[Y]);let X=(0,i.useMemo)(()=>new Map(N.map(e=>[e.id,e])),[N]),je=(0,i.useMemo)(()=>ye.map(e=>({...e,agentEmail:X.get(e.agentMemberId)?.email??null,agentName:X.get(e.agentMemberId)?.displayName??e.agentMemberId,key:e.id,principalEmail:X.get(e.principalMemberId)?.email??null,principalName:X.get(e.principalMemberId)?.displayName??e.principalMemberId,scopeLabel:oe(e)})),[X,ye]),Z=g.find(e=>e.id===Te.id)??g[0],Me=(0,i.useMemo)(()=>[{key:`principal`,render:e=>(0,o.jsx)(S,{email:e.principalEmail,name:e.principalName}),title:`原簽核人`,width:220},{key:`agent`,render:e=>(0,o.jsx)(S,{email:e.agentEmail,name:e.agentName}),title:`代理人`,width:220},{dataIndex:`scopeLabel`,key:`scope`,title:`代理範圍`,width:220},{key:`status`,render:e=>(0,o.jsx)(se,{status:e.status}),title:`狀態`,width:120},{dataIndex:`priority`,key:`priority`,title:`優先序`,width:100},{key:`startAt`,render:e=>(0,o.jsx)(a.Typography,{component:`span`,variant:`body`,children:n.t(e.startAt)}),title:`開始時間`,width:220},{key:`endAt`,render:e=>(0,o.jsx)(a.Typography,{component:`span`,variant:`body`,children:e.endAt?n.t(e.endAt):`-`}),title:`結束時間`,width:220}],[]),Ne=(0,i.useCallback)(async e=>{if(p){D(null);try{await(0,s.revokeDelegationRule)({id:e,revokedByMemberId:p}),await Y()}catch(e){D(k(e))}}},[p,Y]),Pe=(0,i.useMemo)(()=>({render:e=>e.status===`ACTIVE`?[{name:`撤銷`,onClick:()=>void Ne(e.id)}]:[],variant:`destructive-secondary`,width:88}),[Ne]);async function Q(e){M(!0);try{P((await(0,s.searchMembers)(e)).map(b))}catch(e){D(k(e))}finally{M(!1)}}async function $(e,t=G){ke(!0);try{let n=(await(0,d.listApprovalTemplates)()).map(ee);J(re(t,ne(n,e)))}catch(e){D(k(e))}finally{ke(!1)}}function Fe(){x(null),w(``),z(null),me(`100`),Ce([]),Ee(g[0]),De(``),J([]),$(``,[]),L(!0)}function Ie(){xe||L(!1)}async function Le(){if(p){if(!R||!v){D(`請選擇原簽核人與代理人`);return}if(Z.id===`TEMPLATE_LIST`&&G.length<1){D(`請選擇至少一個簽核模板`);return}if(ue(q,C)){D(`結束時間必須晚於起始時間`);return}Se(!0),D(null);try{await(0,s.createDelegationRule)({agentMemberId:v.id,createdByMemberId:p,endAt:C||null,principalMemberId:R.id,priority:Number(B)||100,requiresConfirmation:!1,scopeConditionCel:null,scopeTemplateIds:Z.id===`TEMPLATE_LIST`?G.map(e=>e.id):[],scopeType:Z.id,startAt:q||null}),L(!1),V===1?await Y():H(1)}catch(e){D(k(e))}finally{Se(!1)}}}return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(a.PageHeader,{children:(0,o.jsx)(l.default,{description:`設定簽核代理規則,讓符合範圍的待簽任務自動改派給代理人。`,title:`代理設定`,children:(0,o.jsx)(a.Button,{icon:u.PlusIcon,iconType:`leading`,onClick:Fe,variant:`base-primary`,children:`建立代理`})})}),(0,o.jsx)(a.SectionGroup,{children:(0,o.jsxs)(a.Section,{filterArea:(0,o.jsx)(a.FilterArea,{className:f.delegationFilterArea,children:(0,o.jsxs)(a.FilterLine,{children:[(0,o.jsx)(a.Filter,{span:2,children:(0,o.jsx)(y,{hideLabel:!0,label:`原簽核人`,loading:j,name:`principalFilterMemberId`,onChange:e=>{de(e),H(1)},onSearch:Q,options:N,required:!1,layout:c.FormFieldLayout.VERTICAL,size:`sub`,value:F})}),(0,o.jsx)(a.Filter,{span:2,children:(0,o.jsx)(y,{hideLabel:!0,label:`代理人`,loading:j,name:`agentFilterMemberId`,onChange:e=>{fe(e),H(1)},onSearch:Q,options:N,required:!1,layout:c.FormFieldLayout.VERTICAL,size:`sub`,value:I})}),(0,o.jsx)(a.Filter,{span:2,children:(0,o.jsx)(a.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`scopeFilterType`,children:(0,o.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>{we(ae(e)),H(1)},options:[..._],placeholder:`代理範圍`,size:`sub`,value:K})})})]})}),tab:(0,o.jsx)(a.Tab,{activeKey:W,onChange:e=>{ge(ce(e)),H(1)},children:h.map(e=>(0,o.jsx)(a.TabItem,{children:e.label},e.key))}),children:[E?(0,o.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:E}):null,(0,o.jsx)(a.Table,{actions:Pe,columns:Me,dataSource:je,fullWidth:!0,loading:O,pagination:{current:V,onChange:e=>{H(e)},onChangePageSize:e=>{H(1),he(e)},pageSize:U,pageSizeLabel:`每頁筆數`,pageSizeOptions:m,renderResultSummary:(e,t,n)=>`顯示 ${e}-${t} 筆,共 ${n} 筆`,showPageSizeOptions:!0,total:_e}})]})}),(0,o.jsx)(a.Modal,{cancelText:`取消`,confirmButtonProps:{disabled:!R||!v},confirmText:`建立代理`,loading:xe,modalType:`standard`,onCancel:Ie,onClose:Ie,onConfirm:()=>void Le(),open:pe,showModalFooter:!0,showModalHeader:!0,size:`regular`,supportingText:`代理生效後,後續建立的待簽任務會依範圍自動指派。`,title:`建立代理`,children:(0,o.jsxs)(`div`,{className:f.delegationModalFields,children:[(0,o.jsx)(y,{label:`原簽核人`,loading:j,name:`principalMemberId`,onChange:z,onSearch:Q,options:N,value:R}),(0,o.jsx)(y,{label:`代理人`,loading:j,name:`agentMemberId`,onChange:x,onSearch:Q,options:N,value:v}),(0,o.jsx)(r.t,{label:`代理範圍`,name:`scopeType`,required:!0,children:(0,o.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>Ee(ie(e)),options:[...g],value:Z})}),Z.id===`TEMPLATE_LIST`?(0,o.jsx)(r.t,{label:`簽核模板`,name:`scopeTemplateIds`,required:!0,children:(0,o.jsx)(a.AutoComplete,{asyncData:!0,disabledOptionsFilter:!0,emptyText:`沒有符合的模板`,inputProps:{autoCapitalize:`none`,autoCorrect:`off`,name:`scopeTemplateIds`,spellCheck:!1},loading:Oe,loadingText:`搜尋模板中...`,mode:`multiple`,onChange:e=>{let t=te(e);Ce(t),J(e=>re(t,e))},onSearch:$,onVisibilityChange:e=>{e&&$(``)},options:[...Ae],overflowStrategy:`wrap`,placeholder:`搜尋並選取簽核模板`,searchDebounceTime:300,value:[...G]})}):null,(0,o.jsx)(r.t,{label:`優先序`,name:`priority`,children:(0,o.jsx)(a.Input,{fullWidth:!0,onChange:e=>me(e.target.value),value:B,variant:`base`})}),(0,o.jsx)(r.t,{label:`起始時間`,name:`startAt`,children:(0,o.jsx)(a.DateTimePicker,{formatDate:`YYYY-MM-DD`,formatTime:`HH:mm`,fullWidth:!0,hideSecond:!0,onChange:e=>De(T(e)),placeholderLeft:`留空立即生效`,placeholderRight:`選擇時間`,value:le(q)})}),(0,o.jsx)(r.t,{label:`結束時間`,name:`endAt`,children:(0,o.jsx)(a.DateTimePicker,{formatDate:`YYYY-MM-DD`,formatTime:`HH:mm`,fullWidth:!0,hideSecond:!0,onChange:e=>w(T(e)),placeholderLeft:`可留空`,placeholderRight:`選擇時間`,value:le(C)})})]})})]})}function y({hideLabel:e=!1,label:t,layout:n=p,loading:i,name:s,onChange:c,onSearch:l,options:u,required:d=!0,size:f,value:m}){let h=(0,o.jsx)(a.AutoComplete,{asyncData:!0,disabledOptionsFilter:!0,emptyText:`沒有符合的成員`,inputProps:{autoCapitalize:`none`,autoCorrect:`off`,name:s,spellCheck:!1},loading:i,loadingText:`搜尋成員中...`,mode:`single`,onChange:e=>c(x(e)),onSearch:l,onSearchTextChange:e=>c(C(e,u)),onVisibilityChange:e=>{e&&l(``)},options:[...u],placeholder:e?t:`搜尋姓名或信箱`,searchDebounceTime:300,size:f,value:m});return e?(0,o.jsx)(a.FormField,{fullWidth:!0,layout:n,name:s,children:h}):(0,o.jsx)(r.t,{label:t,layout:n,name:s,required:d,children:h})}function b(e){return{displayName:e.name,email:e.email,id:e.memberId,name:`${e.name} · ${e.email}`}}function x(e){if(!A(e))return null;let t=e.id,n=e.name,r=e.email,i=e.displayName;return typeof t==`string`&&typeof n==`string`?{displayName:typeof i==`string`?i:n,email:typeof r==`string`?r:null,id:t,name:n}:null}function S({email:e,name:t}){return e?(0,o.jsx)(a.Tooltip,{title:e,children:({ref:e,...n})=>(0,o.jsx)(`span`,{...n,className:f.memberNameWithTooltip,ref:e,children:t})}):(0,o.jsx)(`span`,{children:t})}function C(e,t){let n=e.trim().toLocaleLowerCase();if(!n)return null;let r=t.filter(e=>[e.id,e.name,e.email??``].some(e=>e.toLocaleLowerCase().includes(n)));return r.length===1?r[0]??null:null}function ee(e){return{id:e.id,name:e.name}}function te(e){return e.flatMap(e=>{if(!A(e))return[];let t=e.id,n=e.name;return typeof t==`string`&&typeof n==`string`?[{id:t,name:n}]:[]})}function ne(e,t){let n=t.trim().toLocaleLowerCase();return n?e.filter(e=>[e.id,e.name].some(e=>e.toLocaleLowerCase().includes(n))):e}function re(e,t){return[...e,...t].reduce((e,t)=>e.some(e=>e.id===t.id)?e:[...e,t],[])}function ie(e){return!A(e)||!w(e.id)?g[0]:g.find(t=>t.id===e.id)??g[0]}function ae(e){if(!A(e))return _[0];let t=e.id;return _.find(e=>e.id===t)??_[0]}function w(e){return e===`ALL`||e===`TEMPLATE_LIST`}function oe(e){return e.scopeType===`ALL`?`全部簽核`:e.scopeType===`TEMPLATE_LIST`?`指定模板:${e.scopeTemplateIds.length}`:e.scopeConditionCel?`條件:${e.scopeConditionCel}`:`條件式`}function se({status:e}){return e===`ACTIVE`?(0,o.jsx)(a.Badge,{size:`sub`,text:`啟用中`,variant:`dot-success`}):e===`REVOKED`?(0,o.jsx)(a.Badge,{size:`sub`,text:`已撤銷`,variant:`dot-inactive`}):e===`EXPIRED`?(0,o.jsx)(a.Badge,{size:`sub`,text:`已過期`,variant:`dot-warning`}):(0,o.jsx)(a.Badge,{size:`sub`,text:e,variant:`dot-info`})}function ce(e){return e===`ACTIVE`||e===`REVOKED`||e===`EXPIRED`?e:`ALL`}function le(e){let t=e?E(e):null;return t?`${D(t)}T${O(t.getHours())}:${O(t.getMinutes())}`:void 0}function T(e){let t=e?E(e):null;return t?t.toISOString():``}function ue(e,t){if(!e||!t)return!1;let n=E(e),r=E(t);return!!n&&!!r&&r.getTime()<=n.getTime()}function E(e){if(e.endsWith(`Z`)||/[+-]\d{2}:\d{2}$/.test(e)){let t=new Date(e);return Number.isNaN(t.getTime())?null:t}let[t=``,n=`00:00`]=e.split(`T`),[r=0,i=1,a=1]=t.split(`-`).map(Number),[o=0,s=0]=n.split(`:`).map(Number),c=new Date(r,i-1,a,o,s);return Number.isNaN(c.getTime())?null:c}function D(e){return`${e.getFullYear()}-${O(e.getMonth()+1)}-${O(e.getDate())}`}function O(e){return String(e).padStart(2,`0`)}function k(e){return e instanceof Error?e.message:`發生未知錯誤`}function A(e){return typeof e==`object`&&!!e}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return v}});
2
- //# sourceMappingURL=delegations-DlYwMiAW.cjs.map