@rytass/bpm-core-react 0.11.0 → 0.13.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 (64) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/chunks/FormBuilderView-CLFlfDGe.cjs +3 -0
  3. package/dist/chunks/FormBuilderView-CLFlfDGe.cjs.map +1 -0
  4. package/dist/chunks/FormBuilderView-D4xIuPYB.js +1960 -0
  5. package/dist/chunks/FormBuilderView-D4xIuPYB.js.map +1 -0
  6. package/dist/chunks/FormRendererView-BxGT16z0.cjs +2 -0
  7. package/dist/chunks/FormRendererView-BxGT16z0.cjs.map +1 -0
  8. package/dist/chunks/FormRendererView-DUceSOXe.js +798 -0
  9. package/dist/chunks/FormRendererView-DUceSOXe.js.map +1 -0
  10. package/dist/chunks/{compose-CUOe5Ia9.js → compose-Bb-REfoB.js} +4 -4
  11. package/dist/chunks/{compose-CUOe5Ia9.js.map → compose-Bb-REfoB.js.map} +1 -1
  12. package/dist/chunks/{compose-CyRkXdeu.cjs → compose-DzRYZcqe.cjs} +2 -2
  13. package/dist/chunks/{compose-CyRkXdeu.cjs.map → compose-DzRYZcqe.cjs.map} +1 -1
  14. package/dist/chunks/{designer-Cb3WAC46.js → designer-C6oIO9Kq.js} +2 -2
  15. package/dist/chunks/{designer-Cb3WAC46.js.map → designer-C6oIO9Kq.js.map} +1 -1
  16. package/dist/chunks/{designer-zLliyrHu.cjs → designer-gFUdImeZ.cjs} +2 -2
  17. package/dist/chunks/{designer-zLliyrHu.cjs.map → designer-gFUdImeZ.cjs.map} +1 -1
  18. package/dist/chunks/{detail-Cmw-aQcu.js → detail-BgKgMvYx.js} +391 -390
  19. package/dist/chunks/{detail-Cmw-aQcu.js.map → detail-BgKgMvYx.js.map} +1 -1
  20. package/dist/chunks/{detail-Bp2Nv0cs.cjs → detail-Dnz5aaI-.cjs} +2 -2
  21. package/dist/chunks/{detail-Bp2Nv0cs.cjs.map → detail-Dnz5aaI-.cjs.map} +1 -1
  22. package/dist/chunks/orgs-Bz8hBMoQ.cjs +2 -0
  23. package/dist/chunks/orgs-Bz8hBMoQ.cjs.map +1 -0
  24. package/dist/chunks/{orgs-B930facb.js → orgs-Cr_7zsAD.js} +343 -329
  25. package/dist/chunks/orgs-Cr_7zsAD.js.map +1 -0
  26. package/dist/pages/admin/orgs/index.cjs +1 -1
  27. package/dist/pages/admin/orgs/index.js +1 -1
  28. package/dist/pages/instances/detail/index.cjs +1 -1
  29. package/dist/pages/instances/detail/index.js +1 -1
  30. package/dist/pages/templates/compose/index.cjs +1 -1
  31. package/dist/pages/templates/compose/index.js +1 -1
  32. package/dist/pages/templates/designer/index.cjs +1 -1
  33. package/dist/pages/templates/designer/index.js +1 -1
  34. package/dist/views/admin/index.cjs +1 -1
  35. package/dist/views/admin/index.js +1 -1
  36. package/dist/views/admin/orgs/index.cjs +1 -1
  37. package/dist/views/admin/orgs/index.js +1 -1
  38. package/dist/views/forms/builder/index.cjs +1 -1
  39. package/dist/views/forms/builder/index.js +1 -1
  40. package/dist/views/forms/renderer/form-data-source-field.d.ts +16 -0
  41. package/dist/views/forms/renderer/index.cjs +1 -1
  42. package/dist/views/forms/renderer/index.js +1 -1
  43. package/dist/views/instances/detail/index.cjs +1 -1
  44. package/dist/views/instances/detail/index.js +1 -1
  45. package/dist/views/instances/new/index.cjs +1 -1
  46. package/dist/views/instances/new/index.cjs.map +1 -1
  47. package/dist/views/instances/new/index.js +48 -48
  48. package/dist/views/instances/new/index.js.map +1 -1
  49. package/dist/views/templates/compose/index.cjs +1 -1
  50. package/dist/views/templates/compose/index.js +1 -1
  51. package/dist/views/templates/designer/index.cjs +1 -1
  52. package/dist/views/templates/designer/index.js +1 -1
  53. package/package.json +3 -3
  54. package/dist/chunks/FormBuilderView-CAqjOYAP.cjs +0 -3
  55. package/dist/chunks/FormBuilderView-CAqjOYAP.cjs.map +0 -1
  56. package/dist/chunks/FormBuilderView-TzSezeqC.js +0 -1479
  57. package/dist/chunks/FormBuilderView-TzSezeqC.js.map +0 -1
  58. package/dist/chunks/FormRendererView-BurlEDUu.js +0 -580
  59. package/dist/chunks/FormRendererView-BurlEDUu.js.map +0 -1
  60. package/dist/chunks/FormRendererView-Dde1s3I0.cjs +0 -2
  61. package/dist/chunks/FormRendererView-Dde1s3I0.cjs.map +0 -1
  62. package/dist/chunks/orgs-B930facb.js.map +0 -1
  63. package/dist/chunks/orgs-BefGgeyc.cjs +0 -2
  64. package/dist/chunks/orgs-BefGgeyc.cjs.map +0 -1
@@ -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 buildFormRendererValues,\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 // What the renderer shows, not just what has been touched: a table seeds\n // its `minRows` rows and a field can carry a `defaultValue`, and neither\n // reaches this state until the filler edits something. Validating and\n // submitting the raw state would reject a table the user can plainly see\n // rows in — and submit a default the backend never receives.\n const submittedValues = buildFormRendererValues(\n context.formVersion.schema.fields,\n formValues,\n );\n const validation = validateFormRendererValues({\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n values: submittedValues,\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: submittedValues,\n initiatorMemberId: currentMemberId,\n templateId: context.template.id,\n title: readFormDataCaseTitle({\n fallbackTitle: context.template.name,\n formData: submittedValues,\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,27 +3,27 @@ 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-BurlEDUu.js";
7
- import { Suspense as o, useCallback as s, useEffect as c, useMemo as l, useState as u } from "react";
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
- import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
10
- import { listLaunchableTemplates as b, readFormDataCaseTitle as x, readLaunchContext as S, submitApprovalInstance as C, uploadAttachment as w } from "@rytass/bpm-core-client/workflow";
11
- import T from "@mezzanine-ui/react/ContentHeader";
12
- import { CheckedIcon as E } from "@mezzanine-ui/icons";
13
- import { focusFormRendererField as D, readFormDataSourceErrorMessage as O, validateFormRendererValues as k } from "@rytass/bpm-core-client/form";
6
+ import { i, t as a } from "../../../chunks/FormRendererView-DUceSOXe.js";
7
+ import { Suspense as o, useCallback as ee, useEffect as s, useMemo as c, useState as l } from "react";
8
+ import { Button as u, PageHeader as d, Section as f, SectionGroup as p, Table as m, Typography as h } from "@mezzanine-ui/react";
9
+ import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
10
+ import { listLaunchableTemplates as y, readFormDataCaseTitle as b, readLaunchContext as x, submitApprovalInstance as S, uploadAttachment as C } from "@rytass/bpm-core-client/workflow";
11
+ import w from "@mezzanine-ui/react/ContentHeader";
12
+ import { CheckedIcon as T } from "@mezzanine-ui/icons";
13
+ import { buildFormRendererValues as E, focusFormRendererField as D, readFormDataSourceErrorMessage as O, validateFormRendererValues as k } from "@rytass/bpm-core-client/form";
14
14
  //#region src/views/instances/new/InstanceNewView.tsx
