@rytass/bpm-core-react 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/chunks/FormBuilderView-CAqjOYAP.cjs +3 -0
  3. package/dist/chunks/{FormBuilderView-D6baVqBY.cjs.map → FormBuilderView-CAqjOYAP.cjs.map} +1 -1
  4. package/dist/chunks/{FormBuilderView-QtREqV4j.js → FormBuilderView-TzSezeqC.js} +18 -16
  5. package/dist/chunks/{FormBuilderView-QtREqV4j.js.map → FormBuilderView-TzSezeqC.js.map} +1 -1
  6. package/dist/chunks/{FormRendererView-D8QHLvd0.js → FormRendererView-BurlEDUu.js} +44 -41
  7. package/dist/chunks/{FormRendererView-D8QHLvd0.js.map → FormRendererView-BurlEDUu.js.map} +1 -1
  8. package/dist/chunks/FormRendererView-Dde1s3I0.cjs +2 -0
  9. package/dist/chunks/{FormRendererView-Cw9LiidV.cjs.map → FormRendererView-Dde1s3I0.cjs.map} +1 -1
  10. package/dist/chunks/admin-pickers-Btvij1at.cjs.map +1 -1
  11. package/dist/chunks/admin-pickers-DLlG_1du.js.map +1 -1
  12. package/dist/chunks/approval-instance-list-page-BjX2kaoF.js.map +1 -1
  13. package/dist/chunks/approval-instance-list-page-CWiQvnfE.cjs +2 -0
  14. package/dist/chunks/{approval-instance-list-page-C408vxE2.cjs.map → approval-instance-list-page-CWiQvnfE.cjs.map} +1 -1
  15. package/dist/chunks/auth-provider-4BeCw7cI.cjs.map +1 -1
  16. package/dist/chunks/auth-provider-B5oPmvk2.js.map +1 -1
  17. package/dist/chunks/bpm-form-field-Bc6k4ZEO.cjs.map +1 -1
  18. package/dist/chunks/categories-DGlxuC6X.js.map +1 -1
  19. package/dist/chunks/categories-Yid05WAX.cjs +2 -0
  20. package/dist/chunks/{categories-DUfldZ_9.cjs.map → categories-Yid05WAX.cjs.map} +1 -1
  21. package/dist/chunks/{compose-D-OS-Ngs.js → compose-CUOe5Ia9.js} +4 -4
  22. package/dist/chunks/{compose-D-OS-Ngs.js.map → compose-CUOe5Ia9.js.map} +1 -1
  23. package/dist/chunks/compose-CyRkXdeu.cjs +2 -0
  24. package/dist/chunks/{compose-CODnd9-2.cjs.map → compose-CyRkXdeu.cjs.map} +1 -1
  25. package/dist/chunks/dashboard-page-CH87L5nx.cjs +2 -0
  26. package/dist/chunks/{dashboard-page-DwHQY6Ki.cjs.map → dashboard-page-CH87L5nx.cjs.map} +1 -1
  27. package/dist/chunks/dashboard-page-DJ9vOPga.js.map +1 -1
  28. package/dist/chunks/{delegations-DLEEFBlH.js → delegations-0MbJ7CWj.js} +3 -2
  29. package/dist/chunks/{delegations-DLEEFBlH.js.map → delegations-0MbJ7CWj.js.map} +1 -1
  30. package/dist/chunks/delegations-Bc9psOZ3.cjs +2 -0
  31. package/dist/chunks/{delegations-CGj-tZNO.cjs.map → delegations-Bc9psOZ3.cjs.map} +1 -1
  32. package/dist/chunks/{delegations-DqMpI_Nk.js → delegations-DyMGIDpp.js} +3 -2
  33. package/dist/chunks/{delegations-DqMpI_Nk.js.map → delegations-DyMGIDpp.js.map} +1 -1
  34. package/dist/chunks/delegations-vpLtus9g.cjs +2 -0
  35. package/dist/chunks/{delegations-kbMOSEif.cjs.map → delegations-vpLtus9g.cjs.map} +1 -1
  36. package/dist/chunks/{designer-DDSxwtjV.js → designer-Cb3WAC46.js} +39 -30
  37. package/dist/chunks/{designer-DDSxwtjV.js.map → designer-Cb3WAC46.js.map} +1 -1
  38. package/dist/chunks/designer-zLliyrHu.cjs +65 -0
  39. package/dist/chunks/{designer-Cdn10NNl.cjs.map → designer-zLliyrHu.cjs.map} +1 -1
  40. package/dist/chunks/detail-Bp2Nv0cs.cjs +2 -0
  41. package/dist/chunks/{detail-CtVu5NTi.cjs.map → detail-Bp2Nv0cs.cjs.map} +1 -1
  42. package/dist/chunks/{detail-DAPz2qyn.js → detail-Cmw-aQcu.js} +4 -4
  43. package/dist/chunks/{detail-DAPz2qyn.js.map → detail-Cmw-aQcu.js.map} +1 -1
  44. package/dist/chunks/format-date-time-CB-LxzqT.js.map +1 -1
  45. package/dist/chunks/format-date-time-D-cx5M8z.cjs +2 -0
  46. package/dist/chunks/{format-date-time-XxBzF0F5.cjs.map → format-date-time-D-cx5M8z.cjs.map} +1 -1
  47. package/dist/chunks/login-9bCXyjbX.cjs.map +1 -1
  48. package/dist/chunks/login-BKxpLibd.js.map +1 -1
  49. package/dist/chunks/notifications-Bc4mgSds.cjs +2 -0
  50. package/dist/chunks/{notifications--hwl-DR0.cjs.map → notifications-Bc4mgSds.cjs.map} +1 -1
  51. package/dist/chunks/notifications-DJ5wzCye.js.map +1 -1
  52. package/dist/chunks/{orgs-DytLvZ_X.js → orgs-B930facb.js} +11 -10
  53. package/dist/chunks/{orgs-DytLvZ_X.js.map → orgs-B930facb.js.map} +1 -1
  54. package/dist/chunks/orgs-BefGgeyc.cjs +2 -0
  55. package/dist/chunks/{orgs-Ni22buHs.cjs.map → orgs-BefGgeyc.cjs.map} +1 -1
  56. package/dist/chunks/providers-BsEn3ikK.cjs +2 -0
  57. package/dist/chunks/{providers-D_zTbkQH.cjs.map → providers-BsEn3ikK.cjs.map} +1 -1
  58. package/dist/chunks/{providers-DEqcuXw9.js → providers-DjLh4oLY.js} +3 -3
  59. package/dist/chunks/{providers-DEqcuXw9.js.map → providers-DjLh4oLY.js.map} +1 -1
  60. package/dist/chunks/{chunk-CMqjfN_6.cjs → rolldown-runtime-BocRIvOZ.cjs} +1 -1
  61. package/dist/chunks/router-adapter--gYs13E8.cjs.map +1 -1
  62. package/dist/chunks/routes-config-fDVHmvXi.cjs.map +1 -1
  63. package/dist/chunks/users-C9LA-Rd7.cjs +2 -0
  64. package/dist/chunks/{users-0HqlM_VQ.cjs.map → users-C9LA-Rd7.cjs.map} +1 -1
  65. package/dist/chunks/users-FWrb3ehW.js.map +1 -1
  66. package/dist/index.cjs +1 -1
  67. package/dist/index.cjs.map +1 -1
  68. package/dist/index.js +1 -1
  69. package/dist/index.js.map +1 -1
  70. package/dist/next/index.cjs +1 -1
  71. package/dist/next/index.cjs.map +1 -1
  72. package/dist/next/index.js +9 -9
  73. package/dist/next/index.js.map +1 -1
  74. package/dist/next/workflow-chat-route.cjs +1 -1
  75. package/dist/next/workflow-chat-route.cjs.map +1 -1
  76. package/dist/next/workflow-chat-route.js +2 -1
  77. package/dist/next/workflow-chat-route.js.map +1 -1
  78. package/dist/pages/admin/delegations/index.cjs +1 -1
  79. package/dist/pages/admin/delegations/index.cjs.map +1 -1
  80. package/dist/pages/admin/delegations/index.js +1 -1
  81. package/dist/pages/admin/orgs/index.cjs +1 -1
  82. package/dist/pages/admin/orgs/index.cjs.map +1 -1
  83. package/dist/pages/admin/orgs/index.js +1 -1
  84. package/dist/pages/admin/users/index.cjs +1 -1
  85. package/dist/pages/admin/users/index.cjs.map +1 -1
  86. package/dist/pages/cc/index.cjs.map +1 -1
  87. package/dist/pages/dashboard/index.cjs.map +1 -1
  88. package/dist/pages/delegations/index.cjs +1 -1
  89. package/dist/pages/delegations/index.cjs.map +1 -1
  90. package/dist/pages/delegations/index.js +1 -1
  91. package/dist/pages/inbox/index.cjs.map +1 -1
  92. package/dist/pages/instances/detail/index.cjs +1 -1
  93. package/dist/pages/instances/detail/index.cjs.map +1 -1
  94. package/dist/pages/instances/detail/index.js +1 -1
  95. package/dist/pages/instances/new/index.cjs.map +1 -1
  96. package/dist/pages/login/index.cjs.map +1 -1
  97. package/dist/pages/root/index.cjs.map +1 -1
  98. package/dist/pages/search/index.cjs.map +1 -1
  99. package/dist/pages/sent/index.cjs.map +1 -1
  100. package/dist/pages/settings/notifications/index.cjs +1 -1
  101. package/dist/pages/settings/notifications/index.cjs.map +1 -1
  102. package/dist/pages/templates/categories/index.cjs +1 -1
  103. package/dist/pages/templates/categories/index.cjs.map +1 -1
  104. package/dist/pages/templates/compose/index.cjs +1 -1
  105. package/dist/pages/templates/compose/index.cjs.map +1 -1
  106. package/dist/pages/templates/compose/index.js +1 -1
  107. package/dist/pages/templates/designer/index.cjs +1 -1
  108. package/dist/pages/templates/designer/index.cjs.map +1 -1
  109. package/dist/pages/templates/designer/index.js +1 -1
  110. package/dist/pages/templates/index.cjs.map +1 -1
  111. package/dist/pages/templates/versions/index.cjs.map +1 -1
  112. package/dist/views/admin/delegations/index.cjs +1 -1
  113. package/dist/views/admin/delegations/index.js +1 -1
  114. package/dist/views/admin/index.cjs +1 -1
  115. package/dist/views/admin/index.js +2 -2
  116. package/dist/views/admin/orgs/index.cjs +1 -1
  117. package/dist/views/admin/orgs/index.js +1 -1
  118. package/dist/views/admin/users/index.cjs +1 -1
  119. package/dist/views/cc/index.cjs +1 -1
  120. package/dist/views/cc/index.cjs.map +1 -1
  121. package/dist/views/dashboard/index.cjs +1 -1
  122. package/dist/views/dashboard/index.cjs.map +1 -1
  123. package/dist/views/delegations/index.cjs +1 -1
  124. package/dist/views/delegations/index.js +1 -1
  125. package/dist/views/forms/builder/index.cjs +1 -1
  126. package/dist/views/forms/builder/index.js +1 -1
  127. package/dist/views/forms/renderer/index.cjs +1 -1
  128. package/dist/views/forms/renderer/index.js +1 -1
  129. package/dist/views/inbox/index.cjs +1 -1
  130. package/dist/views/inbox/index.cjs.map +1 -1
  131. package/dist/views/inbox/index.js.map +1 -1
  132. package/dist/views/instances/detail/index.cjs +1 -1
  133. package/dist/views/instances/detail/index.js +1 -1
  134. package/dist/views/instances/new/index.cjs +1 -1
  135. package/dist/views/instances/new/index.cjs.map +1 -1
  136. package/dist/views/instances/new/index.js +1 -1
  137. package/dist/views/instances/new/index.js.map +1 -1
  138. package/dist/views/search/index.cjs +1 -1
  139. package/dist/views/search/index.cjs.map +1 -1
  140. package/dist/views/sent/index.cjs +1 -1
  141. package/dist/views/sent/index.cjs.map +1 -1
  142. package/dist/views/settings/index.cjs +1 -1
  143. package/dist/views/settings/notifications/index.cjs +1 -1
  144. package/dist/views/templates/categories/index.cjs +1 -1
  145. package/dist/views/templates/compose/index.cjs +1 -1
  146. package/dist/views/templates/compose/index.js +1 -1
  147. package/dist/views/templates/designer/index.cjs +1 -1
  148. package/dist/views/templates/designer/index.js +1 -1
  149. package/dist/views/templates/index.cjs +1 -1
  150. package/dist/views/templates/index.cjs.map +1 -1
  151. package/dist/views/templates/index.js.map +1 -1
  152. package/dist/views/templates/versions/index.cjs +1 -1
  153. package/dist/views/templates/versions/index.cjs.map +1 -1
  154. package/dist/views/templates/versions/index.js.map +1 -1
  155. package/package.json +3 -3
  156. package/dist/chunks/FormBuilderView-D6baVqBY.cjs +0 -3
  157. package/dist/chunks/FormRendererView-Cw9LiidV.cjs +0 -2
  158. package/dist/chunks/approval-instance-list-page-C408vxE2.cjs +0 -2
  159. package/dist/chunks/categories-DUfldZ_9.cjs +0 -2
  160. package/dist/chunks/compose-CODnd9-2.cjs +0 -2
  161. package/dist/chunks/dashboard-page-DwHQY6Ki.cjs +0 -2
  162. package/dist/chunks/delegations-CGj-tZNO.cjs +0 -2
  163. package/dist/chunks/delegations-kbMOSEif.cjs +0 -2
  164. package/dist/chunks/designer-Cdn10NNl.cjs +0 -65
  165. package/dist/chunks/detail-CtVu5NTi.cjs +0 -2
  166. package/dist/chunks/format-date-time-XxBzF0F5.cjs +0 -2
  167. package/dist/chunks/notifications--hwl-DR0.cjs +0 -2
  168. package/dist/chunks/orgs-Ni22buHs.cjs +0 -2
  169. package/dist/chunks/providers-D_zTbkQH.cjs +0 -2
  170. package/dist/chunks/users-0HqlM_VQ.cjs +0 -2
