@rytass/bpm-core-react 0.20.0 → 0.21.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.
- package/CHANGELOG.md +44 -0
- package/README.md +1 -1
- package/dist/approval-instance-list-page.css +1 -1
- package/dist/chunks/FormBuilderView-DjPGrOJ2.cjs +4 -0
- package/dist/chunks/FormBuilderView-DjPGrOJ2.cjs.map +1 -0
- package/dist/chunks/{FormBuilderView-CFRiw04B.js → FormBuilderView-WtC2iW5f.js} +667 -584
- package/dist/chunks/FormBuilderView-WtC2iW5f.js.map +1 -0
- package/dist/chunks/{FormRendererView-lYSaR8CQ.cjs → FormRendererView-B-xycC9S.cjs} +3 -3
- package/dist/chunks/{FormRendererView-lYSaR8CQ.cjs.map → FormRendererView-B-xycC9S.cjs.map} +1 -1
- package/dist/chunks/{FormRendererView-GfbVWEGa.js → FormRendererView-BcQKUi1A.js} +238 -238
- package/dist/chunks/{FormRendererView-GfbVWEGa.js.map → FormRendererView-BcQKUi1A.js.map} +1 -1
- package/dist/chunks/approval-instance-list-page-Bth7Raya.js +724 -0
- package/dist/chunks/approval-instance-list-page-Bth7Raya.js.map +1 -0
- package/dist/chunks/approval-instance-list-page-Dcvo6TrT.cjs +2 -0
- package/dist/chunks/approval-instance-list-page-Dcvo6TrT.cjs.map +1 -0
- package/dist/chunks/{categories-DQUtVEiV.cjs → categories-CyyqG6wG.cjs} +2 -2
- package/dist/chunks/{categories-DQUtVEiV.cjs.map → categories-CyyqG6wG.cjs.map} +1 -1
- package/dist/chunks/{categories-BAdxjNSA.js → categories-f7E-RJEc.js} +9 -9
- package/dist/chunks/{categories-BAdxjNSA.js.map → categories-f7E-RJEc.js.map} +1 -1
- package/dist/chunks/{compose-Bb5bUVFd.cjs → compose-BKUTsB2W.cjs} +2 -2
- package/dist/chunks/{compose-Bb5bUVFd.cjs.map → compose-BKUTsB2W.cjs.map} +1 -1
- package/dist/chunks/{compose-egQlRjuZ.js → compose-DZvIspW3.js} +4 -4
- package/dist/chunks/{compose-egQlRjuZ.js.map → compose-DZvIspW3.js.map} +1 -1
- package/dist/chunks/{delegations-CVmtpkRn.cjs → delegations-ClRCwD1I.cjs} +2 -2
- package/dist/chunks/{delegations-CVmtpkRn.cjs.map → delegations-ClRCwD1I.cjs.map} +1 -1
- package/dist/chunks/{delegations-9-yvWWws.js → delegations-CqND-Qtz.js} +5 -5
- package/dist/chunks/{delegations-9-yvWWws.js.map → delegations-CqND-Qtz.js.map} +1 -1
- package/dist/chunks/{delegations-CrfjsH94.cjs → delegations-D43VDSz1.cjs} +2 -2
- package/dist/chunks/{delegations-CrfjsH94.cjs.map → delegations-D43VDSz1.cjs.map} +1 -1
- package/dist/chunks/{delegations-CxnNvTCc.js → delegations-zisffLwk.js} +5 -5
- package/dist/chunks/{delegations-CxnNvTCc.js.map → delegations-zisffLwk.js.map} +1 -1
- package/dist/chunks/{designer-CZDlQ9Nf.js → designer-CWubIE69.js} +1425 -1412
- package/dist/chunks/designer-CWubIE69.js.map +1 -0
- package/dist/chunks/designer-C_m8DmMl.cjs +69 -0
- package/dist/chunks/designer-C_m8DmMl.cjs.map +1 -0
- package/dist/chunks/{detail-ByZV1XaI.js → detail-Bv90gvy0.js} +578 -577
- package/dist/chunks/detail-Bv90gvy0.js.map +1 -0
- package/dist/chunks/detail-DNzqesdI.cjs +5 -0
- package/dist/chunks/detail-DNzqesdI.cjs.map +1 -0
- package/dist/chunks/instance-error-message-BW464LRQ.cjs +2 -0
- package/dist/chunks/instance-error-message-BW464LRQ.cjs.map +1 -0
- package/dist/chunks/instance-error-message-CAP1vJhX.js +204 -0
- package/dist/chunks/instance-error-message-CAP1vJhX.js.map +1 -0
- package/dist/components/approval-instance-field-filter-controls.d.cts +12 -0
- package/dist/components/approval-instance-field-filter-controls.d.ts +12 -0
- package/dist/components/approval-instance-field-filters.d.cts +86 -0
- package/dist/components/approval-instance-field-filters.d.ts +86 -0
- package/dist/components/approval-instance-list-page.d.cts +4 -0
- package/dist/components/approval-instance-list-page.d.ts +4 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/next/workflow-chat-route.cjs +2 -2
- package/dist/next/workflow-chat-route.cjs.map +1 -1
- package/dist/next/workflow-chat-route.js +13 -13
- package/dist/pages/admin/delegations/index.cjs +1 -1
- package/dist/pages/admin/delegations/index.js +1 -1
- package/dist/pages/delegations/index.cjs +1 -1
- package/dist/pages/delegations/index.js +1 -1
- package/dist/pages/instances/detail/index.cjs +1 -1
- package/dist/pages/instances/detail/index.js +1 -1
- package/dist/pages/templates/categories/index.cjs +1 -1
- package/dist/pages/templates/categories/index.js +1 -1
- package/dist/pages/templates/compose/index.cjs +1 -1
- package/dist/pages/templates/compose/index.js +1 -1
- package/dist/pages/templates/designer/index.cjs +1 -1
- package/dist/pages/templates/designer/index.js +1 -1
- package/dist/views/admin/delegations/index.cjs +1 -1
- package/dist/views/admin/delegations/index.js +1 -1
- package/dist/views/admin/index.cjs +1 -1
- package/dist/views/admin/index.js +1 -1
- package/dist/views/admin/webhook-endpoints/index.cjs +1 -1
- package/dist/views/admin/webhook-endpoints/index.cjs.map +1 -1
- package/dist/views/admin/webhook-endpoints/index.js +60 -60
- package/dist/views/admin/webhook-endpoints/index.js.map +1 -1
- package/dist/views/cc/index.cjs +1 -1
- package/dist/views/cc/index.js +1 -1
- package/dist/views/delegations/index.cjs +1 -1
- package/dist/views/delegations/index.js +1 -1
- package/dist/views/forms/builder/FormBuilderView.d.cts +8 -1
- package/dist/views/forms/builder/FormBuilderView.d.ts +8 -1
- package/dist/views/forms/builder/index.cjs +1 -1
- package/dist/views/forms/builder/index.js +1 -1
- package/dist/views/forms/renderer/index.cjs +1 -1
- package/dist/views/forms/renderer/index.js +1 -1
- package/dist/views/instances/approver-filled-form.d.cts +8 -5
- package/dist/views/instances/approver-filled-form.d.ts +8 -5
- package/dist/views/instances/detail/index.cjs +1 -1
- package/dist/views/instances/detail/index.js +1 -1
- package/dist/views/instances/detail/sections/InstanceTasksSection.d.cts +2 -1
- package/dist/views/instances/detail/sections/InstanceTasksSection.d.ts +2 -1
- package/dist/views/instances/new/index.cjs +1 -1
- package/dist/views/instances/new/index.cjs.map +1 -1
- package/dist/views/instances/new/index.js +8 -8
- package/dist/views/instances/new/index.js.map +1 -1
- package/dist/views/search/index.cjs +1 -1
- package/dist/views/search/index.js +1 -1
- package/dist/views/sent/index.cjs +1 -1
- package/dist/views/sent/index.js +1 -1
- package/dist/views/templates/categories/index.cjs +1 -1
- package/dist/views/templates/categories/index.js +1 -1
- package/dist/views/templates/compose/index.cjs +1 -1
- package/dist/views/templates/compose/index.js +1 -1
- package/dist/views/templates/designer/NotifyWebhookTargetsEditor.d.cts +2 -0
- package/dist/views/templates/designer/NotifyWebhookTargetsEditor.d.ts +2 -0
- package/dist/views/templates/designer/index.cjs +1 -1
- package/dist/views/templates/designer/index.js +1 -1
- package/dist/views/templates/index.cjs +1 -1
- package/dist/views/templates/index.cjs.map +1 -1
- package/dist/views/templates/index.js +7 -7
- package/package.json +3 -3
- package/dist/chunks/FormBuilderView-CFRiw04B.js.map +0 -1
- package/dist/chunks/FormBuilderView-CpUgbSbt.cjs +0 -3
- package/dist/chunks/FormBuilderView-CpUgbSbt.cjs.map +0 -1
- package/dist/chunks/approval-instance-list-page-BnI4t5mD.js +0 -279
- package/dist/chunks/approval-instance-list-page-BnI4t5mD.js.map +0 -1
- package/dist/chunks/approval-instance-list-page-fqvmkBlg.cjs +0 -2
- package/dist/chunks/approval-instance-list-page-fqvmkBlg.cjs.map +0 -1
- package/dist/chunks/designer-CX9bhYJS.cjs +0 -69
- package/dist/chunks/designer-CX9bhYJS.cjs.map +0 -1
- package/dist/chunks/designer-CZDlQ9Nf.js.map +0 -1
- package/dist/chunks/detail-ByZV1XaI.js.map +0 -1
- package/dist/chunks/detail-ChseSF55.cjs +0 -5
- package/dist/chunks/detail-ChseSF55.cjs.map +0 -1
- package/dist/chunks/instance-error-message-DTARGbGo.cjs +0 -2
- package/dist/chunks/instance-error-message-DTARGbGo.cjs.map +0 -1
- package/dist/chunks/instance-error-message-q6gy5evy.js +0 -120
- package/dist/chunks/instance-error-message-q6gy5evy.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_Fragment","BPMFormField","Fragment$1","ContentHeader","STACK_STYLE","ROW_STYLE","HEADER_ROW_STYLE","METHOD_OPTIONS","PARAMETER_TYPE_OPTIONS","AUDIT_ACTION_LABELS","EMPTY_DRAFT","AdminWebhookEndpointsView","management","setManagement","useState","endpoints","setEndpoints","loading","setLoading","error","setError","notice","setNotice","draft","setDraft","saving","setSaving","rotating","setRotating","nextSecret","setNextSecret","removeSecret","setRemoveSecret","audits","setAudits","refresh","useCallback","nextManagement","readWorkflowWebhookEndpointManagement","listWorkflowWebhookManagedEndpoints","requestError","readErrorMessage","run","work","rows","useMemo","endpoint","columns","Typography","Badge","formatDateTime","actions","readEditDraft","readTestNotice","testWorkflowWebhookEndpoint","setWorkflowWebhookEndpointActive","handleSaveDraft","saved","parameters","parameter","headers","header","timeoutMs","updateWorkflowWebhookEndpoint","isOriginChanged","createWorkflowWebhookEndpoint","handleRotate","rotateWorkflowWebhookEndpointSecret","enabled","PageHeader","Button","PlusIcon","SectionGroup","Section","Table","EndpointDraftModal","Modal","Toggle","event","Input","AUDIT_COLUMNS","audit","editing","originChanged","replaceHeaders","update","onChange","patch","updateParameter","current","index","updateHeader","text","field","onCancel","Textarea","Select","option","TrashIcon","readParameterType","mode","result","origin","url","id","message"],"sources":["../../../../src/views/admin/webhook-endpoints/AdminWebhookEndpointsView.tsx"],"sourcesContent":["'use client';\n\nimport {\n ChangeEvent,\n CSSProperties,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n Badge,\n Button,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Select,\n Table,\n Textarea,\n Toggle,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { PlusIcon, TrashIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { NotifyWebhookParameterType } from '@rytass/bpm-core-shared/workflow';\nimport {\n WorkflowWebhookEndpointAuditRecord,\n WorkflowWebhookEndpointManagementRecord,\n WorkflowWebhookEndpointTestResultRecord,\n WorkflowWebhookManagedEndpointRecord,\n createWorkflowWebhookEndpoint,\n listWorkflowWebhookEndpointAudits,\n listWorkflowWebhookManagedEndpoints,\n readWorkflowWebhookEndpointManagement,\n rotateWorkflowWebhookEndpointSecret,\n setWorkflowWebhookEndpointActive,\n testWorkflowWebhookEndpoint,\n updateWorkflowWebhookEndpoint,\n} from '@rytass/bpm-core-client/template';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { formatDateTime } from '../../../lib/format-date-time';\n\ntype SelectOption = Readonly<{ id: string; name: string }>;\n\ntype EndpointRow = Readonly<\n Record<string, unknown> & {\n endpoint: WorkflowWebhookManagedEndpointRecord;\n key: string;\n }\n>;\n\ntype AuditRow = Readonly<\n Record<string, unknown> & {\n audit: WorkflowWebhookEndpointAuditRecord;\n key: string;\n }\n>;\n\ntype ParameterDraft = Readonly<{\n description: string;\n key: string;\n label: string;\n required: boolean;\n type: NotifyWebhookParameterType;\n}>;\n\ntype HeaderDraft = Readonly<{ name: string; value: string }>;\n\n/**\n * `mode` decides what can change: a new endpoint (or a new version of one)\n * sets everything; editing keeps the parameter contract and only replaces\n * headers when asked to.\n */\ntype EndpointDraft = Readonly<{\n deprecated: boolean;\n description: string;\n endpointId: string | null;\n headers: readonly HeaderDraft[];\n key: string;\n label: string;\n method: string;\n mode: 'create' | 'edit' | 'version';\n /** The stored URL when editing, to spot a move to another host. */\n originalUrl: string;\n parameters: readonly ParameterDraft[];\n replaceHeaders: boolean;\n signingSecret: string;\n timeoutMs: string;\n url: string;\n version: string;\n}>;\n\nconst STACK_STYLE: CSSProperties = {\n display: 'grid',\n gap: 'var(--mzn-spacing-gap-base)',\n};\n\nconst ROW_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'grid',\n gap: 'var(--mzn-spacing-gap-base)',\n gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) auto auto',\n};\n\nconst HEADER_ROW_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'grid',\n gap: 'var(--mzn-spacing-gap-base)',\n gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 2fr) auto',\n};\n\nconst METHOD_OPTIONS: readonly SelectOption[] = [\n { id: 'POST', name: 'POST' },\n { id: 'PUT', name: 'PUT' },\n { id: 'PATCH', name: 'PATCH' },\n];\n\nconst PARAMETER_TYPE_OPTIONS: readonly SelectOption[] = [\n { id: 'string', name: '文字' },\n { id: 'number', name: '數字' },\n { id: 'boolean', name: '是/否' },\n { id: 'stringArray', name: '文字清單' },\n { id: 'json', name: 'JSON' },\n];\n\nconst AUDIT_ACTION_LABELS: Readonly<\n Record<WorkflowWebhookEndpointAuditRecord['action'], string>\n> = {\n CREATED: '建立',\n DISABLED: '停用',\n ENABLED: '啟用',\n SECRET_ROTATED: '輪替金鑰',\n TEST_SENT: '測試送出',\n UPDATED: '更新',\n};\n\nconst EMPTY_DRAFT: EndpointDraft = {\n deprecated: false,\n description: '',\n endpointId: null,\n headers: [],\n key: '',\n label: '',\n method: 'POST',\n mode: 'create',\n originalUrl: '',\n parameters: [],\n replaceHeaders: true,\n signingSecret: '',\n timeoutMs: '',\n url: '',\n version: '1',\n};\n\n/**\n * Back-office management of database webhook endpoints (ADR 18 §3.13):\n * create, edit, disable, rotate the signing secret, test-send and read the\n * change history. Header values and secrets are entered here and never shown\n * again. Administrator-only on the server.\n */\nexport function AdminWebhookEndpointsView(): ReactElement {\n const [management, setManagement] =\n useState<WorkflowWebhookEndpointManagementRecord | null>(null);\n const [endpoints, setEndpoints] = useState<\n readonly WorkflowWebhookManagedEndpointRecord[]\n >([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [notice, setNotice] = useState<string | null>(null);\n const [draft, setDraft] = useState<EndpointDraft | null>(null);\n const [saving, setSaving] = useState(false);\n const [rotating, setRotating] =\n useState<WorkflowWebhookManagedEndpointRecord | null>(null);\n const [nextSecret, setNextSecret] = useState('');\n const [removeSecret, setRemoveSecret] = useState(false);\n const [audits, setAudits] = useState<{\n readonly endpoint: WorkflowWebhookManagedEndpointRecord;\n readonly records: readonly WorkflowWebhookEndpointAuditRecord[];\n } | null>(null);\n\n const refresh = useCallback(async (): Promise<void> => {\n setLoading(true);\n\n try {\n const nextManagement = await readWorkflowWebhookEndpointManagement();\n\n setManagement(nextManagement);\n setEndpoints(\n nextManagement.enabled\n ? await listWorkflowWebhookManagedEndpoints()\n : [],\n );\n setError(null);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect((): void => {\n void refresh();\n }, [refresh]);\n\n const run = useCallback(\n async (work: () => Promise<string | null>): Promise<boolean> => {\n setError(null);\n setNotice(null);\n\n try {\n setNotice(await work());\n await refresh();\n\n return true;\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n\n return false;\n }\n },\n [refresh],\n );\n\n const rows = useMemo(\n (): EndpointRow[] =>\n endpoints.map((endpoint) => ({ endpoint, key: endpoint.id })),\n [endpoints],\n );\n\n const columns = useMemo(\n (): TableColumn<EndpointRow>[] => [\n {\n key: 'label',\n render: ({ endpoint }: EndpointRow): ReactElement => (\n <div style={STACK_STYLE}>\n <Typography component=\"span\" variant=\"body\">\n {endpoint.label}\n </Typography>\n <Typography color=\"text-neutral\" component=\"span\" variant=\"caption\">\n {endpoint.key}@{endpoint.version} · 參數{' '}\n {endpoint.parameters.length} 個\n </Typography>\n </div>\n ),\n title: '端點',\n width: 240,\n },\n {\n key: 'url',\n render: ({ endpoint }: EndpointRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {endpoint.method} {endpoint.url}\n </Typography>\n ),\n title: 'URL',\n width: 320,\n },\n {\n key: 'status',\n render: ({ endpoint }: EndpointRow): ReactElement =>\n !endpoint.active ? (\n <Badge size=\"sub\" text=\"已停用\" variant=\"dot-inactive\" />\n ) : endpoint.deprecated ? (\n <Badge size=\"sub\" text=\"不建議使用\" variant=\"dot-warning\" />\n ) : (\n <Badge size=\"sub\" text=\"啟用中\" variant=\"dot-success\" />\n ),\n title: '狀態',\n width: 120,\n },\n {\n key: 'credentials',\n render: ({ endpoint }: EndpointRow): ReactElement => (\n <div style={STACK_STYLE}>\n <Typography component=\"span\" variant=\"body\">\n {endpoint.hasSigningSecret ? '已設定簽章金鑰' : '未簽章'}\n </Typography>\n <Typography color=\"text-neutral\" component=\"span\" variant=\"caption\">\n {endpoint.headerNames.length\n ? `Header:${endpoint.headerNames.join('、')}`\n : '沒有自訂 header'}\n </Typography>\n </div>\n ),\n title: '憑證',\n width: 200,\n },\n {\n key: 'updatedAt',\n render: ({ endpoint }: EndpointRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(endpoint.updatedAt)}\n </Typography>\n ),\n title: '更新時間',\n width: 180,\n },\n ],\n [],\n );\n\n const actions = useMemo(\n (): TableActions<EndpointRow> => ({\n render: ({\n endpoint,\n }): ReturnType<TableActions<EndpointRow>['render']> => [\n {\n name: '編輯',\n onClick: (): void => setDraft(readEditDraft(endpoint, 'edit')),\n },\n {\n name: '建立新版本',\n onClick: (): void => setDraft(readEditDraft(endpoint, 'version')),\n },\n {\n name: '測試送出',\n onClick: (): void => {\n void run(async () =>\n readTestNotice(\n endpoint,\n await testWorkflowWebhookEndpoint(endpoint.id),\n ),\n );\n },\n },\n {\n name: '輪替金鑰',\n onClick: (): void => {\n setNextSecret('');\n setRemoveSecret(false);\n setRotating(endpoint);\n },\n },\n {\n name: endpoint.active ? '停用' : '啟用',\n onClick: (): void => {\n void run(async () => {\n await setWorkflowWebhookEndpointActive(\n endpoint.id,\n !endpoint.active,\n );\n\n return `已${endpoint.active ? '停用' : '啟用'}「${endpoint.label}」。`;\n });\n },\n },\n {\n name: '異動紀錄',\n onClick: (): void => {\n void listWorkflowWebhookEndpointAudits(endpoint.id)\n .then((records): void => setAudits({ endpoint, records }))\n .catch((requestError: unknown): void =>\n setError(readErrorMessage(requestError)),\n );\n },\n },\n ],\n variant: 'base-secondary',\n width: 180,\n }),\n [run],\n );\n\n async function handleSaveDraft(): Promise<void> {\n if (!draft) {\n return;\n }\n\n setSaving(true);\n\n const saved = await run(async () => {\n const parameters = draft.parameters.map((parameter) => ({\n description: parameter.description.trim() || null,\n key: parameter.key.trim(),\n label: parameter.label.trim(),\n required: parameter.required,\n type: parameter.type,\n }));\n const headers = draft.headers\n .filter((header) => header.name.trim())\n .map((header) => ({ name: header.name.trim(), value: header.value }));\n const timeoutMs = draft.timeoutMs.trim() ? Number(draft.timeoutMs) : null;\n\n if (draft.mode === 'edit' && draft.endpointId) {\n await updateWorkflowWebhookEndpoint({\n deprecated: draft.deprecated,\n description: draft.description,\n headers:\n draft.replaceHeaders || isOriginChanged(draft) ? headers : null,\n id: draft.endpointId,\n label: draft.label,\n method: draft.method,\n parameters,\n timeoutMs,\n url: draft.url,\n });\n\n return `已更新「${draft.label}」。`;\n }\n\n await createWorkflowWebhookEndpoint({\n deprecated: draft.deprecated,\n description: draft.description,\n headers,\n key: draft.key,\n label: draft.label,\n method: draft.method,\n parameters,\n signingSecret: draft.signingSecret || null,\n timeoutMs,\n url: draft.url,\n version: Number(draft.version),\n });\n\n return `已建立「${draft.label}」v${draft.version},設計器現在可以選用。`;\n });\n\n setSaving(false);\n\n if (saved) {\n setDraft(null);\n }\n }\n\n async function handleRotate(): Promise<void> {\n if (!rotating) {\n return;\n }\n\n const endpoint = rotating;\n const done = await run(async () => {\n await rotateWorkflowWebhookEndpointSecret(\n endpoint.id,\n removeSecret ? null : nextSecret,\n );\n\n return removeSecret\n ? `已移除「${endpoint.label}」的簽章金鑰,之後的請求不再簽章。`\n : `已輪替「${endpoint.label}」的簽章金鑰,接收端需改用新金鑰驗簽。`;\n });\n\n if (done) {\n setRotating(null);\n setNextSecret('');\n }\n }\n\n const enabled = Boolean(management?.enabled);\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"維護知會節點可呼叫的外部系統端點。Header 值與簽章金鑰加密保存,儲存後不會再顯示。\"\n title=\"Webhook 端點\"\n >\n <Button\n disabled={!enabled}\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => setDraft(EMPTY_DRAFT)}\n variant=\"base-primary\"\n >\n 新增端點\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <div style={STACK_STYLE}>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {notice ? (\n <Typography color=\"text-success\" variant=\"body\">\n {notice}\n </Typography>\n ) : null}\n {management && !enabled ? (\n <Typography color=\"text-warning\" variant=\"body\">\n 此伺服器未啟用後台維護的 Webhook 端點:需要設定\n workflowWebhookTargetSources 含 DATABASE、URL\n 白名單與加密金鑰。程式註冊的端點不受影響。\n </Typography>\n ) : null}\n {enabled ? (\n <Typography color=\"text-neutral\" variant=\"caption\">\n 允許的 URL:{management?.allowedUrlPatterns.join('、')}\n </Typography>\n ) : null}\n <Table\n actions={actions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n />\n </div>\n </Section>\n </SectionGroup>\n\n {draft ? (\n <EndpointDraftModal\n draft={draft}\n onCancel={(): void => setDraft(null)}\n onChange={setDraft}\n onConfirm={(): void => void handleSaveDraft()}\n saving={saving}\n />\n ) : null}\n\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{ disabled: !removeSecret && !nextSecret }}\n confirmText={removeSecret ? '移除金鑰' : '輪替金鑰'}\n modalType=\"standard\"\n onCancel={(): void => setRotating(null)}\n onClose={(): void => setRotating(null)}\n onConfirm={(): void => void handleRotate()}\n open={Boolean(rotating)}\n showModalFooter\n showModalHeader\n supportingText=\"新金鑰會加密保存,不會再顯示;請同時更新接收端的驗簽金鑰。\"\n title={`輪替簽章金鑰:${rotating?.label ?? ''}`}\n >\n <div style={STACK_STYLE}>\n <BPMFormField label=\"移除金鑰\" name=\"removeSigningSecret\">\n <Toggle\n checked={removeSecret}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n setRemoveSecret(event.target.checked)\n }\n />\n </BPMFormField>\n {removeSecret ? null : (\n <BPMFormField label=\"新金鑰\" name=\"nextSigningSecret\" required>\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n setNextSecret(event.target.value)\n }\n value={nextSecret}\n inputProps={{ autoComplete: 'new-password' }}\n variant=\"password\"\n />\n </BPMFormField>\n )}\n </div>\n </Modal>\n\n <Modal\n confirmText=\"關閉\"\n modalType=\"standard\"\n onClose={(): void => setAudits(null)}\n onConfirm={(): void => setAudits(null)}\n open={Boolean(audits)}\n showModalFooter\n showModalHeader\n size=\"wide\"\n supportingText=\"只記錄誰在何時變更了哪些欄位,不記錄任何值。\"\n title={`異動紀錄:${audits?.endpoint.label ?? ''}`}\n >\n <Table\n columns={AUDIT_COLUMNS}\n dataSource={(audits?.records ?? []).map((audit): AuditRow => ({\n audit,\n key: audit.id,\n }))}\n fullWidth\n />\n </Modal>\n </>\n );\n}\n\nconst AUDIT_COLUMNS: TableColumn<AuditRow>[] = [\n {\n key: 'createdAt',\n render: ({ audit }: AuditRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(audit.createdAt)}\n </Typography>\n ),\n title: '時間',\n width: 180,\n },\n {\n key: 'action',\n render: ({ audit }: AuditRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {AUDIT_ACTION_LABELS[audit.action]}\n </Typography>\n ),\n title: '動作',\n width: 120,\n },\n {\n key: 'changedFields',\n render: ({ audit }: AuditRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {audit.changedFields.join('、') || '—'}\n </Typography>\n ),\n title: '欄位',\n width: 280,\n },\n {\n key: 'actor',\n render: ({ audit }: AuditRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {audit.actorMemberId ?? '系統'}\n </Typography>\n ),\n title: '操作者',\n width: 160,\n },\n];\n\nfunction EndpointDraftModal({\n draft,\n onCancel,\n onChange,\n onConfirm,\n saving,\n}: {\n readonly draft: EndpointDraft;\n readonly onCancel: () => void;\n readonly onChange: (draft: EndpointDraft) => void;\n readonly onConfirm: () => void;\n readonly saving: boolean;\n}): ReactElement {\n const editing = draft.mode === 'edit';\n // Stored header values must not follow the URL to another host, so a new\n // host always means entering the headers again.\n const originChanged = isOriginChanged(draft);\n const replaceHeaders = draft.replaceHeaders || originChanged;\n const update = (patch: Partial<EndpointDraft>): void =>\n onChange({ ...draft, ...patch });\n const updateParameter = (\n index: number,\n patch: Partial<ParameterDraft>,\n ): void =>\n update({\n parameters: draft.parameters.map((parameter, current) =>\n current === index ? { ...parameter, ...patch } : parameter,\n ),\n });\n const updateHeader = (index: number, patch: Partial<HeaderDraft>): void =>\n update({\n headers: draft.headers.map((header, current) =>\n current === index ? { ...header, ...patch } : header,\n ),\n });\n const text =\n (field: keyof EndpointDraft) =>\n (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>): void =>\n update({ [field]: event.target.value });\n\n return (\n <Modal\n cancelText=\"取消\"\n confirmText={editing ? '儲存' : '建立'}\n loading={saving}\n modalType=\"standard\"\n onCancel={onCancel}\n onClose={onCancel}\n onConfirm={onConfirm}\n open\n showModalFooter\n showModalHeader\n size=\"wide\"\n supportingText={\n editing\n ? '參數的鍵、型別與必填是這個版本的契約,無法修改;需要變更請建立新版本。'\n : draft.mode === 'version'\n ? '新版本可調整參數;既有模板仍使用舊版本,直到設計者改選。'\n : 'URL 需符合伺服器設定的白名單。'\n }\n title={\n editing\n ? `編輯端點:${draft.label}`\n : draft.mode === 'version'\n ? `建立新版本:${draft.key}`\n : '新增 Webhook 端點'\n }\n >\n <div style={STACK_STYLE}>\n <BPMFormField label=\"Key\" name=\"endpointKey\" required>\n <Input\n {...(draft.mode === 'create' ? {} : { readonly: true as const })}\n onChange={text('key')}\n placeholder=\"例如 crm.lead-created\"\n value={draft.key}\n inputProps={{ autoComplete: 'off' }}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"版本\" name=\"endpointVersion\" required>\n <Input\n {...(editing ? { readonly: true as const } : {})}\n inputProps={{ autoComplete: 'off', inputMode: 'numeric' }}\n onChange={text('version')}\n value={draft.version}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"名稱\" name=\"endpointLabel\" required>\n <Input\n onChange={text('label')}\n placeholder=\"例如 CRM 建立名單\"\n value={draft.label}\n inputProps={{ autoComplete: 'off' }}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"說明\" name=\"endpointDescription\">\n <Textarea\n onChange={text('description')}\n rows={2}\n value={draft.description}\n />\n </BPMFormField>\n <BPMFormField label=\"URL\" name=\"endpointUrl\" required>\n <Input\n onChange={text('url')}\n placeholder=\"https://\"\n value={draft.url}\n inputProps={{ autoComplete: 'off' }}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"Method\" name=\"endpointMethod\" required>\n <Select\n clearable={false}\n onChange={(option): void =>\n update({ method: option?.id ?? 'POST' })\n }\n options={[...METHOD_OPTIONS]}\n value={\n METHOD_OPTIONS.find((option) => option.id === draft.method) ??\n null\n }\n />\n </BPMFormField>\n <BPMFormField\n hintText=\"留空使用預設 10 秒,上限 30000 毫秒。\"\n label=\"逾時(毫秒)\"\n name=\"endpointTimeout\"\n >\n <Input\n inputProps={{ autoComplete: 'off', inputMode: 'numeric' }}\n onChange={text('timeoutMs')}\n value={draft.timeoutMs}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"不建議使用\" name=\"endpointDeprecated\">\n <Toggle\n checked={draft.deprecated}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n update({ deprecated: event.target.checked })\n }\n />\n </BPMFormField>\n {editing ? null : (\n <BPMFormField\n hintText=\"選填;設定後 BPM 以 HMAC-SHA256 簽章,儲存後不會再顯示。\"\n label=\"簽章金鑰\"\n name=\"endpointSigningSecret\"\n >\n <Input\n onChange={text('signingSecret')}\n placeholder=\"選填,儲存後不再顯示\"\n value={draft.signingSecret}\n inputProps={{ autoComplete: 'new-password' }}\n variant=\"password\"\n />\n </BPMFormField>\n )}\n\n <Typography variant=\"label-primary-highlight\">Headers</Typography>\n {editing ? (\n <BPMFormField\n hintText={\n originChanged\n ? 'URL 已改到其他主機,必須重新輸入 header(留空代表不帶任何 header)。'\n : '現有 header 的值不會顯示;開啟後以下列內容取代全部 header。'\n }\n label=\"取代 headers\"\n name=\"endpointReplaceHeaders\"\n >\n <Toggle\n checked={replaceHeaders}\n disabled={originChanged}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n update({ replaceHeaders: event.target.checked })\n }\n />\n </BPMFormField>\n ) : null}\n {replaceHeaders\n ? draft.headers.map((header, index): ReactElement => (\n <div key={index} style={HEADER_ROW_STYLE}>\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateHeader(index, { name: event.target.value })\n }\n placeholder=\"名稱,例如 Authorization\"\n inputProps={{ autoComplete: 'off' }}\n value={header.name}\n variant=\"base\"\n />\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateHeader(index, { value: event.target.value })\n }\n placeholder=\"值\"\n value={header.value}\n inputProps={{ autoComplete: 'new-password' }}\n variant=\"password\"\n />\n <Button\n icon={TrashIcon}\n iconType=\"icon-only\"\n onClick={(): void =>\n update({\n headers: draft.headers.filter(\n (_header, current) => current !== index,\n ),\n })\n }\n variant=\"destructive-text-link\"\n >\n 移除 header\n </Button>\n </div>\n ))\n : null}\n {replaceHeaders ? (\n <div>\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void =>\n update({ headers: [...draft.headers, { name: '', value: '' }] })\n }\n variant=\"base-dashed\"\n >\n 新增 header\n </Button>\n </div>\n ) : null}\n\n <Typography variant=\"label-primary-highlight\">參數</Typography>\n {draft.parameters.map((parameter, index): ReactElement => (\n <div key={index} style={ROW_STYLE}>\n <Input\n {...(editing ? { readonly: true as const } : {})}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateParameter(index, { key: event.target.value })\n }\n placeholder=\"參數鍵\"\n inputProps={{ autoComplete: 'off' }}\n value={parameter.key}\n variant=\"base\"\n />\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateParameter(index, { label: event.target.value })\n }\n placeholder=\"顯示名稱\"\n inputProps={{ autoComplete: 'off' }}\n value={parameter.label}\n variant=\"base\"\n />\n <Select\n clearable={false}\n disabled={editing}\n onChange={(option): void =>\n updateParameter(index, {\n type: readParameterType(option?.id ?? null),\n })\n }\n options={[...PARAMETER_TYPE_OPTIONS]}\n value={\n PARAMETER_TYPE_OPTIONS.find(\n (option) => option.id === parameter.type,\n ) ?? null\n }\n />\n <Toggle\n checked={parameter.required}\n disabled={editing}\n label=\"必填\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateParameter(index, { required: event.target.checked })\n }\n />\n <Button\n disabled={editing}\n icon={TrashIcon}\n iconType=\"icon-only\"\n onClick={(): void =>\n update({\n parameters: draft.parameters.filter(\n (_parameter, current) => current !== index,\n ),\n })\n }\n variant=\"destructive-text-link\"\n >\n 移除參數\n </Button>\n </div>\n ))}\n {editing ? null : (\n <div>\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void =>\n update({\n parameters: [\n ...draft.parameters,\n {\n description: '',\n key: '',\n label: '',\n required: false,\n type: 'string',\n },\n ],\n })\n }\n variant=\"base-dashed\"\n >\n 新增參數\n </Button>\n </div>\n )}\n </div>\n </Modal>\n );\n}\n\nfunction readEditDraft(\n endpoint: WorkflowWebhookManagedEndpointRecord,\n mode: 'edit' | 'version',\n): EndpointDraft {\n return {\n deprecated: endpoint.deprecated,\n description: endpoint.description ?? '',\n endpointId: mode === 'edit' ? endpoint.id : null,\n headers: [],\n key: endpoint.key,\n label: endpoint.label,\n method: endpoint.method,\n mode,\n originalUrl: endpoint.url,\n parameters: endpoint.parameters.map((parameter) => ({\n description: parameter.description ?? '',\n key: parameter.key,\n label: parameter.label,\n required: parameter.required,\n type: parameter.type,\n })),\n // A new version starts without credentials: they are not readable.\n replaceHeaders: mode === 'version',\n signingSecret: '',\n timeoutMs: endpoint.timeoutMs ? String(endpoint.timeoutMs) : '',\n url: endpoint.url,\n version: String(\n mode === 'version' ? endpoint.version + 1 : endpoint.version,\n ),\n };\n}\n\nfunction readTestNotice(\n endpoint: WorkflowWebhookManagedEndpointRecord,\n result: WorkflowWebhookEndpointTestResultRecord,\n): string {\n if (result.ok) {\n return `測試送出成功:「${endpoint.label}」回應 HTTP ${result.status ?? ''}。`;\n }\n\n throw new Error(\n `測試送出失敗:「${endpoint.label}」${result.status ? `回應 HTTP ${result.status}` : ''}(${result.errorCode ?? '未知錯誤'})${result.errorDetail ? `:${result.errorDetail}` : ''}`,\n );\n}\n\nfunction isOriginChanged(draft: EndpointDraft): boolean {\n if (draft.mode !== 'edit') {\n return false;\n }\n\n const origin = (url: string): string => {\n try {\n return new URL(url.trim()).origin;\n } catch {\n return url.trim();\n }\n };\n\n return origin(draft.url) !== origin(draft.originalUrl);\n}\n\nfunction readParameterType(id: string | null): NotifyWebhookParameterType {\n return PARAMETER_TYPE_OPTIONS.some((option) => option.id === id)\n ? (id as NotifyWebhookParameterType)\n : 'string';\n}\n\nfunction readErrorMessage(error: unknown): string {\n if (!(error instanceof Error)) {\n return '發生未知錯誤';\n }\n\n const message = error.message;\n\n if (message.includes('WORKFLOW_WEBHOOK_URL_NOT_ALLOWED')) {\n return 'URL 不在伺服器允許的白名單內。';\n }\n\n if (message.includes('WORKFLOW_WEBHOOK_ENDPOINT_KEY_CONFLICT')) {\n return '這個 Key 已由程式註冊的端點使用,請換一個。';\n }\n\n if (message.includes('WORKFLOW_WEBHOOK_ENDPOINT_CONTRACT_CHANGED')) {\n return '參數契約不能修改,請改用「建立新版本」。';\n }\n\n if (message.includes('WORKFLOW_WEBHOOK_TEST_RATE_LIMITED')) {\n return '測試送出太頻繁,請稍後再試(每 10 秒一次、10 分鐘最多 5 次)。';\n }\n\n return message;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["_Fragment","BPMFormField","Fragment$1","ContentHeader","STACK_STYLE","ROW_STYLE","HEADER_ROW_STYLE","METHOD_OPTIONS","PARAMETER_TYPE_OPTIONS","AUDIT_ACTION_LABELS","EMPTY_DRAFT","AdminWebhookEndpointsView","management","setManagement","useState","endpoints","setEndpoints","loading","setLoading","error","setError","notice","setNotice","draft","setDraft","saving","setSaving","rotating","setRotating","nextSecret","setNextSecret","removeSecret","setRemoveSecret","audits","setAudits","refresh","useCallback","nextManagement","readWorkflowWebhookEndpointManagement","listWorkflowWebhookManagedEndpoints","requestError","readErrorMessage","run","work","rows","useMemo","endpoint","columns","Typography","Badge","formatDateTime","actions","readEditDraft","readTestNotice","testWorkflowWebhookEndpoint","setWorkflowWebhookEndpointActive","handleSaveDraft","saved","parameters","parameter","headers","header","timeoutMs","updateWorkflowWebhookEndpoint","isOriginChanged","createWorkflowWebhookEndpoint","handleRotate","rotateWorkflowWebhookEndpointSecret","enabled","PageHeader","Button","PlusIcon","SectionGroup","Section","Table","EndpointDraftModal","Modal","Toggle","event","Input","AUDIT_COLUMNS","audit","editing","originChanged","replaceHeaders","update","onChange","patch","updateParameter","current","index","updateHeader","text","field","onCancel","Textarea","Select","option","TrashIcon","readParameterType","mode","result","origin","url","id","message"],"sources":["../../../../src/views/admin/webhook-endpoints/AdminWebhookEndpointsView.tsx"],"sourcesContent":["'use client';\n\nimport {\n ChangeEvent,\n CSSProperties,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n Badge,\n Button,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Select,\n Table,\n Textarea,\n Toggle,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { PlusIcon, TrashIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { NotifyWebhookParameterType } from '@rytass/bpm-core-shared/workflow';\nimport {\n WorkflowWebhookEndpointAuditRecord,\n WorkflowWebhookEndpointManagementRecord,\n WorkflowWebhookEndpointTestResultRecord,\n WorkflowWebhookManagedEndpointRecord,\n createWorkflowWebhookEndpoint,\n listWorkflowWebhookEndpointAudits,\n listWorkflowWebhookManagedEndpoints,\n readWorkflowWebhookEndpointManagement,\n rotateWorkflowWebhookEndpointSecret,\n setWorkflowWebhookEndpointActive,\n testWorkflowWebhookEndpoint,\n updateWorkflowWebhookEndpoint,\n} from '@rytass/bpm-core-client/template';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { formatDateTime } from '../../../lib/format-date-time';\n\ntype SelectOption = Readonly<{ id: string; name: string }>;\n\ntype EndpointRow = Readonly<\n Record<string, unknown> & {\n endpoint: WorkflowWebhookManagedEndpointRecord;\n key: string;\n }\n>;\n\ntype AuditRow = Readonly<\n Record<string, unknown> & {\n audit: WorkflowWebhookEndpointAuditRecord;\n key: string;\n }\n>;\n\ntype ParameterDraft = Readonly<{\n description: string;\n key: string;\n label: string;\n required: boolean;\n type: NotifyWebhookParameterType;\n}>;\n\ntype HeaderDraft = Readonly<{ name: string; value: string }>;\n\n/**\n * `mode` decides what can change: a new endpoint (or a new version of one)\n * sets everything; editing keeps the parameter contract and only replaces\n * headers when asked to.\n */\ntype EndpointDraft = Readonly<{\n deprecated: boolean;\n description: string;\n endpointId: string | null;\n headers: readonly HeaderDraft[];\n key: string;\n label: string;\n method: string;\n mode: 'create' | 'edit' | 'version';\n /** The stored URL when editing, to spot a move to another host. */\n originalUrl: string;\n parameters: readonly ParameterDraft[];\n replaceHeaders: boolean;\n signingSecret: string;\n timeoutMs: string;\n url: string;\n version: string;\n}>;\n\nconst STACK_STYLE: CSSProperties = {\n display: 'grid',\n gap: 'var(--mzn-spacing-gap-base)',\n};\n\nconst ROW_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'grid',\n gap: 'var(--mzn-spacing-gap-base)',\n gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) auto auto',\n};\n\nconst HEADER_ROW_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'grid',\n gap: 'var(--mzn-spacing-gap-base)',\n gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 2fr) auto',\n};\n\nconst METHOD_OPTIONS: readonly SelectOption[] = [\n { id: 'POST', name: 'POST' },\n { id: 'PUT', name: 'PUT' },\n { id: 'PATCH', name: 'PATCH' },\n];\n\nconst PARAMETER_TYPE_OPTIONS: readonly SelectOption[] = [\n { id: 'string', name: '文字' },\n { id: 'number', name: '數字' },\n { id: 'boolean', name: '是/否' },\n { id: 'stringArray', name: '文字清單' },\n { id: 'json', name: 'JSON' },\n];\n\nconst AUDIT_ACTION_LABELS: Readonly<\n Record<WorkflowWebhookEndpointAuditRecord['action'], string>\n> = {\n CREATED: '建立',\n DISABLED: '停用',\n ENABLED: '啟用',\n SECRET_ROTATED: '輪替金鑰',\n TEST_SENT: '測試送出',\n UPDATED: '更新',\n};\n\nconst EMPTY_DRAFT: EndpointDraft = {\n deprecated: false,\n description: '',\n endpointId: null,\n headers: [],\n key: '',\n label: '',\n method: 'POST',\n mode: 'create',\n originalUrl: '',\n parameters: [],\n replaceHeaders: true,\n signingSecret: '',\n timeoutMs: '',\n url: '',\n version: '1',\n};\n\n/**\n * Back-office management of database webhook endpoints (ADR 18 §3.13):\n * create, edit, disable, rotate the signing secret, test-send and read the\n * change history. Header values and secrets are entered here and never shown\n * again. Administrator-only on the server.\n */\nexport function AdminWebhookEndpointsView(): ReactElement {\n const [management, setManagement] =\n useState<WorkflowWebhookEndpointManagementRecord | null>(null);\n const [endpoints, setEndpoints] = useState<\n readonly WorkflowWebhookManagedEndpointRecord[]\n >([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [notice, setNotice] = useState<string | null>(null);\n const [draft, setDraft] = useState<EndpointDraft | null>(null);\n const [saving, setSaving] = useState(false);\n const [rotating, setRotating] =\n useState<WorkflowWebhookManagedEndpointRecord | null>(null);\n const [nextSecret, setNextSecret] = useState('');\n const [removeSecret, setRemoveSecret] = useState(false);\n const [audits, setAudits] = useState<{\n readonly endpoint: WorkflowWebhookManagedEndpointRecord;\n readonly records: readonly WorkflowWebhookEndpointAuditRecord[];\n } | null>(null);\n\n const refresh = useCallback(async (): Promise<void> => {\n setLoading(true);\n\n try {\n const nextManagement = await readWorkflowWebhookEndpointManagement();\n\n setManagement(nextManagement);\n setEndpoints(\n nextManagement.enabled\n ? await listWorkflowWebhookManagedEndpoints()\n : [],\n );\n setError(null);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect((): void => {\n void refresh();\n }, [refresh]);\n\n const run = useCallback(\n async (work: () => Promise<string | null>): Promise<boolean> => {\n setError(null);\n setNotice(null);\n\n try {\n setNotice(await work());\n await refresh();\n\n return true;\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n\n return false;\n }\n },\n [refresh],\n );\n\n const rows = useMemo(\n (): EndpointRow[] =>\n endpoints.map((endpoint) => ({ endpoint, key: endpoint.id })),\n [endpoints],\n );\n\n const columns = useMemo(\n (): TableColumn<EndpointRow>[] => [\n {\n key: 'label',\n render: ({ endpoint }: EndpointRow): ReactElement => (\n <div style={STACK_STYLE}>\n <Typography component=\"span\" variant=\"body\">\n {endpoint.label}\n </Typography>\n <Typography color=\"text-neutral\" component=\"span\" variant=\"caption\">\n {endpoint.key}@{endpoint.version} · 參數{' '}\n {endpoint.parameters.length} 個\n </Typography>\n </div>\n ),\n title: '端點',\n width: 240,\n },\n {\n key: 'url',\n render: ({ endpoint }: EndpointRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {endpoint.method} {endpoint.url}\n </Typography>\n ),\n title: 'URL',\n width: 320,\n },\n {\n key: 'status',\n render: ({ endpoint }: EndpointRow): ReactElement =>\n !endpoint.active ? (\n <Badge size=\"sub\" text=\"已停用\" variant=\"dot-inactive\" />\n ) : endpoint.deprecated ? (\n <Badge size=\"sub\" text=\"不建議使用\" variant=\"dot-warning\" />\n ) : (\n <Badge size=\"sub\" text=\"啟用中\" variant=\"dot-success\" />\n ),\n title: '狀態',\n width: 120,\n },\n {\n key: 'credentials',\n render: ({ endpoint }: EndpointRow): ReactElement => (\n <div style={STACK_STYLE}>\n <Typography component=\"span\" variant=\"body\">\n {endpoint.hasSigningSecret ? '已設定簽章金鑰' : '未簽章'}\n </Typography>\n <Typography color=\"text-neutral\" component=\"span\" variant=\"caption\">\n {endpoint.headerNames.length\n ? `Header:${endpoint.headerNames.join('、')}`\n : '沒有自訂 header'}\n </Typography>\n </div>\n ),\n title: '憑證',\n width: 200,\n },\n {\n key: 'updatedAt',\n render: ({ endpoint }: EndpointRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(endpoint.updatedAt)}\n </Typography>\n ),\n title: '更新時間',\n width: 180,\n },\n ],\n [],\n );\n\n const actions = useMemo(\n (): TableActions<EndpointRow> => ({\n render: ({\n endpoint,\n }): ReturnType<TableActions<EndpointRow>['render']> => [\n {\n name: '編輯',\n onClick: (): void => setDraft(readEditDraft(endpoint, 'edit')),\n },\n {\n name: '建立新版本',\n onClick: (): void => setDraft(readEditDraft(endpoint, 'version')),\n },\n {\n name: '測試送出',\n onClick: (): void => {\n void run(async () =>\n readTestNotice(\n endpoint,\n await testWorkflowWebhookEndpoint(endpoint.id),\n ),\n );\n },\n },\n {\n name: '輪替金鑰',\n onClick: (): void => {\n setNextSecret('');\n setRemoveSecret(false);\n setRotating(endpoint);\n },\n },\n {\n name: endpoint.active ? '停用' : '啟用',\n onClick: (): void => {\n void run(async () => {\n await setWorkflowWebhookEndpointActive(\n endpoint.id,\n !endpoint.active,\n );\n\n return `已${endpoint.active ? '停用' : '啟用'}「${endpoint.label}」。`;\n });\n },\n },\n {\n name: '異動紀錄',\n onClick: (): void => {\n void listWorkflowWebhookEndpointAudits(endpoint.id)\n .then((records): void => setAudits({ endpoint, records }))\n .catch((requestError: unknown): void =>\n setError(readErrorMessage(requestError)),\n );\n },\n },\n ],\n variant: 'base-secondary',\n width: 180,\n }),\n [run],\n );\n\n async function handleSaveDraft(): Promise<void> {\n if (!draft) {\n return;\n }\n\n setSaving(true);\n\n const saved = await run(async () => {\n const parameters = draft.parameters.map((parameter) => ({\n description: parameter.description.trim() || null,\n key: parameter.key.trim(),\n label: parameter.label.trim(),\n required: parameter.required,\n type: parameter.type,\n }));\n const headers = draft.headers\n .filter((header) => header.name.trim())\n .map((header) => ({ name: header.name.trim(), value: header.value }));\n const timeoutMs = draft.timeoutMs.trim() ? Number(draft.timeoutMs) : null;\n\n if (draft.mode === 'edit' && draft.endpointId) {\n await updateWorkflowWebhookEndpoint({\n deprecated: draft.deprecated,\n description: draft.description,\n headers:\n draft.replaceHeaders || isOriginChanged(draft) ? headers : null,\n id: draft.endpointId,\n label: draft.label,\n method: draft.method,\n parameters,\n timeoutMs,\n url: draft.url,\n });\n\n return `已更新「${draft.label}」。`;\n }\n\n await createWorkflowWebhookEndpoint({\n deprecated: draft.deprecated,\n description: draft.description,\n headers,\n key: draft.key,\n label: draft.label,\n method: draft.method,\n parameters,\n signingSecret: draft.signingSecret || null,\n timeoutMs,\n url: draft.url,\n version: Number(draft.version),\n });\n\n return `已建立「${draft.label}」v${draft.version},設計器現在可以選用。`;\n });\n\n setSaving(false);\n\n if (saved) {\n setDraft(null);\n }\n }\n\n async function handleRotate(): Promise<void> {\n if (!rotating) {\n return;\n }\n\n const endpoint = rotating;\n const done = await run(async () => {\n await rotateWorkflowWebhookEndpointSecret(\n endpoint.id,\n removeSecret ? null : nextSecret,\n );\n\n return removeSecret\n ? `已移除「${endpoint.label}」的簽章金鑰,之後的請求不再簽章。`\n : `已輪替「${endpoint.label}」的簽章金鑰,接收端需改用新金鑰驗簽。`;\n });\n\n if (done) {\n setRotating(null);\n setNextSecret('');\n }\n }\n\n const enabled = Boolean(management?.enabled);\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"維護知會節點可呼叫的外部系統端點。Header 值與簽章金鑰加密保存,儲存後不會再顯示。\"\n title=\"Webhook 端點\"\n >\n <Button\n disabled={!enabled}\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => setDraft(EMPTY_DRAFT)}\n variant=\"base-primary\"\n >\n 新增端點\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n <div style={STACK_STYLE}>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {notice ? (\n <Typography color=\"text-success\" variant=\"body\">\n {notice}\n </Typography>\n ) : null}\n {management && !enabled ? (\n <Typography color=\"text-warning\" variant=\"body\">\n 此伺服器未啟用後台維護的 Webhook 端點:需要設定\n workflowWebhookTargetSources 含 DATABASE、URL\n 白名單與加密金鑰。程式註冊的端點不受影響。\n </Typography>\n ) : null}\n {enabled ? (\n <Typography color=\"text-neutral\" variant=\"caption\">\n 允許的 URL:{management?.allowedUrlPatterns.join('、')}\n </Typography>\n ) : null}\n <Table\n actions={actions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n />\n </div>\n </Section>\n </SectionGroup>\n\n {draft ? (\n <EndpointDraftModal\n draft={draft}\n onCancel={(): void => setDraft(null)}\n onChange={setDraft}\n onConfirm={(): void => void handleSaveDraft()}\n saving={saving}\n />\n ) : null}\n\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{ disabled: !removeSecret && !nextSecret }}\n confirmText={removeSecret ? '移除金鑰' : '輪替金鑰'}\n modalType=\"standard\"\n onCancel={(): void => setRotating(null)}\n onClose={(): void => setRotating(null)}\n onConfirm={(): void => void handleRotate()}\n open={Boolean(rotating)}\n showModalFooter\n showModalHeader\n supportingText=\"新金鑰會加密保存,不會再顯示;請同時更新接收端的驗簽金鑰。\"\n title={`輪替簽章金鑰:${rotating?.label ?? ''}`}\n >\n <div style={STACK_STYLE}>\n <BPMFormField label=\"移除金鑰\" name=\"removeSigningSecret\">\n <Toggle\n checked={removeSecret}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n setRemoveSecret(event.target.checked)\n }\n />\n </BPMFormField>\n {removeSecret ? null : (\n <BPMFormField label=\"新金鑰\" name=\"nextSigningSecret\" required>\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n setNextSecret(event.target.value)\n }\n value={nextSecret}\n inputProps={{ autoComplete: 'new-password' }}\n variant=\"password\"\n />\n </BPMFormField>\n )}\n </div>\n </Modal>\n\n <Modal\n confirmText=\"關閉\"\n modalType=\"standard\"\n onClose={(): void => setAudits(null)}\n onConfirm={(): void => setAudits(null)}\n open={Boolean(audits)}\n showModalFooter\n showModalHeader\n size=\"wide\"\n supportingText=\"只記錄誰在何時變更了哪些欄位,不記錄任何值。\"\n title={`異動紀錄:${audits?.endpoint.label ?? ''}`}\n >\n <Table\n columns={AUDIT_COLUMNS}\n dataSource={(audits?.records ?? []).map((audit): AuditRow => ({\n audit,\n key: audit.id,\n }))}\n fullWidth\n />\n </Modal>\n </>\n );\n}\n\nconst AUDIT_COLUMNS: TableColumn<AuditRow>[] = [\n {\n key: 'createdAt',\n render: ({ audit }: AuditRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(audit.createdAt)}\n </Typography>\n ),\n title: '時間',\n width: 180,\n },\n {\n key: 'action',\n render: ({ audit }: AuditRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {AUDIT_ACTION_LABELS[audit.action]}\n </Typography>\n ),\n title: '動作',\n width: 120,\n },\n {\n key: 'changedFields',\n render: ({ audit }: AuditRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {audit.changedFields.join('、') || '—'}\n </Typography>\n ),\n title: '欄位',\n width: 280,\n },\n {\n key: 'actor',\n render: ({ audit }: AuditRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {audit.actorMemberId ?? '系統'}\n </Typography>\n ),\n title: '操作者',\n width: 160,\n },\n];\n\nfunction EndpointDraftModal({\n draft,\n onCancel,\n onChange,\n onConfirm,\n saving,\n}: {\n readonly draft: EndpointDraft;\n readonly onCancel: () => void;\n readonly onChange: (draft: EndpointDraft) => void;\n readonly onConfirm: () => void;\n readonly saving: boolean;\n}): ReactElement {\n const editing = draft.mode === 'edit';\n // Stored header values must not follow the URL to another host, so a new\n // host always means entering the headers again.\n const originChanged = isOriginChanged(draft);\n const replaceHeaders = draft.replaceHeaders || originChanged;\n const update = (patch: Partial<EndpointDraft>): void =>\n onChange({ ...draft, ...patch });\n const updateParameter = (\n index: number,\n patch: Partial<ParameterDraft>,\n ): void =>\n update({\n parameters: draft.parameters.map((parameter, current) =>\n current === index ? { ...parameter, ...patch } : parameter,\n ),\n });\n const updateHeader = (index: number, patch: Partial<HeaderDraft>): void =>\n update({\n headers: draft.headers.map((header, current) =>\n current === index ? { ...header, ...patch } : header,\n ),\n });\n const text =\n (field: keyof EndpointDraft) =>\n (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>): void =>\n update({ [field]: event.target.value });\n\n return (\n <Modal\n cancelText=\"取消\"\n confirmText={editing ? '儲存' : '建立'}\n loading={saving}\n modalType=\"standard\"\n onCancel={onCancel}\n onClose={onCancel}\n onConfirm={onConfirm}\n open\n showModalFooter\n showModalHeader\n size=\"wide\"\n supportingText={\n editing\n ? '參數的鍵、型別與必填是這個版本的契約,無法修改;需要變更請建立新版本。'\n : draft.mode === 'version'\n ? '新版本可調整參數;既有模板仍使用舊版本,直到設計者改選。'\n : 'URL 需符合伺服器設定的白名單。'\n }\n title={\n editing\n ? `編輯端點:${draft.label}`\n : draft.mode === 'version'\n ? `建立新版本:${draft.key}`\n : '新增 Webhook 端點'\n }\n >\n <div style={STACK_STYLE}>\n <BPMFormField label=\"Key\" name=\"endpointKey\" required>\n <Input\n {...(draft.mode === 'create' ? {} : { readonly: true as const })}\n onChange={text('key')}\n placeholder=\"例如 crm.lead-created\"\n value={draft.key}\n inputProps={{ autoComplete: 'off' }}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"版本\" name=\"endpointVersion\" required>\n <Input\n {...(editing ? { readonly: true as const } : {})}\n inputProps={{ autoComplete: 'off', inputMode: 'numeric' }}\n onChange={text('version')}\n value={draft.version}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"名稱\" name=\"endpointLabel\" required>\n <Input\n onChange={text('label')}\n placeholder=\"例如 CRM 建立名單\"\n value={draft.label}\n inputProps={{ autoComplete: 'off' }}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"說明\" name=\"endpointDescription\">\n <Textarea\n onChange={text('description')}\n rows={2}\n value={draft.description}\n />\n </BPMFormField>\n <BPMFormField label=\"URL\" name=\"endpointUrl\" required>\n <Input\n onChange={text('url')}\n placeholder=\"https://\"\n value={draft.url}\n inputProps={{ autoComplete: 'off' }}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"Method\" name=\"endpointMethod\" required>\n <Select\n clearable={false}\n onChange={(option): void =>\n update({ method: option?.id ?? 'POST' })\n }\n options={[...METHOD_OPTIONS]}\n value={\n METHOD_OPTIONS.find((option) => option.id === draft.method) ??\n null\n }\n />\n </BPMFormField>\n <BPMFormField\n hintText=\"留空使用預設 10 秒,上限 30000 毫秒。\"\n label=\"逾時(毫秒)\"\n name=\"endpointTimeout\"\n >\n <Input\n inputProps={{ autoComplete: 'off', inputMode: 'numeric' }}\n onChange={text('timeoutMs')}\n value={draft.timeoutMs}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"不建議使用\" name=\"endpointDeprecated\">\n <Toggle\n checked={draft.deprecated}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n update({ deprecated: event.target.checked })\n }\n />\n </BPMFormField>\n {editing ? null : (\n <BPMFormField\n hintText=\"選填;設定後 BPM 以 HMAC-SHA256 簽章,儲存後不會再顯示。\"\n label=\"簽章金鑰\"\n name=\"endpointSigningSecret\"\n >\n <Input\n onChange={text('signingSecret')}\n placeholder=\"選填,儲存後不再顯示\"\n value={draft.signingSecret}\n inputProps={{ autoComplete: 'new-password' }}\n variant=\"password\"\n />\n </BPMFormField>\n )}\n\n <Typography variant=\"label-primary-highlight\">Headers</Typography>\n {editing ? (\n <BPMFormField\n hintText={\n originChanged\n ? 'URL 已改到其他主機,必須重新輸入 header(留空代表不帶任何 header)。'\n : '現有 header 的值不會顯示;開啟後以下列內容取代全部 header。'\n }\n label=\"取代 headers\"\n name=\"endpointReplaceHeaders\"\n >\n <Toggle\n checked={replaceHeaders}\n disabled={originChanged}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n update({ replaceHeaders: event.target.checked })\n }\n />\n </BPMFormField>\n ) : null}\n {replaceHeaders\n ? draft.headers.map((header, index): ReactElement => (\n <div key={index} style={HEADER_ROW_STYLE}>\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateHeader(index, { name: event.target.value })\n }\n placeholder=\"名稱,例如 Authorization\"\n inputProps={{ autoComplete: 'off' }}\n value={header.name}\n variant=\"base\"\n />\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateHeader(index, { value: event.target.value })\n }\n placeholder=\"值\"\n value={header.value}\n inputProps={{ autoComplete: 'new-password' }}\n variant=\"password\"\n />\n <Button\n icon={TrashIcon}\n iconType=\"icon-only\"\n onClick={(): void =>\n update({\n headers: draft.headers.filter(\n (_header, current) => current !== index,\n ),\n })\n }\n variant=\"destructive-text-link\"\n >\n 移除 header\n </Button>\n </div>\n ))\n : null}\n {replaceHeaders ? (\n <div>\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void =>\n update({ headers: [...draft.headers, { name: '', value: '' }] })\n }\n variant=\"base-dashed\"\n >\n 新增 header\n </Button>\n </div>\n ) : null}\n\n <Typography variant=\"label-primary-highlight\">參數</Typography>\n {draft.parameters.map((parameter, index): ReactElement => (\n <div key={index} style={ROW_STYLE}>\n <Input\n {...(editing ? { readonly: true as const } : {})}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateParameter(index, { key: event.target.value })\n }\n placeholder=\"參數鍵\"\n inputProps={{ autoComplete: 'off' }}\n value={parameter.key}\n variant=\"base\"\n />\n <Input\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateParameter(index, { label: event.target.value })\n }\n placeholder=\"顯示名稱\"\n inputProps={{ autoComplete: 'off' }}\n value={parameter.label}\n variant=\"base\"\n />\n <Select\n clearable={false}\n disabled={editing}\n onChange={(option): void =>\n updateParameter(index, {\n type: readParameterType(option?.id ?? null),\n })\n }\n options={[...PARAMETER_TYPE_OPTIONS]}\n value={\n PARAMETER_TYPE_OPTIONS.find(\n (option) => option.id === parameter.type,\n ) ?? null\n }\n />\n <Toggle\n checked={parameter.required}\n disabled={editing}\n label=\"必填\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n updateParameter(index, { required: event.target.checked })\n }\n />\n <Button\n disabled={editing}\n icon={TrashIcon}\n iconType=\"icon-only\"\n onClick={(): void =>\n update({\n parameters: draft.parameters.filter(\n (_parameter, current) => current !== index,\n ),\n })\n }\n variant=\"destructive-text-link\"\n >\n 移除參數\n </Button>\n </div>\n ))}\n {editing ? null : (\n <div>\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void =>\n update({\n parameters: [\n ...draft.parameters,\n {\n description: '',\n key: '',\n label: '',\n required: false,\n type: 'string',\n },\n ],\n })\n }\n variant=\"base-dashed\"\n >\n 新增參數\n </Button>\n </div>\n )}\n </div>\n </Modal>\n );\n}\n\nfunction readEditDraft(\n endpoint: WorkflowWebhookManagedEndpointRecord,\n mode: 'edit' | 'version',\n): EndpointDraft {\n return {\n deprecated: endpoint.deprecated,\n description: endpoint.description ?? '',\n endpointId: mode === 'edit' ? endpoint.id : null,\n headers: [],\n key: endpoint.key,\n label: endpoint.label,\n method: endpoint.method,\n mode,\n originalUrl: endpoint.url,\n parameters: endpoint.parameters.map((parameter) => ({\n description: parameter.description ?? '',\n key: parameter.key,\n label: parameter.label,\n required: parameter.required,\n type: parameter.type,\n })),\n // A new version starts without credentials: they are not readable.\n replaceHeaders: mode === 'version',\n signingSecret: '',\n timeoutMs: endpoint.timeoutMs ? String(endpoint.timeoutMs) : '',\n url: endpoint.url,\n version: String(\n mode === 'version' ? endpoint.version + 1 : endpoint.version,\n ),\n };\n}\n\nfunction readTestNotice(\n endpoint: WorkflowWebhookManagedEndpointRecord,\n result: WorkflowWebhookEndpointTestResultRecord,\n): string {\n if (result.ok) {\n return `測試送出成功:「${endpoint.label}」回應 HTTP ${result.status ?? ''}。`;\n }\n\n throw new Error(\n `測試送出失敗:「${endpoint.label}」${result.status ? `回應 HTTP ${result.status}` : ''}(${result.errorCode ?? '未知錯誤'})${result.errorDetail ? `:${result.errorDetail}` : ''}`,\n );\n}\n\nfunction isOriginChanged(draft: EndpointDraft): boolean {\n if (draft.mode !== 'edit') {\n return false;\n }\n\n const origin = (url: string): string => {\n try {\n return new URL(url.trim()).origin;\n } catch {\n return url.trim();\n }\n };\n\n return origin(draft.url) !== origin(draft.originalUrl);\n}\n\nfunction readParameterType(id: string | null): NotifyWebhookParameterType {\n return PARAMETER_TYPE_OPTIONS.some((option) => option.id === id)\n ? (id as NotifyWebhookParameterType)\n : 'string';\n}\n\nfunction readErrorMessage(error: unknown): string {\n if (!(error instanceof Error)) {\n return '發生未知錯誤';\n }\n\n const message = error.message;\n\n if (message.includes('WORKFLOW_WEBHOOK_URL_NOT_ALLOWED')) {\n return 'URL 不在伺服器允許的白名單內。';\n }\n\n if (message.includes('WORKFLOW_WEBHOOK_ENDPOINT_KEY_CONFLICT')) {\n return '這個 Key 已由程式註冊的端點使用,請換一個。';\n }\n\n if (message.includes('WORKFLOW_WEBHOOK_ENDPOINT_CONTRACT_CHANGED')) {\n return '參數契約不能修改,請改用「建立新版本」。';\n }\n\n if (message.includes('WORKFLOW_WEBHOOK_TEST_RATE_LIMITED')) {\n return '測試送出太頻繁,請稍後再試(每 10 秒一次、10 分鐘最多 5 次)。';\n }\n\n return message;\n}\n"],"mappings":"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"}
|
package/dist/views/cc/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/approval-instance-list-page-
|
|
1
|
+
"use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/approval-instance-list-page-Dcvo6TrT.cjs");let t=require("react/jsx-runtime");function n(){return(0,t.jsx)(e.t,{defaultState:null,description:`查看抄送給你的簽核案件。`,emptyMessage:`目前沒有抄送給你的簽核案件。`,searchPlaceholder:`關鍵字:搜尋案件、發起人、模板或狀態`,title:`抄送給我`,view:`CC`})}exports.CcView=n;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/views/cc/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/delegations-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/delegations-D43VDSz1.cjs");exports.DelegationsView=e.t;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as DelegationsView } from "../../chunks/delegations-
|
|
1
|
+
export { t as DelegationsView } from "../../chunks/delegations-CqND-Qtz.js";
|
|
@@ -14,5 +14,12 @@ export interface FormBuilderViewProps {
|
|
|
14
14
|
readonly schema: FormDefinitionSchema;
|
|
15
15
|
readonly uiSchema: FormUiSchema;
|
|
16
16
|
}) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Template and form version this schema belongs to. With either given, the
|
|
19
|
+
* builder checks filterable fields against existing instances (ADR 25 §5.4)
|
|
20
|
+
* and shows issues; it never blocks a draft.
|
|
21
|
+
*/
|
|
22
|
+
readonly formDefinitionId?: string | null;
|
|
23
|
+
readonly templateId?: string | null;
|
|
17
24
|
}
|
|
18
|
-
export declare function FormBuilderView({ onChange, value, }: FormBuilderViewProps): ReactElement;
|
|
25
|
+
export declare function FormBuilderView({ formDefinitionId, onChange, templateId, value, }: FormBuilderViewProps): ReactElement;
|
|
@@ -14,5 +14,12 @@ export interface FormBuilderViewProps {
|
|
|
14
14
|
readonly schema: FormDefinitionSchema;
|
|
15
15
|
readonly uiSchema: FormUiSchema;
|
|
16
16
|
}) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Template and form version this schema belongs to. With either given, the
|
|
19
|
+
* builder checks filterable fields against existing instances (ADR 25 §5.4)
|
|
20
|
+
* and shows issues; it never blocks a draft.
|
|
21
|
+
*/
|
|
22
|
+
readonly formDefinitionId?: string | null;
|
|
23
|
+
readonly templateId?: string | null;
|
|
17
24
|
}
|
|
18
|
-
export declare function FormBuilderView({ onChange, value, }: FormBuilderViewProps): ReactElement;
|
|
25
|
+
export declare function FormBuilderView({ formDefinitionId, onChange, templateId, value, }: FormBuilderViewProps): ReactElement;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/FormBuilderView-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/FormBuilderView-DjPGrOJ2.cjs");exports.FormBuilderView=e.t;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as FormBuilderView } from "../../../chunks/FormBuilderView-
|
|
1
|
+
export { t as FormBuilderView } from "../../../chunks/FormBuilderView-WtC2iW5f.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/FormRendererView-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/FormRendererView-B-xycC9S.cjs");exports.FormRenderer=e.t,exports.FormRendererView=e.t,exports.isFormDataSourceFieldSubmissionBlocked=e.s,exports.readFileUploadSubmissionBlockMessage=e.a,exports.readFormDataSourceFieldStatusMessage=e.c,exports.readFormDataSourceSubmissionBlockMessage=e.l,exports.useFormDataSourceField=e.u;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as FormRenderer, t as FormRendererView, s as isFormDataSourceFieldSubmissionBlocked, a as readFileUploadSubmissionBlockMessage, c as readFormDataSourceFieldStatusMessage, l as readFormDataSourceSubmissionBlockMessage, u as useFormDataSourceField } from "../../../chunks/FormRendererView-
|
|
1
|
+
export { t as FormRenderer, t as FormRendererView, s as isFormDataSourceFieldSubmissionBlocked, a as readFileUploadSubmissionBlockMessage, c as readFormDataSourceFieldStatusMessage, l as readFormDataSourceSubmissionBlockMessage, u as useFormDataSourceField } from "../../../chunks/FormRendererView-BcQKUi1A.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { UserTaskNode, WorkflowDefinition } from '@rytass/bpm-core-shared';
|
|
2
|
-
import { FormDefinitionSchema } from '@rytass/bpm-core-shared/form';
|
|
2
|
+
import { FormDefinitionSchema, FormDataIssue } from '@rytass/bpm-core-shared/form';
|
|
3
3
|
import { WorkflowFormData } from '@rytass/bpm-core-client/workflow';
|
|
4
4
|
/**
|
|
5
5
|
* The form as the applicant sees it: without the fields some approver fills in.
|
|
@@ -57,12 +57,15 @@ export declare function readFillChanges({ draft, node, schema, stored, values, }
|
|
|
57
57
|
/** The server message of a fill against form data someone else changed. */
|
|
58
58
|
export declare function isFillConflictMessage(message: string): boolean;
|
|
59
59
|
/**
|
|
60
|
-
* Turns the server's fill validation
|
|
60
|
+
* Turns the server's fill validation refusal (docs/08 §8.5, error table 2)
|
|
61
61
|
* into field errors keyed the way `FormRenderer` addresses them, so a check
|
|
62
|
-
* the page missed still lands on the field. `
|
|
63
|
-
*
|
|
62
|
+
* the page missed still lands on the field. `formDataIssues` is the refusal's
|
|
63
|
+
* structured list and wins when it is present: each issue names its value by
|
|
64
|
+
* path, so two fields sharing a label stay apart. Without it, the Chinese
|
|
65
|
+
* `message` is parsed. `null` when any part does not resolve to a fillable
|
|
66
|
+
* field — the caller then shows the message as it is.
|
|
64
67
|
*/
|
|
65
|
-
export declare function readFillServerErrors(message: string, schema: FormDefinitionSchema, node: UserTaskNode): Readonly<Record<string, string>> | null;
|
|
68
|
+
export declare function readFillServerErrors(message: string, schema: FormDefinitionSchema, node: UserTaskNode, formDataIssues?: readonly FormDataIssue[]): Readonly<Record<string, string>> | null;
|
|
66
69
|
export interface FillSummaryItem {
|
|
67
70
|
readonly fieldKey: string;
|
|
68
71
|
readonly label: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { UserTaskNode, WorkflowDefinition } from '@rytass/bpm-core-shared';
|
|
2
|
-
import { FormDefinitionSchema } from '@rytass/bpm-core-shared/form';
|
|
2
|
+
import { FormDefinitionSchema, FormDataIssue } from '@rytass/bpm-core-shared/form';
|
|
3
3
|
import { WorkflowFormData } from '@rytass/bpm-core-client/workflow';
|
|
4
4
|
/**
|
|
5
5
|
* The form as the applicant sees it: without the fields some approver fills in.
|
|
@@ -57,12 +57,15 @@ export declare function readFillChanges({ draft, node, schema, stored, values, }
|
|
|
57
57
|
/** The server message of a fill against form data someone else changed. */
|
|
58
58
|
export declare function isFillConflictMessage(message: string): boolean;
|
|
59
59
|
/**
|
|
60
|
-
* Turns the server's fill validation
|
|
60
|
+
* Turns the server's fill validation refusal (docs/08 §8.5, error table 2)
|
|
61
61
|
* into field errors keyed the way `FormRenderer` addresses them, so a check
|
|
62
|
-
* the page missed still lands on the field. `
|
|
63
|
-
*
|
|
62
|
+
* the page missed still lands on the field. `formDataIssues` is the refusal's
|
|
63
|
+
* structured list and wins when it is present: each issue names its value by
|
|
64
|
+
* path, so two fields sharing a label stay apart. Without it, the Chinese
|
|
65
|
+
* `message` is parsed. `null` when any part does not resolve to a fillable
|
|
66
|
+
* field — the caller then shows the message as it is.
|
|
64
67
|
*/
|
|
65
|
-
export declare function readFillServerErrors(message: string, schema: FormDefinitionSchema, node: UserTaskNode): Readonly<Record<string, string>> | null;
|
|
68
|
+
export declare function readFillServerErrors(message: string, schema: FormDefinitionSchema, node: UserTaskNode, formDataIssues?: readonly FormDataIssue[]): Readonly<Record<string, string>> | null;
|
|
66
69
|
export interface FillSummaryItem {
|
|
67
70
|
readonly fieldKey: string;
|
|
68
71
|
readonly label: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/detail-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/detail-DNzqesdI.cjs");exports.InstanceAttachmentsSection=e.o,exports.InstanceDetailView=e.t,exports.InstanceFormSection=e.s,exports.InstanceHistorySection=e.r,exports.InstanceSignaturesSection=e.i,exports.InstanceTasksSection=e.a,exports.InstanceWebhookDeliveriesSection=e.n;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { o as InstanceAttachmentsSection, t as InstanceDetailView, s as InstanceFormSection, r as InstanceHistorySection, i as InstanceSignaturesSection, a as InstanceTasksSection, n as InstanceWebhookDeliveriesSection } from "../../../chunks/detail-
|
|
1
|
+
export { o as InstanceAttachmentsSection, t as InstanceDetailView, s as InstanceFormSection, r as InstanceHistorySection, i as InstanceSignaturesSection, a as InstanceTasksSection, n as InstanceWebhookDeliveriesSection } from "../../../chunks/detail-Bv90gvy0.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AdhocDirectiveRecord, ApprovalInstanceRecord, MemberProfileRecord, TaskRecord } from '@rytass/bpm-core-client/workflow';
|
|
2
|
+
import { FormDataIssue } from '@rytass/bpm-core-shared/form';
|
|
2
3
|
import { FillSummaryItem } from '../../approver-filled-form.cjs';
|
|
3
4
|
/**
|
|
4
5
|
* Imperative handle exposed by InstanceTasksSection via ref.
|
|
@@ -50,7 +51,7 @@ export interface InstanceTasksSectionProps {
|
|
|
50
51
|
* `true` means the container showed it (a conflict or field errors), so the
|
|
51
52
|
* dialog closes instead of repeating it.
|
|
52
53
|
*/
|
|
53
|
-
readonly onFillApproveError?: (message: string) => boolean;
|
|
54
|
+
readonly onFillApproveError?: (message: string, formDataIssues?: readonly FormDataIssue[]) => boolean;
|
|
54
55
|
/** All tasks for this instance. */
|
|
55
56
|
readonly tasks: readonly TaskRecord[];
|
|
56
57
|
/** Ad-hoc directives recorded on this instance. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AdhocDirectiveRecord, ApprovalInstanceRecord, MemberProfileRecord, TaskRecord } from '@rytass/bpm-core-client/workflow';
|
|
2
|
+
import { FormDataIssue } from '@rytass/bpm-core-shared/form';
|
|
2
3
|
import { FillSummaryItem } from '../../approver-filled-form.js';
|
|
3
4
|
/**
|
|
4
5
|
* Imperative handle exposed by InstanceTasksSection via ref.
|
|
@@ -50,7 +51,7 @@ export interface InstanceTasksSectionProps {
|
|
|
50
51
|
* `true` means the container showed it (a conflict or field errors), so the
|
|
51
52
|
* dialog closes instead of repeating it.
|
|
52
53
|
*/
|
|
53
|
-
readonly onFillApproveError?: (message: string) => boolean;
|
|
54
|
+
readonly onFillApproveError?: (message: string, formDataIssues?: readonly FormDataIssue[]) => boolean;
|
|
54
55
|
/** All tasks for this instance. */
|
|
55
56
|
readonly tasks: readonly TaskRecord[];
|
|
56
57
|
/** Ad-hoc directives recorded on this instance. */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/rolldown-runtime-BocRIvOZ.cjs"),t=require("../../../chunks/instance-error-message-
|
|
1
|
+
"use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/rolldown-runtime-BocRIvOZ.cjs"),t=require("../../../chunks/instance-error-message-BW464LRQ.cjs"),n=require("../../../chunks/format-date-time-D-cx5M8z.cjs"),r=require("../../../chunks/auth-provider-4BeCw7cI.cjs"),i=require("../../../chunks/router-adapter--gYs13E8.cjs"),a=require("../../../chunks/routes-config-C1j_vFKo.cjs"),o=require("../../../chunks/FormRendererView-B-xycC9S.cjs");let s=require("react"),c=require("@mezzanine-ui/react"),l=require("react/jsx-runtime"),u=require("@rytass/bpm-core-client/workflow"),d=require("@mezzanine-ui/react/ContentHeader");d=e.t(d,1);let f=require("@rytass/bpm-core-client/form"),p=require("@mezzanine-ui/icons");var m={display:`grid`,gap:16};function h(e={}){return(0,l.jsx)(s.Suspense,{fallback:(0,l.jsx)(_,{}),children:(0,l.jsx)(g,{templateId:e.templateId??void 0})})}function g({templateId:e}){let h=i.r(),g=a.r(),{member:_}=r.n(),v=_?.memberId??null,y=e??null,[b,x]=(0,s.useState)(null),[S,C]=(0,s.useState)({}),[w,T]=(0,s.useState)([]),[E,D]=(0,s.useState)(null),[O,k]=(0,s.useState)({}),[A,j]=(0,s.useState)(!0),[M,N]=(0,s.useState)(!1),[P,F]=(0,s.useState)({}),I=o.o(),L=(0,s.useMemo)(()=>b?t.r(b.formVersion.schema,b.templateVersion.workflowDefinition):null,[b]),R=(0,s.useCallback)((e,t)=>{F(n=>{let r=n[e];return r?.hasValue===t.hasValue&&r.selectionExpired===(t.selectionExpired===!0)&&r.status===t.status?n:{...n,[e]:{hasValue:t.hasValue,selectionExpired:t.selectionExpired===!0,status:t.status}}})},[]);(0,s.useEffect)(()=>{y?U(y):H()},[y]);let z=(0,s.useMemo)(()=>w.map(e=>({...e,key:e.id,updatedAt:n.t(e.updatedAt),versionLabel:`v${e.version}`})),[w]),B=(0,s.useMemo)(()=>[{dataIndex:`name`,key:`name`,title:`模板名稱`,width:240},{dataIndex:`versionLabel`,key:`versionLabel`,title:`發布版本`,width:120},{dataIndex:`updatedAt`,key:`updatedAt`,title:`更新時間`,width:220}],[]),V=(0,s.useMemo)(()=>({render:e=>[{name:`發起`,onClick:()=>h.push(g.caseNew(e.id)),variant:`base-primary`}],variant:`base-secondary`,width:88}),[h]);async function H(){j(!0),D(null),x(null),F({});try{T(await(0,u.listLaunchableTemplates)())}catch(e){D(t.t(e))}finally{j(!1)}}async function U(e){j(!0),D(null),T([]),F({});try{x(await(0,u.readLaunchContext)(e))}catch(e){D(t.t(e))}finally{j(!1)}}async function W(){if(!b||!L||!v)return;N(!0),D(null),k({});let e=o.l(Object.values(P));if(e){D(e),N(!1);return}if(I.blockMessage){D(I.blockMessage),N(!1);return}let n=t.i((0,f.buildFormRendererValues)(L.fields,S),b.templateVersion.workflowDefinition);try{let e=await(0,f.validateFormRendererValuesInWorker)({schema:L,uiSchema:b.formVersion.uiSchema,values:n});if(!e.valid){k(e.errors),D(`請先修正表單中標示的欄位。`),e.firstInvalidFieldKey&&(0,f.focusFormRendererField)(e.firstInvalidFieldKey);return}let t=await(0,u.submitApprovalInstance)({formData:n,initiatorMemberId:v,templateId:b.template.id,title:(0,u.readFormDataCaseTitle)({fallbackTitle:b.template.name,formData:n,schema:L,uiSchema:b.formVersion.uiSchema})});h.push(g.caseDetail(t))}catch(e){D(t.t(e))}finally{N(!1)}}async function G(e,t){if(!v)throw Error(`尚未登入,無法上傳附件`);return{id:(await(0,u.uploadAttachment)({file:t,formFieldPath:`form.${e.fieldKey}`})).id}}return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(c.PageHeader,{children:(0,l.jsx)(d.default,{description:b?`${b.template.name} · 表單 v${b.formVersion.version}`:`選擇可發起的已發布模板後填寫表單內容。`,title:`發起簽核`,children:b?(0,l.jsx)(c.Button,{disabled:A||M,icon:p.CheckedIcon,iconType:`leading`,onClick:W,variant:`base-primary`,children:`送出`}):null})}),(0,l.jsx)(c.SectionGroup,{children:(0,l.jsx)(c.Section,{children:(0,l.jsxs)(`div`,{style:m,children:[E?(0,l.jsx)(c.Typography,{color:`text-error`,variant:`body`,children:E}):null,A?(0,l.jsx)(c.Typography,{color:`text-neutral`,variant:`body`,children:`載入中...`}):null,b&&L?(0,l.jsx)(o.t,{dataSourceContext:{kind:`runtime`,templateId:b.template.id},errors:O,maxWidth:480,onChange:e=>{C(e),k({})},onDataSourceStateChange:R,onFileUploadStateChange:I.onFileUploadStateChange,onUploadAttachment:G,schema:L,singleColumn:!0,uiSchema:b.formVersion.uiSchema,value:S}):null,!y&&!A?z.length>0?(0,l.jsx)(c.Table,{actions:V,columns:B,dataSource:z,fullWidth:!0}):(0,l.jsx)(c.Typography,{color:`text-neutral`,variant:`body`,children:`目前沒有可發起的已發布模板。`}):null]})})})]})}function _(){return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(c.PageHeader,{children:(0,l.jsx)(d.default,{description:`選擇可發起的已發布模板後填寫表單內容。`,title:`發起簽核`})}),(0,l.jsx)(c.SectionGroup,{children:(0,l.jsx)(c.Section,{children:(0,l.jsx)(c.Typography,{color:`text-neutral`,variant:`body`,children:`載入中...`})})})]})}exports.InstanceNewView=h;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["Suspense","useRouterAdapter","useBPMRoutes","useAuth","useState","useFileUploadFieldStates","useMemo","readApplicantFormSchema","useCallback","formatDateTime","listLaunchableTemplates","readErrorMessage","readLaunchContext","readFormDataSourceSubmissionBlockMessage","readApplicantSubmission","buildFormRendererValues","validateFormRendererValuesInWorker","submitApprovalInstance","readFormDataCaseTitle","uploadAttachment","_Fragment","PageHeader","ContentHeader","Button","CheckedIcon","SectionGroup","Section","Typography","FormRenderer","Table","require_rolldown_runtime","require_instance_error_message","require_format_date_time","require_auth_provider","require_router_adapter","require_routes_config","require_FormRendererView","react","_mezzanine_ui_react","react_jsx_runtime","_rytass_bpm_core_client_workflow","_mezzanine_ui_react_ContentHeader","_mezzanine_ui_icons","_rytass_bpm_core_client_form","FORM_SECTION_STYLE","InstanceNewView","NewApprovalInstanceLoading","NewApprovalInstanceContent","props","templateIdProp","router","routes","currentMemberId","member","templateId","context","setContext","formValues","setFormValues","templates","setTemplates","error","setError","formErrors","setFormErrors","loading","setLoading","submitting","setSubmitting","dataSourceStates","setDataSourceStates","fileUploads","applicantSchema","handleDataSourceStateChange","currentState","currentStates","fieldKey","state","refreshContext","refreshTemplates","rows","template","columns","tableActions","record","requestError","nextTemplateId","handleSubmit","dataSourceBlockMessage","submittedValues","validation","instanceId","handleUploadAttachment","field","values"],"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 validateFormRendererValuesInWorker,\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 {\n readApplicantFormSchema,\n readApplicantSubmission,\n} from '../approver-filled-form';\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';\nimport { useFileUploadFieldStates } from '../../forms/renderer/file-upload-field';\nimport { readErrorMessage } from '../instance-error-message';\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<\n string,\n Pick<FormDataSourceFieldState, 'hasValue' | 'selectionExpired' | 'status'>\n >\n >\n >({});\n const fileUploads = useFileUploadFieldStates();\n\n // The form the applicant sees: approver-filled fields are not theirs to fill\n // (the server drops them), so they are left out of everything below.\n const applicantSchema = useMemo(\n () =>\n context\n ? readApplicantFormSchema(\n context.formVersion.schema,\n context.templateVersion.workflowDefinition,\n )\n : null,\n [context],\n );\n\n const handleDataSourceStateChange = useCallback(\n (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'selectionExpired' | 'status'\n >,\n ): void => {\n setDataSourceStates((currentStates) => {\n const currentState = currentStates[fieldKey];\n\n if (\n currentState?.hasValue === state.hasValue &&\n currentState.selectionExpired === (state.selectionExpired === true) &&\n currentState.status === state.status\n ) {\n return currentStates;\n }\n\n return {\n ...currentStates,\n [fieldKey]: {\n hasValue: state.hasValue,\n selectionExpired: state.selectionExpired === true,\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 || !applicantSchema || !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 // A file still uploading, or one that failed, is listed in its field but\n // is not in the value; submitting now would leave it off the case.\n if (fileUploads.blockMessage) {\n setError(fileUploads.blockMessage);\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 = readApplicantSubmission(\n buildFormRendererValues(applicantSchema.fields, formValues),\n context.templateVersion.workflowDefinition,\n );\n // Inside the `try`, so a validation that throws still clears `submitting`\n // and shows its error instead of leaving the button busy for good.\n try {\n // The format patterns run in a worker under the engine's time budget, so\n // a pattern that backtracks cannot freeze the page.\n const validation = await validateFormRendererValuesInWorker({\n schema: applicantSchema,\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 return;\n }\n\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: applicantSchema,\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 && applicantSchema ? (\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 onFileUploadStateChange={fileUploads.onFileUploadStateChange}\n onUploadAttachment={handleUploadAttachment}\n schema={applicantSchema}\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\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["Suspense","useRouterAdapter","useBPMRoutes","useAuth","useState","useFileUploadFieldStates","useMemo","readApplicantFormSchema","useCallback","formatDateTime","listLaunchableTemplates","readErrorMessage","readLaunchContext","readFormDataSourceSubmissionBlockMessage","readApplicantSubmission","buildFormRendererValues","validateFormRendererValuesInWorker","submitApprovalInstance","readFormDataCaseTitle","uploadAttachment","_Fragment","PageHeader","ContentHeader","Button","CheckedIcon","SectionGroup","Section","Typography","FormRenderer","Table","require_rolldown_runtime","require_instance_error_message","require_format_date_time","require_auth_provider","require_router_adapter","require_routes_config","require_FormRendererView","react","_mezzanine_ui_react","react_jsx_runtime","_rytass_bpm_core_client_workflow","_mezzanine_ui_react_ContentHeader","_rytass_bpm_core_client_form","_mezzanine_ui_icons","FORM_SECTION_STYLE","InstanceNewView","NewApprovalInstanceLoading","NewApprovalInstanceContent","props","templateIdProp","router","routes","currentMemberId","member","templateId","context","setContext","formValues","setFormValues","templates","setTemplates","error","setError","formErrors","setFormErrors","loading","setLoading","submitting","setSubmitting","dataSourceStates","setDataSourceStates","fileUploads","applicantSchema","handleDataSourceStateChange","currentState","currentStates","fieldKey","state","refreshContext","refreshTemplates","rows","template","columns","tableActions","record","requestError","nextTemplateId","handleSubmit","dataSourceBlockMessage","submittedValues","validation","instanceId","handleUploadAttachment","field","values"],"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 validateFormRendererValuesInWorker,\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 {\n readApplicantFormSchema,\n readApplicantSubmission,\n} from '../approver-filled-form';\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';\nimport { useFileUploadFieldStates } from '../../forms/renderer/file-upload-field';\nimport { readErrorMessage } from '../instance-error-message';\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<\n string,\n Pick<FormDataSourceFieldState, 'hasValue' | 'selectionExpired' | 'status'>\n >\n >\n >({});\n const fileUploads = useFileUploadFieldStates();\n\n // The form the applicant sees: approver-filled fields are not theirs to fill\n // (the server drops them), so they are left out of everything below.\n const applicantSchema = useMemo(\n () =>\n context\n ? readApplicantFormSchema(\n context.formVersion.schema,\n context.templateVersion.workflowDefinition,\n )\n : null,\n [context],\n );\n\n const handleDataSourceStateChange = useCallback(\n (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'selectionExpired' | 'status'\n >,\n ): void => {\n setDataSourceStates((currentStates) => {\n const currentState = currentStates[fieldKey];\n\n if (\n currentState?.hasValue === state.hasValue &&\n currentState.selectionExpired === (state.selectionExpired === true) &&\n currentState.status === state.status\n ) {\n return currentStates;\n }\n\n return {\n ...currentStates,\n [fieldKey]: {\n hasValue: state.hasValue,\n selectionExpired: state.selectionExpired === true,\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 || !applicantSchema || !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 // A file still uploading, or one that failed, is listed in its field but\n // is not in the value; submitting now would leave it off the case.\n if (fileUploads.blockMessage) {\n setError(fileUploads.blockMessage);\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 = readApplicantSubmission(\n buildFormRendererValues(applicantSchema.fields, formValues),\n context.templateVersion.workflowDefinition,\n );\n // Inside the `try`, so a validation that throws still clears `submitting`\n // and shows its error instead of leaving the button busy for good.\n try {\n // The format patterns run in a worker under the engine's time budget, so\n // a pattern that backtracks cannot freeze the page.\n const validation = await validateFormRendererValuesInWorker({\n schema: applicantSchema,\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 return;\n }\n\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: applicantSchema,\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 && applicantSchema ? (\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 onFileUploadStateChange={fileUploads.onFileUploadStateChange}\n onUploadAttachment={handleUploadAttachment}\n schema={applicantSchema}\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\n"],"mappings":"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"}
|