@rytass/bpm-core-react 0.20.1 → 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 +34 -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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-instance-list-page-Bth7Raya.js","names":["_Fragment","styles","useRouterAdapter","useBPMRoutes","formatDateTime","Fragment$1","ContentHeader","readFieldFilterControl","item","EMPTY_FIELD_FILTER_DRAFT","DECIMAL_PATTERN","isDecimalText","readDecimal","value","plain","readIdList","text","toApprovalInstanceFieldFilter","draft","ids","from","to","buildApprovalInstanceFieldFilters","paths","filter","drafts","DEFAULT_SORT_DRAFT","DEFAULT_SORT_OPTION","SORT_TIME_LABELS","readSortFieldOptions","timeOptions","APPROVAL_INSTANCE_SORT_TIME_FIELDS","field","fieldOptions","templateSelected","isFilterableFieldSortable","isSortFieldAvailable","toApprovalInstanceSort","BOOLEAN_CHOICES","readFieldFilterElements","change","next","control","renderFilter","Input","event","readNumberHint","renderControl","readIdNoun","Filter","FormField","ControlFieldSlotLayout","FormFieldLayout","key","choices","option","Select","selected","label","choice","DateRangePicker","formatDatePickerValue","target","DateTimeRangePicker","formatDateTimePickerValue","approval_instance_list_page_module_default","INSTANCE_PAGE_SIZE_OPTIONS","FIELD_FILTERS_PER_LINE","STATE_FILTER_OPTIONS","SORT_DIRECTION_OPTIONS","ApprovalInstanceListPage","router","routes","error","setError","useState","initiatorProfilesById","setInitiatorProfilesById","instancePage","setInstancePage","instancePageSize","setInstancePageSize","instanceTotalCount","setInstanceTotalCount","loading","setLoading","rows","setRows","searchText","setSearchText","stateFilter","setStateFilter","readStateFilterOption","defaultState","templates","setTemplates","templateId","setTemplateId","templateSchema","setTemplateSchema","schemaLoading","setSchemaLoading","schemaError","setSchemaError","fieldDrafts","setFieldDrafts","sortDraft","setSortDraft","refreshRequestIdRef","useRef","fieldPaths","useMemo","readFilterableFieldPaths","fieldFilters","sort","sortOptions","refreshInstances","useCallback","requestId","result","listApprovalInstancesPage","readApprovalInstanceRow","requestError","readErrorMessage","view","useEffect","cancelled","loaded","listApprovalTemplates","schema","readApprovalTemplateCurrentFormSchema","schemaLoadError","initiatorMemberIds","row","profiles","resolveMembers","profile","handleTemplateChange","previous","handleFilterReset","handleFilterSubmit","handleFieldDraftChange","path","columns","Typography","readInstanceStateColor","record","readInitiatorLabel","tableActions","templateOptions","template","selectedTemplate","fieldFilterLines","chunkElements","FilterLine","elements","index","sortFieldChoices","selectedSortField","searchFilterLine","searchPlaceholder","readSelectedStateFilterOption","readStateFilterLabel","sortFilterLine","RadioGroup","readSortDirection","PageHeader","SectionGroup","Section","FilterArea","emptyMessage","Table","page","pageSize","total","items","last","lines","size","instance","readApprovalInstanceCaseTitle","readInstanceStateLabel","isStateFilterOption","state","trimmedMemberId","initiatorMemberId"],"sources":["../../src/components/approval-instance-field-filters.ts","../../src/components/approval-instance-field-filter-controls.tsx","../../src/components/approval-instance-list-page.module.scss","../../src/components/approval-instance-list-page.tsx"],"sourcesContent":["import {\n APPROVAL_INSTANCE_SORT_TIME_FIELDS,\n isFilterableFieldSortable,\n type ApprovalInstanceFieldFilter,\n type ApprovalInstanceSort,\n type ApprovalInstanceSortDirection,\n type FilterableFieldPath,\n type FormFieldOption,\n} from '@rytass/bpm-core-shared';\n\n/**\n * Pure logic behind the list page's field filters (ADR 25 §7). Turns the\n * filterable fields of a template's schema into controls, and the control\n * values into `fieldFilters` and `sort` for `listApprovalInstancesPage`. The\n * operator for each control is one `readFilterOperatorsForFieldType` allows.\n */\n\n/** Which control a filterable field gets on the list page. */\nexport type FieldFilterControl =\n /** Text, textarea and dynamic (data-source) options: CONTAINS on a text input. */\n | { readonly kind: 'contains' }\n /** Static options: IN on a multi-select. */\n | { readonly kind: 'option-in'; readonly options: readonly FormFieldOption[] }\n /** Member and org unit: IN on comma-separated ids (no picker yet). */\n | { readonly kind: 'id-in' }\n /** Number and money: RANGE with two number inputs. */\n | { readonly kind: 'number-range' }\n /** Date: RANGE with a date range picker. */\n | { readonly kind: 'date-range' }\n /** Datetime: RANGE with a datetime range picker. */\n | { readonly kind: 'datetime-range' }\n /** Boolean: EQUALS with a yes / no select. */\n | { readonly kind: 'boolean' };\n\nexport function readFieldFilterControl(\n item: FilterableFieldPath,\n): FieldFilterControl {\n switch (item.kind) {\n case 'number':\n return { kind: 'number-range' };\n case 'date':\n return { kind: 'date-range' };\n case 'datetime':\n return { kind: 'datetime-range' };\n case 'boolean':\n return { kind: 'boolean' };\n case 'member':\n case 'org_unit':\n return { kind: 'id-in' };\n case 'option':\n return item.staticOptions\n ? { kind: 'option-in', options: item.staticOptions }\n : { kind: 'contains' };\n case 'text':\n return { kind: 'contains' };\n }\n}\n\n/**\n * One field's entered condition. `from` and `to` hold canonical values\n * (decimal string, `YYYY-MM-DD`, or ISO 8601) as the controls produce them.\n */\nexport interface FieldFilterDraft {\n readonly from: string;\n readonly to: string;\n /** CONTAINS text, or comma-separated ids for IN on member and org unit. */\n readonly text: string;\n /** Selected option values (IN), or `['true']` / `['false']` for boolean. */\n readonly values: readonly string[];\n}\n\nexport const EMPTY_FIELD_FILTER_DRAFT: FieldFilterDraft = {\n from: '',\n text: '',\n to: '',\n values: [],\n};\n\n/** Drafts keyed by the field path, so a path can be looked up directly. */\nexport type FieldFilterDrafts = Readonly<Record<string, FieldFilterDraft>>;\n\nconst DECIMAL_PATTERN = /^-?\\d+(\\.\\d+)?$/u;\n\n/**\n * Whether a number control's text is a decimal. Surrounding spaces and\n * thousands separators (`1,000`) are accepted and dropped before sending.\n */\nexport function isDecimalText(value: string): boolean {\n return readDecimal(value) !== null;\n}\n\nfunction readDecimal(value: string): string | null {\n const plain = value.trim().replace(/,/gu, '');\n\n return DECIMAL_PATTERN.test(plain) ? plain : null;\n}\n\nfunction readIdList(text: string): readonly string[] {\n return text\n .split(',')\n .map((item) => item.trim())\n .filter((item) => item.length > 0);\n}\n\n/**\n * The condition one draft asks for, or `null` when it is empty. Empty means\n * no condition, so it must not reach the server as a filter.\n */\nexport function toApprovalInstanceFieldFilter(\n item: FilterableFieldPath,\n draft: FieldFilterDraft,\n): ApprovalInstanceFieldFilter | null {\n const control = readFieldFilterControl(item);\n\n switch (control.kind) {\n case 'contains': {\n const text = draft.text.trim();\n\n return text\n ? { fieldKey: item.path, operator: 'CONTAINS', values: [text] }\n : null;\n }\n case 'option-in':\n return draft.values.length > 0\n ? { fieldKey: item.path, operator: 'IN', values: [...draft.values] }\n : null;\n case 'id-in': {\n const ids = readIdList(draft.text);\n\n return ids.length > 0\n ? { fieldKey: item.path, operator: 'IN', values: ids }\n : null;\n }\n case 'number-range': {\n const from = readDecimal(draft.from);\n const to = readDecimal(draft.to);\n\n return from || to\n ? {\n fieldKey: item.path,\n operator: 'RANGE',\n ...(from ? { from } : {}),\n ...(to ? { to } : {}),\n }\n : null;\n }\n case 'date-range':\n case 'datetime-range': {\n const from = draft.from.trim();\n const to = draft.to.trim();\n\n return from || to\n ? {\n fieldKey: item.path,\n operator: 'RANGE',\n ...(from ? { from } : {}),\n ...(to ? { to } : {}),\n }\n : null;\n }\n case 'boolean': {\n const value = draft.values[0];\n\n return value === 'true' || value === 'false'\n ? { fieldKey: item.path, operator: 'EQUALS', values: [value] }\n : null;\n }\n }\n}\n\n/** Every non-empty condition, in schema order. */\nexport function buildApprovalInstanceFieldFilters(\n paths: readonly FilterableFieldPath[],\n drafts: FieldFilterDrafts,\n): readonly ApprovalInstanceFieldFilter[] {\n return paths.flatMap((item): readonly ApprovalInstanceFieldFilter[] => {\n const filter = toApprovalInstanceFieldFilter(\n item,\n drafts[item.path] ?? EMPTY_FIELD_FILTER_DRAFT,\n );\n\n return filter ? [filter] : [];\n });\n}\n\n/** The sort the user picked. An empty `field` keeps the server default. */\nexport interface SortDraft {\n readonly direction: ApprovalInstanceSortDirection;\n readonly field: string;\n}\n\nexport const DEFAULT_SORT_DRAFT: SortDraft = { direction: 'DESC', field: '' };\n\nexport interface SortFieldOption {\n readonly id: string;\n readonly label: string;\n}\n\nexport const DEFAULT_SORT_OPTION: SortFieldOption = {\n id: '',\n label: '預設(建立時間,新到舊)',\n};\n\nconst SORT_TIME_LABELS: Readonly<\n Record<(typeof APPROVAL_INSTANCE_SORT_TIME_FIELDS)[number], string>\n> = {\n completedAt: '完成時間',\n submittedAt: '送出時間',\n updatedAt: '最後更新',\n};\n\n/**\n * Sort choices. Time fields are always offered. Form fields are offered only\n * with a template selected, because the server needs a template to sort by a\n * form field.\n */\nexport function readSortFieldOptions(\n paths: readonly FilterableFieldPath[],\n templateSelected: boolean,\n): readonly SortFieldOption[] {\n const timeOptions = APPROVAL_INSTANCE_SORT_TIME_FIELDS.map(\n (field): SortFieldOption => ({ id: field, label: SORT_TIME_LABELS[field] }),\n );\n const fieldOptions = templateSelected\n ? paths\n .filter(isFilterableFieldSortable)\n .map((item): SortFieldOption => ({ id: item.path, label: item.label }))\n : [];\n\n return [DEFAULT_SORT_OPTION, ...timeOptions, ...fieldOptions];\n}\n\n/** Whether a sort on `field` is valid for the current template selection. */\nexport function isSortFieldAvailable(\n field: string,\n paths: readonly FilterableFieldPath[],\n templateSelected: boolean,\n): boolean {\n if (field === '') {\n return true;\n }\n\n if (\n (APPROVAL_INSTANCE_SORT_TIME_FIELDS as readonly string[]).includes(field)\n ) {\n return true;\n }\n\n return templateSelected && paths.some((item) => item.path === field);\n}\n\nexport function toApprovalInstanceSort(\n draft: SortDraft,\n): readonly ApprovalInstanceSort[] | undefined {\n return draft.field === ''\n ? undefined\n : [{ direction: draft.direction, field: draft.field }];\n}\n","'use client';\n\nimport type { ReactElement } from 'react';\nimport {\n DateRangePicker,\n DateTimeRangePicker,\n Filter,\n FormField,\n Input,\n Select,\n type FilterProps,\n} from '@mezzanine-ui/react';\nimport {\n ControlFieldSlotLayout,\n FormFieldLayout,\n} from '@mezzanine-ui/core/form';\nimport {\n formatDatePickerValue,\n formatDateTimePickerValue,\n} from '@rytass/bpm-core-client/form';\nimport type { FilterableFieldPath } from '@rytass/bpm-core-shared';\nimport {\n EMPTY_FIELD_FILTER_DRAFT,\n isDecimalText,\n readFieldFilterControl,\n type FieldFilterDraft,\n type FieldFilterDrafts,\n} from './approval-instance-field-filters';\n\nexport type FieldFilterDraftChange = (\n path: string,\n draft: FieldFilterDraft,\n) => void;\n\ntype SelectChoice = Readonly<{ id: string; name: string }>;\n\nconst BOOLEAN_CHOICES: readonly SelectChoice[] = [\n { id: 'true', name: '是' },\n { id: 'false', name: '否' },\n];\n\n/**\n * One list-page `Filter` per condition the template's filterable fields need.\n * A number field yields two (lower and upper bound) because Mezzanine has no\n * number range control. Returned as elements so the caller can place them\n * directly inside `FilterLine`, which only accepts `Filter` children.\n */\nexport function readFieldFilterElements(\n paths: readonly FilterableFieldPath[],\n drafts: FieldFilterDrafts,\n onDraftChange: FieldFilterDraftChange,\n): readonly ReactElement<FilterProps>[] {\n return paths.flatMap((item): readonly ReactElement<FilterProps>[] => {\n const draft = drafts[item.path] ?? EMPTY_FIELD_FILTER_DRAFT;\n const change = (next: FieldFilterDraft): void => {\n onDraftChange(item.path, next);\n };\n const control = readFieldFilterControl(item);\n\n if (control.kind === 'number-range') {\n return [\n renderFilter(\n `${item.path}:from`,\n `${item.label}(下限)`,\n <Input\n fullWidth\n onChange={(event): void => {\n change({ ...draft, from: event.target.value });\n }}\n placeholder={`${item.label}:下限`}\n size=\"sub\"\n value={draft.from}\n variant=\"base\"\n />,\n readNumberHint(draft.from),\n ),\n renderFilter(\n `${item.path}:to`,\n `${item.label}(上限)`,\n <Input\n fullWidth\n onChange={(event): void => {\n change({ ...draft, to: event.target.value });\n }}\n placeholder={`${item.label}:上限`}\n size=\"sub\"\n value={draft.to}\n variant=\"base\"\n />,\n readNumberHint(draft.to),\n ),\n ];\n }\n\n return [\n renderFilter(\n item.path,\n item.label,\n renderControl(item, draft, change, item.label),\n control.kind === 'id-in'\n ? `多個${readIdNoun(item)}以逗號分隔`\n : undefined,\n ),\n ];\n });\n}\n\nfunction renderFilter(\n key: string,\n label: string,\n control: ReactElement,\n hintText?: string,\n): ReactElement<FilterProps> {\n return (\n <Filter key={key} span={2}>\n <FormField\n fullWidth\n hintText={hintText}\n controlFieldSlotLayout={ControlFieldSlotLayout.SUB}\n layout={FormFieldLayout.VERTICAL}\n label={label}\n name={`fieldFilter-${key}`}\n >\n {control}\n </FormField>\n </Filter>\n );\n}\n\n/** What an id-in field holds: members, or org units for an `org_unit` field. */\nfunction readIdNoun(item: FilterableFieldPath): string {\n return item.kind === 'org_unit' ? '組織' : '成員';\n}\n\nfunction readNumberHint(value: string): string | undefined {\n return !value || isDecimalText(value) ? undefined : '請輸入數字';\n}\n\nfunction renderControl(\n item: FilterableFieldPath,\n draft: FieldFilterDraft,\n change: (next: FieldFilterDraft) => void,\n label: string,\n): ReactElement {\n // The list page hides FormField labels to keep its filter rows compact, so\n // each control names its field in the placeholder, as the state filter does.\n const control = readFieldFilterControl(item);\n\n if (control.kind === 'option-in') {\n const choices = control.options.map((option): SelectChoice => ({\n id: option.value,\n name: option.label,\n }));\n\n return (\n <Select\n clearable\n fullWidth\n mode=\"multiple\"\n onChange={(selected: readonly SelectChoice[]): void => {\n change({ ...draft, values: selected.map((option) => option.id) });\n }}\n options={[...choices]}\n placeholder={`${label}:全部`}\n size=\"sub\"\n value={choices.filter((choice) => draft.values.includes(choice.id))}\n />\n );\n }\n\n if (control.kind === 'boolean') {\n const selected = BOOLEAN_CHOICES.find((choice) =>\n draft.values.includes(choice.id),\n );\n\n return (\n <Select\n clearable\n fullWidth\n onChange={(option: SelectChoice | null): void => {\n change({ ...draft, values: option ? [option.id] : [] });\n }}\n options={[...BOOLEAN_CHOICES]}\n placeholder={`${label}:全部`}\n size=\"sub\"\n value={selected ?? null}\n />\n );\n }\n\n if (control.kind === 'date-range') {\n return (\n <DateRangePicker\n clearable\n fullWidth\n inputFromPlaceholder={`${label}:起`}\n inputToPlaceholder=\"迄\"\n onChange={(target?: readonly (string | undefined)[]): void => {\n change({\n ...draft,\n from: formatDatePickerValue(target?.[0]) ?? '',\n to: formatDatePickerValue(target?.[1]) ?? '',\n });\n }}\n size=\"sub\"\n value={draft.from && draft.to ? [draft.from, draft.to] : []}\n />\n );\n }\n\n if (control.kind === 'datetime-range') {\n return (\n <DateTimeRangePicker\n clearable\n fullWidth\n onChange={(value): void => {\n change({\n ...draft,\n from: formatDateTimePickerValue(value[0]) ?? '',\n to: formatDateTimePickerValue(value[1]) ?? '',\n });\n }}\n size=\"sub\"\n value={[draft.from || undefined, draft.to || undefined]}\n />\n );\n }\n\n if (control.kind === 'id-in') {\n return (\n <Input\n fullWidth\n onChange={(event): void => {\n change({ ...draft, text: event.target.value });\n }}\n placeholder={`${label}:${readIdNoun(item)} ID`}\n size=\"sub\"\n value={draft.text}\n variant=\"base\"\n />\n );\n }\n\n // contains (text, textarea and data-source options)\n return (\n <Input\n fullWidth\n onChange={(event): void => {\n change({ ...draft, text: event.target.value });\n }}\n placeholder={`${label}:包含`}\n size=\"sub\"\n value={draft.text}\n variant=\"base\"\n />\n );\n}\n",".instanceFilterArea {\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 RadioGroup,\n Section,\n SectionGroup,\n Select,\n Table,\n Typography,\n type FilterLineProps,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport {\n ControlFieldSlotLayout,\n FormFieldLayout,\n} 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 listApprovalTemplates,\n type ApprovalTemplateRecord,\n} from '@rytass/bpm-core-client/template';\nimport {\n listApprovalInstancesPage,\n readApprovalInstanceCaseTitle,\n readApprovalTemplateCurrentFormSchema,\n type ApprovalInstanceRecord,\n type ApprovalInstanceState,\n type ApprovalInstanceView,\n} from '@rytass/bpm-core-client/workflow';\nimport {\n readFilterableFieldPaths,\n type ApprovalInstanceFieldFilter,\n type ApprovalInstanceSort,\n type ApprovalInstanceSortDirection,\n type FilterableFieldPath,\n type FormDefinitionSchema,\n} from '@rytass/bpm-core-shared';\nimport { useRouterAdapter } from '../lib/router-adapter';\nimport { useBPMRoutes } from '../lib/routes-config';\nimport { formatDateTime } from '../lib/format-date-time';\nimport {\n buildApprovalInstanceFieldFilters,\n DEFAULT_SORT_DRAFT,\n DEFAULT_SORT_OPTION,\n isSortFieldAvailable,\n readSortFieldOptions,\n toApprovalInstanceSort,\n type FieldFilterDraft,\n type FieldFilterDrafts,\n type SortDraft,\n type SortFieldOption,\n} from './approval-instance-field-filters';\nimport { readFieldFilterElements } from './approval-instance-field-filter-controls';\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\ntype SelectChoice = Readonly<{ id: string; name: string }>;\n\nconst INSTANCE_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst FIELD_FILTERS_PER_LINE = 3;\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];\nconst SORT_DIRECTION_OPTIONS: readonly (SelectChoice & {\n id: ApprovalInstanceSortDirection;\n})[] = [\n { id: 'DESC', name: '新到舊' },\n { id: 'ASC', name: '舊到新' },\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 *\n * With a template selected, the filter bar also carries one control per\n * filterable field of that template's current form (ADR 25 §7), and the sort\n * may use those fields. Without a template only time fields can sort.\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 [templates, setTemplates] = useState<readonly ApprovalTemplateRecord[]>(\n [],\n );\n const [templateId, setTemplateId] = useState<string | null>(null);\n const [templateSchema, setTemplateSchema] =\n useState<FormDefinitionSchema | null>(null);\n const [schemaLoading, setSchemaLoading] = useState(false);\n const [schemaError, setSchemaError] = useState<string | null>(null);\n const [fieldDrafts, setFieldDrafts] = useState<FieldFilterDrafts>({});\n const [sortDraft, setSortDraft] = useState<SortDraft>(DEFAULT_SORT_DRAFT);\n const refreshRequestIdRef = useRef(0);\n\n const fieldPaths = useMemo(\n (): readonly FilterableFieldPath[] =>\n templateSchema ? readFilterableFieldPaths(templateSchema) : [],\n [templateSchema],\n );\n const fieldFilters = useMemo(\n (): readonly ApprovalInstanceFieldFilter[] | undefined =>\n templateId === null\n ? undefined\n : buildApprovalInstanceFieldFilters(fieldPaths, fieldDrafts),\n [fieldDrafts, fieldPaths, templateId],\n );\n const sort = useMemo(\n (): readonly ApprovalInstanceSort[] | undefined =>\n toApprovalInstanceSort(sortDraft),\n [sortDraft],\n );\n const sortOptions = useMemo(\n (): readonly SortFieldOption[] =>\n readSortFieldOptions(fieldPaths, templateId !== null),\n [fieldPaths, templateId],\n );\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 fieldFilters,\n page: instancePage,\n pageSize: instancePageSize,\n searchText,\n sort,\n state: stateFilter.state,\n templateId,\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 }, [\n fieldFilters,\n instancePage,\n instancePageSize,\n searchText,\n sort,\n stateFilter,\n templateId,\n view,\n ]);\n\n useEffect((): void => {\n void refreshInstances();\n }, [refreshInstances]);\n\n useEffect((): (() => void) | void => {\n let cancelled = false;\n\n void (async (): Promise<void> => {\n try {\n const loaded = await listApprovalTemplates();\n\n if (!cancelled) {\n setTemplates(loaded);\n }\n } catch {\n if (!cancelled) {\n setTemplates([]);\n }\n }\n })();\n\n return (): void => {\n cancelled = true;\n };\n }, []);\n\n // Race guard: a schema response for a previously picked template is dropped\n // when the template changes again (cleanup flips `cancelled`).\n useEffect((): (() => void) | void => {\n if (templateId === null) {\n setTemplateSchema(null);\n setSchemaLoading(false);\n setSchemaError(null);\n\n return;\n }\n\n let cancelled = false;\n setSchemaLoading(true);\n setSchemaError(null);\n\n void (async (): Promise<void> => {\n try {\n const schema = await readApprovalTemplateCurrentFormSchema(templateId);\n\n if (!cancelled) {\n setTemplateSchema(schema);\n }\n } catch (schemaLoadError: unknown) {\n if (!cancelled) {\n setTemplateSchema(null);\n setSchemaError(readErrorMessage(schemaLoadError));\n }\n } finally {\n if (!cancelled) {\n setSchemaLoading(false);\n }\n }\n })();\n\n return (): void => {\n cancelled = true;\n };\n }, [templateId]);\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 handleTemplateChange = useCallback(\n (option: SelectChoice | null): void => {\n setTemplateId(option?.id ?? null);\n // Drop the previous template's fields at once, so nothing is built from\n // them while the new schema loads.\n setTemplateSchema(null);\n setFieldDrafts({});\n setInstancePage(1);\n // A form-field sort belongs to one template. Time-field sorts survive.\n setSortDraft((previous): SortDraft =>\n isSortFieldAvailable(previous.field, [], false)\n ? previous\n : { ...previous, field: DEFAULT_SORT_DRAFT.field },\n );\n },\n [],\n );\n\n const handleFilterReset = useCallback((): void => {\n setSearchText('');\n setStateFilter(readStateFilterOption(defaultState));\n setTemplateId(null);\n setTemplateSchema(null);\n setFieldDrafts({});\n setSortDraft(DEFAULT_SORT_DRAFT);\n setInstancePage(1);\n }, [defaultState]);\n const handleFilterSubmit = useCallback((): void => {\n void refreshInstances();\n }, [refreshInstances]);\n const handleFieldDraftChange = useCallback(\n (path: string, draft: FieldFilterDraft): void => {\n setFieldDrafts((previous): FieldFilterDrafts => ({\n ...previous,\n [path]: draft,\n }));\n setInstancePage(1);\n },\n [],\n );\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 const templateOptions = useMemo(\n (): readonly SelectChoice[] =>\n templates.map((template) => ({ id: template.id, name: template.name })),\n [templates],\n );\n const selectedTemplate = templateOptions.find(\n (option) => option.id === templateId,\n );\n const fieldFilterLines = useMemo(\n (): readonly ReactElement<FilterLineProps>[] =>\n chunkElements(\n readFieldFilterElements(\n fieldPaths,\n fieldDrafts,\n handleFieldDraftChange,\n ),\n FIELD_FILTERS_PER_LINE,\n ).map((elements, index): ReactElement<FilterLineProps> => (\n <FilterLine key={`field-filter-line-${index}`}>\n {[...elements]}\n </FilterLine>\n )),\n [fieldDrafts, fieldPaths, handleFieldDraftChange],\n );\n const sortFieldChoices = useMemo(\n (): readonly SelectChoice[] =>\n sortOptions.map((option) => ({ id: option.id, name: option.label })),\n [sortOptions],\n );\n const selectedSortField =\n sortFieldChoices.find((option) => option.id === sortDraft.field) ??\n sortFieldChoices.find((option) => option.id === DEFAULT_SORT_OPTION.id);\n\n const searchFilterLine = (\n <FilterLine key=\"search\">\n <Filter span={2}>\n <FormField\n fullWidth\n controlFieldSlotLayout={ControlFieldSlotLayout.SUB}\n layout={FormFieldLayout.VERTICAL}\n name=\"instanceSearchText\"\n >\n <Input\n fullWidth\n onChange={(event: ChangeEvent<HTMLInputElement>): 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 controlFieldSlotLayout={ControlFieldSlotLayout.SUB}\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 <Filter span={2}>\n <FormField\n fullWidth\n controlFieldSlotLayout={ControlFieldSlotLayout.SUB}\n layout={FormFieldLayout.VERTICAL}\n label=\"範本\"\n name=\"instanceTemplate\"\n >\n <Select\n clearable\n fullWidth\n onChange={handleTemplateChange}\n options={[...templateOptions]}\n placeholder=\"全部範本\"\n size=\"sub\"\n value={selectedTemplate ?? null}\n />\n </FormField>\n </Filter>\n </FilterLine>\n );\n\n const sortFilterLine = (\n <FilterLine key=\"sort\">\n <Filter span={2}>\n <FormField\n fullWidth\n controlFieldSlotLayout={ControlFieldSlotLayout.SUB}\n layout={FormFieldLayout.VERTICAL}\n label=\"排序欄位\"\n name=\"instanceSortField\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option: SelectChoice | null): void => {\n setSortDraft((previous): SortDraft => ({\n ...previous,\n field: option?.id ?? DEFAULT_SORT_DRAFT.field,\n }));\n setInstancePage(1);\n }}\n options={[...sortFieldChoices]}\n placeholder=\"排序欄位\"\n size=\"sub\"\n value={selectedSortField ?? null}\n />\n </FormField>\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n controlFieldSlotLayout={ControlFieldSlotLayout.SUB}\n layout={FormFieldLayout.VERTICAL}\n label=\"排序方向\"\n name=\"instanceSortDirection\"\n >\n <RadioGroup\n name=\"instanceSortDirection\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setSortDraft((previous): SortDraft => ({\n ...previous,\n direction: readSortDirection(event.target.value),\n }));\n setInstancePage(1);\n }}\n options={[...SORT_DIRECTION_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={sortDraft.direction}\n />\n </FormField>\n </Filter>\n </FilterLine>\n );\n\n return (\n <>\n <PageHeader>\n <ContentHeader description={description} title={title} />\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea\n className={styles.instanceFilterArea}\n onReset={handleFilterReset}\n onSubmit={handleFilterSubmit}\n resetText=\"清除條件\"\n rowAlign=\"end\"\n size=\"sub\"\n submitText=\"重新查詢\"\n >\n {[searchFilterLine, ...fieldFilterLines, sortFilterLine]}\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {schemaError ? (\n <Typography color=\"text-error\" variant=\"body\">\n {schemaError}\n </Typography>\n ) : null}\n {templateId !== null &&\n !schemaLoading &&\n !schemaError &&\n templateSchema &&\n fieldPaths.length === 0 ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 此範本沒有可篩選的欄位。\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 chunkElements<T>(\n items: readonly T[],\n size: number,\n): readonly (readonly T[])[] {\n return items.reduce<readonly (readonly T[])[]>(\n (lines, item): readonly (readonly T[])[] => {\n const last = lines[lines.length - 1];\n\n return last && last.length < size\n ? [...lines.slice(0, -1), [...last, item]]\n : [...lines, [item]];\n },\n [],\n );\n}\n\nfunction readSortDirection(value: string): ApprovalInstanceSortDirection {\n return value === 'ASC' ? 'ASC' : 'DESC';\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("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./router-adapter--gYs13E8.cjs"),n=require("./routes-config-C1j_vFKo.cjs"),r=require("./format-date-time-D-cx5M8z.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);let ee=require("@rytass/bpm-core-client/template"),d=require("@rytass/bpm-core-shared"),f=require("@rytass/bpm-core-client/form");function p(e){switch(e.kind){case`number`:return{kind:`number-range`};case`date`:return{kind:`date-range`};case`datetime`:return{kind:`datetime-range`};case`boolean`:return{kind:`boolean`};case`member`:case`org_unit`:return{kind:`id-in`};case`option`:return e.staticOptions?{kind:`option-in`,options:e.staticOptions}:{kind:`contains`};case`text`:return{kind:`contains`}}}var m={from:``,text:``,to:``,values:[]},h=/^-?\d+(\.\d+)?$/u;function g(e){return _(e)!==null}function _(e){let t=e.trim().replace(/,/gu,``);return h.test(t)?t:null}function te(e){return e.split(`,`).map(e=>e.trim()).filter(e=>e.length>0)}function v(e,t){switch(p(e).kind){case`contains`:{let n=t.text.trim();return n?{fieldKey:e.path,operator:`CONTAINS`,values:[n]}:null}case`option-in`:return t.values.length>0?{fieldKey:e.path,operator:`IN`,values:[...t.values]}:null;case`id-in`:{let n=te(t.text);return n.length>0?{fieldKey:e.path,operator:`IN`,values:n}:null}case`number-range`:{let n=_(t.from),r=_(t.to);return n||r?{fieldKey:e.path,operator:`RANGE`,...n?{from:n}:{},...r?{to:r}:{}}:null}case`date-range`:case`datetime-range`:{let n=t.from.trim(),r=t.to.trim();return n||r?{fieldKey:e.path,operator:`RANGE`,...n?{from:n}:{},...r?{to:r}:{}}:null}case`boolean`:{let n=t.values[0];return n===`true`||n===`false`?{fieldKey:e.path,operator:`EQUALS`,values:[n]}:null}}}function ne(e,t){return e.flatMap(e=>{let n=v(e,t[e.path]??m);return n?[n]:[]})}var y={direction:`DESC`,field:``},re={id:``,label:`預設(建立時間,新到舊)`},b={completedAt:`完成時間`,submittedAt:`送出時間`,updatedAt:`最後更新`};function ie(e,t){let n=d.APPROVAL_INSTANCE_SORT_TIME_FIELDS.map(e=>({id:e,label:b[e]})),r=t?e.filter(d.isFilterableFieldSortable).map(e=>({id:e.path,label:e.label})):[];return[re,...n,...r]}function ae(e,t,n){return e===``||d.APPROVAL_INSTANCE_SORT_TIME_FIELDS.includes(e)?!0:n&&t.some(t=>t.path===e)}function oe(e){return e.field===``?void 0:[{direction:e.direction,field:e.field}]}var x=[{id:`true`,name:`是`},{id:`false`,name:`否`}];function se(e,t,n){return e.flatMap(e=>{let r=t[e.path]??m,i=t=>{n(e.path,t)},o=p(e);return o.kind===`number-range`?[S(`${e.path}:from`,`${e.label}(下限)`,(0,s.jsx)(a.Input,{fullWidth:!0,onChange:e=>{i({...r,from:e.target.value})},placeholder:`${e.label}:下限`,size:`sub`,value:r.from,variant:`base`}),w(r.from)),S(`${e.path}:to`,`${e.label}(上限)`,(0,s.jsx)(a.Input,{fullWidth:!0,onChange:e=>{i({...r,to:e.target.value})},placeholder:`${e.label}:上限`,size:`sub`,value:r.to,variant:`base`}),w(r.to))]:[S(e.path,e.label,T(e,r,i,e.label),o.kind===`id-in`?`多個${C(e)}以逗號分隔`:void 0)]})}function S(e,t,n,r){return(0,s.jsx)(a.Filter,{span:2,children:(0,s.jsx)(a.FormField,{fullWidth:!0,hintText:r,controlFieldSlotLayout:l.ControlFieldSlotLayout.SUB,layout:l.FormFieldLayout.VERTICAL,label:t,name:`fieldFilter-${e}`,children:n})},e)}function C(e){return e.kind===`org_unit`?`組織`:`成員`}function w(e){return!e||g(e)?void 0:`請輸入數字`}function T(e,t,n,r){let i=p(e);if(i.kind===`option-in`){let e=i.options.map(e=>({id:e.value,name:e.label}));return(0,s.jsx)(a.Select,{clearable:!0,fullWidth:!0,mode:`multiple`,onChange:e=>{n({...t,values:e.map(e=>e.id)})},options:[...e],placeholder:`${r}:全部`,size:`sub`,value:e.filter(e=>t.values.includes(e.id))})}if(i.kind===`boolean`){let e=x.find(e=>t.values.includes(e.id));return(0,s.jsx)(a.Select,{clearable:!0,fullWidth:!0,onChange:e=>{n({...t,values:e?[e.id]:[]})},options:[...x],placeholder:`${r}:全部`,size:`sub`,value:e??null})}return i.kind===`date-range`?(0,s.jsx)(a.DateRangePicker,{clearable:!0,fullWidth:!0,inputFromPlaceholder:`${r}:起`,inputToPlaceholder:`迄`,onChange:e=>{n({...t,from:(0,f.formatDatePickerValue)(e?.[0])??``,to:(0,f.formatDatePickerValue)(e?.[1])??``})},size:`sub`,value:t.from&&t.to?[t.from,t.to]:[]}):i.kind===`datetime-range`?(0,s.jsx)(a.DateTimeRangePicker,{clearable:!0,fullWidth:!0,onChange:e=>{n({...t,from:(0,f.formatDateTimePickerValue)(e[0])??``,to:(0,f.formatDateTimePickerValue)(e[1])??``})},size:`sub`,value:[t.from||void 0,t.to||void 0]}):i.kind===`id-in`?(0,s.jsx)(a.Input,{fullWidth:!0,onChange:e=>{n({...t,text:e.target.value})},placeholder:`${r}:${C(e)} ID`,size:`sub`,value:t.text,variant:`base`}):(0,s.jsx)(a.Input,{fullWidth:!0,onChange:e=>{n({...t,text:e.target.value})},placeholder:`${r}:包含`,size:`sub`,value:t.text,variant:`base`})}var ce={instanceFilterArea:`bpm_instanceFilterArea_qpvJq`},le=[10,20,50],ue=3,E=[{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`}],de=[{id:`DESC`,name:`新到舊`},{id:`ASC`,name:`舊到新`}];function fe({defaultState:e,description:f,emptyMessage:p,searchPlaceholder:m,title:h,view:g}){let _=t.r(),te=n.r(),[v,b]=(0,i.useState)(null),[x,S]=(0,i.useState)(new Map),[C,w]=(0,i.useState)(1),[T,fe]=(0,i.useState)(10),[O,k]=(0,i.useState)(0),[j,M]=(0,i.useState)(!0),[N,be]=(0,i.useState)([]),[P,F]=(0,i.useState)(``),[I,L]=(0,i.useState)(D(e)),[R,z]=(0,i.useState)([]),[B,xe]=(0,i.useState)(null),[V,H]=(0,i.useState)(null),[Se,U]=(0,i.useState)(!1),[W,G]=(0,i.useState)(null),[K,q]=(0,i.useState)({}),[J,Y]=(0,i.useState)(y),X=(0,i.useRef)(0),Z=(0,i.useMemo)(()=>V?(0,d.readFilterableFieldPaths)(V):[],[V]),Ce=(0,i.useMemo)(()=>B===null?void 0:ne(Z,K),[K,Z,B]),we=(0,i.useMemo)(()=>oe(J),[J]),Te=(0,i.useMemo)(()=>ie(Z,B!==null),[Z,B]),Q=(0,i.useCallback)(async()=>{let e=X.current+1;X.current=e,M(!0),b(null);try{let t=await(0,c.listApprovalInstancesPage)({fieldFilters:Ce,page:C,pageSize:T,searchText:P,sort:we,state:I.state,templateId:B,view:g});if(e!==X.current)return;be(t.instances.map(he)),k(t.totalCount)}catch(t){e===X.current&&b(A(t))}finally{e===X.current&&M(!1)}},[Ce,C,T,P,we,I,B,g]);(0,i.useEffect)(()=>{Q()},[Q]),(0,i.useEffect)(()=>{let e=!1;return(async()=>{try{let t=await(0,ee.listApprovalTemplates)();e||z(t)}catch{e||z([])}})(),()=>{e=!0}},[]),(0,i.useEffect)(()=>{if(B===null){H(null),U(!1),G(null);return}let e=!1;return U(!0),G(null),(async()=>{try{let t=await(0,c.readApprovalTemplateCurrentFormSchema)(B);e||H(t)}catch(t){e||(H(null),G(A(t)))}finally{e||U(!1)}})(),()=>{e=!0}},[B]),(0,i.useEffect)(()=>{let e=Array.from(new Set(N.map(e=>e.initiatorMemberId).filter(Boolean)));if(e.length===0){S(new Map);return}let t=!1;return(async()=>{try{let n=await(0,o.resolveMembers)(e);if(t)return;S(new Map(n.map(e=>[e.memberId,e])))}catch{if(t)return;S(new Map)}})(),()=>{t=!0}},[N]);let Ee=(0,i.useCallback)(e=>{xe(e?.id??null),H(null),q({}),w(1),Y(e=>ae(e.field,[],!1)?e:{...e,field:y.field})},[]),De=(0,i.useCallback)(()=>{F(``),L(D(e)),xe(null),H(null),q({}),Y(y),w(1)},[e]),Oe=(0,i.useCallback)(()=>{Q()},[Q]),ke=(0,i.useCallback)((e,t)=>{q(n=>({...n,[e]:t})),w(1)},[]),Ae=(0,i.useMemo)(()=>[{dataIndex:`caseTitle`,key:`caseTitle`,title:`案件`,width:300},{key:`state`,render:e=>(0,s.jsx)(a.Typography,{color:ve(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:ye(e.initiatorMemberId,x)}),title:`發起人`,width:180},{key:`startedAt`,render:e=>(0,s.jsx)(a.Typography,{component:`span`,variant:`body`,children:r.t(e.startedAt)}),title:`發起時間`,width:220},{key:`completedAt`,render:e=>(0,s.jsx)(a.Typography,{component:`span`,variant:`body`,children:r.t(e.completedAt)}),title:`完成時間`,width:220}],[x]),je=(0,i.useMemo)(()=>({render:e=>[{name:`查看`,onClick:()=>_.push(te.caseDetail(e.id))}],variant:`base-secondary`,width:88}),[_]),Me=(0,i.useMemo)(()=>R.map(e=>({id:e.id,name:e.name})),[R]),Ne=Me.find(e=>e.id===B),Pe=(0,i.useMemo)(()=>pe(se(Z,K,ke),ue).map((e,t)=>(0,s.jsx)(a.FilterLine,{children:[...e]},`field-filter-line-${t}`)),[K,Z,ke]),$=(0,i.useMemo)(()=>Te.map(e=>({id:e.id,name:e.label})),[Te]),Fe=$.find(e=>e.id===J.field)??$.find(e=>e.id===re.id),Ie=(0,s.jsxs)(a.FilterLine,{children:[(0,s.jsx)(a.Filter,{span:2,children:(0,s.jsx)(a.FormField,{fullWidth:!0,controlFieldSlotLayout:l.ControlFieldSlotLayout.SUB,layout:l.FormFieldLayout.VERTICAL,name:`instanceSearchText`,children:(0,s.jsx)(a.Input,{fullWidth:!0,onChange:e=>{F(e.target.value),w(1)},placeholder:m,size:`sub`,value:P,variant:`base`})})}),(0,s.jsx)(a.Filter,{span:2,children:(0,s.jsx)(a.FormField,{fullWidth:!0,controlFieldSlotLayout:l.ControlFieldSlotLayout.SUB,layout:l.FormFieldLayout.VERTICAL,name:`instanceState`,children:(0,s.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>{L(ge(e)),w(1)},options:[...E],placeholder:`狀態`,renderValue:e=>`狀態:${_e(e)}`,size:`sub`,value:I})})}),(0,s.jsx)(a.Filter,{span:2,children:(0,s.jsx)(a.FormField,{fullWidth:!0,controlFieldSlotLayout:l.ControlFieldSlotLayout.SUB,layout:l.FormFieldLayout.VERTICAL,label:`範本`,name:`instanceTemplate`,children:(0,s.jsx)(a.Select,{clearable:!0,fullWidth:!0,onChange:Ee,options:[...Me],placeholder:`全部範本`,size:`sub`,value:Ne??null})})})]},`search`),Le=(0,s.jsxs)(a.FilterLine,{children:[(0,s.jsx)(a.Filter,{span:2,children:(0,s.jsx)(a.FormField,{fullWidth:!0,controlFieldSlotLayout:l.ControlFieldSlotLayout.SUB,layout:l.FormFieldLayout.VERTICAL,label:`排序欄位`,name:`instanceSortField`,children:(0,s.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>{Y(t=>({...t,field:e?.id??y.field})),w(1)},options:[...$],placeholder:`排序欄位`,size:`sub`,value:Fe??null})})}),(0,s.jsx)(a.Filter,{span:2,children:(0,s.jsx)(a.FormField,{fullWidth:!0,controlFieldSlotLayout:l.ControlFieldSlotLayout.SUB,layout:l.FormFieldLayout.VERTICAL,label:`排序方向`,name:`instanceSortDirection`,children:(0,s.jsx)(a.RadioGroup,{name:`instanceSortDirection`,onChange:e=>{Y(t=>({...t,direction:me(e.target.value)})),w(1)},options:[...de],size:`sub`,type:`segment`,value:J.direction})})})]},`sort`);return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.PageHeader,{children:(0,s.jsx)(u.default,{description:f,title:h})}),(0,s.jsx)(a.SectionGroup,{children:(0,s.jsxs)(a.Section,{filterArea:(0,s.jsx)(a.FilterArea,{className:ce.instanceFilterArea,onReset:De,onSubmit:Oe,resetText:`清除條件`,rowAlign:`end`,size:`sub`,submitText:`重新查詢`,children:[Ie,...Pe,Le]}),children:[v?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:v}):null,W?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:W}):null,B!==null&&!Se&&!W&&V&&Z.length===0?(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:`此範本沒有可篩選的欄位。`}):null,!v&&!j&&N.length===0?(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:p}):null,(0,s.jsx)(a.Table,{actions:je,columns:Ae,dataSource:[...N],fullWidth:!0,loading:j,pagination:{current:C,onChange:e=>{w(e)},onChangePageSize:e=>{w(1),fe(e)},pageSize:T,pageSizeLabel:`每頁筆數`,pageSizeOptions:le,renderResultSummary:(e,t,n)=>`顯示 ${e}-${t} 筆,共 ${n} 筆`,showPageSizeOptions:!0,total:O}})]})})]})}function pe(e,t){return e.reduce((e,n)=>{let r=e[e.length-1];return r&&r.length<t?[...e.slice(0,-1),[...r,n]]:[...e,[n]]},[])}function me(e){return e===`ASC`?`ASC`:`DESC`}function he(e){return{...e,caseTitle:(0,c.readApprovalInstanceCaseTitle)(e),key:e.id,stateLabel:k(e.state)}}function ge(e){return O(e)?D(e.state):E[0]}function D(e){return E.find(t=>t.state===e)??E[0]}function _e(e){return O(e)?e.name:E[0].name}function O(e){return typeof e==`object`&&!!e&&`id`in e&&`name`in e&&`state`in e}function k(e){return e===`RUNNING`?`進行中`:e===`APPROVED`?`已通過`:e===`REJECTED`?`已拒絕`:e===`RETURNED`?`已退回`:e===`CANCELLED`?`已取消`:e===`EXPIRED`?`已逾期`:`草稿`}function ve(e){return e===`APPROVED`?`text-success`:e===`REJECTED`||e===`CANCELLED`||e===`EXPIRED`?`text-error`:`text-neutral`}function ye(e,t){let n=(e??``).trim();return n?t.get(n)?.name??n:`未知發起人`}function A(e){return e instanceof Error?e.message:`讀取簽核案件失敗。`}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return fe}});
|
|
2
|
+
//# sourceMappingURL=approval-instance-list-page-Dcvo6TrT.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-instance-list-page-Dcvo6TrT.cjs","names":["APPROVAL_INSTANCE_SORT_TIME_FIELDS","isFilterableFieldSortable","Input","Filter","FormField","ControlFieldSlotLayout","FormFieldLayout","Select","DateRangePicker","formatDatePickerValue","DateTimeRangePicker","formatDateTimePickerValue","useRouterAdapter","useBPMRoutes","useState","useRef","useMemo","readFilterableFieldPaths","useCallback","listApprovalInstancesPage","listApprovalTemplates","readApprovalTemplateCurrentFormSchema","resolveMembers","Typography","formatDateTime","FilterLine","Filter","FormField","ControlFieldSlotLayout","FormFieldLayout","Input","Select","RadioGroup","_Fragment","PageHeader","ContentHeader","SectionGroup","Section","FilterArea","styles","Table","readApprovalInstanceCaseTitle","require_rolldown_runtime","require_router_adapter","require_routes_config","require_format_date_time","react","_mezzanine_ui_react","_rytass_bpm_core_client","react_jsx_runtime","_rytass_bpm_core_client_workflow","_mezzanine_ui_core_form","_mezzanine_ui_react_ContentHeader","_rytass_bpm_core_client_template","_rytass_bpm_core_shared","_rytass_bpm_core_client_form","readFieldFilterControl","item","EMPTY_FIELD_FILTER_DRAFT","DECIMAL_PATTERN","isDecimalText","readDecimal","value","plain","readIdList","text","toApprovalInstanceFieldFilter","draft","ids","from","to","buildApprovalInstanceFieldFilters","paths","filter","drafts","DEFAULT_SORT_DRAFT","DEFAULT_SORT_OPTION","SORT_TIME_LABELS","readSortFieldOptions","timeOptions","field","fieldOptions","templateSelected","isSortFieldAvailable","toApprovalInstanceSort","BOOLEAN_CHOICES","readFieldFilterElements","change","onDraftChange","next","control","renderFilter","event","readNumberHint","renderControl","readIdNoun","key","choices","option","selected","label","choice","target","approval_instance_list_page_module_default","INSTANCE_PAGE_SIZE_OPTIONS","FIELD_FILTERS_PER_LINE","STATE_FILTER_OPTIONS","SORT_DIRECTION_OPTIONS","ApprovalInstanceListPage","router","routes","error","setError","initiatorProfilesById","setInitiatorProfilesById","instancePage","setInstancePage","instancePageSize","setInstancePageSize","instanceTotalCount","setInstanceTotalCount","loading","setLoading","rows","setRows","searchText","setSearchText","stateFilter","setStateFilter","readStateFilterOption","defaultState","templates","setTemplates","templateId","setTemplateId","templateSchema","setTemplateSchema","schemaLoading","setSchemaLoading","schemaError","setSchemaError","fieldDrafts","setFieldDrafts","sortDraft","setSortDraft","refreshRequestIdRef","fieldPaths","fieldFilters","sort","sortOptions","refreshInstances","requestId","result","readApprovalInstanceRow","requestError","readErrorMessage","view","cancelled","loaded","schema","schemaLoadError","initiatorMemberIds","row","profiles","profile","handleTemplateChange","previous","handleFilterReset","handleFilterSubmit","handleFieldDraftChange","path","columns","readInstanceStateColor","record","readInitiatorLabel","tableActions","templateOptions","template","selectedTemplate","fieldFilterLines","chunkElements","elements","index","sortFieldChoices","selectedSortField","searchFilterLine","searchPlaceholder","readSelectedStateFilterOption","readStateFilterLabel","sortFilterLine","readSortDirection","emptyMessage","page","pageSize","total","items","last","lines","size","instance","readInstanceStateLabel","isStateFilterOption","state","trimmedMemberId","initiatorMemberId"],"sources":["../../src/components/approval-instance-field-filters.ts","../../src/components/approval-instance-field-filter-controls.tsx","../../src/components/approval-instance-list-page.module.scss","../../src/components/approval-instance-list-page.tsx"],"sourcesContent":["import {\n APPROVAL_INSTANCE_SORT_TIME_FIELDS,\n isFilterableFieldSortable,\n type ApprovalInstanceFieldFilter,\n type ApprovalInstanceSort,\n type ApprovalInstanceSortDirection,\n type FilterableFieldPath,\n type FormFieldOption,\n} from '@rytass/bpm-core-shared';\n\n/**\n * Pure logic behind the list page's field filters (ADR 25 §7). Turns the\n * filterable fields of a template's schema into controls, and the control\n * values into `fieldFilters` and `sort` for `listApprovalInstancesPage`. The\n * operator for each control is one `readFilterOperatorsForFieldType` allows.\n */\n\n/** Which control a filterable field gets on the list page. */\nexport type FieldFilterControl =\n /** Text, textarea and dynamic (data-source) options: CONTAINS on a text input. */\n | { readonly kind: 'contains' }\n /** Static options: IN on a multi-select. */\n | { readonly kind: 'option-in'; readonly options: readonly FormFieldOption[] }\n /** Member and org unit: IN on comma-separated ids (no picker yet). */\n | { readonly kind: 'id-in' }\n /** Number and money: RANGE with two number inputs. */\n | { readonly kind: 'number-range' }\n /** Date: RANGE with a date range picker. */\n | { readonly kind: 'date-range' }\n /** Datetime: RANGE with a datetime range picker. */\n | { readonly kind: 'datetime-range' }\n /** Boolean: EQUALS with a yes / no select. */\n | { readonly kind: 'boolean' };\n\nexport function readFieldFilterControl(\n item: FilterableFieldPath,\n): FieldFilterControl {\n switch (item.kind) {\n case 'number':\n return { kind: 'number-range' };\n case 'date':\n return { kind: 'date-range' };\n case 'datetime':\n return { kind: 'datetime-range' };\n case 'boolean':\n return { kind: 'boolean' };\n case 'member':\n case 'org_unit':\n return { kind: 'id-in' };\n case 'option':\n return item.staticOptions\n ? { kind: 'option-in', options: item.staticOptions }\n : { kind: 'contains' };\n case 'text':\n return { kind: 'contains' };\n }\n}\n\n/**\n * One field's entered condition. `from` and `to` hold canonical values\n * (decimal string, `YYYY-MM-DD`, or ISO 8601) as the controls produce them.\n */\nexport interface FieldFilterDraft {\n readonly from: string;\n readonly to: string;\n /** CONTAINS text, or comma-separated ids for IN on member and org unit. */\n readonly text: string;\n /** Selected option values (IN), or `['true']` / `['false']` for boolean. */\n readonly values: readonly string[];\n}\n\nexport const EMPTY_FIELD_FILTER_DRAFT: FieldFilterDraft = {\n from: '',\n text: '',\n to: '',\n values: [],\n};\n\n/** Drafts keyed by the field path, so a path can be looked up directly. */\nexport type FieldFilterDrafts = Readonly<Record<string, FieldFilterDraft>>;\n\nconst DECIMAL_PATTERN = /^-?\\d+(\\.\\d+)?$/u;\n\n/**\n * Whether a number control's text is a decimal. Surrounding spaces and\n * thousands separators (`1,000`) are accepted and dropped before sending.\n */\nexport function isDecimalText(value: string): boolean {\n return readDecimal(value) !== null;\n}\n\nfunction readDecimal(value: string): string | null {\n const plain = value.trim().replace(/,/gu, '');\n\n return DECIMAL_PATTERN.test(plain) ? plain : null;\n}\n\nfunction readIdList(text: string): readonly string[] {\n return text\n .split(',')\n .map((item) => item.trim())\n .filter((item) => item.length > 0);\n}\n\n/**\n * The condition one draft asks for, or `null` when it is empty. Empty means\n * no condition, so it must not reach the server as a filter.\n */\nexport function toApprovalInstanceFieldFilter(\n item: FilterableFieldPath,\n draft: FieldFilterDraft,\n): ApprovalInstanceFieldFilter | null {\n const control = readFieldFilterControl(item);\n\n switch (control.kind) {\n case 'contains': {\n const text = draft.text.trim();\n\n return text\n ? { fieldKey: item.path, operator: 'CONTAINS', values: [text] }\n : null;\n }\n case 'option-in':\n return draft.values.length > 0\n ? { fieldKey: item.path, operator: 'IN', values: [...draft.values] }\n : null;\n case 'id-in': {\n const ids = readIdList(draft.text);\n\n return ids.length > 0\n ? { fieldKey: item.path, operator: 'IN', values: ids }\n : null;\n }\n case 'number-range': {\n const from = readDecimal(draft.from);\n const to = readDecimal(draft.to);\n\n return from || to\n ? {\n fieldKey: item.path,\n operator: 'RANGE',\n ...(from ? { from } : {}),\n ...(to ? { to } : {}),\n }\n : null;\n }\n case 'date-range':\n case 'datetime-range': {\n const from = draft.from.trim();\n const to = draft.to.trim();\n\n return from || to\n ? {\n fieldKey: item.path,\n operator: 'RANGE',\n ...(from ? { from } : {}),\n ...(to ? { to } : {}),\n }\n : null;\n }\n case 'boolean': {\n const value = draft.values[0];\n\n return value === 'true' || value === 'false'\n ? { fieldKey: item.path, operator: 'EQUALS', values: [value] }\n : null;\n }\n }\n}\n\n/** Every non-empty condition, in schema order. */\nexport function buildApprovalInstanceFieldFilters(\n paths: readonly FilterableFieldPath[],\n drafts: FieldFilterDrafts,\n): readonly ApprovalInstanceFieldFilter[] {\n return paths.flatMap((item): readonly ApprovalInstanceFieldFilter[] => {\n const filter = toApprovalInstanceFieldFilter(\n item,\n drafts[item.path] ?? EMPTY_FIELD_FILTER_DRAFT,\n );\n\n return filter ? [filter] : [];\n });\n}\n\n/** The sort the user picked. An empty `field` keeps the server default. */\nexport interface SortDraft {\n readonly direction: ApprovalInstanceSortDirection;\n readonly field: string;\n}\n\nexport const DEFAULT_SORT_DRAFT: SortDraft = { direction: 'DESC', field: '' };\n\nexport interface SortFieldOption {\n readonly id: string;\n readonly label: string;\n}\n\nexport const DEFAULT_SORT_OPTION: SortFieldOption = {\n id: '',\n label: '預設(建立時間,新到舊)',\n};\n\nconst SORT_TIME_LABELS: Readonly<\n Record<(typeof APPROVAL_INSTANCE_SORT_TIME_FIELDS)[number], string>\n> = {\n completedAt: '完成時間',\n submittedAt: '送出時間',\n updatedAt: '最後更新',\n};\n\n/**\n * Sort choices. Time fields are always offered. Form fields are offered only\n * with a template selected, because the server needs a template to sort by a\n * form field.\n */\nexport function readSortFieldOptions(\n paths: readonly FilterableFieldPath[],\n templateSelected: boolean,\n): readonly SortFieldOption[] {\n const timeOptions = APPROVAL_INSTANCE_SORT_TIME_FIELDS.map(\n (field): SortFieldOption => ({ id: field, label: SORT_TIME_LABELS[field] }),\n );\n const fieldOptions = templateSelected\n ? paths\n .filter(isFilterableFieldSortable)\n .map((item): SortFieldOption => ({ id: item.path, label: item.label }))\n : [];\n\n return [DEFAULT_SORT_OPTION, ...timeOptions, ...fieldOptions];\n}\n\n/** Whether a sort on `field` is valid for the current template selection. */\nexport function isSortFieldAvailable(\n field: string,\n paths: readonly FilterableFieldPath[],\n templateSelected: boolean,\n): boolean {\n if (field === '') {\n return true;\n }\n\n if (\n (APPROVAL_INSTANCE_SORT_TIME_FIELDS as readonly string[]).includes(field)\n ) {\n return true;\n }\n\n return templateSelected && paths.some((item) => item.path === field);\n}\n\nexport function toApprovalInstanceSort(\n draft: SortDraft,\n): readonly ApprovalInstanceSort[] | undefined {\n return draft.field === ''\n ? undefined\n : [{ direction: draft.direction, field: draft.field }];\n}\n","'use client';\n\nimport type { ReactElement } from 'react';\nimport {\n DateRangePicker,\n DateTimeRangePicker,\n Filter,\n FormField,\n Input,\n Select,\n type FilterProps,\n} from '@mezzanine-ui/react';\nimport {\n ControlFieldSlotLayout,\n FormFieldLayout,\n} from '@mezzanine-ui/core/form';\nimport {\n formatDatePickerValue,\n formatDateTimePickerValue,\n} from '@rytass/bpm-core-client/form';\nimport type { FilterableFieldPath } from '@rytass/bpm-core-shared';\nimport {\n EMPTY_FIELD_FILTER_DRAFT,\n isDecimalText,\n readFieldFilterControl,\n type FieldFilterDraft,\n type FieldFilterDrafts,\n} from './approval-instance-field-filters';\n\nexport type FieldFilterDraftChange = (\n path: string,\n draft: FieldFilterDraft,\n) => void;\n\ntype SelectChoice = Readonly<{ id: string; name: string }>;\n\nconst BOOLEAN_CHOICES: readonly SelectChoice[] = [\n { id: 'true', name: '是' },\n { id: 'false', name: '否' },\n];\n\n/**\n * One list-page `Filter` per condition the template's filterable fields need.\n * A number field yields two (lower and upper bound) because Mezzanine has no\n * number range control. Returned as elements so the caller can place them\n * directly inside `FilterLine`, which only accepts `Filter` children.\n */\nexport function readFieldFilterElements(\n paths: readonly FilterableFieldPath[],\n drafts: FieldFilterDrafts,\n onDraftChange: FieldFilterDraftChange,\n): readonly ReactElement<FilterProps>[] {\n return paths.flatMap((item): readonly ReactElement<FilterProps>[] => {\n const draft = drafts[item.path] ?? EMPTY_FIELD_FILTER_DRAFT;\n const change = (next: FieldFilterDraft): void => {\n onDraftChange(item.path, next);\n };\n const control = readFieldFilterControl(item);\n\n if (control.kind === 'number-range') {\n return [\n renderFilter(\n `${item.path}:from`,\n `${item.label}(下限)`,\n <Input\n fullWidth\n onChange={(event): void => {\n change({ ...draft, from: event.target.value });\n }}\n placeholder={`${item.label}:下限`}\n size=\"sub\"\n value={draft.from}\n variant=\"base\"\n />,\n readNumberHint(draft.from),\n ),\n renderFilter(\n `${item.path}:to`,\n `${item.label}(上限)`,\n <Input\n fullWidth\n onChange={(event): void => {\n change({ ...draft, to: event.target.value });\n }}\n placeholder={`${item.label}:上限`}\n size=\"sub\"\n value={draft.to}\n variant=\"base\"\n />,\n readNumberHint(draft.to),\n ),\n ];\n }\n\n return [\n renderFilter(\n item.path,\n item.label,\n renderControl(item, draft, change, item.label),\n control.kind === 'id-in'\n ? `多個${readIdNoun(item)}以逗號分隔`\n : undefined,\n ),\n ];\n });\n}\n\nfunction renderFilter(\n key: string,\n label: string,\n control: ReactElement,\n hintText?: string,\n): ReactElement<FilterProps> {\n return (\n <Filter key={key} span={2}>\n <FormField\n fullWidth\n hintText={hintText}\n controlFieldSlotLayout={ControlFieldSlotLayout.SUB}\n layout={FormFieldLayout.VERTICAL}\n label={label}\n name={`fieldFilter-${key}`}\n >\n {control}\n </FormField>\n </Filter>\n );\n}\n\n/** What an id-in field holds: members, or org units for an `org_unit` field. */\nfunction readIdNoun(item: FilterableFieldPath): string {\n return item.kind === 'org_unit' ? '組織' : '成員';\n}\n\nfunction readNumberHint(value: string): string | undefined {\n return !value || isDecimalText(value) ? undefined : '請輸入數字';\n}\n\nfunction renderControl(\n item: FilterableFieldPath,\n draft: FieldFilterDraft,\n change: (next: FieldFilterDraft) => void,\n label: string,\n): ReactElement {\n // The list page hides FormField labels to keep its filter rows compact, so\n // each control names its field in the placeholder, as the state filter does.\n const control = readFieldFilterControl(item);\n\n if (control.kind === 'option-in') {\n const choices = control.options.map((option): SelectChoice => ({\n id: option.value,\n name: option.label,\n }));\n\n return (\n <Select\n clearable\n fullWidth\n mode=\"multiple\"\n onChange={(selected: readonly SelectChoice[]): void => {\n change({ ...draft, values: selected.map((option) => option.id) });\n }}\n options={[...choices]}\n placeholder={`${label}:全部`}\n size=\"sub\"\n value={choices.filter((choice) => draft.values.includes(choice.id))}\n />\n );\n }\n\n if (control.kind === 'boolean') {\n const selected = BOOLEAN_CHOICES.find((choice) =>\n draft.values.includes(choice.id),\n );\n\n return (\n <Select\n clearable\n fullWidth\n onChange={(option: SelectChoice | null): void => {\n change({ ...draft, values: option ? [option.id] : [] });\n }}\n options={[...BOOLEAN_CHOICES]}\n placeholder={`${label}:全部`}\n size=\"sub\"\n value={selected ?? null}\n />\n );\n }\n\n if (control.kind === 'date-range') {\n return (\n <DateRangePicker\n clearable\n fullWidth\n inputFromPlaceholder={`${label}:起`}\n inputToPlaceholder=\"迄\"\n onChange={(target?: readonly (string | undefined)[]): void => {\n change({\n ...draft,\n from: formatDatePickerValue(target?.[0]) ?? '',\n to: formatDatePickerValue(target?.[1]) ?? '',\n });\n }}\n size=\"sub\"\n value={draft.from && draft.to ? [draft.from, draft.to] : []}\n />\n );\n }\n\n if (control.kind === 'datetime-range') {\n return (\n <DateTimeRangePicker\n clearable\n fullWidth\n onChange={(value): void => {\n change({\n ...draft,\n from: formatDateTimePickerValue(value[0]) ?? '',\n to: formatDateTimePickerValue(value[1]) ?? '',\n });\n }}\n size=\"sub\"\n value={[draft.from || undefined, draft.to || undefined]}\n />\n );\n }\n\n if (control.kind === 'id-in') {\n return (\n <Input\n fullWidth\n onChange={(event): void => {\n change({ ...draft, text: event.target.value });\n }}\n placeholder={`${label}:${readIdNoun(item)} ID`}\n size=\"sub\"\n value={draft.text}\n variant=\"base\"\n />\n );\n }\n\n // contains (text, textarea and data-source options)\n return (\n <Input\n fullWidth\n onChange={(event): void => {\n change({ ...draft, text: event.target.value });\n }}\n placeholder={`${label}:包含`}\n size=\"sub\"\n value={draft.text}\n variant=\"base\"\n />\n );\n}\n",".instanceFilterArea {\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 RadioGroup,\n Section,\n SectionGroup,\n Select,\n Table,\n Typography,\n type FilterLineProps,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport {\n ControlFieldSlotLayout,\n FormFieldLayout,\n} 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 listApprovalTemplates,\n type ApprovalTemplateRecord,\n} from '@rytass/bpm-core-client/template';\nimport {\n listApprovalInstancesPage,\n readApprovalInstanceCaseTitle,\n readApprovalTemplateCurrentFormSchema,\n type ApprovalInstanceRecord,\n type ApprovalInstanceState,\n type ApprovalInstanceView,\n} from '@rytass/bpm-core-client/workflow';\nimport {\n readFilterableFieldPaths,\n type ApprovalInstanceFieldFilter,\n type ApprovalInstanceSort,\n type ApprovalInstanceSortDirection,\n type FilterableFieldPath,\n type FormDefinitionSchema,\n} from '@rytass/bpm-core-shared';\nimport { useRouterAdapter } from '../lib/router-adapter';\nimport { useBPMRoutes } from '../lib/routes-config';\nimport { formatDateTime } from '../lib/format-date-time';\nimport {\n buildApprovalInstanceFieldFilters,\n DEFAULT_SORT_DRAFT,\n DEFAULT_SORT_OPTION,\n isSortFieldAvailable,\n readSortFieldOptions,\n toApprovalInstanceSort,\n type FieldFilterDraft,\n type FieldFilterDrafts,\n type SortDraft,\n type SortFieldOption,\n} from './approval-instance-field-filters';\nimport { readFieldFilterElements } from './approval-instance-field-filter-controls';\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\ntype SelectChoice = Readonly<{ id: string; name: string }>;\n\nconst INSTANCE_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst FIELD_FILTERS_PER_LINE = 3;\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];\nconst SORT_DIRECTION_OPTIONS: readonly (SelectChoice & {\n id: ApprovalInstanceSortDirection;\n})[] = [\n { id: 'DESC', name: '新到舊' },\n { id: 'ASC', name: '舊到新' },\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 *\n * With a template selected, the filter bar also carries one control per\n * filterable field of that template's current form (ADR 25 §7), and the sort\n * may use those fields. Without a template only time fields can sort.\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 [templates, setTemplates] = useState<readonly ApprovalTemplateRecord[]>(\n [],\n );\n const [templateId, setTemplateId] = useState<string | null>(null);\n const [templateSchema, setTemplateSchema] =\n useState<FormDefinitionSchema | null>(null);\n const [schemaLoading, setSchemaLoading] = useState(false);\n const [schemaError, setSchemaError] = useState<string | null>(null);\n const [fieldDrafts, setFieldDrafts] = useState<FieldFilterDrafts>({});\n const [sortDraft, setSortDraft] = useState<SortDraft>(DEFAULT_SORT_DRAFT);\n const refreshRequestIdRef = useRef(0);\n\n const fieldPaths = useMemo(\n (): readonly FilterableFieldPath[] =>\n templateSchema ? readFilterableFieldPaths(templateSchema) : [],\n [templateSchema],\n );\n const fieldFilters = useMemo(\n (): readonly ApprovalInstanceFieldFilter[] | undefined =>\n templateId === null\n ? undefined\n : buildApprovalInstanceFieldFilters(fieldPaths, fieldDrafts),\n [fieldDrafts, fieldPaths, templateId],\n );\n const sort = useMemo(\n (): readonly ApprovalInstanceSort[] | undefined =>\n toApprovalInstanceSort(sortDraft),\n [sortDraft],\n );\n const sortOptions = useMemo(\n (): readonly SortFieldOption[] =>\n readSortFieldOptions(fieldPaths, templateId !== null),\n [fieldPaths, templateId],\n );\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 fieldFilters,\n page: instancePage,\n pageSize: instancePageSize,\n searchText,\n sort,\n state: stateFilter.state,\n templateId,\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 }, [\n fieldFilters,\n instancePage,\n instancePageSize,\n searchText,\n sort,\n stateFilter,\n templateId,\n view,\n ]);\n\n useEffect((): void => {\n void refreshInstances();\n }, [refreshInstances]);\n\n useEffect((): (() => void) | void => {\n let cancelled = false;\n\n void (async (): Promise<void> => {\n try {\n const loaded = await listApprovalTemplates();\n\n if (!cancelled) {\n setTemplates(loaded);\n }\n } catch {\n if (!cancelled) {\n setTemplates([]);\n }\n }\n })();\n\n return (): void => {\n cancelled = true;\n };\n }, []);\n\n // Race guard: a schema response for a previously picked template is dropped\n // when the template changes again (cleanup flips `cancelled`).\n useEffect((): (() => void) | void => {\n if (templateId === null) {\n setTemplateSchema(null);\n setSchemaLoading(false);\n setSchemaError(null);\n\n return;\n }\n\n let cancelled = false;\n setSchemaLoading(true);\n setSchemaError(null);\n\n void (async (): Promise<void> => {\n try {\n const schema = await readApprovalTemplateCurrentFormSchema(templateId);\n\n if (!cancelled) {\n setTemplateSchema(schema);\n }\n } catch (schemaLoadError: unknown) {\n if (!cancelled) {\n setTemplateSchema(null);\n setSchemaError(readErrorMessage(schemaLoadError));\n }\n } finally {\n if (!cancelled) {\n setSchemaLoading(false);\n }\n }\n })();\n\n return (): void => {\n cancelled = true;\n };\n }, [templateId]);\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 handleTemplateChange = useCallback(\n (option: SelectChoice | null): void => {\n setTemplateId(option?.id ?? null);\n // Drop the previous template's fields at once, so nothing is built from\n // them while the new schema loads.\n setTemplateSchema(null);\n setFieldDrafts({});\n setInstancePage(1);\n // A form-field sort belongs to one template. Time-field sorts survive.\n setSortDraft((previous): SortDraft =>\n isSortFieldAvailable(previous.field, [], false)\n ? previous\n : { ...previous, field: DEFAULT_SORT_DRAFT.field },\n );\n },\n [],\n );\n\n const handleFilterReset = useCallback((): void => {\n setSearchText('');\n setStateFilter(readStateFilterOption(defaultState));\n setTemplateId(null);\n setTemplateSchema(null);\n setFieldDrafts({});\n setSortDraft(DEFAULT_SORT_DRAFT);\n setInstancePage(1);\n }, [defaultState]);\n const handleFilterSubmit = useCallback((): void => {\n void refreshInstances();\n }, [refreshInstances]);\n const handleFieldDraftChange = useCallback(\n (path: string, draft: FieldFilterDraft): void => {\n setFieldDrafts((previous): FieldFilterDrafts => ({\n ...previous,\n [path]: draft,\n }));\n setInstancePage(1);\n },\n [],\n );\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 const templateOptions = useMemo(\n (): readonly SelectChoice[] =>\n templates.map((template) => ({ id: template.id, name: template.name })),\n [templates],\n );\n const selectedTemplate = templateOptions.find(\n (option) => option.id === templateId,\n );\n const fieldFilterLines = useMemo(\n (): readonly ReactElement<FilterLineProps>[] =>\n chunkElements(\n readFieldFilterElements(\n fieldPaths,\n fieldDrafts,\n handleFieldDraftChange,\n ),\n FIELD_FILTERS_PER_LINE,\n ).map((elements, index): ReactElement<FilterLineProps> => (\n <FilterLine key={`field-filter-line-${index}`}>\n {[...elements]}\n </FilterLine>\n )),\n [fieldDrafts, fieldPaths, handleFieldDraftChange],\n );\n const sortFieldChoices = useMemo(\n (): readonly SelectChoice[] =>\n sortOptions.map((option) => ({ id: option.id, name: option.label })),\n [sortOptions],\n );\n const selectedSortField =\n sortFieldChoices.find((option) => option.id === sortDraft.field) ??\n sortFieldChoices.find((option) => option.id === DEFAULT_SORT_OPTION.id);\n\n const searchFilterLine = (\n <FilterLine key=\"search\">\n <Filter span={2}>\n <FormField\n fullWidth\n controlFieldSlotLayout={ControlFieldSlotLayout.SUB}\n layout={FormFieldLayout.VERTICAL}\n name=\"instanceSearchText\"\n >\n <Input\n fullWidth\n onChange={(event: ChangeEvent<HTMLInputElement>): 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 controlFieldSlotLayout={ControlFieldSlotLayout.SUB}\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 <Filter span={2}>\n <FormField\n fullWidth\n controlFieldSlotLayout={ControlFieldSlotLayout.SUB}\n layout={FormFieldLayout.VERTICAL}\n label=\"範本\"\n name=\"instanceTemplate\"\n >\n <Select\n clearable\n fullWidth\n onChange={handleTemplateChange}\n options={[...templateOptions]}\n placeholder=\"全部範本\"\n size=\"sub\"\n value={selectedTemplate ?? null}\n />\n </FormField>\n </Filter>\n </FilterLine>\n );\n\n const sortFilterLine = (\n <FilterLine key=\"sort\">\n <Filter span={2}>\n <FormField\n fullWidth\n controlFieldSlotLayout={ControlFieldSlotLayout.SUB}\n layout={FormFieldLayout.VERTICAL}\n label=\"排序欄位\"\n name=\"instanceSortField\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option: SelectChoice | null): void => {\n setSortDraft((previous): SortDraft => ({\n ...previous,\n field: option?.id ?? DEFAULT_SORT_DRAFT.field,\n }));\n setInstancePage(1);\n }}\n options={[...sortFieldChoices]}\n placeholder=\"排序欄位\"\n size=\"sub\"\n value={selectedSortField ?? null}\n />\n </FormField>\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n controlFieldSlotLayout={ControlFieldSlotLayout.SUB}\n layout={FormFieldLayout.VERTICAL}\n label=\"排序方向\"\n name=\"instanceSortDirection\"\n >\n <RadioGroup\n name=\"instanceSortDirection\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setSortDraft((previous): SortDraft => ({\n ...previous,\n direction: readSortDirection(event.target.value),\n }));\n setInstancePage(1);\n }}\n options={[...SORT_DIRECTION_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={sortDraft.direction}\n />\n </FormField>\n </Filter>\n </FilterLine>\n );\n\n return (\n <>\n <PageHeader>\n <ContentHeader description={description} title={title} />\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea\n className={styles.instanceFilterArea}\n onReset={handleFilterReset}\n onSubmit={handleFilterSubmit}\n resetText=\"清除條件\"\n rowAlign=\"end\"\n size=\"sub\"\n submitText=\"重新查詢\"\n >\n {[searchFilterLine, ...fieldFilterLines, sortFilterLine]}\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {schemaError ? (\n <Typography color=\"text-error\" variant=\"body\">\n {schemaError}\n </Typography>\n ) : null}\n {templateId !== null &&\n !schemaLoading &&\n !schemaError &&\n templateSchema &&\n fieldPaths.length === 0 ? (\n <Typography color=\"text-neutral\" variant=\"body\">\n 此範本沒有可篩選的欄位。\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 chunkElements<T>(\n items: readonly T[],\n size: number,\n): readonly (readonly T[])[] {\n return items.reduce<readonly (readonly T[])[]>(\n (lines, item): readonly (readonly T[])[] => {\n const last = lines[lines.length - 1];\n\n return last && last.length < size\n ? [...lines.slice(0, -1), [...last, item]]\n : [...lines, [item]];\n },\n [],\n );\n}\n\nfunction readSortDirection(value: string): ApprovalInstanceSortDirection {\n return value === 'ASC' ? 'ASC' : 'DESC';\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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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";require('../categories.css');const e=require("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./bpm-form-field-Bc6k4ZEO.cjs"),n=require("./format-date-time-D-cx5M8z.cjs");let r=require("react"),i=require("@mezzanine-ui/react"),a=require("react/jsx-runtime"),o=require("@mezzanine-ui/core/form"),s=require("@mezzanine-ui/react/ContentHeader");s=e.t(s,1);let c=require("@
|
|
2
|
-
//# sourceMappingURL=categories-
|
|
1
|
+
"use client";require('../categories.css');const e=require("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./bpm-form-field-Bc6k4ZEO.cjs"),n=require("./format-date-time-D-cx5M8z.cjs");let r=require("react"),i=require("@mezzanine-ui/react"),a=require("react/jsx-runtime"),o=require("@mezzanine-ui/core/form"),s=require("@mezzanine-ui/react/ContentHeader");s=e.t(s,1);let c=require("@rytass/bpm-core-client/template"),l=require("@mezzanine-ui/icons");var u={templateFilterArea:`bpm_templateFilterArea_nUL-R`,templateModalFields:`bpm_templateModalFields_hUxWp`},d=[10,20,50],f=[{key:`ALL`,label:`全部`},{key:`ACTIVE`,label:`啟用`},{key:`INACTIVE`,label:`停用`}];function p(){let[e,t]=(0,r.useState)([]),[p,y]=(0,r.useState)(1),[b,x]=(0,r.useState)(10),[S,C]=(0,r.useState)(`ALL`),[w,T]=(0,r.useState)(0),[E,D]=(0,r.useState)(null),[O,k]=(0,r.useState)(null),[A,j]=(0,r.useState)(!0),[M,N]=(0,r.useState)(null),[P,F]=(0,r.useState)(!1),[I,L]=(0,r.useState)(``),R=(0,r.useCallback)(async()=>{j(!0),k(null);try{let e=await(0,c.listApprovalTemplateCategoriesPage)({page:p,pageSize:b,searchText:I,status:_(S)});t(e.categories),T(e.totalCount)}catch(e){k(v(e))}finally{j(!1)}},[p,b,S,I]);(0,r.useEffect)(()=>{R()},[R]);let z=(0,r.useMemo)(()=>e.map(e=>({...e,key:e.id,updatedAtLabel:n.t(e.updatedAt)})),[e]),B=(0,r.useMemo)(()=>[{dataIndex:`name`,key:`name`,title:`分類名稱`,width:180},{key:`status`,render:e=>(0,a.jsx)(h,{isActive:e.isActive}),title:`狀態`,width:120},{dataIndex:`sortOrder`,key:`sortOrder`,title:`排序`,width:100},{key:`description`,render:e=>(0,a.jsx)(i.Typography,{component:`span`,variant:`body`,children:e.description||`無`}),title:`說明`,width:260},{dataIndex:`updatedAtLabel`,key:`updatedAtLabel`,title:`更新時間`,width:220}],[]);async function V(e){F(!0),k(null);try{M?.type===`EDIT`&&M.record?await(0,c.updateApprovalTemplateCategory)({...e,id:M.record.id}):await(0,c.createApprovalTemplateCategory)(e),N(null),await R()}catch(e){throw k(v(e)),e}finally{F(!1)}}async function H(e){F(!0),k(null);try{await(0,c.updateApprovalTemplateCategory)({description:e.description,id:e.id,isActive:!e.isActive,name:e.name,sortOrder:e.sortOrder}),await R()}catch(e){k(v(e))}finally{F(!1)}}async function U(){if(E){F(!0),k(null);try{await(0,c.deleteApprovalTemplateCategory)(E.id),D(null),await R()}catch(e){k(v(e))}finally{F(!1)}}}let W=(0,r.useMemo)(()=>({render:e=>[{name:`編輯`,onClick:()=>N({record:e,type:`EDIT`})},{name:e.isActive?`停用`:`啟用`,onClick:()=>void H(e),variant:e.isActive?`destructive-secondary`:`base-secondary`},{name:`刪除`,onClick:()=>D({id:e.id,name:e.name}),variant:`destructive-secondary`}],variant:`base-secondary`,width:192}),[R]);return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(i.PageHeader,{children:(0,a.jsx)(s.default,{description:`維護簽核模板分類,供模板建立、篩選與列表標示使用。`,title:`簽核模板分類`,children:(0,a.jsx)(i.Button,{icon:l.PlusIcon,iconType:`leading`,onClick:()=>N({record:null,type:`CREATE`}),variant:`base-primary`,children:`建立分類`})})}),(0,a.jsx)(i.SectionGroup,{children:(0,a.jsxs)(i.Section,{filterArea:(0,a.jsx)(i.FilterArea,{className:u.templateFilterArea,size:`sub`,children:(0,a.jsx)(i.FilterLine,{children:(0,a.jsx)(i.Filter,{span:3,children:(0,a.jsx)(i.FormField,{fullWidth:!0,layout:o.FormFieldLayout.VERTICAL,name:`categorySearchText`,children:(0,a.jsx)(i.Input,{fullWidth:!0,onChange:e=>{L(e.target.value),y(1)},placeholder:`關鍵字:搜尋分類名稱或說明`,size:`sub`,value:I,variant:`base`})})})})}),tab:(0,a.jsx)(i.Tab,{activeKey:S,onChange:e=>{C(g(e)),y(1)},children:f.map(e=>(0,a.jsx)(i.TabItem,{children:e.label},e.key))}),children:[O?(0,a.jsx)(i.Typography,{color:`text-error`,variant:`body`,children:O}):null,(0,a.jsx)(i.Table,{actions:W,columns:B,dataSource:z,fullWidth:!0,loading:A||P,pagination:{current:p,onChange:e=>{y(e)},onChangePageSize:e=>{y(1),x(e)},pageSize:b,pageSizeLabel:`每頁筆數`,pageSizeOptions:d,renderResultSummary:(e,t,n)=>`顯示 ${e}-${t} 筆,共 ${n} 筆`,showPageSizeOptions:!0,total:w}})]})})]}),(0,a.jsx)(m,{loading:P,modal:M,onClose:()=>N(null),onSubmit:V}),(0,a.jsx)(i.Modal,{cancelText:`取消`,confirmButtonProps:{variant:`destructive-primary`},confirmText:`刪除`,loading:P,modalStatusType:`error`,modalType:`standard`,onCancel:()=>D(null),onClose:()=>D(null),onConfirm:()=>void U(),open:!!E,showModalFooter:!0,showModalHeader:!0,size:`regular`,supportingText:`已被模板使用的分類無法刪除,請改用「停用」。`,title:`刪除分類`,children:(0,a.jsxs)(i.Typography,{color:`text-neutral`,variant:`body`,children:[`確定要刪除「`,E?.name??``,`」嗎?`]})})]})}function m({loading:e,modal:n,onClose:o,onSubmit:s}){let[c,l]=(0,r.useState)(``),[d,f]=(0,r.useState)(null),[p,m]=(0,r.useState)(``),[h,g]=(0,r.useState)(`0`);(0,r.useEffect)(()=>{n&&(l(n.record?.description??``),f(null),m(n.record?.name??``),g(String(n.record?.sortOrder??0)))},[n]);async function _(){let e=p.trim(),t=Number(h);if(!e)f(`請輸入分類名稱`);else if(!Number.isInteger(t))f(`排序必須是整數`);else try{await s({description:c.trim()||null,isActive:n?.record?.isActive??!0,name:e,sortOrder:t})}catch(e){f(v(e))}}return(0,a.jsxs)(i.Modal,{cancelText:`取消`,confirmButtonProps:{disabled:!p.trim()},confirmText:n?.type===`EDIT`?`儲存`:`建立`,loading:e,modalType:`standard`,onCancel:o,onClose:o,onConfirm:()=>void _(),open:!!n,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:n?.type===`EDIT`?`編輯分類`:`建立分類`,children:[(0,a.jsxs)(`div`,{className:u.templateModalFields,children:[(0,a.jsx)(t.t,{label:`分類名稱`,name:`categoryName`,required:!0,children:(0,a.jsx)(i.Input,{autoFocus:!0,fullWidth:!0,onChange:e=>{m(e.target.value),f(null)},placeholder:`例如:行政管理`,value:p,variant:`base`})}),(0,a.jsx)(t.t,{label:`排序`,name:`categorySortOrder`,children:(0,a.jsx)(i.Input,{fullWidth:!0,onChange:e=>{g(e.target.value),f(null)},placeholder:`0`,value:h,variant:`base`})}),(0,a.jsx)(t.t,{label:`說明`,name:`categoryDescription`,children:(0,a.jsx)(i.Textarea,{onChange:e=>{l(e.target.value),f(null)},placeholder:`補充分類用途`,value:c})})]}),d?(0,a.jsx)(i.Typography,{color:`text-error`,variant:`body`,children:d}):null]})}function h({isActive:e}){return e?(0,a.jsx)(i.Badge,{size:`sub`,text:`啟用`,variant:`dot-success`}):(0,a.jsx)(i.Badge,{size:`sub`,text:`停用`,variant:`dot-inactive`})}function g(e){return e===`ACTIVE`||e===`INACTIVE`?e:`ALL`}function _(e){return e}function v(e){return e instanceof Error?e.message:`發生未知錯誤`}Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return p}});
|
|
2
|
+
//# sourceMappingURL=categories-CyyqG6wG.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"categories-DQUtVEiV.cjs","names":["useState","useCallback","listApprovalTemplateCategoriesPage","useMemo","formatDateTime","Typography","updateApprovalTemplateCategory","createApprovalTemplateCategory","deleteApprovalTemplateCategory","_Fragment","PageHeader","ContentHeader","Button","PlusIcon","SectionGroup","Section","FilterArea","styles","FilterLine","Filter","FormField","FormFieldLayout","Input","Tab","TabItem","Table","Modal","BPMFormField","Textarea","Badge","require_rolldown_runtime","require_bpm_form_field","require_format_date_time","react","_mezzanine_ui_react","react_jsx_runtime","_mezzanine_ui_core_form","_mezzanine_ui_react_ContentHeader","_mezzanine_ui_icons","_rytass_bpm_core_client_template","templates_module_default","CATEGORY_PAGE_SIZE_OPTIONS","CATEGORY_STATUS_TABS","TemplateCategoriesView","categories","setCategories","categoryPage","setCategoryPage","categoryPageSize","setCategoryPageSize","categoryStatus","setCategoryStatus","categoryTotalCount","setCategoryTotalCount","deleteConfirmation","setDeleteConfirmation","error","setError","loading","setLoading","modalState","setModalState","saving","setSaving","searchText","setSearchText","refreshCategories","categoryPageResult","readCategoryStatus","requestError","readErrorMessage","rows","category","columns","CategoryStatusBadge","record","handleSaveCategory","input","handleToggleCategory","handleConfirmDelete","tableActions","event","readCategoryStatusTabKey","activeKey","statusTab","page","pageSize","from","to","total","CategoryModal","description","setDescription","name","setName","sortOrder","setSortOrder","modal","handleConfirm","trimmedName","parsedSortOrder","onSubmit","submitError","onClose","isActive","status"],"sources":["../../src/views/templates/templates.module.scss","../../src/views/templates/categories/TemplateCategoriesView.tsx"],"sourcesContent":[".templateFilterArea {\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\n.templateModalFields {\n display: grid;\n gap: 16px;\n}\n","'use client';\n\nimport type { ChangeEvent, Key, ReactElement } from 'react';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Tab,\n TabItem,\n Table,\n Textarea,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { PlusIcon } from '@mezzanine-ui/icons';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { formatDateTime } from '../../../lib/format-date-time';\nimport {\n ApprovalTemplateCategoryRecord,\n ApprovalTemplateCategoryStatus,\n createApprovalTemplateCategory,\n deleteApprovalTemplateCategory,\n listApprovalTemplateCategoriesPage,\n updateApprovalTemplateCategory,\n} from '@rytass/bpm-core-client/template';\nimport styles from '../templates.module.scss';\n\nconst CATEGORY_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst CATEGORY_STATUS_TABS: readonly {\n readonly key: CategoryStatusTabKey;\n readonly label: string;\n}[] = [\n { key: 'ALL', label: '全部' },\n { key: 'ACTIVE', label: '啟用' },\n { key: 'INACTIVE', label: '停用' },\n];\ntype CategoryStatusTabKey = 'ACTIVE' | 'ALL' | 'INACTIVE';\n\ntype CategoryRow = Readonly<\n Record<string, unknown> &\n ApprovalTemplateCategoryRecord & {\n key: string;\n updatedAtLabel: string;\n }\n>;\n\ntype CategoryModalState = Readonly<{\n record: ApprovalTemplateCategoryRecord | null;\n type: 'CREATE' | 'EDIT';\n}>;\n\ntype DeleteConfirmationState = Readonly<{\n id: string;\n name: string;\n}>;\n\n\nexport function TemplateCategoriesView(): ReactElement {\n const [categories, setCategories] = useState<\n readonly ApprovalTemplateCategoryRecord[]\n >([]);\n const [categoryPage, setCategoryPage] = useState(1);\n const [categoryPageSize, setCategoryPageSize] = useState(10);\n const [categoryStatus, setCategoryStatus] =\n useState<CategoryStatusTabKey>('ALL');\n const [categoryTotalCount, setCategoryTotalCount] = useState(0);\n const [deleteConfirmation, setDeleteConfirmation] =\n useState<DeleteConfirmationState | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [modalState, setModalState] = useState<CategoryModalState | null>(null);\n const [saving, setSaving] = useState(false);\n const [searchText, setSearchText] = useState('');\n\n const refreshCategories = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const categoryPageResult = await listApprovalTemplateCategoriesPage({\n page: categoryPage,\n pageSize: categoryPageSize,\n searchText,\n status: readCategoryStatus(categoryStatus),\n });\n\n setCategories(categoryPageResult.categories);\n setCategoryTotalCount(categoryPageResult.totalCount);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [categoryPage, categoryPageSize, categoryStatus, searchText]);\n\n useEffect((): void => {\n void refreshCategories();\n }, [refreshCategories]);\n\n const rows = useMemo(\n (): CategoryRow[] =>\n categories.map((category) => ({\n ...category,\n key: category.id,\n updatedAtLabel: formatDateTime(category.updatedAt),\n })),\n [categories],\n );\n\n const columns = useMemo(\n (): TableColumn<CategoryRow>[] => [\n { dataIndex: 'name', key: 'name', title: '分類名稱', width: 180 },\n {\n key: 'status',\n render: (record: CategoryRow): ReactElement => (\n <CategoryStatusBadge isActive={record.isActive} />\n ),\n title: '狀態',\n width: 120,\n },\n {\n dataIndex: 'sortOrder',\n key: 'sortOrder',\n title: '排序',\n width: 100,\n },\n {\n key: 'description',\n render: (record: CategoryRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {record.description || '無'}\n </Typography>\n ),\n title: '說明',\n width: 260,\n },\n {\n dataIndex: 'updatedAtLabel',\n key: 'updatedAtLabel',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n\n async function handleSaveCategory(input: CategoryFormInput): Promise<void> {\n setSaving(true);\n setError(null);\n\n try {\n if (modalState?.type === 'EDIT' && modalState.record) {\n await updateApprovalTemplateCategory({\n ...input,\n id: modalState.record.id,\n });\n } else {\n await createApprovalTemplateCategory(input);\n }\n\n setModalState(null);\n await refreshCategories();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n throw requestError;\n } finally {\n setSaving(false);\n }\n }\n\n async function handleToggleCategory(\n record: ApprovalTemplateCategoryRecord,\n ): Promise<void> {\n setSaving(true);\n setError(null);\n\n try {\n await updateApprovalTemplateCategory({\n description: record.description,\n id: record.id,\n isActive: !record.isActive,\n name: record.name,\n sortOrder: record.sortOrder,\n });\n await refreshCategories();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSaving(false);\n }\n }\n\n async function handleConfirmDelete(): Promise<void> {\n if (!deleteConfirmation) {\n return;\n }\n\n setSaving(true);\n setError(null);\n\n try {\n await deleteApprovalTemplateCategory(deleteConfirmation.id);\n setDeleteConfirmation(null);\n await refreshCategories();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSaving(false);\n }\n }\n\n const tableActions = useMemo(\n (): TableActions<CategoryRow> => ({\n render: (record): ReturnType<TableActions<CategoryRow>['render']> => [\n {\n name: '編輯',\n onClick: (): void => setModalState({ record, type: 'EDIT' }),\n },\n {\n name: record.isActive ? '停用' : '啟用',\n onClick: (): void => void handleToggleCategory(record),\n variant: record.isActive ? 'destructive-secondary' : 'base-secondary',\n },\n {\n name: '刪除',\n onClick: (): void =>\n setDeleteConfirmation({ id: record.id, name: record.name }),\n variant: 'destructive-secondary',\n },\n ],\n variant: 'base-secondary',\n width: 192,\n }),\n [refreshCategories],\n );\n\n return (\n <>\n <>\n <PageHeader>\n <ContentHeader\n description=\"維護簽核模板分類,供模板建立、篩選與列表標示使用。\"\n title=\"簽核模板分類\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void =>\n setModalState({ record: null, type: 'CREATE' })\n }\n variant=\"base-primary\"\n >\n 建立分類\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.templateFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"categorySearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setCategoryPage(1);\n }}\n placeholder=\"關鍵字:搜尋分類名稱或說明\"\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n tab={\n <Tab\n activeKey={categoryStatus}\n onChange={(activeKey): void => {\n setCategoryStatus(readCategoryStatusTabKey(activeKey));\n setCategoryPage(1);\n }}\n >\n {CATEGORY_STATUS_TABS.map((statusTab) => (\n <TabItem key={statusTab.key}>{statusTab.label}</TabItem>\n ))}\n </Tab>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading || saving}\n pagination={{\n current: categoryPage,\n onChange: (page): void => {\n setCategoryPage(page);\n },\n onChangePageSize: (pageSize): void => {\n setCategoryPage(1);\n setCategoryPageSize(pageSize);\n },\n pageSize: categoryPageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: CATEGORY_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: categoryTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n </>\n\n <CategoryModal\n loading={saving}\n modal={modalState}\n onClose={(): void => setModalState(null)}\n onSubmit={handleSaveCategory}\n />\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{ variant: 'destructive-primary' }}\n confirmText=\"刪除\"\n loading={saving}\n modalStatusType=\"error\"\n modalType=\"standard\"\n onCancel={(): void => setDeleteConfirmation(null)}\n onClose={(): void => setDeleteConfirmation(null)}\n onConfirm={(): void => void handleConfirmDelete()}\n open={Boolean(deleteConfirmation)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n supportingText=\"已被模板使用的分類無法刪除,請改用「停用」。\"\n title=\"刪除分類\"\n >\n <Typography color=\"text-neutral\" variant=\"body\">\n 確定要刪除「{deleteConfirmation?.name ?? ''}」嗎?\n </Typography>\n </Modal>\n </>\n );\n}\n\ninterface CategoryFormInput {\n readonly description: string | null;\n readonly isActive: boolean;\n readonly name: string;\n readonly sortOrder: number;\n}\n\nfunction CategoryModal({\n loading,\n modal,\n onClose,\n onSubmit,\n}: {\n readonly loading: boolean;\n readonly modal: CategoryModalState | null;\n readonly onClose: () => void;\n readonly onSubmit: (input: CategoryFormInput) => Promise<void>;\n}): ReactElement {\n const [description, setDescription] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [name, setName] = useState('');\n const [sortOrder, setSortOrder] = useState('0');\n\n useEffect((): void => {\n if (!modal) {\n return;\n }\n\n setDescription(modal.record?.description ?? '');\n setError(null);\n setName(modal.record?.name ?? '');\n setSortOrder(String(modal.record?.sortOrder ?? 0));\n }, [modal]);\n\n async function handleConfirm(): Promise<void> {\n const trimmedName = name.trim();\n const parsedSortOrder = Number(sortOrder);\n\n if (!trimmedName) {\n setError('請輸入分類名稱');\n return;\n }\n\n if (!Number.isInteger(parsedSortOrder)) {\n setError('排序必須是整數');\n return;\n }\n\n try {\n await onSubmit({\n description: description.trim() || null,\n isActive: modal?.record?.isActive ?? true,\n name: trimmedName,\n sortOrder: parsedSortOrder,\n });\n } catch (submitError: unknown) {\n setError(readErrorMessage(submitError));\n }\n }\n\n return (\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{ disabled: !name.trim() }}\n confirmText={modal?.type === 'EDIT' ? '儲存' : '建立'}\n loading={loading}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void => void handleConfirm()}\n open={Boolean(modal)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={modal?.type === 'EDIT' ? '編輯分類' : '建立分類'}\n >\n <div className={styles.templateModalFields}>\n <BPMFormField label=\"分類名稱\" name=\"categoryName\" required>\n <Input\n autoFocus\n fullWidth\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setName(event.target.value);\n setError(null);\n }}\n placeholder=\"例如:行政管理\"\n value={name}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"排序\" name=\"categorySortOrder\">\n <Input\n fullWidth\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setSortOrder(event.target.value);\n setError(null);\n }}\n placeholder=\"0\"\n value={sortOrder}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"說明\" name=\"categoryDescription\">\n <Textarea\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void => {\n setDescription(event.target.value);\n setError(null);\n }}\n placeholder=\"補充分類用途\"\n value={description}\n />\n </BPMFormField>\n </div>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n </Modal>\n );\n}\n\nfunction CategoryStatusBadge({\n isActive,\n}: {\n readonly isActive: boolean;\n}): ReactElement {\n return isActive ? (\n <Badge size=\"sub\" text=\"啟用\" variant=\"dot-success\" />\n ) : (\n <Badge size=\"sub\" text=\"停用\" variant=\"dot-inactive\" />\n );\n}\n\nfunction readCategoryStatusTabKey(activeKey: Key): CategoryStatusTabKey {\n if (activeKey === 'ACTIVE' || activeKey === 'INACTIVE') {\n return activeKey;\n }\n\n return 'ALL';\n}\n\nfunction readCategoryStatus(\n status: CategoryStatusTabKey,\n): ApprovalTemplateCategoryStatus {\n return status;\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"categories-CyyqG6wG.cjs","names":["useState","useCallback","listApprovalTemplateCategoriesPage","useMemo","formatDateTime","Typography","updateApprovalTemplateCategory","createApprovalTemplateCategory","deleteApprovalTemplateCategory","_Fragment","PageHeader","ContentHeader","Button","PlusIcon","SectionGroup","Section","FilterArea","styles","FilterLine","Filter","FormField","FormFieldLayout","Input","Tab","TabItem","Table","Modal","BPMFormField","Textarea","Badge","require_rolldown_runtime","require_bpm_form_field","require_format_date_time","react","_mezzanine_ui_react","react_jsx_runtime","_mezzanine_ui_core_form","_mezzanine_ui_react_ContentHeader","_rytass_bpm_core_client_template","_mezzanine_ui_icons","templates_module_default","CATEGORY_PAGE_SIZE_OPTIONS","CATEGORY_STATUS_TABS","TemplateCategoriesView","categories","setCategories","categoryPage","setCategoryPage","categoryPageSize","setCategoryPageSize","categoryStatus","setCategoryStatus","categoryTotalCount","setCategoryTotalCount","deleteConfirmation","setDeleteConfirmation","error","setError","loading","setLoading","modalState","setModalState","saving","setSaving","searchText","setSearchText","refreshCategories","categoryPageResult","readCategoryStatus","requestError","readErrorMessage","rows","category","columns","CategoryStatusBadge","record","handleSaveCategory","input","handleToggleCategory","handleConfirmDelete","tableActions","event","readCategoryStatusTabKey","activeKey","statusTab","page","pageSize","from","to","total","CategoryModal","description","setDescription","name","setName","sortOrder","setSortOrder","modal","handleConfirm","trimmedName","parsedSortOrder","onSubmit","submitError","onClose","isActive","status"],"sources":["../../src/views/templates/templates.module.scss","../../src/views/templates/categories/TemplateCategoriesView.tsx"],"sourcesContent":[".templateFilterArea {\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\n.templateModalFields {\n display: grid;\n gap: 16px;\n}\n","'use client';\n\nimport type { ChangeEvent, Key, ReactElement } from 'react';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Tab,\n TabItem,\n Table,\n Textarea,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { PlusIcon } from '@mezzanine-ui/icons';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { formatDateTime } from '../../../lib/format-date-time';\nimport {\n ApprovalTemplateCategoryRecord,\n ApprovalTemplateCategoryStatus,\n createApprovalTemplateCategory,\n deleteApprovalTemplateCategory,\n listApprovalTemplateCategoriesPage,\n updateApprovalTemplateCategory,\n} from '@rytass/bpm-core-client/template';\nimport styles from '../templates.module.scss';\n\nconst CATEGORY_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst CATEGORY_STATUS_TABS: readonly {\n readonly key: CategoryStatusTabKey;\n readonly label: string;\n}[] = [\n { key: 'ALL', label: '全部' },\n { key: 'ACTIVE', label: '啟用' },\n { key: 'INACTIVE', label: '停用' },\n];\ntype CategoryStatusTabKey = 'ACTIVE' | 'ALL' | 'INACTIVE';\n\ntype CategoryRow = Readonly<\n Record<string, unknown> &\n ApprovalTemplateCategoryRecord & {\n key: string;\n updatedAtLabel: string;\n }\n>;\n\ntype CategoryModalState = Readonly<{\n record: ApprovalTemplateCategoryRecord | null;\n type: 'CREATE' | 'EDIT';\n}>;\n\ntype DeleteConfirmationState = Readonly<{\n id: string;\n name: string;\n}>;\n\n\nexport function TemplateCategoriesView(): ReactElement {\n const [categories, setCategories] = useState<\n readonly ApprovalTemplateCategoryRecord[]\n >([]);\n const [categoryPage, setCategoryPage] = useState(1);\n const [categoryPageSize, setCategoryPageSize] = useState(10);\n const [categoryStatus, setCategoryStatus] =\n useState<CategoryStatusTabKey>('ALL');\n const [categoryTotalCount, setCategoryTotalCount] = useState(0);\n const [deleteConfirmation, setDeleteConfirmation] =\n useState<DeleteConfirmationState | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [modalState, setModalState] = useState<CategoryModalState | null>(null);\n const [saving, setSaving] = useState(false);\n const [searchText, setSearchText] = useState('');\n\n const refreshCategories = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const categoryPageResult = await listApprovalTemplateCategoriesPage({\n page: categoryPage,\n pageSize: categoryPageSize,\n searchText,\n status: readCategoryStatus(categoryStatus),\n });\n\n setCategories(categoryPageResult.categories);\n setCategoryTotalCount(categoryPageResult.totalCount);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [categoryPage, categoryPageSize, categoryStatus, searchText]);\n\n useEffect((): void => {\n void refreshCategories();\n }, [refreshCategories]);\n\n const rows = useMemo(\n (): CategoryRow[] =>\n categories.map((category) => ({\n ...category,\n key: category.id,\n updatedAtLabel: formatDateTime(category.updatedAt),\n })),\n [categories],\n );\n\n const columns = useMemo(\n (): TableColumn<CategoryRow>[] => [\n { dataIndex: 'name', key: 'name', title: '分類名稱', width: 180 },\n {\n key: 'status',\n render: (record: CategoryRow): ReactElement => (\n <CategoryStatusBadge isActive={record.isActive} />\n ),\n title: '狀態',\n width: 120,\n },\n {\n dataIndex: 'sortOrder',\n key: 'sortOrder',\n title: '排序',\n width: 100,\n },\n {\n key: 'description',\n render: (record: CategoryRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {record.description || '無'}\n </Typography>\n ),\n title: '說明',\n width: 260,\n },\n {\n dataIndex: 'updatedAtLabel',\n key: 'updatedAtLabel',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n\n async function handleSaveCategory(input: CategoryFormInput): Promise<void> {\n setSaving(true);\n setError(null);\n\n try {\n if (modalState?.type === 'EDIT' && modalState.record) {\n await updateApprovalTemplateCategory({\n ...input,\n id: modalState.record.id,\n });\n } else {\n await createApprovalTemplateCategory(input);\n }\n\n setModalState(null);\n await refreshCategories();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n throw requestError;\n } finally {\n setSaving(false);\n }\n }\n\n async function handleToggleCategory(\n record: ApprovalTemplateCategoryRecord,\n ): Promise<void> {\n setSaving(true);\n setError(null);\n\n try {\n await updateApprovalTemplateCategory({\n description: record.description,\n id: record.id,\n isActive: !record.isActive,\n name: record.name,\n sortOrder: record.sortOrder,\n });\n await refreshCategories();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSaving(false);\n }\n }\n\n async function handleConfirmDelete(): Promise<void> {\n if (!deleteConfirmation) {\n return;\n }\n\n setSaving(true);\n setError(null);\n\n try {\n await deleteApprovalTemplateCategory(deleteConfirmation.id);\n setDeleteConfirmation(null);\n await refreshCategories();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSaving(false);\n }\n }\n\n const tableActions = useMemo(\n (): TableActions<CategoryRow> => ({\n render: (record): ReturnType<TableActions<CategoryRow>['render']> => [\n {\n name: '編輯',\n onClick: (): void => setModalState({ record, type: 'EDIT' }),\n },\n {\n name: record.isActive ? '停用' : '啟用',\n onClick: (): void => void handleToggleCategory(record),\n variant: record.isActive ? 'destructive-secondary' : 'base-secondary',\n },\n {\n name: '刪除',\n onClick: (): void =>\n setDeleteConfirmation({ id: record.id, name: record.name }),\n variant: 'destructive-secondary',\n },\n ],\n variant: 'base-secondary',\n width: 192,\n }),\n [refreshCategories],\n );\n\n return (\n <>\n <>\n <PageHeader>\n <ContentHeader\n description=\"維護簽核模板分類,供模板建立、篩選與列表標示使用。\"\n title=\"簽核模板分類\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void =>\n setModalState({ record: null, type: 'CREATE' })\n }\n variant=\"base-primary\"\n >\n 建立分類\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.templateFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"categorySearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setCategoryPage(1);\n }}\n placeholder=\"關鍵字:搜尋分類名稱或說明\"\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n tab={\n <Tab\n activeKey={categoryStatus}\n onChange={(activeKey): void => {\n setCategoryStatus(readCategoryStatusTabKey(activeKey));\n setCategoryPage(1);\n }}\n >\n {CATEGORY_STATUS_TABS.map((statusTab) => (\n <TabItem key={statusTab.key}>{statusTab.label}</TabItem>\n ))}\n </Tab>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading || saving}\n pagination={{\n current: categoryPage,\n onChange: (page): void => {\n setCategoryPage(page);\n },\n onChangePageSize: (pageSize): void => {\n setCategoryPage(1);\n setCategoryPageSize(pageSize);\n },\n pageSize: categoryPageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: CATEGORY_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: categoryTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n </>\n\n <CategoryModal\n loading={saving}\n modal={modalState}\n onClose={(): void => setModalState(null)}\n onSubmit={handleSaveCategory}\n />\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{ variant: 'destructive-primary' }}\n confirmText=\"刪除\"\n loading={saving}\n modalStatusType=\"error\"\n modalType=\"standard\"\n onCancel={(): void => setDeleteConfirmation(null)}\n onClose={(): void => setDeleteConfirmation(null)}\n onConfirm={(): void => void handleConfirmDelete()}\n open={Boolean(deleteConfirmation)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n supportingText=\"已被模板使用的分類無法刪除,請改用「停用」。\"\n title=\"刪除分類\"\n >\n <Typography color=\"text-neutral\" variant=\"body\">\n 確定要刪除「{deleteConfirmation?.name ?? ''}」嗎?\n </Typography>\n </Modal>\n </>\n );\n}\n\ninterface CategoryFormInput {\n readonly description: string | null;\n readonly isActive: boolean;\n readonly name: string;\n readonly sortOrder: number;\n}\n\nfunction CategoryModal({\n loading,\n modal,\n onClose,\n onSubmit,\n}: {\n readonly loading: boolean;\n readonly modal: CategoryModalState | null;\n readonly onClose: () => void;\n readonly onSubmit: (input: CategoryFormInput) => Promise<void>;\n}): ReactElement {\n const [description, setDescription] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [name, setName] = useState('');\n const [sortOrder, setSortOrder] = useState('0');\n\n useEffect((): void => {\n if (!modal) {\n return;\n }\n\n setDescription(modal.record?.description ?? '');\n setError(null);\n setName(modal.record?.name ?? '');\n setSortOrder(String(modal.record?.sortOrder ?? 0));\n }, [modal]);\n\n async function handleConfirm(): Promise<void> {\n const trimmedName = name.trim();\n const parsedSortOrder = Number(sortOrder);\n\n if (!trimmedName) {\n setError('請輸入分類名稱');\n return;\n }\n\n if (!Number.isInteger(parsedSortOrder)) {\n setError('排序必須是整數');\n return;\n }\n\n try {\n await onSubmit({\n description: description.trim() || null,\n isActive: modal?.record?.isActive ?? true,\n name: trimmedName,\n sortOrder: parsedSortOrder,\n });\n } catch (submitError: unknown) {\n setError(readErrorMessage(submitError));\n }\n }\n\n return (\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{ disabled: !name.trim() }}\n confirmText={modal?.type === 'EDIT' ? '儲存' : '建立'}\n loading={loading}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void => void handleConfirm()}\n open={Boolean(modal)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={modal?.type === 'EDIT' ? '編輯分類' : '建立分類'}\n >\n <div className={styles.templateModalFields}>\n <BPMFormField label=\"分類名稱\" name=\"categoryName\" required>\n <Input\n autoFocus\n fullWidth\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setName(event.target.value);\n setError(null);\n }}\n placeholder=\"例如:行政管理\"\n value={name}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"排序\" name=\"categorySortOrder\">\n <Input\n fullWidth\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setSortOrder(event.target.value);\n setError(null);\n }}\n placeholder=\"0\"\n value={sortOrder}\n variant=\"base\"\n />\n </BPMFormField>\n <BPMFormField label=\"說明\" name=\"categoryDescription\">\n <Textarea\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void => {\n setDescription(event.target.value);\n setError(null);\n }}\n placeholder=\"補充分類用途\"\n value={description}\n />\n </BPMFormField>\n </div>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n </Modal>\n );\n}\n\nfunction CategoryStatusBadge({\n isActive,\n}: {\n readonly isActive: boolean;\n}): ReactElement {\n return isActive ? (\n <Badge size=\"sub\" text=\"啟用\" variant=\"dot-success\" />\n ) : (\n <Badge size=\"sub\" text=\"停用\" variant=\"dot-inactive\" />\n );\n}\n\nfunction readCategoryStatusTabKey(activeKey: Key): CategoryStatusTabKey {\n if (activeKey === 'ACTIVE' || activeKey === 'INACTIVE') {\n return activeKey;\n }\n\n return 'ALL';\n}\n\nfunction readCategoryStatus(\n status: CategoryStatusTabKey,\n): ApprovalTemplateCategoryStatus {\n return status;\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
|
|
@@ -6,8 +6,8 @@ import { Badge as o, Button as s, Filter as c, FilterArea as l, FilterLine as u,
|
|
|
6
6
|
import { Fragment as S, jsx as C, jsxs as w } from "react/jsx-runtime";
|
|
7
7
|
import { FormFieldLayout as ee } from "@mezzanine-ui/core/form";
|
|
8
8
|
import te from "@mezzanine-ui/react/ContentHeader";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { createApprovalTemplateCategory as T, deleteApprovalTemplateCategory as E, listApprovalTemplateCategoriesPage as D, updateApprovalTemplateCategory as O } from "@rytass/bpm-core-client/template";
|
|
10
|
+
import { PlusIcon as k } from "@mezzanine-ui/icons";
|
|
11
11
|
import '../categories.css';var A = {
|
|
12
12
|
templateFilterArea: "bpm_templateFilterArea_nUL-R",
|
|
13
13
|
templateModalFields: "bpm_templateModalFields_hUxWp"
|
|
@@ -33,7 +33,7 @@ function N() {
|
|
|
33
33
|
let [e, o] = a([]), [b, N] = a(1), [F, I] = a(10), [L, R] = a("ALL"), [z, B] = a(0), [V, H] = a(null), [U, W] = a(null), [G, K] = a(!0), [q, J] = a(null), [Y, X] = a(!1), [Z, oe] = a(""), Q = n(async () => {
|
|
34
34
|
K(!0), W(null);
|
|
35
35
|
try {
|
|
36
|
-
let e = await
|
|
36
|
+
let e = await D({
|
|
37
37
|
page: b,
|
|
38
38
|
pageSize: F,
|
|
39
39
|
searchText: Z,
|
|
@@ -97,10 +97,10 @@ function N() {
|
|
|
97
97
|
async function le(e) {
|
|
98
98
|
X(!0), W(null);
|
|
99
99
|
try {
|
|
100
|
-
q?.type === "EDIT" && q.record ? await
|
|
100
|
+
q?.type === "EDIT" && q.record ? await O({
|
|
101
101
|
...e,
|
|
102
102
|
id: q.record.id
|
|
103
|
-
}) : await
|
|
103
|
+
}) : await T(e), J(null), await Q();
|
|
104
104
|
} catch (e) {
|
|
105
105
|
throw W(P(e)), e;
|
|
106
106
|
} finally {
|
|
@@ -110,7 +110,7 @@ function N() {
|
|
|
110
110
|
async function $(e) {
|
|
111
111
|
X(!0), W(null);
|
|
112
112
|
try {
|
|
113
|
-
await
|
|
113
|
+
await O({
|
|
114
114
|
description: e.description,
|
|
115
115
|
id: e.id,
|
|
116
116
|
isActive: !e.isActive,
|
|
@@ -127,7 +127,7 @@ function N() {
|
|
|
127
127
|
if (V) {
|
|
128
128
|
X(!0), W(null);
|
|
129
129
|
try {
|
|
130
|
-
await
|
|
130
|
+
await E(V.id), H(null), await Q();
|
|
131
131
|
} catch (e) {
|
|
132
132
|
W(P(e));
|
|
133
133
|
} finally {
|
|
@@ -166,7 +166,7 @@ function N() {
|
|
|
166
166
|
description: "維護簽核模板分類,供模板建立、篩選與列表標示使用。",
|
|
167
167
|
title: "簽核模板分類",
|
|
168
168
|
children: /* @__PURE__ */ C(s, {
|
|
169
|
-
icon:
|
|
169
|
+
icon: k,
|
|
170
170
|
iconType: "leading",
|
|
171
171
|
onClick: () => J({
|
|
172
172
|
record: null,
|
|
@@ -372,4 +372,4 @@ function P(e) {
|
|
|
372
372
|
}
|
|
373
373
|
export { A as n, N as t };
|
|
374
374
|
|
|
375
|
-
//# sourceMappingURL=categories-
|
|
375
|
+
//# sourceMappingURL=categories-f7E-RJEc.js.map
|