@rytass/bpm-core-react 0.17.0 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/chunks/admin-pickers-BRHk3qKq.cjs +2 -0
  3. package/dist/chunks/admin-pickers-BRHk3qKq.cjs.map +1 -0
  4. package/dist/chunks/{admin-pickers-DxhzECkD.js → admin-pickers-Djq3h-UR.js} +41 -39
  5. package/dist/chunks/admin-pickers-Djq3h-UR.js.map +1 -0
  6. package/dist/chunks/{categories-DjENouRm.cjs → categories-AxxhqjLZ.cjs} +2 -2
  7. package/dist/chunks/{categories-DjENouRm.cjs.map → categories-AxxhqjLZ.cjs.map} +1 -1
  8. package/dist/chunks/{categories-1gKxeEqw.js → categories-riC33J_j.js} +2 -2
  9. package/dist/chunks/{categories-1gKxeEqw.js.map → categories-riC33J_j.js.map} +1 -1
  10. package/dist/chunks/{compose-DZ7RKvUp.cjs → compose-B7TtrpQJ.cjs} +2 -2
  11. package/dist/chunks/{compose-DZ7RKvUp.cjs.map → compose-B7TtrpQJ.cjs.map} +1 -1
  12. package/dist/chunks/{compose-Crklayzy.js → compose-_pREPtfN.js} +2 -2
  13. package/dist/chunks/{compose-Crklayzy.js.map → compose-_pREPtfN.js.map} +1 -1
  14. package/dist/chunks/{designer-D9eFma1W.js → designer-BiywgNXs.js} +2 -2
  15. package/dist/chunks/{designer-D9eFma1W.js.map → designer-BiywgNXs.js.map} +1 -1
  16. package/dist/chunks/{designer-sJGTGYOf.cjs → designer-ttAqv859.cjs} +2 -2
  17. package/dist/chunks/{designer-sJGTGYOf.cjs.map → designer-ttAqv859.cjs.map} +1 -1
  18. package/dist/chunks/{orgs-Dr0FFoZo.cjs → orgs-C8usknWb.cjs} +2 -2
  19. package/dist/chunks/{orgs-Dr0FFoZo.cjs.map → orgs-C8usknWb.cjs.map} +1 -1
  20. package/dist/chunks/{orgs-CY0i1fie.js → orgs-Lg7tXv2u.js} +2 -2
  21. package/dist/chunks/{orgs-CY0i1fie.js.map → orgs-Lg7tXv2u.js.map} +1 -1
  22. package/dist/chunks/{users-BCyePbwB.js → users-DRbuDYF1.js} +2 -2
  23. package/dist/chunks/{users-BCyePbwB.js.map → users-DRbuDYF1.js.map} +1 -1
  24. package/dist/chunks/{users-DVBJluFR.cjs → users-DVQicZIo.cjs} +2 -2
  25. package/dist/chunks/{users-DVBJluFR.cjs.map → users-DVQicZIo.cjs.map} +1 -1
  26. package/dist/components/admin-pickers.d.cts +65 -0
  27. package/dist/components/approval-instance-list-page.d.cts +17 -0
  28. package/dist/components/bpm-form-field.d.cts +10 -0
  29. package/dist/components/bpm-notification-bell-button.d.cts +22 -0
  30. package/dist/components/dashboard-page.d.cts +7 -0
  31. package/dist/components/notification-drawer.d.cts +11 -0
  32. package/dist/components/org-unit-tree-draft-editor.d.cts +24 -0
  33. package/dist/components/org-unit-tree-draft-editor.d.ts +1 -1
  34. package/dist/components/pdf-preview.d.cts +12 -0
  35. package/dist/index.cjs +1 -1
  36. package/dist/index.d.cts +15 -0
  37. package/dist/index.d.ts +15 -15
  38. package/dist/index.js +1 -1
  39. package/dist/lib/auth-provider.d.cts +37 -0
  40. package/dist/lib/format-date-time.d.cts +5 -0
  41. package/dist/lib/format-member-label.d.cts +12 -0
  42. package/dist/lib/member-profile-resolution.d.cts +48 -0
  43. package/dist/lib/notification-drawer-provider.d.cts +27 -0
  44. package/dist/lib/notification-unread-provider.d.cts +25 -0
  45. package/dist/lib/org-tree-draft.d.cts +27 -0
  46. package/dist/lib/providers.d.cts +31 -0
  47. package/dist/lib/router-adapter.d.cts +47 -0
  48. package/dist/lib/routes-config.d.cts +117 -0
  49. package/dist/lib/task-node-label.d.cts +10 -0
  50. package/dist/lib/use-bpm-logout.d.cts +12 -0
  51. package/dist/lib/use-bpm-member.d.cts +17 -0
  52. package/dist/next/BPMNextProviders.d.cts +51 -0
  53. package/dist/next/index.d.cts +2 -0
  54. package/dist/next/index.d.ts +2 -2
  55. package/dist/next/workflow-chat-route.d.cts +17 -0
  56. package/dist/pages/admin/delegations/index.d.cts +4 -0
  57. package/dist/pages/admin/orgs/index.cjs +1 -1
  58. package/dist/pages/admin/orgs/index.d.cts +4 -0
  59. package/dist/pages/admin/orgs/index.js +1 -1
  60. package/dist/pages/admin/users/index.cjs +1 -1
  61. package/dist/pages/admin/users/index.d.cts +4 -0
  62. package/dist/pages/admin/users/index.js +1 -1
  63. package/dist/pages/admin/webhook-endpoints/index.d.cts +4 -0
  64. package/dist/pages/cc/index.d.cts +16 -0
  65. package/dist/pages/dashboard/index.d.cts +16 -0
  66. package/dist/pages/delegations/index.d.cts +4 -0
  67. package/dist/pages/inbox/index.d.cts +16 -0
  68. package/dist/pages/instances/detail/index.d.cts +23 -0
  69. package/dist/pages/instances/new/index.d.cts +20 -0
  70. package/dist/pages/login/index.d.cts +21 -0
  71. package/dist/pages/root/index.d.cts +18 -0
  72. package/dist/pages/search/index.d.cts +16 -0
  73. package/dist/pages/sent/index.d.cts +16 -0
  74. package/dist/pages/settings/notifications/index.d.cts +4 -0
  75. package/dist/pages/templates/categories/index.cjs +1 -1
  76. package/dist/pages/templates/categories/index.d.cts +4 -0
  77. package/dist/pages/templates/categories/index.js +1 -1
  78. package/dist/pages/templates/compose/index.cjs +1 -1
  79. package/dist/pages/templates/compose/index.d.cts +25 -0
  80. package/dist/pages/templates/compose/index.js +1 -1
  81. package/dist/pages/templates/designer/index.cjs +1 -1
  82. package/dist/pages/templates/designer/index.d.cts +8 -0
  83. package/dist/pages/templates/designer/index.js +1 -1
  84. package/dist/pages/templates/index.d.cts +4 -0
  85. package/dist/pages/templates/versions/index.d.cts +8 -0
  86. package/dist/views/admin/delegations/AdminDelegationsView.d.cts +2 -0
  87. package/dist/views/admin/delegations/index.d.cts +1 -0
  88. package/dist/views/admin/delegations/index.d.ts +1 -1
  89. package/dist/views/admin/index.cjs +1 -1
  90. package/dist/views/admin/index.d.cts +4 -0
  91. package/dist/views/admin/index.d.ts +4 -4
  92. package/dist/views/admin/index.js +2 -2
  93. package/dist/views/admin/orgs/AdminOrgsView.d.cts +2 -0
  94. package/dist/views/admin/orgs/index.cjs +1 -1
  95. package/dist/views/admin/orgs/index.d.cts +1 -0
  96. package/dist/views/admin/orgs/index.d.ts +1 -1
  97. package/dist/views/admin/orgs/index.js +1 -1
  98. package/dist/views/admin/users/AdminUsersView.d.cts +2 -0
  99. package/dist/views/admin/users/MemberTaskReassignModal.d.cts +13 -0
  100. package/dist/views/admin/users/index.cjs +1 -1
  101. package/dist/views/admin/users/index.d.cts +1 -0
  102. package/dist/views/admin/users/index.d.ts +1 -1
  103. package/dist/views/admin/users/index.js +1 -1
  104. package/dist/views/admin/webhook-endpoints/AdminWebhookEndpointsView.d.cts +8 -0
  105. package/dist/views/admin/webhook-endpoints/index.d.cts +1 -0
  106. package/dist/views/admin/webhook-endpoints/index.d.ts +1 -1
  107. package/dist/views/cc/CcView.d.cts +7 -0
  108. package/dist/views/cc/index.d.cts +1 -0
  109. package/dist/views/cc/index.d.ts +1 -1
  110. package/dist/views/dashboard/DashboardView.d.cts +7 -0
  111. package/dist/views/dashboard/index.d.cts +1 -0
  112. package/dist/views/dashboard/index.d.ts +1 -1
  113. package/dist/views/delegations/DelegationsView.d.cts +2 -0
  114. package/dist/views/delegations/index.d.cts +1 -0
  115. package/dist/views/delegations/index.d.ts +1 -1
  116. package/dist/views/forms/builder/FormBuilderView.d.cts +18 -0
  117. package/dist/views/forms/builder/index.d.cts +1 -0
  118. package/dist/views/forms/builder/index.d.ts +1 -1
  119. package/dist/views/forms/builder/json-code-editor.d.cts +11 -0
  120. package/dist/views/forms/renderer/FormRendererView.d.cts +24 -0
  121. package/dist/views/forms/renderer/FormRendererView.d.ts +1 -1
  122. package/dist/views/forms/renderer/form-data-source-field.d.cts +65 -0
  123. package/dist/views/forms/renderer/form-field-link.d.cts +16 -0
  124. package/dist/views/forms/renderer/index.d.cts +2 -0
  125. package/dist/views/forms/renderer/index.d.ts +2 -2
  126. package/dist/views/forms/renderer/member-field-options.d.cts +39 -0
  127. package/dist/views/forms/renderer/member-field.d.cts +21 -0
  128. package/dist/views/inbox/InboxView.d.cts +7 -0
  129. package/dist/views/inbox/index.d.cts +1 -0
  130. package/dist/views/inbox/index.d.ts +1 -1
  131. package/dist/views/instances/detail/InstanceDetailView.d.cts +27 -0
  132. package/dist/views/instances/detail/index.d.cts +7 -0
  133. package/dist/views/instances/detail/index.d.ts +7 -7
  134. package/dist/views/instances/detail/sections/InstanceAttachmentsSection.d.cts +15 -0
  135. package/dist/views/instances/detail/sections/InstanceFormSection.d.cts +36 -0
  136. package/dist/views/instances/detail/sections/InstanceFormSection.d.ts +1 -1
  137. package/dist/views/instances/detail/sections/InstanceHistorySection.d.cts +29 -0
  138. package/dist/views/instances/detail/sections/InstanceSignaturesSection.d.cts +14 -0
  139. package/dist/views/instances/detail/sections/InstanceTasksSection.d.cts +55 -0
  140. package/dist/views/instances/detail/sections/InstanceWebhookDeliveriesSection.d.cts +20 -0
  141. package/dist/views/instances/detail/sections/container-helpers.d.cts +10 -0
  142. package/dist/views/instances/detail/sections/container-helpers.d.ts +1 -1
  143. package/dist/views/instances/detail/sections/shared.d.cts +141 -0
  144. package/dist/views/instances/detail/submitted-by.d.cts +23 -0
  145. package/dist/views/instances/index.d.cts +1 -0
  146. package/dist/views/instances/index.d.ts +1 -1
  147. package/dist/views/instances/new/InstanceNewView.d.cts +15 -0
  148. package/dist/views/instances/new/index.d.cts +1 -0
  149. package/dist/views/instances/new/index.d.ts +1 -1
  150. package/dist/views/login/LoginView.d.cts +47 -0
  151. package/dist/views/login/index.d.cts +1 -0
  152. package/dist/views/login/index.d.ts +1 -1
  153. package/dist/views/root/RootView.d.cts +10 -0
  154. package/dist/views/root/index.d.cts +1 -0
  155. package/dist/views/root/index.d.ts +1 -1
  156. package/dist/views/search/SearchView.d.cts +7 -0
  157. package/dist/views/search/index.d.cts +1 -0
  158. package/dist/views/search/index.d.ts +1 -1
  159. package/dist/views/sent/SentView.d.cts +7 -0
  160. package/dist/views/sent/index.d.cts +1 -0
  161. package/dist/views/sent/index.d.ts +1 -1
  162. package/dist/views/settings/index.d.cts +1 -0
  163. package/dist/views/settings/index.d.ts +1 -1
  164. package/dist/views/settings/notifications/SettingsNotificationsView.d.cts +2 -0
  165. package/dist/views/settings/notifications/index.d.cts +1 -0
  166. package/dist/views/settings/notifications/index.d.ts +1 -1
  167. package/dist/views/templates/TemplatesView.d.cts +7 -0
  168. package/dist/views/templates/categories/TemplateCategoriesView.d.cts +2 -0
  169. package/dist/views/templates/categories/index.cjs +1 -1
  170. package/dist/views/templates/categories/index.d.cts +1 -0
  171. package/dist/views/templates/categories/index.d.ts +1 -1
  172. package/dist/views/templates/categories/index.js +1 -1
  173. package/dist/views/templates/compose/TemplateComposeWizardView.d.cts +21 -0
  174. package/dist/views/templates/compose/index.cjs +1 -1
  175. package/dist/views/templates/compose/index.d.cts +2 -0
  176. package/dist/views/templates/compose/index.d.ts +2 -2
  177. package/dist/views/templates/compose/index.js +1 -1
  178. package/dist/views/templates/compose/steps/ComposeFormStep.d.cts +15 -0
  179. package/dist/views/templates/compose/steps/ComposeReviewStep.d.cts +12 -0
  180. package/dist/views/templates/compose/steps/ComposeWorkflowStep.d.cts +22 -0
  181. package/dist/views/templates/compose/use-template-compose-wizard.d.cts +46 -0
  182. package/dist/views/templates/designer/NotifyWebhookTargetsEditor.d.cts +20 -0
  183. package/dist/views/templates/designer/NotifyWebhookTargetsEditor.d.ts +1 -1
  184. package/dist/views/templates/designer/TemplateDesignerView.d.cts +65 -0
  185. package/dist/views/templates/designer/chrome-workflow-chat.d.cts +12 -0
  186. package/dist/views/templates/designer/chrome-workflow-chat.d.ts +1 -1
  187. package/dist/views/templates/designer/decision-policy-options.d.cts +8 -0
  188. package/dist/views/templates/designer/designer-version-labels.d.cts +12 -0
  189. package/dist/views/templates/designer/dry-run-assignee-label.d.cts +28 -0
  190. package/dist/views/templates/designer/dry-run-sample-data.d.cts +9 -0
  191. package/dist/views/templates/designer/dynamic-form-resolver-options.d.cts +35 -0
  192. package/dist/views/templates/designer/index.cjs +1 -1
  193. package/dist/views/templates/designer/index.d.cts +1 -0
  194. package/dist/views/templates/designer/index.d.ts +1 -1
  195. package/dist/views/templates/designer/index.js +1 -1
  196. package/dist/views/templates/designer/notify-webhook-designer.d.cts +74 -0
  197. package/dist/views/templates/designer/position-level-options.d.cts +17 -0
  198. package/dist/views/templates/designer/use-workflow-chat.d.cts +21 -0
  199. package/dist/views/templates/designer/use-workflow-chat.d.ts +1 -1
  200. package/dist/views/templates/designer/use-workflow-designer-controller.d.cts +41 -0
  201. package/dist/views/templates/designer/workflow-chat-drawer.d.cts +16 -0
  202. package/dist/views/templates/designer/workflow-chat-drawer.d.ts +1 -1
  203. package/dist/views/templates/index.cjs +1 -1
  204. package/dist/views/templates/index.d.cts +3 -0
  205. package/dist/views/templates/index.d.ts +3 -3
  206. package/dist/views/templates/index.js +1 -1
  207. package/dist/views/templates/versions/TemplateVersionsView.d.cts +5 -0
  208. package/dist/views/templates/versions/index.d.cts +1 -0
  209. package/dist/views/templates/versions/index.d.ts +1 -1
  210. package/dist/views/workflow/index.d.cts +4 -0
  211. package/dist/views/workflow/index.d.ts +4 -4
  212. package/package.json +387 -147
  213. package/dist/chunks/admin-pickers-DxhzECkD.js.map +0 -1
  214. package/dist/chunks/admin-pickers-qe3j--gX.cjs +0 -2
  215. package/dist/chunks/admin-pickers-qe3j--gX.cjs.map +0 -1
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { t as e } from "./bpm-form-field-Cao0rMol.js";
3
3
  import { t } from "./format-member-label-DudVI55w.js";
