@rytass/bpm-core-react 0.3.1 → 0.3.2

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 (175) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/dist/chunks/app-navigation-BSkMsEhy.js +268 -0
  3. package/dist/chunks/app-navigation-BSkMsEhy.js.map +1 -0
  4. package/dist/chunks/app-navigation-KnlJCUp1.cjs +2 -0
  5. package/dist/chunks/app-navigation-KnlJCUp1.cjs.map +1 -0
  6. package/dist/chunks/approval-instance-list-page-CVXgE2K3.cjs +2 -0
  7. package/dist/chunks/approval-instance-list-page-CVXgE2K3.cjs.map +1 -0
  8. package/dist/chunks/{approval-instance-list-page-nmzMrj0b.js → approval-instance-list-page-CqNdoZqx.js} +73 -72
  9. package/dist/chunks/approval-instance-list-page-CqNdoZqx.js.map +1 -0
  10. package/dist/chunks/builder-CMlJfQHE.cjs +3 -0
  11. package/dist/chunks/builder-CMlJfQHE.cjs.map +1 -0
  12. package/dist/chunks/{builder-DqZskyXC.js → builder-D950gct_.js} +492 -491
  13. package/dist/chunks/builder-D950gct_.js.map +1 -0
  14. package/dist/chunks/categories-5yEM3p3N.cjs +2 -0
  15. package/dist/chunks/categories-5yEM3p3N.cjs.map +1 -0
  16. package/dist/chunks/{categories-DTEl182t.js → categories-BIpOG451.js} +115 -114
  17. package/dist/chunks/categories-BIpOG451.js.map +1 -0
  18. package/dist/chunks/dashboard-page-1K_jQXQk.cjs +2 -0
  19. package/dist/chunks/dashboard-page-1K_jQXQk.cjs.map +1 -0
  20. package/dist/chunks/dashboard-page-R_T2OEiE.js +122 -0
  21. package/dist/chunks/dashboard-page-R_T2OEiE.js.map +1 -0
  22. package/dist/chunks/{delegations-C5PzZ5Kn.js → delegations-B2j-wNEO.js} +193 -192
  23. package/dist/chunks/delegations-B2j-wNEO.js.map +1 -0
  24. package/dist/chunks/delegations-CsB9ozLu.cjs +2 -0
  25. package/dist/chunks/delegations-CsB9ozLu.cjs.map +1 -0
  26. package/dist/chunks/delegations-CvtwTXNP.cjs +2 -0
  27. package/dist/chunks/delegations-CvtwTXNP.cjs.map +1 -0
  28. package/dist/chunks/{delegations-C-ZrwzvU.js → delegations-dKodb0WW.js} +175 -174
  29. package/dist/chunks/delegations-dKodb0WW.js.map +1 -0
  30. package/dist/chunks/{detail-CfFyU5zC.js → detail-BcGAqJ_R.js} +465 -464
  31. package/dist/chunks/detail-BcGAqJ_R.js.map +1 -0
  32. package/dist/chunks/detail-CqjqLd65.cjs +2 -0
  33. package/dist/chunks/detail-CqjqLd65.cjs.map +1 -0
  34. package/dist/chunks/{format-date-time-isOa3e9q.cjs → format-date-time-26_pFvv4.cjs} +2 -2
  35. package/dist/chunks/{format-date-time-isOa3e9q.cjs.map → format-date-time-26_pFvv4.cjs.map} +1 -1
  36. package/dist/chunks/notifications-2swRqDPF.js +198 -0
  37. package/dist/chunks/notifications-2swRqDPF.js.map +1 -0
  38. package/dist/chunks/notifications-BaYDebFt.cjs +2 -0
  39. package/dist/chunks/notifications-BaYDebFt.cjs.map +1 -0
  40. package/dist/chunks/{orgs-xrdhb3hS.js → orgs-CuHxxd_n.js} +608 -607
  41. package/dist/chunks/orgs-CuHxxd_n.js.map +1 -0
  42. package/dist/chunks/orgs-YMiVLNvL.cjs +2 -0
  43. package/dist/chunks/orgs-YMiVLNvL.cjs.map +1 -0
  44. package/dist/chunks/routes-config-2aKbWq2H.cjs +2 -0
  45. package/dist/chunks/routes-config-2aKbWq2H.cjs.map +1 -0
  46. package/dist/chunks/routes-config-dxahImVe.js +43 -0
  47. package/dist/chunks/routes-config-dxahImVe.js.map +1 -0
  48. package/dist/chunks/templates-DTkbSgFY.cjs +2 -0
  49. package/dist/chunks/templates-DTkbSgFY.cjs.map +1 -0
  50. package/dist/chunks/templates-DoDWM68t.js +384 -0
  51. package/dist/chunks/templates-DoDWM68t.js.map +1 -0
  52. package/dist/chunks/users-3ySyUW4u.cjs +2 -0
  53. package/dist/chunks/users-3ySyUW4u.cjs.map +1 -0
  54. package/dist/chunks/{users-CY4-NK3j.js → users-sMfrSjRQ.js} +75 -74
  55. package/dist/chunks/users-sMfrSjRQ.js.map +1 -0
  56. package/dist/index.cjs +1 -1
  57. package/dist/index.cjs.map +1 -1
  58. package/dist/index.d.ts +1 -0
  59. package/dist/index.js +101 -99
  60. package/dist/index.js.map +1 -1
  61. package/dist/lib/routes-config.d.ts +96 -0
  62. package/dist/next/index.cjs +1 -1
  63. package/dist/next/index.cjs.map +1 -1
  64. package/dist/next/index.d.ts +1 -0
  65. package/dist/next/index.js +22 -21
  66. package/dist/next/index.js.map +1 -1
  67. package/dist/pages/admin/delegations/index.cjs +1 -1
  68. package/dist/pages/admin/delegations/index.js +1 -1
  69. package/dist/pages/admin/orgs/index.cjs +1 -1
  70. package/dist/pages/admin/orgs/index.js +1 -1
  71. package/dist/pages/admin/users/index.cjs +1 -1
  72. package/dist/pages/admin/users/index.js +1 -1
  73. package/dist/pages/delegations/index.cjs +1 -1
  74. package/dist/pages/delegations/index.js +1 -1
  75. package/dist/pages/forms/builder/index.cjs +1 -1
  76. package/dist/pages/forms/builder/index.js +1 -1
  77. package/dist/pages/instances/detail/index.cjs +1 -1
  78. package/dist/pages/instances/detail/index.js +1 -1
  79. package/dist/pages/settings/notifications/index.cjs +1 -1
  80. package/dist/pages/settings/notifications/index.js +1 -1
  81. package/dist/pages/templates/categories/index.cjs +1 -1
  82. package/dist/pages/templates/categories/index.js +1 -1
  83. package/dist/pages/templates/index.cjs +1 -1
  84. package/dist/pages/templates/index.js +1 -1
  85. package/dist/views/admin/delegations/index.cjs +1 -1
  86. package/dist/views/admin/delegations/index.js +1 -1
  87. package/dist/views/admin/index.cjs +1 -1
  88. package/dist/views/admin/index.js +3 -3
  89. package/dist/views/admin/orgs/index.cjs +1 -1
  90. package/dist/views/admin/orgs/index.js +1 -1
  91. package/dist/views/admin/users/index.cjs +1 -1
  92. package/dist/views/admin/users/index.js +1 -1
  93. package/dist/views/cc/index.cjs +1 -1
  94. package/dist/views/cc/index.js +1 -1
  95. package/dist/views/dashboard/index.cjs +1 -1
  96. package/dist/views/dashboard/index.js +1 -1
  97. package/dist/views/delegations/index.cjs +1 -1
  98. package/dist/views/delegations/index.js +1 -1
  99. package/dist/views/forms/builder/index.cjs +1 -1
  100. package/dist/views/forms/builder/index.js +1 -1
  101. package/dist/views/forms/index.cjs +1 -1
  102. package/dist/views/forms/index.cjs.map +1 -1
  103. package/dist/views/forms/index.js +78 -77
  104. package/dist/views/forms/index.js.map +1 -1
  105. package/dist/views/inbox/index.cjs +1 -1
  106. package/dist/views/inbox/index.cjs.map +1 -1
  107. package/dist/views/inbox/index.js +106 -105
  108. package/dist/views/inbox/index.js.map +1 -1
  109. package/dist/views/instances/detail/index.cjs +1 -1
  110. package/dist/views/instances/detail/index.js +1 -1
  111. package/dist/views/instances/new/index.cjs +1 -1
  112. package/dist/views/instances/new/index.cjs.map +1 -1
  113. package/dist/views/instances/new/index.js +90 -89
  114. package/dist/views/instances/new/index.js.map +1 -1
  115. package/dist/views/search/index.cjs +1 -1
  116. package/dist/views/search/index.js +1 -1
  117. package/dist/views/sent/index.cjs +1 -1
  118. package/dist/views/sent/index.js +1 -1
  119. package/dist/views/settings/index.cjs +1 -1
  120. package/dist/views/settings/index.js +1 -1
  121. package/dist/views/settings/notifications/index.cjs +1 -1
  122. package/dist/views/settings/notifications/index.js +1 -1
  123. package/dist/views/templates/categories/index.cjs +1 -1
  124. package/dist/views/templates/categories/index.js +1 -1
  125. package/dist/views/templates/designer/index.cjs +6 -6
  126. package/dist/views/templates/designer/index.cjs.map +1 -1
  127. package/dist/views/templates/designer/index.js +589 -588
  128. package/dist/views/templates/designer/index.js.map +1 -1
  129. package/dist/views/templates/index.cjs +1 -1
  130. package/dist/views/templates/index.js +2 -2
  131. package/dist/views/templates/versions/index.cjs +1 -1
  132. package/dist/views/templates/versions/index.cjs.map +1 -1
  133. package/dist/views/templates/versions/index.js +44 -43
  134. package/dist/views/templates/versions/index.js.map +1 -1
  135. package/package.json +3 -3
  136. package/dist/chunks/app-navigation-C_mbz7jx.cjs +0 -2
  137. package/dist/chunks/app-navigation-C_mbz7jx.cjs.map +0 -1
  138. package/dist/chunks/app-navigation-uwbNEw9P.js +0 -262
  139. package/dist/chunks/app-navigation-uwbNEw9P.js.map +0 -1
  140. package/dist/chunks/approval-instance-list-page-Mo6wpDPb.cjs +0 -2
  141. package/dist/chunks/approval-instance-list-page-Mo6wpDPb.cjs.map +0 -1
  142. package/dist/chunks/approval-instance-list-page-nmzMrj0b.js.map +0 -1
  143. package/dist/chunks/builder-DPhAH381.cjs +0 -3
  144. package/dist/chunks/builder-DPhAH381.cjs.map +0 -1
  145. package/dist/chunks/builder-DqZskyXC.js.map +0 -1
  146. package/dist/chunks/categories-DEijUOnw.cjs +0 -2
  147. package/dist/chunks/categories-DEijUOnw.cjs.map +0 -1
  148. package/dist/chunks/categories-DTEl182t.js.map +0 -1
  149. package/dist/chunks/dashboard-page-DCmuB0Rw.cjs +0 -2
  150. package/dist/chunks/dashboard-page-DCmuB0Rw.cjs.map +0 -1
  151. package/dist/chunks/dashboard-page-Dx5PeEeN.js +0 -117
  152. package/dist/chunks/dashboard-page-Dx5PeEeN.js.map +0 -1
  153. package/dist/chunks/delegations-C-ZrwzvU.js.map +0 -1
  154. package/dist/chunks/delegations-C5PzZ5Kn.js.map +0 -1
  155. package/dist/chunks/delegations-DOGDvybX.cjs +0 -2
  156. package/dist/chunks/delegations-DOGDvybX.cjs.map +0 -1
  157. package/dist/chunks/delegations-DkDBWOQ7.cjs +0 -2
  158. package/dist/chunks/delegations-DkDBWOQ7.cjs.map +0 -1
  159. package/dist/chunks/detail-B2gcOPkd.cjs +0 -2
  160. package/dist/chunks/detail-B2gcOPkd.cjs.map +0 -1
  161. package/dist/chunks/detail-CfFyU5zC.js.map +0 -1
  162. package/dist/chunks/notifications-CPQ-nVar.cjs +0 -2
  163. package/dist/chunks/notifications-CPQ-nVar.cjs.map +0 -1
  164. package/dist/chunks/notifications-DweexUVy.js +0 -197
  165. package/dist/chunks/notifications-DweexUVy.js.map +0 -1
  166. package/dist/chunks/orgs-DgZ0DQ3-.cjs +0 -2
  167. package/dist/chunks/orgs-DgZ0DQ3-.cjs.map +0 -1
  168. package/dist/chunks/orgs-xrdhb3hS.js.map +0 -1
  169. package/dist/chunks/templates-PK_VYvcy.js +0 -383
  170. package/dist/chunks/templates-PK_VYvcy.js.map +0 -1
  171. package/dist/chunks/templates-x1OJZmsG.cjs +0 -2
  172. package/dist/chunks/templates-x1OJZmsG.cjs.map +0 -1
  173. package/dist/chunks/users-CY4-NK3j.js.map +0 -1
  174. package/dist/chunks/users-DHnu_056.cjs +0 -2
  175. package/dist/chunks/users-DHnu_056.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/views/inbox/InboxView.tsx"],"sourcesContent":["'use client';\n\nimport { type Key, ReactElement, useEffect, useMemo, useState } from 'react';\nimport {\n Button,\n PageHeader,\n Section,\n SectionGroup,\n Tab,\n TabItem,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { PlusIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport {\n ApprovalInstanceRecord,\n listApprovalHistoryTasks,\n listInboxTasks,\n listTaskDecisions,\n readApprovalInstance,\n readApprovalInstanceCaseTitle,\n TaskDecisionRecord,\n TaskRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { formatDateTime } from '../../lib/format-date-time';\nimport { useAuth } from '../../lib/auth-provider';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport { AppLayout } from '../../components/app-navigation';\n\ntype InboxTabKey = 'history' | 'pending' | 'tracking';\n\ntype InboxTaskRow = Readonly<\n Record<string, unknown> &\n TaskRecord & {\n caseTitle: string;\n key: string;\n slaStatusColor: 'text-error' | 'text-neutral' | 'text-success';\n slaStatusText: string;\n statusLabel: string;\n }\n>;\n\ntype ApprovalHistoryRow = Readonly<\n Record<string, unknown> &\n TaskRecord & {\n caseTitle: string;\n decisionAction: TaskDecisionRecord['action'] | null;\n decisionComment: string | null;\n decisionCommentText: string;\n decisionLabel: string;\n decidedAt: string | null;\n instanceState: ApprovalInstanceRecord['state'] | null;\n instanceStateLabel: string;\n key: string;\n }\n>;\n\nexport interface InboxViewProps {}\n\n/**\n * Framework-agnostic view for the BPM \"我的待簽\" inbox. Mechanical port of\n * `apps/client/src/app/inbox/page.tsx` — renders pending tasks, tracking,\n * and history tabs.\n */\nexport function InboxView(_props: InboxViewProps = {}): ReactElement {\n const router = useRouterAdapter();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [activeTab, setActiveTab] = useState<InboxTabKey>('pending');\n const [error, setError] = useState<string | null>(null);\n const [historyRows, setHistoryRows] = useState<ApprovalHistoryRow[]>([]);\n const [loading, setLoading] = useState(true);\n const [pendingRows, setPendingRows] = useState<InboxTaskRow[]>([]);\n\n useEffect((): void => {\n if (!currentMemberId) {\n return;\n }\n\n void refreshTasks();\n }, [currentMemberId]);\n\n const pendingColumns = useMemo(\n (): TableColumn<InboxTaskRow>[] => [\n { dataIndex: 'caseTitle', key: 'caseTitle', title: '案件', width: 280 },\n { dataIndex: 'nodeId', key: 'nodeId', title: '節點', width: 180 },\n {\n dataIndex: 'statusLabel',\n key: 'statusLabel',\n title: '狀態',\n width: 120,\n },\n {\n key: 'slaDueAt',\n render: (record: InboxTaskRow): ReactElement => (\n <Typography\n color={record.slaStatusColor}\n component=\"span\"\n variant=\"body\"\n >\n {record.slaStatusText}\n </Typography>\n ),\n title: 'SLA',\n width: 180,\n },\n {\n key: 'createdAt',\n render: (record: InboxTaskRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.createdAt)}\n </Typography>\n ),\n title: '建立時間',\n width: 220,\n },\n ],\n [],\n );\n const pendingTableActions = useMemo(\n (): TableActions<InboxTaskRow> => ({\n render: (record): ReturnType<TableActions<InboxTaskRow>['render']> => [\n {\n name: '處理',\n onClick: (): void => router.push(`/instances/${record.instanceId}`),\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router],\n );\n const historyColumns = useMemo(\n (): TableColumn<ApprovalHistoryRow>[] => [\n { dataIndex: 'caseTitle', key: 'caseTitle', title: '案件', width: 280 },\n { dataIndex: 'nodeId', key: 'nodeId', title: '節點', width: 180 },\n {\n key: 'decisionLabel',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography\n color={readTaskDecisionColor(record.decisionAction)}\n component=\"span\"\n variant=\"body\"\n >\n {record.decisionLabel}\n </Typography>\n ),\n title: '決議',\n width: 120,\n },\n {\n key: 'decisionComment',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {record.decisionCommentText}\n </Typography>\n ),\n title: '意見',\n width: 240,\n },\n {\n key: 'instanceStateLabel',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography\n color={readInstanceStateColor(record.instanceState)}\n component=\"span\"\n variant=\"body\"\n >\n {record.instanceStateLabel}\n </Typography>\n ),\n title: '流程狀態',\n width: 140,\n },\n {\n key: 'decidedAt',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatHistoryDateTime(record.decidedAt)}\n </Typography>\n ),\n title: '簽核時間',\n width: 220,\n },\n ],\n [],\n );\n const historyTableActions = useMemo(\n (): TableActions<ApprovalHistoryRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<ApprovalHistoryRow>['render']> => [\n {\n name: '查看',\n onClick: (): void => router.push(`/instances/${record.instanceId}`),\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router],\n );\n const trackingRows = useMemo(\n (): ApprovalHistoryRow[] =>\n historyRows.filter((row) => row.instanceState === 'RUNNING'),\n [historyRows],\n );\n\n function handleTabChange(activeKey: Key): void {\n if (\n activeKey === 'history' ||\n activeKey === 'pending' ||\n activeKey === 'tracking'\n ) {\n setActiveTab(activeKey);\n return;\n }\n\n setActiveTab('pending');\n }\n\n async function refreshTasks(): Promise<void> {\n setLoading(true);\n setError(null);\n\n try {\n if (!currentMemberId) {\n setPendingRows([]);\n setHistoryRows([]);\n return;\n }\n\n const [nextPendingTasks, nextHistoryTasks] = await Promise.all([\n listInboxTasks(currentMemberId),\n listApprovalHistoryTasks(currentMemberId),\n ]);\n const [nextPendingRows, nextHistoryRows] = await Promise.all([\n readInboxTaskRows(nextPendingTasks),\n readApprovalHistoryRows(nextHistoryTasks),\n ]);\n\n setPendingRows(nextPendingRows);\n setHistoryRows(nextHistoryRows);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n return (\n <AppLayout activeHref=\"/inbox\">\n <PageHeader>\n <ContentHeader\n description={`目前以 ${member?.name ?? currentMemberId ?? '目前登入會員'} 查詢待處理與歷史簽核任務。`}\n title=\"我的待簽\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => router.push('/instances/new')}\n variant=\"base-primary\"\n >\n 發起簽核\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Tab activeKey={activeTab} onChange={handleTabChange} size=\"sub\">\n <TabItem\n badgeCount={loading ? undefined : pendingRows.length}\n key=\"pending\"\n >\n 待簽核\n </TabItem>\n <TabItem\n badgeCount={loading ? undefined : trackingRows.length}\n key=\"tracking\"\n >\n 已處理未結束\n </TabItem>\n <TabItem key=\"history\">歷史簽核記錄</TabItem>\n </Tab>\n\n {activeTab === 'pending' ? (\n <Table\n actions={pendingTableActions}\n columns={pendingColumns}\n dataSource={pendingRows}\n fullWidth\n loading={loading}\n />\n ) : null}\n {activeTab === 'tracking' ? (\n <Table\n actions={historyTableActions}\n columns={historyColumns}\n dataSource={trackingRows}\n fullWidth\n loading={loading}\n />\n ) : null}\n {activeTab === 'history' ? (\n <Table\n actions={historyTableActions}\n columns={historyColumns}\n dataSource={historyRows}\n fullWidth\n loading={loading}\n />\n ) : null}\n </Section>\n </SectionGroup>\n </AppLayout>\n );\n}\n\nasync function readInboxTaskRows(\n tasks: readonly TaskRecord[],\n): Promise<InboxTaskRow[]> {\n const instances = await readTaskInstances(tasks);\n\n return tasks.map(\n (task, index): InboxTaskRow => ({\n ...task,\n caseTitle: readTaskCaseTitle(task, instances[index] ?? null),\n key: task.id,\n slaStatusColor: readSlaStatusColor(task.slaDueAt),\n slaStatusText: readSlaStatusText(task.slaDueAt),\n statusLabel: readTaskStatusLabel(task.status),\n }),\n );\n}\n\nasync function readApprovalHistoryRows(\n tasks: readonly TaskRecord[],\n): Promise<ApprovalHistoryRow[]> {\n const [decisionLists, instances] = await Promise.all([\n Promise.all(tasks.map((task) => listTaskDecisions(task.id))),\n readTaskInstances(tasks),\n ]);\n\n return tasks.map((task, index): ApprovalHistoryRow => {\n const decision = readLatestTaskDecision(decisionLists[index] ?? []);\n const instance = instances[index] ?? null;\n\n return {\n ...task,\n caseTitle: readTaskCaseTitle(task, instance),\n decisionAction: decision?.action ?? null,\n decisionComment: decision?.comment ?? null,\n decisionCommentText: readDecisionCommentText(decision?.comment ?? null),\n decisionLabel: readTaskDecisionLabel(decision?.action ?? null),\n decidedAt: decision?.decidedAt ?? task.completedAt,\n instanceState: instance?.state ?? null,\n instanceStateLabel: readInstanceStateLabel(instance?.state ?? null),\n key: task.id,\n };\n });\n}\n\nasync function readTaskInstances(\n tasks: readonly TaskRecord[],\n): Promise<readonly (ApprovalInstanceRecord | null)[]> {\n return Promise.all(\n tasks.map(async (task): Promise<ApprovalInstanceRecord | null> => {\n try {\n return (await readApprovalInstance(task.instanceId)).instance;\n } catch {\n return null;\n }\n }),\n );\n}\n\nfunction readTaskCaseTitle(\n task: TaskRecord,\n instance: ApprovalInstanceRecord | null,\n): string {\n return instance ? readApprovalInstanceCaseTitle(instance) : task.instanceId;\n}\n\nfunction readLatestTaskDecision(\n decisions: readonly TaskDecisionRecord[],\n): TaskDecisionRecord | null {\n return [...decisions].sort(compareTaskDecisionDesc)[0] ?? null;\n}\n\nfunction compareTaskDecisionDesc(\n left: TaskDecisionRecord,\n right: TaskDecisionRecord,\n): number {\n return (\n new Date(right.decidedAt).getTime() - new Date(left.decidedAt).getTime()\n );\n}\n\nfunction readTaskDecisionLabel(\n action: TaskDecisionRecord['action'] | null,\n): string {\n if (action === 'APPROVED') {\n return '同意';\n }\n\n if (action === 'REJECTED') {\n return '拒絕';\n }\n\n if (action === 'RETURNED') {\n return '退回';\n }\n\n if (action === 'TRANSFERRED') {\n return '轉派';\n }\n\n return '未記錄';\n}\n\nfunction readTaskDecisionColor(\n action: TaskDecisionRecord['action'] | null,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (action === 'APPROVED') {\n return 'text-success';\n }\n\n if (action === 'REJECTED' || action === 'RETURNED') {\n return 'text-error';\n }\n\n return 'text-neutral';\n}\n\nfunction readInstanceStateLabel(\n state: ApprovalInstanceRecord['state'] | null,\n): string {\n if (state === 'RUNNING') {\n return '進行中';\n }\n\n if (state === 'APPROVED') {\n return '已通過';\n }\n\n if (state === 'REJECTED') {\n return '已拒絕';\n }\n\n if (state === 'RETURNED') {\n return '已退回';\n }\n\n if (state === 'CANCELLED') {\n return '已取消';\n }\n\n if (state === 'EXPIRED') {\n return '已逾期';\n }\n\n if (state === 'DRAFT') {\n return '草稿';\n }\n\n return '-';\n}\n\nfunction readInstanceStateColor(\n state: ApprovalInstanceRecord['state'] | null,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (state === 'APPROVED') {\n return 'text-success';\n }\n\n if (state === 'REJECTED' || state === 'CANCELLED' || state === 'EXPIRED') {\n return 'text-error';\n }\n\n return 'text-neutral';\n}\n\nfunction readDecisionCommentText(comment: string | null): string {\n const trimmedComment = comment?.trim() ?? '';\n\n return trimmedComment || '-';\n}\n\nfunction formatHistoryDateTime(value: string | null): string {\n return formatDateTime(value);\n}\n\nfunction readSlaStatusText(value: string | null): string {\n if (!value) {\n return '-';\n }\n\n const dueAt = new Date(value).getTime();\n const now = Date.now();\n const diffMs = Math.abs(dueAt - now);\n const label = formatDuration(diffMs);\n\n return dueAt < now ? `已逾期 ${label}` : `剩餘 ${label}`;\n}\n\nfunction readSlaStatusColor(\n value: string | null,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (!value) {\n return 'text-neutral';\n }\n\n return new Date(value).getTime() < Date.now() ? 'text-error' : 'text-success';\n}\n\nfunction formatDuration(value: number): string {\n const totalMinutes = Math.max(1, Math.ceil(value / 60_000));\n const days = Math.floor(totalMinutes / 1440);\n const hours = Math.floor((totalMinutes % 1440) / 60);\n const minutes = totalMinutes % 60;\n\n if (days > 0) {\n return `${days}天 ${hours}小時`;\n }\n\n if (hours > 0) {\n return `${hours}小時 ${minutes}分鐘`;\n }\n\n return `${minutes}分鐘`;\n}\n\nfunction readTaskStatusLabel(status: TaskRecord['status']): string {\n if (status === 'PENDING') {\n return '待處理';\n }\n\n if (status === 'IN_PROGRESS') {\n return '處理中';\n }\n\n if (status === 'COMPLETED') {\n return '已完成';\n }\n\n if (status === 'TRANSFERRED') {\n return '已轉派';\n }\n\n if (status === 'CANCELLED') {\n return '已取消';\n }\n\n return status;\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":"index.js","names":[],"sources":["../../../src/views/inbox/InboxView.tsx"],"sourcesContent":["'use client';\n\nimport { type Key, ReactElement, useEffect, useMemo, useState } from 'react';\nimport {\n Button,\n PageHeader,\n Section,\n SectionGroup,\n Tab,\n TabItem,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { PlusIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport {\n ApprovalInstanceRecord,\n listApprovalHistoryTasks,\n listInboxTasks,\n listTaskDecisions,\n readApprovalInstance,\n readApprovalInstanceCaseTitle,\n TaskDecisionRecord,\n TaskRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { formatDateTime } from '../../lib/format-date-time';\nimport { useAuth } from '../../lib/auth-provider';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport { useBPMRoutes } from '../../lib/routes-config';\nimport { AppLayout } from '../../components/app-navigation';\n\ntype InboxTabKey = 'history' | 'pending' | 'tracking';\n\ntype InboxTaskRow = Readonly<\n Record<string, unknown> &\n TaskRecord & {\n caseTitle: string;\n key: string;\n slaStatusColor: 'text-error' | 'text-neutral' | 'text-success';\n slaStatusText: string;\n statusLabel: string;\n }\n>;\n\ntype ApprovalHistoryRow = Readonly<\n Record<string, unknown> &\n TaskRecord & {\n caseTitle: string;\n decisionAction: TaskDecisionRecord['action'] | null;\n decisionComment: string | null;\n decisionCommentText: string;\n decisionLabel: string;\n decidedAt: string | null;\n instanceState: ApprovalInstanceRecord['state'] | null;\n instanceStateLabel: string;\n key: string;\n }\n>;\n\nexport interface InboxViewProps {}\n\n/**\n * Framework-agnostic view for the BPM \"我的待簽\" inbox. Mechanical port of\n * `apps/client/src/app/inbox/page.tsx` — renders pending tasks, tracking,\n * and history tabs.\n */\nexport function InboxView(_props: InboxViewProps = {}): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [activeTab, setActiveTab] = useState<InboxTabKey>('pending');\n const [error, setError] = useState<string | null>(null);\n const [historyRows, setHistoryRows] = useState<ApprovalHistoryRow[]>([]);\n const [loading, setLoading] = useState(true);\n const [pendingRows, setPendingRows] = useState<InboxTaskRow[]>([]);\n\n useEffect((): void => {\n if (!currentMemberId) {\n return;\n }\n\n void refreshTasks();\n }, [currentMemberId]);\n\n const pendingColumns = useMemo(\n (): TableColumn<InboxTaskRow>[] => [\n { dataIndex: 'caseTitle', key: 'caseTitle', title: '案件', width: 280 },\n { dataIndex: 'nodeId', key: 'nodeId', title: '節點', width: 180 },\n {\n dataIndex: 'statusLabel',\n key: 'statusLabel',\n title: '狀態',\n width: 120,\n },\n {\n key: 'slaDueAt',\n render: (record: InboxTaskRow): ReactElement => (\n <Typography\n color={record.slaStatusColor}\n component=\"span\"\n variant=\"body\"\n >\n {record.slaStatusText}\n </Typography>\n ),\n title: 'SLA',\n width: 180,\n },\n {\n key: 'createdAt',\n render: (record: InboxTaskRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.createdAt)}\n </Typography>\n ),\n title: '建立時間',\n width: 220,\n },\n ],\n [],\n );\n const pendingTableActions = useMemo(\n (): TableActions<InboxTaskRow> => ({\n render: (record): ReturnType<TableActions<InboxTaskRow>['render']> => [\n {\n name: '處理',\n onClick: (): void => router.push(routes.caseDetail(record.instanceId)),\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router, routes],\n );\n const historyColumns = useMemo(\n (): TableColumn<ApprovalHistoryRow>[] => [\n { dataIndex: 'caseTitle', key: 'caseTitle', title: '案件', width: 280 },\n { dataIndex: 'nodeId', key: 'nodeId', title: '節點', width: 180 },\n {\n key: 'decisionLabel',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography\n color={readTaskDecisionColor(record.decisionAction)}\n component=\"span\"\n variant=\"body\"\n >\n {record.decisionLabel}\n </Typography>\n ),\n title: '決議',\n width: 120,\n },\n {\n key: 'decisionComment',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {record.decisionCommentText}\n </Typography>\n ),\n title: '意見',\n width: 240,\n },\n {\n key: 'instanceStateLabel',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography\n color={readInstanceStateColor(record.instanceState)}\n component=\"span\"\n variant=\"body\"\n >\n {record.instanceStateLabel}\n </Typography>\n ),\n title: '流程狀態',\n width: 140,\n },\n {\n key: 'decidedAt',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatHistoryDateTime(record.decidedAt)}\n </Typography>\n ),\n title: '簽核時間',\n width: 220,\n },\n ],\n [],\n );\n const historyTableActions = useMemo(\n (): TableActions<ApprovalHistoryRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<ApprovalHistoryRow>['render']> => [\n {\n name: '查看',\n onClick: (): void => router.push(routes.caseDetail(record.instanceId)),\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router, routes],\n );\n const trackingRows = useMemo(\n (): ApprovalHistoryRow[] =>\n historyRows.filter((row) => row.instanceState === 'RUNNING'),\n [historyRows],\n );\n\n function handleTabChange(activeKey: Key): void {\n if (\n activeKey === 'history' ||\n activeKey === 'pending' ||\n activeKey === 'tracking'\n ) {\n setActiveTab(activeKey);\n return;\n }\n\n setActiveTab('pending');\n }\n\n async function refreshTasks(): Promise<void> {\n setLoading(true);\n setError(null);\n\n try {\n if (!currentMemberId) {\n setPendingRows([]);\n setHistoryRows([]);\n return;\n }\n\n const [nextPendingTasks, nextHistoryTasks] = await Promise.all([\n listInboxTasks(currentMemberId),\n listApprovalHistoryTasks(currentMemberId),\n ]);\n const [nextPendingRows, nextHistoryRows] = await Promise.all([\n readInboxTaskRows(nextPendingTasks),\n readApprovalHistoryRows(nextHistoryTasks),\n ]);\n\n setPendingRows(nextPendingRows);\n setHistoryRows(nextHistoryRows);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n return (\n <AppLayout activeHref={routes.inbox()}>\n <PageHeader>\n <ContentHeader\n description={`目前以 ${member?.name ?? currentMemberId ?? '目前登入會員'} 查詢待處理與歷史簽核任務。`}\n title=\"我的待簽\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => router.push(routes.caseNew())}\n variant=\"base-primary\"\n >\n 發起簽核\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Tab activeKey={activeTab} onChange={handleTabChange} size=\"sub\">\n <TabItem\n badgeCount={loading ? undefined : pendingRows.length}\n key=\"pending\"\n >\n 待簽核\n </TabItem>\n <TabItem\n badgeCount={loading ? undefined : trackingRows.length}\n key=\"tracking\"\n >\n 已處理未結束\n </TabItem>\n <TabItem key=\"history\">歷史簽核記錄</TabItem>\n </Tab>\n\n {activeTab === 'pending' ? (\n <Table\n actions={pendingTableActions}\n columns={pendingColumns}\n dataSource={pendingRows}\n fullWidth\n loading={loading}\n />\n ) : null}\n {activeTab === 'tracking' ? (\n <Table\n actions={historyTableActions}\n columns={historyColumns}\n dataSource={trackingRows}\n fullWidth\n loading={loading}\n />\n ) : null}\n {activeTab === 'history' ? (\n <Table\n actions={historyTableActions}\n columns={historyColumns}\n dataSource={historyRows}\n fullWidth\n loading={loading}\n />\n ) : null}\n </Section>\n </SectionGroup>\n </AppLayout>\n );\n}\n\nasync function readInboxTaskRows(\n tasks: readonly TaskRecord[],\n): Promise<InboxTaskRow[]> {\n const instances = await readTaskInstances(tasks);\n\n return tasks.map(\n (task, index): InboxTaskRow => ({\n ...task,\n caseTitle: readTaskCaseTitle(task, instances[index] ?? null),\n key: task.id,\n slaStatusColor: readSlaStatusColor(task.slaDueAt),\n slaStatusText: readSlaStatusText(task.slaDueAt),\n statusLabel: readTaskStatusLabel(task.status),\n }),\n );\n}\n\nasync function readApprovalHistoryRows(\n tasks: readonly TaskRecord[],\n): Promise<ApprovalHistoryRow[]> {\n const [decisionLists, instances] = await Promise.all([\n Promise.all(tasks.map((task) => listTaskDecisions(task.id))),\n readTaskInstances(tasks),\n ]);\n\n return tasks.map((task, index): ApprovalHistoryRow => {\n const decision = readLatestTaskDecision(decisionLists[index] ?? []);\n const instance = instances[index] ?? null;\n\n return {\n ...task,\n caseTitle: readTaskCaseTitle(task, instance),\n decisionAction: decision?.action ?? null,\n decisionComment: decision?.comment ?? null,\n decisionCommentText: readDecisionCommentText(decision?.comment ?? null),\n decisionLabel: readTaskDecisionLabel(decision?.action ?? null),\n decidedAt: decision?.decidedAt ?? task.completedAt,\n instanceState: instance?.state ?? null,\n instanceStateLabel: readInstanceStateLabel(instance?.state ?? null),\n key: task.id,\n };\n });\n}\n\nasync function readTaskInstances(\n tasks: readonly TaskRecord[],\n): Promise<readonly (ApprovalInstanceRecord | null)[]> {\n return Promise.all(\n tasks.map(async (task): Promise<ApprovalInstanceRecord | null> => {\n try {\n return (await readApprovalInstance(task.instanceId)).instance;\n } catch {\n return null;\n }\n }),\n );\n}\n\nfunction readTaskCaseTitle(\n task: TaskRecord,\n instance: ApprovalInstanceRecord | null,\n): string {\n return instance ? readApprovalInstanceCaseTitle(instance) : task.instanceId;\n}\n\nfunction readLatestTaskDecision(\n decisions: readonly TaskDecisionRecord[],\n): TaskDecisionRecord | null {\n return [...decisions].sort(compareTaskDecisionDesc)[0] ?? null;\n}\n\nfunction compareTaskDecisionDesc(\n left: TaskDecisionRecord,\n right: TaskDecisionRecord,\n): number {\n return (\n new Date(right.decidedAt).getTime() - new Date(left.decidedAt).getTime()\n );\n}\n\nfunction readTaskDecisionLabel(\n action: TaskDecisionRecord['action'] | null,\n): string {\n if (action === 'APPROVED') {\n return '同意';\n }\n\n if (action === 'REJECTED') {\n return '拒絕';\n }\n\n if (action === 'RETURNED') {\n return '退回';\n }\n\n if (action === 'TRANSFERRED') {\n return '轉派';\n }\n\n return '未記錄';\n}\n\nfunction readTaskDecisionColor(\n action: TaskDecisionRecord['action'] | null,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (action === 'APPROVED') {\n return 'text-success';\n }\n\n if (action === 'REJECTED' || action === 'RETURNED') {\n return 'text-error';\n }\n\n return 'text-neutral';\n}\n\nfunction readInstanceStateLabel(\n state: ApprovalInstanceRecord['state'] | null,\n): string {\n if (state === 'RUNNING') {\n return '進行中';\n }\n\n if (state === 'APPROVED') {\n return '已通過';\n }\n\n if (state === 'REJECTED') {\n return '已拒絕';\n }\n\n if (state === 'RETURNED') {\n return '已退回';\n }\n\n if (state === 'CANCELLED') {\n return '已取消';\n }\n\n if (state === 'EXPIRED') {\n return '已逾期';\n }\n\n if (state === 'DRAFT') {\n return '草稿';\n }\n\n return '-';\n}\n\nfunction readInstanceStateColor(\n state: ApprovalInstanceRecord['state'] | null,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (state === 'APPROVED') {\n return 'text-success';\n }\n\n if (state === 'REJECTED' || state === 'CANCELLED' || state === 'EXPIRED') {\n return 'text-error';\n }\n\n return 'text-neutral';\n}\n\nfunction readDecisionCommentText(comment: string | null): string {\n const trimmedComment = comment?.trim() ?? '';\n\n return trimmedComment || '-';\n}\n\nfunction formatHistoryDateTime(value: string | null): string {\n return formatDateTime(value);\n}\n\nfunction readSlaStatusText(value: string | null): string {\n if (!value) {\n return '-';\n }\n\n const dueAt = new Date(value).getTime();\n const now = Date.now();\n const diffMs = Math.abs(dueAt - now);\n const label = formatDuration(diffMs);\n\n return dueAt < now ? `已逾期 ${label}` : `剩餘 ${label}`;\n}\n\nfunction readSlaStatusColor(\n value: string | null,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (!value) {\n return 'text-neutral';\n }\n\n return new Date(value).getTime() < Date.now() ? 'text-error' : 'text-success';\n}\n\nfunction formatDuration(value: number): string {\n const totalMinutes = Math.max(1, Math.ceil(value / 60_000));\n const days = Math.floor(totalMinutes / 1440);\n const hours = Math.floor((totalMinutes % 1440) / 60);\n const minutes = totalMinutes % 60;\n\n if (days > 0) {\n return `${days}天 ${hours}小時`;\n }\n\n if (hours > 0) {\n return `${hours}小時 ${minutes}分鐘`;\n }\n\n return `${minutes}分鐘`;\n}\n\nfunction readTaskStatusLabel(status: TaskRecord['status']): string {\n if (status === 'PENDING') {\n return '待處理';\n }\n\n if (status === 'IN_PROGRESS') {\n return '處理中';\n }\n\n if (status === 'COMPLETED') {\n return '已完成';\n }\n\n if (status === 'TRANSFERRED') {\n return '已轉派';\n }\n\n if (status === 'CANCELLED') {\n return '已取消';\n }\n\n return status;\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/detail-B2gcOPkd.cjs");exports.InstanceDetailView=e.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/detail-CqjqLd65.cjs");exports.InstanceDetailView=e.t;
@@ -1,2 +1,2 @@
1
- import { t as e } from "../../../chunks/detail-CfFyU5zC.js";
1
+ import { t as e } from "../../../chunks/detail-BcGAqJ_R.js";
2
2
  export { e as InstanceDetailView };
@@ -1,2 +1,2 @@
1
- "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/app-navigation-C_mbz7jx.cjs"),t=require("../../../chunks/auth-provider-BV8Iiwfb.cjs"),n=require("../../../chunks/format-date-time-isOa3e9q.cjs"),r=require("../../../chunks/FormRendererView-BwVsH2eX.cjs");let i=require("react"),a=require("@mezzanine-ui/react"),o=require("react/jsx-runtime"),s=require("@rytass/bpm-core-client/workflow"),c=require("@mezzanine-ui/icons"),l=require("@mezzanine-ui/react/ContentHeader");l=e.o(l,1);let u=require("@rytass/bpm-core-client/form");var d={display:`grid`,gap:16};function f(e={}){return(0,o.jsx)(i.Suspense,{fallback:(0,o.jsx)(m,{}),children:(0,o.jsx)(p,{templateId:e.templateId??void 0})})}function p({templateId:f}){let p=t.a(),{member:m}=t.n(),g=m?.memberId??null,_=f??null,[v,y]=(0,i.useState)(null),[b,x]=(0,i.useState)({}),[S,C]=(0,i.useState)([]),[w,T]=(0,i.useState)(null),[E,D]=(0,i.useState)({}),[O,k]=(0,i.useState)(!0),[A,j]=(0,i.useState)(!1);(0,i.useEffect)(()=>{if(!_){F();return}I(_)},[_]);let M=(0,i.useMemo)(()=>S.map(e=>({...e,key:e.id,updatedAt:n.t(e.updatedAt),versionLabel:`v${e.version}`})),[S]),N=(0,i.useMemo)(()=>[{dataIndex:`name`,key:`name`,title:`模板名稱`,width:240},{dataIndex:`versionLabel`,key:`versionLabel`,title:`發布版本`,width:120},{dataIndex:`updatedAt`,key:`updatedAt`,title:`更新時間`,width:220}],[]),P=(0,i.useMemo)(()=>({render:e=>[{name:`發起`,onClick:()=>p.push(`/instances/new?templateId=${e.id}`),variant:`base-primary`}],variant:`base-secondary`,width:88}),[p]);async function F(){k(!0),T(null),y(null);try{C(await(0,s.listLaunchableTemplates)())}catch(e){T(h(e))}finally{k(!1)}}async function I(e){k(!0),T(null),C([]);try{y(await(0,s.readLaunchContext)(e))}catch(e){T(h(e))}finally{k(!1)}}async function L(){if(!v||!g)return;j(!0),T(null),D({});let e=(0,u.validateFormRendererValues)({schema:v.formVersion.schema,uiSchema:v.formVersion.uiSchema,values:b});if(!e.valid){D(e.errors),T(`請先補齊必填欄位。`),e.firstInvalidFieldKey&&(0,u.focusFormRendererField)(e.firstInvalidFieldKey),j(!1);return}try{let e=await(0,s.submitApprovalInstance)({formData:b,initiatorMemberId:g,templateId:v.template.id,title:(0,s.readFormDataCaseTitle)({fallbackTitle:v.template.name,formData:b,schema:v.formVersion.schema,uiSchema:v.formVersion.uiSchema})});p.push(`/instances/${e}`)}catch(e){T(h(e))}finally{j(!1)}}async function R(e,t){if(!g)throw Error(`尚未登入,無法上傳附件`);return{id:(await(0,s.uploadAttachment)({file:t,formFieldPath:`form.${e.fieldKey}`})).id}}return(0,o.jsxs)(e.t,{activeHref:`/`,children:[(0,o.jsx)(a.PageHeader,{children:(0,o.jsx)(l.default,{description:v?`${v.template.name} · 表單 v${v.formVersion.version}`:`選擇可發起的已發布模板後填寫表單內容。`,title:`發起簽核`,children:v?(0,o.jsx)(a.Button,{disabled:O||A,icon:c.CheckedIcon,iconType:`leading`,onClick:L,variant:`base-primary`,children:`送出`}):null})}),(0,o.jsx)(a.SectionGroup,{children:(0,o.jsx)(a.Section,{children:(0,o.jsxs)(`div`,{style:d,children:[w?(0,o.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:w}):null,O?(0,o.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:`載入中...`}):null,v?(0,o.jsx)(r.t,{errors:E,maxWidth:480,onChange:e=>{x(e),D({})},onUploadAttachment:R,schema:v.formVersion.schema,singleColumn:!0,uiSchema:v.formVersion.uiSchema,value:b}):null,!_&&!O?M.length>0?(0,o.jsx)(a.Table,{actions:P,columns:N,dataSource:M,fullWidth:!0}):(0,o.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:`目前沒有可發起的已發布模板。`}):null]})})})]})}function m(){return(0,o.jsxs)(e.t,{activeHref:`/`,children:[(0,o.jsx)(a.PageHeader,{children:(0,o.jsx)(l.default,{description:`選擇可發起的已發布模板後填寫表單內容。`,title:`發起簽核`})}),(0,o.jsx)(a.SectionGroup,{children:(0,o.jsx)(a.Section,{children:(0,o.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:`載入中...`})})})]})}function h(e){return e instanceof Error?e.message:`發生未知錯誤`}exports.InstanceNewView=f;
1
+ "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/app-navigation-KnlJCUp1.cjs"),t=require("../../../chunks/auth-provider-BV8Iiwfb.cjs"),n=require("../../../chunks/format-date-time-26_pFvv4.cjs"),r=require("../../../chunks/routes-config-2aKbWq2H.cjs"),i=require("../../../chunks/FormRendererView-BwVsH2eX.cjs");let a=require("react"),o=require("@mezzanine-ui/react"),s=require("react/jsx-runtime"),c=require("@rytass/bpm-core-client/workflow"),l=require("@mezzanine-ui/icons"),u=require("@mezzanine-ui/react/ContentHeader");u=e.o(u,1);let d=require("@rytass/bpm-core-client/form");var f={display:`grid`,gap:16};function p(e={}){return(0,s.jsx)(a.Suspense,{fallback:(0,s.jsx)(h,{}),children:(0,s.jsx)(m,{templateId:e.templateId??void 0})})}function m({templateId:p}){let m=t.a(),h=r.r(),{member:_}=t.n(),v=_?.memberId??null,y=p??null,[b,x]=(0,a.useState)(null),[S,C]=(0,a.useState)({}),[w,T]=(0,a.useState)([]),[E,D]=(0,a.useState)(null),[O,k]=(0,a.useState)({}),[A,j]=(0,a.useState)(!0),[M,N]=(0,a.useState)(!1);(0,a.useEffect)(()=>{if(!y){L();return}R(y)},[y]);let P=(0,a.useMemo)(()=>w.map(e=>({...e,key:e.id,updatedAt:n.t(e.updatedAt),versionLabel:`v${e.version}`})),[w]),F=(0,a.useMemo)(()=>[{dataIndex:`name`,key:`name`,title:`模板名稱`,width:240},{dataIndex:`versionLabel`,key:`versionLabel`,title:`發布版本`,width:120},{dataIndex:`updatedAt`,key:`updatedAt`,title:`更新時間`,width:220}],[]),I=(0,a.useMemo)(()=>({render:e=>[{name:`發起`,onClick:()=>m.push(h.caseNew(e.id)),variant:`base-primary`}],variant:`base-secondary`,width:88}),[m]);async function L(){j(!0),D(null),x(null);try{T(await(0,c.listLaunchableTemplates)())}catch(e){D(g(e))}finally{j(!1)}}async function R(e){j(!0),D(null),T([]);try{x(await(0,c.readLaunchContext)(e))}catch(e){D(g(e))}finally{j(!1)}}async function z(){if(!b||!v)return;N(!0),D(null),k({});let e=(0,d.validateFormRendererValues)({schema:b.formVersion.schema,uiSchema:b.formVersion.uiSchema,values:S});if(!e.valid){k(e.errors),D(`請先補齊必填欄位。`),e.firstInvalidFieldKey&&(0,d.focusFormRendererField)(e.firstInvalidFieldKey),N(!1);return}try{let e=await(0,c.submitApprovalInstance)({formData:S,initiatorMemberId:v,templateId:b.template.id,title:(0,c.readFormDataCaseTitle)({fallbackTitle:b.template.name,formData:S,schema:b.formVersion.schema,uiSchema:b.formVersion.uiSchema})});m.push(h.caseDetail(e))}catch(e){D(g(e))}finally{N(!1)}}async function B(e,t){if(!v)throw Error(`尚未登入,無法上傳附件`);return{id:(await(0,c.uploadAttachment)({file:t,formFieldPath:`form.${e.fieldKey}`})).id}}return(0,s.jsxs)(e.t,{activeHref:`/`,children:[(0,s.jsx)(o.PageHeader,{children:(0,s.jsx)(u.default,{description:b?`${b.template.name} · 表單 v${b.formVersion.version}`:`選擇可發起的已發布模板後填寫表單內容。`,title:`發起簽核`,children:b?(0,s.jsx)(o.Button,{disabled:A||M,icon:l.CheckedIcon,iconType:`leading`,onClick:z,variant:`base-primary`,children:`送出`}):null})}),(0,s.jsx)(o.SectionGroup,{children:(0,s.jsx)(o.Section,{children:(0,s.jsxs)(`div`,{style:f,children:[E?(0,s.jsx)(o.Typography,{color:`text-error`,variant:`body`,children:E}):null,A?(0,s.jsx)(o.Typography,{color:`text-neutral`,variant:`body`,children:`載入中...`}):null,b?(0,s.jsx)(i.t,{errors:O,maxWidth:480,onChange:e=>{C(e),k({})},onUploadAttachment:B,schema:b.formVersion.schema,singleColumn:!0,uiSchema:b.formVersion.uiSchema,value:S}):null,!y&&!A?P.length>0?(0,s.jsx)(o.Table,{actions:I,columns:F,dataSource:P,fullWidth:!0}):(0,s.jsx)(o.Typography,{color:`text-neutral`,variant:`body`,children:`目前沒有可發起的已發布模板。`}):null]})})})]})}function h(){return(0,s.jsxs)(e.t,{activeHref:`/`,children:[(0,s.jsx)(o.PageHeader,{children:(0,s.jsx)(u.default,{description:`選擇可發起的已發布模板後填寫表單內容。`,title:`發起簽核`})}),(0,s.jsx)(o.SectionGroup,{children:(0,s.jsx)(o.Section,{children:(0,s.jsx)(o.Typography,{color:`text-neutral`,variant:`body`,children:`載入中...`})})})]})}function g(e){return e instanceof Error?e.message:`發生未知錯誤`}exports.InstanceNewView=p;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../../../src/views/instances/new/InstanceNewView.tsx"],"sourcesContent":["'use client';\n\nimport {\n CSSProperties,\n ReactElement,\n Suspense,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n Button,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { CheckedIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { FormFieldDefinition } from '@rytass/bpm-core-shared/form';\nimport {\n focusFormRendererField,\n FormRendererValues,\n validateFormRendererValues,\n} from '@rytass/bpm-core-client/form';\nimport {\n LaunchContext,\n LaunchableTemplateRecord,\n listLaunchableTemplates,\n readFormDataCaseTitle,\n readLaunchContext,\n submitApprovalInstance,\n uploadAttachment,\n} from '@rytass/bpm-core-client/workflow';\nimport { formatDateTime } from '../../../lib/format-date-time';\nimport { useAuth } from '../../../lib/auth-provider';\nimport { useRouterAdapter } from '../../../lib/router-adapter';\nimport { AppLayout } from '../../../components/app-navigation';\nimport { FormRenderer } from '../../forms/renderer/FormRendererView';\n\nconst FORM_SECTION_STYLE: CSSProperties = {\n display: 'grid',\n gap: 16,\n};\n\ntype LaunchableTemplateRow = Readonly<\n Record<string, unknown> &\n LaunchableTemplateRecord & {\n key: string;\n versionLabel: string;\n }\n>;\n\nexport interface InstanceNewViewProps {\n /**\n * Optional template id pre-selected by the host. The Server Component\n * page should read `?templateId=` from its `searchParams` and pass the\n * value through this prop.\n */\n readonly templateId?: string | null;\n}\n\n/**\n * Framework-agnostic view for the BPM \"發起簽核\" launch page. Mechanical port\n * of `apps/client/src/app/instances/new/page.tsx` — picks a launchable\n * template and submits the launch form.\n */\nexport function InstanceNewView(\n props: InstanceNewViewProps = {},\n): ReactElement {\n return (\n <Suspense fallback={<NewApprovalInstanceLoading />}>\n <NewApprovalInstanceContent templateId={props.templateId ?? undefined} />\n </Suspense>\n );\n}\n\nfunction NewApprovalInstanceContent({\n templateId: templateIdProp,\n}: {\n readonly templateId?: string;\n}): ReactElement {\n const router = useRouterAdapter();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const templateId = templateIdProp ?? null;\n const [context, setContext] = useState<LaunchContext | null>(null);\n const [formValues, setFormValues] = useState<FormRendererValues>({});\n const [templates, setTemplates] = useState<\n readonly LaunchableTemplateRecord[]\n >([]);\n const [error, setError] = useState<string | null>(null);\n const [formErrors, setFormErrors] = useState<\n Readonly<Record<string, string>>\n >({});\n const [loading, setLoading] = useState(true);\n const [submitting, setSubmitting] = useState(false);\n\n useEffect((): void => {\n if (!templateId) {\n void refreshTemplates();\n\n return;\n }\n\n void refreshContext(templateId);\n }, [templateId]);\n\n const rows = useMemo(\n (): LaunchableTemplateRow[] =>\n templates.map((template) => ({\n ...template,\n key: template.id,\n updatedAt: formatDateTime(template.updatedAt),\n versionLabel: `v${template.version}`,\n })),\n [templates],\n );\n const columns = useMemo(\n (): TableColumn<LaunchableTemplateRow>[] => [\n { dataIndex: 'name', key: 'name', title: '模板名稱', width: 240 },\n {\n dataIndex: 'versionLabel',\n key: 'versionLabel',\n title: '發布版本',\n width: 120,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<LaunchableTemplateRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<LaunchableTemplateRow>['render']> => [\n {\n name: '發起',\n onClick: (): void =>\n router.push(`/instances/new?templateId=${record.id}`),\n variant: 'base-primary',\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router],\n );\n\n async function refreshTemplates(): Promise<void> {\n setLoading(true);\n setError(null);\n setContext(null);\n\n try {\n setTemplates(await listLaunchableTemplates());\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function refreshContext(nextTemplateId: string): Promise<void> {\n setLoading(true);\n setError(null);\n setTemplates([]);\n\n try {\n setContext(await readLaunchContext(nextTemplateId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function handleSubmit(): Promise<void> {\n if (!context || !currentMemberId) {\n return;\n }\n\n setSubmitting(true);\n setError(null);\n setFormErrors({});\n\n const validation = validateFormRendererValues({\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n values: formValues,\n });\n\n if (!validation.valid) {\n setFormErrors(validation.errors);\n setError('請先補齊必填欄位。');\n\n if (validation.firstInvalidFieldKey) {\n focusFormRendererField(validation.firstInvalidFieldKey);\n }\n\n setSubmitting(false);\n\n return;\n }\n\n try {\n const instanceId = await submitApprovalInstance({\n formData: formValues,\n initiatorMemberId: currentMemberId,\n templateId: context.template.id,\n title: readFormDataCaseTitle({\n fallbackTitle: context.template.name,\n formData: formValues,\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n }),\n });\n\n router.push(`/instances/${instanceId}`);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSubmitting(false);\n }\n }\n\n async function handleUploadAttachment(\n field: FormFieldDefinition,\n file: File,\n ): Promise<{ readonly id: string }> {\n if (!currentMemberId) {\n throw new Error('尚未登入,無法上傳附件');\n }\n\n const attachment = await uploadAttachment({\n file,\n formFieldPath: `form.${field.fieldKey}`,\n });\n\n return { id: attachment.id };\n }\n\n return (\n <AppLayout activeHref=\"/\">\n <PageHeader>\n <ContentHeader\n description={\n context\n ? `${context.template.name} · 表單 v${context.formVersion.version}`\n : '選擇可發起的已發布模板後填寫表單內容。'\n }\n title=\"發起簽核\"\n >\n {context ? (\n <Button\n disabled={loading || submitting}\n icon={CheckedIcon}\n iconType=\"leading\"\n onClick={handleSubmit}\n variant=\"base-primary\"\n >\n 送出\n </Button>\n ) : null}\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <div style={FORM_SECTION_STYLE}>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n {loading ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n ) : null}\n\n {context ? (\n <FormRenderer\n errors={formErrors}\n maxWidth={480}\n onChange={(values): void => {\n setFormValues(values);\n setFormErrors({});\n }}\n onUploadAttachment={handleUploadAttachment}\n schema={context.formVersion.schema}\n singleColumn\n uiSchema={context.formVersion.uiSchema}\n value={formValues}\n />\n ) : null}\n\n {!templateId && !loading ? (\n rows.length > 0 ? (\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 目前沒有可發起的已發布模板。\n </Typography>\n )\n ) : null}\n </div>\n </Section>\n </SectionGroup>\n </AppLayout>\n );\n}\n\nfunction NewApprovalInstanceLoading(): ReactElement {\n return (\n <AppLayout activeHref=\"/\">\n <PageHeader>\n <ContentHeader\n description=\"選擇可發起的已發布模板後填寫表單內容。\"\n title=\"發起簽核\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n </Section>\n </SectionGroup>\n </AppLayout>\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":"index.cjs","names":[],"sources":["../../../../src/views/instances/new/InstanceNewView.tsx"],"sourcesContent":["'use client';\n\nimport {\n CSSProperties,\n ReactElement,\n Suspense,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n Button,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { CheckedIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { FormFieldDefinition } from '@rytass/bpm-core-shared/form';\nimport {\n focusFormRendererField,\n FormRendererValues,\n validateFormRendererValues,\n} from '@rytass/bpm-core-client/form';\nimport {\n LaunchContext,\n LaunchableTemplateRecord,\n listLaunchableTemplates,\n readFormDataCaseTitle,\n readLaunchContext,\n submitApprovalInstance,\n uploadAttachment,\n} from '@rytass/bpm-core-client/workflow';\nimport { formatDateTime } from '../../../lib/format-date-time';\nimport { useAuth } from '../../../lib/auth-provider';\nimport { useRouterAdapter } from '../../../lib/router-adapter';\nimport { useBPMRoutes } from '../../../lib/routes-config';\nimport { AppLayout } from '../../../components/app-navigation';\nimport { FormRenderer } from '../../forms/renderer/FormRendererView';\n\nconst FORM_SECTION_STYLE: CSSProperties = {\n display: 'grid',\n gap: 16,\n};\n\ntype LaunchableTemplateRow = Readonly<\n Record<string, unknown> &\n LaunchableTemplateRecord & {\n key: string;\n versionLabel: string;\n }\n>;\n\nexport interface InstanceNewViewProps {\n /**\n * Optional template id pre-selected by the host. The Server Component\n * page should read `?templateId=` from its `searchParams` and pass the\n * value through this prop.\n */\n readonly templateId?: string | null;\n}\n\n/**\n * Framework-agnostic view for the BPM \"發起簽核\" launch page. Mechanical port\n * of `apps/client/src/app/instances/new/page.tsx` — picks a launchable\n * template and submits the launch form.\n */\nexport function InstanceNewView(\n props: InstanceNewViewProps = {},\n): ReactElement {\n return (\n <Suspense fallback={<NewApprovalInstanceLoading />}>\n <NewApprovalInstanceContent templateId={props.templateId ?? undefined} />\n </Suspense>\n );\n}\n\nfunction NewApprovalInstanceContent({\n templateId: templateIdProp,\n}: {\n readonly templateId?: string;\n}): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const templateId = templateIdProp ?? null;\n const [context, setContext] = useState<LaunchContext | null>(null);\n const [formValues, setFormValues] = useState<FormRendererValues>({});\n const [templates, setTemplates] = useState<\n readonly LaunchableTemplateRecord[]\n >([]);\n const [error, setError] = useState<string | null>(null);\n const [formErrors, setFormErrors] = useState<\n Readonly<Record<string, string>>\n >({});\n const [loading, setLoading] = useState(true);\n const [submitting, setSubmitting] = useState(false);\n\n useEffect((): void => {\n if (!templateId) {\n void refreshTemplates();\n\n return;\n }\n\n void refreshContext(templateId);\n }, [templateId]);\n\n const rows = useMemo(\n (): LaunchableTemplateRow[] =>\n templates.map((template) => ({\n ...template,\n key: template.id,\n updatedAt: formatDateTime(template.updatedAt),\n versionLabel: `v${template.version}`,\n })),\n [templates],\n );\n const columns = useMemo(\n (): TableColumn<LaunchableTemplateRow>[] => [\n { dataIndex: 'name', key: 'name', title: '模板名稱', width: 240 },\n {\n dataIndex: 'versionLabel',\n key: 'versionLabel',\n title: '發布版本',\n width: 120,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<LaunchableTemplateRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<LaunchableTemplateRow>['render']> => [\n {\n name: '發起',\n onClick: (): void =>\n router.push(routes.caseNew(record.id)),\n variant: 'base-primary',\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router],\n );\n\n async function refreshTemplates(): Promise<void> {\n setLoading(true);\n setError(null);\n setContext(null);\n\n try {\n setTemplates(await listLaunchableTemplates());\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function refreshContext(nextTemplateId: string): Promise<void> {\n setLoading(true);\n setError(null);\n setTemplates([]);\n\n try {\n setContext(await readLaunchContext(nextTemplateId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function handleSubmit(): Promise<void> {\n if (!context || !currentMemberId) {\n return;\n }\n\n setSubmitting(true);\n setError(null);\n setFormErrors({});\n\n const validation = validateFormRendererValues({\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n values: formValues,\n });\n\n if (!validation.valid) {\n setFormErrors(validation.errors);\n setError('請先補齊必填欄位。');\n\n if (validation.firstInvalidFieldKey) {\n focusFormRendererField(validation.firstInvalidFieldKey);\n }\n\n setSubmitting(false);\n\n return;\n }\n\n try {\n const instanceId = await submitApprovalInstance({\n formData: formValues,\n initiatorMemberId: currentMemberId,\n templateId: context.template.id,\n title: readFormDataCaseTitle({\n fallbackTitle: context.template.name,\n formData: formValues,\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n }),\n });\n\n router.push(routes.caseDetail(instanceId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSubmitting(false);\n }\n }\n\n async function handleUploadAttachment(\n field: FormFieldDefinition,\n file: File,\n ): Promise<{ readonly id: string }> {\n if (!currentMemberId) {\n throw new Error('尚未登入,無法上傳附件');\n }\n\n const attachment = await uploadAttachment({\n file,\n formFieldPath: `form.${field.fieldKey}`,\n });\n\n return { id: attachment.id };\n }\n\n return (\n <AppLayout activeHref=\"/\">\n <PageHeader>\n <ContentHeader\n description={\n context\n ? `${context.template.name} · 表單 v${context.formVersion.version}`\n : '選擇可發起的已發布模板後填寫表單內容。'\n }\n title=\"發起簽核\"\n >\n {context ? (\n <Button\n disabled={loading || submitting}\n icon={CheckedIcon}\n iconType=\"leading\"\n onClick={handleSubmit}\n variant=\"base-primary\"\n >\n 送出\n </Button>\n ) : null}\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <div style={FORM_SECTION_STYLE}>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n {loading ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n ) : null}\n\n {context ? (\n <FormRenderer\n errors={formErrors}\n maxWidth={480}\n onChange={(values): void => {\n setFormValues(values);\n setFormErrors({});\n }}\n onUploadAttachment={handleUploadAttachment}\n schema={context.formVersion.schema}\n singleColumn\n uiSchema={context.formVersion.uiSchema}\n value={formValues}\n />\n ) : null}\n\n {!templateId && !loading ? (\n rows.length > 0 ? (\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 目前沒有可發起的已發布模板。\n </Typography>\n )\n ) : null}\n </div>\n </Section>\n </SectionGroup>\n </AppLayout>\n );\n}\n\nfunction NewApprovalInstanceLoading(): ReactElement {\n return (\n <AppLayout activeHref=\"/\">\n <PageHeader>\n <ContentHeader\n description=\"選擇可發起的已發布模板後填寫表單內容。\"\n title=\"發起簽核\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n </Section>\n </SectionGroup>\n </AppLayout>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
@@ -1,41 +1,42 @@
1
1
  "use client";
2
2
  import { a as e, n as t } from "../../../chunks/auth-provider-Bnox5gsx.js";
3
3
  import { t as n } from "../../../chunks/format-date-time-CB-LxzqT.js";
4
- import { t as r } from "../../../chunks/app-navigation-uwbNEw9P.js";
5
- import { t as i } from "../../../chunks/FormRendererView-DrHsuSVo.js";
6
- import { Suspense as a, useEffect as o, useMemo as s, useState as c } from "react";
7
- import { Button as l, PageHeader as u, Section as d, SectionGroup as f, Table as p, Typography as m } from "@mezzanine-ui/react";
8
- import { jsx as h, jsxs as g } from "react/jsx-runtime";
9
- import { listLaunchableTemplates as _, readFormDataCaseTitle as v, readLaunchContext as y, submitApprovalInstance as b, uploadAttachment as x } from "@rytass/bpm-core-client/workflow";
10
- import { CheckedIcon as S } from "@mezzanine-ui/icons";
11
- import C from "@mezzanine-ui/react/ContentHeader";
12
- import { focusFormRendererField as w, validateFormRendererValues as T } from "@rytass/bpm-core-client/form";
4
+ import { t as r } from "../../../chunks/app-navigation-BSkMsEhy.js";
5
+ import { r as i } from "../../../chunks/routes-config-dxahImVe.js";
6
+ import { t as a } from "../../../chunks/FormRendererView-DrHsuSVo.js";
7
+ import { Suspense as o, useEffect as s, useMemo as c, useState as l } from "react";
8
+ import { Button as u, PageHeader as d, Section as f, SectionGroup as p, Table as m, Typography as h } from "@mezzanine-ui/react";
9
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
10
+ import { listLaunchableTemplates as v, readFormDataCaseTitle as y, readLaunchContext as b, submitApprovalInstance as x, uploadAttachment as S } from "@rytass/bpm-core-client/workflow";
11
+ import { CheckedIcon as C } from "@mezzanine-ui/icons";
12
+ import w from "@mezzanine-ui/react/ContentHeader";
13
+ import { focusFormRendererField as T, validateFormRendererValues as E } from "@rytass/bpm-core-client/form";
13
14
  //#region src/views/instances/new/InstanceNewView.tsx
14
- var E = {
15
+ var D = {
15
16
  display: "grid",
16
17
  gap: 16
17
18
  };
18
- function D(e = {}) {
19
- return /* @__PURE__ */ h(a, {
20
- fallback: /* @__PURE__ */ h(k, {}),
21
- children: /* @__PURE__ */ h(O, { templateId: e.templateId ?? void 0 })
19
+ function O(e = {}) {
20
+ return /* @__PURE__ */ g(o, {
21
+ fallback: /* @__PURE__ */ g(A, {}),
22
+ children: /* @__PURE__ */ g(k, { templateId: e.templateId ?? void 0 })
22
23
  });
23
24
  }
24
- function O({ templateId: a }) {
25
- let D = e(), { member: O } = t(), k = O?.memberId ?? null, j = a ?? null, [M, N] = c(null), [P, F] = c({}), [I, L] = c([]), [R, z] = c(null), [B, V] = c({}), [H, U] = c(!0), [W, G] = c(!1);
26
- o(() => {
27
- if (!j) {
28
- Y();
25
+ function k({ templateId: o }) {
26
+ let O = e(), k = i(), { member: A } = t(), M = A?.memberId ?? null, N = o ?? null, [P, F] = l(null), [I, L] = l({}), [R, z] = l([]), [B, V] = l(null), [H, U] = l({}), [W, G] = l(!0), [K, q] = l(!1);
27
+ s(() => {
28
+ if (!N) {
29
+ Z();
29
30
  return;
30
31
  }
31
- X(j);
32
- }, [j]);
33
- let K = s(() => I.map((e) => ({
32
+ Q(N);
33
+ }, [N]);
34
+ let J = c(() => R.map((e) => ({
34
35
  ...e,
35
36
  key: e.id,
36
37
  updatedAt: n(e.updatedAt),
37
38
  versionLabel: `v${e.version}`
38
- })), [I]), q = s(() => [
39
+ })), [R]), Y = c(() => [
39
40
  {
40
41
  dataIndex: "name",
41
42
  key: "name",
@@ -54,117 +55,117 @@ function O({ templateId: a }) {
54
55
  title: "更新時間",
55
56
  width: 220
56
57
  }
57
- ], []), J = s(() => ({
58
+ ], []), X = c(() => ({
58
59
  render: (e) => [{
59
60
  name: "發起",
60
- onClick: () => D.push(`/instances/new?templateId=${e.id}`),
61
+ onClick: () => O.push(k.caseNew(e.id)),
61
62
  variant: "base-primary"
62
63
  }],
63
64
  variant: "base-secondary",
64
65
  width: 88
65
- }), [D]);
66
- async function Y() {
67
- U(!0), z(null), N(null);
66
+ }), [O]);
67
+ async function Z() {
68
+ G(!0), V(null), F(null);
68
69
  try {
69
- L(await _());
70
+ z(await v());
70
71
  } catch (e) {
71
- z(A(e));
72
+ V(j(e));
72
73
  } finally {
73
- U(!1);
74
+ G(!1);
74
75
  }
75
76
  }
76
- async function X(e) {
77
- U(!0), z(null), L([]);
77
+ async function Q(e) {
78
+ G(!0), V(null), z([]);
78
79
  try {
79
- N(await y(e));
80
+ F(await b(e));
80
81
  } catch (e) {
81
- z(A(e));
82
+ V(j(e));
82
83
  } finally {
83
- U(!1);
84
+ G(!1);
84
85
  }
85
86
  }
86
- async function Z() {
87
- if (!M || !k) return;
88
- G(!0), z(null), V({});
89
- let e = T({
90
- schema: M.formVersion.schema,
91
- uiSchema: M.formVersion.uiSchema,
92
- values: P
87
+ async function $() {
88
+ if (!P || !M) return;
89
+ q(!0), V(null), U({});
90
+ let e = E({
91
+ schema: P.formVersion.schema,
92
+ uiSchema: P.formVersion.uiSchema,
93
+ values: I
93
94
  });
94
95
  if (!e.valid) {
95
- V(e.errors), z("請先補齊必填欄位。"), e.firstInvalidFieldKey && w(e.firstInvalidFieldKey), G(!1);
96
+ U(e.errors), V("請先補齊必填欄位。"), e.firstInvalidFieldKey && T(e.firstInvalidFieldKey), q(!1);
96
97
  return;
97
98
  }
98
99
  try {
99
- let e = await b({
100
- formData: P,
101
- initiatorMemberId: k,
102
- templateId: M.template.id,
103
- title: v({
104
- fallbackTitle: M.template.name,
105
- formData: P,
106
- schema: M.formVersion.schema,
107
- uiSchema: M.formVersion.uiSchema
100
+ let e = await x({
101
+ formData: I,
102
+ initiatorMemberId: M,
103
+ templateId: P.template.id,
104
+ title: y({
105
+ fallbackTitle: P.template.name,
106
+ formData: I,
107
+ schema: P.formVersion.schema,
108
+ uiSchema: P.formVersion.uiSchema
108
109
  })
109
110
  });
110
- D.push(`/instances/${e}`);
111
+ O.push(k.caseDetail(e));
111
112
  } catch (e) {
112
- z(A(e));
113
+ V(j(e));
113
114
  } finally {
114
- G(!1);
115
+ q(!1);
115
116
  }
116
117
  }
117
- async function Q(e, t) {
118
- if (!k) throw Error("尚未登入,無法上傳附件");
119
- return { id: (await x({
118
+ async function ee(e, t) {
119
+ if (!M) throw Error("尚未登入,無法上傳附件");
120
+ return { id: (await S({
120
121
  file: t,
121
122
  formFieldPath: `form.${e.fieldKey}`
122
123
  })).id };
123
124
  }
124
- return /* @__PURE__ */ g(r, {
125
+ return /* @__PURE__ */ _(r, {
125
126
  activeHref: "/",
126
- children: [/* @__PURE__ */ h(u, { children: /* @__PURE__ */ h(C, {
127
- description: M ? `${M.template.name} · 表單 v${M.formVersion.version}` : "選擇可發起的已發布模板後填寫表單內容。",
127
+ children: [/* @__PURE__ */ g(d, { children: /* @__PURE__ */ g(w, {
128
+ description: P ? `${P.template.name} · 表單 v${P.formVersion.version}` : "選擇可發起的已發布模板後填寫表單內容。",
128
129
  title: "發起簽核",
129
- children: M ? /* @__PURE__ */ h(l, {
130
- disabled: H || W,
131
- icon: S,
130
+ children: P ? /* @__PURE__ */ g(u, {
131
+ disabled: W || K,
132
+ icon: C,
132
133
  iconType: "leading",
133
- onClick: Z,
134
+ onClick: $,
134
135
  variant: "base-primary",
135
136
  children: "送出"
136
137
  }) : null
137
- }) }), /* @__PURE__ */ h(f, { children: /* @__PURE__ */ h(d, { children: /* @__PURE__ */ g("div", {
138
- style: E,
138
+ }) }), /* @__PURE__ */ g(p, { children: /* @__PURE__ */ g(f, { children: /* @__PURE__ */ _("div", {
139
+ style: D,
139
140
  children: [
140
- R ? /* @__PURE__ */ h(m, {
141
+ B ? /* @__PURE__ */ g(h, {
141
142
  color: "text-error",
142
143
  variant: "body",
143
- children: R
144
+ children: B
144
145
  }) : null,
145
- H ? /* @__PURE__ */ h(m, {
146
+ W ? /* @__PURE__ */ g(h, {
146
147
  color: "text-neutral",
147
148
  variant: "body",
148
149
  children: "載入中..."
149
150
  }) : null,
150
- M ? /* @__PURE__ */ h(i, {
151
- errors: B,
151
+ P ? /* @__PURE__ */ g(a, {
152
+ errors: H,
152
153
  maxWidth: 480,
153
154
  onChange: (e) => {
154
- F(e), V({});
155
+ L(e), U({});
155
156
  },
156
- onUploadAttachment: Q,
157
- schema: M.formVersion.schema,
157
+ onUploadAttachment: ee,
158
+ schema: P.formVersion.schema,
158
159
  singleColumn: !0,
159
- uiSchema: M.formVersion.uiSchema,
160
- value: P
160
+ uiSchema: P.formVersion.uiSchema,
161
+ value: I
161
162
  }) : null,
162
- !j && !H ? K.length > 0 ? /* @__PURE__ */ h(p, {
163
- actions: J,
164
- columns: q,
165
- dataSource: K,
163
+ !N && !W ? J.length > 0 ? /* @__PURE__ */ g(m, {
164
+ actions: X,
165
+ columns: Y,
166
+ dataSource: J,
166
167
  fullWidth: !0
167
- }) : /* @__PURE__ */ h(m, {
168
+ }) : /* @__PURE__ */ g(h, {
168
169
  color: "text-neutral",
169
170
  variant: "body",
170
171
  children: "目前沒有可發起的已發布模板。"
@@ -173,23 +174,23 @@ function O({ templateId: a }) {
173
174
  }) }) })]
174
175
  });
175
176
  }
176
- function k() {
177
- return /* @__PURE__ */ g(r, {
177
+ function A() {
178
+ return /* @__PURE__ */ _(r, {
178
179
  activeHref: "/",
179
- children: [/* @__PURE__ */ h(u, { children: /* @__PURE__ */ h(C, {
180
+ children: [/* @__PURE__ */ g(d, { children: /* @__PURE__ */ g(w, {
180
181
  description: "選擇可發起的已發布模板後填寫表單內容。",
181
182
  title: "發起簽核"
182
- }) }), /* @__PURE__ */ h(f, { children: /* @__PURE__ */ h(d, { children: /* @__PURE__ */ h(m, {
183
+ }) }), /* @__PURE__ */ g(p, { children: /* @__PURE__ */ g(f, { children: /* @__PURE__ */ g(h, {
183
184
  color: "text-neutral",
184
185
  variant: "body",
185
186
  children: "載入中..."
186
187
  }) }) })]
187
188
  });
188
189
  }
189
- function A(e) {
190
+ function j(e) {
190
191
  return e instanceof Error ? e.message : "發生未知錯誤";
191
192
  }
192
193
  //#endregion
193
- export { D as InstanceNewView };
194
+ export { O as InstanceNewView };
194
195
 
195
196
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/views/instances/new/InstanceNewView.tsx"],"sourcesContent":["'use client';\n\nimport {\n CSSProperties,\n ReactElement,\n Suspense,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n Button,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { CheckedIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { FormFieldDefinition } from '@rytass/bpm-core-shared/form';\nimport {\n focusFormRendererField,\n FormRendererValues,\n validateFormRendererValues,\n} from '@rytass/bpm-core-client/form';\nimport {\n LaunchContext,\n LaunchableTemplateRecord,\n listLaunchableTemplates,\n readFormDataCaseTitle,\n readLaunchContext,\n submitApprovalInstance,\n uploadAttachment,\n} from '@rytass/bpm-core-client/workflow';\nimport { formatDateTime } from '../../../lib/format-date-time';\nimport { useAuth } from '../../../lib/auth-provider';\nimport { useRouterAdapter } from '../../../lib/router-adapter';\nimport { AppLayout } from '../../../components/app-navigation';\nimport { FormRenderer } from '../../forms/renderer/FormRendererView';\n\nconst FORM_SECTION_STYLE: CSSProperties = {\n display: 'grid',\n gap: 16,\n};\n\ntype LaunchableTemplateRow = Readonly<\n Record<string, unknown> &\n LaunchableTemplateRecord & {\n key: string;\n versionLabel: string;\n }\n>;\n\nexport interface InstanceNewViewProps {\n /**\n * Optional template id pre-selected by the host. The Server Component\n * page should read `?templateId=` from its `searchParams` and pass the\n * value through this prop.\n */\n readonly templateId?: string | null;\n}\n\n/**\n * Framework-agnostic view for the BPM \"發起簽核\" launch page. Mechanical port\n * of `apps/client/src/app/instances/new/page.tsx` — picks a launchable\n * template and submits the launch form.\n */\nexport function InstanceNewView(\n props: InstanceNewViewProps = {},\n): ReactElement {\n return (\n <Suspense fallback={<NewApprovalInstanceLoading />}>\n <NewApprovalInstanceContent templateId={props.templateId ?? undefined} />\n </Suspense>\n );\n}\n\nfunction NewApprovalInstanceContent({\n templateId: templateIdProp,\n}: {\n readonly templateId?: string;\n}): ReactElement {\n const router = useRouterAdapter();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const templateId = templateIdProp ?? null;\n const [context, setContext] = useState<LaunchContext | null>(null);\n const [formValues, setFormValues] = useState<FormRendererValues>({});\n const [templates, setTemplates] = useState<\n readonly LaunchableTemplateRecord[]\n >([]);\n const [error, setError] = useState<string | null>(null);\n const [formErrors, setFormErrors] = useState<\n Readonly<Record<string, string>>\n >({});\n const [loading, setLoading] = useState(true);\n const [submitting, setSubmitting] = useState(false);\n\n useEffect((): void => {\n if (!templateId) {\n void refreshTemplates();\n\n return;\n }\n\n void refreshContext(templateId);\n }, [templateId]);\n\n const rows = useMemo(\n (): LaunchableTemplateRow[] =>\n templates.map((template) => ({\n ...template,\n key: template.id,\n updatedAt: formatDateTime(template.updatedAt),\n versionLabel: `v${template.version}`,\n })),\n [templates],\n );\n const columns = useMemo(\n (): TableColumn<LaunchableTemplateRow>[] => [\n { dataIndex: 'name', key: 'name', title: '模板名稱', width: 240 },\n {\n dataIndex: 'versionLabel',\n key: 'versionLabel',\n title: '發布版本',\n width: 120,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<LaunchableTemplateRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<LaunchableTemplateRow>['render']> => [\n {\n name: '發起',\n onClick: (): void =>\n router.push(`/instances/new?templateId=${record.id}`),\n variant: 'base-primary',\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router],\n );\n\n async function refreshTemplates(): Promise<void> {\n setLoading(true);\n setError(null);\n setContext(null);\n\n try {\n setTemplates(await listLaunchableTemplates());\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function refreshContext(nextTemplateId: string): Promise<void> {\n setLoading(true);\n setError(null);\n setTemplates([]);\n\n try {\n setContext(await readLaunchContext(nextTemplateId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function handleSubmit(): Promise<void> {\n if (!context || !currentMemberId) {\n return;\n }\n\n setSubmitting(true);\n setError(null);\n setFormErrors({});\n\n const validation = validateFormRendererValues({\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n values: formValues,\n });\n\n if (!validation.valid) {\n setFormErrors(validation.errors);\n setError('請先補齊必填欄位。');\n\n if (validation.firstInvalidFieldKey) {\n focusFormRendererField(validation.firstInvalidFieldKey);\n }\n\n setSubmitting(false);\n\n return;\n }\n\n try {\n const instanceId = await submitApprovalInstance({\n formData: formValues,\n initiatorMemberId: currentMemberId,\n templateId: context.template.id,\n title: readFormDataCaseTitle({\n fallbackTitle: context.template.name,\n formData: formValues,\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n }),\n });\n\n router.push(`/instances/${instanceId}`);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSubmitting(false);\n }\n }\n\n async function handleUploadAttachment(\n field: FormFieldDefinition,\n file: File,\n ): Promise<{ readonly id: string }> {\n if (!currentMemberId) {\n throw new Error('尚未登入,無法上傳附件');\n }\n\n const attachment = await uploadAttachment({\n file,\n formFieldPath: `form.${field.fieldKey}`,\n });\n\n return { id: attachment.id };\n }\n\n return (\n <AppLayout activeHref=\"/\">\n <PageHeader>\n <ContentHeader\n description={\n context\n ? `${context.template.name} · 表單 v${context.formVersion.version}`\n : '選擇可發起的已發布模板後填寫表單內容。'\n }\n title=\"發起簽核\"\n >\n {context ? (\n <Button\n disabled={loading || submitting}\n icon={CheckedIcon}\n iconType=\"leading\"\n onClick={handleSubmit}\n variant=\"base-primary\"\n >\n 送出\n </Button>\n ) : null}\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <div style={FORM_SECTION_STYLE}>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n {loading ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n ) : null}\n\n {context ? (\n <FormRenderer\n errors={formErrors}\n maxWidth={480}\n onChange={(values): void => {\n setFormValues(values);\n setFormErrors({});\n }}\n onUploadAttachment={handleUploadAttachment}\n schema={context.formVersion.schema}\n singleColumn\n uiSchema={context.formVersion.uiSchema}\n value={formValues}\n />\n ) : null}\n\n {!templateId && !loading ? (\n rows.length > 0 ? (\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 目前沒有可發起的已發布模板。\n </Typography>\n )\n ) : null}\n </div>\n </Section>\n </SectionGroup>\n </AppLayout>\n );\n}\n\nfunction NewApprovalInstanceLoading(): ReactElement {\n return (\n <AppLayout activeHref=\"/\">\n <PageHeader>\n <ContentHeader\n description=\"選擇可發起的已發布模板後填寫表單內容。\"\n title=\"發起簽核\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n </Section>\n </SectionGroup>\n </AppLayout>\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":"index.js","names":[],"sources":["../../../../src/views/instances/new/InstanceNewView.tsx"],"sourcesContent":["'use client';\n\nimport {\n CSSProperties,\n ReactElement,\n Suspense,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n Button,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { CheckedIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { FormFieldDefinition } from '@rytass/bpm-core-shared/form';\nimport {\n focusFormRendererField,\n FormRendererValues,\n validateFormRendererValues,\n} from '@rytass/bpm-core-client/form';\nimport {\n LaunchContext,\n LaunchableTemplateRecord,\n listLaunchableTemplates,\n readFormDataCaseTitle,\n readLaunchContext,\n submitApprovalInstance,\n uploadAttachment,\n} from '@rytass/bpm-core-client/workflow';\nimport { formatDateTime } from '../../../lib/format-date-time';\nimport { useAuth } from '../../../lib/auth-provider';\nimport { useRouterAdapter } from '../../../lib/router-adapter';\nimport { useBPMRoutes } from '../../../lib/routes-config';\nimport { AppLayout } from '../../../components/app-navigation';\nimport { FormRenderer } from '../../forms/renderer/FormRendererView';\n\nconst FORM_SECTION_STYLE: CSSProperties = {\n display: 'grid',\n gap: 16,\n};\n\ntype LaunchableTemplateRow = Readonly<\n Record<string, unknown> &\n LaunchableTemplateRecord & {\n key: string;\n versionLabel: string;\n }\n>;\n\nexport interface InstanceNewViewProps {\n /**\n * Optional template id pre-selected by the host. The Server Component\n * page should read `?templateId=` from its `searchParams` and pass the\n * value through this prop.\n */\n readonly templateId?: string | null;\n}\n\n/**\n * Framework-agnostic view for the BPM \"發起簽核\" launch page. Mechanical port\n * of `apps/client/src/app/instances/new/page.tsx` — picks a launchable\n * template and submits the launch form.\n */\nexport function InstanceNewView(\n props: InstanceNewViewProps = {},\n): ReactElement {\n return (\n <Suspense fallback={<NewApprovalInstanceLoading />}>\n <NewApprovalInstanceContent templateId={props.templateId ?? undefined} />\n </Suspense>\n );\n}\n\nfunction NewApprovalInstanceContent({\n templateId: templateIdProp,\n}: {\n readonly templateId?: string;\n}): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const templateId = templateIdProp ?? null;\n const [context, setContext] = useState<LaunchContext | null>(null);\n const [formValues, setFormValues] = useState<FormRendererValues>({});\n const [templates, setTemplates] = useState<\n readonly LaunchableTemplateRecord[]\n >([]);\n const [error, setError] = useState<string | null>(null);\n const [formErrors, setFormErrors] = useState<\n Readonly<Record<string, string>>\n >({});\n const [loading, setLoading] = useState(true);\n const [submitting, setSubmitting] = useState(false);\n\n useEffect((): void => {\n if (!templateId) {\n void refreshTemplates();\n\n return;\n }\n\n void refreshContext(templateId);\n }, [templateId]);\n\n const rows = useMemo(\n (): LaunchableTemplateRow[] =>\n templates.map((template) => ({\n ...template,\n key: template.id,\n updatedAt: formatDateTime(template.updatedAt),\n versionLabel: `v${template.version}`,\n })),\n [templates],\n );\n const columns = useMemo(\n (): TableColumn<LaunchableTemplateRow>[] => [\n { dataIndex: 'name', key: 'name', title: '模板名稱', width: 240 },\n {\n dataIndex: 'versionLabel',\n key: 'versionLabel',\n title: '發布版本',\n width: 120,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<LaunchableTemplateRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<LaunchableTemplateRow>['render']> => [\n {\n name: '發起',\n onClick: (): void =>\n router.push(routes.caseNew(record.id)),\n variant: 'base-primary',\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router],\n );\n\n async function refreshTemplates(): Promise<void> {\n setLoading(true);\n setError(null);\n setContext(null);\n\n try {\n setTemplates(await listLaunchableTemplates());\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function refreshContext(nextTemplateId: string): Promise<void> {\n setLoading(true);\n setError(null);\n setTemplates([]);\n\n try {\n setContext(await readLaunchContext(nextTemplateId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function handleSubmit(): Promise<void> {\n if (!context || !currentMemberId) {\n return;\n }\n\n setSubmitting(true);\n setError(null);\n setFormErrors({});\n\n const validation = validateFormRendererValues({\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n values: formValues,\n });\n\n if (!validation.valid) {\n setFormErrors(validation.errors);\n setError('請先補齊必填欄位。');\n\n if (validation.firstInvalidFieldKey) {\n focusFormRendererField(validation.firstInvalidFieldKey);\n }\n\n setSubmitting(false);\n\n return;\n }\n\n try {\n const instanceId = await submitApprovalInstance({\n formData: formValues,\n initiatorMemberId: currentMemberId,\n templateId: context.template.id,\n title: readFormDataCaseTitle({\n fallbackTitle: context.template.name,\n formData: formValues,\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n }),\n });\n\n router.push(routes.caseDetail(instanceId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSubmitting(false);\n }\n }\n\n async function handleUploadAttachment(\n field: FormFieldDefinition,\n file: File,\n ): Promise<{ readonly id: string }> {\n if (!currentMemberId) {\n throw new Error('尚未登入,無法上傳附件');\n }\n\n const attachment = await uploadAttachment({\n file,\n formFieldPath: `form.${field.fieldKey}`,\n });\n\n return { id: attachment.id };\n }\n\n return (\n <AppLayout activeHref=\"/\">\n <PageHeader>\n <ContentHeader\n description={\n context\n ? `${context.template.name} · 表單 v${context.formVersion.version}`\n : '選擇可發起的已發布模板後填寫表單內容。'\n }\n title=\"發起簽核\"\n >\n {context ? (\n <Button\n disabled={loading || submitting}\n icon={CheckedIcon}\n iconType=\"leading\"\n onClick={handleSubmit}\n variant=\"base-primary\"\n >\n 送出\n </Button>\n ) : null}\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <div style={FORM_SECTION_STYLE}>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n {loading ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n ) : null}\n\n {context ? (\n <FormRenderer\n errors={formErrors}\n maxWidth={480}\n onChange={(values): void => {\n setFormValues(values);\n setFormErrors({});\n }}\n onUploadAttachment={handleUploadAttachment}\n schema={context.formVersion.schema}\n singleColumn\n uiSchema={context.formVersion.uiSchema}\n value={formValues}\n />\n ) : null}\n\n {!templateId && !loading ? (\n rows.length > 0 ? (\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 目前沒有可發起的已發布模板。\n </Typography>\n )\n ) : null}\n </div>\n </Section>\n </SectionGroup>\n </AppLayout>\n );\n}\n\nfunction NewApprovalInstanceLoading(): ReactElement {\n return (\n <AppLayout activeHref=\"/\">\n <PageHeader>\n <ContentHeader\n description=\"選擇可發起的已發布模板後填寫表單內容。\"\n title=\"發起簽核\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <Typography color=\"text-neutral\" variant=\"body\">\n 載入中...\n </Typography>\n </Section>\n </SectionGroup>\n </AppLayout>\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";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/approval-instance-list-page-Mo6wpDPb.cjs");let t=require("react/jsx-runtime");function n(n={}){return(0,t.jsx)(e.t,{activeHref:`/search`,defaultState:null,description:`以關鍵字與狀態查詢你有權限查看的簽核案件。`,emptyMessage:`沒有符合條件的簽核案件。`,searchPlaceholder:`關鍵字:搜尋案件、發起人、模板或狀態`,title:`案件搜尋`,view:`ALL`})}exports.SearchView=n;
1
+ "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/approval-instance-list-page-CVXgE2K3.cjs");let t=require("react/jsx-runtime");function n(n={}){return(0,t.jsx)(e.t,{activeHref:`/search`,defaultState:null,description:`以關鍵字與狀態查詢你有權限查看的簽核案件。`,emptyMessage:`沒有符合條件的簽核案件。`,searchPlaceholder:`關鍵字:搜尋案件、發起人、模板或狀態`,title:`案件搜尋`,view:`ALL`})}exports.SearchView=n;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { t as e } from "../../chunks/approval-instance-list-page-nmzMrj0b.js";
2
+ import { t as e } from "../../chunks/approval-instance-list-page-CqNdoZqx.js";
3
3
  import { jsx as t } from "react/jsx-runtime";
4
4
  //#region src/views/search/SearchView.tsx
5
5
  function n(n = {}) {
@@ -1,2 +1,2 @@
1
- "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/approval-instance-list-page-Mo6wpDPb.cjs");let t=require("react/jsx-runtime");function n(n={}){return(0,t.jsx)(e.t,{activeHref:`/sent`,defaultState:null,description:`查看由你發起的簽核案件與目前流程狀態。`,emptyMessage:`目前沒有由你發起的簽核案件。`,searchPlaceholder:`關鍵字:搜尋案件、發起人、模板或狀態`,title:`我發起的`,view:`SENT`})}exports.SentView=n;
1
+ "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/approval-instance-list-page-CVXgE2K3.cjs");let t=require("react/jsx-runtime");function n(n={}){return(0,t.jsx)(e.t,{activeHref:`/sent`,defaultState:null,description:`查看由你發起的簽核案件與目前流程狀態。`,emptyMessage:`目前沒有由你發起的簽核案件。`,searchPlaceholder:`關鍵字:搜尋案件、發起人、模板或狀態`,title:`我發起的`,view:`SENT`})}exports.SentView=n;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { t as e } from "../../chunks/approval-instance-list-page-nmzMrj0b.js";
2
+ import { t as e } from "../../chunks/approval-instance-list-page-CqNdoZqx.js";
3
3
  import { jsx as t } from "react/jsx-runtime";
4
4
  //#region src/views/sent/SentView.tsx
5
5
  function n(n = {}) {
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/notifications-CPQ-nVar.cjs");exports.SettingsNotificationsView=e.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/notifications-BaYDebFt.cjs");exports.SettingsNotificationsView=e.t;
@@ -1,2 +1,2 @@
1
- import { t as e } from "../../chunks/notifications-DweexUVy.js";
1
+ import { t as e } from "../../chunks/notifications-2swRqDPF.js";
2
2
  export { e as SettingsNotificationsView };