@@ -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 useCallback,\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 readFormDataSourceErrorMessage,\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 { FormRenderer } from '../../forms/renderer/FormRendererView';\nimport {\n readFormDataSourceSubmissionBlockMessage,\n type FormDataSourceFieldState,\n} from '../../forms/renderer/form-data-source-field';\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 const [dataSourceStates, setDataSourceStates] = useState<\n Readonly<\n Record<string, Pick<FormDataSourceFieldState, 'hasValue' | 'status'>>\n >\n >({});\n\n const handleDataSourceStateChange = useCallback(\n (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'status'\n >,\n ): void => {\n setDataSourceStates((currentStates) => {\n const currentState = currentStates[fieldKey];\n\n if (\n currentState?.hasValue === state.hasValue &&\n currentState.status === state.status\n ) {\n return currentStates;\n }\n\n return {\n ...currentStates,\n [fieldKey]: {\n hasValue: state.hasValue,\n status: state.status,\n },\n };\n });\n },\n [],\n );\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 setDataSourceStates({});\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 setDataSourceStates({});\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 dataSourceBlockMessage = readFormDataSourceSubmissionBlockMessage(\n Object.values(dataSourceStates),\n );\n\n if (dataSourceBlockMessage) {\n setError(dataSourceBlockMessage);\n setSubmitting(false);\n\n return;\n }\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 <>\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 dataSourceContext={{\n kind: 'runtime',\n templateId: context.template.id,\n }}\n errors={formErrors}\n maxWidth={480}\n onChange={(values): void => {\n setFormValues(values);\n setFormErrors({});\n }}\n onDataSourceStateChange={handleDataSourceStateChange}\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 </>\n );\n}\n\nfunction NewApprovalInstanceLoading(): ReactElement {\n return (\n <>\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 </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n // DataSource failures arrive as stable codes so the backend never leaks\n // upstream transport detail; translate them instead of showing the raw code.\n const dataSourceMessage = readFormDataSourceErrorMessage(error);\n\n if (dataSourceMessage) {\n return dataSourceMessage;\n }\n\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 useCallback,\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 readFormDataSourceErrorMessage,\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 { FormRenderer } from '../../forms/renderer/FormRendererView';\nimport {\n readFormDataSourceSubmissionBlockMessage,\n type FormDataSourceFieldState,\n} from '../../forms/renderer/form-data-source-field';\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 const [dataSourceStates, setDataSourceStates] = useState<\n Readonly<\n Record<string, Pick<FormDataSourceFieldState, 'hasValue' | 'status'>>\n >\n >({});\n\n const handleDataSourceStateChange = useCallback(\n (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'status'\n >,\n ): void => {\n setDataSourceStates((currentStates) => {\n const currentState = currentStates[fieldKey];\n\n if (\n currentState?.hasValue === state.hasValue &&\n currentState.status === state.status\n ) {\n return currentStates;\n }\n\n return {\n ...currentStates,\n [fieldKey]: {\n hasValue: state.hasValue,\n status: state.status,\n },\n };\n });\n },\n [],\n );\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 setDataSourceStates({});\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 setDataSourceStates({});\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 dataSourceBlockMessage = readFormDataSourceSubmissionBlockMessage(\n Object.values(dataSourceStates),\n );\n\n if (dataSourceBlockMessage) {\n setError(dataSourceBlockMessage);\n setSubmitting(false);\n\n return;\n }\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 <>\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 dataSourceContext={{\n kind: 'runtime',\n templateId: context.template.id,\n }}\n errors={formErrors}\n maxWidth={480}\n onChange={(values): void => {\n setFormValues(values);\n setFormErrors({});\n }}\n onDataSourceStateChange={handleDataSourceStateChange}\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 </>\n );\n}\n\nfunction NewApprovalInstanceLoading(): ReactElement {\n return (\n <>\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 </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n // DataSource failures arrive as stable codes so the backend never leaks\n // upstream transport detail; translate them instead of showing the raw code.\n const dataSourceMessage = readFormDataSourceErrorMessage(error);\n\n if (dataSourceMessage) {\n return dataSourceMessage;\n }\n\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { r as e } from "../../../chunks/router-adapter-DftlFTOd.js";
3
3
  import { n as t } from "../../../chunks/auth-provider-B5oPmvk2.js";
4
4
  import { t as n } from "../../../chunks/format-date-time-CB-LxzqT.js";
5
5
  import { r } from "../../../chunks/routes-config-RBYQtUd0.js";
6
- import { i, t as a } from "../../../chunks/FormRendererView-D8QHLvd0.js";
6
+ import { i, t as a } from "../../../chunks/FormRendererView-BurlEDUu.js";
7
7
  import { Suspense as o, useCallback as s, useEffect as c, useMemo as l, useState as u } from "react";
8
8
  import { Button as d, PageHeader as f, Section as p, SectionGroup as m, Table as h, Typography as g } from "@mezzanine-ui/react";
9
9
  import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
@@ -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 useCallback,\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 readFormDataSourceErrorMessage,\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 { FormRenderer } from '../../forms/renderer/FormRendererView';\nimport {\n readFormDataSourceSubmissionBlockMessage,\n type FormDataSourceFieldState,\n} from '../../forms/renderer/form-data-source-field';\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 const [dataSourceStates, setDataSourceStates] = useState<\n Readonly<\n Record<string, Pick<FormDataSourceFieldState, 'hasValue' | 'status'>>\n >\n >({});\n\n const handleDataSourceStateChange = useCallback(\n (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'status'\n >,\n ): void => {\n setDataSourceStates((currentStates) => {\n const currentState = currentStates[fieldKey];\n\n if (\n currentState?.hasValue === state.hasValue &&\n currentState.status === state.status\n ) {\n return currentStates;\n }\n\n return {\n ...currentStates,\n [fieldKey]: {\n hasValue: state.hasValue,\n status: state.status,\n },\n };\n });\n },\n [],\n );\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 setDataSourceStates({});\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 setDataSourceStates({});\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 dataSourceBlockMessage = readFormDataSourceSubmissionBlockMessage(\n Object.values(dataSourceStates),\n );\n\n if (dataSourceBlockMessage) {\n setError(dataSourceBlockMessage);\n setSubmitting(false);\n\n return;\n }\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 <>\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 dataSourceContext={{\n kind: 'runtime',\n templateId: context.template.id,\n }}\n errors={formErrors}\n maxWidth={480}\n onChange={(values): void => {\n setFormValues(values);\n setFormErrors({});\n }}\n onDataSourceStateChange={handleDataSourceStateChange}\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 </>\n );\n}\n\nfunction NewApprovalInstanceLoading(): ReactElement {\n return (\n <>\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 </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n // DataSource failures arrive as stable codes so the backend never leaks\n // upstream transport detail; translate them instead of showing the raw code.\n const dataSourceMessage = readFormDataSourceErrorMessage(error);\n\n if (dataSourceMessage) {\n return dataSourceMessage;\n }\n\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 useCallback,\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 readFormDataSourceErrorMessage,\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 { FormRenderer } from '../../forms/renderer/FormRendererView';\nimport {\n readFormDataSourceSubmissionBlockMessage,\n type FormDataSourceFieldState,\n} from '../../forms/renderer/form-data-source-field';\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 const [dataSourceStates, setDataSourceStates] = useState<\n Readonly<\n Record<string, Pick<FormDataSourceFieldState, 'hasValue' | 'status'>>\n >\n >({});\n\n const handleDataSourceStateChange = useCallback(\n (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'status'\n >,\n ): void => {\n setDataSourceStates((currentStates) => {\n const currentState = currentStates[fieldKey];\n\n if (\n currentState?.hasValue === state.hasValue &&\n currentState.status === state.status\n ) {\n return currentStates;\n }\n\n return {\n ...currentStates,\n [fieldKey]: {\n hasValue: state.hasValue,\n status: state.status,\n },\n };\n });\n },\n [],\n );\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 setDataSourceStates({});\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 setDataSourceStates({});\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 dataSourceBlockMessage = readFormDataSourceSubmissionBlockMessage(\n Object.values(dataSourceStates),\n );\n\n if (dataSourceBlockMessage) {\n setError(dataSourceBlockMessage);\n setSubmitting(false);\n\n return;\n }\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 <>\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 dataSourceContext={{\n kind: 'runtime',\n templateId: context.template.id,\n }}\n errors={formErrors}\n maxWidth={480}\n onChange={(values): void => {\n setFormValues(values);\n setFormErrors({});\n }}\n onDataSourceStateChange={handleDataSourceStateChange}\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 </>\n );\n}\n\nfunction NewApprovalInstanceLoading(): ReactElement {\n return (\n <>\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 </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n // DataSource failures arrive as stable codes so the backend never leaks\n // upstream transport detail; translate them instead of showing the raw code.\n const dataSourceMessage = readFormDataSourceErrorMessage(error);\n\n if (dataSourceMessage) {\n return dataSourceMessage;\n }\n\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":";;;;;;;;;;;;;;AAgDA,IAAM,IAAoC;CACxC,SAAS;CACT,KAAK;AACP;AAwBA,SAAgB,EACd,IAA8B,CAAC,GACjB;CACd,OACE,kBAAC,GAAD;EAAU,UAAU,kBAAC,GAAD,CAA6B,CAAA;EAC/C,UAAA,kBAAC,GAAD,EAA4B,YAAY,EAAM,cAAc,KAAA,EAAY,CAAA;CAChE,CAAA;AAEd;AAEA,SAAS,EAA2B,EAClC,YAAY,KAGG;CACf,IAAM,IAAS,EAAiB,GAC1B,IAAS,EAAa,GACtB,EAAE,cAAW,EAAQ,GACrB,IAAkB,GAAQ,YAAY,MACtC,IAAa,KAAkB,MAC/B,CAAC,GAAS,KAAc,EAA+B,IAAI,GAC3D,CAAC,GAAY,KAAiB,EAA6B,CAAC,CAAC,GAC7D,CAAC,GAAW,KAAgB,EAEhC,CAAC,CAAC,GACE,CAAC,GAAO,KAAY,EAAwB,IAAI,GAChD,CAAC,GAAY,KAAiB,EAElC,CAAC,CAAC,GACE,CAAC,GAAS,KAAc,EAAS,EAAI,GACrC,CAAC,GAAY,KAAiB,EAAS,EAAK,GAC5C,CAAC,GAAkB,KAAuB,EAI9C,CAAC,CAAC,GAEE,IAA8B,GAEhC,GACA,MAIS;EACT,GAAqB,MAAkB;GACrC,IAAM,IAAe,EAAc;GASnC,OANE,GAAc,aAAa,EAAM,YACjC,EAAa,WAAW,EAAM,SAEvB,IAGF;IACL,GAAG;KACF,IAAW;KACV,UAAU,EAAM;KAChB,QAAQ,EAAM;IAChB;GACF;EACF,CAAC;CACH,GACA,CAAC,CACH;CAEA,QAAsB;EACpB,IAAI,CAAC,GAAY;GACf,GAAsB;GAEtB;EACF;EAEA,GAAoB,CAAU;CAChC,GAAG,CAAC,CAAU,CAAC;CAEf,IAAM,IAAO,QAET,EAAU,KAAK,OAAc;EAC3B,GAAG;EACH,KAAK,EAAS;EACd,WAAW,EAAe,EAAS,SAAS;EAC5C,cAAc,IAAI,EAAS;CAC7B,EAAE,GACJ,CAAC,CAAS,CACZ,GACM,KAAU,QAC8B;EAC1C;GAAE,WAAW;GAAQ,KAAK;GAAQ,OAAO;GAAQ,OAAO;EAAI;EAC5D;GACE,WAAW;GACX,KAAK;GACL,OAAO;GACP,OAAO;EACT;EACA;GACE,WAAW;GACX,KAAK;GACL,OAAO;GACP,OAAO;EACT;CACF,GACA,CAAC,CACH,GACM,KAAe,SACyB;EAC1C,SACE,MAC8D,CAC9D;GACE,MAAM;GACN,eACE,EAAO,KAAK,EAAO,QAAQ,EAAO,EAAE,CAAC;GACvC,SAAS;EACX,CACF;EACA,SAAS;EACT,OAAO;CACT,IACA,CAAC,CAAM,CACT;CAEA,eAAe,KAAkC;EAI/C,AAHA,EAAW,EAAI,GACf,EAAS,IAAI,GACb,EAAW,IAAI,GACf,EAAoB,CAAC,CAAC;EAEtB,IAAI;GACF,EAAa,MAAM,EAAwB,CAAC;EAC9C,SAAS,GAAuB;GAC9B,EAAS,EAAiB,CAAY,CAAC;EACzC,UAAU;GACR,EAAW,EAAK;EAClB;CACF;CAEA,eAAe,GAAe,GAAuC;EAInE,AAHA,EAAW,EAAI,GACf,EAAS,IAAI,GACb,EAAa,CAAC,CAAC,GACf,EAAoB,CAAC,CAAC;EAEtB,IAAI;GACF,EAAW,MAAM,EAAkB,CAAc,CAAC;EACpD,SAAS,GAAuB;GAC9B,EAAS,EAAiB,CAAY,CAAC;EACzC,UAAU;GACR,EAAW,EAAK;EAClB;CACF;CAEA,eAAe,KAA8B;EAC3C,IAAI,CAAC,KAAW,CAAC,GACf;EAKF,AAFA,EAAc,EAAI,GAClB,EAAS,IAAI,GACb,EAAc,CAAC,CAAC;EAEhB,IAAM,IAAyB,EAC7B,OAAO,OAAO,CAAgB,CAChC;EAEA,IAAI,GAAwB;GAE1B,AADA,EAAS,CAAsB,GAC/B,EAAc,EAAK;GAEnB;EACF;EAEA,IAAM,IAAa,EAA2B;GAC5C,QAAQ,EAAQ,YAAY;GAC5B,UAAU,EAAQ,YAAY;GAC9B,QAAQ;EACV,CAAC;EAED,IAAI,CAAC,EAAW,OAAO;GAQrB,AAPA,EAAc,EAAW,MAAM,GAC/B,EAAS,WAAW,GAEhB,EAAW,wBACb,EAAuB,EAAW,oBAAoB,GAGxD,EAAc,EAAK;GAEnB;EACF;EAEA,IAAI;GACF,IAAM,IAAa,MAAM,EAAuB;IAC9C,UAAU;IACV,mBAAmB;IACnB,YAAY,EAAQ,SAAS;IAC7B,OAAO,EAAsB;KAC3B,eAAe,EAAQ,SAAS;KAChC,UAAU;KACV,QAAQ,EAAQ,YAAY;KAC5B,UAAU,EAAQ,YAAY;IAChC,CAAC;GACH,CAAC;GAED,EAAO,KAAK,EAAO,WAAW,CAAU,CAAC;EAC3C,SAAS,GAAuB;GAC9B,EAAS,EAAiB,CAAY,CAAC;EACzC,UAAU;GACR,EAAc,EAAK;EACrB;CACF;CAEA,eAAe,GACb,GACA,GACkC;EAClC,IAAI,CAAC,GACH,MAAU,MAAM,aAAa;EAQ/B,OAAO,EAAE,KAAI,MALY,EAAiB;GACxC;GACA,eAAe,QAAQ,EAAM;EAC/B,CAAC,EAAA,CAEuB,GAAG;CAC7B;CAEA,OACE,kBAAA,GAAA,EAAA,UAAA,CACI,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EACE,aACE,IACI,GAAG,EAAQ,SAAS,KAAK,SAAS,EAAQ,YAAY,YACtD;EAEN,OAAM;EAEL,UAAA,IACC,kBAAC,GAAD;GACE,UAAU,KAAW;GACrB,MAAM;GACN,UAAS;GACT,SAAS;GACT,SAAQ;GACT,UAAA;EAEO,CAAA,IACN;CACS,CAAA,EACL,CAAA,GAEZ,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;EAAK,OAAO;EAAZ,UAAA;GACG,IACC,kBAAC,GAAD;IAAY,OAAM;IAAa,SAAQ;IACpC,UAAA;GACS,CAAA,IACV;GAEH,IACC,kBAAC,GAAD;IAAY,OAAM;IAAe,SAAQ;IAAO,UAAA;GAEpC,CAAA,IACV;GAEH,IACC,kBAAC,GAAD;IACE,mBAAmB;KACjB,MAAM;KACN,YAAY,EAAQ,SAAS;IAC/B;IACA,QAAQ;IACR,UAAU;IACV,WAAW,MAAiB;KAE1B,AADA,EAAc,CAAM,GACpB,EAAc,CAAC,CAAC;IAClB;IACA,yBAAyB;IACzB,oBAAoB;IACpB,QAAQ,EAAQ,YAAY;IAC5B,cAAA;IACA,UAAU,EAAQ,YAAY;IAC9B,OAAO;GACR,CAAA,IACC;GAEH,CAAC,KAAc,CAAC,IACf,EAAK,SAAS,IACZ,kBAAC,GAAD;IACE,SAAS;IACA;IACT,YAAY;IACZ,WAAA;GACD,CAAA,IAED,kBAAC,GAAD;IAAY,OAAM;IAAe,SAAQ;IAAO,UAAA;GAEpC,CAAA,IAEZ;EACD;CACE,CAAA,EAAA,CAAA,EACG,CAAA,CACd,EAAA,CAAA;AAER;AAEA,SAAS,IAA2C;CAClD,OACE,kBAAA,GAAA,EAAA,UAAA,CACI,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EACE,aAAY;EACZ,OAAM;CACP,CAAA,EACS,CAAA,GAEZ,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EAAY,OAAM;EAAe,SAAQ;EAAO,UAAA;CAEpC,CAAA,EACL,CAAA,EACG,CAAA,CACd,EAAA,CAAA;AAER;AAEA,SAAS,EAAiB,GAAwB;CAShD,OAN0B,EAA+B,CAErD,MAIG,aAAiB,QAAQ,EAAM,UAAU;AAClD"}
@@ -1,2 +1,2 @@
1
- "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/approval-instance-list-page-C408vxE2.cjs");let t=require("react/jsx-runtime");function n(){return(0,t.jsx)(e.t,{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-CWiQvnfE.cjs");let t=require("react/jsx-runtime");function n(){return(0,t.jsx)(e.t,{defaultState:null,description:`以關鍵字與狀態查詢你有權限查看的簽核案件。`,emptyMessage:`沒有符合條件的簽核案件。`,searchPlaceholder:`關鍵字:搜尋案件、發起人、模板或狀態`,title:`案件搜尋`,view:`ALL`})}exports.SearchView=n;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/views/search/SearchView.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactElement } from 'react';\nimport { ApprovalInstanceListPage } from '../../components/approval-instance-list-page';\n\n\n/**\n * Framework-agnostic view for the BPM case search page — list of all\n * instances the current member has visibility on. Mechanical port of\n * `apps/client/src/app/search/page.tsx`.\n */\nexport function SearchView(): ReactElement {\n return (\n <ApprovalInstanceListPage\n defaultState={null}\n description=\"以關鍵字與狀態查詢你有權限查看的簽核案件。\"\n emptyMessage=\"沒有符合條件的簽核案件。\"\n searchPlaceholder=\"關鍵字:搜尋案件、發起人、模板或狀態\"\n title=\"案件搜尋\"\n view=\"ALL\"\n />\n );\n}\n"],"mappings":"4LAWA,SAAgB,GAA2B,CACzC,OACE,EAAA,EAAA,KAAC,EAAA,EAAD,CACE,aAAc,KACd,YAAY,wBACZ,aAAa,eACb,kBAAkB,qBAClB,MAAM,OACN,KAAK,KACN,CAAA,CAEL"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/views/search/SearchView.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactElement } from 'react';\nimport { ApprovalInstanceListPage } from '../../components/approval-instance-list-page';\n\n\n/**\n * Framework-agnostic view for the BPM case search page — list of all\n * instances the current member has visibility on. Mechanical port of\n * `apps/client/src/app/search/page.tsx`.\n */\nexport function SearchView(): ReactElement {\n return (\n <ApprovalInstanceListPage\n defaultState={null}\n description=\"以關鍵字與狀態查詢你有權限查看的簽核案件。\"\n emptyMessage=\"沒有符合條件的簽核案件。\"\n searchPlaceholder=\"關鍵字:搜尋案件、發起人、模板或狀態\"\n title=\"案件搜尋\"\n view=\"ALL\"\n />\n );\n}\n"],"mappings":"4LAWA,SAAgB,GAA2B,CACzC,OACE,EAAA,EAAA,IAAA,CAAC,EAAA,EAAD,CACE,aAAc,KACd,YAAY,wBACZ,aAAa,eACb,kBAAkB,qBAClB,MAAM,OACN,KAAK,KACN,CAAA,CAEL"}
@@ -1,2 +1,2 @@
1
- "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/approval-instance-list-page-C408vxE2.cjs");let t=require("react/jsx-runtime");function n(){return(0,t.jsx)(e.t,{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-CWiQvnfE.cjs");let t=require("react/jsx-runtime");function n(){return(0,t.jsx)(e.t,{defaultState:null,description:`查看由你發起的簽核案件與目前流程狀態。`,emptyMessage:`目前沒有由你發起的簽核案件。`,searchPlaceholder:`關鍵字:搜尋案件、發起人、模板或狀態`,title:`我發起的`,view:`SENT`})}exports.SentView=n;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/views/sent/SentView.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactElement } from 'react';\nimport { ApprovalInstanceListPage } from '../../components/approval-instance-list-page';\n\n\n/**\n * Framework-agnostic view for the BPM \"sent\" inbox — instances the current\n * member has initiated. Mechanical port of\n * `apps/client/src/app/sent/page.tsx`.\n */\nexport function SentView(): ReactElement {\n return (\n <ApprovalInstanceListPage\n defaultState={null}\n description=\"查看由你發起的簽核案件與目前流程狀態。\"\n emptyMessage=\"目前沒有由你發起的簽核案件。\"\n searchPlaceholder=\"關鍵字:搜尋案件、發起人、模板或狀態\"\n title=\"我發起的\"\n view=\"SENT\"\n />\n );\n}\n"],"mappings":"4LAWA,SAAgB,GAAyB,CACvC,OACE,EAAA,EAAA,KAAC,EAAA,EAAD,CACE,aAAc,KACd,YAAY,sBACZ,aAAa,iBACb,kBAAkB,qBAClB,MAAM,OACN,KAAK,MACN,CAAA,CAEL"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/views/sent/SentView.tsx"],"sourcesContent":["'use client';\n\nimport type { ReactElement } from 'react';\nimport { ApprovalInstanceListPage } from '../../components/approval-instance-list-page';\n\n\n/**\n * Framework-agnostic view for the BPM \"sent\" inbox — instances the current\n * member has initiated. Mechanical port of\n * `apps/client/src/app/sent/page.tsx`.\n */\nexport function SentView(): ReactElement {\n return (\n <ApprovalInstanceListPage\n defaultState={null}\n description=\"查看由你發起的簽核案件與目前流程狀態。\"\n emptyMessage=\"目前沒有由你發起的簽核案件。\"\n searchPlaceholder=\"關鍵字:搜尋案件、發起人、模板或狀態\"\n title=\"我發起的\"\n view=\"SENT\"\n />\n );\n}\n"],"mappings":"4LAWA,SAAgB,GAAyB,CACvC,OACE,EAAA,EAAA,IAAA,CAAC,EAAA,EAAD,CACE,aAAc,KACd,YAAY,sBACZ,aAAa,iBACb,kBAAkB,qBAClB,MAAM,OACN,KAAK,MACN,CAAA,CAEL"}
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/notifications--hwl-DR0.cjs");exports.SettingsNotificationsView=e.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/notifications-Bc4mgSds.cjs");exports.SettingsNotificationsView=e.t;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/notifications--hwl-DR0.cjs");exports.SettingsNotificationsView=e.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/notifications-Bc4mgSds.cjs");exports.SettingsNotificationsView=e.t;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/categories-DUfldZ_9.cjs");exports.TemplateCategoriesView=e.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/categories-Yid05WAX.cjs");exports.TemplateCategoriesView=e.t;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/compose-CODnd9-2.cjs");exports.EMPTY_COMPOSE_FORM_SCHEMA=e.n,exports.EMPTY_COMPOSE_FORM_UI_SCHEMA=e.r,exports.TemplateComposeWizardView=e.t,exports.useTemplateComposeWizard=e.i;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/compose-CyRkXdeu.cjs");exports.EMPTY_COMPOSE_FORM_SCHEMA=e.n,exports.EMPTY_COMPOSE_FORM_UI_SCHEMA=e.r,exports.TemplateComposeWizardView=e.t,exports.useTemplateComposeWizard=e.i;
@@ -1,2 +1,2 @@
1
- import { i as e, n as t, r as n, t as r } from "../../../chunks/compose-D-OS-Ngs.js";
1
+ import { i as e, n as t, r as n, t as r } from "../../../chunks/compose-CUOe5Ia9.js";
2
2
  export { t as EMPTY_COMPOSE_FORM_SCHEMA, n as EMPTY_COMPOSE_FORM_UI_SCHEMA, r as TemplateComposeWizardView, e as useTemplateComposeWizard };
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/designer-Cdn10NNl.cjs");exports.TemplateDesignerView=e.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/designer-zLliyrHu.cjs");exports.TemplateDesignerView=e.t;
@@ -1,2 +1,2 @@
1
- import { t as e } from "../../../chunks/designer-DDSxwtjV.js";
1
+ import { t as e } from "../../../chunks/designer-Cb3WAC46.js";
2
2
  export { e as TemplateDesignerView };