4
- import { t as n } from "./admin-pickers-DxhzECkD.js";
4
+ import { t as n } from "./admin-pickers-Djq3h-UR.js";
5
5
  import { useCallback as r, useEffect as i, useMemo as a, useRef as o, useState as s } from "react";
6
6
  import { BaseCard as c, Button as l, Filter as u, FilterArea as d, FilterLine as f, FormField as p, Input as m, Modal as h, PageHeader as g, Section as _, SectionGroup as v, Table as y, Typography as b } from "@mezzanine-ui/react";
7
7
  import { listMemberDirectoryPage as x, resolveMembers as S } from "@rytass/bpm-core-client";
@@ -419,4 +419,4 @@ function U(e) {
419
419
  //#endregion
420
420
  export { R as t };
421
421
 
422
- //# sourceMappingURL=users-BCyePbwB.js.map
422
+ //# sourceMappingURL=users-DRbuDYF1.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"users-BCyePbwB.js","names":["readErrorMessage","styles","_Fragment","styles","BPMFormField","MemberPicker","Fragment$1","ContentHeader","users_module_default","MemberTaskReassignModal","tasks","setTasks","useState","tasksLoading","setTasksLoading","target","setTarget","reason","setReason","preview","setPreview","committed","setCommitted","busy","setBusy","error","setError","trimmedReason","inputKey","previewIsCurrent","canConfirm","result","latestRequestRef","useRef","loadTasks","useCallback","request","loaded","listMemberOpenTasks","memberId","requestError","readErrorMessage$1","member","titleById","useMemo","task","runReassignment","outcomes","reassignMemberTasks","dryRun","shownResultRows","shownResults","shownTitleById","readOutcomeLabel","taskColumns","record","resultColumns","Modal","onClose","Typography","Table","option","Input","event","Button","outcome","MEMBER_PAGE_SIZE_OPTIONS","AdminUsersView","detailMember","setDetailMember","detailMemberships","setDetailMemberships","detailManagerProfile","setDetailManagerProfile","detailResolvedManager","setDetailResolvedManager","loading","setLoading","memberPage","setMemberPage","memberPageSize","setMemberPageSize","memberTotalCount","setMemberTotalCount","members","setMembers","orgUnits","setOrgUnits","positions","setPositions","reassignMember","setReassignMember","searchText","setSearchText","orgUnitsById","orgUnit","positionsById","position","refreshMembers","memberPageResult","organization","listMemberDirectoryPage","readOrganizationDashboard","readErrorMessage","rows","openDetail","memberships","resolvedManager","listMemberships","readResolvedManager","resolveMembers","columns","tableActions","closeDetail","PageHeader","SectionGroup","Section","FilterArea","FilterLine","Filter","FormField","FormFieldLayout","page","pageSize","from","to","total","MemberDetailModal","BaseCard","readOrgUnitLabel","membership","readPositionLabel","readMemberLabel","managerProfile","formatMemberLabel"],"sources":["../../src/views/admin/users/users.module.scss","../../src/views/admin/users/MemberTaskReassignModal.tsx","../../src/views/admin/users/AdminUsersView.tsx"],"sourcesContent":[".memberFilterArea {\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 :global(.mzn-input),\n :global(.mzn-input-container),\n :global(.mzn-text-field) {\n width: 100%;\n min-width: 0 !important;\n }\n}\n\n.header {\n display: grid;\n gap: 4px;\n padding: 24px 24px 0;\n}\n\n.detailFields {\n display: grid;\n gap: 16px;\n}\n\n.detailSection {\n display: grid;\n gap: 8px;\n}\n\n.membershipList {\n display: grid;\n gap: 8px;\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { Button, Input, Modal, Table, Typography } from '@mezzanine-ui/react';\nimport type { TableColumn } from '@mezzanine-ui/core/table';\nimport type { MemberProfileRecord } from '@rytass/bpm-core-client';\nimport {\n listMemberOpenTasks,\n type MemberOpenTaskRecord,\n reassignMemberTasks,\n type TaskReassignmentResultRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { MemberOption, MemberPicker } from '../../../components/admin-pickers';\nimport styles from './users.module.scss';\n\ntype TaskRow = Readonly<\n Record<string, unknown> &\n MemberOpenTaskRecord & {\n key: string;\n }\n>;\n\ntype ResultRow = Readonly<\n Record<string, unknown> & {\n instanceTitle: string;\n key: string;\n message: string | null;\n outcomeLabel: string;\n }\n>;\n\ninterface PreviewState {\n readonly inputKey: string;\n readonly results: readonly TaskReassignmentResultRecord[];\n}\n\n/**\n * A committed run keeps the titles it was started with: the task list reloads\n * right after, and a member whose every task moved no longer lists any of them.\n */\ninterface CommittedState {\n readonly results: readonly TaskReassignmentResultRecord[];\n readonly titleById: ReadonlyMap<string, string>;\n}\n\n/**\n * Administrator reassignment of a member's open tasks. Lists what the member\n * holds, takes a target and a reason, previews every task's outcome (dry run),\n * and only then commits. Confirm stays disabled until the preview matches the\n * current target and reason. Replacing a seat is not a decision: no signature\n * is written, and the task keeps its id.\n */\nexport function MemberTaskReassignModal({\n member,\n onClose,\n}: {\n readonly member: MemberProfileRecord | null;\n readonly onClose: () => void;\n}): ReactElement {\n const [tasks, setTasks] = useState<readonly MemberOpenTaskRecord[]>([]);\n const [tasksLoading, setTasksLoading] = useState(false);\n const [target, setTarget] = useState<MemberOption | null>(null);\n const [reason, setReason] = useState('');\n const [preview, setPreview] = useState<PreviewState | null>(null);\n const [committed, setCommitted] = useState<CommittedState | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const trimmedReason = reason.trim();\n const inputKey = `${target?.id ?? ''}|${trimmedReason}`;\n const previewIsCurrent = preview !== null && preview.inputKey === inputKey;\n const canConfirm =\n preview !== null &&\n previewIsCurrent &&\n preview.results.some((result) => result.outcome === 'WOULD_REASSIGN');\n\n // Only the latest request may write: switching members while an earlier\n // listing is in flight must not let its late answer replace the current one.\n const latestRequestRef = useRef(0);\n\n const loadTasks = useCallback(async (memberId: string): Promise<void> => {\n const request = latestRequestRef.current + 1;\n\n latestRequestRef.current = request;\n setTasksLoading(true);\n\n try {\n const loaded = await listMemberOpenTasks(memberId);\n\n if (latestRequestRef.current === request) {\n setTasks(loaded);\n }\n } catch (requestError: unknown) {\n if (latestRequestRef.current === request) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (latestRequestRef.current === request) {\n setTasksLoading(false);\n }\n }\n }, []);\n\n useEffect((): void => {\n setTarget(null);\n setReason('');\n setPreview(null);\n setCommitted(null);\n setError(null);\n\n if (!member) {\n latestRequestRef.current += 1;\n setTasks([]);\n setTasksLoading(false);\n\n return;\n }\n\n setTasks([]);\n void loadTasks(member.memberId);\n }, [member, loadTasks]);\n\n const titleById = useMemo(\n (): ReadonlyMap<string, string> =>\n new Map(tasks.map((task) => [task.taskId, task.instanceTitle])),\n [tasks],\n );\n\n async function runReassignment(dryRun: boolean): Promise<void> {\n if (!member || !target || !trimmedReason) {\n return;\n }\n\n setBusy(true);\n setError(null);\n\n try {\n const outcomes = await reassignMemberTasks({\n dryRun,\n fromMemberId: member.memberId,\n reason: trimmedReason,\n toMemberId: target.id,\n });\n\n if (dryRun) {\n setPreview({ inputKey, results: outcomes });\n setCommitted(null);\n } else {\n setCommitted({ results: outcomes, titleById });\n setPreview(null);\n await loadTasks(member.memberId);\n }\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setBusy(false);\n }\n }\n\n const shownResultRows = useMemo((): ResultRow[] => {\n const shownResults = committed?.results ?? preview?.results ?? [];\n const shownTitleById = committed?.titleById ?? titleById;\n\n return shownResults.map((result) => ({\n instanceTitle: shownTitleById.get(result.taskId) ?? result.taskId,\n key: result.taskId,\n message: result.message,\n outcomeLabel: readOutcomeLabel(result.outcome),\n }));\n }, [committed, preview, titleById]);\n\n const taskColumns = useMemo(\n (): TableColumn<TaskRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'nodeLabel',\n key: 'nodeLabel',\n title: '節點',\n width: 160,\n },\n {\n key: 'memberRole',\n render: (record: TaskRow): string =>\n record.memberRole === 'ASSIGNEE' ? '指派人' : '會簽候選人',\n title: '身分',\n width: 120,\n },\n ],\n [],\n );\n const resultColumns = useMemo(\n (): TableColumn<ResultRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'outcomeLabel',\n key: 'outcomeLabel',\n title: '結果',\n width: 100,\n },\n {\n dataIndex: 'message',\n key: 'message',\n title: '說明',\n width: 160,\n },\n ],\n [],\n );\n\n return (\n <Modal\n cancelText=\"關閉\"\n confirmButtonProps={{ disabled: !canConfirm || busy }}\n confirmText=\"確認改派\"\n loading={busy}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void => {\n void runReassignment(false);\n }}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member ? `改派待辦:${member.name}` : '改派待辦'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <Typography variant=\"body\">\n 改派會保留任務編號,但不產生簽核紀錄;原簽核人的待辦會結案為已轉交,\n 接手人會收到新的待辦通知。\n </Typography>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {tasks.length ? (\n <Table\n columns={taskColumns}\n dataSource={tasks.map((task): TaskRow => ({\n ...task,\n key: task.taskId,\n }))}\n fullWidth\n loading={tasksLoading}\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n {tasksLoading ? '載入待辦中…' : '此成員目前沒有待簽任務。'}\n </Typography>\n )}\n <BPMFormField label=\"接手人\" name=\"reassignTarget\">\n <MemberPicker\n name=\"reassignTarget\"\n onChange={(option): void => {\n setTarget(option);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"搜尋接手人姓名或信箱\"\n value={target}\n />\n </BPMFormField>\n <BPMFormField label=\"改派原因\" name=\"reassignReason\">\n <Input\n fullWidth\n name=\"reassignReason\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setReason(event.target.value);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"例如:原簽核人已離職\"\n value={reason}\n />\n </BPMFormField>\n <div className={styles.membershipList}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 先按「預覽」確認每筆任務的結果,確認無誤後再按「確認改派」。\n </Typography>\n <div>\n <Button\n disabled={\n busy || !target || !trimmedReason || tasks.length === 0\n }\n onClick={(): void => {\n void runReassignment(true);\n }}\n variant=\"base-secondary\"\n >\n 預覽\n </Button>\n </div>\n </div>\n {shownResultRows.length ? (\n <Table\n columns={resultColumns}\n dataSource={shownResultRows}\n fullWidth\n />\n ) : null}\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOutcomeLabel(\n outcome: TaskReassignmentResultRecord['outcome'],\n): string {\n if (outcome === 'WOULD_REASSIGN') {\n return '會改派';\n }\n\n if (outcome === 'REASSIGNED') {\n return '已改派';\n }\n\n return '會被拒';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '改派待辦失敗。';\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n BaseCard,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { formatMemberLabel } from '../../../lib/format-member-label';\nimport styles from './users.module.scss';\nimport { MemberTaskReassignModal } from './MemberTaskReassignModal';\nimport {\n listMemberDirectoryPage,\n MemberProfileRecord,\n resolveMembers,\n} from '@rytass/bpm-core-client';\nimport {\n listMemberships,\n MembershipRecord,\n OrgUnitRecord,\n PositionRecord,\n readOrganizationDashboard,\n readResolvedManager,\n ResolvedManagerRecord,\n} from '@rytass/bpm-core-client/organization';\n\ntype MemberRow = Readonly<\n Record<string, unknown> &\n MemberProfileRecord & {\n key: string;\n }\n>;\n\nconst MEMBER_PAGE_SIZE_OPTIONS = [10, 20, 50];\n\nexport function AdminUsersView(): ReactElement {\n const [detailMember, setDetailMember] = useState<MemberProfileRecord | null>(\n null,\n );\n const [detailMemberships, setDetailMemberships] = useState<\n readonly MembershipRecord[]\n >([]);\n const [detailManagerProfile, setDetailManagerProfile] =\n useState<MemberProfileRecord | null>(null);\n const [detailResolvedManager, setDetailResolvedManager] =\n useState<ResolvedManagerRecord | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [memberPage, setMemberPage] = useState(1);\n const [memberPageSize, setMemberPageSize] = useState(10);\n const [memberTotalCount, setMemberTotalCount] = useState(0);\n const [members, setMembers] = useState<readonly MemberProfileRecord[]>([]);\n const [orgUnits, setOrgUnits] = useState<readonly OrgUnitRecord[]>([]);\n const [positions, setPositions] = useState<readonly PositionRecord[]>([]);\n const [reassignMember, setReassignMember] =\n useState<MemberProfileRecord | null>(null);\n const [searchText, setSearchText] = useState('');\n\n const orgUnitsById = useMemo(\n (): ReadonlyMap<string, OrgUnitRecord> =>\n new Map(orgUnits.map((orgUnit) => [orgUnit.id, orgUnit])),\n [orgUnits],\n );\n const positionsById = useMemo(\n (): ReadonlyMap<string, PositionRecord> =>\n new Map(positions.map((position) => [position.id, position])),\n [positions],\n );\n\n const refreshMembers = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const [memberPageResult, organization] = await Promise.all([\n listMemberDirectoryPage({\n page: memberPage,\n pageSize: memberPageSize,\n searchText,\n }),\n readOrganizationDashboard(),\n ]);\n\n setMembers(memberPageResult.members);\n setMemberTotalCount(memberPageResult.totalCount);\n setOrgUnits(organization.orgUnits);\n setPositions(organization.positions);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [memberPage, memberPageSize, searchText]);\n\n useEffect((): void => {\n void refreshMembers();\n }, [refreshMembers]);\n\n const rows = useMemo(\n (): MemberRow[] =>\n members.map((member) => ({\n ...member,\n key: member.memberId,\n })),\n [members],\n );\n\n const openDetail = useCallback(\n async (member: MemberProfileRecord): Promise<void> => {\n setDetailMember(member);\n setDetailManagerProfile(null);\n setError(null);\n\n try {\n const [memberships, resolvedManager] = await Promise.all([\n listMemberships({ memberId: member.memberId }),\n readResolvedManager(member.memberId),\n ]);\n\n setDetailMemberships(memberships);\n setDetailResolvedManager(resolvedManager);\n setDetailManagerProfile(\n (\n await resolveMembers(\n resolvedManager.managerMemberId\n ? [resolvedManager.managerMemberId]\n : [],\n )\n )[0] ?? null,\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n }\n },\n [],\n );\n\n const columns = useMemo(\n (): TableColumn<MemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<MemberRow> => ({\n render: (): ReturnType<TableActions<MemberRow>['render']> => [\n {\n name: '檢視',\n onClick: (record): void => {\n void openDetail(record);\n },\n },\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember(record);\n },\n },\n ],\n variant: 'base-secondary',\n width: 176,\n }),\n [openDetail],\n );\n\n function closeDetail(): void {\n setDetailMember(null);\n setDetailManagerProfile(null);\n setDetailMemberships([]);\n setDetailResolvedManager(null);\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"會員資料由 host member resolver 提供,BPM 僅維護組織歸屬與主管解析。\"\n title=\"會員對照\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.memberFilterArea}>\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"memberSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setMemberPage(1);\n }}\n placeholder=\"搜尋姓名或信箱\"\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\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: memberPage,\n onChange: (page): void => {\n setMemberPage(page);\n },\n onChangePageSize: (pageSize): void => {\n setMemberPage(1);\n setMemberPageSize(pageSize);\n },\n pageSize: memberPageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: MEMBER_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: memberTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n\n <MemberTaskReassignModal\n member={reassignMember}\n onClose={(): void => {\n setReassignMember(null);\n }}\n />\n\n <MemberDetailModal\n managerProfile={detailManagerProfile}\n member={detailMember}\n memberships={detailMemberships}\n onClose={closeDetail}\n orgUnitsById={orgUnitsById}\n positionsById={positionsById}\n resolvedManager={detailResolvedManager}\n />\n </>\n );\n}\n\nfunction MemberDetailModal({\n managerProfile,\n member,\n memberships,\n onClose,\n orgUnitsById,\n positionsById,\n resolvedManager,\n}: {\n readonly managerProfile: MemberProfileRecord | null;\n readonly member: MemberProfileRecord | null;\n readonly memberships: readonly MembershipRecord[];\n readonly onClose: () => void;\n readonly orgUnitsById: ReadonlyMap<string, OrgUnitRecord>;\n readonly positionsById: ReadonlyMap<string, PositionRecord>;\n readonly resolvedManager: ResolvedManagerRecord | null;\n}): ReactElement {\n return (\n <Modal\n cancelText=\"關閉\"\n confirmText=\"關閉\"\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={onClose}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member?.name ?? '會員明細'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <BaseCard title=\"基本資料\">\n <div className={styles.detailSection}>\n <Typography variant=\"body\">\n 信箱:{member.email?.trim() ? member.email : '未設定'}\n </Typography>\n </div>\n </BaseCard>\n <BaseCard title=\"BPM 組織歸屬\">\n <div className={styles.membershipList}>\n {memberships.length ? (\n memberships.map((membership) => (\n <Typography key={membership.id} variant=\"body\">\n {readOrgUnitLabel(orgUnitsById.get(membership.orgUnitId))}\n {' / '}\n {membership.positionId\n ? readPositionLabel(\n positionsById.get(membership.positionId),\n )\n : '未指定職位'}\n {' / '}\n {membership.isPrimary ? '主要' : '一般'}\n </Typography>\n ))\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 尚未建立 BPM 組織歸屬\n </Typography>\n )}\n </div>\n </BaseCard>\n <BaseCard title=\"主管解析\">\n <Typography variant=\"body\">\n {resolvedManager?.managerMemberId\n ? readMemberLabel(managerProfile)\n : '尚未解析到主管'}\n </Typography>\n </BaseCard>\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOrgUnitLabel(orgUnit: OrgUnitRecord | undefined): string {\n return orgUnit ? `${orgUnit.name} · ${orgUnit.code}` : '未知組織';\n}\n\nfunction readPositionLabel(position: PositionRecord | undefined): string {\n return position ? `${position.name} · ${position.code}` : '未知職位';\n}\n\nfunction readMemberLabel(member: MemberProfileRecord | null): string {\n return member\n ? formatMemberLabel(member.name, member.email, 'dot')\n : '主管資料尚未載入';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '讀取會員資料失敗。';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"users-DRbuDYF1.js","names":["readErrorMessage","styles","_Fragment","styles","BPMFormField","MemberPicker","Fragment$1","ContentHeader","users_module_default","MemberTaskReassignModal","tasks","setTasks","useState","tasksLoading","setTasksLoading","target","setTarget","reason","setReason","preview","setPreview","committed","setCommitted","busy","setBusy","error","setError","trimmedReason","inputKey","previewIsCurrent","canConfirm","result","latestRequestRef","useRef","loadTasks","useCallback","request","loaded","listMemberOpenTasks","memberId","requestError","readErrorMessage$1","member","titleById","useMemo","task","runReassignment","outcomes","reassignMemberTasks","dryRun","shownResultRows","shownResults","shownTitleById","readOutcomeLabel","taskColumns","record","resultColumns","Modal","onClose","Typography","Table","option","Input","event","Button","outcome","MEMBER_PAGE_SIZE_OPTIONS","AdminUsersView","detailMember","setDetailMember","detailMemberships","setDetailMemberships","detailManagerProfile","setDetailManagerProfile","detailResolvedManager","setDetailResolvedManager","loading","setLoading","memberPage","setMemberPage","memberPageSize","setMemberPageSize","memberTotalCount","setMemberTotalCount","members","setMembers","orgUnits","setOrgUnits","positions","setPositions","reassignMember","setReassignMember","searchText","setSearchText","orgUnitsById","orgUnit","positionsById","position","refreshMembers","memberPageResult","organization","listMemberDirectoryPage","readOrganizationDashboard","readErrorMessage","rows","openDetail","memberships","resolvedManager","listMemberships","readResolvedManager","resolveMembers","columns","tableActions","closeDetail","PageHeader","SectionGroup","Section","FilterArea","FilterLine","Filter","FormField","FormFieldLayout","page","pageSize","from","to","total","MemberDetailModal","BaseCard","readOrgUnitLabel","membership","readPositionLabel","readMemberLabel","managerProfile","formatMemberLabel"],"sources":["../../src/views/admin/users/users.module.scss","../../src/views/admin/users/MemberTaskReassignModal.tsx","../../src/views/admin/users/AdminUsersView.tsx"],"sourcesContent":[".memberFilterArea {\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 :global(.mzn-input),\n :global(.mzn-input-container),\n :global(.mzn-text-field) {\n width: 100%;\n min-width: 0 !important;\n }\n}\n\n.header {\n display: grid;\n gap: 4px;\n padding: 24px 24px 0;\n}\n\n.detailFields {\n display: grid;\n gap: 16px;\n}\n\n.detailSection {\n display: grid;\n gap: 8px;\n}\n\n.membershipList {\n display: grid;\n gap: 8px;\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { Button, Input, Modal, Table, Typography } from '@mezzanine-ui/react';\nimport type { TableColumn } from '@mezzanine-ui/core/table';\nimport type { MemberProfileRecord } from '@rytass/bpm-core-client';\nimport {\n listMemberOpenTasks,\n type MemberOpenTaskRecord,\n reassignMemberTasks,\n type TaskReassignmentResultRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { MemberOption, MemberPicker } from '../../../components/admin-pickers';\nimport styles from './users.module.scss';\n\ntype TaskRow = Readonly<\n Record<string, unknown> &\n MemberOpenTaskRecord & {\n key: string;\n }\n>;\n\ntype ResultRow = Readonly<\n Record<string, unknown> & {\n instanceTitle: string;\n key: string;\n message: string | null;\n outcomeLabel: string;\n }\n>;\n\ninterface PreviewState {\n readonly inputKey: string;\n readonly results: readonly TaskReassignmentResultRecord[];\n}\n\n/**\n * A committed run keeps the titles it was started with: the task list reloads\n * right after, and a member whose every task moved no longer lists any of them.\n */\ninterface CommittedState {\n readonly results: readonly TaskReassignmentResultRecord[];\n readonly titleById: ReadonlyMap<string, string>;\n}\n\n/**\n * Administrator reassignment of a member's open tasks. Lists what the member\n * holds, takes a target and a reason, previews every task's outcome (dry run),\n * and only then commits. Confirm stays disabled until the preview matches the\n * current target and reason. Replacing a seat is not a decision: no signature\n * is written, and the task keeps its id.\n */\nexport function MemberTaskReassignModal({\n member,\n onClose,\n}: {\n readonly member: MemberProfileRecord | null;\n readonly onClose: () => void;\n}): ReactElement {\n const [tasks, setTasks] = useState<readonly MemberOpenTaskRecord[]>([]);\n const [tasksLoading, setTasksLoading] = useState(false);\n const [target, setTarget] = useState<MemberOption | null>(null);\n const [reason, setReason] = useState('');\n const [preview, setPreview] = useState<PreviewState | null>(null);\n const [committed, setCommitted] = useState<CommittedState | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const trimmedReason = reason.trim();\n const inputKey = `${target?.id ?? ''}|${trimmedReason}`;\n const previewIsCurrent = preview !== null && preview.inputKey === inputKey;\n const canConfirm =\n preview !== null &&\n previewIsCurrent &&\n preview.results.some((result) => result.outcome === 'WOULD_REASSIGN');\n\n // Only the latest request may write: switching members while an earlier\n // listing is in flight must not let its late answer replace the current one.\n const latestRequestRef = useRef(0);\n\n const loadTasks = useCallback(async (memberId: string): Promise<void> => {\n const request = latestRequestRef.current + 1;\n\n latestRequestRef.current = request;\n setTasksLoading(true);\n\n try {\n const loaded = await listMemberOpenTasks(memberId);\n\n if (latestRequestRef.current === request) {\n setTasks(loaded);\n }\n } catch (requestError: unknown) {\n if (latestRequestRef.current === request) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (latestRequestRef.current === request) {\n setTasksLoading(false);\n }\n }\n }, []);\n\n useEffect((): void => {\n setTarget(null);\n setReason('');\n setPreview(null);\n setCommitted(null);\n setError(null);\n\n if (!member) {\n latestRequestRef.current += 1;\n setTasks([]);\n setTasksLoading(false);\n\n return;\n }\n\n setTasks([]);\n void loadTasks(member.memberId);\n }, [member, loadTasks]);\n\n const titleById = useMemo(\n (): ReadonlyMap<string, string> =>\n new Map(tasks.map((task) => [task.taskId, task.instanceTitle])),\n [tasks],\n );\n\n async function runReassignment(dryRun: boolean): Promise<void> {\n if (!member || !target || !trimmedReason) {\n return;\n }\n\n setBusy(true);\n setError(null);\n\n try {\n const outcomes = await reassignMemberTasks({\n dryRun,\n fromMemberId: member.memberId,\n reason: trimmedReason,\n toMemberId: target.id,\n });\n\n if (dryRun) {\n setPreview({ inputKey, results: outcomes });\n setCommitted(null);\n } else {\n setCommitted({ results: outcomes, titleById });\n setPreview(null);\n await loadTasks(member.memberId);\n }\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setBusy(false);\n }\n }\n\n const shownResultRows = useMemo((): ResultRow[] => {\n const shownResults = committed?.results ?? preview?.results ?? [];\n const shownTitleById = committed?.titleById ?? titleById;\n\n return shownResults.map((result) => ({\n instanceTitle: shownTitleById.get(result.taskId) ?? result.taskId,\n key: result.taskId,\n message: result.message,\n outcomeLabel: readOutcomeLabel(result.outcome),\n }));\n }, [committed, preview, titleById]);\n\n const taskColumns = useMemo(\n (): TableColumn<TaskRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'nodeLabel',\n key: 'nodeLabel',\n title: '節點',\n width: 160,\n },\n {\n key: 'memberRole',\n render: (record: TaskRow): string =>\n record.memberRole === 'ASSIGNEE' ? '指派人' : '會簽候選人',\n title: '身分',\n width: 120,\n },\n ],\n [],\n );\n const resultColumns = useMemo(\n (): TableColumn<ResultRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'outcomeLabel',\n key: 'outcomeLabel',\n title: '結果',\n width: 100,\n },\n {\n dataIndex: 'message',\n key: 'message',\n title: '說明',\n width: 160,\n },\n ],\n [],\n );\n\n return (\n <Modal\n cancelText=\"關閉\"\n confirmButtonProps={{ disabled: !canConfirm || busy }}\n confirmText=\"確認改派\"\n loading={busy}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void => {\n void runReassignment(false);\n }}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member ? `改派待辦:${member.name}` : '改派待辦'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <Typography variant=\"body\">\n 改派會保留任務編號,但不產生簽核紀錄;原簽核人的待辦會結案為已轉交,\n 接手人會收到新的待辦通知。\n </Typography>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {tasks.length ? (\n <Table\n columns={taskColumns}\n dataSource={tasks.map((task): TaskRow => ({\n ...task,\n key: task.taskId,\n }))}\n fullWidth\n loading={tasksLoading}\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n {tasksLoading ? '載入待辦中…' : '此成員目前沒有待簽任務。'}\n </Typography>\n )}\n <BPMFormField label=\"接手人\" name=\"reassignTarget\">\n <MemberPicker\n name=\"reassignTarget\"\n onChange={(option): void => {\n setTarget(option);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"搜尋接手人姓名或信箱\"\n value={target}\n />\n </BPMFormField>\n <BPMFormField label=\"改派原因\" name=\"reassignReason\">\n <Input\n fullWidth\n name=\"reassignReason\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setReason(event.target.value);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"例如:原簽核人已離職\"\n value={reason}\n />\n </BPMFormField>\n <div className={styles.membershipList}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 先按「預覽」確認每筆任務的結果,確認無誤後再按「確認改派」。\n </Typography>\n <div>\n <Button\n disabled={\n busy || !target || !trimmedReason || tasks.length === 0\n }\n onClick={(): void => {\n void runReassignment(true);\n }}\n variant=\"base-secondary\"\n >\n 預覽\n </Button>\n </div>\n </div>\n {shownResultRows.length ? (\n <Table\n columns={resultColumns}\n dataSource={shownResultRows}\n fullWidth\n />\n ) : null}\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOutcomeLabel(\n outcome: TaskReassignmentResultRecord['outcome'],\n): string {\n if (outcome === 'WOULD_REASSIGN') {\n return '會改派';\n }\n\n if (outcome === 'REASSIGNED') {\n return '已改派';\n }\n\n return '會被拒';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '改派待辦失敗。';\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n BaseCard,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { formatMemberLabel } from '../../../lib/format-member-label';\nimport styles from './users.module.scss';\nimport { MemberTaskReassignModal } from './MemberTaskReassignModal';\nimport {\n listMemberDirectoryPage,\n MemberProfileRecord,\n resolveMembers,\n} from '@rytass/bpm-core-client';\nimport {\n listMemberships,\n MembershipRecord,\n OrgUnitRecord,\n PositionRecord,\n readOrganizationDashboard,\n readResolvedManager,\n ResolvedManagerRecord,\n} from '@rytass/bpm-core-client/organization';\n\ntype MemberRow = Readonly<\n Record<string, unknown> &\n MemberProfileRecord & {\n key: string;\n }\n>;\n\nconst MEMBER_PAGE_SIZE_OPTIONS = [10, 20, 50];\n\nexport function AdminUsersView(): ReactElement {\n const [detailMember, setDetailMember] = useState<MemberProfileRecord | null>(\n null,\n );\n const [detailMemberships, setDetailMemberships] = useState<\n readonly MembershipRecord[]\n >([]);\n const [detailManagerProfile, setDetailManagerProfile] =\n useState<MemberProfileRecord | null>(null);\n const [detailResolvedManager, setDetailResolvedManager] =\n useState<ResolvedManagerRecord | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [memberPage, setMemberPage] = useState(1);\n const [memberPageSize, setMemberPageSize] = useState(10);\n const [memberTotalCount, setMemberTotalCount] = useState(0);\n const [members, setMembers] = useState<readonly MemberProfileRecord[]>([]);\n const [orgUnits, setOrgUnits] = useState<readonly OrgUnitRecord[]>([]);\n const [positions, setPositions] = useState<readonly PositionRecord[]>([]);\n const [reassignMember, setReassignMember] =\n useState<MemberProfileRecord | null>(null);\n const [searchText, setSearchText] = useState('');\n\n const orgUnitsById = useMemo(\n (): ReadonlyMap<string, OrgUnitRecord> =>\n new Map(orgUnits.map((orgUnit) => [orgUnit.id, orgUnit])),\n [orgUnits],\n );\n const positionsById = useMemo(\n (): ReadonlyMap<string, PositionRecord> =>\n new Map(positions.map((position) => [position.id, position])),\n [positions],\n );\n\n const refreshMembers = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const [memberPageResult, organization] = await Promise.all([\n listMemberDirectoryPage({\n page: memberPage,\n pageSize: memberPageSize,\n searchText,\n }),\n readOrganizationDashboard(),\n ]);\n\n setMembers(memberPageResult.members);\n setMemberTotalCount(memberPageResult.totalCount);\n setOrgUnits(organization.orgUnits);\n setPositions(organization.positions);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [memberPage, memberPageSize, searchText]);\n\n useEffect((): void => {\n void refreshMembers();\n }, [refreshMembers]);\n\n const rows = useMemo(\n (): MemberRow[] =>\n members.map((member) => ({\n ...member,\n key: member.memberId,\n })),\n [members],\n );\n\n const openDetail = useCallback(\n async (member: MemberProfileRecord): Promise<void> => {\n setDetailMember(member);\n setDetailManagerProfile(null);\n setError(null);\n\n try {\n const [memberships, resolvedManager] = await Promise.all([\n listMemberships({ memberId: member.memberId }),\n readResolvedManager(member.memberId),\n ]);\n\n setDetailMemberships(memberships);\n setDetailResolvedManager(resolvedManager);\n setDetailManagerProfile(\n (\n await resolveMembers(\n resolvedManager.managerMemberId\n ? [resolvedManager.managerMemberId]\n : [],\n )\n )[0] ?? null,\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n }\n },\n [],\n );\n\n const columns = useMemo(\n (): TableColumn<MemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<MemberRow> => ({\n render: (): ReturnType<TableActions<MemberRow>['render']> => [\n {\n name: '檢視',\n onClick: (record): void => {\n void openDetail(record);\n },\n },\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember(record);\n },\n },\n ],\n variant: 'base-secondary',\n width: 176,\n }),\n [openDetail],\n );\n\n function closeDetail(): void {\n setDetailMember(null);\n setDetailManagerProfile(null);\n setDetailMemberships([]);\n setDetailResolvedManager(null);\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"會員資料由 host member resolver 提供,BPM 僅維護組織歸屬與主管解析。\"\n title=\"會員對照\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.memberFilterArea}>\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"memberSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setMemberPage(1);\n }}\n placeholder=\"搜尋姓名或信箱\"\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\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: memberPage,\n onChange: (page): void => {\n setMemberPage(page);\n },\n onChangePageSize: (pageSize): void => {\n setMemberPage(1);\n setMemberPageSize(pageSize);\n },\n pageSize: memberPageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: MEMBER_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: memberTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n\n <MemberTaskReassignModal\n member={reassignMember}\n onClose={(): void => {\n setReassignMember(null);\n }}\n />\n\n <MemberDetailModal\n managerProfile={detailManagerProfile}\n member={detailMember}\n memberships={detailMemberships}\n onClose={closeDetail}\n orgUnitsById={orgUnitsById}\n positionsById={positionsById}\n resolvedManager={detailResolvedManager}\n />\n </>\n );\n}\n\nfunction MemberDetailModal({\n managerProfile,\n member,\n memberships,\n onClose,\n orgUnitsById,\n positionsById,\n resolvedManager,\n}: {\n readonly managerProfile: MemberProfileRecord | null;\n readonly member: MemberProfileRecord | null;\n readonly memberships: readonly MembershipRecord[];\n readonly onClose: () => void;\n readonly orgUnitsById: ReadonlyMap<string, OrgUnitRecord>;\n readonly positionsById: ReadonlyMap<string, PositionRecord>;\n readonly resolvedManager: ResolvedManagerRecord | null;\n}): ReactElement {\n return (\n <Modal\n cancelText=\"關閉\"\n confirmText=\"關閉\"\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={onClose}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member?.name ?? '會員明細'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <BaseCard title=\"基本資料\">\n <div className={styles.detailSection}>\n <Typography variant=\"body\">\n 信箱:{member.email?.trim() ? member.email : '未設定'}\n </Typography>\n </div>\n </BaseCard>\n <BaseCard title=\"BPM 組織歸屬\">\n <div className={styles.membershipList}>\n {memberships.length ? (\n memberships.map((membership) => (\n <Typography key={membership.id} variant=\"body\">\n {readOrgUnitLabel(orgUnitsById.get(membership.orgUnitId))}\n {' / '}\n {membership.positionId\n ? readPositionLabel(\n positionsById.get(membership.positionId),\n )\n : '未指定職位'}\n {' / '}\n {membership.isPrimary ? '主要' : '一般'}\n </Typography>\n ))\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 尚未建立 BPM 組織歸屬\n </Typography>\n )}\n </div>\n </BaseCard>\n <BaseCard title=\"主管解析\">\n <Typography variant=\"body\">\n {resolvedManager?.managerMemberId\n ? readMemberLabel(managerProfile)\n : '尚未解析到主管'}\n </Typography>\n </BaseCard>\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOrgUnitLabel(orgUnit: OrgUnitRecord | undefined): string {\n return orgUnit ? `${orgUnit.name} · ${orgUnit.code}` : '未知組織';\n}\n\nfunction readPositionLabel(position: PositionRecord | undefined): string {\n return position ? `${position.name} · ${position.code}` : '未知職位';\n}\n\nfunction readMemberLabel(member: MemberProfileRecord | null): string {\n return member\n ? formatMemberLabel(member.name, member.email, 'dot')\n : '主管資料尚未載入';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '讀取會員資料失敗。';\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use client";require('../users.css');const e=require("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./bpm-form-field-Bc6k4ZEO.cjs"),n=require("./format-member-label-t7ANTF62.cjs"),r=require("./admin-pickers-qe3j--gX.cjs");let i=require("react"),a=require("@mezzanine-ui/react"),o=require("@rytass/bpm-core-client"),s=require("react/jsx-runtime"),c=require("@rytass/bpm-core-client/workflow"),l=require("@mezzanine-ui/core/form"),u=require("@mezzanine-ui/react/ContentHeader");u=e.t(u,1);let d=require("@rytass/bpm-core-client/organization");var f={memberFilterArea:`bpm_memberFilterArea_9RB2k`,header:`bpm_header_sIEtg`,detailFields:`bpm_detailFields_TyKNL`,detailSection:`bpm_detailSection_-iLjy`,membershipList:`bpm_membershipList_5n9iq`};function p({member:e,onClose:n}){let[o,l]=(0,i.useState)([]),[u,d]=(0,i.useState)(!1),[p,g]=(0,i.useState)(null),[_,v]=(0,i.useState)(``),[y,b]=(0,i.useState)(null),[x,S]=(0,i.useState)(null),[C,w]=(0,i.useState)(!1),[T,E]=(0,i.useState)(null),D=_.trim(),O=`${p?.id??``}|${D}`,k=y!==null&&y.inputKey===O,A=y!==null&&k&&y.results.some(e=>e.outcome===`WOULD_REASSIGN`),j=(0,i.useRef)(0),M=(0,i.useCallback)(async e=>{let t=j.current+1;j.current=t,d(!0);try{let n=await(0,c.listMemberOpenTasks)(e);j.current===t&&l(n)}catch(e){j.current===t&&E(h(e))}finally{j.current===t&&d(!1)}},[]);(0,i.useEffect)(()=>{g(null),v(``),b(null),S(null),E(null),e?(l([]),M(e.memberId)):(j.current+=1,l([]),d(!1))},[e,M]);let N=(0,i.useMemo)(()=>new Map(o.map(e=>[e.taskId,e.instanceTitle])),[o]);async function P(t){if(e&&p&&D){w(!0),E(null);try{let n=await(0,c.reassignMemberTasks)({dryRun:t,fromMemberId:e.memberId,reason:D,toMemberId:p.id});t?(b({inputKey:O,results:n}),S(null)):(S({results:n,titleById:N}),b(null),await M(e.memberId))}catch(e){E(h(e))}finally{w(!1)}}}let F=(0,i.useMemo)(()=>{let e=x?.results??y?.results??[],t=x?.titleById??N;return e.map(e=>({instanceTitle:t.get(e.taskId)??e.taskId,key:e.taskId,message:e.message,outcomeLabel:m(e.outcome)}))},[x,y,N]),I=(0,i.useMemo)(()=>[{dataIndex:`instanceTitle`,key:`instanceTitle`,title:`案件`,width:220},{dataIndex:`nodeLabel`,key:`nodeLabel`,title:`節點`,width:160},{key:`memberRole`,render:e=>e.memberRole===`ASSIGNEE`?`指派人`:`會簽候選人`,title:`身分`,width:120}],[]),L=(0,i.useMemo)(()=>[{dataIndex:`instanceTitle`,key:`instanceTitle`,title:`案件`,width:220},{dataIndex:`outcomeLabel`,key:`outcomeLabel`,title:`結果`,width:100},{dataIndex:`message`,key:`message`,title:`說明`,width:160}],[]);return(0,s.jsx)(a.Modal,{cancelText:`關閉`,confirmButtonProps:{disabled:!A||C},confirmText:`確認改派`,loading:C,modalType:`standard`,onCancel:n,onClose:n,onConfirm:()=>{P(!1)},open:!!e,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:e?`改派待辦:${e.name}`:`改派待辦`,children:e?(0,s.jsxs)(`div`,{className:f.detailFields,children:[(0,s.jsx)(a.Typography,{variant:`body`,children:`改派會保留任務編號,但不產生簽核紀錄;原簽核人的待辦會結案為已轉交, 接手人會收到新的待辦通知。`}),T?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:T}):null,o.length?(0,s.jsx)(a.Table,{columns:I,dataSource:o.map(e=>({...e,key:e.taskId})),fullWidth:!0,loading:u}):(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:u?`載入待辦中…`:`此成員目前沒有待簽任務。`}),(0,s.jsx)(t.t,{label:`接手人`,name:`reassignTarget`,children:(0,s.jsx)(r.t,{name:`reassignTarget`,onChange:e=>{g(e),b(null),S(null)},placeholder:`搜尋接手人姓名或信箱`,value:p})}),(0,s.jsx)(t.t,{label:`改派原因`,name:`reassignReason`,children:(0,s.jsx)(a.Input,{fullWidth:!0,name:`reassignReason`,onChange:e=>{v(e.target.value),b(null),S(null)},placeholder:`例如:原簽核人已離職`,value:_})}),(0,s.jsxs)(`div`,{className:f.membershipList,children:[(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`caption`,children:`先按「預覽」確認每筆任務的結果,確認無誤後再按「確認改派」。`}),(0,s.jsx)(`div`,{children:(0,s.jsx)(a.Button,{disabled:C||!p||!D||o.length===0,onClick:()=>{P(!0)},variant:`base-secondary`,children:`預覽`})})]}),F.length?(0,s.jsx)(a.Table,{columns:L,dataSource:F,fullWidth:!0}):null]}):null})}function m(e){return e===`WOULD_REASSIGN`?`會改派`:e===`REASSIGNED`?`已改派`:`會被拒`}function h(e){return e instanceof Error?e.message:`改派待辦失敗。`}var g=[10,20,50];function _(){let[e,t]=(0,i.useState)(null),[n,r]=(0,i.useState)([]),[c,m]=(0,i.useState)(null),[h,_]=(0,i.useState)(null),[y,b]=(0,i.useState)(null),[x,C]=(0,i.useState)(!0),[w,T]=(0,i.useState)(1),[E,D]=(0,i.useState)(10),[O,k]=(0,i.useState)(0),[A,j]=(0,i.useState)([]),[M,N]=(0,i.useState)([]),[P,F]=(0,i.useState)([]),[I,L]=(0,i.useState)(null),[R,z]=(0,i.useState)(``),B=(0,i.useMemo)(()=>new Map(M.map(e=>[e.id,e])),[M]),V=(0,i.useMemo)(()=>new Map(P.map(e=>[e.id,e])),[P]),H=(0,i.useCallback)(async()=>{C(!0),b(null);try{let[e,t]=await Promise.all([(0,o.listMemberDirectoryPage)({page:w,pageSize:E,searchText:R}),(0,d.readOrganizationDashboard)()]);j(e.members),k(e.totalCount),N(t.orgUnits),F(t.positions)}catch(e){b(S(e))}finally{C(!1)}},[w,E,R]);(0,i.useEffect)(()=>{H()},[H]);let U=(0,i.useMemo)(()=>A.map(e=>({...e,key:e.memberId})),[A]),W=(0,i.useCallback)(async e=>{t(e),m(null),b(null);try{let[t,n]=await Promise.all([(0,d.listMemberships)({memberId:e.memberId}),(0,d.readResolvedManager)(e.memberId)]);r(t),_(n),m((await(0,o.resolveMembers)(n.managerMemberId?[n.managerMemberId]:[]))[0]??null)}catch(e){b(S(e))}},[]),G=(0,i.useMemo)(()=>[{dataIndex:`name`,key:`name`,title:`姓名`,width:160},{dataIndex:`email`,key:`email`,title:`信箱`,width:260}],[]),K=(0,i.useMemo)(()=>({render:()=>[{name:`檢視`,onClick:e=>{W(e)}},{name:`改派待辦`,onClick:e=>{L(e)}}],variant:`base-secondary`,width:176}),[W]);function q(){t(null),m(null),r([]),_(null)}return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.PageHeader,{children:(0,s.jsx)(u.default,{description:`會員資料由 host member resolver 提供,BPM 僅維護組織歸屬與主管解析。`,title:`會員對照`})}),(0,s.jsx)(a.SectionGroup,{children:(0,s.jsxs)(a.Section,{filterArea:(0,s.jsx)(a.FilterArea,{className:f.memberFilterArea,children:(0,s.jsx)(a.FilterLine,{children:(0,s.jsx)(a.Filter,{span:3,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:l.FormFieldLayout.VERTICAL,name:`memberSearchText`,children:(0,s.jsx)(a.Input,{fullWidth:!0,onChange:e=>{z(e.target.value),T(1)},placeholder:`搜尋姓名或信箱`,size:`sub`,value:R,variant:`base`})})})})}),children:[y?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:y}):null,(0,s.jsx)(a.Table,{actions:K,columns:G,dataSource:U,fullWidth:!0,loading:x,pagination:{current:w,onChange:e=>{T(e)},onChangePageSize:e=>{T(1),D(e)},pageSize:E,pageSizeLabel:`每頁筆數`,pageSizeOptions:g,renderResultSummary:(e,t,n)=>`顯示 ${e}-${t} 筆,共 ${n} 筆`,showPageSizeOptions:!0,total:O}})]})}),(0,s.jsx)(p,{member:I,onClose:()=>{L(null)}}),(0,s.jsx)(v,{managerProfile:c,member:e,memberships:n,onClose:q,orgUnitsById:B,positionsById:V,resolvedManager:h})]})}function v({managerProfile:e,member:t,memberships:n,onClose:r,orgUnitsById:i,positionsById:o,resolvedManager:c}){return(0,s.jsx)(a.Modal,{cancelText:`關閉`,confirmText:`關閉`,modalType:`standard`,onCancel:r,onClose:r,onConfirm:r,open:!!t,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:t?.name??`會員明細`,children:t?(0,s.jsxs)(`div`,{className:f.detailFields,children:[(0,s.jsx)(a.BaseCard,{title:`基本資料`,children:(0,s.jsx)(`div`,{className:f.detailSection,children:(0,s.jsxs)(a.Typography,{variant:`body`,children:[`信箱:`,t.email?.trim()?t.email:`未設定`]})})}),(0,s.jsx)(a.BaseCard,{title:`BPM 組織歸屬`,children:(0,s.jsx)(`div`,{className:f.membershipList,children:n.length?n.map(e=>(0,s.jsxs)(a.Typography,{variant:`body`,children:[y(i.get(e.orgUnitId)),` / `,e.positionId?b(o.get(e.positionId)):`未指定職位`,` / `,e.isPrimary?`主要`:`一般`]},e.id)):(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:`尚未建立 BPM 組織歸屬`})})}),(0,s.jsx)(a.BaseCard,{title:`主管解析`,children:(0,s.jsx)(a.Typography,{variant:`body`,children:c?.managerMemberId?x(e):`尚未解析到主管`})})]}):null})}function y(e){return e?`${e.name} · ${e.code}`:`未知組織`}function b(e){return e?`${e.name} · ${e.code}`:`未知職位`}function x(e){return e?n.t(e.name,e.email,`dot`):`主管資料尚未載入`}function S(e){return e instanceof Error?e.message:`讀取會員資料失敗。`}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return _}});
2
- //# sourceMappingURL=users-DVBJluFR.cjs.map
1
+ "use client";require('../users.css');const e=require("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./bpm-form-field-Bc6k4ZEO.cjs"),n=require("./format-member-label-t7ANTF62.cjs"),r=require("./admin-pickers-BRHk3qKq.cjs");let i=require("react"),a=require("@mezzanine-ui/react"),o=require("@rytass/bpm-core-client"),s=require("react/jsx-runtime"),c=require("@rytass/bpm-core-client/workflow"),l=require("@mezzanine-ui/core/form"),u=require("@mezzanine-ui/react/ContentHeader");u=e.t(u,1);let d=require("@rytass/bpm-core-client/organization");var f={memberFilterArea:`bpm_memberFilterArea_9RB2k`,header:`bpm_header_sIEtg`,detailFields:`bpm_detailFields_TyKNL`,detailSection:`bpm_detailSection_-iLjy`,membershipList:`bpm_membershipList_5n9iq`};function p({member:e,onClose:n}){let[o,l]=(0,i.useState)([]),[u,d]=(0,i.useState)(!1),[p,g]=(0,i.useState)(null),[_,v]=(0,i.useState)(``),[y,b]=(0,i.useState)(null),[x,S]=(0,i.useState)(null),[C,w]=(0,i.useState)(!1),[T,E]=(0,i.useState)(null),D=_.trim(),O=`${p?.id??``}|${D}`,k=y!==null&&y.inputKey===O,A=y!==null&&k&&y.results.some(e=>e.outcome===`WOULD_REASSIGN`),j=(0,i.useRef)(0),M=(0,i.useCallback)(async e=>{let t=j.current+1;j.current=t,d(!0);try{let n=await(0,c.listMemberOpenTasks)(e);j.current===t&&l(n)}catch(e){j.current===t&&E(h(e))}finally{j.current===t&&d(!1)}},[]);(0,i.useEffect)(()=>{g(null),v(``),b(null),S(null),E(null),e?(l([]),M(e.memberId)):(j.current+=1,l([]),d(!1))},[e,M]);let N=(0,i.useMemo)(()=>new Map(o.map(e=>[e.taskId,e.instanceTitle])),[o]);async function P(t){if(e&&p&&D){w(!0),E(null);try{let n=await(0,c.reassignMemberTasks)({dryRun:t,fromMemberId:e.memberId,reason:D,toMemberId:p.id});t?(b({inputKey:O,results:n}),S(null)):(S({results:n,titleById:N}),b(null),await M(e.memberId))}catch(e){E(h(e))}finally{w(!1)}}}let F=(0,i.useMemo)(()=>{let e=x?.results??y?.results??[],t=x?.titleById??N;return e.map(e=>({instanceTitle:t.get(e.taskId)??e.taskId,key:e.taskId,message:e.message,outcomeLabel:m(e.outcome)}))},[x,y,N]),I=(0,i.useMemo)(()=>[{dataIndex:`instanceTitle`,key:`instanceTitle`,title:`案件`,width:220},{dataIndex:`nodeLabel`,key:`nodeLabel`,title:`節點`,width:160},{key:`memberRole`,render:e=>e.memberRole===`ASSIGNEE`?`指派人`:`會簽候選人`,title:`身分`,width:120}],[]),L=(0,i.useMemo)(()=>[{dataIndex:`instanceTitle`,key:`instanceTitle`,title:`案件`,width:220},{dataIndex:`outcomeLabel`,key:`outcomeLabel`,title:`結果`,width:100},{dataIndex:`message`,key:`message`,title:`說明`,width:160}],[]);return(0,s.jsx)(a.Modal,{cancelText:`關閉`,confirmButtonProps:{disabled:!A||C},confirmText:`確認改派`,loading:C,modalType:`standard`,onCancel:n,onClose:n,onConfirm:()=>{P(!1)},open:!!e,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:e?`改派待辦:${e.name}`:`改派待辦`,children:e?(0,s.jsxs)(`div`,{className:f.detailFields,children:[(0,s.jsx)(a.Typography,{variant:`body`,children:`改派會保留任務編號,但不產生簽核紀錄;原簽核人的待辦會結案為已轉交, 接手人會收到新的待辦通知。`}),T?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:T}):null,o.length?(0,s.jsx)(a.Table,{columns:I,dataSource:o.map(e=>({...e,key:e.taskId})),fullWidth:!0,loading:u}):(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:u?`載入待辦中…`:`此成員目前沒有待簽任務。`}),(0,s.jsx)(t.t,{label:`接手人`,name:`reassignTarget`,children:(0,s.jsx)(r.t,{name:`reassignTarget`,onChange:e=>{g(e),b(null),S(null)},placeholder:`搜尋接手人姓名或信箱`,value:p})}),(0,s.jsx)(t.t,{label:`改派原因`,name:`reassignReason`,children:(0,s.jsx)(a.Input,{fullWidth:!0,name:`reassignReason`,onChange:e=>{v(e.target.value),b(null),S(null)},placeholder:`例如:原簽核人已離職`,value:_})}),(0,s.jsxs)(`div`,{className:f.membershipList,children:[(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`caption`,children:`先按「預覽」確認每筆任務的結果,確認無誤後再按「確認改派」。`}),(0,s.jsx)(`div`,{children:(0,s.jsx)(a.Button,{disabled:C||!p||!D||o.length===0,onClick:()=>{P(!0)},variant:`base-secondary`,children:`預覽`})})]}),F.length?(0,s.jsx)(a.Table,{columns:L,dataSource:F,fullWidth:!0}):null]}):null})}function m(e){return e===`WOULD_REASSIGN`?`會改派`:e===`REASSIGNED`?`已改派`:`會被拒`}function h(e){return e instanceof Error?e.message:`改派待辦失敗。`}var g=[10,20,50];function _(){let[e,t]=(0,i.useState)(null),[n,r]=(0,i.useState)([]),[c,m]=(0,i.useState)(null),[h,_]=(0,i.useState)(null),[y,b]=(0,i.useState)(null),[x,C]=(0,i.useState)(!0),[w,T]=(0,i.useState)(1),[E,D]=(0,i.useState)(10),[O,k]=(0,i.useState)(0),[A,j]=(0,i.useState)([]),[M,N]=(0,i.useState)([]),[P,F]=(0,i.useState)([]),[I,L]=(0,i.useState)(null),[R,z]=(0,i.useState)(``),B=(0,i.useMemo)(()=>new Map(M.map(e=>[e.id,e])),[M]),V=(0,i.useMemo)(()=>new Map(P.map(e=>[e.id,e])),[P]),H=(0,i.useCallback)(async()=>{C(!0),b(null);try{let[e,t]=await Promise.all([(0,o.listMemberDirectoryPage)({page:w,pageSize:E,searchText:R}),(0,d.readOrganizationDashboard)()]);j(e.members),k(e.totalCount),N(t.orgUnits),F(t.positions)}catch(e){b(S(e))}finally{C(!1)}},[w,E,R]);(0,i.useEffect)(()=>{H()},[H]);let U=(0,i.useMemo)(()=>A.map(e=>({...e,key:e.memberId})),[A]),W=(0,i.useCallback)(async e=>{t(e),m(null),b(null);try{let[t,n]=await Promise.all([(0,d.listMemberships)({memberId:e.memberId}),(0,d.readResolvedManager)(e.memberId)]);r(t),_(n),m((await(0,o.resolveMembers)(n.managerMemberId?[n.managerMemberId]:[]))[0]??null)}catch(e){b(S(e))}},[]),G=(0,i.useMemo)(()=>[{dataIndex:`name`,key:`name`,title:`姓名`,width:160},{dataIndex:`email`,key:`email`,title:`信箱`,width:260}],[]),K=(0,i.useMemo)(()=>({render:()=>[{name:`檢視`,onClick:e=>{W(e)}},{name:`改派待辦`,onClick:e=>{L(e)}}],variant:`base-secondary`,width:176}),[W]);function q(){t(null),m(null),r([]),_(null)}return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.PageHeader,{children:(0,s.jsx)(u.default,{description:`會員資料由 host member resolver 提供,BPM 僅維護組織歸屬與主管解析。`,title:`會員對照`})}),(0,s.jsx)(a.SectionGroup,{children:(0,s.jsxs)(a.Section,{filterArea:(0,s.jsx)(a.FilterArea,{className:f.memberFilterArea,children:(0,s.jsx)(a.FilterLine,{children:(0,s.jsx)(a.Filter,{span:3,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:l.FormFieldLayout.VERTICAL,name:`memberSearchText`,children:(0,s.jsx)(a.Input,{fullWidth:!0,onChange:e=>{z(e.target.value),T(1)},placeholder:`搜尋姓名或信箱`,size:`sub`,value:R,variant:`base`})})})})}),children:[y?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:y}):null,(0,s.jsx)(a.Table,{actions:K,columns:G,dataSource:U,fullWidth:!0,loading:x,pagination:{current:w,onChange:e=>{T(e)},onChangePageSize:e=>{T(1),D(e)},pageSize:E,pageSizeLabel:`每頁筆數`,pageSizeOptions:g,renderResultSummary:(e,t,n)=>`顯示 ${e}-${t} 筆,共 ${n} 筆`,showPageSizeOptions:!0,total:O}})]})}),(0,s.jsx)(p,{member:I,onClose:()=>{L(null)}}),(0,s.jsx)(v,{managerProfile:c,member:e,memberships:n,onClose:q,orgUnitsById:B,positionsById:V,resolvedManager:h})]})}function v({managerProfile:e,member:t,memberships:n,onClose:r,orgUnitsById:i,positionsById:o,resolvedManager:c}){return(0,s.jsx)(a.Modal,{cancelText:`關閉`,confirmText:`關閉`,modalType:`standard`,onCancel:r,onClose:r,onConfirm:r,open:!!t,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:t?.name??`會員明細`,children:t?(0,s.jsxs)(`div`,{className:f.detailFields,children:[(0,s.jsx)(a.BaseCard,{title:`基本資料`,children:(0,s.jsx)(`div`,{className:f.detailSection,children:(0,s.jsxs)(a.Typography,{variant:`body`,children:[`信箱:`,t.email?.trim()?t.email:`未設定`]})})}),(0,s.jsx)(a.BaseCard,{title:`BPM 組織歸屬`,children:(0,s.jsx)(`div`,{className:f.membershipList,children:n.length?n.map(e=>(0,s.jsxs)(a.Typography,{variant:`body`,children:[y(i.get(e.orgUnitId)),` / `,e.positionId?b(o.get(e.positionId)):`未指定職位`,` / `,e.isPrimary?`主要`:`一般`]},e.id)):(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:`尚未建立 BPM 組織歸屬`})})}),(0,s.jsx)(a.BaseCard,{title:`主管解析`,children:(0,s.jsx)(a.Typography,{variant:`body`,children:c?.managerMemberId?x(e):`尚未解析到主管`})})]}):null})}function y(e){return e?`${e.name} · ${e.code}`:`未知組織`}function b(e){return e?`${e.name} · ${e.code}`:`未知職位`}function x(e){return e?n.t(e.name,e.email,`dot`):`主管資料尚未載入`}function S(e){return e instanceof Error?e.message:`讀取會員資料失敗。`}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return _}});
2
+ //# sourceMappingURL=users-DVQicZIo.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"users-DVBJluFR.cjs","names":["useState","useRef","useCallback","listMemberOpenTasks","readErrorMessage","useMemo","reassignMemberTasks","Modal","styles","Typography","Table","BPMFormField","MemberPicker","Input","Button","useState","useMemo","useCallback","listMemberDirectoryPage","readOrganizationDashboard","listMemberships","readResolvedManager","resolveMembers","_Fragment","PageHeader","ContentHeader","SectionGroup","Section","FilterArea","styles","FilterLine","Filter","FormField","FormFieldLayout","Input","Typography","Table","Modal","BaseCard","formatMemberLabel","require_rolldown_runtime","require_bpm_form_field","require_format_member_label","require_admin_pickers","react","_mezzanine_ui_react","_rytass_bpm_core_client","react_jsx_runtime","_rytass_bpm_core_client_workflow","_mezzanine_ui_core_form","_mezzanine_ui_react_ContentHeader","_rytass_bpm_core_client_organization","users_module_default","MemberTaskReassignModal","tasks","setTasks","tasksLoading","setTasksLoading","target","setTarget","reason","setReason","preview","setPreview","committed","setCommitted","busy","setBusy","error","setError","trimmedReason","inputKey","previewIsCurrent","canConfirm","result","latestRequestRef","loadTasks","request","loaded","memberId","requestError","readErrorMessage$1","member","titleById","task","runReassignment","outcomes","dryRun","shownResultRows","shownResults","shownTitleById","readOutcomeLabel","taskColumns","record","resultColumns","onClose","option","event","outcome","MEMBER_PAGE_SIZE_OPTIONS","AdminUsersView","detailMember","setDetailMember","detailMemberships","setDetailMemberships","detailManagerProfile","setDetailManagerProfile","detailResolvedManager","setDetailResolvedManager","loading","setLoading","memberPage","setMemberPage","memberPageSize","setMemberPageSize","memberTotalCount","setMemberTotalCount","members","setMembers","orgUnits","setOrgUnits","positions","setPositions","reassignMember","setReassignMember","searchText","setSearchText","orgUnitsById","orgUnit","positionsById","position","refreshMembers","memberPageResult","organization","readErrorMessage","rows","openDetail","memberships","resolvedManager","columns","tableActions","closeDetail","page","pageSize","from","to","total","MemberDetailModal","readOrgUnitLabel","membership","readPositionLabel","readMemberLabel","managerProfile"],"sources":["../../src/views/admin/users/users.module.scss","../../src/views/admin/users/MemberTaskReassignModal.tsx","../../src/views/admin/users/AdminUsersView.tsx"],"sourcesContent":[".memberFilterArea {\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 :global(.mzn-input),\n :global(.mzn-input-container),\n :global(.mzn-text-field) {\n width: 100%;\n min-width: 0 !important;\n }\n}\n\n.header {\n display: grid;\n gap: 4px;\n padding: 24px 24px 0;\n}\n\n.detailFields {\n display: grid;\n gap: 16px;\n}\n\n.detailSection {\n display: grid;\n gap: 8px;\n}\n\n.membershipList {\n display: grid;\n gap: 8px;\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { Button, Input, Modal, Table, Typography } from '@mezzanine-ui/react';\nimport type { TableColumn } from '@mezzanine-ui/core/table';\nimport type { MemberProfileRecord } from '@rytass/bpm-core-client';\nimport {\n listMemberOpenTasks,\n type MemberOpenTaskRecord,\n reassignMemberTasks,\n type TaskReassignmentResultRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { MemberOption, MemberPicker } from '../../../components/admin-pickers';\nimport styles from './users.module.scss';\n\ntype TaskRow = Readonly<\n Record<string, unknown> &\n MemberOpenTaskRecord & {\n key: string;\n }\n>;\n\ntype ResultRow = Readonly<\n Record<string, unknown> & {\n instanceTitle: string;\n key: string;\n message: string | null;\n outcomeLabel: string;\n }\n>;\n\ninterface PreviewState {\n readonly inputKey: string;\n readonly results: readonly TaskReassignmentResultRecord[];\n}\n\n/**\n * A committed run keeps the titles it was started with: the task list reloads\n * right after, and a member whose every task moved no longer lists any of them.\n */\ninterface CommittedState {\n readonly results: readonly TaskReassignmentResultRecord[];\n readonly titleById: ReadonlyMap<string, string>;\n}\n\n/**\n * Administrator reassignment of a member's open tasks. Lists what the member\n * holds, takes a target and a reason, previews every task's outcome (dry run),\n * and only then commits. Confirm stays disabled until the preview matches the\n * current target and reason. Replacing a seat is not a decision: no signature\n * is written, and the task keeps its id.\n */\nexport function MemberTaskReassignModal({\n member,\n onClose,\n}: {\n readonly member: MemberProfileRecord | null;\n readonly onClose: () => void;\n}): ReactElement {\n const [tasks, setTasks] = useState<readonly MemberOpenTaskRecord[]>([]);\n const [tasksLoading, setTasksLoading] = useState(false);\n const [target, setTarget] = useState<MemberOption | null>(null);\n const [reason, setReason] = useState('');\n const [preview, setPreview] = useState<PreviewState | null>(null);\n const [committed, setCommitted] = useState<CommittedState | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const trimmedReason = reason.trim();\n const inputKey = `${target?.id ?? ''}|${trimmedReason}`;\n const previewIsCurrent = preview !== null && preview.inputKey === inputKey;\n const canConfirm =\n preview !== null &&\n previewIsCurrent &&\n preview.results.some((result) => result.outcome === 'WOULD_REASSIGN');\n\n // Only the latest request may write: switching members while an earlier\n // listing is in flight must not let its late answer replace the current one.\n const latestRequestRef = useRef(0);\n\n const loadTasks = useCallback(async (memberId: string): Promise<void> => {\n const request = latestRequestRef.current + 1;\n\n latestRequestRef.current = request;\n setTasksLoading(true);\n\n try {\n const loaded = await listMemberOpenTasks(memberId);\n\n if (latestRequestRef.current === request) {\n setTasks(loaded);\n }\n } catch (requestError: unknown) {\n if (latestRequestRef.current === request) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (latestRequestRef.current === request) {\n setTasksLoading(false);\n }\n }\n }, []);\n\n useEffect((): void => {\n setTarget(null);\n setReason('');\n setPreview(null);\n setCommitted(null);\n setError(null);\n\n if (!member) {\n latestRequestRef.current += 1;\n setTasks([]);\n setTasksLoading(false);\n\n return;\n }\n\n setTasks([]);\n void loadTasks(member.memberId);\n }, [member, loadTasks]);\n\n const titleById = useMemo(\n (): ReadonlyMap<string, string> =>\n new Map(tasks.map((task) => [task.taskId, task.instanceTitle])),\n [tasks],\n );\n\n async function runReassignment(dryRun: boolean): Promise<void> {\n if (!member || !target || !trimmedReason) {\n return;\n }\n\n setBusy(true);\n setError(null);\n\n try {\n const outcomes = await reassignMemberTasks({\n dryRun,\n fromMemberId: member.memberId,\n reason: trimmedReason,\n toMemberId: target.id,\n });\n\n if (dryRun) {\n setPreview({ inputKey, results: outcomes });\n setCommitted(null);\n } else {\n setCommitted({ results: outcomes, titleById });\n setPreview(null);\n await loadTasks(member.memberId);\n }\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setBusy(false);\n }\n }\n\n const shownResultRows = useMemo((): ResultRow[] => {\n const shownResults = committed?.results ?? preview?.results ?? [];\n const shownTitleById = committed?.titleById ?? titleById;\n\n return shownResults.map((result) => ({\n instanceTitle: shownTitleById.get(result.taskId) ?? result.taskId,\n key: result.taskId,\n message: result.message,\n outcomeLabel: readOutcomeLabel(result.outcome),\n }));\n }, [committed, preview, titleById]);\n\n const taskColumns = useMemo(\n (): TableColumn<TaskRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'nodeLabel',\n key: 'nodeLabel',\n title: '節點',\n width: 160,\n },\n {\n key: 'memberRole',\n render: (record: TaskRow): string =>\n record.memberRole === 'ASSIGNEE' ? '指派人' : '會簽候選人',\n title: '身分',\n width: 120,\n },\n ],\n [],\n );\n const resultColumns = useMemo(\n (): TableColumn<ResultRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'outcomeLabel',\n key: 'outcomeLabel',\n title: '結果',\n width: 100,\n },\n {\n dataIndex: 'message',\n key: 'message',\n title: '說明',\n width: 160,\n },\n ],\n [],\n );\n\n return (\n <Modal\n cancelText=\"關閉\"\n confirmButtonProps={{ disabled: !canConfirm || busy }}\n confirmText=\"確認改派\"\n loading={busy}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void => {\n void runReassignment(false);\n }}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member ? `改派待辦:${member.name}` : '改派待辦'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <Typography variant=\"body\">\n 改派會保留任務編號,但不產生簽核紀錄;原簽核人的待辦會結案為已轉交,\n 接手人會收到新的待辦通知。\n </Typography>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {tasks.length ? (\n <Table\n columns={taskColumns}\n dataSource={tasks.map((task): TaskRow => ({\n ...task,\n key: task.taskId,\n }))}\n fullWidth\n loading={tasksLoading}\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n {tasksLoading ? '載入待辦中…' : '此成員目前沒有待簽任務。'}\n </Typography>\n )}\n <BPMFormField label=\"接手人\" name=\"reassignTarget\">\n <MemberPicker\n name=\"reassignTarget\"\n onChange={(option): void => {\n setTarget(option);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"搜尋接手人姓名或信箱\"\n value={target}\n />\n </BPMFormField>\n <BPMFormField label=\"改派原因\" name=\"reassignReason\">\n <Input\n fullWidth\n name=\"reassignReason\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setReason(event.target.value);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"例如:原簽核人已離職\"\n value={reason}\n />\n </BPMFormField>\n <div className={styles.membershipList}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 先按「預覽」確認每筆任務的結果,確認無誤後再按「確認改派」。\n </Typography>\n <div>\n <Button\n disabled={\n busy || !target || !trimmedReason || tasks.length === 0\n }\n onClick={(): void => {\n void runReassignment(true);\n }}\n variant=\"base-secondary\"\n >\n 預覽\n </Button>\n </div>\n </div>\n {shownResultRows.length ? (\n <Table\n columns={resultColumns}\n dataSource={shownResultRows}\n fullWidth\n />\n ) : null}\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOutcomeLabel(\n outcome: TaskReassignmentResultRecord['outcome'],\n): string {\n if (outcome === 'WOULD_REASSIGN') {\n return '會改派';\n }\n\n if (outcome === 'REASSIGNED') {\n return '已改派';\n }\n\n return '會被拒';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '改派待辦失敗。';\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n BaseCard,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { formatMemberLabel } from '../../../lib/format-member-label';\nimport styles from './users.module.scss';\nimport { MemberTaskReassignModal } from './MemberTaskReassignModal';\nimport {\n listMemberDirectoryPage,\n MemberProfileRecord,\n resolveMembers,\n} from '@rytass/bpm-core-client';\nimport {\n listMemberships,\n MembershipRecord,\n OrgUnitRecord,\n PositionRecord,\n readOrganizationDashboard,\n readResolvedManager,\n ResolvedManagerRecord,\n} from '@rytass/bpm-core-client/organization';\n\ntype MemberRow = Readonly<\n Record<string, unknown> &\n MemberProfileRecord & {\n key: string;\n }\n>;\n\nconst MEMBER_PAGE_SIZE_OPTIONS = [10, 20, 50];\n\nexport function AdminUsersView(): ReactElement {\n const [detailMember, setDetailMember] = useState<MemberProfileRecord | null>(\n null,\n );\n const [detailMemberships, setDetailMemberships] = useState<\n readonly MembershipRecord[]\n >([]);\n const [detailManagerProfile, setDetailManagerProfile] =\n useState<MemberProfileRecord | null>(null);\n const [detailResolvedManager, setDetailResolvedManager] =\n useState<ResolvedManagerRecord | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [memberPage, setMemberPage] = useState(1);\n const [memberPageSize, setMemberPageSize] = useState(10);\n const [memberTotalCount, setMemberTotalCount] = useState(0);\n const [members, setMembers] = useState<readonly MemberProfileRecord[]>([]);\n const [orgUnits, setOrgUnits] = useState<readonly OrgUnitRecord[]>([]);\n const [positions, setPositions] = useState<readonly PositionRecord[]>([]);\n const [reassignMember, setReassignMember] =\n useState<MemberProfileRecord | null>(null);\n const [searchText, setSearchText] = useState('');\n\n const orgUnitsById = useMemo(\n (): ReadonlyMap<string, OrgUnitRecord> =>\n new Map(orgUnits.map((orgUnit) => [orgUnit.id, orgUnit])),\n [orgUnits],\n );\n const positionsById = useMemo(\n (): ReadonlyMap<string, PositionRecord> =>\n new Map(positions.map((position) => [position.id, position])),\n [positions],\n );\n\n const refreshMembers = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const [memberPageResult, organization] = await Promise.all([\n listMemberDirectoryPage({\n page: memberPage,\n pageSize: memberPageSize,\n searchText,\n }),\n readOrganizationDashboard(),\n ]);\n\n setMembers(memberPageResult.members);\n setMemberTotalCount(memberPageResult.totalCount);\n setOrgUnits(organization.orgUnits);\n setPositions(organization.positions);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [memberPage, memberPageSize, searchText]);\n\n useEffect((): void => {\n void refreshMembers();\n }, [refreshMembers]);\n\n const rows = useMemo(\n (): MemberRow[] =>\n members.map((member) => ({\n ...member,\n key: member.memberId,\n })),\n [members],\n );\n\n const openDetail = useCallback(\n async (member: MemberProfileRecord): Promise<void> => {\n setDetailMember(member);\n setDetailManagerProfile(null);\n setError(null);\n\n try {\n const [memberships, resolvedManager] = await Promise.all([\n listMemberships({ memberId: member.memberId }),\n readResolvedManager(member.memberId),\n ]);\n\n setDetailMemberships(memberships);\n setDetailResolvedManager(resolvedManager);\n setDetailManagerProfile(\n (\n await resolveMembers(\n resolvedManager.managerMemberId\n ? [resolvedManager.managerMemberId]\n : [],\n )\n )[0] ?? null,\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n }\n },\n [],\n );\n\n const columns = useMemo(\n (): TableColumn<MemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<MemberRow> => ({\n render: (): ReturnType<TableActions<MemberRow>['render']> => [\n {\n name: '檢視',\n onClick: (record): void => {\n void openDetail(record);\n },\n },\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember(record);\n },\n },\n ],\n variant: 'base-secondary',\n width: 176,\n }),\n [openDetail],\n );\n\n function closeDetail(): void {\n setDetailMember(null);\n setDetailManagerProfile(null);\n setDetailMemberships([]);\n setDetailResolvedManager(null);\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"會員資料由 host member resolver 提供,BPM 僅維護組織歸屬與主管解析。\"\n title=\"會員對照\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.memberFilterArea}>\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"memberSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setMemberPage(1);\n }}\n placeholder=\"搜尋姓名或信箱\"\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\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: memberPage,\n onChange: (page): void => {\n setMemberPage(page);\n },\n onChangePageSize: (pageSize): void => {\n setMemberPage(1);\n setMemberPageSize(pageSize);\n },\n pageSize: memberPageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: MEMBER_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: memberTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n\n <MemberTaskReassignModal\n member={reassignMember}\n onClose={(): void => {\n setReassignMember(null);\n }}\n />\n\n <MemberDetailModal\n managerProfile={detailManagerProfile}\n member={detailMember}\n memberships={detailMemberships}\n onClose={closeDetail}\n orgUnitsById={orgUnitsById}\n positionsById={positionsById}\n resolvedManager={detailResolvedManager}\n />\n </>\n );\n}\n\nfunction MemberDetailModal({\n managerProfile,\n member,\n memberships,\n onClose,\n orgUnitsById,\n positionsById,\n resolvedManager,\n}: {\n readonly managerProfile: MemberProfileRecord | null;\n readonly member: MemberProfileRecord | null;\n readonly memberships: readonly MembershipRecord[];\n readonly onClose: () => void;\n readonly orgUnitsById: ReadonlyMap<string, OrgUnitRecord>;\n readonly positionsById: ReadonlyMap<string, PositionRecord>;\n readonly resolvedManager: ResolvedManagerRecord | null;\n}): ReactElement {\n return (\n <Modal\n cancelText=\"關閉\"\n confirmText=\"關閉\"\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={onClose}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member?.name ?? '會員明細'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <BaseCard title=\"基本資料\">\n <div className={styles.detailSection}>\n <Typography variant=\"body\">\n 信箱:{member.email?.trim() ? member.email : '未設定'}\n </Typography>\n </div>\n </BaseCard>\n <BaseCard title=\"BPM 組織歸屬\">\n <div className={styles.membershipList}>\n {memberships.length ? (\n memberships.map((membership) => (\n <Typography key={membership.id} variant=\"body\">\n {readOrgUnitLabel(orgUnitsById.get(membership.orgUnitId))}\n {' / '}\n {membership.positionId\n ? readPositionLabel(\n positionsById.get(membership.positionId),\n )\n : '未指定職位'}\n {' / '}\n {membership.isPrimary ? '主要' : '一般'}\n </Typography>\n ))\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 尚未建立 BPM 組織歸屬\n </Typography>\n )}\n </div>\n </BaseCard>\n <BaseCard title=\"主管解析\">\n <Typography variant=\"body\">\n {resolvedManager?.managerMemberId\n ? readMemberLabel(managerProfile)\n : '尚未解析到主管'}\n </Typography>\n </BaseCard>\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOrgUnitLabel(orgUnit: OrgUnitRecord | undefined): string {\n return orgUnit ? `${orgUnit.name} · ${orgUnit.code}` : '未知組織';\n}\n\nfunction readPositionLabel(position: PositionRecord | undefined): string {\n return position ? `${position.name} · ${position.code}` : '未知職位';\n}\n\nfunction readMemberLabel(member: MemberProfileRecord | null): string {\n return member\n ? formatMemberLabel(member.name, member.email, 'dot')\n : '主管資料尚未載入';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '讀取會員資料失敗。';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"users-DVQicZIo.cjs","names":["useState","useRef","useCallback","listMemberOpenTasks","readErrorMessage","useMemo","reassignMemberTasks","Modal","styles","Typography","Table","BPMFormField","MemberPicker","Input","Button","useState","useMemo","useCallback","listMemberDirectoryPage","readOrganizationDashboard","listMemberships","readResolvedManager","resolveMembers","_Fragment","PageHeader","ContentHeader","SectionGroup","Section","FilterArea","styles","FilterLine","Filter","FormField","FormFieldLayout","Input","Typography","Table","Modal","BaseCard","formatMemberLabel","require_rolldown_runtime","require_bpm_form_field","require_format_member_label","require_admin_pickers","react","_mezzanine_ui_react","_rytass_bpm_core_client","react_jsx_runtime","_rytass_bpm_core_client_workflow","_mezzanine_ui_core_form","_mezzanine_ui_react_ContentHeader","_rytass_bpm_core_client_organization","users_module_default","MemberTaskReassignModal","tasks","setTasks","tasksLoading","setTasksLoading","target","setTarget","reason","setReason","preview","setPreview","committed","setCommitted","busy","setBusy","error","setError","trimmedReason","inputKey","previewIsCurrent","canConfirm","result","latestRequestRef","loadTasks","request","loaded","memberId","requestError","readErrorMessage$1","member","titleById","task","runReassignment","outcomes","dryRun","shownResultRows","shownResults","shownTitleById","readOutcomeLabel","taskColumns","record","resultColumns","onClose","option","event","outcome","MEMBER_PAGE_SIZE_OPTIONS","AdminUsersView","detailMember","setDetailMember","detailMemberships","setDetailMemberships","detailManagerProfile","setDetailManagerProfile","detailResolvedManager","setDetailResolvedManager","loading","setLoading","memberPage","setMemberPage","memberPageSize","setMemberPageSize","memberTotalCount","setMemberTotalCount","members","setMembers","orgUnits","setOrgUnits","positions","setPositions","reassignMember","setReassignMember","searchText","setSearchText","orgUnitsById","orgUnit","positionsById","position","refreshMembers","memberPageResult","organization","readErrorMessage","rows","openDetail","memberships","resolvedManager","columns","tableActions","closeDetail","page","pageSize","from","to","total","MemberDetailModal","readOrgUnitLabel","membership","readPositionLabel","readMemberLabel","managerProfile"],"sources":["../../src/views/admin/users/users.module.scss","../../src/views/admin/users/MemberTaskReassignModal.tsx","../../src/views/admin/users/AdminUsersView.tsx"],"sourcesContent":[".memberFilterArea {\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 :global(.mzn-input),\n :global(.mzn-input-container),\n :global(.mzn-text-field) {\n width: 100%;\n min-width: 0 !important;\n }\n}\n\n.header {\n display: grid;\n gap: 4px;\n padding: 24px 24px 0;\n}\n\n.detailFields {\n display: grid;\n gap: 16px;\n}\n\n.detailSection {\n display: grid;\n gap: 8px;\n}\n\n.membershipList {\n display: grid;\n gap: 8px;\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { Button, Input, Modal, Table, Typography } from '@mezzanine-ui/react';\nimport type { TableColumn } from '@mezzanine-ui/core/table';\nimport type { MemberProfileRecord } from '@rytass/bpm-core-client';\nimport {\n listMemberOpenTasks,\n type MemberOpenTaskRecord,\n reassignMemberTasks,\n type TaskReassignmentResultRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { MemberOption, MemberPicker } from '../../../components/admin-pickers';\nimport styles from './users.module.scss';\n\ntype TaskRow = Readonly<\n Record<string, unknown> &\n MemberOpenTaskRecord & {\n key: string;\n }\n>;\n\ntype ResultRow = Readonly<\n Record<string, unknown> & {\n instanceTitle: string;\n key: string;\n message: string | null;\n outcomeLabel: string;\n }\n>;\n\ninterface PreviewState {\n readonly inputKey: string;\n readonly results: readonly TaskReassignmentResultRecord[];\n}\n\n/**\n * A committed run keeps the titles it was started with: the task list reloads\n * right after, and a member whose every task moved no longer lists any of them.\n */\ninterface CommittedState {\n readonly results: readonly TaskReassignmentResultRecord[];\n readonly titleById: ReadonlyMap<string, string>;\n}\n\n/**\n * Administrator reassignment of a member's open tasks. Lists what the member\n * holds, takes a target and a reason, previews every task's outcome (dry run),\n * and only then commits. Confirm stays disabled until the preview matches the\n * current target and reason. Replacing a seat is not a decision: no signature\n * is written, and the task keeps its id.\n */\nexport function MemberTaskReassignModal({\n member,\n onClose,\n}: {\n readonly member: MemberProfileRecord | null;\n readonly onClose: () => void;\n}): ReactElement {\n const [tasks, setTasks] = useState<readonly MemberOpenTaskRecord[]>([]);\n const [tasksLoading, setTasksLoading] = useState(false);\n const [target, setTarget] = useState<MemberOption | null>(null);\n const [reason, setReason] = useState('');\n const [preview, setPreview] = useState<PreviewState | null>(null);\n const [committed, setCommitted] = useState<CommittedState | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const trimmedReason = reason.trim();\n const inputKey = `${target?.id ?? ''}|${trimmedReason}`;\n const previewIsCurrent = preview !== null && preview.inputKey === inputKey;\n const canConfirm =\n preview !== null &&\n previewIsCurrent &&\n preview.results.some((result) => result.outcome === 'WOULD_REASSIGN');\n\n // Only the latest request may write: switching members while an earlier\n // listing is in flight must not let its late answer replace the current one.\n const latestRequestRef = useRef(0);\n\n const loadTasks = useCallback(async (memberId: string): Promise<void> => {\n const request = latestRequestRef.current + 1;\n\n latestRequestRef.current = request;\n setTasksLoading(true);\n\n try {\n const loaded = await listMemberOpenTasks(memberId);\n\n if (latestRequestRef.current === request) {\n setTasks(loaded);\n }\n } catch (requestError: unknown) {\n if (latestRequestRef.current === request) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (latestRequestRef.current === request) {\n setTasksLoading(false);\n }\n }\n }, []);\n\n useEffect((): void => {\n setTarget(null);\n setReason('');\n setPreview(null);\n setCommitted(null);\n setError(null);\n\n if (!member) {\n latestRequestRef.current += 1;\n setTasks([]);\n setTasksLoading(false);\n\n return;\n }\n\n setTasks([]);\n void loadTasks(member.memberId);\n }, [member, loadTasks]);\n\n const titleById = useMemo(\n (): ReadonlyMap<string, string> =>\n new Map(tasks.map((task) => [task.taskId, task.instanceTitle])),\n [tasks],\n );\n\n async function runReassignment(dryRun: boolean): Promise<void> {\n if (!member || !target || !trimmedReason) {\n return;\n }\n\n setBusy(true);\n setError(null);\n\n try {\n const outcomes = await reassignMemberTasks({\n dryRun,\n fromMemberId: member.memberId,\n reason: trimmedReason,\n toMemberId: target.id,\n });\n\n if (dryRun) {\n setPreview({ inputKey, results: outcomes });\n setCommitted(null);\n } else {\n setCommitted({ results: outcomes, titleById });\n setPreview(null);\n await loadTasks(member.memberId);\n }\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setBusy(false);\n }\n }\n\n const shownResultRows = useMemo((): ResultRow[] => {\n const shownResults = committed?.results ?? preview?.results ?? [];\n const shownTitleById = committed?.titleById ?? titleById;\n\n return shownResults.map((result) => ({\n instanceTitle: shownTitleById.get(result.taskId) ?? result.taskId,\n key: result.taskId,\n message: result.message,\n outcomeLabel: readOutcomeLabel(result.outcome),\n }));\n }, [committed, preview, titleById]);\n\n const taskColumns = useMemo(\n (): TableColumn<TaskRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'nodeLabel',\n key: 'nodeLabel',\n title: '節點',\n width: 160,\n },\n {\n key: 'memberRole',\n render: (record: TaskRow): string =>\n record.memberRole === 'ASSIGNEE' ? '指派人' : '會簽候選人',\n title: '身分',\n width: 120,\n },\n ],\n [],\n );\n const resultColumns = useMemo(\n (): TableColumn<ResultRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'outcomeLabel',\n key: 'outcomeLabel',\n title: '結果',\n width: 100,\n },\n {\n dataIndex: 'message',\n key: 'message',\n title: '說明',\n width: 160,\n },\n ],\n [],\n );\n\n return (\n <Modal\n cancelText=\"關閉\"\n confirmButtonProps={{ disabled: !canConfirm || busy }}\n confirmText=\"確認改派\"\n loading={busy}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void => {\n void runReassignment(false);\n }}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member ? `改派待辦:${member.name}` : '改派待辦'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <Typography variant=\"body\">\n 改派會保留任務編號,但不產生簽核紀錄;原簽核人的待辦會結案為已轉交,\n 接手人會收到新的待辦通知。\n </Typography>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {tasks.length ? (\n <Table\n columns={taskColumns}\n dataSource={tasks.map((task): TaskRow => ({\n ...task,\n key: task.taskId,\n }))}\n fullWidth\n loading={tasksLoading}\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n {tasksLoading ? '載入待辦中…' : '此成員目前沒有待簽任務。'}\n </Typography>\n )}\n <BPMFormField label=\"接手人\" name=\"reassignTarget\">\n <MemberPicker\n name=\"reassignTarget\"\n onChange={(option): void => {\n setTarget(option);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"搜尋接手人姓名或信箱\"\n value={target}\n />\n </BPMFormField>\n <BPMFormField label=\"改派原因\" name=\"reassignReason\">\n <Input\n fullWidth\n name=\"reassignReason\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setReason(event.target.value);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"例如:原簽核人已離職\"\n value={reason}\n />\n </BPMFormField>\n <div className={styles.membershipList}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 先按「預覽」確認每筆任務的結果,確認無誤後再按「確認改派」。\n </Typography>\n <div>\n <Button\n disabled={\n busy || !target || !trimmedReason || tasks.length === 0\n }\n onClick={(): void => {\n void runReassignment(true);\n }}\n variant=\"base-secondary\"\n >\n 預覽\n </Button>\n </div>\n </div>\n {shownResultRows.length ? (\n <Table\n columns={resultColumns}\n dataSource={shownResultRows}\n fullWidth\n />\n ) : null}\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOutcomeLabel(\n outcome: TaskReassignmentResultRecord['outcome'],\n): string {\n if (outcome === 'WOULD_REASSIGN') {\n return '會改派';\n }\n\n if (outcome === 'REASSIGNED') {\n return '已改派';\n }\n\n return '會被拒';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '改派待辦失敗。';\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n BaseCard,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { formatMemberLabel } from '../../../lib/format-member-label';\nimport styles from './users.module.scss';\nimport { MemberTaskReassignModal } from './MemberTaskReassignModal';\nimport {\n listMemberDirectoryPage,\n MemberProfileRecord,\n resolveMembers,\n} from '@rytass/bpm-core-client';\nimport {\n listMemberships,\n MembershipRecord,\n OrgUnitRecord,\n PositionRecord,\n readOrganizationDashboard,\n readResolvedManager,\n ResolvedManagerRecord,\n} from '@rytass/bpm-core-client/organization';\n\ntype MemberRow = Readonly<\n Record<string, unknown> &\n MemberProfileRecord & {\n key: string;\n }\n>;\n\nconst MEMBER_PAGE_SIZE_OPTIONS = [10, 20, 50];\n\nexport function AdminUsersView(): ReactElement {\n const [detailMember, setDetailMember] = useState<MemberProfileRecord | null>(\n null,\n );\n const [detailMemberships, setDetailMemberships] = useState<\n readonly MembershipRecord[]\n >([]);\n const [detailManagerProfile, setDetailManagerProfile] =\n useState<MemberProfileRecord | null>(null);\n const [detailResolvedManager, setDetailResolvedManager] =\n useState<ResolvedManagerRecord | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [memberPage, setMemberPage] = useState(1);\n const [memberPageSize, setMemberPageSize] = useState(10);\n const [memberTotalCount, setMemberTotalCount] = useState(0);\n const [members, setMembers] = useState<readonly MemberProfileRecord[]>([]);\n const [orgUnits, setOrgUnits] = useState<readonly OrgUnitRecord[]>([]);\n const [positions, setPositions] = useState<readonly PositionRecord[]>([]);\n const [reassignMember, setReassignMember] =\n useState<MemberProfileRecord | null>(null);\n const [searchText, setSearchText] = useState('');\n\n const orgUnitsById = useMemo(\n (): ReadonlyMap<string, OrgUnitRecord> =>\n new Map(orgUnits.map((orgUnit) => [orgUnit.id, orgUnit])),\n [orgUnits],\n );\n const positionsById = useMemo(\n (): ReadonlyMap<string, PositionRecord> =>\n new Map(positions.map((position) => [position.id, position])),\n [positions],\n );\n\n const refreshMembers = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const [memberPageResult, organization] = await Promise.all([\n listMemberDirectoryPage({\n page: memberPage,\n pageSize: memberPageSize,\n searchText,\n }),\n readOrganizationDashboard(),\n ]);\n\n setMembers(memberPageResult.members);\n setMemberTotalCount(memberPageResult.totalCount);\n setOrgUnits(organization.orgUnits);\n setPositions(organization.positions);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [memberPage, memberPageSize, searchText]);\n\n useEffect((): void => {\n void refreshMembers();\n }, [refreshMembers]);\n\n const rows = useMemo(\n (): MemberRow[] =>\n members.map((member) => ({\n ...member,\n key: member.memberId,\n })),\n [members],\n );\n\n const openDetail = useCallback(\n async (member: MemberProfileRecord): Promise<void> => {\n setDetailMember(member);\n setDetailManagerProfile(null);\n setError(null);\n\n try {\n const [memberships, resolvedManager] = await Promise.all([\n listMemberships({ memberId: member.memberId }),\n readResolvedManager(member.memberId),\n ]);\n\n setDetailMemberships(memberships);\n setDetailResolvedManager(resolvedManager);\n setDetailManagerProfile(\n (\n await resolveMembers(\n resolvedManager.managerMemberId\n ? [resolvedManager.managerMemberId]\n : [],\n )\n )[0] ?? null,\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n }\n },\n [],\n );\n\n const columns = useMemo(\n (): TableColumn<MemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<MemberRow> => ({\n render: (): ReturnType<TableActions<MemberRow>['render']> => [\n {\n name: '檢視',\n onClick: (record): void => {\n void openDetail(record);\n },\n },\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember(record);\n },\n },\n ],\n variant: 'base-secondary',\n width: 176,\n }),\n [openDetail],\n );\n\n function closeDetail(): void {\n setDetailMember(null);\n setDetailManagerProfile(null);\n setDetailMemberships([]);\n setDetailResolvedManager(null);\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"會員資料由 host member resolver 提供,BPM 僅維護組織歸屬與主管解析。\"\n title=\"會員對照\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.memberFilterArea}>\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"memberSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setMemberPage(1);\n }}\n placeholder=\"搜尋姓名或信箱\"\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\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: memberPage,\n onChange: (page): void => {\n setMemberPage(page);\n },\n onChangePageSize: (pageSize): void => {\n setMemberPage(1);\n setMemberPageSize(pageSize);\n },\n pageSize: memberPageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: MEMBER_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: memberTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n\n <MemberTaskReassignModal\n member={reassignMember}\n onClose={(): void => {\n setReassignMember(null);\n }}\n />\n\n <MemberDetailModal\n managerProfile={detailManagerProfile}\n member={detailMember}\n memberships={detailMemberships}\n onClose={closeDetail}\n orgUnitsById={orgUnitsById}\n positionsById={positionsById}\n resolvedManager={detailResolvedManager}\n />\n </>\n );\n}\n\nfunction MemberDetailModal({\n managerProfile,\n member,\n memberships,\n onClose,\n orgUnitsById,\n positionsById,\n resolvedManager,\n}: {\n readonly managerProfile: MemberProfileRecord | null;\n readonly member: MemberProfileRecord | null;\n readonly memberships: readonly MembershipRecord[];\n readonly onClose: () => void;\n readonly orgUnitsById: ReadonlyMap<string, OrgUnitRecord>;\n readonly positionsById: ReadonlyMap<string, PositionRecord>;\n readonly resolvedManager: ResolvedManagerRecord | null;\n}): ReactElement {\n return (\n <Modal\n cancelText=\"關閉\"\n confirmText=\"關閉\"\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={onClose}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member?.name ?? '會員明細'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <BaseCard title=\"基本資料\">\n <div className={styles.detailSection}>\n <Typography variant=\"body\">\n 信箱:{member.email?.trim() ? member.email : '未設定'}\n </Typography>\n </div>\n </BaseCard>\n <BaseCard title=\"BPM 組織歸屬\">\n <div className={styles.membershipList}>\n {memberships.length ? (\n memberships.map((membership) => (\n <Typography key={membership.id} variant=\"body\">\n {readOrgUnitLabel(orgUnitsById.get(membership.orgUnitId))}\n {' / '}\n {membership.positionId\n ? readPositionLabel(\n positionsById.get(membership.positionId),\n )\n : '未指定職位'}\n {' / '}\n {membership.isPrimary ? '主要' : '一般'}\n </Typography>\n ))\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 尚未建立 BPM 組織歸屬\n </Typography>\n )}\n </div>\n </BaseCard>\n <BaseCard title=\"主管解析\">\n <Typography variant=\"body\">\n {resolvedManager?.managerMemberId\n ? readMemberLabel(managerProfile)\n : '尚未解析到主管'}\n </Typography>\n </BaseCard>\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOrgUnitLabel(orgUnit: OrgUnitRecord | undefined): string {\n return orgUnit ? `${orgUnit.name} · ${orgUnit.code}` : '未知組織';\n}\n\nfunction readPositionLabel(position: PositionRecord | undefined): string {\n return position ? `${position.name} · ${position.code}` : '未知職位';\n}\n\nfunction readMemberLabel(member: MemberProfileRecord | null): string {\n return member\n ? formatMemberLabel(member.name, member.email, 'dot')\n : '主管資料尚未載入';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '讀取會員資料失敗。';\n}\n"],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ import { ReactElement } from 'react';
2
+ import { OrgUnitRecord, PositionRecord } from '@rytass/bpm-core-client/organization';
3
+ export type MemberOption = Readonly<{
4
+ email: string;
5
+ id: string;
6
+ name: string;
7
+ }>;
8
+ export type OrgUnitOption = Readonly<{
9
+ id: string;
10
+ name: string;
11
+ }>;
12
+ export type PositionOption = Readonly<{
13
+ id: string;
14
+ name: string;
15
+ }>;
16
+ interface MemberPickerProps {
17
+ readonly disabled?: boolean;
18
+ readonly name: string;
19
+ readonly onChange: (option: MemberOption | null) => void;
20
+ readonly placeholder?: string;
21
+ readonly size?: 'main' | 'sub';
22
+ readonly value: MemberOption | null;
23
+ }
24
+ interface OrgUnitPickerProps {
25
+ readonly disabled?: boolean;
26
+ readonly name: string;
27
+ readonly onChange: (option: OrgUnitOption | null) => void;
28
+ readonly orgUnits: readonly OrgUnitRecord[];
29
+ readonly placeholder?: string;
30
+ readonly size?: 'main' | 'sub';
31
+ readonly value: OrgUnitOption | null;
32
+ }
33
+ interface PositionPickerProps {
34
+ readonly disabled?: boolean;
35
+ readonly name: string;
36
+ readonly onChange: (option: PositionOption | null) => void;
37
+ readonly placeholder?: string;
38
+ readonly positions: readonly PositionRecord[];
39
+ readonly size?: 'main' | 'sub';
40
+ readonly value: PositionOption | null;
41
+ }
42
+ /**
43
+ * AutoComplete-backed picker that searches the BPM member directory via
44
+ * `searchMembers()`. Emits a {@link MemberOption} `{ id, name, email }`
45
+ * on selection (or `null` when cleared).
46
+ */
47
+ export declare function MemberPicker({ disabled, name, onChange, placeholder, size, value, }: MemberPickerProps): ReactElement;
48
+ /**
49
+ * Static `<Select>` over a pre-fetched list of org units. Caller is
50
+ * responsible for fetching the org units (typically via
51
+ * `readOrganizationDashboard` from `@rytass/bpm-core-client/organization`).
52
+ */
53
+ export declare function OrgUnitPicker({ disabled, onChange, orgUnits, placeholder, size, value, }: OrgUnitPickerProps): ReactElement;
54
+ /**
55
+ * Static `<Select>` over a pre-fetched list of positions.
56
+ */
57
+ export declare function PositionPicker({ disabled, onChange, placeholder, positions, size, value, }: PositionPickerProps): ReactElement;
58
+ export declare function readMemberOption(member: {
59
+ readonly email: string;
60
+ readonly memberId: string;
61
+ readonly name: string;
62
+ }): MemberOption;
63
+ export declare function readOrgUnitOption(orgUnit: OrgUnitRecord): OrgUnitOption;
64
+ export declare function readPositionOption(position: PositionRecord): PositionOption;
65
+ export {};
@@ -0,0 +1,17 @@
1
+ import { ReactElement } from 'react';
2
+ import { ApprovalInstanceState, ApprovalInstanceView } from '@rytass/bpm-core-client/workflow';
3
+ export interface ApprovalInstanceListPageProps {
4
+ readonly defaultState: ApprovalInstanceState | null;
5
+ readonly description: string;
6
+ readonly emptyMessage: string;
7
+ readonly searchPlaceholder: string;
8
+ readonly title: string;
9
+ readonly view: ApprovalInstanceView;
10
+ }
11
+ /**
12
+ * Shared list page for any approval-instance "view" (inbox / sent / cc /
13
+ * delegated). Caller picks the view + default state filter; the page renders
14
+ * the standard BPM filter bar + paginated table and navigates to
15
+ * `/instances/:id` on row action.
16
+ */
17
+ export declare function ApprovalInstanceListPage({ defaultState, description, emptyMessage, searchPlaceholder, title, view, }: ApprovalInstanceListPageProps): ReactElement;
@@ -0,0 +1,10 @@
1
+ import { ReactElement } from 'react';
2
+ import { FormFieldProps } from '@mezzanine-ui/react';
3
+ type BPMFormFieldProps = Omit<FormFieldProps, 'density' | 'fullWidth' | 'layout'> & Partial<Pick<FormFieldProps, 'density' | 'fullWidth' | 'layout'>>;
4
+ /**
5
+ * Mezzanine `<FormField>` pre-configured with the BPM admin defaults
6
+ * (`TIGHT` density, `HORIZONTAL` layout, full width). Use everywhere a
7
+ * label-aligned field is needed.
8
+ */
9
+ export declare function BPMFormField({ density, fullWidth, layout, ...props }: BPMFormFieldProps): ReactElement;
10
+ export {};
@@ -0,0 +1,22 @@
1
+ import { ReactElement } from 'react';
2
+ export interface BPMNotificationBellButtonProps {
3
+ /** Override the aria-label / tooltip. Defaults to `通知中心`. */
4
+ readonly label?: string;
5
+ }
6
+ /**
7
+ * Drop-in notification bell. Reads the unread count from
8
+ * `<NotificationUnreadProvider>`, opens the BPM `<NotificationDrawer />`
9
+ * mounted by `<Providers>` (or `<BPMNextProviders>`) on click, and
10
+ * renders a small red badge with the unread count.
11
+ *
12
+ * Use this when the host navigation wants the BPM notification UX with
13
+ * minimum wiring. Hosts that need a fully custom button can skip this
14
+ * widget and consume `useNotificationDrawer()` + `useNotificationUnread()`
15
+ * directly to wire their own trigger.
16
+ *
17
+ * Visual: uses Mezzanine `NavigationIconButton` so the bell aligns with
18
+ * surrounding Mezzanine navigation chrome. The button is decoupled from
19
+ * the `<Navigation>` container — it does not require a Mezzanine
20
+ * navigation tree to render.
21
+ */
22
+ export declare function BPMNotificationBellButton({ label, }?: BPMNotificationBellButtonProps): ReactElement;
@@ -0,0 +1,7 @@
1
+ import { ReactElement } from 'react';
2
+ /**
3
+ * Operator dashboard — shows pending/unread/active counts for the
4
+ * currently-authenticated member. Reads {@link readWorkflowDashboardSummary}
5
+ * and renders five metric tiles that navigate via {@link useRouterAdapter}.
6
+ */
7
+ export declare function DashboardPage(): ReactElement;
@@ -0,0 +1,11 @@
1
+ import { ReactElement } from 'react';
2
+ /**
3
+ * Right-side notification drawer mounted at the root by `<Providers>`.
4
+ * Opens / closes via `useNotificationDrawer()`, polls
5
+ * `listNotifications()` for the current member, supports filter
6
+ * (`all` / `read` / `unread`), per-row mark-read, per-row archive / unarchive,
7
+ * bulk mark-all-read, and load-more pagination. Archived notifications are
8
+ * hidden until the filter-bar menu turns "顯示已封存" on. Clicking a row with an
9
+ * `instanceId` navigates to `/instances/<id>` via the host's router adapter.
10
+ */
11
+ export declare function NotificationDrawer(): ReactElement | null;
@@ -0,0 +1,24 @@
1
+ import { OrgUnitRecord } from '@rytass/bpm-core-client/organization';
2
+ import { OrgUnitHierarchyDraftChange } from '../lib/org-tree-draft.cjs';
3
+ export type OrgUnitTreeDraftEditorHandle = Readonly<{
4
+ cancelEditing: () => void;
5
+ saveDraft: () => Promise<void>;
6
+ startEditing: () => void;
7
+ }>;
8
+ export type OrgUnitTreeDraftEditorState = Readonly<{
9
+ hasDraftChanges: boolean;
10
+ isEditing: boolean;
11
+ }>;
12
+ export declare const OrgUnitTreeDraftEditor: import('react').ForwardRefExoticComponent<Readonly<{
13
+ onCreateChild: (parentId: string) => void;
14
+ onCreateRoot: () => void;
15
+ onEditOrgUnit: (orgUnit: OrgUnitRecord) => void;
16
+ onSaveDraft?: (changes: readonly OrgUnitHierarchyDraftChange[]) => Promise<void>;
17
+ onStateChange: (state: OrgUnitTreeDraftEditorState) => void;
18
+ orgUnits: readonly OrgUnitRecord[];
19
+ saving: boolean;
20
+ }> & import('react').RefAttributes<Readonly<{
21
+ cancelEditing: () => void;
22
+ saveDraft: () => Promise<void>;
23
+ startEditing: () => void;
24
+ }>>>;
@@ -1,5 +1,5 @@
1
1
  import { OrgUnitRecord } from '@rytass/bpm-core-client/organization';
2
- import { OrgUnitHierarchyDraftChange } from '../lib/org-tree-draft';
2
+ import { OrgUnitHierarchyDraftChange } from '../lib/org-tree-draft.js';
3
3
  export type OrgUnitTreeDraftEditorHandle = Readonly<{
4
4
  cancelEditing: () => void;
5
5
  saveDraft: () => Promise<void>;
@@ -0,0 +1,12 @@
1
+ import { ReactElement } from 'react';
2
+ export declare function configurePdfWorker(workerSrc: string): void;
3
+ export interface PDFPreviewProps {
4
+ readonly filename: string;
5
+ readonly fileUrl: string;
6
+ readonly onDownload?: () => void;
7
+ }
8
+ /**
9
+ * Mezzanine-styled PDF preview powered by `react-pdf`. Used by the instance
10
+ * detail view to preview PDF attachments inline.
11
+ */
12
+ export declare function PDFPreview({ filename, fileUrl, onDownload, }: PDFPreviewProps): ReactElement;