@rytass/bpm-core-react 0.8.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +93 -0
- package/README.md +18 -2
- package/dist/chunks/FormBuilderView-BPLwAJGv.cjs +3 -0
- package/dist/chunks/FormBuilderView-BPLwAJGv.cjs.map +1 -0
- package/dist/chunks/FormBuilderView-Do9-MIAe.js +1477 -0
- package/dist/chunks/FormBuilderView-Do9-MIAe.js.map +1 -0
- package/dist/chunks/FormRendererView-C5POZbWz.js +492 -0
- package/dist/chunks/FormRendererView-C5POZbWz.js.map +1 -0
- package/dist/chunks/FormRendererView-DNtNodNl.cjs +2 -0
- package/dist/chunks/FormRendererView-DNtNodNl.cjs.map +1 -0
- package/dist/chunks/{approval-instance-list-page-YZcGGDD8.js → approval-instance-list-page-BjX2kaoF.js} +56 -54
- package/dist/chunks/approval-instance-list-page-BjX2kaoF.js.map +1 -0
- package/dist/chunks/approval-instance-list-page-C408vxE2.cjs +2 -0
- package/dist/chunks/approval-instance-list-page-C408vxE2.cjs.map +1 -0
- package/dist/chunks/{categories-DBPoSrsi.js → categories-DGlxuC6X.js} +5 -5
- package/dist/chunks/{categories-DBPoSrsi.js.map → categories-DGlxuC6X.js.map} +1 -1
- package/dist/chunks/{categories-B6QZKZRt.cjs → categories-DUfldZ_9.cjs} +2 -2
- package/dist/chunks/{categories-B6QZKZRt.cjs.map → categories-DUfldZ_9.cjs.map} +1 -1
- package/dist/chunks/compose-CULMDsLS.cjs +2 -0
- package/dist/chunks/compose-CULMDsLS.cjs.map +1 -0
- package/dist/chunks/{compose-CQHDT7vh.js → compose-DJBlA5PD.js} +60 -58
- package/dist/chunks/compose-DJBlA5PD.js.map +1 -0
- package/dist/chunks/{delegations-DDEk-WI6.cjs → delegations-CGj-tZNO.cjs} +2 -2
- package/dist/chunks/{delegations-DDEk-WI6.cjs.map → delegations-CGj-tZNO.cjs.map} +1 -1
- package/dist/chunks/{delegations-iVnRi3QE.js → delegations-DLEEFBlH.js} +231 -231
- package/dist/chunks/{delegations-iVnRi3QE.js.map → delegations-DLEEFBlH.js.map} +1 -1
- package/dist/chunks/{delegations-ZNtodFaD.js → delegations-DqMpI_Nk.js} +168 -167
- package/dist/chunks/delegations-DqMpI_Nk.js.map +1 -0
- package/dist/chunks/delegations-kbMOSEif.cjs +2 -0
- package/dist/chunks/delegations-kbMOSEif.cjs.map +1 -0
- package/dist/chunks/{designer-CUbVXEtS.js → designer-BszXJ5RO.js} +1227 -990
- package/dist/chunks/designer-BszXJ5RO.js.map +1 -0
- package/dist/chunks/designer-CmqAU92b.cjs +65 -0
- package/dist/chunks/designer-CmqAU92b.cjs.map +1 -0
- package/dist/chunks/detail-CDexqBoU.cjs +2 -0
- package/dist/chunks/detail-CDexqBoU.cjs.map +1 -0
- package/dist/chunks/{detail-Cts5_gVp.js → detail-DAak2OXS.js} +704 -622
- package/dist/chunks/detail-DAak2OXS.js.map +1 -0
- package/dist/chunks/notifications--hwl-DR0.cjs +2 -0
- package/dist/chunks/{notifications-BKs4--96.cjs.map → notifications--hwl-DR0.cjs.map} +1 -1
- package/dist/chunks/{notifications-CSulztkU.js → notifications-DJ5wzCye.js} +7 -7
- package/dist/chunks/{notifications-CSulztkU.js.map → notifications-DJ5wzCye.js.map} +1 -1
- package/dist/chunks/{orgs-CrNxqlwp.js → orgs-DytLvZ_X.js} +243 -241
- package/dist/chunks/{orgs-CrNxqlwp.js.map → orgs-DytLvZ_X.js.map} +1 -1
- package/dist/chunks/orgs-Ni22buHs.cjs +2 -0
- package/dist/chunks/orgs-Ni22buHs.cjs.map +1 -0
- package/dist/chunks/providers-DEqcuXw9.js +506 -0
- package/dist/chunks/providers-DEqcuXw9.js.map +1 -0
- package/dist/chunks/providers-D_zTbkQH.cjs +2 -0
- package/dist/chunks/providers-D_zTbkQH.cjs.map +1 -0
- package/dist/chunks/{users-qghSMtLn.cjs → users-0HqlM_VQ.cjs} +2 -2
- package/dist/chunks/{users-qghSMtLn.cjs.map → users-0HqlM_VQ.cjs.map} +1 -1
- package/dist/chunks/{users-CUY139DF.js → users-FWrb3ehW.js} +5 -5
- package/dist/chunks/{users-CUY139DF.js.map → users-FWrb3ehW.js.map} +1 -1
- package/dist/components/notification-drawer.d.ts +4 -3
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +21 -428
- package/dist/index.js.map +1 -1
- package/dist/next/index.cjs +1 -1
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.js +16 -15
- package/dist/next/index.js.map +1 -1
- package/dist/pages/admin/delegations/index.cjs +1 -1
- package/dist/pages/admin/delegations/index.js +1 -1
- package/dist/pages/admin/orgs/index.cjs +1 -1
- package/dist/pages/admin/orgs/index.js +1 -1
- package/dist/pages/admin/users/index.cjs +1 -1
- package/dist/pages/admin/users/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/settings/notifications/index.cjs +1 -1
- package/dist/pages/settings/notifications/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 +3 -3
- package/dist/views/admin/orgs/index.cjs +1 -1
- package/dist/views/admin/orgs/index.js +1 -1
- package/dist/views/admin/users/index.cjs +1 -1
- package/dist/views/admin/users/index.js +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/index.cjs +1 -1
- package/dist/views/forms/builder/index.js +1 -1
- package/dist/views/forms/renderer/FormRendererView.d.ts +7 -2
- package/dist/views/forms/renderer/form-data-source-field.d.ts +34 -0
- package/dist/views/forms/renderer/index.cjs +1 -1
- package/dist/views/forms/renderer/index.d.ts +1 -0
- package/dist/views/forms/renderer/index.js +2 -2
- package/dist/views/instances/detail/index.cjs +1 -1
- package/dist/views/instances/detail/index.js +1 -1
- package/dist/views/instances/detail/sections/InstanceFormSection.d.ts +4 -1
- package/dist/views/instances/detail/sections/InstanceTasksSection.d.ts +5 -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 +105 -86
- 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/settings/index.cjs +1 -1
- package/dist/views/settings/index.js +1 -1
- package/dist/views/settings/notifications/index.cjs +1 -1
- package/dist/views/settings/notifications/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/TemplateComposeWizardView.d.ts +3 -2
- package/dist/views/templates/compose/index.cjs +1 -1
- package/dist/views/templates/compose/index.js +1 -1
- 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 +153 -112
- package/dist/views/templates/index.js.map +1 -1
- package/package.json +56 -11
- package/dist/chunks/FormBuilderView-B_KGPjlp.cjs +0 -3
- package/dist/chunks/FormBuilderView-B_KGPjlp.cjs.map +0 -1
- package/dist/chunks/FormBuilderView-D8DrQOXD.js +0 -1090
- package/dist/chunks/FormBuilderView-D8DrQOXD.js.map +0 -1
- package/dist/chunks/FormRendererView-BwVsH2eX.cjs +0 -2
- package/dist/chunks/FormRendererView-BwVsH2eX.cjs.map +0 -1
- package/dist/chunks/FormRendererView-DrHsuSVo.js +0 -220
- package/dist/chunks/FormRendererView-DrHsuSVo.js.map +0 -1
- package/dist/chunks/approval-instance-list-page-BMUKxzcz.cjs +0 -2
- package/dist/chunks/approval-instance-list-page-BMUKxzcz.cjs.map +0 -1
- package/dist/chunks/approval-instance-list-page-YZcGGDD8.js.map +0 -1
- package/dist/chunks/compose-CQHDT7vh.js.map +0 -1
- package/dist/chunks/compose-Ds_cAefe.cjs +0 -2
- package/dist/chunks/compose-Ds_cAefe.cjs.map +0 -1
- package/dist/chunks/delegations-C2wLWsDQ.cjs +0 -2
- package/dist/chunks/delegations-C2wLWsDQ.cjs.map +0 -1
- package/dist/chunks/delegations-ZNtodFaD.js.map +0 -1
- package/dist/chunks/designer-CQ9hxSdD.cjs +0 -65
- package/dist/chunks/designer-CQ9hxSdD.cjs.map +0 -1
- package/dist/chunks/designer-CUbVXEtS.js.map +0 -1
- package/dist/chunks/detail-B-Q4W-iw.cjs +0 -2
- package/dist/chunks/detail-B-Q4W-iw.cjs.map +0 -1
- package/dist/chunks/detail-Cts5_gVp.js.map +0 -1
- package/dist/chunks/notifications-BKs4--96.cjs +0 -2
- package/dist/chunks/orgs-iNJ0QEcK.cjs +0 -2
- package/dist/chunks/orgs-iNJ0QEcK.cjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormRendererView-DNtNodNl.cjs","names":[],"sources":["../../src/views/forms/renderer/form-data-source-field.ts","../../src/views/forms/renderer/FormRendererView.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n FormDataSourceValueSnapshots,\n FormDefinitionSchema,\n FormFieldDefinition,\n FormFieldOption,\n FormFieldValue,\n FormUiSchema,\n isFormDataSourceFieldDefinition,\n} from '@rytass/bpm-core-shared/form';\nimport {\n FormDataSourceFieldStatus,\n FormRendererValues,\n mergeFormDataSourceOptions,\n readFormDataSourceErrorMessage,\n readMissingFormDataSourceOptionValues,\n previewFormFieldOptions,\n readFormDataSourceValueSignature,\n readMissingFormDataSourceDependencies,\n readSelectedFormDataSourceOptions,\n readFormFieldOptions,\n} from '@rytass/bpm-core-client/form';\n\nexport type FormRendererDataSourceContext =\n | { readonly kind: 'preview' }\n | {\n readonly instanceId?: string | null;\n readonly kind: 'runtime';\n readonly templateId?: string | null;\n };\n\nexport interface FormDataSourceFieldState {\n readonly error: string | null;\n readonly hasValue: boolean;\n readonly hasNextPage: boolean;\n readonly invalidValues: readonly string[];\n readonly onReachBottom: () => void;\n readonly onSearch: (searchText: string) => void;\n readonly options: readonly FormFieldOption[];\n readonly retry: () => void;\n readonly status: FormDataSourceFieldStatus;\n}\n\nexport interface UseFormDataSourceFieldInput {\n readonly context?: FormRendererDataSourceContext;\n readonly field: FormFieldDefinition;\n readonly formData: FormRendererValues;\n readonly initialFormData?: FormRendererValues;\n readonly initialValue?: FormFieldValue | undefined;\n readonly optionSnapshots?: FormDataSourceValueSnapshots;\n readonly readonly: boolean;\n readonly schema: FormDefinitionSchema;\n readonly uiSchema: FormUiSchema;\n}\n\nconst EMPTY_FIELD_STATE: FormDataSourceFieldState = {\n error: null,\n hasValue: false,\n hasNextPage: false,\n invalidValues: [],\n onReachBottom: (): void => undefined,\n onSearch: (): void => undefined,\n options: [],\n retry: (): void => undefined,\n status: 'IDLE',\n};\n\nexport function useFormDataSourceField(\n input: UseFormDataSourceFieldInput,\n): FormDataSourceFieldState {\n const dynamicField = isFormDataSourceFieldDefinition(input.field)\n ? input.field\n : null;\n const snapshot = dynamicField\n ? input.optionSnapshots?.[dynamicField.fieldKey]\n : undefined;\n const snapshotSignature = JSON.stringify(snapshot ?? null);\n const snapshotOptions = useMemo(\n (): readonly FormFieldOption[] => snapshot?.options ?? [],\n [snapshotSignature],\n );\n const formDataSignature = JSON.stringify(input.formData);\n const initialFormDataSignature = JSON.stringify(input.initialFormData ?? {});\n const schemaSignature = JSON.stringify(input.schema);\n const uiSchemaSignature = JSON.stringify(input.uiSchema);\n const contextKind = input.context?.kind;\n const contextInstanceId =\n input.context?.kind === 'runtime' ? input.context.instanceId : undefined;\n const contextTemplateId =\n input.context?.kind === 'runtime' ? input.context.templateId : undefined;\n const missingDependencies = dynamicField\n ? readMissingFormDataSourceDependencies(dynamicField, input.formData)\n : [];\n const missingDependenciesSignature = JSON.stringify(missingDependencies);\n const dataSourceRefreshSignature = dynamicField\n ? JSON.stringify({\n bindings: dynamicField.dataSource.bindings.map((binding) =>\n binding.from.kind === 'FIELD'\n ? {\n fieldKey: binding.from.fieldKey,\n value: input.formData[binding.from.fieldKey],\n }\n : { value: binding.from.value },\n ),\n value:\n typeof input.initialFormData !== 'undefined' ||\n typeof input.initialValue !== 'undefined'\n ? input.formData[dynamicField.fieldKey]\n : undefined,\n })\n : '';\n const effectiveContext = useMemo(\n (): FormRendererDataSourceContext | undefined => {\n if (contextKind === 'preview') {\n return { kind: 'preview' };\n }\n\n if (contextKind === 'runtime' && !input.readonly) {\n return {\n instanceId: contextInstanceId,\n kind: 'runtime',\n templateId: contextTemplateId,\n };\n }\n\n return undefined;\n },\n [\n contextInstanceId,\n contextKind,\n contextTemplateId,\n input.readonly,\n ],\n );\n const valueChanged = dynamicField\n ? (typeof input.initialFormData !== 'undefined' ||\n typeof input.initialValue !== 'undefined') &&\n readFormDataSourceValueSignature(input.initialValue) !==\n readFormDataSourceValueSignature(input.formData[dynamicField.fieldKey])\n : false;\n const bindingsChanged = dynamicField\n ? typeof input.initialFormData !== 'undefined' &&\n dynamicField.dataSource.bindings.some((binding) => {\n if (binding.from.kind !== 'FIELD') {\n return false;\n }\n\n return (\n readFormDataSourceValueSignature(\n input.initialFormData?.[binding.from.fieldKey],\n ) !==\n readFormDataSourceValueSignature(input.formData[binding.from.fieldKey])\n );\n })\n : false;\n const isStale = Boolean(snapshot && (valueChanged || bindingsChanged));\n const [remoteOptions, setRemoteOptions] = useState<readonly FormFieldOption[]>(\n [],\n );\n const [searchText, setSearchText] = useState('');\n const [nextCursor, setNextCursor] = useState<string | null>(null);\n const [status, setStatus] = useState<FormDataSourceFieldStatus>(\n dynamicField ? (snapshot ? (isStale ? 'STALE' : 'VALID') : 'IDLE') : 'IDLE',\n );\n const [error, setError] = useState<string | null>(null);\n const requestSequence = useRef(0);\n const lastRequest = useRef<{ readonly cursor: string | null; readonly searchText: string }>({\n cursor: null,\n searchText: '',\n });\n\n const queryFormData = useMemo(\n (): Readonly<Record<string, FormFieldValue>> =>\n Object.entries(input.formData).reduce<\n Readonly<Record<string, FormFieldValue>>\n >((values, [key, value]) => {\n if (typeof value === 'undefined') {\n return values;\n }\n\n return { ...values, [key]: value };\n }, {}),\n [formDataSignature],\n );\n const mergedOptions = useMemo(\n (): readonly FormFieldOption[] =>\n mergeFormDataSourceOptions(snapshotOptions, remoteOptions),\n [remoteOptions, snapshotOptions],\n );\n const invalidValues = useMemo(\n (): readonly string[] =>\n readMissingFormDataSourceOptionValues(\n dynamicField ? input.formData[dynamicField.fieldKey] : undefined,\n mergedOptions,\n ),\n [dynamicField, input.formData, mergedOptions],\n );\n const hasValue = readFormDataSourceValuePresent(\n dynamicField ? input.formData[dynamicField.fieldKey] : undefined,\n );\n\n const loadOptions = useCallback(\n (nextSearchTextToLoad: string, cursor: string | null): void => {\n if (!dynamicField || !effectiveContext) {\n return;\n }\n\n if (missingDependencies.length > 0) {\n setStatus('WAITING_FOR_DEPENDENCIES');\n setError(null);\n\n return;\n }\n\n const requestId = requestSequence.current + 1;\n requestSequence.current = requestId;\n lastRequest.current = {\n cursor,\n searchText: nextSearchTextToLoad,\n };\n setStatus(isStale ? 'STALE' : 'LOADING');\n setError(null);\n\n const request =\n effectiveContext.kind === 'preview'\n ? previewFormFieldOptions({\n cursor,\n fieldKey: dynamicField.fieldKey,\n formData: queryFormData,\n schema: input.schema,\n searchText: nextSearchTextToLoad,\n uiSchema: input.uiSchema,\n })\n : readFormFieldOptions({\n cursor,\n fieldKey: dynamicField.fieldKey,\n formData: queryFormData,\n instanceId: effectiveContext.instanceId ?? null,\n searchText: nextSearchTextToLoad,\n templateId: effectiveContext.templateId ?? null,\n });\n\n void request\n .then((result): void => {\n if (requestSequence.current !== requestId) {\n return;\n }\n\n setRemoteOptions((currentOptions) => {\n const currentValue = dynamicField\n ? input.formData[dynamicField.fieldKey]\n : undefined;\n const selectedOptions = readSelectedFormDataSourceOptions(\n currentValue,\n currentOptions,\n );\n\n return mergeFormDataSourceOptions(\n selectedOptions,\n cursor ? currentOptions : [],\n result.options,\n );\n });\n setNextCursor(result.nextCursor);\n setStatus('VALID');\n setError(null);\n })\n .catch((requestError: unknown): void => {\n if (requestSequence.current !== requestId) {\n return;\n }\n\n setStatus('UNAVAILABLE');\n // The backend answers with stable codes rather than prose, so show\n // the mapped copy instead of a raw `FORM_DATA_SOURCE_*` string.\n setError(\n readFormDataSourceErrorMessage(requestError) ??\n (requestError instanceof Error\n ? requestError.message\n : '選項來源暫時無法使用。'),\n );\n });\n },\n [\n dynamicField,\n effectiveContext,\n isStale,\n missingDependencies.length,\n queryFormData,\n schemaSignature,\n uiSchemaSignature,\n ],\n );\n const loadOptionsRef = useRef(loadOptions);\n loadOptionsRef.current = loadOptions;\n\n useEffect((): void => {\n requestSequence.current += 1;\n setRemoteOptions((currentOptions) => {\n const currentValue = dynamicField\n ? input.formData[dynamicField.fieldKey]\n : undefined;\n\n return readSelectedFormDataSourceOptions(currentValue, currentOptions);\n });\n setNextCursor((currentCursor) =>\n currentCursor === null ? currentCursor : null,\n );\n setSearchText((currentSearchText) =>\n currentSearchText ? '' : currentSearchText,\n );\n setError((currentError) => (currentError ? null : currentError));\n\n if (!dynamicField) {\n setStatus('IDLE');\n\n return;\n }\n\n if (missingDependencies.length > 0) {\n setStatus('WAITING_FOR_DEPENDENCIES');\n\n return;\n }\n\n if (!effectiveContext) {\n setStatus(\n snapshot\n ? isStale\n ? 'STALE'\n : 'VALID'\n : input.readonly\n ? 'UNAVAILABLE'\n : 'IDLE',\n );\n\n return;\n }\n\n if (dynamicField.type === 'autocomplete') {\n setStatus(snapshot ? (isStale ? 'STALE' : 'VALID') : 'IDLE');\n\n return;\n }\n\n loadOptionsRef.current('', null);\n }, [\n dynamicField,\n effectiveContext,\n dataSourceRefreshSignature,\n initialFormDataSignature,\n input.readonly,\n isStale,\n missingDependenciesSignature,\n snapshotSignature,\n ]);\n\n const onSearch = useCallback(\n (nextSearchTextToLoad: string): void => {\n setSearchText(nextSearchTextToLoad);\n setRemoteOptions((currentOptions) => {\n const currentValue = dynamicField\n ? input.formData[dynamicField.fieldKey]\n : undefined;\n\n return readSelectedFormDataSourceOptions(currentValue, currentOptions);\n });\n setNextCursor(null);\n loadOptions(nextSearchTextToLoad, null);\n },\n [loadOptions],\n );\n const onReachBottom = useCallback((): void => {\n if (nextCursor) {\n loadOptions(searchText, nextCursor);\n }\n }, [loadOptions, nextCursor, searchText]);\n const retry = useCallback((): void => {\n loadOptions(lastRequest.current.searchText, lastRequest.current.cursor);\n }, [loadOptions]);\n\n if (!dynamicField) {\n return EMPTY_FIELD_STATE;\n }\n\n return {\n error,\n hasValue,\n hasNextPage: Boolean(nextCursor),\n invalidValues,\n onReachBottom,\n onSearch,\n options: mergedOptions,\n retry,\n status: status === 'VALID' && invalidValues.length ? 'INVALID' : status,\n };\n}\n\nexport function readFormDataSourceFieldStatusMessage(\n state: FormDataSourceFieldState,\n): string | null {\n switch (state.status) {\n case 'WAITING_FOR_DEPENDENCIES':\n return '請先填寫相依欄位。';\n case 'STALE':\n return '選項需要重新載入或驗證。';\n case 'INVALID':\n return state.invalidValues.length\n ? `無法辨識選項:${state.invalidValues.join('、')}`\n : '目前選項已失效,請重新選擇。';\n case 'UNAVAILABLE':\n return state.error ?? '選項來源暫時無法使用。';\n case 'VALID':\n return state.options.length ? null : '目前沒有可用選項。';\n default:\n return null;\n }\n}\n\nexport function isFormDataSourceFieldSubmissionBlocked(\n state: Pick<FormDataSourceFieldState, 'hasValue' | 'status'>,\n): boolean {\n return state.hasValue && state.status !== 'VALID';\n}\n\nfunction readFormDataSourceValuePresent(\n value: FormFieldValue | undefined,\n): boolean {\n if (typeof value === 'undefined' || value === null) {\n return false;\n }\n\n if (typeof value === 'string') {\n return value.trim().length > 0;\n }\n\n if (Array.isArray(value)) {\n return value.length > 0;\n }\n\n return true;\n}\n","'use client';\n\nimport {\n ChangeEvent,\n CSSProperties,\n ReactElement,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n AutoComplete,\n Button,\n CheckboxGroup,\n DatePicker,\n DateTimePicker,\n Input,\n RadioGroup,\n Select,\n Textarea,\n Toggle,\n Typography,\n Upload,\n} from '@mezzanine-ui/react';\nimport type { UploadFile } from '@mezzanine-ui/react/Upload';\nimport {\n FormDataSourceOptionFieldDefinition,\n FormDataSourceValueSnapshots,\n FormDefinitionSchema,\n FormFieldDefinition,\n FormFieldValue,\n FormUiSchema,\n isFormDataSourceFieldDefinition,\n isFormStaticOptionFieldDefinition,\n readFormFieldSelectionMode,\n} from '@rytass/bpm-core-shared/form';\nimport {\n buildFormRendererValues,\n clampOptionalNumber,\n formatDatePickerValue,\n formatDateTimePickerValue,\n FormRendererValues,\n isFormRendererFieldReadonly,\n isFormRendererFieldRequired,\n parseOptionalNumberInput,\n readDatePickerValue,\n readFieldOptionAsSelectOption,\n readSelectedFormDataSourceOptions,\n readSelectOption,\n readVisibleFormRendererFields,\n} from '@rytass/bpm-core-client/form';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport {\n FormDataSourceFieldState,\n FormRendererDataSourceContext,\n readFormDataSourceFieldStatusMessage,\n useFormDataSourceField,\n} from './form-data-source-field';\n\nexport interface FormRendererProps {\n readonly dataSourceContext?: FormRendererDataSourceContext;\n readonly dataSourceInitialValues?: FormRendererValues;\n readonly emptyText?: string;\n readonly errors?: Readonly<Record<string, string>>;\n readonly maxWidth?: CSSProperties['maxWidth'];\n readonly onChange?: (values: FormRendererValues) => void;\n readonly onDataSourceStateChange?: (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'status'\n >,\n ) => void;\n readonly onUploadAttachment?: (\n field: FormFieldDefinition,\n file: File,\n ) => Promise<{ readonly id: string }>;\n readonly optionSnapshots?: FormDataSourceValueSnapshots;\n readonly readonly?: boolean;\n readonly schema: FormDefinitionSchema;\n readonly singleColumn?: boolean;\n readonly uiSchema: FormUiSchema;\n readonly value?: FormRendererValues;\n}\n\nconst FORM_RENDERER_GRID_STYLE: CSSProperties = {\n alignItems: 'start',\n display: 'grid',\n gap: 12,\n gridTemplateColumns: 'repeat(12, minmax(0, 1fr))',\n};\n\nconst FORM_RENDERER_EMPTY_STYLE: CSSProperties = {\n gridColumn: '1 / -1',\n};\n\nconst FORM_RENDERER_FIELD_STYLE: CSSProperties = {\n alignItems: 'start',\n display: 'grid',\n gap: 8,\n minWidth: 0,\n};\n\nconst TEXTAREA_STYLE: CSSProperties = {\n minWidth: '100%',\n width: '100%',\n};\n\nfunction applyFullWidthTextareaHost(element: HTMLDivElement | null): void {\n if (!element) {\n return;\n }\n\n element.style.width = '100%';\n}\n\nexport function FormRenderer({\n dataSourceContext,\n dataSourceInitialValues,\n emptyText = '尚未建立欄位。',\n errors = {},\n maxWidth,\n onChange,\n onDataSourceStateChange,\n onUploadAttachment,\n optionSnapshots,\n readonly = false,\n schema,\n singleColumn = false,\n uiSchema,\n value,\n}: FormRendererProps): ReactElement {\n const [internalValues, setInternalValues] = useState<FormRendererValues>(() =>\n buildFormRendererValues(schema.fields, value ?? {}),\n );\n const values = useMemo(\n (): FormRendererValues =>\n buildFormRendererValues(schema.fields, value ?? internalValues),\n [internalValues, schema.fields, value],\n );\n const valuesRef = useRef<FormRendererValues>(values);\n const visibleFields = useMemo(\n (): readonly FormFieldDefinition[] =>\n readVisibleFormRendererFields(schema, uiSchema, values),\n [schema, uiSchema, values],\n );\n\n useEffect((): void => {\n valuesRef.current = values;\n }, [values]);\n\n useEffect((): void => {\n setInternalValues((currentValues) =>\n buildFormRendererValues(schema.fields, value ?? currentValues),\n );\n }, [schema.fields, value]);\n\n function updateValue(\n fieldKey: string,\n nextValue: FormFieldValue | undefined,\n ): void {\n const nextValues = {\n ...valuesRef.current,\n [fieldKey]: nextValue,\n };\n valuesRef.current = nextValues;\n\n if (!value) {\n setInternalValues(nextValues);\n }\n\n onChange?.(nextValues);\n }\n\n if (!visibleFields.length) {\n return (\n <div style={FORM_RENDERER_GRID_STYLE}>\n <Typography\n color=\"text-neutral\"\n style={FORM_RENDERER_EMPTY_STYLE}\n variant=\"body\"\n >\n {schema.fields.length > 0 ? '目前條件下沒有可填寫欄位。' : emptyText}\n </Typography>\n </div>\n );\n }\n\n return (\n <div\n style={{\n ...FORM_RENDERER_GRID_STYLE,\n ...(singleColumn ? { maxWidth, width: '100%' } : {}),\n }}\n >\n {visibleFields.map((field) => (\n <FormRendererField\n dataSourceContext={dataSourceContext}\n dataSourceInitialValues={dataSourceInitialValues}\n field={field}\n error={errors[field.fieldKey] ?? null}\n fields={schema.fields}\n key={field.fieldKey}\n onChange={updateValue}\n onDataSourceStateChange={onDataSourceStateChange}\n onUploadAttachment={onUploadAttachment}\n optionSnapshots={optionSnapshots}\n readonly={readonly}\n schema={schema}\n style={{\n ...FORM_RENDERER_FIELD_STYLE,\n gridColumn: `span ${\n singleColumn ? 12 : readFieldColumnSpan(field, uiSchema)\n }`,\n }}\n value={values[field.fieldKey]}\n values={values}\n uiSchema={uiSchema}\n />\n ))}\n </div>\n );\n}\n\nfunction FormRendererField({\n dataSourceContext,\n dataSourceInitialValues,\n error,\n field,\n fields,\n onChange,\n onDataSourceStateChange,\n onUploadAttachment,\n optionSnapshots,\n readonly,\n schema,\n style,\n value,\n values,\n uiSchema,\n}: {\n readonly dataSourceContext?: FormRendererDataSourceContext;\n readonly dataSourceInitialValues?: FormRendererValues;\n readonly error: string | null;\n readonly field: FormFieldDefinition;\n readonly fields: readonly FormFieldDefinition[];\n readonly onChange: (\n fieldKey: string,\n value: FormFieldValue | undefined,\n ) => void;\n readonly onDataSourceStateChange?: (\n fieldKey: string,\n state: Pick<\n FormDataSourceFieldState,\n 'hasValue' | 'invalidValues' | 'status'\n >,\n ) => void;\n readonly onUploadAttachment?:\n | ((\n field: FormFieldDefinition,\n file: File,\n ) => Promise<{ readonly id: string }>)\n | undefined;\n readonly optionSnapshots?: FormDataSourceValueSnapshots;\n readonly readonly: boolean;\n readonly schema: FormDefinitionSchema;\n readonly style: CSSProperties;\n readonly uiSchema: FormUiSchema;\n readonly value: FormFieldValue | undefined;\n readonly values: FormRendererValues;\n}): ReactElement {\n const required = isFormRendererFieldRequired(field, fields, values);\n const fieldReadonly =\n readonly || isFormRendererFieldReadonly(field, fields, values);\n const dataSourceState = useFormDataSourceField({\n context: dataSourceContext,\n field,\n formData: values,\n initialFormData: dataSourceInitialValues,\n initialValue: dataSourceInitialValues?.[field.fieldKey],\n optionSnapshots,\n readonly: fieldReadonly,\n schema,\n uiSchema,\n });\n const dataSourceStatusMessage = readFormDataSourceFieldStatusMessage(\n dataSourceState,\n );\n const dataSourceStateSignature = JSON.stringify({\n hasValue: dataSourceState.hasValue,\n invalidValues: dataSourceState.invalidValues,\n status: dataSourceState.status,\n });\n\n useEffect((): void => {\n if (!isFormDataSourceFieldDefinition(field)) {\n return;\n }\n\n onDataSourceStateChange?.(field.fieldKey, {\n hasValue: dataSourceState.hasValue,\n invalidValues: dataSourceState.invalidValues,\n status: dataSourceState.status,\n });\n }, [\n dataSourceStateSignature,\n field.fieldKey,\n onDataSourceStateChange,\n ]);\n\n return (\n <div data-form-field-key={field.fieldKey} style={style}>\n <BPMFormField\n label={field.label}\n name={field.fieldKey}\n required={required}\n >\n {renderControl(\n field,\n value,\n fieldReadonly,\n onChange,\n onUploadAttachment,\n dataSourceContext,\n dataSourceState,\n )}\n </BPMFormField>\n {error ? (\n <Typography color=\"text-error\" variant=\"caption\">\n {error}\n </Typography>\n ) : null}\n {dataSourceStatusMessage ? (\n <div style={DATA_SOURCE_FEEDBACK_STYLE}>\n <Typography\n color={\n dataSourceState.status === 'INVALID' ||\n dataSourceState.status === 'UNAVAILABLE'\n ? 'text-error'\n : 'text-neutral'\n }\n variant=\"caption\"\n >\n {dataSourceStatusMessage}\n </Typography>\n {dataSourceState.status === 'UNAVAILABLE' ? (\n <Button\n onClick={dataSourceState.retry}\n size=\"sub\"\n type=\"button\"\n variant=\"base-ghost\"\n >\n 重試\n </Button>\n ) : null}\n </div>\n ) : null}\n </div>\n );\n}\n\nconst DATA_SOURCE_FEEDBACK_STYLE: CSSProperties = {\n alignItems: 'center',\n display: 'flex',\n gap: 8,\n};\n\nfunction renderControl(\n field: FormFieldDefinition,\n value: FormFieldValue | undefined,\n readonly: boolean,\n onChange: (fieldKey: string, value: FormFieldValue | undefined) => void,\n onUploadAttachment:\n | ((\n field: FormFieldDefinition,\n file: File,\n ) => Promise<{ readonly id: string }>)\n | undefined,\n dataSourceContext: FormRendererDataSourceContext | undefined,\n dataSourceState: FormDataSourceFieldState,\n): ReactElement {\n if (field.type === 'textarea') {\n return (\n <Textarea\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void =>\n onChange(field.fieldKey, event.target.value)\n }\n placeholder={field.placeholder ?? '請輸入多行文字'}\n readOnly={readonly}\n ref={applyFullWidthTextareaHost}\n rows={3}\n style={TEXTAREA_STYLE}\n value={readStringValue(value)}\n />\n );\n }\n\n if (field.type === 'boolean') {\n return (\n <Toggle\n checked={value === true}\n disabled={readonly}\n label=\"啟用\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onChange(field.fieldKey, event.target.checked)\n }\n />\n );\n }\n\n if (isFormDataSourceFieldDefinition(field)) {\n return renderDynamicOptionControl(\n field,\n value,\n readonly,\n onChange,\n dataSourceContext,\n dataSourceState,\n );\n }\n\n if (isFormStaticOptionFieldDefinition(field) && field.type === 'checkbox') {\n const options = field.options.map(readFieldOptionAsSelectOption);\n\n return (\n <Select\n mode=\"multiple\"\n onChange={(options): void =>\n onChange(\n field.fieldKey,\n options?.length\n ? options.map((option) => option.id)\n : undefined,\n )\n }\n options={options}\n placeholder={field.placeholder ?? '請選擇一或多個選項'}\n readOnly={readonly}\n value={options.filter((option) =>\n readStringArrayValue(value).includes(option.id),\n )}\n />\n );\n }\n\n if (isFormStaticOptionFieldDefinition(field)) {\n const options = field.options.map(readFieldOptionAsSelectOption);\n\n return (\n <Select\n onChange={(option): void =>\n onChange(field.fieldKey, option?.id ?? undefined)\n }\n options={options}\n placeholder={field.placeholder ?? '請選擇'}\n readOnly={readonly}\n value={readSelectOption(options, readStringValue(value))}\n />\n );\n }\n\n if (field.type === 'file_upload') {\n return (\n <Upload\n accept={field.acceptedMimeTypes?.join(',')}\n disabled={readonly}\n maxFiles={field.maxFiles}\n mode=\"button-list\"\n {...((field.maxFiles ?? 1) > 1 ? { multiple: true } : {})}\n onChange={(files): void =>\n onChange(\n field.fieldKey,\n files.length ? files.map((file) => file.id) : undefined,\n )\n }\n onUpload={async (files): Promise<UploadFile[]> =>\n Promise.all(\n files.map(async (file): Promise<UploadFile> => {\n const uploadedFile = onUploadAttachment\n ? await onUploadAttachment(field, file)\n : { id: `${file.name}-${file.lastModified}` };\n\n return {\n file,\n id: uploadedFile.id,\n progress: 100,\n status: 'done',\n };\n }),\n )\n }\n size=\"sub\"\n />\n );\n }\n\n if (field.type === 'date') {\n return (\n <DatePicker\n format=\"YYYY-MM-DD\"\n fullWidth\n onChange={(nextValue): void =>\n onChange(field.fieldKey, formatDatePickerValue(nextValue))\n }\n placeholder={field.placeholder ?? readInputPlaceholder(field.type)}\n readOnly={readonly}\n value={readDatePickerValue(value)}\n />\n );\n }\n\n if (field.type === 'datetime') {\n return (\n <DateTimePicker\n formatDate=\"YYYY-MM-DD\"\n formatTime=\"HH:mm\"\n fullWidth\n hideSecond\n onChange={(nextValue): void =>\n onChange(field.fieldKey, formatDateTimePickerValue(nextValue))\n }\n placeholderLeft=\"選擇日期\"\n placeholderRight=\"選擇時間\"\n readOnly={readonly}\n value={readDatePickerValue(value)}\n />\n );\n }\n\n if (field.type === 'number' || field.type === 'money') {\n return (\n <Input\n fullWidth\n max={field.maximum}\n min={field.minimum}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onChange(\n field.fieldKey,\n clampOptionalNumber(parseOptionalNumberInput(event.target.value), {\n max: field.maximum,\n min: field.minimum,\n }),\n )\n }\n placeholder={field.placeholder ?? readInputPlaceholder(field.type)}\n {...(readonly ? { readonly: true as const } : {})}\n showSpinner\n value={readNumberInputValue(value)}\n variant=\"measure\"\n />\n );\n }\n\n return (\n <Input\n fullWidth\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onChange(field.fieldKey, event.target.value)\n }\n placeholder={field.placeholder ?? readInputPlaceholder(field.type)}\n {...(readonly ? { readonly: true as const } : {})}\n value={readStringValue(value)}\n variant=\"base\"\n />\n );\n}\n\nfunction renderDynamicOptionControl(\n field: FormDataSourceOptionFieldDefinition,\n value: FormFieldValue | undefined,\n readonly: boolean,\n onChange: (fieldKey: string, value: FormFieldValue | undefined) => void,\n dataSourceContext: FormRendererDataSourceContext | undefined,\n dataSourceState: FormDataSourceFieldState,\n): ReactElement {\n const options = dataSourceState.options.map(readFieldOptionAsSelectOption);\n const selectedOptions = readSelectedFormDataSourceOptions(\n value,\n dataSourceState.options,\n ).map(readFieldOptionAsSelectOption);\n const loading = dataSourceState.status === 'LOADING';\n const waitingForDependencies =\n dataSourceState.status === 'WAITING_FOR_DEPENDENCIES';\n const interactiveSearch = Boolean(dataSourceContext) && !readonly;\n const optionControlDisabled = readonly || waitingForDependencies;\n\n if (field.type === 'autocomplete') {\n if (readFormFieldSelectionMode(field) === 'multiple') {\n return (\n <AutoComplete\n asyncData={interactiveSearch}\n clearSearchText\n disabled={optionControlDisabled}\n disabledOptionsFilter={interactiveSearch}\n globalPortal\n loading={loading}\n mode=\"multiple\"\n onChange={(nextOptions): void =>\n onChange(\n field.fieldKey,\n nextOptions.length\n ? nextOptions.map((option) => option.id)\n : undefined,\n )\n }\n onReachBottom={\n dataSourceState.hasNextPage\n ? dataSourceState.onReachBottom\n : undefined\n }\n onSearch={interactiveSearch ? dataSourceState.onSearch : undefined}\n options={options}\n placeholder={field.placeholder ?? '請輸入或選擇'}\n readOnly={readonly}\n searchDebounceTime={300}\n value={selectedOptions}\n />\n );\n }\n\n return (\n <AutoComplete\n asyncData={interactiveSearch}\n clearSearchText\n disabled={optionControlDisabled}\n disabledOptionsFilter={interactiveSearch}\n globalPortal\n loading={loading}\n mode=\"single\"\n onChange={(nextOption): void =>\n onChange(field.fieldKey, nextOption?.id ?? undefined)\n }\n onReachBottom={\n dataSourceState.hasNextPage\n ? dataSourceState.onReachBottom\n : undefined\n }\n onSearch={interactiveSearch ? dataSourceState.onSearch : undefined}\n options={options}\n placeholder={field.placeholder ?? '請輸入或選擇'}\n readOnly={readonly}\n searchDebounceTime={300}\n value={selectedOptions[0] ?? null}\n />\n );\n }\n\n if (field.type === 'radio') {\n return (\n <RadioGroup\n disabled={optionControlDisabled}\n name={field.fieldKey}\n onChange={(event): void =>\n onChange(field.fieldKey, event.target.value || undefined)\n }\n options={options}\n value={readStringValue(value)}\n />\n );\n }\n\n if (field.type === 'checkbox') {\n return (\n <CheckboxGroup\n disabled={optionControlDisabled}\n name={field.fieldKey}\n onChange={(event): void =>\n onChange(\n field.fieldKey,\n event.target.values.length ? event.target.values : undefined,\n )\n }\n options={options.map((option) => ({\n label: option.name,\n value: option.id,\n }))}\n value={[...readStringArrayValue(value)]}\n />\n );\n }\n\n if (readFormFieldSelectionMode(field) === 'multiple') {\n return (\n <Select\n disabled={optionControlDisabled}\n loading={loading}\n mode=\"multiple\"\n onChange={(nextOptions): void =>\n onChange(\n field.fieldKey,\n nextOptions.length\n ? nextOptions.map((option) => option.id)\n : undefined,\n )\n }\n onReachBottom={\n dataSourceState.hasNextPage\n ? dataSourceState.onReachBottom\n : undefined\n }\n options={options}\n placeholder={field.placeholder ?? '請選擇一或多個選項'}\n readOnly={readonly}\n value={selectedOptions}\n />\n );\n }\n\n return (\n <Select\n disabled={optionControlDisabled}\n loading={loading}\n onChange={(nextOption): void =>\n onChange(field.fieldKey, nextOption?.id ?? undefined)\n }\n onReachBottom={\n dataSourceState.hasNextPage\n ? dataSourceState.onReachBottom\n : undefined\n }\n options={options}\n placeholder={field.placeholder ?? '請選擇'}\n readOnly={readonly}\n value={selectedOptions[0] ?? null}\n />\n );\n}\n\nfunction readFieldColumnSpan(\n field: FormFieldDefinition,\n uiSchema: FormUiSchema,\n): number {\n const width =\n uiSchema.layout.find((item) => item.fieldKey === field.fieldKey)?.width ??\n 'FULL';\n const spans: Readonly<Record<typeof width, number>> = {\n FULL: 12,\n HALF: 6,\n THIRD: 4,\n };\n\n return spans[width];\n}\n\nfunction readStringValue(value: FormFieldValue | undefined): string {\n return typeof value === 'string' ? value : '';\n}\n\nfunction readStringArrayValue(\n value: FormFieldValue | undefined,\n): readonly string[] {\n return Array.isArray(value) ? value : [];\n}\n\nfunction readNumberInputValue(value: FormFieldValue | undefined): string {\n return typeof value === 'number' ? String(value) : '';\n}\n\nfunction readInputPlaceholder(type: FormFieldDefinition['type']): string {\n const placeholders: Readonly<Record<FormFieldDefinition['type'], string>> = {\n boolean: '',\n autocomplete: '請輸入或選擇',\n checkbox: '請選擇一或多個選項',\n date: '請選擇日期',\n datetime: '請選擇日期與時間',\n file_upload: '請上傳附件',\n money: '請輸入金額',\n number: '請輸入數字',\n radio: '請選擇一個選項',\n select: '請選擇一個選項',\n text: '請輸入文字',\n textarea: '請輸入多行文字',\n };\n\n return placeholders[type];\n}\n\nexport { FormRenderer as FormRendererView };\n"],"mappings":"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"}
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
import { r as e } from "./router-adapter-DftlFTOd.js";
|
|
3
3
|
import { t } from "./format-date-time-CB-LxzqT.js";
|
|
4
4
|
import { r as n } from "./routes-config-RBYQtUd0.js";
|
|
5
|
-
import { useCallback as r, useEffect as i, useMemo as a,
|
|
6
|
-
import { Filter as
|
|
7
|
-
import { resolveMembers as
|
|
5
|
+
import { useCallback as r, useEffect as i, useMemo as a, useRef as o, useState as s } from "react";
|
|
6
|
+
import { Filter as c, FilterArea as ee, FilterLine as te, FormField as l, Input as u, PageHeader as d, Section as ne, SectionGroup as f, Select as p, Table as m, Typography as h } from "@mezzanine-ui/react";
|
|
7
|
+
import { resolveMembers as re } from "@rytass/bpm-core-client";
|
|
8
8
|
import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
9
|
-
import { listApprovalInstancesPage as
|
|
9
|
+
import { listApprovalInstancesPage as ie, readApprovalInstanceCaseTitle as y } from "@rytass/bpm-core-client/workflow";
|
|
10
|
+
import { FormFieldLayout as b } from "@mezzanine-ui/core/form";
|
|
10
11
|
import x from "@mezzanine-ui/react/ContentHeader";
|
|
11
|
-
import {
|
|
12
|
-
import '../approval-instance-list-page.css';var C = { instanceFilterArea: "bpm_instanceFilterArea_qpvJq" }, w = [
|
|
12
|
+
import '../approval-instance-list-page.css';var S = { instanceFilterArea: "bpm_instanceFilterArea_qpvJq" }, C = [
|
|
13
13
|
10,
|
|
14
14
|
20,
|
|
15
15
|
50
|
|
16
|
-
],
|
|
16
|
+
], w = [
|
|
17
17
|
{
|
|
18
18
|
id: "ALL",
|
|
19
19
|
name: "全部狀態",
|
|
@@ -55,11 +55,12 @@ import '../approval-instance-list-page.css';var C = { instanceFilterArea: "bpm_i
|
|
|
55
55
|
state: "DRAFT"
|
|
56
56
|
}
|
|
57
57
|
];
|
|
58
|
-
function
|
|
59
|
-
let F = e(), I = n(), [L, R] =
|
|
60
|
-
|
|
58
|
+
function T({ defaultState: y, description: T, emptyMessage: O, searchPlaceholder: k, title: N, view: P }) {
|
|
59
|
+
let F = e(), I = n(), [L, R] = s(null), [z, B] = s(/* @__PURE__ */ new Map()), [V, H] = s(1), [U, W] = s(10), [G, K] = s(0), [q, J] = s(!0), [Y, se] = s([]), [X, ce] = s(""), [Z, le] = s(D(y)), Q = o(0), $ = r(async () => {
|
|
60
|
+
let e = Q.current + 1;
|
|
61
|
+
Q.current = e, J(!0), R(null);
|
|
61
62
|
try {
|
|
62
|
-
let
|
|
63
|
+
let t = await ie({
|
|
63
64
|
page: V,
|
|
64
65
|
pageSize: U,
|
|
65
66
|
searchText: X,
|
|
@@ -67,11 +68,12 @@ function E({ defaultState: b, description: E, emptyMessage: O, searchPlaceholder
|
|
|
67
68
|
templateId: null,
|
|
68
69
|
view: P
|
|
69
70
|
});
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
if (e !== Q.current) return;
|
|
72
|
+
se(t.instances.map(E)), K(t.totalCount);
|
|
73
|
+
} catch (t) {
|
|
74
|
+
e === Q.current && R(M(t));
|
|
73
75
|
} finally {
|
|
74
|
-
J(!1);
|
|
76
|
+
e === Q.current && J(!1);
|
|
75
77
|
}
|
|
76
78
|
}, [
|
|
77
79
|
V,
|
|
@@ -91,7 +93,7 @@ function E({ defaultState: b, description: E, emptyMessage: O, searchPlaceholder
|
|
|
91
93
|
let t = !1;
|
|
92
94
|
return (async () => {
|
|
93
95
|
try {
|
|
94
|
-
let n = await
|
|
96
|
+
let n = await re(e);
|
|
95
97
|
if (t) return;
|
|
96
98
|
B(new Map(n.map((e) => [e.memberId, e])));
|
|
97
99
|
} catch {
|
|
@@ -102,7 +104,7 @@ function E({ defaultState: b, description: E, emptyMessage: O, searchPlaceholder
|
|
|
102
104
|
t = !0;
|
|
103
105
|
};
|
|
104
106
|
}, [Y]);
|
|
105
|
-
let
|
|
107
|
+
let ue = a(() => [
|
|
106
108
|
{
|
|
107
109
|
dataIndex: "caseTitle",
|
|
108
110
|
key: "caseTitle",
|
|
@@ -111,7 +113,7 @@ function E({ defaultState: b, description: E, emptyMessage: O, searchPlaceholder
|
|
|
111
113
|
},
|
|
112
114
|
{
|
|
113
115
|
key: "state",
|
|
114
|
-
render: (e) => /* @__PURE__ */ _(
|
|
116
|
+
render: (e) => /* @__PURE__ */ _(h, {
|
|
115
117
|
color: A(e.state),
|
|
116
118
|
component: "span",
|
|
117
119
|
variant: "body",
|
|
@@ -122,7 +124,7 @@ function E({ defaultState: b, description: E, emptyMessage: O, searchPlaceholder
|
|
|
122
124
|
},
|
|
123
125
|
{
|
|
124
126
|
key: "initiatorMemberId",
|
|
125
|
-
render: (e) => /* @__PURE__ */ _(
|
|
127
|
+
render: (e) => /* @__PURE__ */ _(h, {
|
|
126
128
|
component: "span",
|
|
127
129
|
variant: "body",
|
|
128
130
|
children: j(e.initiatorMemberId, z)
|
|
@@ -132,7 +134,7 @@ function E({ defaultState: b, description: E, emptyMessage: O, searchPlaceholder
|
|
|
132
134
|
},
|
|
133
135
|
{
|
|
134
136
|
key: "startedAt",
|
|
135
|
-
render: (e) => /* @__PURE__ */ _(
|
|
137
|
+
render: (e) => /* @__PURE__ */ _(h, {
|
|
136
138
|
component: "span",
|
|
137
139
|
variant: "body",
|
|
138
140
|
children: t(e.startedAt)
|
|
@@ -142,7 +144,7 @@ function E({ defaultState: b, description: E, emptyMessage: O, searchPlaceholder
|
|
|
142
144
|
},
|
|
143
145
|
{
|
|
144
146
|
key: "completedAt",
|
|
145
|
-
render: (e) => /* @__PURE__ */ _(
|
|
147
|
+
render: (e) => /* @__PURE__ */ _(h, {
|
|
146
148
|
component: "span",
|
|
147
149
|
variant: "body",
|
|
148
150
|
children: t(e.completedAt)
|
|
@@ -150,7 +152,7 @@ function E({ defaultState: b, description: E, emptyMessage: O, searchPlaceholder
|
|
|
150
152
|
title: "完成時間",
|
|
151
153
|
width: 220
|
|
152
154
|
}
|
|
153
|
-
], [z]),
|
|
155
|
+
], [z]), de = a(() => ({
|
|
154
156
|
render: (e) => [{
|
|
155
157
|
name: "查看",
|
|
156
158
|
onClick: () => F.push(I.caseDetail(e.id))
|
|
@@ -158,23 +160,23 @@ function E({ defaultState: b, description: E, emptyMessage: O, searchPlaceholder
|
|
|
158
160
|
variant: "base-secondary",
|
|
159
161
|
width: 88
|
|
160
162
|
}), [F]);
|
|
161
|
-
return /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(
|
|
162
|
-
description:
|
|
163
|
+
return /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(d, { children: /* @__PURE__ */ _(x, {
|
|
164
|
+
description: T,
|
|
163
165
|
title: N
|
|
164
|
-
}) }), /* @__PURE__ */ _(
|
|
165
|
-
filterArea: /* @__PURE__ */ _(
|
|
166
|
-
className:
|
|
166
|
+
}) }), /* @__PURE__ */ _(f, { children: /* @__PURE__ */ v(ne, {
|
|
167
|
+
filterArea: /* @__PURE__ */ _(ee, {
|
|
168
|
+
className: S.instanceFilterArea,
|
|
167
169
|
size: "sub",
|
|
168
|
-
children: /* @__PURE__ */ v(
|
|
170
|
+
children: /* @__PURE__ */ v(te, { children: [/* @__PURE__ */ _(c, {
|
|
169
171
|
span: 3,
|
|
170
|
-
children: /* @__PURE__ */ _(
|
|
172
|
+
children: /* @__PURE__ */ _(l, {
|
|
171
173
|
fullWidth: !0,
|
|
172
|
-
layout:
|
|
174
|
+
layout: b.VERTICAL,
|
|
173
175
|
name: "instanceSearchText",
|
|
174
|
-
children: /* @__PURE__ */ _(
|
|
176
|
+
children: /* @__PURE__ */ _(u, {
|
|
175
177
|
fullWidth: !0,
|
|
176
178
|
onChange: (e) => {
|
|
177
|
-
|
|
179
|
+
ce(e.target.value), H(1);
|
|
178
180
|
},
|
|
179
181
|
placeholder: k,
|
|
180
182
|
size: "sub",
|
|
@@ -182,21 +184,21 @@ function E({ defaultState: b, description: E, emptyMessage: O, searchPlaceholder
|
|
|
182
184
|
variant: "base"
|
|
183
185
|
})
|
|
184
186
|
})
|
|
185
|
-
}), /* @__PURE__ */ _(
|
|
187
|
+
}), /* @__PURE__ */ _(c, {
|
|
186
188
|
span: 2,
|
|
187
|
-
children: /* @__PURE__ */ _(
|
|
189
|
+
children: /* @__PURE__ */ _(l, {
|
|
188
190
|
fullWidth: !0,
|
|
189
|
-
layout:
|
|
191
|
+
layout: b.VERTICAL,
|
|
190
192
|
name: "instanceState",
|
|
191
|
-
children: /* @__PURE__ */ _(
|
|
193
|
+
children: /* @__PURE__ */ _(p, {
|
|
192
194
|
clearable: !1,
|
|
193
195
|
fullWidth: !0,
|
|
194
196
|
onChange: (e) => {
|
|
195
|
-
|
|
197
|
+
le(ae(e)), H(1);
|
|
196
198
|
},
|
|
197
|
-
options: [...
|
|
199
|
+
options: [...w],
|
|
198
200
|
placeholder: "狀態",
|
|
199
|
-
renderValue: (e) => `狀態:${
|
|
201
|
+
renderValue: (e) => `狀態:${oe(e)}`,
|
|
200
202
|
size: "sub",
|
|
201
203
|
value: Z
|
|
202
204
|
})
|
|
@@ -204,19 +206,19 @@ function E({ defaultState: b, description: E, emptyMessage: O, searchPlaceholder
|
|
|
204
206
|
})] })
|
|
205
207
|
}),
|
|
206
208
|
children: [
|
|
207
|
-
L ? /* @__PURE__ */ _(
|
|
209
|
+
L ? /* @__PURE__ */ _(h, {
|
|
208
210
|
color: "text-error",
|
|
209
211
|
variant: "body",
|
|
210
212
|
children: L
|
|
211
213
|
}) : null,
|
|
212
|
-
!L && !q && Y.length === 0 ? /* @__PURE__ */ _(
|
|
214
|
+
!L && !q && Y.length === 0 ? /* @__PURE__ */ _(h, {
|
|
213
215
|
color: "text-neutral",
|
|
214
216
|
variant: "body",
|
|
215
217
|
children: O
|
|
216
218
|
}) : null,
|
|
217
|
-
/* @__PURE__ */ _(
|
|
218
|
-
actions:
|
|
219
|
-
columns:
|
|
219
|
+
/* @__PURE__ */ _(m, {
|
|
220
|
+
actions: de,
|
|
221
|
+
columns: ue,
|
|
220
222
|
dataSource: [...Y],
|
|
221
223
|
fullWidth: !0,
|
|
222
224
|
loading: q,
|
|
@@ -230,7 +232,7 @@ function E({ defaultState: b, description: E, emptyMessage: O, searchPlaceholder
|
|
|
230
232
|
},
|
|
231
233
|
pageSize: U,
|
|
232
234
|
pageSizeLabel: "每頁筆數",
|
|
233
|
-
pageSizeOptions:
|
|
235
|
+
pageSizeOptions: C,
|
|
234
236
|
renderResultSummary: (e, t, n) => `顯示 ${e}-${t} 筆,共 ${n} 筆`,
|
|
235
237
|
showPageSizeOptions: !0,
|
|
236
238
|
total: G
|
|
@@ -239,22 +241,22 @@ function E({ defaultState: b, description: E, emptyMessage: O, searchPlaceholder
|
|
|
239
241
|
]
|
|
240
242
|
}) })] });
|
|
241
243
|
}
|
|
242
|
-
function
|
|
244
|
+
function E(e) {
|
|
243
245
|
return {
|
|
244
246
|
...e,
|
|
245
|
-
caseTitle:
|
|
247
|
+
caseTitle: y(e),
|
|
246
248
|
key: e.id,
|
|
247
249
|
stateLabel: k(e.state)
|
|
248
250
|
};
|
|
249
251
|
}
|
|
250
|
-
function
|
|
251
|
-
return O(e) ? D(e.state) :
|
|
252
|
+
function ae(e) {
|
|
253
|
+
return O(e) ? D(e.state) : w[0];
|
|
252
254
|
}
|
|
253
255
|
function D(e) {
|
|
254
|
-
return
|
|
256
|
+
return w.find((t) => t.state === e) ?? w[0];
|
|
255
257
|
}
|
|
256
|
-
function
|
|
257
|
-
return O(e) ? e.name :
|
|
258
|
+
function oe(e) {
|
|
259
|
+
return O(e) ? e.name : w[0].name;
|
|
258
260
|
}
|
|
259
261
|
function O(e) {
|
|
260
262
|
return typeof e == "object" && !!e && "id" in e && "name" in e && "state" in e;
|
|
@@ -273,6 +275,6 @@ function M(e) {
|
|
|
273
275
|
return e instanceof Error ? e.message : "讀取簽核案件失敗。";
|
|
274
276
|
}
|
|
275
277
|
//#endregion
|
|
276
|
-
export {
|
|
278
|
+
export { T as t };
|
|
277
279
|
|
|
278
|
-
//# sourceMappingURL=approval-instance-list-page-
|
|
280
|
+
//# sourceMappingURL=approval-instance-list-page-BjX2kaoF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-instance-list-page-BjX2kaoF.js","names":[],"sources":["../../src/components/approval-instance-list-page.module.scss","../../src/components/approval-instance-list-page.tsx"],"sourcesContent":[".instanceFilterArea {\n :global(.mzn-filter-area__actions) {\n display: none;\n }\n\n :global(.mzn-form-field__label-area) {\n display: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n}\n","'use client';\n\nimport type { ChangeEvent, ReactElement } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n PageHeader,\n Section,\n SectionGroup,\n Select,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport {\n resolveMembers,\n type MemberProfileRecord,\n} from '@rytass/bpm-core-client';\nimport {\n listApprovalInstancesPage,\n readApprovalInstanceCaseTitle,\n type ApprovalInstanceRecord,\n type ApprovalInstanceState,\n type ApprovalInstanceView,\n} from '@rytass/bpm-core-client/workflow';\nimport { useRouterAdapter } from '../lib/router-adapter';\nimport { useBPMRoutes } from '../lib/routes-config';\nimport { formatDateTime } from '../lib/format-date-time';\nimport styles from './approval-instance-list-page.module.scss';\n\nexport interface ApprovalInstanceListPageProps {\n readonly defaultState: ApprovalInstanceState | null;\n readonly description: string;\n readonly emptyMessage: string;\n readonly searchPlaceholder: string;\n readonly title: string;\n readonly view: ApprovalInstanceView;\n}\n\ntype StateFilterOption = Readonly<{\n id: 'ALL' | ApprovalInstanceState;\n name: string;\n state: ApprovalInstanceState | null;\n}>;\n\ntype ApprovalInstanceRow = Readonly<\n Record<string, unknown> &\n ApprovalInstanceRecord & {\n caseTitle: string;\n key: string;\n stateLabel: string;\n }\n>;\n\nconst INSTANCE_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst STATE_FILTER_OPTIONS: readonly StateFilterOption[] = [\n { id: 'ALL', name: '全部狀態', state: null },\n { id: 'RUNNING', name: '進行中', state: 'RUNNING' },\n { id: 'APPROVED', name: '已通過', state: 'APPROVED' },\n { id: 'REJECTED', name: '已拒絕', state: 'REJECTED' },\n { id: 'RETURNED', name: '已退回', state: 'RETURNED' },\n { id: 'CANCELLED', name: '已取消', state: 'CANCELLED' },\n { id: 'EXPIRED', name: '已逾期', state: 'EXPIRED' },\n { id: 'DRAFT', name: '草稿', state: 'DRAFT' },\n];\n\n/**\n * Shared list page for any approval-instance \"view\" (inbox / sent / cc /\n * delegated). Caller picks the view + default state filter; the page renders\n * the standard BPM filter bar + paginated table and navigates to\n * `/instances/:id` on row action.\n */\nexport function ApprovalInstanceListPage({\n defaultState,\n description,\n emptyMessage,\n searchPlaceholder,\n title,\n view,\n}: ApprovalInstanceListPageProps): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const [error, setError] = useState<string | null>(null);\n const [initiatorProfilesById, setInitiatorProfilesById] = useState<\n ReadonlyMap<string, MemberProfileRecord>\n >(new Map());\n const [instancePage, setInstancePage] = useState(1);\n const [instancePageSize, setInstancePageSize] = useState(10);\n const [instanceTotalCount, setInstanceTotalCount] = useState(0);\n const [loading, setLoading] = useState(true);\n const [rows, setRows] = useState<readonly ApprovalInstanceRow[]>([]);\n const [searchText, setSearchText] = useState('');\n const [stateFilter, setStateFilter] = useState<StateFilterOption>(\n readStateFilterOption(defaultState),\n );\n const refreshRequestIdRef = useRef(0);\n\n const refreshInstances = useCallback(async (): Promise<void> => {\n const requestId = refreshRequestIdRef.current + 1;\n refreshRequestIdRef.current = requestId;\n setLoading(true);\n setError(null);\n\n try {\n const result = await listApprovalInstancesPage({\n page: instancePage,\n pageSize: instancePageSize,\n searchText,\n state: stateFilter.state,\n templateId: null,\n view,\n });\n\n if (requestId !== refreshRequestIdRef.current) {\n return;\n }\n\n setRows(result.instances.map(readApprovalInstanceRow));\n setInstanceTotalCount(result.totalCount);\n } catch (requestError: unknown) {\n if (requestId === refreshRequestIdRef.current) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (requestId === refreshRequestIdRef.current) {\n setLoading(false);\n }\n }\n }, [instancePage, instancePageSize, searchText, stateFilter, view]);\n\n useEffect((): void => {\n void refreshInstances();\n }, [refreshInstances]);\n\n useEffect((): (() => void) | void => {\n const initiatorMemberIds = Array.from(\n new Set(rows.map((row) => row.initiatorMemberId).filter(Boolean)),\n );\n\n if (initiatorMemberIds.length === 0) {\n setInitiatorProfilesById(new Map());\n\n return;\n }\n\n let cancelled = false;\n\n void (async (): Promise<void> => {\n try {\n const profiles = await resolveMembers(initiatorMemberIds);\n\n if (cancelled) {\n return;\n }\n\n setInitiatorProfilesById(\n new Map(profiles.map((profile) => [profile.memberId, profile])),\n );\n } catch {\n if (cancelled) {\n return;\n }\n\n setInitiatorProfilesById(new Map());\n }\n })();\n\n return (): void => {\n cancelled = true;\n };\n }, [rows]);\n\n const columns = useMemo(\n (): TableColumn<ApprovalInstanceRow>[] => [\n { dataIndex: 'caseTitle', key: 'caseTitle', title: '案件', width: 300 },\n {\n key: 'state',\n render: (record: ApprovalInstanceRow): ReactElement => (\n <Typography\n color={readInstanceStateColor(record.state)}\n component=\"span\"\n variant=\"body\"\n >\n {record.stateLabel}\n </Typography>\n ),\n title: '狀態',\n width: 120,\n },\n {\n key: 'initiatorMemberId',\n render: (record: ApprovalInstanceRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {readInitiatorLabel(\n record.initiatorMemberId,\n initiatorProfilesById,\n )}\n </Typography>\n ),\n title: '發起人',\n width: 180,\n },\n {\n key: 'startedAt',\n render: (record: ApprovalInstanceRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.startedAt)}\n </Typography>\n ),\n title: '發起時間',\n width: 220,\n },\n {\n key: 'completedAt',\n render: (record: ApprovalInstanceRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.completedAt)}\n </Typography>\n ),\n title: '完成時間',\n width: 220,\n },\n ],\n [initiatorProfilesById],\n );\n const tableActions = useMemo(\n (): TableActions<ApprovalInstanceRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<ApprovalInstanceRow>['render']> => [\n {\n name: '查看',\n onClick: (): void => router.push(routes.caseDetail(record.id)),\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router],\n );\n\n return (\n <>\n <PageHeader>\n <ContentHeader description={description} title={title} />\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.instanceFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"instanceSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setInstancePage(1);\n }}\n placeholder={searchPlaceholder}\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"instanceState\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void => {\n setStateFilter(readSelectedStateFilterOption(option));\n setInstancePage(1);\n }}\n options={[...STATE_FILTER_OPTIONS]}\n placeholder=\"狀態\"\n renderValue={(value): string =>\n `狀態:${readStateFilterLabel(value)}`\n }\n size=\"sub\"\n value={stateFilter}\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {!error && !loading && rows.length === 0 ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n {emptyMessage}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={[...rows]}\n fullWidth\n loading={loading}\n pagination={{\n current: instancePage,\n onChange: (page): void => {\n setInstancePage(page);\n },\n onChangePageSize: (pageSize): void => {\n setInstancePage(1);\n setInstancePageSize(pageSize);\n },\n pageSize: instancePageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: INSTANCE_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: instanceTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction readApprovalInstanceRow(\n instance: ApprovalInstanceRecord,\n): ApprovalInstanceRow {\n return {\n ...instance,\n caseTitle: readApprovalInstanceCaseTitle(instance),\n key: instance.id,\n stateLabel: readInstanceStateLabel(instance.state),\n };\n}\n\nfunction readSelectedStateFilterOption(option: unknown): StateFilterOption {\n if (!isStateFilterOption(option)) {\n return STATE_FILTER_OPTIONS[0];\n }\n return readStateFilterOption(option.state);\n}\n\nfunction readStateFilterOption(\n state: ApprovalInstanceState | null,\n): StateFilterOption {\n return (\n STATE_FILTER_OPTIONS.find((option) => option.state === state) ??\n STATE_FILTER_OPTIONS[0]\n );\n}\n\nfunction readStateFilterLabel(value: unknown): string {\n return isStateFilterOption(value) ? value.name : STATE_FILTER_OPTIONS[0].name;\n}\n\nfunction isStateFilterOption(value: unknown): value is StateFilterOption {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'id' in value &&\n 'name' in value &&\n 'state' in value\n );\n}\n\nfunction readInstanceStateLabel(state: ApprovalInstanceState): string {\n if (state === 'RUNNING') return '進行中';\n if (state === 'APPROVED') return '已通過';\n if (state === 'REJECTED') return '已拒絕';\n if (state === 'RETURNED') return '已退回';\n if (state === 'CANCELLED') return '已取消';\n if (state === 'EXPIRED') return '已逾期';\n return '草稿';\n}\n\nfunction readInstanceStateColor(\n state: ApprovalInstanceState,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (state === 'APPROVED') return 'text-success';\n if (state === 'REJECTED' || state === 'CANCELLED' || state === 'EXPIRED') {\n return 'text-error';\n }\n return 'text-neutral';\n}\n\nfunction readInitiatorLabel(\n initiatorMemberId: string | null | undefined,\n initiatorProfilesById: ReadonlyMap<string, MemberProfileRecord>,\n): string {\n const trimmedMemberId = (initiatorMemberId ?? '').trim();\n if (!trimmedMemberId) return '未知發起人';\n return initiatorProfilesById.get(trimmedMemberId)?.name ?? trimmedMemberId;\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '讀取簽核案件失敗。';\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";require('../approval-instance-list-page.css');const e=require("./chunk-CMqjfN_6.cjs"),t=require("./router-adapter--gYs13E8.cjs"),n=require("./format-date-time-XxBzF0F5.cjs"),r=require("./routes-config-fDVHmvXi.cjs");let i=require("react"),a=require("@mezzanine-ui/react"),o=require("@rytass/bpm-core-client"),s=require("react/jsx-runtime"),c=require("@rytass/bpm-core-client/workflow"),l=require("@mezzanine-ui/core/form"),u=require("@mezzanine-ui/react/ContentHeader");u=e.t(u,1);var d={instanceFilterArea:`bpm_instanceFilterArea_qpvJq`},f=[10,20,50],p=[{id:`ALL`,name:`全部狀態`,state:null},{id:`RUNNING`,name:`進行中`,state:`RUNNING`},{id:`APPROVED`,name:`已通過`,state:`APPROVED`},{id:`REJECTED`,name:`已拒絕`,state:`REJECTED`},{id:`RETURNED`,name:`已退回`,state:`RETURNED`},{id:`CANCELLED`,name:`已取消`,state:`CANCELLED`},{id:`EXPIRED`,name:`已逾期`,state:`EXPIRED`},{id:`DRAFT`,name:`草稿`,state:`DRAFT`}];function m({defaultState:e,description:m,emptyMessage:y,searchPlaceholder:b,title:w,view:T}){let E=t.r(),D=r.r(),[O,k]=(0,i.useState)(null),[A,j]=(0,i.useState)(new Map),[M,N]=(0,i.useState)(1),[P,F]=(0,i.useState)(10),[I,L]=(0,i.useState)(0),[R,z]=(0,i.useState)(!0),[B,V]=(0,i.useState)([]),[H,U]=(0,i.useState)(``),[W,G]=(0,i.useState)(_(e)),K=(0,i.useRef)(0),q=(0,i.useCallback)(async()=>{let e=K.current+1;K.current=e,z(!0),k(null);try{let t=await(0,c.listApprovalInstancesPage)({page:M,pageSize:P,searchText:H,state:W.state,templateId:null,view:T});if(e!==K.current)return;V(t.instances.map(h)),L(t.totalCount)}catch(t){e===K.current&&k(C(t))}finally{e===K.current&&z(!1)}},[M,P,H,W,T]);(0,i.useEffect)(()=>{q()},[q]),(0,i.useEffect)(()=>{let e=Array.from(new Set(B.map(e=>e.initiatorMemberId).filter(Boolean)));if(e.length===0){j(new Map);return}let t=!1;return(async()=>{try{let n=await(0,o.resolveMembers)(e);if(t)return;j(new Map(n.map(e=>[e.memberId,e])))}catch{if(t)return;j(new Map)}})(),()=>{t=!0}},[B]);let J=(0,i.useMemo)(()=>[{dataIndex:`caseTitle`,key:`caseTitle`,title:`案件`,width:300},{key:`state`,render:e=>(0,s.jsx)(a.Typography,{color:x(e.state),component:`span`,variant:`body`,children:e.stateLabel}),title:`狀態`,width:120},{key:`initiatorMemberId`,render:e=>(0,s.jsx)(a.Typography,{component:`span`,variant:`body`,children:S(e.initiatorMemberId,A)}),title:`發起人`,width:180},{key:`startedAt`,render:e=>(0,s.jsx)(a.Typography,{component:`span`,variant:`body`,children:n.t(e.startedAt)}),title:`發起時間`,width:220},{key:`completedAt`,render:e=>(0,s.jsx)(a.Typography,{component:`span`,variant:`body`,children:n.t(e.completedAt)}),title:`完成時間`,width:220}],[A]),Y=(0,i.useMemo)(()=>({render:e=>[{name:`查看`,onClick:()=>E.push(D.caseDetail(e.id))}],variant:`base-secondary`,width:88}),[E]);return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.PageHeader,{children:(0,s.jsx)(u.default,{description:m,title:w})}),(0,s.jsx)(a.SectionGroup,{children:(0,s.jsxs)(a.Section,{filterArea:(0,s.jsx)(a.FilterArea,{className:d.instanceFilterArea,size:`sub`,children:(0,s.jsxs)(a.FilterLine,{children:[(0,s.jsx)(a.Filter,{span:3,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:l.FormFieldLayout.VERTICAL,name:`instanceSearchText`,children:(0,s.jsx)(a.Input,{fullWidth:!0,onChange:e=>{U(e.target.value),N(1)},placeholder:b,size:`sub`,value:H,variant:`base`})})}),(0,s.jsx)(a.Filter,{span:2,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:l.FormFieldLayout.VERTICAL,name:`instanceState`,children:(0,s.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>{G(g(e)),N(1)},options:[...p],placeholder:`狀態`,renderValue:e=>`狀態:${v(e)}`,size:`sub`,value:W})})})]})}),children:[O?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:O}):null,!O&&!R&&B.length===0?(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:y}):null,(0,s.jsx)(a.Table,{actions:Y,columns:J,dataSource:[...B],fullWidth:!0,loading:R,pagination:{current:M,onChange:e=>{N(e)},onChangePageSize:e=>{N(1),F(e)},pageSize:P,pageSizeLabel:`每頁筆數`,pageSizeOptions:f,renderResultSummary:(e,t,n)=>`顯示 ${e}-${t} 筆,共 ${n} 筆`,showPageSizeOptions:!0,total:I}})]})})]})}function h(e){return{...e,caseTitle:(0,c.readApprovalInstanceCaseTitle)(e),key:e.id,stateLabel:b(e.state)}}function g(e){return y(e)?_(e.state):p[0]}function _(e){return p.find(t=>t.state===e)??p[0]}function v(e){return y(e)?e.name:p[0].name}function y(e){return typeof e==`object`&&!!e&&`id`in e&&`name`in e&&`state`in e}function b(e){return e===`RUNNING`?`進行中`:e===`APPROVED`?`已通過`:e===`REJECTED`?`已拒絕`:e===`RETURNED`?`已退回`:e===`CANCELLED`?`已取消`:e===`EXPIRED`?`已逾期`:`草稿`}function x(e){return e===`APPROVED`?`text-success`:e===`REJECTED`||e===`CANCELLED`||e===`EXPIRED`?`text-error`:`text-neutral`}function S(e,t){let n=(e??``).trim();return n?t.get(n)?.name??n:`未知發起人`}function C(e){return e instanceof Error?e.message:`讀取簽核案件失敗。`}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return m}});
|
|
2
|
+
//# sourceMappingURL=approval-instance-list-page-C408vxE2.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-instance-list-page-C408vxE2.cjs","names":[],"sources":["../../src/components/approval-instance-list-page.module.scss","../../src/components/approval-instance-list-page.tsx"],"sourcesContent":[".instanceFilterArea {\n :global(.mzn-filter-area__actions) {\n display: none;\n }\n\n :global(.mzn-form-field__label-area) {\n display: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n}\n","'use client';\n\nimport type { ChangeEvent, ReactElement } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n PageHeader,\n Section,\n SectionGroup,\n Select,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport {\n resolveMembers,\n type MemberProfileRecord,\n} from '@rytass/bpm-core-client';\nimport {\n listApprovalInstancesPage,\n readApprovalInstanceCaseTitle,\n type ApprovalInstanceRecord,\n type ApprovalInstanceState,\n type ApprovalInstanceView,\n} from '@rytass/bpm-core-client/workflow';\nimport { useRouterAdapter } from '../lib/router-adapter';\nimport { useBPMRoutes } from '../lib/routes-config';\nimport { formatDateTime } from '../lib/format-date-time';\nimport styles from './approval-instance-list-page.module.scss';\n\nexport interface ApprovalInstanceListPageProps {\n readonly defaultState: ApprovalInstanceState | null;\n readonly description: string;\n readonly emptyMessage: string;\n readonly searchPlaceholder: string;\n readonly title: string;\n readonly view: ApprovalInstanceView;\n}\n\ntype StateFilterOption = Readonly<{\n id: 'ALL' | ApprovalInstanceState;\n name: string;\n state: ApprovalInstanceState | null;\n}>;\n\ntype ApprovalInstanceRow = Readonly<\n Record<string, unknown> &\n ApprovalInstanceRecord & {\n caseTitle: string;\n key: string;\n stateLabel: string;\n }\n>;\n\nconst INSTANCE_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst STATE_FILTER_OPTIONS: readonly StateFilterOption[] = [\n { id: 'ALL', name: '全部狀態', state: null },\n { id: 'RUNNING', name: '進行中', state: 'RUNNING' },\n { id: 'APPROVED', name: '已通過', state: 'APPROVED' },\n { id: 'REJECTED', name: '已拒絕', state: 'REJECTED' },\n { id: 'RETURNED', name: '已退回', state: 'RETURNED' },\n { id: 'CANCELLED', name: '已取消', state: 'CANCELLED' },\n { id: 'EXPIRED', name: '已逾期', state: 'EXPIRED' },\n { id: 'DRAFT', name: '草稿', state: 'DRAFT' },\n];\n\n/**\n * Shared list page for any approval-instance \"view\" (inbox / sent / cc /\n * delegated). Caller picks the view + default state filter; the page renders\n * the standard BPM filter bar + paginated table and navigates to\n * `/instances/:id` on row action.\n */\nexport function ApprovalInstanceListPage({\n defaultState,\n description,\n emptyMessage,\n searchPlaceholder,\n title,\n view,\n}: ApprovalInstanceListPageProps): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const [error, setError] = useState<string | null>(null);\n const [initiatorProfilesById, setInitiatorProfilesById] = useState<\n ReadonlyMap<string, MemberProfileRecord>\n >(new Map());\n const [instancePage, setInstancePage] = useState(1);\n const [instancePageSize, setInstancePageSize] = useState(10);\n const [instanceTotalCount, setInstanceTotalCount] = useState(0);\n const [loading, setLoading] = useState(true);\n const [rows, setRows] = useState<readonly ApprovalInstanceRow[]>([]);\n const [searchText, setSearchText] = useState('');\n const [stateFilter, setStateFilter] = useState<StateFilterOption>(\n readStateFilterOption(defaultState),\n );\n const refreshRequestIdRef = useRef(0);\n\n const refreshInstances = useCallback(async (): Promise<void> => {\n const requestId = refreshRequestIdRef.current + 1;\n refreshRequestIdRef.current = requestId;\n setLoading(true);\n setError(null);\n\n try {\n const result = await listApprovalInstancesPage({\n page: instancePage,\n pageSize: instancePageSize,\n searchText,\n state: stateFilter.state,\n templateId: null,\n view,\n });\n\n if (requestId !== refreshRequestIdRef.current) {\n return;\n }\n\n setRows(result.instances.map(readApprovalInstanceRow));\n setInstanceTotalCount(result.totalCount);\n } catch (requestError: unknown) {\n if (requestId === refreshRequestIdRef.current) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (requestId === refreshRequestIdRef.current) {\n setLoading(false);\n }\n }\n }, [instancePage, instancePageSize, searchText, stateFilter, view]);\n\n useEffect((): void => {\n void refreshInstances();\n }, [refreshInstances]);\n\n useEffect((): (() => void) | void => {\n const initiatorMemberIds = Array.from(\n new Set(rows.map((row) => row.initiatorMemberId).filter(Boolean)),\n );\n\n if (initiatorMemberIds.length === 0) {\n setInitiatorProfilesById(new Map());\n\n return;\n }\n\n let cancelled = false;\n\n void (async (): Promise<void> => {\n try {\n const profiles = await resolveMembers(initiatorMemberIds);\n\n if (cancelled) {\n return;\n }\n\n setInitiatorProfilesById(\n new Map(profiles.map((profile) => [profile.memberId, profile])),\n );\n } catch {\n if (cancelled) {\n return;\n }\n\n setInitiatorProfilesById(new Map());\n }\n })();\n\n return (): void => {\n cancelled = true;\n };\n }, [rows]);\n\n const columns = useMemo(\n (): TableColumn<ApprovalInstanceRow>[] => [\n { dataIndex: 'caseTitle', key: 'caseTitle', title: '案件', width: 300 },\n {\n key: 'state',\n render: (record: ApprovalInstanceRow): ReactElement => (\n <Typography\n color={readInstanceStateColor(record.state)}\n component=\"span\"\n variant=\"body\"\n >\n {record.stateLabel}\n </Typography>\n ),\n title: '狀態',\n width: 120,\n },\n {\n key: 'initiatorMemberId',\n render: (record: ApprovalInstanceRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {readInitiatorLabel(\n record.initiatorMemberId,\n initiatorProfilesById,\n )}\n </Typography>\n ),\n title: '發起人',\n width: 180,\n },\n {\n key: 'startedAt',\n render: (record: ApprovalInstanceRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.startedAt)}\n </Typography>\n ),\n title: '發起時間',\n width: 220,\n },\n {\n key: 'completedAt',\n render: (record: ApprovalInstanceRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.completedAt)}\n </Typography>\n ),\n title: '完成時間',\n width: 220,\n },\n ],\n [initiatorProfilesById],\n );\n const tableActions = useMemo(\n (): TableActions<ApprovalInstanceRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<ApprovalInstanceRow>['render']> => [\n {\n name: '查看',\n onClick: (): void => router.push(routes.caseDetail(record.id)),\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router],\n );\n\n return (\n <>\n <PageHeader>\n <ContentHeader description={description} title={title} />\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.instanceFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"instanceSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setInstancePage(1);\n }}\n placeholder={searchPlaceholder}\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"instanceState\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void => {\n setStateFilter(readSelectedStateFilterOption(option));\n setInstancePage(1);\n }}\n options={[...STATE_FILTER_OPTIONS]}\n placeholder=\"狀態\"\n renderValue={(value): string =>\n `狀態:${readStateFilterLabel(value)}`\n }\n size=\"sub\"\n value={stateFilter}\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {!error && !loading && rows.length === 0 ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n {emptyMessage}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={[...rows]}\n fullWidth\n loading={loading}\n pagination={{\n current: instancePage,\n onChange: (page): void => {\n setInstancePage(page);\n },\n onChangePageSize: (pageSize): void => {\n setInstancePage(1);\n setInstancePageSize(pageSize);\n },\n pageSize: instancePageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: INSTANCE_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: instanceTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction readApprovalInstanceRow(\n instance: ApprovalInstanceRecord,\n): ApprovalInstanceRow {\n return {\n ...instance,\n caseTitle: readApprovalInstanceCaseTitle(instance),\n key: instance.id,\n stateLabel: readInstanceStateLabel(instance.state),\n };\n}\n\nfunction readSelectedStateFilterOption(option: unknown): StateFilterOption {\n if (!isStateFilterOption(option)) {\n return STATE_FILTER_OPTIONS[0];\n }\n return readStateFilterOption(option.state);\n}\n\nfunction readStateFilterOption(\n state: ApprovalInstanceState | null,\n): StateFilterOption {\n return (\n STATE_FILTER_OPTIONS.find((option) => option.state === state) ??\n STATE_FILTER_OPTIONS[0]\n );\n}\n\nfunction readStateFilterLabel(value: unknown): string {\n return isStateFilterOption(value) ? value.name : STATE_FILTER_OPTIONS[0].name;\n}\n\nfunction isStateFilterOption(value: unknown): value is StateFilterOption {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'id' in value &&\n 'name' in value &&\n 'state' in value\n );\n}\n\nfunction readInstanceStateLabel(state: ApprovalInstanceState): string {\n if (state === 'RUNNING') return '進行中';\n if (state === 'APPROVED') return '已通過';\n if (state === 'REJECTED') return '已拒絕';\n if (state === 'RETURNED') return '已退回';\n if (state === 'CANCELLED') return '已取消';\n if (state === 'EXPIRED') return '已逾期';\n return '草稿';\n}\n\nfunction readInstanceStateColor(\n state: ApprovalInstanceState,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (state === 'APPROVED') return 'text-success';\n if (state === 'REJECTED' || state === 'CANCELLED' || state === 'EXPIRED') {\n return 'text-error';\n }\n return 'text-neutral';\n}\n\nfunction readInitiatorLabel(\n initiatorMemberId: string | null | undefined,\n initiatorProfilesById: ReadonlyMap<string, MemberProfileRecord>,\n): string {\n const trimmedMemberId = (initiatorMemberId ?? '').trim();\n if (!trimmedMemberId) return '未知發起人';\n return initiatorProfilesById.get(trimmedMemberId)?.name ?? trimmedMemberId;\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '讀取簽核案件失敗。';\n}\n"],"mappings":"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"}
|
|
@@ -4,8 +4,8 @@ import { t } from "./bpm-form-field-Cao0rMol.js";
|
|
|
4
4
|
import { useCallback as n, useEffect as r, useMemo as i, useState as a } from "react";
|
|
5
5
|
import { Badge as o, Button as s, Filter as c, FilterArea as l, FilterLine as u, FormField as d, Input as f, Modal as p, PageHeader as m, Section as h, SectionGroup as g, Tab as _, TabItem as v, Table as y, Textarea as b, Typography as x } from "@mezzanine-ui/react";
|
|
6
6
|
import { Fragment as S, jsx as C, jsxs as w } from "react/jsx-runtime";
|
|
7
|
-
import ee from "@mezzanine-ui/
|
|
8
|
-
import
|
|
7
|
+
import { FormFieldLayout as ee } from "@mezzanine-ui/core/form";
|
|
8
|
+
import te from "@mezzanine-ui/react/ContentHeader";
|
|
9
9
|
import { PlusIcon as T } from "@mezzanine-ui/icons";
|
|
10
10
|
import { createApprovalTemplateCategory as E, deleteApprovalTemplateCategory as D, listApprovalTemplateCategoriesPage as O, updateApprovalTemplateCategory as k } from "@rytass/bpm-core-client/template";
|
|
11
11
|
import '../categories.css';var A = {
|
|
@@ -162,7 +162,7 @@ function N() {
|
|
|
162
162
|
width: 192
|
|
163
163
|
}), [Q]);
|
|
164
164
|
return /* @__PURE__ */ w(S, { children: [
|
|
165
|
-
/* @__PURE__ */ w(S, { children: [/* @__PURE__ */ C(m, { children: /* @__PURE__ */ C(
|
|
165
|
+
/* @__PURE__ */ w(S, { children: [/* @__PURE__ */ C(m, { children: /* @__PURE__ */ C(te, {
|
|
166
166
|
description: "維護簽核模板分類,供模板建立、篩選與列表標示使用。",
|
|
167
167
|
title: "簽核模板分類",
|
|
168
168
|
children: /* @__PURE__ */ C(s, {
|
|
@@ -183,7 +183,7 @@ function N() {
|
|
|
183
183
|
span: 3,
|
|
184
184
|
children: /* @__PURE__ */ C(d, {
|
|
185
185
|
fullWidth: !0,
|
|
186
|
-
layout:
|
|
186
|
+
layout: ee.VERTICAL,
|
|
187
187
|
name: "categorySearchText",
|
|
188
188
|
children: /* @__PURE__ */ C(f, {
|
|
189
189
|
fullWidth: !0,
|
|
@@ -379,4 +379,4 @@ function P(e) {
|
|
|
379
379
|
//#endregion
|
|
380
380
|
export { A as n, N as t };
|
|
381
381
|
|
|
382
|
-
//# sourceMappingURL=categories-
|
|
382
|
+
//# sourceMappingURL=categories-DGlxuC6X.js.map
|