15
15
  var A = {
16
16
  display: "grid",
17
17
  gap: 16
18
18
  };
19
19
  function j(e = {}) {
20
- return /* @__PURE__ */ v(o, {
21
- fallback: /* @__PURE__ */ v(N, {}),
22
- children: /* @__PURE__ */ v(M, { templateId: e.templateId ?? void 0 })
20
+ return /* @__PURE__ */ _(o, {
21
+ fallback: /* @__PURE__ */ _(N, {}),
22
+ children: /* @__PURE__ */ _(M, { templateId: e.templateId ?? void 0 })
23
23
  });
24
24
  }
25
25
  function M({ templateId: o }) {
26
- let O = e(), j = r(), { member: M } = t(), N = M?.memberId ?? null, F = o ?? null, [I, L] = u(null), [R, z] = u({}), [B, V] = u([]), [H, U] = u(null), [W, G] = u({}), [K, q] = u(!0), [J, Y] = u(!1), [X, Z] = u({}), Q = s((e, t) => {
26
+ let O = e(), j = r(), { member: M } = t(), N = M?.memberId ?? null, F = o ?? null, [I, L] = l(null), [R, z] = l({}), [B, V] = l([]), [H, U] = l(null), [W, G] = l({}), [K, q] = l(!0), [J, Y] = l(!1), [X, Z] = l({}), Q = ee((e, t) => {
27
27
  Z((n) => {
28
28
  let r = n[e];
29
29
  return r?.hasValue === t.hasValue && r.status === t.status ? n : {
@@ -35,19 +35,19 @@ function M({ templateId: o }) {
35
35
  };
36
36
  });
37
37
  }, []);
38
- c(() => {
38
+ s(() => {
39
39
  if (!F) {
40
- ne();
40
+ re();
41
41
  return;
42
42
  }
43
- re(F);
43
+ ie(F);
44
44
  }, [F]);
45
- let $ = l(() => B.map((e) => ({
45
+ let $ = c(() => B.map((e) => ({
46
46
  ...e,
47
47
  key: e.id,
48
48
  updatedAt: n(e.updatedAt),
49
49
  versionLabel: `v${e.version}`
50
- })), [B]), ee = l(() => [
50
+ })), [B]), te = c(() => [
51
51
  {
52
52
  dataIndex: "name",
53
53
  key: "name",
@@ -66,7 +66,7 @@ function M({ templateId: o }) {
66
66
  title: "更新時間",
67
67
  width: 220
68
68
  }
69
- ], []), te = l(() => ({
69
+ ], []), ne = c(() => ({
70
70
  render: (e) => [{
71
71
  name: "發起",
72
72
  onClick: () => O.push(j.caseNew(e.id)),
@@ -75,27 +75,27 @@ function M({ templateId: o }) {
75
75
  variant: "base-secondary",
76
76
  width: 88
77
77
  }), [O]);
78
- async function ne() {
78
+ async function re() {
79
79
  q(!0), U(null), L(null), Z({});
80
80
  try {
81
- V(await b());
81
+ V(await y());
82
82
  } catch (e) {
83
83
  U(P(e));
84
84
  } finally {
85
85
  q(!1);
86
86
  }
87
87
  }
88
- async function re(e) {
88
+ async function ie(e) {
89
89
  q(!0), U(null), V([]), Z({});
90
90
  try {
91
- L(await S(e));
91
+ L(await x(e));
92
92
  } catch (e) {
93
93
  U(P(e));
94
94
  } finally {
95
95
  q(!1);
96
96
  }
97
97
  }
98
- async function ie() {
98
+ async function ae() {
99
99
  if (!I || !N) return;
100
100
  Y(!0), U(null), G({});
101
101
  let e = i(Object.values(X));
@@ -103,23 +103,23 @@ function M({ templateId: o }) {
103
103
  U(e), Y(!1);
104
104
  return;
105
105
  }
106
- let t = k({
106
+ let t = E(I.formVersion.schema.fields, R), n = k({
107
107
  schema: I.formVersion.schema,
108
108
  uiSchema: I.formVersion.uiSchema,
109
- values: R
109
+ values: t
110
110
  });
111
- if (!t.valid) {
112
- G(t.errors), U("請先補齊必填欄位。"), t.firstInvalidFieldKey && D(t.firstInvalidFieldKey), Y(!1);
111
+ if (!n.valid) {
112
+ G(n.errors), U("請先補齊必填欄位。"), n.firstInvalidFieldKey && D(n.firstInvalidFieldKey), Y(!1);
113
113
  return;
114
114
  }
115
115
  try {
116
- let e = await C({
117
- formData: R,
116
+ let e = await S({
117
+ formData: t,
118
118
  initiatorMemberId: N,
119
119
  templateId: I.template.id,
120
- title: x({
120
+ title: b({
121
121
  fallbackTitle: I.template.name,
122
- formData: R,
122
+ formData: t,
123
123
  schema: I.formVersion.schema,
124
124
  uiSchema: I.formVersion.uiSchema
125
125
  })
@@ -131,38 +131,38 @@ function M({ templateId: o }) {
131
131
  Y(!1);
132
132
  }
133
133
  }
134
- async function ae(e, t) {
134
+ async function oe(e, t) {
135
135
  if (!N) throw Error("尚未登入,無法上傳附件");
136
- return { id: (await w({
136
+ return { id: (await C({
137
137
  file: t,
138
138
  formFieldPath: `form.${e.fieldKey}`
139
139
  })).id };
140
140
  }
141
- return /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v(f, { children: /* @__PURE__ */ v(T, {
141
+ return /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(d, { children: /* @__PURE__ */ _(w, {
142
142
  description: I ? `${I.template.name} · 表單 v${I.formVersion.version}` : "選擇可發起的已發布模板後填寫表單內容。",
143
143
  title: "發起簽核",
144
- children: I ? /* @__PURE__ */ v(d, {
144
+ children: I ? /* @__PURE__ */ _(u, {
145
145
  disabled: K || J,
146
- icon: E,
146
+ icon: T,
147
147
  iconType: "leading",
148
- onClick: ie,
148
+ onClick: ae,
149
149
  variant: "base-primary",
150
150
  children: "送出"
151
151
  }) : null
152
- }) }), /* @__PURE__ */ v(m, { children: /* @__PURE__ */ v(p, { children: /* @__PURE__ */ y("div", {
152
+ }) }), /* @__PURE__ */ _(p, { children: /* @__PURE__ */ _(f, { children: /* @__PURE__ */ v("div", {
153
153
  style: A,
154
154
  children: [
155
- H ? /* @__PURE__ */ v(g, {
155
+ H ? /* @__PURE__ */ _(h, {
156
156
  color: "text-error",
157
157
  variant: "body",
158
158
  children: H
159
159
  }) : null,
160
- K ? /* @__PURE__ */ v(g, {
160
+ K ? /* @__PURE__ */ _(h, {
161
161
  color: "text-neutral",
162
162
  variant: "body",
163
163
  children: "載入中..."
164
164
  }) : null,
165
- I ? /* @__PURE__ */ v(a, {
165
+ I ? /* @__PURE__ */ _(a, {
166
166
  dataSourceContext: {
167
167
  kind: "runtime",
168
168
  templateId: I.template.id
@@ -173,18 +173,18 @@ function M({ templateId: o }) {
173
173
  z(e), G({});
174
174
  },
175
175
  onDataSourceStateChange: Q,
176
- onUploadAttachment: ae,
176
+ onUploadAttachment: oe,
177
177
  schema: I.formVersion.schema,
178
178
  singleColumn: !0,
179
179
  uiSchema: I.formVersion.uiSchema,
180
180
  value: R
181
181
  }) : null,
182
- !F && !K ? $.length > 0 ? /* @__PURE__ */ v(h, {
183
- actions: te,
184
- columns: ee,
182
+ !F && !K ? $.length > 0 ? /* @__PURE__ */ _(m, {
183
+ actions: ne,
184
+ columns: te,
185
185
  dataSource: $,
186
186
  fullWidth: !0
187
- }) : /* @__PURE__ */ v(g, {
187
+ }) : /* @__PURE__ */ _(h, {
188
188
  color: "text-neutral",
189
189
  variant: "body",
190
190
  children: "目前沒有可發起的已發布模板。"
@@ -193,10 +193,10 @@ function M({ templateId: o }) {
193
193
  }) }) })] });
194
194
  }
195
195
  function N() {
196
- return /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v(f, { children: /* @__PURE__ */ v(T, {
196
+ return /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(d, { children: /* @__PURE__ */ _(w, {
197
197
  description: "選擇可發起的已發布模板後填寫表單內容。",
198
198
  title: "發起簽核"
199
- }) }), /* @__PURE__ */ v(m, { children: /* @__PURE__ */ v(p, { children: /* @__PURE__ */ v(g, {
199
+ }) }), /* @__PURE__ */ _(p, { children: /* @__PURE__ */ _(f, { children: /* @__PURE__ */ _(h, {
200
200
  color: "text-neutral",
201
201
  variant: "body",
202
202
  children: "載入中..."
@@ -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 buildFormRendererValues,\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 // What the renderer shows, not just what has been touched: a table seeds\n // its `minRows` rows and a field can carry a `defaultValue`, and neither\n // reaches this state until the filler edits something. Validating and\n // submitting the raw state would reject a table the user can plainly see\n // rows in — and submit a default the backend never receives.\n const submittedValues = buildFormRendererValues(\n context.formVersion.schema.fields,\n formValues,\n );\n const validation = validateFormRendererValues({\n schema: context.formVersion.schema,\n uiSchema: context.formVersion.uiSchema,\n values: submittedValues,\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: submittedValues,\n initiatorMemberId: currentMemberId,\n templateId: context.template.id,\n title: readFormDataCaseTitle({\n fallbackTitle: context.template.name,\n formData: submittedValues,\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 +1 @@
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
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/compose-DzRYZcqe.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-CUOe5Ia9.js";
1
+ import { i as e, n as t, r as n, t as r } from "../../../chunks/compose-Bb-REfoB.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-zLliyrHu.cjs");exports.TemplateDesignerView=e.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/designer-gFUdImeZ.cjs");exports.TemplateDesignerView=e.t;
@@ -1,2 +1,2 @@
1
- import { t as e } from "../../../chunks/designer-Cb3WAC46.js";
1
+ import { t as e } from "../../../chunks/designer-C6oIO9Kq.js";
2
2
  export { e as TemplateDesignerView };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rytass/bpm-core-react",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "BPM approval workflow React components and views for the Rytass BPM stack. Ships AuthProvider, NotificationDrawer + bell widget, host-facing hooks (useBPMMember / useBPMLogout / useBPMRoutes), and full page-body views for inbox / instances / templates / forms / admin / settings on top of Mezzanine UI and the BPM client functions. The host owns the navigation shell — BPM does not bundle a layout.",
5
5
  "keywords": [
6
6
  "bpm",
@@ -286,8 +286,8 @@
286
286
  "@mezzanine-ui/core": ">=1.0.0",
287
287
  "@mezzanine-ui/icons": ">=1.0.0",
288
288
  "@mezzanine-ui/react": ">=1.0.0",
289
- "@rytass/bpm-core-client": "^0.11.0",
290
- "@rytass/bpm-core-shared": "^0.11.0",
289
+ "@rytass/bpm-core-client": "^0.13.0",
290
+ "@rytass/bpm-core-shared": "^0.13.0",
291
291
  "@uiw/react-codemirror": ">=4.0.0",
292
292
  "@xyflow/react": ">=12.0.0",
293
293
  "ai": ">=6.0.0",
@@ -1,3 +0,0 @@
1
- "use client";const e=require("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./bpm-form-field-Bc6k4ZEO.cjs"),n=require("./FormRendererView-Dde1s3I0.cjs");let r=require("react"),i=require("@mezzanine-ui/react"),a=require("react/jsx-runtime"),o=require("@mezzanine-ui/icons"),s=require("@rytass/bpm-core-client/form"),c=require("@rytass/bpm-core-shared/form"),l=require("@hello-pangea/dnd"),u=require("next/dynamic");u=e.t(u,1);let d=require("@codemirror/lang-json"),f=require("@codemirror/view");var p={alignItems:`center`,border:`1px solid var(--mzn-color-border-neutral)`,borderRadius:4,color:`var(--mzn-color-text-neutral)`,display:`flex`,minHeight:160,padding:12,width:`100%`},m=[(0,d.json)(),f.EditorView.lineWrapping,f.EditorView.theme({"&":{border:`1px solid var(--mzn-color-border-neutral)`,borderRadius:`4px`,fontSize:`13px`,width:`100%`},"&.cm-focused":{outline:`1px solid var(--mzn-color-border-primary)`},".cm-content":{fontFamily:`ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace`,minHeight:`100%`},".cm-editor":{width:`100%`},".cm-gutters":{borderRight:`1px solid var(--mzn-color-border-neutral)`},".cm-scroller":{fontFamily:`ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace`}})],h=(0,u.default)(()=>import(`@uiw/react-codemirror`),{loading:()=>(0,a.jsx)(`div`,{style:p,children:`載入 JSON 編輯器`}),ssr:!1});function ee({disabled:e=!1,height:t,name:n,onChange:r,placeholder:i,value:o}){return(0,a.jsx)(h,{"aria-label":n,basicSetup:{autocompletion:!0,bracketMatching:!0,closeBrackets:!0,defaultKeymap:!0,foldGutter:!0,highlightActiveLine:!0,highlightSelectionMatches:!0,lineNumbers:!0,syntaxHighlighting:!0},editable:!e,extensions:[...m],height:t,indentWithTab:!1,onChange:r,placeholder:i,readOnly:e,theme:`light`,value:o,width:`100%`})}var g=[{description:`單行文字、姓名、編號`,icon:o.AlignLeftIcon,label:`文字`,type:`text`},{description:`多行補充內容`,icon:o.FileIcon,label:`長文字`,type:`textarea`},{description:`金額、數量、分數`,icon:o.CurrencyDollarIcon,label:`數字`,type:`number`},{description:`金額與費用`,icon:o.CurrencyDollarIcon,label:`金額`,type:`money`},{description:`日期或到期日`,icon:o.CalendarIcon,label:`日期`,type:`date`},{description:`日期與時間`,icon:o.CalendarIcon,label:`日期時間`,type:`datetime`},{description:`是 / 否狀態`,icon:o.CheckedIcon,label:`開關`,type:`boolean`},{description:`固定選項擇一`,icon:o.ListIcon,label:`下拉選單`,type:`select`},{description:`可搜尋的固定選項`,icon:o.ListIcon,label:`自動完成`,type:`autocomplete`},{description:`固定選項單選`,icon:o.DotGridIcon,label:`單選`,type:`radio`},{description:`固定選項複選`,icon:o.CheckedOutlineIcon,label:`複選`,type:`checkbox`},{description:`附件或佐證資料`,icon:o.FileAttachmentIcon,label:`附件`,type:`file_upload`}],te={alignItems:`start`,display:`flex`,flexWrap:`wrap`,gap:16},ne={flex:`0.55 1 300px`,minWidth:0},re={flex:`1.45 1 720px`,minWidth:620},_={display:`grid`,gap:12},ie={display:`flex`,flexWrap:`wrap`,gap:6},ae={flex:`0 0 auto`,whiteSpace:`nowrap`},oe={display:`grid`,gap:8},se={alignItems:`center`,cursor:`grab`,display:`flex`,gap:12,touchAction:`none`},ce={display:`grid`,flex:`1 1 auto`,gap:2,minWidth:0},le={alignItems:`center`,display:`flex`,flex:`0 0 auto`,gap:4},ue={alignItems:`center`,display:`flex`,gap:6},de={cursor:`pointer`,userSelect:`none`},fe={filter:`drop-shadow(0 8px 18px rgba(0, 0, 0, 0.12))`},pe={backgroundColor:`color-mix(in srgb, var(--mzn-color-primary) 8%, var(--mzn-color-bg-surface))`,boxShadow:`inset 0 0 0 1px var(--mzn-color-border-primary)`},me={alignItems:`center`,border:`1px dashed var(--mzn-color-border-neutral)`,borderRadius:6,display:`grid`,gap:12,minHeight:240,padding:32,textAlign:`center`},he={display:`flex`,gap:8,justifyContent:`center`},ge={display:`grid`,gap:14},_e={display:`grid`,columnGap:16,gridTemplateColumns:`repeat(auto-fit, minmax(280px, 1fr))`,rowGap:8},ve={gridColumn:`1 / -1`},ye={alignItems:`center`,display:`flex`,gap:8,gridColumn:`1 / -1`,justifyContent:`flex-end`},be={gridColumn:`1 / -1`},xe={alignItems:`start`,display:`block`,width:`100%`},Se={...xe,gridColumn:`1 / -1`},Ce={minWidth:0,width:`100%`},we={minWidth:`100%`,width:`100%`},Te={display:`grid`,gap:14},Ee={alignItems:`start`,display:`block`,width:`100%`},De={minWidth:0,width:`100%`},Oe={gridColumn:`2 / -1`},ke={display:`grid`,gap:10,width:`100%`},Ae={display:`grid`,gap:8,gridTemplateColumns:`repeat(auto-fit, minmax(160px, 1fr))`},je={display:`inline-flex`},Me={display:`grid`,gap:16},v={display:`grid`,gap:8},y={display:`flex`,justifyContent:`flex-end`},Ne={color:`var(--mzn-color-text-error)`,fontSize:`0.72em`,lineHeight:0,marginLeft:2,verticalAlign:`super`},Pe={display:`grid`,gap:10,gridColumn:`1 / -1`},Fe={backgroundColor:`var(--mzn-color-bg-surface-secondary)`,borderRadius:6,display:`grid`,gap:4,padding:10},Ie={display:`grid`,gap:8,gridTemplateColumns:`minmax(180px, 0.7fr) minmax(220px, 1.3fr)`};function Le(e){e&&(e.style.width=`100%`)}var Re={fields:[],schemaVersion:1},ze={layout:[],schemaVersion:1},b=`__STATIC_OPTIONS__`,x=`__CONSTANT__`,S=`__UNBOUND__`,Be=[{id:b,name:`靜態選項`}],C=[{id:`single`,name:`單選`},{id:`multiple`,name:`複選`}],Ve=[{id:`unset`,name:`不預設`},{id:`true`,name:`是`},{id:`false`,name:`否`}],He=[{id:`true`,name:`是`},{id:`false`,name:`否`}],Ue=[{label:`顯示`,name:`fieldVisibleWhen`,supportingText:`符合條件時才顯示這個欄位。`,target:`visibleWhen`},{label:`必填`,name:`fieldRequiredWhen`,supportingText:`符合條件時才要求填寫這個欄位。`,target:`requiredWhen`},{label:`唯讀`,name:`fieldReadonlyWhen`,supportingText:`符合條件時不允許修改這個欄位。`,target:`readonlyWhen`}];function w({onChange:e,value:u}){let d=u?.schema??Re,f=u?.uiSchema??ze,[p,m]=(0,r.useState)(d),[h,w]=(0,r.useState)(f),[O,k]=(0,r.useState)(D(d)),[rt,A]=(0,r.useState)(D(f)),[it,at]=(0,r.useState)({}),[ot,j]=(0,r.useState)(null),[M,N]=(0,r.useState)(`design`),[P,F]=(0,r.useState)(null),[I,st]=(0,r.useState)([]),[L,ct]=(0,r.useState)(null),[lt,ut]=(0,r.useState)(`loading`),[R,z]=(0,r.useState)(null),[dt,ft]=(0,r.useState)(!1),[B,V]=(0,r.useState)(null);(0,r.useEffect)(()=>{let e=!0;return(0,s.listFormDataSources)().then(t=>{e&&(st(t),ct(null),ut(`ready`))}).catch(t=>{e&&(st([]),ct(`目前無法載入 DataSource Catalog,請稍後重試。`),ut(`unavailable`))}),()=>{e=!1}},[]),(0,r.useEffect)(()=>{p.fields.some(e=>e.fieldKey===P)||F(p.fields[0]?.fieldKey??null)},[p.fields,P]),(0,r.useEffect)(()=>{at(e=>(0,s.buildFormRendererValues)(p.fields,e))},[p.fields]),(0,r.useEffect)(()=>{M!==`advanced`&&(k(D(p)),A(D(h)))},[M,p,h]);let H=(0,r.useMemo)(()=>p.fields.find(e=>e.fieldKey===P)??p.fields[0]??null,[p.fields,P]);(0,r.useEffect)(()=>{e?.({schema:p,uiSchema:h})},[p,h]);function U(e){let t=p.fields.length+1,n=(0,s.createFieldDefinition)(e,t);m({...p,fields:[...p.fields,n]}),w({...h,layout:[...h.layout,{fieldKey:n.fieldKey,width:e===`textarea`||e===`file_upload`?`FULL`:`HALF`}]}),F(n.fieldKey),N(`design`),j(null)}function pt(e){let t=e;t===`advanced`&&M!==`advanced`&&(k(D(p)),A(D(h))),N(t)}function mt(e){let t=p.fields.flatMap(t=>(0,c.isFormDataSourceFieldDefinition)(t)&&(0,s.readFormDataSourceFieldDependencyKeys)(t).includes(e)?[t.fieldKey]:[]);if(t.length>0){V({affectedFieldKeys:t,fieldKey:e,kind:`remove-field`});return}ht(e)}function ht(e){let t=p.fields.filter(t=>t.fieldKey!==e);m({...p,fields:t}),w({...h,layout:h.layout.filter(t=>t.fieldKey!==e)}),F(P===e?t[0]?.fieldKey??null:P),j(null),z(null)}function gt(e){let t=e.destination;t&&e.source.index!==t.index&&(m(n=>({...n,fields:nt(n.fields,e.source.index,t.index)})),w(n=>({...n,layout:nt(n.layout,e.source.index,t.index)})),j(null))}function W(e){G(t=>({...t,...e}))}function G(e){if(!H)return;let t=H.fieldKey,n=e(H),r=n.fieldKey,i={...p,fields:p.fields.map(e=>e.fieldKey===t?n:e)},a=t===r?i:(0,s.renameFormDataSourceFieldBindings)(i,t,r);m(a),w({...h,layout:h.layout.map(e=>e.fieldKey===t?{...e,fieldKey:r}:e)}),F(r),j(null),z(null)}function K(e){G(t=>Ze(t)?{...t,...e}:t)}function q(e){G(t=>(0,s.isNumberFieldDefinition)(t)?{...t,...e}:t)}function _t(e){G(t=>(0,s.isDateFieldDefinition)(t)?{...t,...e}:t)}function J(e){G(t=>(0,s.isSelectFieldDefinition)(t)?{...t,...e}:t)}function vt(e){if(!H||H.type!==`select`&&H.type!==`autocomplete`||(0,c.readFormFieldSelectionMode)(H)===e)return;let t=H.defaultValue,n=e===`multiple`?typeof t==`string`?[t]:t:Array.isArray(t)?t[0]:t;Y(H,{...H,defaultValue:n,mode:e},`選擇模式變更可能轉換或捨棄既有預設值。`)}function Y(e,t,n=`此變更會替換目前選項來源;既有 options、dynamic reference 或 bindings 可能失效。`){JSON.stringify(e)!==JSON.stringify(t)&&V({fieldKey:e.fieldKey,impact:n,kind:`replace-field`,nextField:t})}function yt(e,t){if(!t)return;if(t===b){if(!(0,c.isFormDataSourceFieldDefinition)(e))return;let{dataSource:t,defaultValue:n,...r}=e;Y(e,{...r,options:[]});return}let n=I.find(e=>T(e)===t);if(!n)return;if((0,c.isFormDataSourceFieldDefinition)(e)){let t=new Set(n.parameters.map(e=>e.key)),r=e.dataSource.bindings.filter(e=>t.has(e.parameter));Y(e,{...e,dataSource:{bindings:r,key:n.key,version:n.version}});return}let{options:r,defaultValue:i,...a}=e;Y(e,{...a,dataSource:{bindings:[],key:n.key,version:n.version}})}function bt(){B&&(B.kind===`remove-field`?ht(B.fieldKey):(m({...p,fields:p.fields.map(e=>e.fieldKey===B.fieldKey?B.nextField:e)}),j(null),z(null)),V(null))}async function xt(){ft(!0);try{let e=await(0,s.lintFormSchema)(p,h);z(e.errors.map(s.readFormSchemaLintMessage))}catch{z([`目前無法完成 DataSource schema 驗證。`])}finally{ft(!1)}}function St(e){G(t=>t.type===`boolean`?{...t,...e}:t)}function Ct(e){G(t=>t.type===`file_upload`?{...t,...e}:t)}function wt(e){at(e)}function Tt(e,t){m(n=>({...n,fields:n.fields.map(n=>n.fieldKey===e?{...n,required:t}:n)})),j(null)}function Et(e){k(e);try{m(JSON.parse(e)),j(null)}catch{j(`Form Schema JSON 格式不正確`)}}function Dt(e){A(e);try{w(JSON.parse(e)),j(null)}catch{j(`UI Schema JSON 格式不正確`)}}return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(a.Fragment,{children:(0,a.jsx)(i.SectionGroup,{children:(0,a.jsx)(i.Section,{children:(0,a.jsxs)(`div`,{style:Me,children:[(0,a.jsxs)(i.Tab,{activeKey:M,onChange:pt,size:`sub`,children:[(0,a.jsx)(i.TabItem,{children:`設計`},`design`),(0,a.jsx)(i.TabItem,{children:`預覽`},`preview`),(0,a.jsx)(i.TabItem,{children:`進階`},`advanced`)]}),M===`design`?Ot():null,M===`preview`?en():null,M===`advanced`?tn():null]})})})}),B?(0,a.jsx)(i.Modal,{cancelText:`返回`,confirmText:`確認變更`,modalType:`standard`,onCancel:()=>V(null),onClose:()=>V(null),onConfirm:bt,open:!0,showModalFooter:!0,showModalHeader:!0,title:B.kind===`remove-field`?`確認移除 dependency 欄位`:`確認替換選項來源`,children:B.kind===`remove-field`?(0,a.jsxs)(`div`,{style:v,children:[(0,a.jsx)(i.Typography,{variant:`body`,children:`此欄位仍被下列 DataSource binding 使用;移除後請重新設定這些欄位。`}),(0,a.jsx)(i.Typography,{color:`text-warning`,variant:`body`,children:B.affectedFieldKeys.join(`、`)})]}):(0,a.jsxs)(i.Typography,{variant:`body`,children:[B.impact,`確認後才會寫入 schema。`]})}):null]});function Ot(){return(0,a.jsxs)(`div`,{style:_,children:[(0,a.jsxs)(`div`,{style:oe,children:[(0,a.jsx)(i.Typography,{component:`h2`,variant:`label-primary`,children:`新增欄位`}),(0,a.jsx)(`div`,{style:ie,children:g.map(e=>(0,a.jsx)(i.Button,{icon:e.icon,iconType:`leading`,onClick:()=>U(e.type),size:`sub`,style:ae,type:`button`,variant:`base-secondary`,children:e.label},e.type))})]}),(0,a.jsxs)(`div`,{style:te,children:[(0,a.jsxs)(`div`,{style:{..._,...ne},children:[(0,a.jsx)(i.Typography,{component:`h2`,variant:`label-primary`,children:`表單畫布`}),p.fields.length>0?(0,a.jsx)(l.DragDropContext,{onDragEnd:gt,children:(0,a.jsx)(l.Droppable,{droppableId:`form-builder-fields`,children:e=>(0,a.jsxs)(`div`,{...e.droppableProps,ref:e.innerRef,style:_,children:[p.fields.map((e,t)=>(0,a.jsx)(l.Draggable,{draggableId:e.fieldKey,index:t,children:(t,n)=>Qt(e,t,n.isDragging)},e.fieldKey)),e.placeholder]})})}):(0,a.jsxs)(`div`,{style:me,children:[(0,a.jsxs)(`div`,{style:_,children:[(0,a.jsx)(i.Typography,{component:`h3`,variant:`h3`,children:`尚未建立欄位`}),(0,a.jsx)(i.Typography,{color:`text-neutral`,variant:`body`,children:`從上方新增第一個欄位,或直接建立常用文字欄位開始設計。`})]}),(0,a.jsxs)(`div`,{style:he,children:[(0,a.jsx)(i.Button,{onClick:()=>U(`text`),variant:`base-primary`,children:`新增文字欄位`}),(0,a.jsx)(i.Button,{onClick:()=>U(`textarea`),variant:`base-secondary`,children:`新增長文字`})]})]})]}),(0,a.jsxs)(`div`,{style:{..._,...re},children:[(0,a.jsx)(i.Typography,{component:`h2`,variant:`label-primary`,children:`欄位設定`}),H?kt(H):(0,a.jsx)(i.Typography,{color:`text-neutral`,variant:`body`,children:`請先新增或選取欄位。`})]})]})]})}function kt(e){return(0,a.jsxs)(`div`,{style:ge,children:[At(e),jt(e)]})}function At(e){return(0,a.jsxs)(`div`,{style:_e,children:[(0,a.jsx)(`div`,{style:ye,children:(0,a.jsx)(i.Badge,{size:`main`,text:We(e.type),variant:`text-info`})}),Q(`標題`,`fieldLabel`,(0,a.jsx)(i.Input,{onChange:e=>W({label:e.target.value}),placeholder:`例如:申請金額`,value:e.label,variant:`base`})),Q(`欄位 Key`,`fieldKey`,(0,a.jsx)(i.Input,{onChange:e=>W({fieldKey:e.target.value}),placeholder:`例如:amount`,value:e.fieldKey,variant:`base`})),Q(`提示文字`,`fieldPlaceholder`,(0,a.jsx)(i.Input,{onChange:e=>W({placeholder:e.target.value||void 0}),placeholder:`例如:請輸入申請金額`,value:e.placeholder??``,variant:`base`})),Mt(e)]})}function jt(e){return(0,a.jsx)(i.Accordion,{defaultExpanded:Ye(e),size:`sub`,title:`進階設定`,children:(0,a.jsxs)(`div`,{style:_e,children:[(0,a.jsx)(i.Typography,{component:`h3`,style:ve,variant:`label-primary`,children:`條件規則`}),(0,a.jsx)(i.Typography,{color:`text-neutral`,style:be,variant:`body`,children:`只有需要根據其他欄位改變顯示、必填或唯讀狀態時才需要設定。`}),Kt(e)]})})}function Mt(e){return Ze(e)?Nt(e):(0,s.isNumberFieldDefinition)(e)?Pt(e):(0,s.isDateFieldDefinition)(e)?Ft(e):(0,c.isFormOptionFieldDefinition)(e)?It(e):e.type===`boolean`?Wt(e):Gt(e)}function Nt(e){return(0,a.jsxs)(a.Fragment,{children:[Q(`預設值`,`fieldDefaultValue`,e.type===`textarea`?Yt({name:`fieldDefaultValue`,onChange:e=>K({defaultValue:e||void 0}),placeholder:`輸入此欄位的預設文字`,rows:3,value:E(e.defaultValue)}):(0,a.jsx)(i.Input,{onChange:e=>K({defaultValue:e.target.value||void 0}),placeholder:`輸入此欄位的預設文字`,value:E(e.defaultValue),variant:`base`})),Q(`最小長度`,`fieldMinLength`,Z(e.minLength,e=>K({minLength:e}),`例如:2`,{min:0})),Q(`最大長度`,`fieldMaxLength`,Z(e.maxLength,e=>K({maxLength:e}),`例如:100`,{min:1}))]})}function Pt(e){return(0,a.jsxs)(a.Fragment,{children:[Q(`預設值`,`fieldDefaultValue`,Z(typeof e.defaultValue==`number`?e.defaultValue:void 0,e=>q({defaultValue:e}),e.type===`money`?`例如:1000`:`輸入預設數值`,{max:e.maximum,min:e.minimum})),Q(`最小值`,`fieldMinimum`,Z(e.minimum,e=>q({minimum:e}),`例如:0`)),Q(`最大值`,`fieldMaximum`,Z(e.maximum,e=>q({maximum:e}),`例如:999999`))]})}function Ft(e){return Q(`預設值`,`fieldDefaultValue`,Xt(e,E(e.defaultValue),e=>_t({defaultValue:e})))}function It(e){let t=(0,s.readCompatibleFormDataSourceDescriptors)(e.type,I),n=(0,c.isFormDataSourceFieldDefinition)(e)?T(e.dataSource):b,r=(0,c.isFormDataSourceFieldDefinition)(e)?I.find(t=>t.key===e.dataSource.key&&t.version===e.dataSource.version):null,o=r?t.some(e=>e.key===r.key&&e.version===r.version):!1,l=[...Be,...t.map(Ge),...(0,c.isFormDataSourceFieldDefinition)(e)&&!o?[{id:n,name:`${e.dataSource.key} v${e.dataSource.version}(目前不可用或不支援)`}]:[]],u=(0,c.readFormFieldSelectionMode)(e);return(0,a.jsxs)(a.Fragment,{children:[e.type===`select`||e.type===`autocomplete`?Q(`選擇模式`,`fieldSelectionMode`,(0,a.jsx)(i.Select,{clearable:!1,onChange:e=>{(e?.id===`single`||e?.id===`multiple`)&&vt(e.id)},options:[...C],value:(0,s.readSelectOption)(C,u)})):Q(`選擇模式`,`fieldSelectionMode`,(0,a.jsx)(i.Typography,{color:`text-neutral`,variant:`body`,children:u===`multiple`?`固定複選`:`固定單選`})),Q(`選項來源`,`fieldOptionSource`,(0,a.jsx)(i.Select,{clearable:!1,disabled:lt===`loading`&&!(0,c.isFormDataSourceFieldDefinition)(e),onChange:t=>yt(e,t?.id),options:l,placeholder:`選擇選項來源`,value:(0,s.readSelectOption)(l,n)})),(0,c.isFormDataSourceFieldDefinition)(e)?Lt(e,t):Ut(e)]})}function Lt(e,t){let n=I.find(t=>t.key===e.dataSource.key&&t.version===e.dataSource.version),r=n&&!(0,s.isFormDataSourceDescriptorCompatible)(n,e.type);return(0,a.jsxs)(`div`,{style:Pe,children:[lt===`loading`?(0,a.jsx)(i.Typography,{color:`text-neutral`,variant:`body`,children:`正在載入可用的 DataSource Catalog…`}):null,L?(0,a.jsx)(i.Typography,{color:`text-error`,variant:`body`,children:L}):null,n?null:(0,a.jsx)(i.Typography,{color:`text-warning`,variant:`body`,children:`目前來源版本未出現在 Catalog;會保留原設定,但在環境 lint 通過前不可發布。`}),r?(0,a.jsx)(i.Typography,{color:`text-error`,variant:`body`,children:`目前來源不支援此控制項或超出 bounded list 限制,請選擇其他版本。`}):null,n?Rt(n):null,n?n.parameters.map(t=>zt(e,t)):null,t.length===0&&!L?(0,a.jsx)(i.Typography,{color:`text-warning`,variant:`body`,children:`沒有符合目前控制項能力的已註冊來源。`}):null,(0,a.jsx)(`div`,{style:y,children:(0,a.jsx)(i.Button,{disabled:dt,onClick:()=>void xt(),size:`sub`,type:`button`,variant:`base-secondary`,children:dt?`驗證中…`:`驗證 DataSource 設定`})}),R?(0,a.jsx)(i.Typography,{color:R.length>0?`text-error`:`text-success`,variant:`caption`,children:R.length>0?R.join(`;`):`DataSource schema 與目前環境均通過驗證。`}):null]})}function Rt(e){return(0,a.jsxs)(`div`,{style:Fe,children:[(0,a.jsxs)(i.Typography,{variant:`label-primary`,children:[e.label,` · v`,e.version]}),e.description?(0,a.jsx)(i.Typography,{color:`text-neutral`,variant:`caption`,children:e.description}):null,(0,a.jsxs)(i.Typography,{color:`text-neutral`,variant:`caption`,children:[`支援:`,e.supportedControls.join(`、`),`;`,e.supportsSearch?`支援搜尋`:`不支援搜尋`,`;`,e.paginationMode===`CURSOR`?`支援分頁`:`完整清單`,`; policy:`,e.revalidationPolicy]})]})}function zt(e,n){let r=(0,s.readFormDataSourceBinding)(e,n.key),o=Ke(r),c=(0,s.readCompatibleFormDataSourceBindingFields)(n.type,p.fields,e.fieldKey),l=[...n.required?[]:[{id:S,name:`未綁定`}],...c,...n.type===`STRING_ARRAY`?[]:[{id:x,name:`固定常數`}]];return(0,a.jsxs)(`div`,{style:Ie,children:[(0,a.jsx)(t.t,{label:`${n.label??n.key}${n.required?`(必填)`:`(選填)`}`,name:`dataSourceParameter_${n.key}`,children:(0,a.jsx)(i.Select,{clearable:!1,onChange:t=>Vt(e,n.key,n.type,t?.id),options:l,placeholder:`選擇欄位或常數`,value:(0,s.readSelectOption)(l,o)})}),(0,s.readFormDataSourceBindingValueKind)(r)===`CONSTANT`?Bt(e,n.key,n.type,r):(0,s.readFormDataSourceBindingValueKind)(r)===`FIELD`?(0,a.jsxs)(i.Typography,{color:`text-neutral`,variant:`caption`,children:[`使用表單欄位「`,r?.from.kind===`FIELD`?r.from.fieldKey:``,`」的目前值。`]}):(0,a.jsx)(i.Typography,{color:`text-neutral`,variant:`caption`,children:n.required?c.length>0?`請選擇相容的表單欄位或固定常數。`:`目前沒有型別相容的表單欄位,請先建立 dependency。`:`此參數可不綁定。`})]},n.key)}function Bt(e,t,n,r){let o=(0,s.readFormDataSourceBindingValue)(e,t);if(n===`BOOLEAN`){let e=[{id:`true`,name:`是`},{id:`false`,name:`否`}];return(0,a.jsx)(i.Select,{clearable:!1,onChange:e=>Ht(t,e?.id===`true`),options:e,value:(0,s.readSelectOption)(e,o===!0?`true`:`false`)})}return n===`STRING_ARRAY`?(0,a.jsx)(i.Typography,{color:`text-warning`,variant:`caption`,children:`STRING_ARRAY 參數請綁定複選欄位;目前不接受固定常數。`}):(0,a.jsx)(i.Input,{onChange:e=>Ht(t,n===`NUMBER`?(0,s.parseOptionalNumberInput)(e.target.value)??0:e.target.value),placeholder:n===`NUMBER`?`輸入數字`:`輸入固定值`,value:Je(r,n),variant:`base`})}function Vt(e,t,n,r){if(!r||r===S){G(e=>(0,c.isFormDataSourceFieldDefinition)(e)?(0,s.upsertFormDataSourceFieldBinding)(e,t,null):e);return}if(r===x){G(e=>(0,c.isFormDataSourceFieldDefinition)(e)?(0,s.upsertFormDataSourceFieldBinding)(e,t,{from:{kind:`CONSTANT`,value:qe(n)},parameter:t}):e);return}G(e=>(0,c.isFormDataSourceFieldDefinition)(e)?(0,s.upsertFormDataSourceFieldBinding)(e,t,{from:{fieldKey:r,kind:`FIELD`},parameter:t}):e)}function Ht(e,t){G(n=>(0,c.isFormDataSourceFieldDefinition)(n)?(0,s.upsertFormDataSourceFieldBinding)(n,e,{from:{kind:`CONSTANT`,value:t},parameter:e}):n)}function Ut(e){let t=(0,c.readFormFieldSelectionMode)(e),n=Array.isArray(e.defaultValue)?e.defaultValue:[],r=e.options.map(s.readFieldOptionAsSelectOption),o=r.filter(e=>n.includes(e.id));return(0,a.jsxs)(a.Fragment,{children:[Q(`預設值`,`fieldDefaultValue`,t===`multiple`?(0,a.jsx)(i.Select,{clearable:!0,mode:`multiple`,onChange:e=>J({defaultValue:e.length?e.map(e=>e.id):void 0}),options:r,placeholder:`選擇一或多個預設選項`,value:o}):(0,a.jsx)(i.Select,{clearable:!0,onChange:e=>J({defaultValue:e?.id||void 0}),options:r,placeholder:`選擇預設選項`,value:typeof e.defaultValue==`string`?(0,s.readSelectOption)(r,e.defaultValue):null})),Q(`選項`,`fieldOptions`,Zt(e),!0)]})}function Wt(e){let t=typeof e.defaultValue==`boolean`?String(e.defaultValue):`unset`;return Q(`預設值`,`fieldDefaultValue`,(0,a.jsx)(i.Select,{clearable:!1,onChange:e=>St({defaultValue:e?.id===`true`||e?.id!==`false`&&void 0}),options:[...Ve],placeholder:`選擇預設狀態`,value:(0,s.readSelectOption)(Ve,t)}))}function Gt(e){return(0,a.jsxs)(a.Fragment,{children:[Q(`檔案數`,`fieldMaxFiles`,Z(e.maxFiles,e=>Ct({maxFiles:e}),`例如:1`,{min:1})),Q(`MIME`,`fieldAcceptedMimeTypes`,Yt({name:`fieldAcceptedMimeTypes`,onChange:e=>Ct({acceptedMimeTypes:Qe(e)}),placeholder:`每行一個 MIME type,例如:application/pdf`,rows:3,value:$e(e.acceptedMimeTypes)}),!1)]})}function Kt(e){let t=p.fields.filter(t=>t.fieldKey!==e.fieldKey);return t.length?(0,a.jsx)(a.Fragment,{children:Ue.map(n=>qt(e,n,t))}):(0,a.jsx)(i.Typography,{color:`text-neutral`,style:be,variant:`body`,children:`目前沒有其他欄位可作為條件來源。新增更多欄位後即可設定條件規則。`})}function qt(e,t,n){let r=e[t.target],o=r?(0,s.parseConditionRule)(r):null,c=n.find(e=>e.fieldKey===o?.fieldKey),l=c??n[0],u=n.map(Xe),d=(0,s.readConditionOperatorOptions)(l),f=o&&d.some(e=>e.id===o.operator)?o.operator:(0,s.readDefaultConditionOperator)(l),p=o?.value??(0,s.readDefaultConditionValue)(l),m=!!r,h=m&&(!o||!c);return Q(t.label,t.name,(0,a.jsxs)(`div`,{style:ke,children:[(0,a.jsx)(i.Toggle,{checked:m,label:m?`已啟用`:`不啟用`,onChange:e=>X(t.target,e.target.checked?(0,s.buildConditionExpression)(l,(0,s.readDefaultConditionOperator)(l),(0,s.readDefaultConditionValue)(l)):void 0),size:`sub`,supportingText:t.supportingText}),m?h?(0,a.jsx)(i.Typography,{color:`text-warning`,variant:`body`,children:`這個規則不是目前 UI 支援的格式。重新選擇條件後會取代既有規則。`}):(0,a.jsxs)(`div`,{style:Ae,children:[(0,a.jsx)(i.Select,{clearable:!1,onChange:e=>{let r=n.find(t=>t.fieldKey===e?.id)??l;X(t.target,(0,s.buildConditionExpression)(r,(0,s.readDefaultConditionOperator)(r),(0,s.readDefaultConditionValue)(r)))},options:u,placeholder:`選擇欄位`,value:(0,s.readSelectOption)(u,l.fieldKey)}),(0,a.jsx)(i.Select,{clearable:!1,onChange:e=>X(t.target,(0,s.buildConditionExpression)(l,(0,s.readConditionOperatorOption)(e?.id)??f,p)),options:[...d],placeholder:`判斷方式`,value:(0,s.readSelectOption)(d,f)}),Jt(l,p,e=>X(t.target,(0,s.buildConditionExpression)(l,f,e)))]}):null]}),!0)}function X(e,t){W({[e]:t})}function Jt(e,t,n){if(e.type===`boolean`)return(0,a.jsx)(i.Select,{clearable:!1,onChange:e=>n(e?.id??`true`),options:[...He],placeholder:`比較值`,value:(0,s.readSelectOption)(He,t===`false`?`false`:`true`)});if((0,s.isSelectFieldDefinition)(e)){let r=e.options.map(s.readFieldOptionAsSelectOption);return(0,a.jsx)(i.Select,{clearable:!1,onChange:e=>n(e?.id??r[0]?.id??``),options:r,placeholder:`比較值`,value:(0,s.readSelectOption)(r,t)})}return(0,s.isNumberFieldDefinition)(e)?Z((0,s.parseOptionalNumberInput)(t),e=>n(String(e??0)),`比較值`):(0,s.isDateFieldDefinition)(e)?Xt(e,t,e=>n(e??``)):(0,a.jsx)(i.Input,{onChange:e=>n(e.target.value),placeholder:`比較值`,value:t,variant:`base`})}function Yt({name:e,onChange:t,placeholder:n,rows:r,value:o}){return(0,a.jsx)(i.Textarea,{"aria-label":e,onChange:e=>t(e.target.value),placeholder:n,ref:Le,resize:`vertical`,rows:r,style:we,value:o})}function Z(e,t,n,r={}){return(0,a.jsx)(i.Input,{max:r.max,min:r.min,onChange:e=>t((0,s.clampOptionalNumber)((0,s.parseOptionalNumberInput)(e.target.value),r)),placeholder:n,showSpinner:!0,step:r.step??1,value:typeof e==`number`?String(e):``,variant:`measure`})}function Xt(e,t,n){return e.type===`datetime`?(0,a.jsx)(i.DateTimePicker,{formatDate:`YYYY-MM-DD`,formatTime:`HH:mm`,hideSecond:!0,onChange:e=>n((0,s.formatDateTimePickerValue)(e)),placeholderLeft:`選擇日期`,placeholderRight:`選擇時間`,value:(0,s.readDatePickerValue)(t)}):(0,a.jsx)(i.DatePicker,{format:`YYYY-MM-DD`,onChange:e=>n((0,s.formatDatePickerValue)(e)),placeholder:`選擇日期`,value:(0,s.readDatePickerValue)(t)})}function Zt(e){let t=e.options.map((t,n)=>({index:n,key:`${e.fieldKey}-${n}`,label:t.label,value:t.value}));return(0,a.jsxs)(`div`,{style:v,children:[(0,a.jsx)(i.Table,{actions:{render:t=>[{disabled:()=>e.options.length<=1,icon:o.TrashIcon,iconType:`icon-only`,name:`移除選項`,onClick:()=>J({options:e.options.filter((e,n)=>n!==t.index)}),variant:`destructive-ghost`}],width:56},columns:[{key:`label`,render:t=>(0,a.jsx)(i.Input,{onChange:n=>J({options:et(e.options,t.index,{label:n.target.value})}),placeholder:`例如:主管`,size:`sub`,value:t.label,variant:`base`}),title:`Label`},{key:`value`,render:t=>(0,a.jsx)(i.Input,{onChange:n=>J({options:et(e.options,t.index,{value:n.target.value})}),placeholder:`例如:manager`,size:`sub`,value:t.value,variant:`base`}),title:`Value`}],dataSource:t,showHeader:!0,size:`sub`}),(0,a.jsx)(`div`,{style:y,children:(0,a.jsx)(i.Button,{icon:o.PlusIcon,iconType:`leading`,onClick:()=>J({options:[...e.options,tt(e.options)]}),variant:`base-secondary`,children:`新增選項`})})]})}function Qt(e,t,n){return(0,a.jsx)(`div`,{...t.draggableProps,"data-form-builder-field-key":e.fieldKey,ref:t.innerRef,style:{...de,...n?fe:null,...t.draggableProps.style},children:(0,a.jsx)(i.BaseCard,{style:e.fieldKey===H?.fieldKey?pe:void 0,children:$t(e,t,n)})})}function Q(e,n,r,i=!1){return(0,a.jsx)(`div`,{style:i?Se:xe,children:(0,a.jsx)(`div`,{style:Ce,children:(0,a.jsx)(t.t,{label:e,name:n,children:r})})})}function $t(e,t,n){return(0,a.jsxs)(`div`,{...t.dragHandleProps??{},"aria-label":`選取或拖曳排序欄位`,onClick:()=>F(e.fieldKey),style:se,title:`點擊選取,拖曳排序`,children:[(0,a.jsx)(`span`,{"aria-label":`拖曳排序`,role:`img`,style:je,title:`拖曳排序`,children:(0,a.jsx)(i.Icon,{icon:o.DotDragVerticalIcon,size:20})}),(0,a.jsxs)(`div`,{style:ce,children:[(0,a.jsxs)(i.Typography,{component:`span`,ellipsis:!0,variant:`label-primary`,children:[e.label,e.required?(0,a.jsx)(`sup`,{"aria-label":`必填`,style:Ne,children:`*`}):null]}),(0,a.jsxs)(i.Typography,{color:`text-neutral`,component:`span`,ellipsis:!0,variant:`caption`,children:[We(e.type),` ·`,e.required?` 必填`:` 選填`,` ·`,e.fieldKey]})]}),(0,a.jsxs)(`div`,{onClick:e=>e.stopPropagation(),style:le,children:[(0,a.jsx)(`div`,{style:ue,children:(0,a.jsx)(i.Toggle,{checked:!!e.required,disabled:n,label:`必填`,onChange:t=>Tt(e.fieldKey,t.target.checked)})}),(0,a.jsx)(i.Button,{disabled:n,icon:o.TrashIcon,iconType:`icon-only`,onClick:()=>mt(e.fieldKey),variant:`destructive-ghost`,children:`移除欄位`})]})]})}function en(){return(0,a.jsxs)(`div`,{style:_,children:[(0,a.jsx)(i.Typography,{component:`h2`,variant:`h3`,children:`填寫預覽`}),(0,a.jsx)(n.t,{dataSourceContext:{kind:`preview`},onChange:wt,schema:p,uiSchema:h,value:it})]})}function tn(){return(0,a.jsxs)(`div`,{style:_,children:[(0,a.jsx)(i.Typography,{component:`h2`,variant:`h3`,children:`Schema`}),(0,a.jsxs)(`div`,{style:Te,children:[$(`Form Schema`,`schemaJson`,(0,a.jsx)(ee,{height:`360px`,name:`schemaJson`,onChange:Et,placeholder:`輸入 Form Schema JSON`,value:O})),$(`UI Schema`,`uiSchemaJson`,(0,a.jsx)(ee,{height:`240px`,name:`uiSchemaJson`,onChange:Dt,placeholder:`輸入 UI Schema JSON`,value:rt})),ot?(0,a.jsx)(i.Typography,{color:`text-error`,style:Oe,variant:`body`,children:ot}):null]})]})}function $(e,n,r){return(0,a.jsx)(`div`,{style:Ee,children:(0,a.jsx)(`div`,{style:De,children:(0,a.jsx)(t.t,{label:e,name:n,children:r})})})}}function We(e){return g.find(t=>t.type===e)?.label??e}function T(e){return`${e.key}@${e.version}`}function Ge(e){return{id:T(e),name:`${e.label} · ${e.key} v${e.version}`}}function Ke(e){return e?e.from.kind===`FIELD`?e.from.fieldKey:x:S}function qe(e){switch(e){case`BOOLEAN`:return!1;case`NUMBER`:return 0;case`STRING_ARRAY`:return``;case`STRING`:return``;default:return``}}function Je(e,t){let n=e?.from.kind===`CONSTANT`?e.from.value:``;return t===`NUMBER`?typeof n==`number`?String(n):``:typeof n==`string`?n:``}function Ye(e){return!!(e.visibleWhen||e.requiredWhen||e.readonlyWhen)}function Xe(e){return{id:e.fieldKey,name:e.label}}function Ze(e){return e.type===`text`||e.type===`textarea`}function E(e){return typeof e==`string`?e:``}function Qe(e){let t=e.split(/[\n,]/u).map(e=>e.trim()).filter(Boolean);return t.length?t:void 0}function $e(e){return e?.join(`
2
- `)??``}function D(e){return JSON.stringify(e,null,2)}function et(e,t,n){return e.map((e,r)=>r===t?{...e,...n}:e)}function tt(e){let t=e.length+1;return{label:`選項 ${t}`,value:O(e,t)}}function O(e,t){let n=`option_${t}`;return e.some(e=>e.value===n)?O(e,t+1):n}function nt(e,t,n){let r=e[t];if(!r||t===n)return[...e];let i=e.filter((e,n)=>n!==t);return[...i.slice(0,n),r,...i.slice(n)]}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return w}});
3
- //# sourceMappingURL=FormBuilderView-CAqjOYAP.cjs.map