@@ -1,2 +1,2 @@
1
- "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/chunk-CMqjfN_6.cjs"),t=require("../../chunks/router-adapter--gYs13E8.cjs"),n=require("../../chunks/format-date-time-XxBzF0F5.cjs"),r=require("../../chunks/routes-config-fDVHmvXi.cjs"),i=require("../../chunks/categories-DUfldZ_9.cjs"),a=require("./versions/index.cjs");let o=require("react"),s=require("@mezzanine-ui/react"),c=require("react/jsx-runtime"),l=require("@rytass/bpm-core-client/workflow"),u=require("@mezzanine-ui/core/form"),d=require("@mezzanine-ui/react/ContentHeader");d=e.t(d,1);let f=require("@mezzanine-ui/icons"),p=require("@rytass/bpm-core-client/template");var m=[10,20,50],h=[{key:`ALL`,label:`全部`},{key:`PUBLISHED`,label:`已發布`},{key:`DRAFT`,label:`草稿`}],g=100;function _(){let e=t.r(),a=r.r(),[_,O]=(0,o.useState)([]),[k,A]=(0,o.useState)(C),[j,M]=(0,o.useState)([]),[N,P]=(0,o.useState)(new Set),[F,I]=(0,o.useState)(null),[L,R]=(0,o.useState)(!0),[z,B]=(0,o.useState)(1),[V,H]=(0,o.useState)(10),[U,W]=(0,o.useState)(``),[G,K]=(0,o.useState)(`ALL`),[q,J]=(0,o.useState)(0),[Y,X]=(0,o.useState)(null),Z=(0,o.useRef)(0),Q=(0,o.useCallback)(async()=>{let e=Z.current+1;Z.current=e,R(!0),I(null),P(new Set),(0,l.listLaunchableTemplates)().then(t=>{e===Z.current&&P(new Set(t.map(e=>e.id)))}).catch(()=>{e===Z.current&&P(new Set)});try{let[t,n]=await Promise.all([(0,p.listApprovalTemplatesPage)({categoryId:k.categoryId,page:z,pageSize:V,searchText:U,status:G===`ALL`?null:G}),(0,p.listApprovalTemplateCategoriesPage)({page:1,pageSize:g,searchText:``,status:`ACTIVE`})]);if(e!==Z.current)return;M([...n.categories.map(w)]),O(t.templates),J(t.totalCount)}catch(t){e===Z.current&&I(v(t))}finally{e===Z.current&&R(!1)}},[k,z,V,U,G]);(0,o.useEffect)(()=>{Q()},[Q]);let $=(0,o.useCallback)(async e=>{X(e.id),I(null);try{await(e.isActive?(0,p.deactivateApprovalTemplate)(e.id):(0,p.activateApprovalTemplate)(e.id)),await Q()}catch(e){I(v(e))}finally{X(null)}},[Q]),ee=(0,o.useMemo)(()=>_.map(e=>({...e,categoryLabel:D(e),key:e.id,status:e.currentVersionId?`PUBLISHED`:`DRAFT`,updatedAt:n.t(e.updatedAt)})),[_]),te=(0,o.useMemo)(()=>[{dataIndex:`name`,key:`name`,title:`模板名稱`,width:220},{key:`status`,render:e=>(0,c.jsx)(b,{status:e.status}),title:`狀態`,width:120},{key:`isActive`,render:e=>(0,c.jsx)(x,{isActive:e.isActive}),title:`服務狀態`,width:120},{key:`category`,render:e=>(0,c.jsx)(S,{record:e}),title:`分類`,width:160},{dataIndex:`updatedAt`,key:`updatedAt`,title:`更新時間`,width:220}],[]),ne=(0,o.useMemo)(()=>({render:t=>[{disabled:e=>!N.has(e.id),name:`發起`,onClick:()=>e.push(a.caseNew(t.id)),variant:`base-primary`},{name:`設計`,onClick:()=>e.push(a.templateDesigner(t.id))},{name:`版本`,onClick:()=>e.push(a.templateVersions(t.id))},{disabled:e=>Y===e.id,name:t.isActive?`停用`:`啟用`,onClick:e=>{$(e)},variant:t.isActive?`destructive-secondary`:`base-secondary`}],variant:`base-secondary`,width:264}),[Y,N,e,$]);return(0,c.jsx)(c.Fragment,{children:(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(s.PageHeader,{children:(0,c.jsx)(d.default,{description:`建立流程模板、維護草稿與發布版本。`,title:`簽核模板`,children:(0,c.jsx)(s.Button,{icon:f.PlusIcon,iconType:`leading`,onClick:()=>e.push(a.templateCompose()),variant:`base-primary`,children:`建立模板`})})}),(0,c.jsx)(s.SectionGroup,{children:(0,c.jsxs)(s.Section,{filterArea:(0,c.jsx)(s.FilterArea,{className:i.n.templateFilterArea,size:`sub`,children:(0,c.jsxs)(s.FilterLine,{children:[(0,c.jsx)(s.Filter,{span:3,children:(0,c.jsx)(s.FormField,{fullWidth:!0,layout:u.FormFieldLayout.VERTICAL,name:`templateSearchText`,children:(0,c.jsx)(s.Input,{fullWidth:!0,onChange:e=>{W(e.target.value),B(1)},placeholder:`關鍵字:搜尋模板名稱、分類或描述`,size:`sub`,value:U,variant:`base`})})}),(0,c.jsx)(s.Filter,{span:2,children:(0,c.jsx)(s.FormField,{fullWidth:!0,layout:u.FormFieldLayout.VERTICAL,name:`templateCategoryFilter`,children:(0,c.jsx)(s.Select,{clearable:!1,fullWidth:!0,onChange:e=>{A(T(e,j)),B(1)},options:[C,...j],placeholder:`分類`,renderValue:e=>`分類:${E(e)}`,size:`sub`,value:k})})})]})}),tab:(0,c.jsx)(s.Tab,{activeKey:G,onChange:e=>{K(y(e)),B(1)},children:h.map(e=>(0,c.jsx)(s.TabItem,{children:e.label},e.key))}),children:[F?(0,c.jsx)(s.Typography,{color:`text-error`,variant:`body`,children:F}):null,(0,c.jsx)(s.Table,{actions:ne,columns:te,dataSource:ee,fullWidth:!0,loading:L,pagination:{current:z,onChange:e=>{B(e)},onChangePageSize:e=>{B(1),H(e)},pageSize:V,pageSizeLabel:`每頁筆數`,pageSizeOptions:m,renderResultSummary:(e,t,n)=>`顯示 ${e}-${t} 筆,共 ${n} 筆`,showPageSizeOptions:!0,total:q}})]})})]})})}function v(e){return e instanceof Error?e.message:`發生未知錯誤`}function y(e){return e===`PUBLISHED`||e===`DRAFT`?e:`ALL`}function b({status:e}){return e===`PUBLISHED`?(0,c.jsx)(s.Badge,{size:`sub`,text:`已發布`,variant:`dot-success`}):(0,c.jsx)(s.Badge,{size:`sub`,text:`草稿`,variant:`dot-inactive`})}function x({isActive:e}){return e?(0,c.jsx)(s.Badge,{size:`sub`,text:`啟用中`,variant:`dot-success`}):(0,c.jsx)(s.Badge,{size:`sub`,text:`已停用`,variant:`dot-inactive`})}function S({record:e}){return e.categoryDetail?.isActive===!1?(0,c.jsx)(s.Badge,{size:`sub`,text:`${e.categoryLabel}(停用)`,variant:`dot-inactive`}):(0,c.jsx)(s.Typography,{component:`span`,variant:`body`,children:e.categoryLabel})}var C={categoryId:null,id:`ALL_CATEGORIES`,name:`全部分類`};function w(e){return{categoryId:e.id,id:e.id,name:e.name}}function T(e,t){if(!O(e))return C;let n=typeof e.id==`string`?e.id:null;return n===C.id?C:t.find(e=>e.id===n)??C}function E(e){return Array.isArray(e)||!O(e)?C.name:typeof e.name==`string`?e.name:C.name}function D(e){return e.categoryDetail?.name??e.category??`未分類`}function O(e){return typeof e==`object`&&!!e}exports.TemplateCategoriesView=i.t,exports.TemplateVersionsView=a.TemplateVersionsView,exports.TemplatesView=_;
1
+ "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/rolldown-runtime-BocRIvOZ.cjs"),t=require("../../chunks/router-adapter--gYs13E8.cjs"),n=require("../../chunks/format-date-time-D-cx5M8z.cjs"),r=require("../../chunks/routes-config-fDVHmvXi.cjs"),i=require("../../chunks/categories-Yid05WAX.cjs"),a=require("./versions/index.cjs");let o=require("react"),s=require("@mezzanine-ui/react"),c=require("react/jsx-runtime"),l=require("@rytass/bpm-core-client/workflow"),u=require("@mezzanine-ui/core/form"),d=require("@mezzanine-ui/react/ContentHeader");d=e.t(d,1);let f=require("@mezzanine-ui/icons"),p=require("@rytass/bpm-core-client/template");var m=[10,20,50],h=[{key:`ALL`,label:`全部`},{key:`PUBLISHED`,label:`已發布`},{key:`DRAFT`,label:`草稿`}],g=100;function _(){let e=t.r(),a=r.r(),[_,O]=(0,o.useState)([]),[k,A]=(0,o.useState)(C),[j,M]=(0,o.useState)([]),[N,P]=(0,o.useState)(new Set),[F,I]=(0,o.useState)(null),[L,R]=(0,o.useState)(!0),[z,B]=(0,o.useState)(1),[V,H]=(0,o.useState)(10),[U,W]=(0,o.useState)(``),[G,K]=(0,o.useState)(`ALL`),[q,J]=(0,o.useState)(0),[Y,X]=(0,o.useState)(null),Z=(0,o.useRef)(0),Q=(0,o.useCallback)(async()=>{let e=Z.current+1;Z.current=e,R(!0),I(null),P(new Set),(0,l.listLaunchableTemplates)().then(t=>{e===Z.current&&P(new Set(t.map(e=>e.id)))}).catch(()=>{e===Z.current&&P(new Set)});try{let[t,n]=await Promise.all([(0,p.listApprovalTemplatesPage)({categoryId:k.categoryId,page:z,pageSize:V,searchText:U,status:G===`ALL`?null:G}),(0,p.listApprovalTemplateCategoriesPage)({page:1,pageSize:g,searchText:``,status:`ACTIVE`})]);if(e!==Z.current)return;M([...n.categories.map(w)]),O(t.templates),J(t.totalCount)}catch(t){e===Z.current&&I(v(t))}finally{e===Z.current&&R(!1)}},[k,z,V,U,G]);(0,o.useEffect)(()=>{Q()},[Q]);let $=(0,o.useCallback)(async e=>{X(e.id),I(null);try{await(e.isActive?(0,p.deactivateApprovalTemplate)(e.id):(0,p.activateApprovalTemplate)(e.id)),await Q()}catch(e){I(v(e))}finally{X(null)}},[Q]),ee=(0,o.useMemo)(()=>_.map(e=>({...e,categoryLabel:D(e),key:e.id,status:e.currentVersionId?`PUBLISHED`:`DRAFT`,updatedAt:n.t(e.updatedAt)})),[_]),te=(0,o.useMemo)(()=>[{dataIndex:`name`,key:`name`,title:`模板名稱`,width:220},{key:`status`,render:e=>(0,c.jsx)(b,{status:e.status}),title:`狀態`,width:120},{key:`isActive`,render:e=>(0,c.jsx)(x,{isActive:e.isActive}),title:`服務狀態`,width:120},{key:`category`,render:e=>(0,c.jsx)(S,{record:e}),title:`分類`,width:160},{dataIndex:`updatedAt`,key:`updatedAt`,title:`更新時間`,width:220}],[]),ne=(0,o.useMemo)(()=>({render:t=>[{disabled:e=>!N.has(e.id),name:`發起`,onClick:()=>e.push(a.caseNew(t.id)),variant:`base-primary`},{name:`設計`,onClick:()=>e.push(a.templateDesigner(t.id))},{name:`版本`,onClick:()=>e.push(a.templateVersions(t.id))},{disabled:e=>Y===e.id,name:t.isActive?`停用`:`啟用`,onClick:e=>{$(e)},variant:t.isActive?`destructive-secondary`:`base-secondary`}],variant:`base-secondary`,width:264}),[Y,N,e,$]);return(0,c.jsx)(c.Fragment,{children:(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(s.PageHeader,{children:(0,c.jsx)(d.default,{description:`建立流程模板、維護草稿與發布版本。`,title:`簽核模板`,children:(0,c.jsx)(s.Button,{icon:f.PlusIcon,iconType:`leading`,onClick:()=>e.push(a.templateCompose()),variant:`base-primary`,children:`建立模板`})})}),(0,c.jsx)(s.SectionGroup,{children:(0,c.jsxs)(s.Section,{filterArea:(0,c.jsx)(s.FilterArea,{className:i.n.templateFilterArea,size:`sub`,children:(0,c.jsxs)(s.FilterLine,{children:[(0,c.jsx)(s.Filter,{span:3,children:(0,c.jsx)(s.FormField,{fullWidth:!0,layout:u.FormFieldLayout.VERTICAL,name:`templateSearchText`,children:(0,c.jsx)(s.Input,{fullWidth:!0,onChange:e=>{W(e.target.value),B(1)},placeholder:`關鍵字:搜尋模板名稱、分類或描述`,size:`sub`,value:U,variant:`base`})})}),(0,c.jsx)(s.Filter,{span:2,children:(0,c.jsx)(s.FormField,{fullWidth:!0,layout:u.FormFieldLayout.VERTICAL,name:`templateCategoryFilter`,children:(0,c.jsx)(s.Select,{clearable:!1,fullWidth:!0,onChange:e=>{A(T(e,j)),B(1)},options:[C,...j],placeholder:`分類`,renderValue:e=>`分類:${E(e)}`,size:`sub`,value:k})})})]})}),tab:(0,c.jsx)(s.Tab,{activeKey:G,onChange:e=>{K(y(e)),B(1)},children:h.map(e=>(0,c.jsx)(s.TabItem,{children:e.label},e.key))}),children:[F?(0,c.jsx)(s.Typography,{color:`text-error`,variant:`body`,children:F}):null,(0,c.jsx)(s.Table,{actions:ne,columns:te,dataSource:ee,fullWidth:!0,loading:L,pagination:{current:z,onChange:e=>{B(e)},onChangePageSize:e=>{B(1),H(e)},pageSize:V,pageSizeLabel:`每頁筆數`,pageSizeOptions:m,renderResultSummary:(e,t,n)=>`顯示 ${e}-${t} 筆,共 ${n} 筆`,showPageSizeOptions:!0,total:q}})]})})]})})}function v(e){return e instanceof Error?e.message:`發生未知錯誤`}function y(e){return e===`PUBLISHED`||e===`DRAFT`?e:`ALL`}function b({status:e}){return e===`PUBLISHED`?(0,c.jsx)(s.Badge,{size:`sub`,text:`已發布`,variant:`dot-success`}):(0,c.jsx)(s.Badge,{size:`sub`,text:`草稿`,variant:`dot-inactive`})}function x({isActive:e}){return e?(0,c.jsx)(s.Badge,{size:`sub`,text:`啟用中`,variant:`dot-success`}):(0,c.jsx)(s.Badge,{size:`sub`,text:`已停用`,variant:`dot-inactive`})}function S({record:e}){return e.categoryDetail?.isActive===!1?(0,c.jsx)(s.Badge,{size:`sub`,text:`${e.categoryLabel}(停用)`,variant:`dot-inactive`}):(0,c.jsx)(s.Typography,{component:`span`,variant:`body`,children:e.categoryLabel})}var C={categoryId:null,id:`ALL_CATEGORIES`,name:`全部分類`};function w(e){return{categoryId:e.id,id:e.id,name:e.name}}function T(e,t){if(!O(e))return C;let n=typeof e.id==`string`?e.id:null;return n===C.id?C:t.find(e=>e.id===n)??C}function E(e){return Array.isArray(e)||!O(e)?C.name:typeof e.name==`string`?e.name:C.name}function D(e){return e.categoryDetail?.name??e.category??`未分類`}function O(e){return typeof e==`object`&&!!e}exports.TemplateCategoriesView=i.t,exports.TemplateVersionsView=a.TemplateVersionsView,exports.TemplatesView=_;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/views/templates/TemplatesView.tsx"],"sourcesContent":["'use client';\n\nimport type { ChangeEvent, Key, ReactElement } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n Badge,\n Button,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n PageHeader,\n Section,\n SectionGroup,\n Select,\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 { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport styles from './templates.module.scss';\nimport { formatDateTime } from '../../lib/format-date-time';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport { useBPMRoutes } from '../../lib/routes-config';\nimport {\n ApprovalTemplateListStatus,\n ApprovalTemplateRecord,\n ApprovalTemplateCategoryRecord,\n activateApprovalTemplate,\n deactivateApprovalTemplate,\n listApprovalTemplateCategoriesPage,\n listApprovalTemplatesPage,\n} from '@rytass/bpm-core-client/template';\nimport { listLaunchableTemplates } from '@rytass/bpm-core-client/workflow';\n\nconst TEMPLATE_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst TEMPLATE_STATUS_TABS: readonly {\n readonly key: TemplateStatusTabKey;\n readonly label: string;\n}[] = [\n { key: 'ALL', label: '全部' },\n { key: 'PUBLISHED', label: '已發布' },\n { key: 'DRAFT', label: '草稿' },\n];\n\nconst TEMPLATE_CATEGORY_PAGE_SIZE = 100;\n\nexport interface TemplateCategoryOption {\n readonly categoryId: string | null;\n readonly id: string;\n readonly name: string;\n}\n\ntype TemplateStatusTabKey = 'ALL' | ApprovalTemplateListStatus;\n\ntype TemplateRow = Readonly<\n Record<string, unknown> &\n ApprovalTemplateRecord & {\n categoryLabel: string;\n key: string;\n status: ApprovalTemplateListStatus;\n }\n>;\n\nexport function TemplatesView(): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const [templates, setTemplates] = useState<readonly ApprovalTemplateRecord[]>(\n [],\n );\n const [categoryFilter, setCategoryFilter] = useState<TemplateCategoryOption>(\n UNCATEGORIZED_TEMPLATE_FILTER_OPTION,\n );\n const [categoryOptions, setCategoryOptions] = useState<\n readonly TemplateCategoryOption[]\n >([]);\n const [launchableTemplateIds, setLaunchableTemplateIds] = useState<\n ReadonlySet<string>\n >(new Set());\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [templatePage, setTemplatePage] = useState(1);\n const [templatePageSize, setTemplatePageSize] = useState(10);\n const [templateSearchText, setTemplateSearchText] = useState('');\n const [templateStatus, setTemplateStatus] =\n useState<TemplateStatusTabKey>('ALL');\n const [templateTotalCount, setTemplateTotalCount] = useState(0);\n const [activationPendingTemplateId, setActivationPendingTemplateId] =\n useState<string | null>(null);\n const refreshRequestIdRef = useRef(0);\n\n const refreshTemplates = useCallback(async (): Promise<void> => {\n const requestId = refreshRequestIdRef.current + 1;\n refreshRequestIdRef.current = requestId;\n setLoading(true);\n setError(null);\n setLaunchableTemplateIds(new Set());\n\n void listLaunchableTemplates()\n .then((nextLaunchableTemplates): void => {\n if (requestId !== refreshRequestIdRef.current) {\n return;\n }\n\n setLaunchableTemplateIds(\n new Set(nextLaunchableTemplates.map((template) => template.id)),\n );\n })\n .catch((): void => {\n if (requestId === refreshRequestIdRef.current) {\n setLaunchableTemplateIds(new Set());\n }\n });\n\n try {\n const [templatePageResult, activeCategoryPageResult] = await Promise.all([\n listApprovalTemplatesPage({\n categoryId: categoryFilter.categoryId,\n page: templatePage,\n pageSize: templatePageSize,\n searchText: templateSearchText,\n status: templateStatus === 'ALL' ? null : templateStatus,\n }),\n listApprovalTemplateCategoriesPage({\n page: 1,\n pageSize: TEMPLATE_CATEGORY_PAGE_SIZE,\n searchText: '',\n status: 'ACTIVE',\n }),\n ]);\n\n if (requestId !== refreshRequestIdRef.current) {\n return;\n }\n\n setCategoryOptions([\n ...activeCategoryPageResult.categories.map(readCategoryOption),\n ]);\n setTemplates(templatePageResult.templates);\n setTemplateTotalCount(templatePageResult.totalCount);\n } catch (requestError: unknown) {\n if (requestId === refreshRequestIdRef.current) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (requestId === refreshRequestIdRef.current) {\n setLoading(false);\n }\n }\n }, [\n categoryFilter,\n templatePage,\n templatePageSize,\n templateSearchText,\n templateStatus,\n ]);\n\n useEffect((): void => {\n void refreshTemplates();\n }, [refreshTemplates]);\n\n const toggleTemplateActivation = useCallback(\n async (template: ApprovalTemplateRecord): Promise<void> => {\n setActivationPendingTemplateId(template.id);\n setError(null);\n\n try {\n await (template.isActive\n ? deactivateApprovalTemplate(template.id)\n : activateApprovalTemplate(template.id));\n await refreshTemplates();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setActivationPendingTemplateId(null);\n }\n },\n [refreshTemplates],\n );\n\n const rows = useMemo(\n (): TemplateRow[] =>\n templates.map((template) => ({\n ...template,\n categoryLabel: readTemplateCategoryLabel(template),\n key: template.id,\n status: template.currentVersionId ? 'PUBLISHED' : 'DRAFT',\n updatedAt: formatDateTime(template.updatedAt),\n })),\n [templates],\n );\n const columns = useMemo(\n (): TableColumn<TemplateRow>[] => [\n { dataIndex: 'name', key: 'name', title: '模板名稱', width: 220 },\n {\n key: 'status',\n render: (record: TemplateRow): ReactElement => (\n <TemplateStatusBadge status={record.status} />\n ),\n title: '狀態',\n width: 120,\n },\n {\n key: 'isActive',\n render: (record: TemplateRow): ReactElement => (\n <TemplateActivationBadge isActive={record.isActive} />\n ),\n title: '服務狀態',\n width: 120,\n },\n {\n key: 'category',\n render: (record: TemplateRow): ReactElement => (\n <TemplateCategoryLabel record={record} />\n ),\n title: '分類',\n width: 160,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<TemplateRow> => ({\n render: (record): ReturnType<TableActions<TemplateRow>['render']> => [\n {\n disabled: (template): boolean =>\n !launchableTemplateIds.has(template.id),\n name: '發起',\n onClick: (): void => router.push(routes.caseNew(record.id)),\n variant: 'base-primary',\n },\n {\n name: '設計',\n onClick: (): void => router.push(routes.templateDesigner(record.id)),\n },\n {\n name: '版本',\n onClick: (): void => router.push(routes.templateVersions(record.id)),\n },\n {\n disabled: (template): boolean =>\n activationPendingTemplateId === template.id,\n name: record.isActive ? '停用' : '啟用',\n onClick: (template): void => {\n void toggleTemplateActivation(template);\n },\n variant: record.isActive ? 'destructive-secondary' : 'base-secondary',\n },\n ],\n variant: 'base-secondary',\n width: 264,\n }),\n [\n activationPendingTemplateId,\n launchableTemplateIds,\n router,\n toggleTemplateActivation,\n ],\n );\n\n return (\n <>\n <>\n <PageHeader>\n <ContentHeader\n description=\"建立流程模板、維護草稿與發布版本。\"\n title=\"簽核模板\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => router.push(routes.templateCompose())}\n variant=\"base-primary\"\n >\n 建立模板\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.templateFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"templateSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setTemplateSearchText(event.target.value);\n setTemplatePage(1);\n }}\n placeholder=\"關鍵字:搜尋模板名稱、分類或描述\"\n size=\"sub\"\n value={templateSearchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"templateCategoryFilter\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void => {\n setCategoryFilter(\n readCategoryFilterOption(option, categoryOptions),\n );\n setTemplatePage(1);\n }}\n options={[\n UNCATEGORIZED_TEMPLATE_FILTER_OPTION,\n ...categoryOptions,\n ]}\n placeholder=\"分類\"\n renderValue={(value): string =>\n `分類:${readTemplateCategoryFilterLabel(value)}`\n }\n size=\"sub\"\n value={categoryFilter}\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n tab={\n <Tab\n activeKey={templateStatus}\n onChange={(activeKey): void => {\n setTemplateStatus(readTemplateStatusTabKey(activeKey));\n setTemplatePage(1);\n }}\n >\n {TEMPLATE_STATUS_TABS.map((statusTab) => (\n <TabItem key={statusTab.key}>{statusTab.label}</TabItem>\n ))}\n </Tab>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n pagination={{\n current: templatePage,\n onChange: (page): void => {\n setTemplatePage(page);\n },\n onChangePageSize: (pageSize): void => {\n setTemplatePage(1);\n setTemplatePageSize(pageSize);\n },\n pageSize: templatePageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: TEMPLATE_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: templateTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n </>\n </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n\nfunction readTemplateStatusTabKey(activeKey: Key): TemplateStatusTabKey {\n if (activeKey === 'PUBLISHED' || activeKey === 'DRAFT') {\n return activeKey;\n }\n\n return 'ALL';\n}\n\nfunction TemplateStatusBadge({\n status,\n}: {\n readonly status: ApprovalTemplateListStatus;\n}): ReactElement {\n if (status === 'PUBLISHED') {\n return <Badge size=\"sub\" text=\"已發布\" variant=\"dot-success\" />;\n }\n\n return <Badge size=\"sub\" text=\"草稿\" variant=\"dot-inactive\" />;\n}\n\nfunction TemplateActivationBadge({\n isActive,\n}: {\n readonly isActive: boolean;\n}): ReactElement {\n if (isActive) {\n return <Badge size=\"sub\" text=\"啟用中\" variant=\"dot-success\" />;\n }\n\n return <Badge size=\"sub\" text=\"已停用\" variant=\"dot-inactive\" />;\n}\n\nfunction TemplateCategoryLabel({\n record,\n}: {\n readonly record: TemplateRow;\n}): ReactElement {\n if (record.categoryDetail?.isActive === false) {\n return (\n <Badge\n size=\"sub\"\n text={`${record.categoryLabel}(停用)`}\n variant=\"dot-inactive\"\n />\n );\n }\n\n return (\n <Typography component=\"span\" variant=\"body\">\n {record.categoryLabel}\n </Typography>\n );\n}\n\nconst UNCATEGORIZED_TEMPLATE_FILTER_OPTION: TemplateCategoryOption = {\n categoryId: null,\n id: 'ALL_CATEGORIES',\n name: '全部分類',\n};\n\nfunction readCategoryOption(\n category: ApprovalTemplateCategoryRecord,\n): TemplateCategoryOption {\n return {\n categoryId: category.id,\n id: category.id,\n name: category.name,\n };\n}\n\nfunction readCategoryFilterOption(\n value: unknown,\n options: readonly TemplateCategoryOption[],\n): TemplateCategoryOption {\n if (!isRecord(value)) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION;\n }\n\n const id = typeof value.id === 'string' ? value.id : null;\n\n if (id === UNCATEGORIZED_TEMPLATE_FILTER_OPTION.id) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION;\n }\n\n return (\n options.find((option) => option.id === id) ??\n UNCATEGORIZED_TEMPLATE_FILTER_OPTION\n );\n}\n\nfunction readTemplateCategoryFilterLabel(value: unknown): string {\n if (Array.isArray(value)) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION.name;\n }\n\n if (!isRecord(value)) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION.name;\n }\n\n return typeof value.name === 'string'\n ? value.name\n : UNCATEGORIZED_TEMPLATE_FILTER_OPTION.name;\n}\n\nfunction readTemplateCategoryLabel(template: ApprovalTemplateRecord): string {\n return template.categoryDetail?.name ?? template.category ?? '未分類';\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/views/templates/TemplatesView.tsx"],"sourcesContent":["'use client';\n\nimport type { ChangeEvent, Key, ReactElement } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n Badge,\n Button,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n PageHeader,\n Section,\n SectionGroup,\n Select,\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 { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport styles from './templates.module.scss';\nimport { formatDateTime } from '../../lib/format-date-time';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport { useBPMRoutes } from '../../lib/routes-config';\nimport {\n ApprovalTemplateListStatus,\n ApprovalTemplateRecord,\n ApprovalTemplateCategoryRecord,\n activateApprovalTemplate,\n deactivateApprovalTemplate,\n listApprovalTemplateCategoriesPage,\n listApprovalTemplatesPage,\n} from '@rytass/bpm-core-client/template';\nimport { listLaunchableTemplates } from '@rytass/bpm-core-client/workflow';\n\nconst TEMPLATE_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst TEMPLATE_STATUS_TABS: readonly {\n readonly key: TemplateStatusTabKey;\n readonly label: string;\n}[] = [\n { key: 'ALL', label: '全部' },\n { key: 'PUBLISHED', label: '已發布' },\n { key: 'DRAFT', label: '草稿' },\n];\n\nconst TEMPLATE_CATEGORY_PAGE_SIZE = 100;\n\nexport interface TemplateCategoryOption {\n readonly categoryId: string | null;\n readonly id: string;\n readonly name: string;\n}\n\ntype TemplateStatusTabKey = 'ALL' | ApprovalTemplateListStatus;\n\ntype TemplateRow = Readonly<\n Record<string, unknown> &\n ApprovalTemplateRecord & {\n categoryLabel: string;\n key: string;\n status: ApprovalTemplateListStatus;\n }\n>;\n\nexport function TemplatesView(): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const [templates, setTemplates] = useState<readonly ApprovalTemplateRecord[]>(\n [],\n );\n const [categoryFilter, setCategoryFilter] = useState<TemplateCategoryOption>(\n UNCATEGORIZED_TEMPLATE_FILTER_OPTION,\n );\n const [categoryOptions, setCategoryOptions] = useState<\n readonly TemplateCategoryOption[]\n >([]);\n const [launchableTemplateIds, setLaunchableTemplateIds] = useState<\n ReadonlySet<string>\n >(new Set());\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [templatePage, setTemplatePage] = useState(1);\n const [templatePageSize, setTemplatePageSize] = useState(10);\n const [templateSearchText, setTemplateSearchText] = useState('');\n const [templateStatus, setTemplateStatus] =\n useState<TemplateStatusTabKey>('ALL');\n const [templateTotalCount, setTemplateTotalCount] = useState(0);\n const [activationPendingTemplateId, setActivationPendingTemplateId] =\n useState<string | null>(null);\n const refreshRequestIdRef = useRef(0);\n\n const refreshTemplates = useCallback(async (): Promise<void> => {\n const requestId = refreshRequestIdRef.current + 1;\n refreshRequestIdRef.current = requestId;\n setLoading(true);\n setError(null);\n setLaunchableTemplateIds(new Set());\n\n void listLaunchableTemplates()\n .then((nextLaunchableTemplates): void => {\n if (requestId !== refreshRequestIdRef.current) {\n return;\n }\n\n setLaunchableTemplateIds(\n new Set(nextLaunchableTemplates.map((template) => template.id)),\n );\n })\n .catch((): void => {\n if (requestId === refreshRequestIdRef.current) {\n setLaunchableTemplateIds(new Set());\n }\n });\n\n try {\n const [templatePageResult, activeCategoryPageResult] = await Promise.all([\n listApprovalTemplatesPage({\n categoryId: categoryFilter.categoryId,\n page: templatePage,\n pageSize: templatePageSize,\n searchText: templateSearchText,\n status: templateStatus === 'ALL' ? null : templateStatus,\n }),\n listApprovalTemplateCategoriesPage({\n page: 1,\n pageSize: TEMPLATE_CATEGORY_PAGE_SIZE,\n searchText: '',\n status: 'ACTIVE',\n }),\n ]);\n\n if (requestId !== refreshRequestIdRef.current) {\n return;\n }\n\n setCategoryOptions([\n ...activeCategoryPageResult.categories.map(readCategoryOption),\n ]);\n setTemplates(templatePageResult.templates);\n setTemplateTotalCount(templatePageResult.totalCount);\n } catch (requestError: unknown) {\n if (requestId === refreshRequestIdRef.current) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (requestId === refreshRequestIdRef.current) {\n setLoading(false);\n }\n }\n }, [\n categoryFilter,\n templatePage,\n templatePageSize,\n templateSearchText,\n templateStatus,\n ]);\n\n useEffect((): void => {\n void refreshTemplates();\n }, [refreshTemplates]);\n\n const toggleTemplateActivation = useCallback(\n async (template: ApprovalTemplateRecord): Promise<void> => {\n setActivationPendingTemplateId(template.id);\n setError(null);\n\n try {\n await (template.isActive\n ? deactivateApprovalTemplate(template.id)\n : activateApprovalTemplate(template.id));\n await refreshTemplates();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setActivationPendingTemplateId(null);\n }\n },\n [refreshTemplates],\n );\n\n const rows = useMemo(\n (): TemplateRow[] =>\n templates.map((template) => ({\n ...template,\n categoryLabel: readTemplateCategoryLabel(template),\n key: template.id,\n status: template.currentVersionId ? 'PUBLISHED' : 'DRAFT',\n updatedAt: formatDateTime(template.updatedAt),\n })),\n [templates],\n );\n const columns = useMemo(\n (): TableColumn<TemplateRow>[] => [\n { dataIndex: 'name', key: 'name', title: '模板名稱', width: 220 },\n {\n key: 'status',\n render: (record: TemplateRow): ReactElement => (\n <TemplateStatusBadge status={record.status} />\n ),\n title: '狀態',\n width: 120,\n },\n {\n key: 'isActive',\n render: (record: TemplateRow): ReactElement => (\n <TemplateActivationBadge isActive={record.isActive} />\n ),\n title: '服務狀態',\n width: 120,\n },\n {\n key: 'category',\n render: (record: TemplateRow): ReactElement => (\n <TemplateCategoryLabel record={record} />\n ),\n title: '分類',\n width: 160,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<TemplateRow> => ({\n render: (record): ReturnType<TableActions<TemplateRow>['render']> => [\n {\n disabled: (template): boolean =>\n !launchableTemplateIds.has(template.id),\n name: '發起',\n onClick: (): void => router.push(routes.caseNew(record.id)),\n variant: 'base-primary',\n },\n {\n name: '設計',\n onClick: (): void => router.push(routes.templateDesigner(record.id)),\n },\n {\n name: '版本',\n onClick: (): void => router.push(routes.templateVersions(record.id)),\n },\n {\n disabled: (template): boolean =>\n activationPendingTemplateId === template.id,\n name: record.isActive ? '停用' : '啟用',\n onClick: (template): void => {\n void toggleTemplateActivation(template);\n },\n variant: record.isActive ? 'destructive-secondary' : 'base-secondary',\n },\n ],\n variant: 'base-secondary',\n width: 264,\n }),\n [\n activationPendingTemplateId,\n launchableTemplateIds,\n router,\n toggleTemplateActivation,\n ],\n );\n\n return (\n <>\n <>\n <PageHeader>\n <ContentHeader\n description=\"建立流程模板、維護草稿與發布版本。\"\n title=\"簽核模板\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => router.push(routes.templateCompose())}\n variant=\"base-primary\"\n >\n 建立模板\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.templateFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"templateSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setTemplateSearchText(event.target.value);\n setTemplatePage(1);\n }}\n placeholder=\"關鍵字:搜尋模板名稱、分類或描述\"\n size=\"sub\"\n value={templateSearchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"templateCategoryFilter\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void => {\n setCategoryFilter(\n readCategoryFilterOption(option, categoryOptions),\n );\n setTemplatePage(1);\n }}\n options={[\n UNCATEGORIZED_TEMPLATE_FILTER_OPTION,\n ...categoryOptions,\n ]}\n placeholder=\"分類\"\n renderValue={(value): string =>\n `分類:${readTemplateCategoryFilterLabel(value)}`\n }\n size=\"sub\"\n value={categoryFilter}\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n tab={\n <Tab\n activeKey={templateStatus}\n onChange={(activeKey): void => {\n setTemplateStatus(readTemplateStatusTabKey(activeKey));\n setTemplatePage(1);\n }}\n >\n {TEMPLATE_STATUS_TABS.map((statusTab) => (\n <TabItem key={statusTab.key}>{statusTab.label}</TabItem>\n ))}\n </Tab>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n pagination={{\n current: templatePage,\n onChange: (page): void => {\n setTemplatePage(page);\n },\n onChangePageSize: (pageSize): void => {\n setTemplatePage(1);\n setTemplatePageSize(pageSize);\n },\n pageSize: templatePageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: TEMPLATE_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: templateTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n </>\n </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n\nfunction readTemplateStatusTabKey(activeKey: Key): TemplateStatusTabKey {\n if (activeKey === 'PUBLISHED' || activeKey === 'DRAFT') {\n return activeKey;\n }\n\n return 'ALL';\n}\n\nfunction TemplateStatusBadge({\n status,\n}: {\n readonly status: ApprovalTemplateListStatus;\n}): ReactElement {\n if (status === 'PUBLISHED') {\n return <Badge size=\"sub\" text=\"已發布\" variant=\"dot-success\" />;\n }\n\n return <Badge size=\"sub\" text=\"草稿\" variant=\"dot-inactive\" />;\n}\n\nfunction TemplateActivationBadge({\n isActive,\n}: {\n readonly isActive: boolean;\n}): ReactElement {\n if (isActive) {\n return <Badge size=\"sub\" text=\"啟用中\" variant=\"dot-success\" />;\n }\n\n return <Badge size=\"sub\" text=\"已停用\" variant=\"dot-inactive\" />;\n}\n\nfunction TemplateCategoryLabel({\n record,\n}: {\n readonly record: TemplateRow;\n}): ReactElement {\n if (record.categoryDetail?.isActive === false) {\n return (\n <Badge\n size=\"sub\"\n text={`${record.categoryLabel}(停用)`}\n variant=\"dot-inactive\"\n />\n );\n }\n\n return (\n <Typography component=\"span\" variant=\"body\">\n {record.categoryLabel}\n </Typography>\n );\n}\n\nconst UNCATEGORIZED_TEMPLATE_FILTER_OPTION: TemplateCategoryOption = {\n categoryId: null,\n id: 'ALL_CATEGORIES',\n name: '全部分類',\n};\n\nfunction readCategoryOption(\n category: ApprovalTemplateCategoryRecord,\n): TemplateCategoryOption {\n return {\n categoryId: category.id,\n id: category.id,\n name: category.name,\n };\n}\n\nfunction readCategoryFilterOption(\n value: unknown,\n options: readonly TemplateCategoryOption[],\n): TemplateCategoryOption {\n if (!isRecord(value)) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION;\n }\n\n const id = typeof value.id === 'string' ? value.id : null;\n\n if (id === UNCATEGORIZED_TEMPLATE_FILTER_OPTION.id) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION;\n }\n\n return (\n options.find((option) => option.id === id) ??\n UNCATEGORIZED_TEMPLATE_FILTER_OPTION\n );\n}\n\nfunction readTemplateCategoryFilterLabel(value: unknown): string {\n if (Array.isArray(value)) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION.name;\n }\n\n if (!isRecord(value)) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION.name;\n }\n\n return typeof value.name === 'string'\n ? value.name\n : UNCATEGORIZED_TEMPLATE_FILTER_OPTION.name;\n}\n\nfunction readTemplateCategoryLabel(template: ApprovalTemplateRecord): string {\n return template.categoryDetail?.name ?? template.category ?? '未分類';\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/views/templates/TemplatesView.tsx"],"sourcesContent":["'use client';\n\nimport type { ChangeEvent, Key, ReactElement } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n Badge,\n Button,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n PageHeader,\n Section,\n SectionGroup,\n Select,\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 { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport styles from './templates.module.scss';\nimport { formatDateTime } from '../../lib/format-date-time';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport { useBPMRoutes } from '../../lib/routes-config';\nimport {\n ApprovalTemplateListStatus,\n ApprovalTemplateRecord,\n ApprovalTemplateCategoryRecord,\n activateApprovalTemplate,\n deactivateApprovalTemplate,\n listApprovalTemplateCategoriesPage,\n listApprovalTemplatesPage,\n} from '@rytass/bpm-core-client/template';\nimport { listLaunchableTemplates } from '@rytass/bpm-core-client/workflow';\n\nconst TEMPLATE_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst TEMPLATE_STATUS_TABS: readonly {\n readonly key: TemplateStatusTabKey;\n readonly label: string;\n}[] = [\n { key: 'ALL', label: '全部' },\n { key: 'PUBLISHED', label: '已發布' },\n { key: 'DRAFT', label: '草稿' },\n];\n\nconst TEMPLATE_CATEGORY_PAGE_SIZE = 100;\n\nexport interface TemplateCategoryOption {\n readonly categoryId: string | null;\n readonly id: string;\n readonly name: string;\n}\n\ntype TemplateStatusTabKey = 'ALL' | ApprovalTemplateListStatus;\n\ntype TemplateRow = Readonly<\n Record<string, unknown> &\n ApprovalTemplateRecord & {\n categoryLabel: string;\n key: string;\n status: ApprovalTemplateListStatus;\n }\n>;\n\nexport function TemplatesView(): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const [templates, setTemplates] = useState<readonly ApprovalTemplateRecord[]>(\n [],\n );\n const [categoryFilter, setCategoryFilter] = useState<TemplateCategoryOption>(\n UNCATEGORIZED_TEMPLATE_FILTER_OPTION,\n );\n const [categoryOptions, setCategoryOptions] = useState<\n readonly TemplateCategoryOption[]\n >([]);\n const [launchableTemplateIds, setLaunchableTemplateIds] = useState<\n ReadonlySet<string>\n >(new Set());\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [templatePage, setTemplatePage] = useState(1);\n const [templatePageSize, setTemplatePageSize] = useState(10);\n const [templateSearchText, setTemplateSearchText] = useState('');\n const [templateStatus, setTemplateStatus] =\n useState<TemplateStatusTabKey>('ALL');\n const [templateTotalCount, setTemplateTotalCount] = useState(0);\n const [activationPendingTemplateId, setActivationPendingTemplateId] =\n useState<string | null>(null);\n const refreshRequestIdRef = useRef(0);\n\n const refreshTemplates = useCallback(async (): Promise<void> => {\n const requestId = refreshRequestIdRef.current + 1;\n refreshRequestIdRef.current = requestId;\n setLoading(true);\n setError(null);\n setLaunchableTemplateIds(new Set());\n\n void listLaunchableTemplates()\n .then((nextLaunchableTemplates): void => {\n if (requestId !== refreshRequestIdRef.current) {\n return;\n }\n\n setLaunchableTemplateIds(\n new Set(nextLaunchableTemplates.map((template) => template.id)),\n );\n })\n .catch((): void => {\n if (requestId === refreshRequestIdRef.current) {\n setLaunchableTemplateIds(new Set());\n }\n });\n\n try {\n const [templatePageResult, activeCategoryPageResult] = await Promise.all([\n listApprovalTemplatesPage({\n categoryId: categoryFilter.categoryId,\n page: templatePage,\n pageSize: templatePageSize,\n searchText: templateSearchText,\n status: templateStatus === 'ALL' ? null : templateStatus,\n }),\n listApprovalTemplateCategoriesPage({\n page: 1,\n pageSize: TEMPLATE_CATEGORY_PAGE_SIZE,\n searchText: '',\n status: 'ACTIVE',\n }),\n ]);\n\n if (requestId !== refreshRequestIdRef.current) {\n return;\n }\n\n setCategoryOptions([\n ...activeCategoryPageResult.categories.map(readCategoryOption),\n ]);\n setTemplates(templatePageResult.templates);\n setTemplateTotalCount(templatePageResult.totalCount);\n } catch (requestError: unknown) {\n if (requestId === refreshRequestIdRef.current) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (requestId === refreshRequestIdRef.current) {\n setLoading(false);\n }\n }\n }, [\n categoryFilter,\n templatePage,\n templatePageSize,\n templateSearchText,\n templateStatus,\n ]);\n\n useEffect((): void => {\n void refreshTemplates();\n }, [refreshTemplates]);\n\n const toggleTemplateActivation = useCallback(\n async (template: ApprovalTemplateRecord): Promise<void> => {\n setActivationPendingTemplateId(template.id);\n setError(null);\n\n try {\n await (template.isActive\n ? deactivateApprovalTemplate(template.id)\n : activateApprovalTemplate(template.id));\n await refreshTemplates();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setActivationPendingTemplateId(null);\n }\n },\n [refreshTemplates],\n );\n\n const rows = useMemo(\n (): TemplateRow[] =>\n templates.map((template) => ({\n ...template,\n categoryLabel: readTemplateCategoryLabel(template),\n key: template.id,\n status: template.currentVersionId ? 'PUBLISHED' : 'DRAFT',\n updatedAt: formatDateTime(template.updatedAt),\n })),\n [templates],\n );\n const columns = useMemo(\n (): TableColumn<TemplateRow>[] => [\n { dataIndex: 'name', key: 'name', title: '模板名稱', width: 220 },\n {\n key: 'status',\n render: (record: TemplateRow): ReactElement => (\n <TemplateStatusBadge status={record.status} />\n ),\n title: '狀態',\n width: 120,\n },\n {\n key: 'isActive',\n render: (record: TemplateRow): ReactElement => (\n <TemplateActivationBadge isActive={record.isActive} />\n ),\n title: '服務狀態',\n width: 120,\n },\n {\n key: 'category',\n render: (record: TemplateRow): ReactElement => (\n <TemplateCategoryLabel record={record} />\n ),\n title: '分類',\n width: 160,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<TemplateRow> => ({\n render: (record): ReturnType<TableActions<TemplateRow>['render']> => [\n {\n disabled: (template): boolean =>\n !launchableTemplateIds.has(template.id),\n name: '發起',\n onClick: (): void => router.push(routes.caseNew(record.id)),\n variant: 'base-primary',\n },\n {\n name: '設計',\n onClick: (): void => router.push(routes.templateDesigner(record.id)),\n },\n {\n name: '版本',\n onClick: (): void => router.push(routes.templateVersions(record.id)),\n },\n {\n disabled: (template): boolean =>\n activationPendingTemplateId === template.id,\n name: record.isActive ? '停用' : '啟用',\n onClick: (template): void => {\n void toggleTemplateActivation(template);\n },\n variant: record.isActive ? 'destructive-secondary' : 'base-secondary',\n },\n ],\n variant: 'base-secondary',\n width: 264,\n }),\n [\n activationPendingTemplateId,\n launchableTemplateIds,\n router,\n toggleTemplateActivation,\n ],\n );\n\n return (\n <>\n <>\n <PageHeader>\n <ContentHeader\n description=\"建立流程模板、維護草稿與發布版本。\"\n title=\"簽核模板\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => router.push(routes.templateCompose())}\n variant=\"base-primary\"\n >\n 建立模板\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.templateFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"templateSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setTemplateSearchText(event.target.value);\n setTemplatePage(1);\n }}\n placeholder=\"關鍵字:搜尋模板名稱、分類或描述\"\n size=\"sub\"\n value={templateSearchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"templateCategoryFilter\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void => {\n setCategoryFilter(\n readCategoryFilterOption(option, categoryOptions),\n );\n setTemplatePage(1);\n }}\n options={[\n UNCATEGORIZED_TEMPLATE_FILTER_OPTION,\n ...categoryOptions,\n ]}\n placeholder=\"分類\"\n renderValue={(value): string =>\n `分類:${readTemplateCategoryFilterLabel(value)}`\n }\n size=\"sub\"\n value={categoryFilter}\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n tab={\n <Tab\n activeKey={templateStatus}\n onChange={(activeKey): void => {\n setTemplateStatus(readTemplateStatusTabKey(activeKey));\n setTemplatePage(1);\n }}\n >\n {TEMPLATE_STATUS_TABS.map((statusTab) => (\n <TabItem key={statusTab.key}>{statusTab.label}</TabItem>\n ))}\n </Tab>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n pagination={{\n current: templatePage,\n onChange: (page): void => {\n setTemplatePage(page);\n },\n onChangePageSize: (pageSize): void => {\n setTemplatePage(1);\n setTemplatePageSize(pageSize);\n },\n pageSize: templatePageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: TEMPLATE_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: templateTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n </>\n </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n\nfunction readTemplateStatusTabKey(activeKey: Key): TemplateStatusTabKey {\n if (activeKey === 'PUBLISHED' || activeKey === 'DRAFT') {\n return activeKey;\n }\n\n return 'ALL';\n}\n\nfunction TemplateStatusBadge({\n status,\n}: {\n readonly status: ApprovalTemplateListStatus;\n}): ReactElement {\n if (status === 'PUBLISHED') {\n return <Badge size=\"sub\" text=\"已發布\" variant=\"dot-success\" />;\n }\n\n return <Badge size=\"sub\" text=\"草稿\" variant=\"dot-inactive\" />;\n}\n\nfunction TemplateActivationBadge({\n isActive,\n}: {\n readonly isActive: boolean;\n}): ReactElement {\n if (isActive) {\n return <Badge size=\"sub\" text=\"啟用中\" variant=\"dot-success\" />;\n }\n\n return <Badge size=\"sub\" text=\"已停用\" variant=\"dot-inactive\" />;\n}\n\nfunction TemplateCategoryLabel({\n record,\n}: {\n readonly record: TemplateRow;\n}): ReactElement {\n if (record.categoryDetail?.isActive === false) {\n return (\n <Badge\n size=\"sub\"\n text={`${record.categoryLabel}(停用)`}\n variant=\"dot-inactive\"\n />\n );\n }\n\n return (\n <Typography component=\"span\" variant=\"body\">\n {record.categoryLabel}\n </Typography>\n );\n}\n\nconst UNCATEGORIZED_TEMPLATE_FILTER_OPTION: TemplateCategoryOption = {\n categoryId: null,\n id: 'ALL_CATEGORIES',\n name: '全部分類',\n};\n\nfunction readCategoryOption(\n category: ApprovalTemplateCategoryRecord,\n): TemplateCategoryOption {\n return {\n categoryId: category.id,\n id: category.id,\n name: category.name,\n };\n}\n\nfunction readCategoryFilterOption(\n value: unknown,\n options: readonly TemplateCategoryOption[],\n): TemplateCategoryOption {\n if (!isRecord(value)) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION;\n }\n\n const id = typeof value.id === 'string' ? value.id : null;\n\n if (id === UNCATEGORIZED_TEMPLATE_FILTER_OPTION.id) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION;\n }\n\n return (\n options.find((option) => option.id === id) ??\n UNCATEGORIZED_TEMPLATE_FILTER_OPTION\n );\n}\n\nfunction readTemplateCategoryFilterLabel(value: unknown): string {\n if (Array.isArray(value)) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION.name;\n }\n\n if (!isRecord(value)) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION.name;\n }\n\n return typeof value.name === 'string'\n ? value.name\n : UNCATEGORIZED_TEMPLATE_FILTER_OPTION.name;\n}\n\nfunction readTemplateCategoryLabel(template: ApprovalTemplateRecord): string {\n return template.categoryDetail?.name ?? template.category ?? '未分類';\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAwCA,IAAM,KAA6B;CAAC;CAAI;CAAI;AAAE,GACxC,IAGA;CACJ;EAAE,KAAK;EAAO,OAAO;CAAK;CAC1B;EAAE,KAAK;EAAa,OAAO;CAAM;CACjC;EAAE,KAAK;EAAS,OAAO;CAAK;AAC9B,GAEM,IAA8B;AAmBpC,SAAgB,IAA8B;CAC5C,IAAM,IAAS,EAAiB,GAC1B,IAAS,EAAa,GACtB,CAAC,GAAW,KAAgB,EAChC,CAAC,CACH,GACM,CAAC,GAAgB,KAAqB,EAC1C,CACF,GACM,CAAC,GAAiB,KAAsB,EAE5C,CAAC,CAAC,GACE,CAAC,GAAuB,KAA4B,kBAExD,IAAI,IAAI,CAAC,GACL,CAAC,GAAO,KAAY,EAAwB,IAAI,GAChD,CAAC,IAAS,KAAc,EAAS,EAAI,GACrC,CAAC,GAAc,KAAmB,EAAS,CAAC,GAC5C,CAAC,GAAkB,MAAuB,EAAS,EAAE,GACrD,CAAC,GAAoB,MAAyB,EAAS,EAAE,GACzD,CAAC,GAAgB,MACrB,EAA+B,KAAK,GAChC,CAAC,IAAoB,MAAyB,EAAS,CAAC,GACxD,CAAC,GAA6B,KAClC,EAAwB,IAAI,GACxB,IAAsB,EAAO,CAAC,GAE9B,IAAmB,EAAY,YAA2B;EAC9D,IAAM,IAAY,EAAoB,UAAU;EAMhD,AALA,EAAoB,UAAU,GAC9B,EAAW,EAAI,GACf,EAAS,IAAI,GACb,kBAAyB,IAAI,IAAI,CAAC,GAElC,EAA6B,EAC1B,MAAM,MAAkC;GACnC,MAAc,EAAoB,WAItC,EACE,IAAI,IAAI,EAAwB,KAAK,MAAa,EAAS,EAAE,CAAC,CAChE;EACF,CAAC,EACA,YAAkB;GACjB,AAAI,MAAc,EAAoB,WACpC,kBAAyB,IAAI,IAAI,CAAC;EAEtC,CAAC;EAEH,IAAI;GACF,IAAM,CAAC,GAAoB,KAA4B,MAAM,QAAQ,IAAI,CACvE,GAA0B;IACxB,YAAY,EAAe;IAC3B,MAAM;IACN,UAAU;IACV,YAAY;IACZ,QAAQ,MAAmB,QAAQ,OAAO;GAC5C,CAAC,GACD,GAAmC;IACjC,MAAM;IACN,UAAU;IACV,YAAY;IACZ,QAAQ;GACV,CAAC,CACH,CAAC;GAED,IAAI,MAAc,EAAoB,SACpC;GAOF,AAJA,EAAmB,CACjB,GAAG,EAAyB,WAAW,IAAI,CAAkB,CAC/D,CAAC,GACD,EAAa,EAAmB,SAAS,GACzC,GAAsB,EAAmB,UAAU;EACrD,SAAS,GAAuB;GAC9B,AAAI,MAAc,EAAoB,WACpC,EAAS,EAAiB,CAAY,CAAC;EAE3C,UAAU;GACR,AAAI,MAAc,EAAoB,WACpC,EAAW,EAAK;EAEpB;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,QAAsB;EACpB,EAAsB;CACxB,GAAG,CAAC,CAAgB,CAAC;CAErB,IAAM,IAA2B,EAC/B,OAAO,MAAoD;EAEzD,AADA,EAA+B,EAAS,EAAE,GAC1C,EAAS,IAAI;EAEb,IAAI;GAIF,AAHA,OAAO,EAAS,WACZ,GAA2B,EAAS,EAAE,IACtC,GAAyB,EAAS,EAAE,IACxC,MAAM,EAAiB;EACzB,SAAS,GAAuB;GAC9B,EAAS,EAAiB,CAAY,CAAC;EACzC,UAAU;GACR,EAA+B,IAAI;EACrC;CACF,GACA,CAAC,CAAgB,CACnB,GAEM,KAAO,QAET,EAAU,KAAK,OAAc;EAC3B,GAAG;EACH,eAAe,EAA0B,CAAQ;EACjD,KAAK,EAAS;EACd,QAAQ,EAAS,mBAAmB,cAAc;EAClD,WAAW,EAAe,EAAS,SAAS;CAC9C,EAAE,GACJ,CAAC,CAAS,CACZ,GACM,KAAU,QACoB;EAChC;GAAE,WAAW;GAAQ,KAAK;GAAQ,OAAO;GAAQ,OAAO;EAAI;EAC5D;GACE,KAAK;GACL,SAAS,MACP,kBAAC,GAAD,EAAqB,QAAQ,EAAO,OAAS,CAAA;GAE/C,OAAO;GACP,OAAO;EACT;EACA;GACE,KAAK;GACL,SAAS,MACP,kBAAC,GAAD,EAAyB,UAAU,EAAO,SAAW,CAAA;GAEvD,OAAO;GACP,OAAO;EACT;EACA;GACE,KAAK;GACL,SAAS,MACP,kBAAC,GAAD,EAA+B,UAAS,CAAA;GAE1C,OAAO;GACP,OAAO;EACT;EACA;GACE,WAAW;GACX,KAAK;GACL,OAAO;GACP,OAAO;EACT;CACF,GACA,CAAC,CACH,GACM,KAAe,SACe;EAChC,SAAS,MAA4D;GACnE;IACE,WAAW,MACT,CAAC,EAAsB,IAAI,EAAS,EAAE;IACxC,MAAM;IACN,eAAqB,EAAO,KAAK,EAAO,QAAQ,EAAO,EAAE,CAAC;IAC1D,SAAS;GACX;GACA;IACE,MAAM;IACN,eAAqB,EAAO,KAAK,EAAO,iBAAiB,EAAO,EAAE,CAAC;GACrE;GACA;IACE,MAAM;IACN,eAAqB,EAAO,KAAK,EAAO,iBAAiB,EAAO,EAAE,CAAC;GACrE;GACA;IACE,WAAW,MACT,MAAgC,EAAS;IAC3C,MAAM,EAAO,WAAW,OAAO;IAC/B,UAAU,MAAmB;KAC3B,EAA8B,CAAQ;IACxC;IACA,SAAS,EAAO,WAAW,0BAA0B;GACvD;EACF;EACA,SAAS;EACT,OAAO;CACT,IACA;EACE;EACA;EACA;EACA;CACF,CACF;CAEA,OACE,kBAAA,GAAA,EAAA,UACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,IAAD;EACE,aAAY;EACZ,OAAM;YAEN,kBAAC,IAAD;GACE,MAAM;GACN,UAAS;GACT,eAAqB,EAAO,KAAK,EAAO,gBAAgB,CAAC;GACzD,SAAQ;aACT;EAEO,CAAA;CACK,CAAA,EACL,CAAA,GAEZ,kBAAC,IAAD,EAAA,UACE,kBAAC,GAAD;EACE,YACE,kBAAC,IAAD;GAAY,WAAW,GAAO;GAAoB,MAAK;aACrD,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,GAAD;IAAQ,MAAM;cACZ,kBAAC,GAAD;KACE,WAAA;KACA,QAAQ,EAAgB;KACxB,MAAK;eAEL,kBAAC,GAAD;MACE,WAAA;MACA,WACE,MACS;OAET,AADA,GAAsB,EAAM,OAAO,KAAK,GACxC,EAAgB,CAAC;MACnB;MACA,aAAY;MACZ,MAAK;MACL,OAAO;MACP,SAAQ;KACT,CAAA;IACQ,CAAA;GACL,CAAA,GACR,kBAAC,GAAD;IAAQ,MAAM;cACZ,kBAAC,GAAD;KACE,WAAA;KACA,QAAQ,EAAgB;KACxB,MAAK;eAEL,kBAAC,IAAD;MACE,WAAW;MACX,WAAA;MACA,WAAW,MAAiB;OAI1B,AAHA,EACE,EAAyB,GAAQ,CAAe,CAClD,GACA,EAAgB,CAAC;MACnB;MACA,SAAS,CACP,GACA,GAAG,CACL;MACA,aAAY;MACZ,cAAc,MACZ,MAAM,EAAgC,CAAK;MAE7C,MAAK;MACL,OAAO;KACR,CAAA;IACQ,CAAA;GACL,CAAA,CACE,EAAA,CAAA;EACF,CAAA;EAEd,KACE,kBAAC,IAAD;GACE,WAAW;GACX,WAAW,MAAoB;IAE7B,AADA,GAAkB,EAAyB,CAAS,CAAC,GACrD,EAAgB,CAAC;GACnB;aAEC,EAAqB,KAAK,MACzB,kBAAC,IAAD,EAAA,UAA8B,EAAU,MAAe,GAAzC,EAAU,GAA+B,CACxD;EACE,CAAA;YAnET,CAsEG,IACC,kBAAC,GAAD;GAAY,OAAM;GAAa,SAAQ;aACpC;EACS,CAAA,IACV,MACJ,kBAAC,IAAD;GACE,SAAS;GACA;GACT,YAAY;GACZ,WAAA;GACS;GACT,YAAY;IACV,SAAS;IACT,WAAW,MAAe;KACxB,EAAgB,CAAI;IACtB;IACA,mBAAmB,MAAmB;KAEpC,AADA,EAAgB,CAAC,GACjB,GAAoB,CAAQ;IAC9B;IACA,UAAU;IACV,eAAe;IACf,iBAAiB;IACjB,sBAAsB,GAAM,GAAI,MAC9B,MAAM,EAAK,GAAG,EAAG,OAAO,EAAM;IAChC,qBAAqB;IACrB,OAAO;GACT;EACD,CAAA,CACM;IACG,CAAA,CACd,EAAA,CAAA,EACF,CAAA;AAEN;AAEA,SAAS,EAAiB,GAAwB;CAChD,OAAO,aAAiB,QAAQ,EAAM,UAAU;AAClD;AAEA,SAAS,EAAyB,GAAsC;CAKtE,OAJI,MAAc,eAAe,MAAc,UACtC,IAGF;AACT;AAEA,SAAS,EAAoB,EAC3B,aAGe;CAKf,OAJI,MAAW,cACN,kBAAC,GAAD;EAAO,MAAK;EAAM,MAAK;EAAM,SAAQ;CAAe,CAAA,IAGtD,kBAAC,GAAD;EAAO,MAAK;EAAM,MAAK;EAAK,SAAQ;CAAgB,CAAA;AAC7D;AAEA,SAAS,EAAwB,EAC/B,eAGe;CAKf,OAJI,IACK,kBAAC,GAAD;EAAO,MAAK;EAAM,MAAK;EAAM,SAAQ;CAAe,CAAA,IAGtD,kBAAC,GAAD;EAAO,MAAK;EAAM,MAAK;EAAM,SAAQ;CAAgB,CAAA;AAC9D;AAEA,SAAS,EAAsB,EAC7B,aAGe;CAWf,OAVI,EAAO,gBAAgB,aAAa,KAEpC,kBAAC,GAAD;EACE,MAAK;EACL,MAAM,GAAG,EAAO,cAAc;EAC9B,SAAQ;CACT,CAAA,IAKH,kBAAC,GAAD;EAAY,WAAU;EAAO,SAAQ;YAClC,EAAO;CACE,CAAA;AAEhB;AAEA,IAAM,IAA+D;CACnE,YAAY;CACZ,IAAI;CACJ,MAAM;AACR;AAEA,SAAS,EACP,GACwB;CACxB,OAAO;EACL,YAAY,EAAS;EACrB,IAAI,EAAS;EACb,MAAM,EAAS;CACjB;AACF;AAEA,SAAS,EACP,GACA,GACwB;CACxB,IAAI,CAAC,EAAS,CAAK,GACjB,OAAO;CAGT,IAAM,IAAK,OAAO,EAAM,MAAO,WAAW,EAAM,KAAK;CAMrD,OAJI,MAAO,EAAqC,KACvC,IAIP,EAAQ,MAAM,MAAW,EAAO,OAAO,CAAE,KACzC;AAEJ;AAEA,SAAS,EAAgC,GAAwB;CAS/D,OARI,MAAM,QAAQ,CAAK,KAInB,CAAC,EAAS,CAAK,IACV,EAAqC,OAGvC,OAAO,EAAM,QAAS,WACzB,EAAM,OACN,EAAqC;AAC3C;AAEA,SAAS,EAA0B,GAA0C;CAC3E,OAAO,EAAS,gBAAgB,QAAQ,EAAS,YAAY;AAC/D;AAEA,SAAS,EAAS,GAA4D;CAC5E,OAAO,OAAO,KAAU,cAAY;AACtC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/views/templates/TemplatesView.tsx"],"sourcesContent":["'use client';\n\nimport type { ChangeEvent, Key, ReactElement } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n Badge,\n Button,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n PageHeader,\n Section,\n SectionGroup,\n Select,\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 { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport styles from './templates.module.scss';\nimport { formatDateTime } from '../../lib/format-date-time';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport { useBPMRoutes } from '../../lib/routes-config';\nimport {\n ApprovalTemplateListStatus,\n ApprovalTemplateRecord,\n ApprovalTemplateCategoryRecord,\n activateApprovalTemplate,\n deactivateApprovalTemplate,\n listApprovalTemplateCategoriesPage,\n listApprovalTemplatesPage,\n} from '@rytass/bpm-core-client/template';\nimport { listLaunchableTemplates } from '@rytass/bpm-core-client/workflow';\n\nconst TEMPLATE_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst TEMPLATE_STATUS_TABS: readonly {\n readonly key: TemplateStatusTabKey;\n readonly label: string;\n}[] = [\n { key: 'ALL', label: '全部' },\n { key: 'PUBLISHED', label: '已發布' },\n { key: 'DRAFT', label: '草稿' },\n];\n\nconst TEMPLATE_CATEGORY_PAGE_SIZE = 100;\n\nexport interface TemplateCategoryOption {\n readonly categoryId: string | null;\n readonly id: string;\n readonly name: string;\n}\n\ntype TemplateStatusTabKey = 'ALL' | ApprovalTemplateListStatus;\n\ntype TemplateRow = Readonly<\n Record<string, unknown> &\n ApprovalTemplateRecord & {\n categoryLabel: string;\n key: string;\n status: ApprovalTemplateListStatus;\n }\n>;\n\nexport function TemplatesView(): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const [templates, setTemplates] = useState<readonly ApprovalTemplateRecord[]>(\n [],\n );\n const [categoryFilter, setCategoryFilter] = useState<TemplateCategoryOption>(\n UNCATEGORIZED_TEMPLATE_FILTER_OPTION,\n );\n const [categoryOptions, setCategoryOptions] = useState<\n readonly TemplateCategoryOption[]\n >([]);\n const [launchableTemplateIds, setLaunchableTemplateIds] = useState<\n ReadonlySet<string>\n >(new Set());\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [templatePage, setTemplatePage] = useState(1);\n const [templatePageSize, setTemplatePageSize] = useState(10);\n const [templateSearchText, setTemplateSearchText] = useState('');\n const [templateStatus, setTemplateStatus] =\n useState<TemplateStatusTabKey>('ALL');\n const [templateTotalCount, setTemplateTotalCount] = useState(0);\n const [activationPendingTemplateId, setActivationPendingTemplateId] =\n useState<string | null>(null);\n const refreshRequestIdRef = useRef(0);\n\n const refreshTemplates = useCallback(async (): Promise<void> => {\n const requestId = refreshRequestIdRef.current + 1;\n refreshRequestIdRef.current = requestId;\n setLoading(true);\n setError(null);\n setLaunchableTemplateIds(new Set());\n\n void listLaunchableTemplates()\n .then((nextLaunchableTemplates): void => {\n if (requestId !== refreshRequestIdRef.current) {\n return;\n }\n\n setLaunchableTemplateIds(\n new Set(nextLaunchableTemplates.map((template) => template.id)),\n );\n })\n .catch((): void => {\n if (requestId === refreshRequestIdRef.current) {\n setLaunchableTemplateIds(new Set());\n }\n });\n\n try {\n const [templatePageResult, activeCategoryPageResult] = await Promise.all([\n listApprovalTemplatesPage({\n categoryId: categoryFilter.categoryId,\n page: templatePage,\n pageSize: templatePageSize,\n searchText: templateSearchText,\n status: templateStatus === 'ALL' ? null : templateStatus,\n }),\n listApprovalTemplateCategoriesPage({\n page: 1,\n pageSize: TEMPLATE_CATEGORY_PAGE_SIZE,\n searchText: '',\n status: 'ACTIVE',\n }),\n ]);\n\n if (requestId !== refreshRequestIdRef.current) {\n return;\n }\n\n setCategoryOptions([\n ...activeCategoryPageResult.categories.map(readCategoryOption),\n ]);\n setTemplates(templatePageResult.templates);\n setTemplateTotalCount(templatePageResult.totalCount);\n } catch (requestError: unknown) {\n if (requestId === refreshRequestIdRef.current) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (requestId === refreshRequestIdRef.current) {\n setLoading(false);\n }\n }\n }, [\n categoryFilter,\n templatePage,\n templatePageSize,\n templateSearchText,\n templateStatus,\n ]);\n\n useEffect((): void => {\n void refreshTemplates();\n }, [refreshTemplates]);\n\n const toggleTemplateActivation = useCallback(\n async (template: ApprovalTemplateRecord): Promise<void> => {\n setActivationPendingTemplateId(template.id);\n setError(null);\n\n try {\n await (template.isActive\n ? deactivateApprovalTemplate(template.id)\n : activateApprovalTemplate(template.id));\n await refreshTemplates();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setActivationPendingTemplateId(null);\n }\n },\n [refreshTemplates],\n );\n\n const rows = useMemo(\n (): TemplateRow[] =>\n templates.map((template) => ({\n ...template,\n categoryLabel: readTemplateCategoryLabel(template),\n key: template.id,\n status: template.currentVersionId ? 'PUBLISHED' : 'DRAFT',\n updatedAt: formatDateTime(template.updatedAt),\n })),\n [templates],\n );\n const columns = useMemo(\n (): TableColumn<TemplateRow>[] => [\n { dataIndex: 'name', key: 'name', title: '模板名稱', width: 220 },\n {\n key: 'status',\n render: (record: TemplateRow): ReactElement => (\n <TemplateStatusBadge status={record.status} />\n ),\n title: '狀態',\n width: 120,\n },\n {\n key: 'isActive',\n render: (record: TemplateRow): ReactElement => (\n <TemplateActivationBadge isActive={record.isActive} />\n ),\n title: '服務狀態',\n width: 120,\n },\n {\n key: 'category',\n render: (record: TemplateRow): ReactElement => (\n <TemplateCategoryLabel record={record} />\n ),\n title: '分類',\n width: 160,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<TemplateRow> => ({\n render: (record): ReturnType<TableActions<TemplateRow>['render']> => [\n {\n disabled: (template): boolean =>\n !launchableTemplateIds.has(template.id),\n name: '發起',\n onClick: (): void => router.push(routes.caseNew(record.id)),\n variant: 'base-primary',\n },\n {\n name: '設計',\n onClick: (): void => router.push(routes.templateDesigner(record.id)),\n },\n {\n name: '版本',\n onClick: (): void => router.push(routes.templateVersions(record.id)),\n },\n {\n disabled: (template): boolean =>\n activationPendingTemplateId === template.id,\n name: record.isActive ? '停用' : '啟用',\n onClick: (template): void => {\n void toggleTemplateActivation(template);\n },\n variant: record.isActive ? 'destructive-secondary' : 'base-secondary',\n },\n ],\n variant: 'base-secondary',\n width: 264,\n }),\n [\n activationPendingTemplateId,\n launchableTemplateIds,\n router,\n toggleTemplateActivation,\n ],\n );\n\n return (\n <>\n <>\n <PageHeader>\n <ContentHeader\n description=\"建立流程模板、維護草稿與發布版本。\"\n title=\"簽核模板\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => router.push(routes.templateCompose())}\n variant=\"base-primary\"\n >\n 建立模板\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.templateFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"templateSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setTemplateSearchText(event.target.value);\n setTemplatePage(1);\n }}\n placeholder=\"關鍵字:搜尋模板名稱、分類或描述\"\n size=\"sub\"\n value={templateSearchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"templateCategoryFilter\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void => {\n setCategoryFilter(\n readCategoryFilterOption(option, categoryOptions),\n );\n setTemplatePage(1);\n }}\n options={[\n UNCATEGORIZED_TEMPLATE_FILTER_OPTION,\n ...categoryOptions,\n ]}\n placeholder=\"分類\"\n renderValue={(value): string =>\n `分類:${readTemplateCategoryFilterLabel(value)}`\n }\n size=\"sub\"\n value={categoryFilter}\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n tab={\n <Tab\n activeKey={templateStatus}\n onChange={(activeKey): void => {\n setTemplateStatus(readTemplateStatusTabKey(activeKey));\n setTemplatePage(1);\n }}\n >\n {TEMPLATE_STATUS_TABS.map((statusTab) => (\n <TabItem key={statusTab.key}>{statusTab.label}</TabItem>\n ))}\n </Tab>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n pagination={{\n current: templatePage,\n onChange: (page): void => {\n setTemplatePage(page);\n },\n onChangePageSize: (pageSize): void => {\n setTemplatePage(1);\n setTemplatePageSize(pageSize);\n },\n pageSize: templatePageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: TEMPLATE_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: templateTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n </>\n </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n\nfunction readTemplateStatusTabKey(activeKey: Key): TemplateStatusTabKey {\n if (activeKey === 'PUBLISHED' || activeKey === 'DRAFT') {\n return activeKey;\n }\n\n return 'ALL';\n}\n\nfunction TemplateStatusBadge({\n status,\n}: {\n readonly status: ApprovalTemplateListStatus;\n}): ReactElement {\n if (status === 'PUBLISHED') {\n return <Badge size=\"sub\" text=\"已發布\" variant=\"dot-success\" />;\n }\n\n return <Badge size=\"sub\" text=\"草稿\" variant=\"dot-inactive\" />;\n}\n\nfunction TemplateActivationBadge({\n isActive,\n}: {\n readonly isActive: boolean;\n}): ReactElement {\n if (isActive) {\n return <Badge size=\"sub\" text=\"啟用中\" variant=\"dot-success\" />;\n }\n\n return <Badge size=\"sub\" text=\"已停用\" variant=\"dot-inactive\" />;\n}\n\nfunction TemplateCategoryLabel({\n record,\n}: {\n readonly record: TemplateRow;\n}): ReactElement {\n if (record.categoryDetail?.isActive === false) {\n return (\n <Badge\n size=\"sub\"\n text={`${record.categoryLabel}(停用)`}\n variant=\"dot-inactive\"\n />\n );\n }\n\n return (\n <Typography component=\"span\" variant=\"body\">\n {record.categoryLabel}\n </Typography>\n );\n}\n\nconst UNCATEGORIZED_TEMPLATE_FILTER_OPTION: TemplateCategoryOption = {\n categoryId: null,\n id: 'ALL_CATEGORIES',\n name: '全部分類',\n};\n\nfunction readCategoryOption(\n category: ApprovalTemplateCategoryRecord,\n): TemplateCategoryOption {\n return {\n categoryId: category.id,\n id: category.id,\n name: category.name,\n };\n}\n\nfunction readCategoryFilterOption(\n value: unknown,\n options: readonly TemplateCategoryOption[],\n): TemplateCategoryOption {\n if (!isRecord(value)) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION;\n }\n\n const id = typeof value.id === 'string' ? value.id : null;\n\n if (id === UNCATEGORIZED_TEMPLATE_FILTER_OPTION.id) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION;\n }\n\n return (\n options.find((option) => option.id === id) ??\n UNCATEGORIZED_TEMPLATE_FILTER_OPTION\n );\n}\n\nfunction readTemplateCategoryFilterLabel(value: unknown): string {\n if (Array.isArray(value)) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION.name;\n }\n\n if (!isRecord(value)) {\n return UNCATEGORIZED_TEMPLATE_FILTER_OPTION.name;\n }\n\n return typeof value.name === 'string'\n ? value.name\n : UNCATEGORIZED_TEMPLATE_FILTER_OPTION.name;\n}\n\nfunction readTemplateCategoryLabel(template: ApprovalTemplateRecord): string {\n return template.categoryDetail?.name ?? template.category ?? '未分類';\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/chunk-CMqjfN_6.cjs"),t=require("../../../chunks/router-adapter--gYs13E8.cjs"),n=require("../../../chunks/format-date-time-XxBzF0F5.cjs"),r=require("../../../chunks/routes-config-fDVHmvXi.cjs");let i=require("react"),a=require("@mezzanine-ui/react"),o=require("react/jsx-runtime"),s=require("@mezzanine-ui/react/ContentHeader");s=e.t(s,1);let c=require("@rytass/bpm-core-client/template");function l({templateId:e}){let l=t.r(),d=r.r(),[f,p]=(0,i.useState)(null),[m,h]=(0,i.useState)(null),[g,_]=(0,i.useState)(!0),[v,y]=(0,i.useState)(!1);(0,i.useEffect)(()=>{C()},[e]);let b=(0,i.useMemo)(()=>(f?.versions??[]).map(e=>({formVersion:f?.formVersions.find(t=>t.id===e.formDefinitionVersionId)?.label??`未綁定`,key:e.id,publishedAt:n.t(e.publishedAt),status:e.status,updatedAt:n.t(e.updatedAt),version:`v${e.version}`,versionId:e.id})),[f]),x=(0,i.useMemo)(()=>[{dataIndex:`version`,key:`version`,title:`版本`,width:100},{dataIndex:`status`,key:`status`,title:`狀態`,width:140},{dataIndex:`formVersion`,key:`formVersion`,title:`表單版本`,width:220},{dataIndex:`publishedAt`,key:`publishedAt`,title:`發布時間`,width:200},{dataIndex:`updatedAt`,key:`updatedAt`,title:`更新時間`,width:200}],[]),S=(0,i.useMemo)(()=>({render:e=>[{disabled:()=>v||e.status===`DRAFT`,name:`Rollback`,onClick:()=>void w(e.versionId)}],variant:`base-secondary`,width:104}),[v]);async function C(){_(!0),h(null);try{p(await(0,c.readTemplateDesigner)(e))}catch(e){h(u(e))}finally{_(!1)}}async function w(e){y(!0),h(null);try{await(0,c.rollbackApprovalTemplateVersion)(e),await C()}catch(e){h(u(e))}finally{y(!1)}}return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(a.PageHeader,{children:(0,o.jsx)(s.default,{description:`查看發布、歸檔與 rollback 狀態。`,onBackClick:()=>l.push(d.templates()),title:f?.template.name??`模板版本`})}),(0,o.jsx)(a.SectionGroup,{children:(0,o.jsxs)(a.Section,{children:[m?(0,o.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:m}):null,(0,o.jsx)(a.Table,{actions:S,columns:x,dataSource:b,fullWidth:!0,loading:g})]})})]})}function u(e){return e instanceof Error?e.message:`發生未知錯誤`}exports.TemplateVersionsView=l;
1
+ "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/rolldown-runtime-BocRIvOZ.cjs"),t=require("../../../chunks/router-adapter--gYs13E8.cjs"),n=require("../../../chunks/format-date-time-D-cx5M8z.cjs"),r=require("../../../chunks/routes-config-fDVHmvXi.cjs");let i=require("react"),a=require("@mezzanine-ui/react"),o=require("react/jsx-runtime"),s=require("@mezzanine-ui/react/ContentHeader");s=e.t(s,1);let c=require("@rytass/bpm-core-client/template");function l({templateId:e}){let l=t.r(),d=r.r(),[f,p]=(0,i.useState)(null),[m,h]=(0,i.useState)(null),[g,_]=(0,i.useState)(!0),[v,y]=(0,i.useState)(!1);(0,i.useEffect)(()=>{C()},[e]);let b=(0,i.useMemo)(()=>(f?.versions??[]).map(e=>({formVersion:f?.formVersions.find(t=>t.id===e.formDefinitionVersionId)?.label??`未綁定`,key:e.id,publishedAt:n.t(e.publishedAt),status:e.status,updatedAt:n.t(e.updatedAt),version:`v${e.version}`,versionId:e.id})),[f]),x=(0,i.useMemo)(()=>[{dataIndex:`version`,key:`version`,title:`版本`,width:100},{dataIndex:`status`,key:`status`,title:`狀態`,width:140},{dataIndex:`formVersion`,key:`formVersion`,title:`表單版本`,width:220},{dataIndex:`publishedAt`,key:`publishedAt`,title:`發布時間`,width:200},{dataIndex:`updatedAt`,key:`updatedAt`,title:`更新時間`,width:200}],[]),S=(0,i.useMemo)(()=>({render:e=>[{disabled:()=>v||e.status===`DRAFT`,name:`Rollback`,onClick:()=>void w(e.versionId)}],variant:`base-secondary`,width:104}),[v]);async function C(){_(!0),h(null);try{p(await(0,c.readTemplateDesigner)(e))}catch(e){h(u(e))}finally{_(!1)}}async function w(e){y(!0),h(null);try{await(0,c.rollbackApprovalTemplateVersion)(e),await C()}catch(e){h(u(e))}finally{y(!1)}}return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(a.PageHeader,{children:(0,o.jsx)(s.default,{description:`查看發布、歸檔與 rollback 狀態。`,onBackClick:()=>l.push(d.templates()),title:f?.template.name??`模板版本`})}),(0,o.jsx)(a.SectionGroup,{children:(0,o.jsxs)(a.Section,{children:[m?(0,o.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:m}):null,(0,o.jsx)(a.Table,{actions:S,columns:x,dataSource:b,fullWidth:!0,loading:g})]})})]})}function u(e){return e instanceof Error?e.message:`發生未知錯誤`}exports.TemplateVersionsView=l;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../../../src/views/templates/versions/TemplateVersionsView.tsx"],"sourcesContent":["'use client';\n\nimport { ReactElement, useEffect, useMemo, useState } from 'react';\nimport {\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { useRouterAdapter } from '../../../lib/router-adapter';\nimport { useBPMRoutes } from '../../../lib/routes-config';\nimport {\n readTemplateDesigner,\n rollbackApprovalTemplateVersion,\n TemplateDesignerRecord,\n} from '@rytass/bpm-core-client/template';\nimport { formatDateTime } from '../../../lib/format-date-time';\n\ntype VersionRow = Readonly<\n Record<string, unknown> & {\n formVersion: string;\n key: string;\n publishedAt: string;\n status: string;\n updatedAt: string;\n version: string;\n versionId: string;\n }\n>;\n\nexport interface TemplateVersionsViewProps {\n readonly templateId: string;\n}\n\nexport function TemplateVersionsView({\n templateId,\n}: TemplateVersionsViewProps): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const [record, setRecord] = useState<TemplateDesignerRecord | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [rollingBack, setRollingBack] = useState(false);\n\n useEffect((): void => {\n void refreshVersions();\n }, [templateId]);\n\n const rows = useMemo(\n (): VersionRow[] =>\n (record?.versions ?? []).map((version) => ({\n formVersion:\n record?.formVersions.find(\n (formVersion) => formVersion.id === version.formDefinitionVersionId,\n )?.label ?? '未綁定',\n key: version.id,\n publishedAt: formatDateTime(version.publishedAt),\n status: version.status,\n updatedAt: formatDateTime(version.updatedAt),\n version: `v${version.version}`,\n versionId: version.id,\n })),\n [record],\n );\n const columns = useMemo(\n (): TableColumn<VersionRow>[] => [\n { dataIndex: 'version', key: 'version', title: '版本', width: 100 },\n { dataIndex: 'status', key: 'status', title: '狀態', width: 140 },\n {\n dataIndex: 'formVersion',\n key: 'formVersion',\n title: '表單版本',\n width: 220,\n },\n {\n dataIndex: 'publishedAt',\n key: 'publishedAt',\n title: '發布時間',\n width: 200,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 200,\n },\n ],\n [],\n );\n const actions = useMemo(\n (): TableActions<VersionRow> => ({\n render: (row): ReturnType<TableActions<VersionRow>['render']> => [\n {\n disabled: (): boolean => rollingBack || row.status === 'DRAFT',\n name: 'Rollback',\n onClick: (): void => void handleRollback(row.versionId),\n },\n ],\n variant: 'base-secondary',\n width: 104,\n }),\n [rollingBack],\n );\n\n async function refreshVersions(): Promise<void> {\n setLoading(true);\n setError(null);\n\n try {\n setRecord(await readTemplateDesigner(templateId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function handleRollback(versionId: string): Promise<void> {\n setRollingBack(true);\n setError(null);\n\n try {\n await rollbackApprovalTemplateVersion(versionId);\n await refreshVersions();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setRollingBack(false);\n }\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"查看發布、歸檔與 rollback 狀態。\"\n onBackClick={(): void => router.push(routes.templates())}\n title={record?.template.name ?? '模板版本'}\n />\n </PageHeader>\n\n <SectionGroup>\n <Section>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={actions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n />\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"qfAqCA,SAAgB,EAAqB,CACnC,cAC0C,CAC1C,IAAM,EAAS,EAAA,EAAiB,EAC1B,EAAS,EAAA,EAAa,EACtB,CAAC,EAAQ,IAAA,EAAA,EAAA,UAAqD,IAAI,EAClE,CAAC,EAAO,IAAA,EAAA,EAAA,UAAoC,IAAI,EAChD,CAAC,EAAS,IAAA,EAAA,EAAA,UAAuB,EAAI,EACrC,CAAC,EAAa,IAAA,EAAA,EAAA,UAA2B,EAAK,GAEpD,EAAA,EAAA,eAAsB,CACpB,EAAqB,CACvB,EAAG,CAAC,CAAU,CAAC,EAEf,IAAM,GAAA,EAAA,EAAA,cAED,GAAQ,UAAY,CAAC,GAAG,IAAK,IAAa,CACzC,YACE,GAAQ,aAAa,KAClB,GAAgB,EAAY,KAAO,EAAQ,uBAC9C,GAAG,OAAS,MACd,IAAK,EAAQ,GACb,YAAa,EAAA,EAAe,EAAQ,WAAW,EAC/C,OAAQ,EAAQ,OAChB,UAAW,EAAA,EAAe,EAAQ,SAAS,EAC3C,QAAS,IAAI,EAAQ,UACrB,UAAW,EAAQ,EACrB,EAAE,EACJ,CAAC,CAAM,CACT,EACM,GAAA,EAAA,EAAA,aAC6B,CAC/B,CAAE,UAAW,UAAW,IAAK,UAAW,MAAO,KAAM,MAAO,GAAI,EAChE,CAAE,UAAW,SAAU,IAAK,SAAU,MAAO,KAAM,MAAO,GAAI,EAC9D,CACE,UAAW,cACX,IAAK,cACL,MAAO,OACP,MAAO,GACT,EACA,CACE,UAAW,cACX,IAAK,cACL,MAAO,OACP,MAAO,GACT,EACA,CACE,UAAW,YACX,IAAK,YACL,MAAO,OACP,MAAO,GACT,CACF,EACA,CAAC,CACH,EACM,GAAA,EAAA,EAAA,cAC6B,CAC/B,OAAS,GAAwD,CAC/D,CACE,aAAyB,GAAe,EAAI,SAAW,QACvD,KAAM,WACN,YAAqB,KAAK,EAAe,EAAI,SAAS,CACxD,CACF,EACA,QAAS,iBACT,MAAO,GACT,GACA,CAAC,CAAW,CACd,EAEA,eAAe,GAAiC,CAC9C,EAAW,EAAI,EACf,EAAS,IAAI,EAEb,GAAI,CACF,EAAU,MAAA,EAAA,EAAA,sBAA2B,CAAU,CAAC,CAClD,OAAS,EAAuB,CAC9B,EAAS,EAAiB,CAAY,CAAC,CACzC,QAAU,CACR,EAAW,EAAK,CAClB,CACF,CAEA,eAAe,EAAe,EAAkC,CAC9D,EAAe,EAAI,EACnB,EAAS,IAAI,EAEb,GAAI,CACF,MAAA,EAAA,EAAA,iCAAsC,CAAS,EAC/C,MAAM,EAAgB,CACxB,OAAS,EAAuB,CAC9B,EAAS,EAAiB,CAAY,CAAC,CACzC,QAAU,CACR,EAAe,EAAK,CACtB,CACF,CAEA,OACE,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,EACI,EAAA,EAAA,KAAC,EAAA,WAAD,CAAA,UACE,EAAA,EAAA,KAAC,EAAA,QAAD,CACE,YAAY,wBACZ,gBAAyB,EAAO,KAAK,EAAO,UAAU,CAAC,EACvD,MAAO,GAAQ,SAAS,MAAQ,MACjC,CAAA,CACS,CAAA,GAEZ,EAAA,EAAA,KAAC,EAAA,aAAD,CAAA,UACE,EAAA,EAAA,MAAC,EAAA,QAAD,CAAA,SAAA,CACG,GACC,EAAA,EAAA,KAAC,EAAA,WAAD,CAAY,MAAM,aAAa,QAAQ,gBACpC,CACS,CAAA,EACV,MACJ,EAAA,EAAA,KAAC,EAAA,MAAD,CACW,UACA,UACT,WAAY,EACZ,UAAA,GACS,SACV,CAAA,CACM,CAAA,CAAA,CACG,CAAA,CACd,CAAA,CAAA,CAER,CAEA,SAAS,EAAiB,EAAwB,CAChD,OAAO,aAAiB,MAAQ,EAAM,QAAU,QAClD"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../../../src/views/templates/versions/TemplateVersionsView.tsx"],"sourcesContent":["'use client';\n\nimport { ReactElement, useEffect, useMemo, useState } from 'react';\nimport {\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { useRouterAdapter } from '../../../lib/router-adapter';\nimport { useBPMRoutes } from '../../../lib/routes-config';\nimport {\n readTemplateDesigner,\n rollbackApprovalTemplateVersion,\n TemplateDesignerRecord,\n} from '@rytass/bpm-core-client/template';\nimport { formatDateTime } from '../../../lib/format-date-time';\n\ntype VersionRow = Readonly<\n Record<string, unknown> & {\n formVersion: string;\n key: string;\n publishedAt: string;\n status: string;\n updatedAt: string;\n version: string;\n versionId: string;\n }\n>;\n\nexport interface TemplateVersionsViewProps {\n readonly templateId: string;\n}\n\nexport function TemplateVersionsView({\n templateId,\n}: TemplateVersionsViewProps): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const [record, setRecord] = useState<TemplateDesignerRecord | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [rollingBack, setRollingBack] = useState(false);\n\n useEffect((): void => {\n void refreshVersions();\n }, [templateId]);\n\n const rows = useMemo(\n (): VersionRow[] =>\n (record?.versions ?? []).map((version) => ({\n formVersion:\n record?.formVersions.find(\n (formVersion) => formVersion.id === version.formDefinitionVersionId,\n )?.label ?? '未綁定',\n key: version.id,\n publishedAt: formatDateTime(version.publishedAt),\n status: version.status,\n updatedAt: formatDateTime(version.updatedAt),\n version: `v${version.version}`,\n versionId: version.id,\n })),\n [record],\n );\n const columns = useMemo(\n (): TableColumn<VersionRow>[] => [\n { dataIndex: 'version', key: 'version', title: '版本', width: 100 },\n { dataIndex: 'status', key: 'status', title: '狀態', width: 140 },\n {\n dataIndex: 'formVersion',\n key: 'formVersion',\n title: '表單版本',\n width: 220,\n },\n {\n dataIndex: 'publishedAt',\n key: 'publishedAt',\n title: '發布時間',\n width: 200,\n },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 200,\n },\n ],\n [],\n );\n const actions = useMemo(\n (): TableActions<VersionRow> => ({\n render: (row): ReturnType<TableActions<VersionRow>['render']> => [\n {\n disabled: (): boolean => rollingBack || row.status === 'DRAFT',\n name: 'Rollback',\n onClick: (): void => void handleRollback(row.versionId),\n },\n ],\n variant: 'base-secondary',\n width: 104,\n }),\n [rollingBack],\n );\n\n async function refreshVersions(): Promise<void> {\n setLoading(true);\n setError(null);\n\n try {\n setRecord(await readTemplateDesigner(templateId));\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n async function handleRollback(versionId: string): Promise<void> {\n setRollingBack(true);\n setError(null);\n\n try {\n await rollbackApprovalTemplateVersion(versionId);\n await refreshVersions();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setRollingBack(false);\n }\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"查看發布、歸檔與 rollback 狀態。\"\n onBackClick={(): void => router.push(routes.templates())}\n title={record?.template.name ?? '模板版本'}\n />\n </PageHeader>\n\n <SectionGroup>\n <Section>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={actions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n />\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}