@rytass/bpm-core-react 0.21.2 → 0.21.3
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 +16 -0
- package/dist/chunks/{FormBuilderView-CGKkuVFi.cjs → FormBuilderView-Bq4TXdxF.cjs} +2 -2
- package/dist/chunks/{FormBuilderView-CGKkuVFi.cjs.map → FormBuilderView-Bq4TXdxF.cjs.map} +1 -1
- package/dist/chunks/{FormBuilderView-6KdApi-D.js → FormBuilderView-DNsFwZgk.js} +2 -2
- package/dist/chunks/{FormBuilderView-6KdApi-D.js.map → FormBuilderView-DNsFwZgk.js.map} +1 -1
- package/dist/chunks/{FormRendererView-BcQKUi1A.js → FormRendererView-BF8Ge0Zk.js} +178 -153
- package/dist/chunks/FormRendererView-BF8Ge0Zk.js.map +1 -0
- package/dist/chunks/FormRendererView-ZIfSRWPi.cjs +6 -0
- package/dist/chunks/FormRendererView-ZIfSRWPi.cjs.map +1 -0
- package/dist/chunks/admin-pickers-BjbkBpSJ.cjs.map +1 -1
- package/dist/chunks/admin-pickers-DfGxsjpp.js.map +1 -1
- package/dist/chunks/approval-instance-list-page-BI5fIXc-.js.map +1 -1
- package/dist/chunks/approval-instance-list-page-Cv5I1YPX.cjs.map +1 -1
- package/dist/chunks/auth-provider-4BeCw7cI.cjs.map +1 -1
- package/dist/chunks/auth-provider-C2b-5mGt.js.map +1 -1
- package/dist/chunks/categories-CyyqG6wG.cjs.map +1 -1
- package/dist/chunks/categories-f7E-RJEc.js.map +1 -1
- package/dist/chunks/{compose-M-GR6smM.js → compose-C_Y38ENa.js} +4 -4
- package/dist/chunks/{compose-M-GR6smM.js.map → compose-C_Y38ENa.js.map} +1 -1
- package/dist/chunks/{compose-CtWuunwB.cjs → compose-NHbyjV73.cjs} +2 -2
- package/dist/chunks/{compose-CtWuunwB.cjs.map → compose-NHbyjV73.cjs.map} +1 -1
- package/dist/chunks/dashboard-page-BoqNhjT_.js.map +1 -1
- package/dist/chunks/dashboard-page-D7YJ3udk.cjs.map +1 -1
- package/dist/chunks/delegations-ClRCwD1I.cjs.map +1 -1
- package/dist/chunks/delegations-CqND-Qtz.js.map +1 -1
- package/dist/chunks/delegations-D43VDSz1.cjs.map +1 -1
- package/dist/chunks/delegations-zisffLwk.js.map +1 -1
- package/dist/chunks/{designer-BnMeiMVe.js → designer-BRYIpeTC.js} +3 -3
- package/dist/chunks/{designer-BnMeiMVe.js.map → designer-BRYIpeTC.js.map} +1 -1
- package/dist/chunks/{designer-D6fCDq_q.cjs → designer-oDGvHWBJ.cjs} +2 -2
- package/dist/chunks/{designer-D6fCDq_q.cjs.map → designer-oDGvHWBJ.cjs.map} +1 -1
- package/dist/chunks/{detail-C5KrUC7s.cjs → detail-BLhZp1mO.cjs} +2 -2
- package/dist/chunks/detail-BLhZp1mO.cjs.map +1 -0
- package/dist/chunks/{detail-Dnc4PPWO.js → detail-CkRgfU7l.js} +2 -2
- package/dist/chunks/detail-CkRgfU7l.js.map +1 -0
- package/dist/chunks/login-D6cc3bo7.js.map +1 -1
- package/dist/chunks/login-uvVcltrS.cjs.map +1 -1
- package/dist/chunks/notifications-Bc4mgSds.cjs.map +1 -1
- package/dist/chunks/notifications-Cvme5Qbl.js.map +1 -1
- package/dist/chunks/orgs-B_2J2tLX.cjs.map +1 -1
- package/dist/chunks/orgs-DqxMds26.js.map +1 -1
- package/dist/chunks/users-BBtiZ9QQ.js.map +1 -1
- package/dist/chunks/users-EqSzDhuj.cjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/pages/instances/detail/index.cjs +1 -1
- package/dist/pages/instances/detail/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/forms/builder/index.cjs +1 -1
- package/dist/views/forms/builder/index.js +1 -1
- package/dist/views/forms/renderer/form-control-menu.d.cts +7 -0
- package/dist/views/forms/renderer/form-control-menu.d.ts +7 -0
- package/dist/views/forms/renderer/form-data-source-field.d.cts +12 -0
- package/dist/views/forms/renderer/form-data-source-field.d.ts +12 -0
- package/dist/views/forms/renderer/index.cjs +1 -1
- package/dist/views/forms/renderer/index.js +1 -1
- package/dist/views/instances/detail/index.cjs +1 -1
- package/dist/views/instances/detail/index.js +1 -1
- package/dist/views/instances/new/index.cjs +1 -1
- package/dist/views/instances/new/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/index.cjs +1 -1
- package/dist/views/templates/designer/index.js +1 -1
- package/package.json +3 -3
- package/dist/chunks/FormRendererView-B-xycC9S.cjs +0 -6
- package/dist/chunks/FormRendererView-B-xycC9S.cjs.map +0 -1
- package/dist/chunks/FormRendererView-BcQKUi1A.js.map +0 -1
- package/dist/chunks/detail-C5KrUC7s.cjs.map +0 -1
- package/dist/chunks/detail-Dnc4PPWO.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users-BBtiZ9QQ.js","names":["readErrorMessage","styles","_Fragment","styles","formatMemberLabel","MemberPicker","Fragment$1","ContentHeader","users_module_default","MemberTaskReassignModal","tasks","setTasks","useState","tasksLoading","setTasksLoading","target","setTarget","reason","setReason","preview","setPreview","committed","setCommitted","busy","setBusy","error","setError","trimmedReason","inputKey","previewIsCurrent","canConfirm","result","latestRequestRef","useRef","loadTasks","useCallback","request","loaded","listMemberOpenTasks","memberId","requestError","readErrorMessage$1","member","titleById","useMemo","task","runReassignment","outcomes","reassignMemberTasks","dryRun","shownResultRows","shownResults","shownTitleById","readOutcomeLabel","taskColumns","record","resultColumns","Modal","onClose","Typography","Table","BPMFormField","option","Input","event","Button","outcome","MEMBER_PAGE_SIZE_OPTIONS","AdminUsersView","detailMember","setDetailMember","detailMemberships","setDetailMemberships","detailManagerProfile","setDetailManagerProfile","detailResolvedManager","setDetailResolvedManager","inactiveMembers","setInactiveMembers","inactiveMembersError","setInactiveMembersError","loading","setLoading","memberPage","setMemberPage","memberPageSize","setMemberPageSize","memberTotalCount","setMemberTotalCount","members","setMembers","orgUnits","setOrgUnits","positions","setPositions","reassignMember","setReassignMember","searchText","setSearchText","orgUnitsById","orgUnit","positionsById","position","refreshMembers","memberPageResult","organization","listMemberDirectoryPage","readOrganizationDashboard","readErrorMessage","latestInactiveRequestRef","refreshInactiveMembers","listInactiveMembersWithOpenTasks","inactiveMemberRows","inactiveMemberColumns","inactiveMemberActions","rows","openDetail","memberships","resolvedManager","listMemberships","readResolvedManager","resolveMembers","columns","tableActions","closeDetail","PageHeader","SectionGroup","Section","FilterArea","FilterLine","Filter","FormField","FormFieldLayout","page","pageSize","from","to","total","MemberDetailModal","BaseCard","readOrgUnitLabel","membership","readPositionLabel","readMemberLabel","managerProfile"],"sources":["../../src/views/admin/users/users.module.scss","../../src/views/admin/users/MemberTaskReassignModal.tsx","../../src/views/admin/users/AdminUsersView.tsx"],"sourcesContent":[".memberFilterArea {\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 :global(.mzn-input),\n :global(.mzn-input-container),\n :global(.mzn-text-field) {\n width: 100%;\n min-width: 0 !important;\n }\n}\n\n.header {\n display: grid;\n gap: 4px;\n padding: 24px 24px 0;\n}\n\n.detailFields {\n display: grid;\n gap: 16px;\n}\n\n.detailSection {\n display: grid;\n gap: 8px;\n}\n\n.membershipList {\n display: grid;\n gap: 8px;\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { Button, Input, Modal, Table, Typography } from '@mezzanine-ui/react';\nimport type { TableColumn } from '@mezzanine-ui/core/table';\nimport type { MemberProfileRecord } from '@rytass/bpm-core-client';\nimport {\n listMemberOpenTasks,\n type MemberOpenTaskRecord,\n reassignMemberTasks,\n type TaskReassignmentResultRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { MemberOption, MemberPicker } from '../../../components/admin-pickers';\nimport styles from './users.module.scss';\n\ntype TaskRow = Readonly<\n Record<string, unknown> &\n MemberOpenTaskRecord & {\n key: string;\n }\n>;\n\ntype ResultRow = Readonly<\n Record<string, unknown> & {\n instanceTitle: string;\n key: string;\n message: string | null;\n outcomeLabel: string;\n }\n>;\n\ninterface PreviewState {\n readonly inputKey: string;\n readonly results: readonly TaskReassignmentResultRecord[];\n}\n\n/**\n * A committed run keeps the titles it was started with: the task list reloads\n * right after, and a member whose every task moved no longer lists any of them.\n */\ninterface CommittedState {\n readonly results: readonly TaskReassignmentResultRecord[];\n readonly titleById: ReadonlyMap<string, string>;\n}\n\n/**\n * Administrator reassignment of a member's open tasks. Lists what the member\n * holds, takes a target and a reason, previews every task's outcome (dry run),\n * and only then commits. Confirm stays disabled until the preview matches the\n * current target and reason. Replacing a seat is not a decision: no signature\n * is written, and the task keeps its id.\n */\nexport function MemberTaskReassignModal({\n member,\n onClose,\n}: {\n readonly member: MemberProfileRecord | null;\n readonly onClose: () => void;\n}): ReactElement {\n const [tasks, setTasks] = useState<readonly MemberOpenTaskRecord[]>([]);\n const [tasksLoading, setTasksLoading] = useState(false);\n const [target, setTarget] = useState<MemberOption | null>(null);\n const [reason, setReason] = useState('');\n const [preview, setPreview] = useState<PreviewState | null>(null);\n const [committed, setCommitted] = useState<CommittedState | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const trimmedReason = reason.trim();\n const inputKey = `${target?.id ?? ''}|${trimmedReason}`;\n const previewIsCurrent = preview !== null && preview.inputKey === inputKey;\n const canConfirm =\n preview !== null &&\n previewIsCurrent &&\n preview.results.some((result) => result.outcome === 'WOULD_REASSIGN');\n\n // Only the latest request may write: switching members while an earlier\n // listing is in flight must not let its late answer replace the current one.\n const latestRequestRef = useRef(0);\n\n const loadTasks = useCallback(async (memberId: string): Promise<void> => {\n const request = latestRequestRef.current + 1;\n\n latestRequestRef.current = request;\n setTasksLoading(true);\n\n try {\n const loaded = await listMemberOpenTasks(memberId);\n\n if (latestRequestRef.current === request) {\n setTasks(loaded);\n }\n } catch (requestError: unknown) {\n if (latestRequestRef.current === request) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (latestRequestRef.current === request) {\n setTasksLoading(false);\n }\n }\n }, []);\n\n useEffect((): void => {\n setTarget(null);\n setReason('');\n setPreview(null);\n setCommitted(null);\n setError(null);\n\n if (!member) {\n latestRequestRef.current += 1;\n setTasks([]);\n setTasksLoading(false);\n\n return;\n }\n\n setTasks([]);\n void loadTasks(member.memberId);\n }, [member, loadTasks]);\n\n const titleById = useMemo(\n (): ReadonlyMap<string, string> =>\n new Map(tasks.map((task) => [task.taskId, task.instanceTitle])),\n [tasks],\n );\n\n async function runReassignment(dryRun: boolean): Promise<void> {\n if (!member || !target || !trimmedReason) {\n return;\n }\n\n setBusy(true);\n setError(null);\n\n try {\n const outcomes = await reassignMemberTasks({\n dryRun,\n fromMemberId: member.memberId,\n reason: trimmedReason,\n toMemberId: target.id,\n });\n\n if (dryRun) {\n setPreview({ inputKey, results: outcomes });\n setCommitted(null);\n } else {\n setCommitted({ results: outcomes, titleById });\n setPreview(null);\n await loadTasks(member.memberId);\n }\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setBusy(false);\n }\n }\n\n const shownResultRows = useMemo((): ResultRow[] => {\n const shownResults = committed?.results ?? preview?.results ?? [];\n const shownTitleById = committed?.titleById ?? titleById;\n\n return shownResults.map((result) => ({\n instanceTitle: shownTitleById.get(result.taskId) ?? result.taskId,\n key: result.taskId,\n message: result.message,\n outcomeLabel: readOutcomeLabel(result.outcome),\n }));\n }, [committed, preview, titleById]);\n\n const taskColumns = useMemo(\n (): TableColumn<TaskRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'nodeLabel',\n key: 'nodeLabel',\n title: '節點',\n width: 160,\n },\n {\n key: 'memberRole',\n render: (record: TaskRow): string =>\n record.memberRole === 'ASSIGNEE' ? '指派人' : '會簽候選人',\n title: '身分',\n width: 120,\n },\n ],\n [],\n );\n const resultColumns = useMemo(\n (): TableColumn<ResultRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'outcomeLabel',\n key: 'outcomeLabel',\n title: '結果',\n width: 100,\n },\n {\n dataIndex: 'message',\n key: 'message',\n title: '說明',\n width: 160,\n },\n ],\n [],\n );\n\n return (\n <Modal\n cancelText=\"關閉\"\n confirmButtonProps={{ disabled: !canConfirm || busy }}\n confirmText=\"確認改派\"\n loading={busy}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void => {\n void runReassignment(false);\n }}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member ? `改派待辦:${member.name}` : '改派待辦'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <Typography variant=\"body\">\n 改派會保留任務編號,但不產生簽核紀錄;原簽核人的待辦會結案為已轉交,\n 接手人會收到新的待辦通知。\n </Typography>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {tasks.length ? (\n <Table\n columns={taskColumns}\n dataSource={tasks.map((task): TaskRow => ({\n ...task,\n key: task.taskId,\n }))}\n fullWidth\n loading={tasksLoading}\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n {tasksLoading ? '載入待辦中…' : '此成員目前沒有待簽任務。'}\n </Typography>\n )}\n <BPMFormField label=\"接手人\" name=\"reassignTarget\">\n <MemberPicker\n name=\"reassignTarget\"\n onChange={(option): void => {\n setTarget(option);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"搜尋接手人姓名或信箱\"\n value={target}\n />\n </BPMFormField>\n <BPMFormField label=\"改派原因\" name=\"reassignReason\">\n <Input\n fullWidth\n name=\"reassignReason\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setReason(event.target.value);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"例如:原簽核人已離職\"\n value={reason}\n />\n </BPMFormField>\n <div className={styles.membershipList}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 先按「預覽」確認每筆任務的結果,確認無誤後再按「確認改派」。\n </Typography>\n <div>\n <Button\n disabled={\n busy || !target || !trimmedReason || tasks.length === 0\n }\n onClick={(): void => {\n void runReassignment(true);\n }}\n variant=\"base-secondary\"\n >\n 預覽\n </Button>\n </div>\n </div>\n {shownResultRows.length ? (\n <Table\n columns={resultColumns}\n dataSource={shownResultRows}\n fullWidth\n />\n ) : null}\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOutcomeLabel(\n outcome: TaskReassignmentResultRecord['outcome'],\n): string {\n if (outcome === 'WOULD_REASSIGN') {\n return '會改派';\n }\n\n if (outcome === 'REASSIGNED') {\n return '已改派';\n }\n\n return '會被拒';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '改派待辦失敗。';\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n BaseCard,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { formatMemberLabel } from '../../../lib/format-member-label';\nimport styles from './users.module.scss';\nimport { MemberTaskReassignModal } from './MemberTaskReassignModal';\nimport {\n listMemberDirectoryPage,\n MemberProfileRecord,\n resolveMembers,\n} from '@rytass/bpm-core-client';\nimport {\n listMemberships,\n MembershipRecord,\n OrgUnitRecord,\n PositionRecord,\n readOrganizationDashboard,\n readResolvedManager,\n ResolvedManagerRecord,\n} from '@rytass/bpm-core-client/organization';\nimport {\n type InactiveMemberWithOpenTasksRecord,\n listInactiveMembersWithOpenTasks,\n} from '@rytass/bpm-core-client/workflow';\n\ntype MemberRow = Readonly<\n Record<string, unknown> &\n MemberProfileRecord & {\n key: string;\n }\n>;\n\ntype InactiveMemberRow = Readonly<\n Record<string, unknown> &\n InactiveMemberWithOpenTasksRecord & {\n key: string;\n }\n>;\n\nconst MEMBER_PAGE_SIZE_OPTIONS = [10, 20, 50];\n\nexport function AdminUsersView(): ReactElement {\n const [detailMember, setDetailMember] = useState<MemberProfileRecord | null>(\n null,\n );\n const [detailMemberships, setDetailMemberships] = useState<\n readonly MembershipRecord[]\n >([]);\n const [detailManagerProfile, setDetailManagerProfile] =\n useState<MemberProfileRecord | null>(null);\n const [detailResolvedManager, setDetailResolvedManager] =\n useState<ResolvedManagerRecord | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [inactiveMembers, setInactiveMembers] = useState<\n readonly InactiveMemberWithOpenTasksRecord[]\n >([]);\n const [inactiveMembersError, setInactiveMembersError] = useState<\n string | null\n >(null);\n const [loading, setLoading] = useState(true);\n const [memberPage, setMemberPage] = useState(1);\n const [memberPageSize, setMemberPageSize] = useState(10);\n const [memberTotalCount, setMemberTotalCount] = useState(0);\n const [members, setMembers] = useState<readonly MemberProfileRecord[]>([]);\n const [orgUnits, setOrgUnits] = useState<readonly OrgUnitRecord[]>([]);\n const [positions, setPositions] = useState<readonly PositionRecord[]>([]);\n const [reassignMember, setReassignMember] =\n useState<MemberProfileRecord | null>(null);\n const [searchText, setSearchText] = useState('');\n\n const orgUnitsById = useMemo(\n (): ReadonlyMap<string, OrgUnitRecord> =>\n new Map(orgUnits.map((orgUnit) => [orgUnit.id, orgUnit])),\n [orgUnits],\n );\n const positionsById = useMemo(\n (): ReadonlyMap<string, PositionRecord> =>\n new Map(positions.map((position) => [position.id, position])),\n [positions],\n );\n\n const refreshMembers = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const [memberPageResult, organization] = await Promise.all([\n listMemberDirectoryPage({\n page: memberPage,\n pageSize: memberPageSize,\n searchText,\n }),\n readOrganizationDashboard(),\n ]);\n\n setMembers(memberPageResult.members);\n setMemberTotalCount(memberPageResult.totalCount);\n setOrgUnits(organization.orgUnits);\n setPositions(organization.positions);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [memberPage, memberPageSize, searchText]);\n\n useEffect((): void => {\n void refreshMembers();\n }, [refreshMembers]);\n\n const latestInactiveRequestRef = useRef(0);\n\n // Loaded on its own so a failure here leaves the member directory usable.\n // Only the latest request may write: a reload started when the reassignment\n // closes must not be overwritten by an earlier one answering late.\n const refreshInactiveMembers = useCallback(async (): Promise<void> => {\n const request = latestInactiveRequestRef.current + 1;\n\n latestInactiveRequestRef.current = request;\n\n try {\n const loaded = await listInactiveMembersWithOpenTasks();\n\n if (latestInactiveRequestRef.current === request) {\n setInactiveMembers(loaded);\n setInactiveMembersError(null);\n }\n } catch (requestError: unknown) {\n if (latestInactiveRequestRef.current === request) {\n setInactiveMembersError(readErrorMessage(requestError));\n }\n }\n }, []);\n\n useEffect((): void => {\n void refreshInactiveMembers();\n }, [refreshInactiveMembers]);\n\n const inactiveMemberRows = useMemo(\n (): InactiveMemberRow[] =>\n inactiveMembers.map(\n (member): InactiveMemberRow => ({ ...member, key: member.memberId }),\n ),\n [inactiveMembers],\n );\n const inactiveMemberColumns = useMemo(\n (): TableColumn<InactiveMemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n {\n dataIndex: 'openTaskCount',\n key: 'openTaskCount',\n title: '待簽數',\n width: 96,\n },\n ],\n [],\n );\n const inactiveMemberActions = useMemo(\n (): TableActions<InactiveMemberRow> => ({\n render: (): ReturnType<TableActions<InactiveMemberRow>['render']> => [\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember({\n customFieldsJson: '{}',\n email: record.email,\n memberId: record.memberId,\n name: record.name,\n });\n },\n },\n ],\n variant: 'base-secondary',\n width: 112,\n }),\n [],\n );\n\n const rows = useMemo(\n (): MemberRow[] =>\n members.map((member) => ({\n ...member,\n key: member.memberId,\n })),\n [members],\n );\n\n const openDetail = useCallback(\n async (member: MemberProfileRecord): Promise<void> => {\n setDetailMember(member);\n setDetailManagerProfile(null);\n setError(null);\n\n try {\n const [memberships, resolvedManager] = await Promise.all([\n listMemberships({ memberId: member.memberId }),\n readResolvedManager(member.memberId),\n ]);\n\n setDetailMemberships(memberships);\n setDetailResolvedManager(resolvedManager);\n setDetailManagerProfile(\n (\n await resolveMembers(\n resolvedManager.managerMemberId\n ? [resolvedManager.managerMemberId]\n : [],\n )\n )[0] ?? null,\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n }\n },\n [],\n );\n\n const columns = useMemo(\n (): TableColumn<MemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<MemberRow> => ({\n render: (): ReturnType<TableActions<MemberRow>['render']> => [\n {\n name: '檢視',\n onClick: (record): void => {\n void openDetail(record);\n },\n },\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember(record);\n },\n },\n ],\n variant: 'base-secondary',\n width: 176,\n }),\n [openDetail],\n );\n\n function closeDetail(): void {\n setDetailMember(null);\n setDetailManagerProfile(null);\n setDetailMemberships([]);\n setDetailResolvedManager(null);\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"會員資料由 host member resolver 提供,BPM 僅維護組織歸屬與主管解析。\"\n title=\"會員對照\"\n />\n </PageHeader>\n\n <SectionGroup>\n {inactiveMemberRows.length || inactiveMembersError ? (\n <Section\n contentHeader={\n <ContentHeader\n description=\"這些會員已停用,身上仍有待簽,請改派給在職的人。\"\n title=\"已停用、仍有待簽的會員\"\n />\n }\n >\n <div data-inactive-members=\"\">\n {inactiveMembersError ? (\n <Typography color=\"text-error\" variant=\"body\">\n {inactiveMembersError}\n </Typography>\n ) : (\n <Table\n actions={inactiveMemberActions}\n columns={inactiveMemberColumns}\n dataSource={inactiveMemberRows}\n fullWidth\n />\n )}\n </div>\n </Section>\n ) : null}\n <Section\n filterArea={\n <FilterArea className={styles.memberFilterArea}>\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"memberSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setMemberPage(1);\n }}\n placeholder=\"搜尋姓名或信箱\"\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n pagination={{\n current: memberPage,\n onChange: (page): void => {\n setMemberPage(page);\n },\n onChangePageSize: (pageSize): void => {\n setMemberPage(1);\n setMemberPageSize(pageSize);\n },\n pageSize: memberPageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: MEMBER_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: memberTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n\n <MemberTaskReassignModal\n member={reassignMember}\n onClose={(): void => {\n setReassignMember(null);\n // A reassignment may have cleared someone off the list.\n void refreshInactiveMembers();\n }}\n />\n\n <MemberDetailModal\n managerProfile={detailManagerProfile}\n member={detailMember}\n memberships={detailMemberships}\n onClose={closeDetail}\n orgUnitsById={orgUnitsById}\n positionsById={positionsById}\n resolvedManager={detailResolvedManager}\n />\n </>\n );\n}\n\nfunction MemberDetailModal({\n managerProfile,\n member,\n memberships,\n onClose,\n orgUnitsById,\n positionsById,\n resolvedManager,\n}: {\n readonly managerProfile: MemberProfileRecord | null;\n readonly member: MemberProfileRecord | null;\n readonly memberships: readonly MembershipRecord[];\n readonly onClose: () => void;\n readonly orgUnitsById: ReadonlyMap<string, OrgUnitRecord>;\n readonly positionsById: ReadonlyMap<string, PositionRecord>;\n readonly resolvedManager: ResolvedManagerRecord | null;\n}): ReactElement {\n return (\n <Modal\n cancelText=\"關閉\"\n confirmText=\"關閉\"\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={onClose}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member?.name ?? '會員明細'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <BaseCard title=\"基本資料\">\n <div className={styles.detailSection}>\n <Typography variant=\"body\">\n 信箱:{member.email?.trim() ? member.email : '未設定'}\n </Typography>\n </div>\n </BaseCard>\n <BaseCard title=\"BPM 組織歸屬\">\n <div className={styles.membershipList}>\n {memberships.length ? (\n memberships.map((membership) => (\n <Typography key={membership.id} variant=\"body\">\n {readOrgUnitLabel(orgUnitsById.get(membership.orgUnitId))}\n {' / '}\n {membership.positionId\n ? readPositionLabel(\n positionsById.get(membership.positionId),\n )\n : '未指定職位'}\n {' / '}\n {membership.isPrimary ? '主要' : '一般'}\n </Typography>\n ))\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 尚未建立 BPM 組織歸屬\n </Typography>\n )}\n </div>\n </BaseCard>\n <BaseCard title=\"主管解析\">\n <Typography variant=\"body\">\n {resolvedManager?.managerMemberId\n ? readMemberLabel(managerProfile)\n : '尚未解析到主管'}\n </Typography>\n </BaseCard>\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOrgUnitLabel(orgUnit: OrgUnitRecord | undefined): string {\n return orgUnit ? `${orgUnit.name} · ${orgUnit.code}` : '未知組織';\n}\n\nfunction readPositionLabel(position: PositionRecord | undefined): string {\n return position ? `${position.name} · ${position.code}` : '未知職位';\n}\n\nfunction readMemberLabel(member: MemberProfileRecord | null): string {\n return member\n ? formatMemberLabel(member.name, member.email, 'dot')\n : '主管資料尚未載入';\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":"users-BBtiZ9QQ.js","names":["readErrorMessage","styles","_Fragment","styles","formatMemberLabel","MemberPicker","Fragment$1","ContentHeader","users_module_default","MemberTaskReassignModal","tasks","setTasks","useState","tasksLoading","setTasksLoading","target","setTarget","reason","setReason","preview","setPreview","committed","setCommitted","busy","setBusy","error","setError","trimmedReason","inputKey","previewIsCurrent","canConfirm","result","latestRequestRef","useRef","loadTasks","useCallback","request","loaded","listMemberOpenTasks","memberId","requestError","readErrorMessage$1","member","titleById","useMemo","task","runReassignment","outcomes","reassignMemberTasks","dryRun","shownResultRows","shownResults","shownTitleById","readOutcomeLabel","taskColumns","record","resultColumns","Modal","onClose","Typography","Table","BPMFormField","option","Input","event","Button","outcome","MEMBER_PAGE_SIZE_OPTIONS","AdminUsersView","detailMember","setDetailMember","detailMemberships","setDetailMemberships","detailManagerProfile","setDetailManagerProfile","detailResolvedManager","setDetailResolvedManager","inactiveMembers","setInactiveMembers","inactiveMembersError","setInactiveMembersError","loading","setLoading","memberPage","setMemberPage","memberPageSize","setMemberPageSize","memberTotalCount","setMemberTotalCount","members","setMembers","orgUnits","setOrgUnits","positions","setPositions","reassignMember","setReassignMember","searchText","setSearchText","orgUnitsById","orgUnit","positionsById","position","refreshMembers","memberPageResult","organization","listMemberDirectoryPage","readOrganizationDashboard","readErrorMessage","latestInactiveRequestRef","refreshInactiveMembers","listInactiveMembersWithOpenTasks","inactiveMemberRows","inactiveMemberColumns","inactiveMemberActions","rows","openDetail","memberships","resolvedManager","listMemberships","readResolvedManager","resolveMembers","columns","tableActions","closeDetail","PageHeader","SectionGroup","Section","FilterArea","FilterLine","Filter","FormField","FormFieldLayout","page","pageSize","from","to","total","MemberDetailModal","BaseCard","readOrgUnitLabel","membership","readPositionLabel","readMemberLabel","managerProfile"],"sources":["../../src/views/admin/users/MemberTaskReassignModal.tsx","../../src/views/admin/users/AdminUsersView.tsx"],"sourcesContent":["'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { Button, Input, Modal, Table, Typography } from '@mezzanine-ui/react';\nimport type { TableColumn } from '@mezzanine-ui/core/table';\nimport type { MemberProfileRecord } from '@rytass/bpm-core-client';\nimport {\n listMemberOpenTasks,\n type MemberOpenTaskRecord,\n reassignMemberTasks,\n type TaskReassignmentResultRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { MemberOption, MemberPicker } from '../../../components/admin-pickers';\nimport styles from './users.module.scss';\n\ntype TaskRow = Readonly<\n Record<string, unknown> &\n MemberOpenTaskRecord & {\n key: string;\n }\n>;\n\ntype ResultRow = Readonly<\n Record<string, unknown> & {\n instanceTitle: string;\n key: string;\n message: string | null;\n outcomeLabel: string;\n }\n>;\n\ninterface PreviewState {\n readonly inputKey: string;\n readonly results: readonly TaskReassignmentResultRecord[];\n}\n\n/**\n * A committed run keeps the titles it was started with: the task list reloads\n * right after, and a member whose every task moved no longer lists any of them.\n */\ninterface CommittedState {\n readonly results: readonly TaskReassignmentResultRecord[];\n readonly titleById: ReadonlyMap<string, string>;\n}\n\n/**\n * Administrator reassignment of a member's open tasks. Lists what the member\n * holds, takes a target and a reason, previews every task's outcome (dry run),\n * and only then commits. Confirm stays disabled until the preview matches the\n * current target and reason. Replacing a seat is not a decision: no signature\n * is written, and the task keeps its id.\n */\nexport function MemberTaskReassignModal({\n member,\n onClose,\n}: {\n readonly member: MemberProfileRecord | null;\n readonly onClose: () => void;\n}): ReactElement {\n const [tasks, setTasks] = useState<readonly MemberOpenTaskRecord[]>([]);\n const [tasksLoading, setTasksLoading] = useState(false);\n const [target, setTarget] = useState<MemberOption | null>(null);\n const [reason, setReason] = useState('');\n const [preview, setPreview] = useState<PreviewState | null>(null);\n const [committed, setCommitted] = useState<CommittedState | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const trimmedReason = reason.trim();\n const inputKey = `${target?.id ?? ''}|${trimmedReason}`;\n const previewIsCurrent = preview !== null && preview.inputKey === inputKey;\n const canConfirm =\n preview !== null &&\n previewIsCurrent &&\n preview.results.some((result) => result.outcome === 'WOULD_REASSIGN');\n\n // Only the latest request may write: switching members while an earlier\n // listing is in flight must not let its late answer replace the current one.\n const latestRequestRef = useRef(0);\n\n const loadTasks = useCallback(async (memberId: string): Promise<void> => {\n const request = latestRequestRef.current + 1;\n\n latestRequestRef.current = request;\n setTasksLoading(true);\n\n try {\n const loaded = await listMemberOpenTasks(memberId);\n\n if (latestRequestRef.current === request) {\n setTasks(loaded);\n }\n } catch (requestError: unknown) {\n if (latestRequestRef.current === request) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (latestRequestRef.current === request) {\n setTasksLoading(false);\n }\n }\n }, []);\n\n useEffect((): void => {\n setTarget(null);\n setReason('');\n setPreview(null);\n setCommitted(null);\n setError(null);\n\n if (!member) {\n latestRequestRef.current += 1;\n setTasks([]);\n setTasksLoading(false);\n\n return;\n }\n\n setTasks([]);\n void loadTasks(member.memberId);\n }, [member, loadTasks]);\n\n const titleById = useMemo(\n (): ReadonlyMap<string, string> =>\n new Map(tasks.map((task) => [task.taskId, task.instanceTitle])),\n [tasks],\n );\n\n async function runReassignment(dryRun: boolean): Promise<void> {\n if (!member || !target || !trimmedReason) {\n return;\n }\n\n setBusy(true);\n setError(null);\n\n try {\n const outcomes = await reassignMemberTasks({\n dryRun,\n fromMemberId: member.memberId,\n reason: trimmedReason,\n toMemberId: target.id,\n });\n\n if (dryRun) {\n setPreview({ inputKey, results: outcomes });\n setCommitted(null);\n } else {\n setCommitted({ results: outcomes, titleById });\n setPreview(null);\n await loadTasks(member.memberId);\n }\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setBusy(false);\n }\n }\n\n const shownResultRows = useMemo((): ResultRow[] => {\n const shownResults = committed?.results ?? preview?.results ?? [];\n const shownTitleById = committed?.titleById ?? titleById;\n\n return shownResults.map((result) => ({\n instanceTitle: shownTitleById.get(result.taskId) ?? result.taskId,\n key: result.taskId,\n message: result.message,\n outcomeLabel: readOutcomeLabel(result.outcome),\n }));\n }, [committed, preview, titleById]);\n\n const taskColumns = useMemo(\n (): TableColumn<TaskRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'nodeLabel',\n key: 'nodeLabel',\n title: '節點',\n width: 160,\n },\n {\n key: 'memberRole',\n render: (record: TaskRow): string =>\n record.memberRole === 'ASSIGNEE' ? '指派人' : '會簽候選人',\n title: '身分',\n width: 120,\n },\n ],\n [],\n );\n const resultColumns = useMemo(\n (): TableColumn<ResultRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'outcomeLabel',\n key: 'outcomeLabel',\n title: '結果',\n width: 100,\n },\n {\n dataIndex: 'message',\n key: 'message',\n title: '說明',\n width: 160,\n },\n ],\n [],\n );\n\n return (\n <Modal\n cancelText=\"關閉\"\n confirmButtonProps={{ disabled: !canConfirm || busy }}\n confirmText=\"確認改派\"\n loading={busy}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void => {\n void runReassignment(false);\n }}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member ? `改派待辦:${member.name}` : '改派待辦'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <Typography variant=\"body\">\n 改派會保留任務編號,但不產生簽核紀錄;原簽核人的待辦會結案為已轉交,\n 接手人會收到新的待辦通知。\n </Typography>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {tasks.length ? (\n <Table\n columns={taskColumns}\n dataSource={tasks.map((task): TaskRow => ({\n ...task,\n key: task.taskId,\n }))}\n fullWidth\n loading={tasksLoading}\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n {tasksLoading ? '載入待辦中…' : '此成員目前沒有待簽任務。'}\n </Typography>\n )}\n <BPMFormField label=\"接手人\" name=\"reassignTarget\">\n <MemberPicker\n name=\"reassignTarget\"\n onChange={(option): void => {\n setTarget(option);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"搜尋接手人姓名或信箱\"\n value={target}\n />\n </BPMFormField>\n <BPMFormField label=\"改派原因\" name=\"reassignReason\">\n <Input\n fullWidth\n name=\"reassignReason\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setReason(event.target.value);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"例如:原簽核人已離職\"\n value={reason}\n />\n </BPMFormField>\n <div className={styles.membershipList}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 先按「預覽」確認每筆任務的結果,確認無誤後再按「確認改派」。\n </Typography>\n <div>\n <Button\n disabled={\n busy || !target || !trimmedReason || tasks.length === 0\n }\n onClick={(): void => {\n void runReassignment(true);\n }}\n variant=\"base-secondary\"\n >\n 預覽\n </Button>\n </div>\n </div>\n {shownResultRows.length ? (\n <Table\n columns={resultColumns}\n dataSource={shownResultRows}\n fullWidth\n />\n ) : null}\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOutcomeLabel(\n outcome: TaskReassignmentResultRecord['outcome'],\n): string {\n if (outcome === 'WOULD_REASSIGN') {\n return '會改派';\n }\n\n if (outcome === 'REASSIGNED') {\n return '已改派';\n }\n\n return '會被拒';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '改派待辦失敗。';\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n BaseCard,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { formatMemberLabel } from '../../../lib/format-member-label';\nimport styles from './users.module.scss';\nimport { MemberTaskReassignModal } from './MemberTaskReassignModal';\nimport {\n listMemberDirectoryPage,\n MemberProfileRecord,\n resolveMembers,\n} from '@rytass/bpm-core-client';\nimport {\n listMemberships,\n MembershipRecord,\n OrgUnitRecord,\n PositionRecord,\n readOrganizationDashboard,\n readResolvedManager,\n ResolvedManagerRecord,\n} from '@rytass/bpm-core-client/organization';\nimport {\n type InactiveMemberWithOpenTasksRecord,\n listInactiveMembersWithOpenTasks,\n} from '@rytass/bpm-core-client/workflow';\n\ntype MemberRow = Readonly<\n Record<string, unknown> &\n MemberProfileRecord & {\n key: string;\n }\n>;\n\ntype InactiveMemberRow = Readonly<\n Record<string, unknown> &\n InactiveMemberWithOpenTasksRecord & {\n key: string;\n }\n>;\n\nconst MEMBER_PAGE_SIZE_OPTIONS = [10, 20, 50];\n\nexport function AdminUsersView(): ReactElement {\n const [detailMember, setDetailMember] = useState<MemberProfileRecord | null>(\n null,\n );\n const [detailMemberships, setDetailMemberships] = useState<\n readonly MembershipRecord[]\n >([]);\n const [detailManagerProfile, setDetailManagerProfile] =\n useState<MemberProfileRecord | null>(null);\n const [detailResolvedManager, setDetailResolvedManager] =\n useState<ResolvedManagerRecord | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [inactiveMembers, setInactiveMembers] = useState<\n readonly InactiveMemberWithOpenTasksRecord[]\n >([]);\n const [inactiveMembersError, setInactiveMembersError] = useState<\n string | null\n >(null);\n const [loading, setLoading] = useState(true);\n const [memberPage, setMemberPage] = useState(1);\n const [memberPageSize, setMemberPageSize] = useState(10);\n const [memberTotalCount, setMemberTotalCount] = useState(0);\n const [members, setMembers] = useState<readonly MemberProfileRecord[]>([]);\n const [orgUnits, setOrgUnits] = useState<readonly OrgUnitRecord[]>([]);\n const [positions, setPositions] = useState<readonly PositionRecord[]>([]);\n const [reassignMember, setReassignMember] =\n useState<MemberProfileRecord | null>(null);\n const [searchText, setSearchText] = useState('');\n\n const orgUnitsById = useMemo(\n (): ReadonlyMap<string, OrgUnitRecord> =>\n new Map(orgUnits.map((orgUnit) => [orgUnit.id, orgUnit])),\n [orgUnits],\n );\n const positionsById = useMemo(\n (): ReadonlyMap<string, PositionRecord> =>\n new Map(positions.map((position) => [position.id, position])),\n [positions],\n );\n\n const refreshMembers = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const [memberPageResult, organization] = await Promise.all([\n listMemberDirectoryPage({\n page: memberPage,\n pageSize: memberPageSize,\n searchText,\n }),\n readOrganizationDashboard(),\n ]);\n\n setMembers(memberPageResult.members);\n setMemberTotalCount(memberPageResult.totalCount);\n setOrgUnits(organization.orgUnits);\n setPositions(organization.positions);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [memberPage, memberPageSize, searchText]);\n\n useEffect((): void => {\n void refreshMembers();\n }, [refreshMembers]);\n\n const latestInactiveRequestRef = useRef(0);\n\n // Loaded on its own so a failure here leaves the member directory usable.\n // Only the latest request may write: a reload started when the reassignment\n // closes must not be overwritten by an earlier one answering late.\n const refreshInactiveMembers = useCallback(async (): Promise<void> => {\n const request = latestInactiveRequestRef.current + 1;\n\n latestInactiveRequestRef.current = request;\n\n try {\n const loaded = await listInactiveMembersWithOpenTasks();\n\n if (latestInactiveRequestRef.current === request) {\n setInactiveMembers(loaded);\n setInactiveMembersError(null);\n }\n } catch (requestError: unknown) {\n if (latestInactiveRequestRef.current === request) {\n setInactiveMembersError(readErrorMessage(requestError));\n }\n }\n }, []);\n\n useEffect((): void => {\n void refreshInactiveMembers();\n }, [refreshInactiveMembers]);\n\n const inactiveMemberRows = useMemo(\n (): InactiveMemberRow[] =>\n inactiveMembers.map(\n (member): InactiveMemberRow => ({ ...member, key: member.memberId }),\n ),\n [inactiveMembers],\n );\n const inactiveMemberColumns = useMemo(\n (): TableColumn<InactiveMemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n {\n dataIndex: 'openTaskCount',\n key: 'openTaskCount',\n title: '待簽數',\n width: 96,\n },\n ],\n [],\n );\n const inactiveMemberActions = useMemo(\n (): TableActions<InactiveMemberRow> => ({\n render: (): ReturnType<TableActions<InactiveMemberRow>['render']> => [\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember({\n customFieldsJson: '{}',\n email: record.email,\n memberId: record.memberId,\n name: record.name,\n });\n },\n },\n ],\n variant: 'base-secondary',\n width: 112,\n }),\n [],\n );\n\n const rows = useMemo(\n (): MemberRow[] =>\n members.map((member) => ({\n ...member,\n key: member.memberId,\n })),\n [members],\n );\n\n const openDetail = useCallback(\n async (member: MemberProfileRecord): Promise<void> => {\n setDetailMember(member);\n setDetailManagerProfile(null);\n setError(null);\n\n try {\n const [memberships, resolvedManager] = await Promise.all([\n listMemberships({ memberId: member.memberId }),\n readResolvedManager(member.memberId),\n ]);\n\n setDetailMemberships(memberships);\n setDetailResolvedManager(resolvedManager);\n setDetailManagerProfile(\n (\n await resolveMembers(\n resolvedManager.managerMemberId\n ? [resolvedManager.managerMemberId]\n : [],\n )\n )[0] ?? null,\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n }\n },\n [],\n );\n\n const columns = useMemo(\n (): TableColumn<MemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<MemberRow> => ({\n render: (): ReturnType<TableActions<MemberRow>['render']> => [\n {\n name: '檢視',\n onClick: (record): void => {\n void openDetail(record);\n },\n },\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember(record);\n },\n },\n ],\n variant: 'base-secondary',\n width: 176,\n }),\n [openDetail],\n );\n\n function closeDetail(): void {\n setDetailMember(null);\n setDetailManagerProfile(null);\n setDetailMemberships([]);\n setDetailResolvedManager(null);\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"會員資料由 host member resolver 提供,BPM 僅維護組織歸屬與主管解析。\"\n title=\"會員對照\"\n />\n </PageHeader>\n\n <SectionGroup>\n {inactiveMemberRows.length || inactiveMembersError ? (\n <Section\n contentHeader={\n <ContentHeader\n description=\"這些會員已停用,身上仍有待簽,請改派給在職的人。\"\n title=\"已停用、仍有待簽的會員\"\n />\n }\n >\n <div data-inactive-members=\"\">\n {inactiveMembersError ? (\n <Typography color=\"text-error\" variant=\"body\">\n {inactiveMembersError}\n </Typography>\n ) : (\n <Table\n actions={inactiveMemberActions}\n columns={inactiveMemberColumns}\n dataSource={inactiveMemberRows}\n fullWidth\n />\n )}\n </div>\n </Section>\n ) : null}\n <Section\n filterArea={\n <FilterArea className={styles.memberFilterArea}>\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"memberSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setMemberPage(1);\n }}\n placeholder=\"搜尋姓名或信箱\"\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n pagination={{\n current: memberPage,\n onChange: (page): void => {\n setMemberPage(page);\n },\n onChangePageSize: (pageSize): void => {\n setMemberPage(1);\n setMemberPageSize(pageSize);\n },\n pageSize: memberPageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: MEMBER_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: memberTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n\n <MemberTaskReassignModal\n member={reassignMember}\n onClose={(): void => {\n setReassignMember(null);\n // A reassignment may have cleared someone off the list.\n void refreshInactiveMembers();\n }}\n />\n\n <MemberDetailModal\n managerProfile={detailManagerProfile}\n member={detailMember}\n memberships={detailMemberships}\n onClose={closeDetail}\n orgUnitsById={orgUnitsById}\n positionsById={positionsById}\n resolvedManager={detailResolvedManager}\n />\n </>\n );\n}\n\nfunction MemberDetailModal({\n managerProfile,\n member,\n memberships,\n onClose,\n orgUnitsById,\n positionsById,\n resolvedManager,\n}: {\n readonly managerProfile: MemberProfileRecord | null;\n readonly member: MemberProfileRecord | null;\n readonly memberships: readonly MembershipRecord[];\n readonly onClose: () => void;\n readonly orgUnitsById: ReadonlyMap<string, OrgUnitRecord>;\n readonly positionsById: ReadonlyMap<string, PositionRecord>;\n readonly resolvedManager: ResolvedManagerRecord | null;\n}): ReactElement {\n return (\n <Modal\n cancelText=\"關閉\"\n confirmText=\"關閉\"\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={onClose}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member?.name ?? '會員明細'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <BaseCard title=\"基本資料\">\n <div className={styles.detailSection}>\n <Typography variant=\"body\">\n 信箱:{member.email?.trim() ? member.email : '未設定'}\n </Typography>\n </div>\n </BaseCard>\n <BaseCard title=\"BPM 組織歸屬\">\n <div className={styles.membershipList}>\n {memberships.length ? (\n memberships.map((membership) => (\n <Typography key={membership.id} variant=\"body\">\n {readOrgUnitLabel(orgUnitsById.get(membership.orgUnitId))}\n {' / '}\n {membership.positionId\n ? readPositionLabel(\n positionsById.get(membership.positionId),\n )\n : '未指定職位'}\n {' / '}\n {membership.isPrimary ? '主要' : '一般'}\n </Typography>\n ))\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 尚未建立 BPM 組織歸屬\n </Typography>\n )}\n </div>\n </BaseCard>\n <BaseCard title=\"主管解析\">\n <Typography variant=\"body\">\n {resolvedManager?.managerMemberId\n ? readMemberLabel(managerProfile)\n : '尚未解析到主管'}\n </Typography>\n </BaseCard>\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOrgUnitLabel(orgUnit: OrgUnitRecord | undefined): string {\n return orgUnit ? `${orgUnit.name} · ${orgUnit.code}` : '未知組織';\n}\n\nfunction readPositionLabel(position: PositionRecord | undefined): string {\n return position ? `${position.name} · ${position.code}` : '未知職位';\n}\n\nfunction readMemberLabel(member: MemberProfileRecord | null): string {\n return member\n ? formatMemberLabel(member.name, member.email, 'dot')\n : '主管資料尚未載入';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '讀取會員資料失敗。';\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users-EqSzDhuj.cjs","names":["useState","useRef","useCallback","listMemberOpenTasks","readErrorMessage","useMemo","reassignMemberTasks","Modal","styles","Typography","Table","BPMFormField","MemberPicker","Input","Button","useState","useMemo","useCallback","listMemberDirectoryPage","readOrganizationDashboard","useRef","listInactiveMembersWithOpenTasks","listMemberships","readResolvedManager","resolveMembers","_Fragment","PageHeader","ContentHeader","SectionGroup","Section","Typography","Table","FilterArea","styles","FilterLine","Filter","FormField","FormFieldLayout","Input","Modal","BaseCard","formatMemberLabel","require_rolldown_runtime","require_format_member_label","require_bpm_form_field","require_admin_pickers","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_organization","users_module_default","MemberTaskReassignModal","tasks","setTasks","tasksLoading","setTasksLoading","target","setTarget","reason","setReason","preview","setPreview","committed","setCommitted","busy","setBusy","error","setError","trimmedReason","inputKey","previewIsCurrent","canConfirm","result","latestRequestRef","loadTasks","request","loaded","memberId","requestError","readErrorMessage$1","member","titleById","task","runReassignment","outcomes","dryRun","shownResultRows","shownResults","shownTitleById","readOutcomeLabel","taskColumns","record","resultColumns","onClose","option","event","outcome","MEMBER_PAGE_SIZE_OPTIONS","AdminUsersView","detailMember","setDetailMember","detailMemberships","setDetailMemberships","detailManagerProfile","setDetailManagerProfile","detailResolvedManager","setDetailResolvedManager","inactiveMembers","setInactiveMembers","inactiveMembersError","setInactiveMembersError","loading","setLoading","memberPage","setMemberPage","memberPageSize","setMemberPageSize","memberTotalCount","setMemberTotalCount","members","setMembers","orgUnits","setOrgUnits","positions","setPositions","reassignMember","setReassignMember","searchText","setSearchText","orgUnitsById","orgUnit","positionsById","position","refreshMembers","memberPageResult","organization","readErrorMessage","latestInactiveRequestRef","refreshInactiveMembers","inactiveMemberRows","inactiveMemberColumns","inactiveMemberActions","rows","openDetail","memberships","resolvedManager","columns","tableActions","closeDetail","page","pageSize","from","to","total","MemberDetailModal","readOrgUnitLabel","membership","readPositionLabel","readMemberLabel","managerProfile"],"sources":["../../src/views/admin/users/users.module.scss","../../src/views/admin/users/MemberTaskReassignModal.tsx","../../src/views/admin/users/AdminUsersView.tsx"],"sourcesContent":[".memberFilterArea {\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 :global(.mzn-input),\n :global(.mzn-input-container),\n :global(.mzn-text-field) {\n width: 100%;\n min-width: 0 !important;\n }\n}\n\n.header {\n display: grid;\n gap: 4px;\n padding: 24px 24px 0;\n}\n\n.detailFields {\n display: grid;\n gap: 16px;\n}\n\n.detailSection {\n display: grid;\n gap: 8px;\n}\n\n.membershipList {\n display: grid;\n gap: 8px;\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { Button, Input, Modal, Table, Typography } from '@mezzanine-ui/react';\nimport type { TableColumn } from '@mezzanine-ui/core/table';\nimport type { MemberProfileRecord } from '@rytass/bpm-core-client';\nimport {\n listMemberOpenTasks,\n type MemberOpenTaskRecord,\n reassignMemberTasks,\n type TaskReassignmentResultRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { MemberOption, MemberPicker } from '../../../components/admin-pickers';\nimport styles from './users.module.scss';\n\ntype TaskRow = Readonly<\n Record<string, unknown> &\n MemberOpenTaskRecord & {\n key: string;\n }\n>;\n\ntype ResultRow = Readonly<\n Record<string, unknown> & {\n instanceTitle: string;\n key: string;\n message: string | null;\n outcomeLabel: string;\n }\n>;\n\ninterface PreviewState {\n readonly inputKey: string;\n readonly results: readonly TaskReassignmentResultRecord[];\n}\n\n/**\n * A committed run keeps the titles it was started with: the task list reloads\n * right after, and a member whose every task moved no longer lists any of them.\n */\ninterface CommittedState {\n readonly results: readonly TaskReassignmentResultRecord[];\n readonly titleById: ReadonlyMap<string, string>;\n}\n\n/**\n * Administrator reassignment of a member's open tasks. Lists what the member\n * holds, takes a target and a reason, previews every task's outcome (dry run),\n * and only then commits. Confirm stays disabled until the preview matches the\n * current target and reason. Replacing a seat is not a decision: no signature\n * is written, and the task keeps its id.\n */\nexport function MemberTaskReassignModal({\n member,\n onClose,\n}: {\n readonly member: MemberProfileRecord | null;\n readonly onClose: () => void;\n}): ReactElement {\n const [tasks, setTasks] = useState<readonly MemberOpenTaskRecord[]>([]);\n const [tasksLoading, setTasksLoading] = useState(false);\n const [target, setTarget] = useState<MemberOption | null>(null);\n const [reason, setReason] = useState('');\n const [preview, setPreview] = useState<PreviewState | null>(null);\n const [committed, setCommitted] = useState<CommittedState | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const trimmedReason = reason.trim();\n const inputKey = `${target?.id ?? ''}|${trimmedReason}`;\n const previewIsCurrent = preview !== null && preview.inputKey === inputKey;\n const canConfirm =\n preview !== null &&\n previewIsCurrent &&\n preview.results.some((result) => result.outcome === 'WOULD_REASSIGN');\n\n // Only the latest request may write: switching members while an earlier\n // listing is in flight must not let its late answer replace the current one.\n const latestRequestRef = useRef(0);\n\n const loadTasks = useCallback(async (memberId: string): Promise<void> => {\n const request = latestRequestRef.current + 1;\n\n latestRequestRef.current = request;\n setTasksLoading(true);\n\n try {\n const loaded = await listMemberOpenTasks(memberId);\n\n if (latestRequestRef.current === request) {\n setTasks(loaded);\n }\n } catch (requestError: unknown) {\n if (latestRequestRef.current === request) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (latestRequestRef.current === request) {\n setTasksLoading(false);\n }\n }\n }, []);\n\n useEffect((): void => {\n setTarget(null);\n setReason('');\n setPreview(null);\n setCommitted(null);\n setError(null);\n\n if (!member) {\n latestRequestRef.current += 1;\n setTasks([]);\n setTasksLoading(false);\n\n return;\n }\n\n setTasks([]);\n void loadTasks(member.memberId);\n }, [member, loadTasks]);\n\n const titleById = useMemo(\n (): ReadonlyMap<string, string> =>\n new Map(tasks.map((task) => [task.taskId, task.instanceTitle])),\n [tasks],\n );\n\n async function runReassignment(dryRun: boolean): Promise<void> {\n if (!member || !target || !trimmedReason) {\n return;\n }\n\n setBusy(true);\n setError(null);\n\n try {\n const outcomes = await reassignMemberTasks({\n dryRun,\n fromMemberId: member.memberId,\n reason: trimmedReason,\n toMemberId: target.id,\n });\n\n if (dryRun) {\n setPreview({ inputKey, results: outcomes });\n setCommitted(null);\n } else {\n setCommitted({ results: outcomes, titleById });\n setPreview(null);\n await loadTasks(member.memberId);\n }\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setBusy(false);\n }\n }\n\n const shownResultRows = useMemo((): ResultRow[] => {\n const shownResults = committed?.results ?? preview?.results ?? [];\n const shownTitleById = committed?.titleById ?? titleById;\n\n return shownResults.map((result) => ({\n instanceTitle: shownTitleById.get(result.taskId) ?? result.taskId,\n key: result.taskId,\n message: result.message,\n outcomeLabel: readOutcomeLabel(result.outcome),\n }));\n }, [committed, preview, titleById]);\n\n const taskColumns = useMemo(\n (): TableColumn<TaskRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'nodeLabel',\n key: 'nodeLabel',\n title: '節點',\n width: 160,\n },\n {\n key: 'memberRole',\n render: (record: TaskRow): string =>\n record.memberRole === 'ASSIGNEE' ? '指派人' : '會簽候選人',\n title: '身分',\n width: 120,\n },\n ],\n [],\n );\n const resultColumns = useMemo(\n (): TableColumn<ResultRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'outcomeLabel',\n key: 'outcomeLabel',\n title: '結果',\n width: 100,\n },\n {\n dataIndex: 'message',\n key: 'message',\n title: '說明',\n width: 160,\n },\n ],\n [],\n );\n\n return (\n <Modal\n cancelText=\"關閉\"\n confirmButtonProps={{ disabled: !canConfirm || busy }}\n confirmText=\"確認改派\"\n loading={busy}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void => {\n void runReassignment(false);\n }}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member ? `改派待辦:${member.name}` : '改派待辦'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <Typography variant=\"body\">\n 改派會保留任務編號,但不產生簽核紀錄;原簽核人的待辦會結案為已轉交,\n 接手人會收到新的待辦通知。\n </Typography>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {tasks.length ? (\n <Table\n columns={taskColumns}\n dataSource={tasks.map((task): TaskRow => ({\n ...task,\n key: task.taskId,\n }))}\n fullWidth\n loading={tasksLoading}\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n {tasksLoading ? '載入待辦中…' : '此成員目前沒有待簽任務。'}\n </Typography>\n )}\n <BPMFormField label=\"接手人\" name=\"reassignTarget\">\n <MemberPicker\n name=\"reassignTarget\"\n onChange={(option): void => {\n setTarget(option);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"搜尋接手人姓名或信箱\"\n value={target}\n />\n </BPMFormField>\n <BPMFormField label=\"改派原因\" name=\"reassignReason\">\n <Input\n fullWidth\n name=\"reassignReason\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setReason(event.target.value);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"例如:原簽核人已離職\"\n value={reason}\n />\n </BPMFormField>\n <div className={styles.membershipList}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 先按「預覽」確認每筆任務的結果,確認無誤後再按「確認改派」。\n </Typography>\n <div>\n <Button\n disabled={\n busy || !target || !trimmedReason || tasks.length === 0\n }\n onClick={(): void => {\n void runReassignment(true);\n }}\n variant=\"base-secondary\"\n >\n 預覽\n </Button>\n </div>\n </div>\n {shownResultRows.length ? (\n <Table\n columns={resultColumns}\n dataSource={shownResultRows}\n fullWidth\n />\n ) : null}\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOutcomeLabel(\n outcome: TaskReassignmentResultRecord['outcome'],\n): string {\n if (outcome === 'WOULD_REASSIGN') {\n return '會改派';\n }\n\n if (outcome === 'REASSIGNED') {\n return '已改派';\n }\n\n return '會被拒';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '改派待辦失敗。';\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n BaseCard,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { formatMemberLabel } from '../../../lib/format-member-label';\nimport styles from './users.module.scss';\nimport { MemberTaskReassignModal } from './MemberTaskReassignModal';\nimport {\n listMemberDirectoryPage,\n MemberProfileRecord,\n resolveMembers,\n} from '@rytass/bpm-core-client';\nimport {\n listMemberships,\n MembershipRecord,\n OrgUnitRecord,\n PositionRecord,\n readOrganizationDashboard,\n readResolvedManager,\n ResolvedManagerRecord,\n} from '@rytass/bpm-core-client/organization';\nimport {\n type InactiveMemberWithOpenTasksRecord,\n listInactiveMembersWithOpenTasks,\n} from '@rytass/bpm-core-client/workflow';\n\ntype MemberRow = Readonly<\n Record<string, unknown> &\n MemberProfileRecord & {\n key: string;\n }\n>;\n\ntype InactiveMemberRow = Readonly<\n Record<string, unknown> &\n InactiveMemberWithOpenTasksRecord & {\n key: string;\n }\n>;\n\nconst MEMBER_PAGE_SIZE_OPTIONS = [10, 20, 50];\n\nexport function AdminUsersView(): ReactElement {\n const [detailMember, setDetailMember] = useState<MemberProfileRecord | null>(\n null,\n );\n const [detailMemberships, setDetailMemberships] = useState<\n readonly MembershipRecord[]\n >([]);\n const [detailManagerProfile, setDetailManagerProfile] =\n useState<MemberProfileRecord | null>(null);\n const [detailResolvedManager, setDetailResolvedManager] =\n useState<ResolvedManagerRecord | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [inactiveMembers, setInactiveMembers] = useState<\n readonly InactiveMemberWithOpenTasksRecord[]\n >([]);\n const [inactiveMembersError, setInactiveMembersError] = useState<\n string | null\n >(null);\n const [loading, setLoading] = useState(true);\n const [memberPage, setMemberPage] = useState(1);\n const [memberPageSize, setMemberPageSize] = useState(10);\n const [memberTotalCount, setMemberTotalCount] = useState(0);\n const [members, setMembers] = useState<readonly MemberProfileRecord[]>([]);\n const [orgUnits, setOrgUnits] = useState<readonly OrgUnitRecord[]>([]);\n const [positions, setPositions] = useState<readonly PositionRecord[]>([]);\n const [reassignMember, setReassignMember] =\n useState<MemberProfileRecord | null>(null);\n const [searchText, setSearchText] = useState('');\n\n const orgUnitsById = useMemo(\n (): ReadonlyMap<string, OrgUnitRecord> =>\n new Map(orgUnits.map((orgUnit) => [orgUnit.id, orgUnit])),\n [orgUnits],\n );\n const positionsById = useMemo(\n (): ReadonlyMap<string, PositionRecord> =>\n new Map(positions.map((position) => [position.id, position])),\n [positions],\n );\n\n const refreshMembers = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const [memberPageResult, organization] = await Promise.all([\n listMemberDirectoryPage({\n page: memberPage,\n pageSize: memberPageSize,\n searchText,\n }),\n readOrganizationDashboard(),\n ]);\n\n setMembers(memberPageResult.members);\n setMemberTotalCount(memberPageResult.totalCount);\n setOrgUnits(organization.orgUnits);\n setPositions(organization.positions);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [memberPage, memberPageSize, searchText]);\n\n useEffect((): void => {\n void refreshMembers();\n }, [refreshMembers]);\n\n const latestInactiveRequestRef = useRef(0);\n\n // Loaded on its own so a failure here leaves the member directory usable.\n // Only the latest request may write: a reload started when the reassignment\n // closes must not be overwritten by an earlier one answering late.\n const refreshInactiveMembers = useCallback(async (): Promise<void> => {\n const request = latestInactiveRequestRef.current + 1;\n\n latestInactiveRequestRef.current = request;\n\n try {\n const loaded = await listInactiveMembersWithOpenTasks();\n\n if (latestInactiveRequestRef.current === request) {\n setInactiveMembers(loaded);\n setInactiveMembersError(null);\n }\n } catch (requestError: unknown) {\n if (latestInactiveRequestRef.current === request) {\n setInactiveMembersError(readErrorMessage(requestError));\n }\n }\n }, []);\n\n useEffect((): void => {\n void refreshInactiveMembers();\n }, [refreshInactiveMembers]);\n\n const inactiveMemberRows = useMemo(\n (): InactiveMemberRow[] =>\n inactiveMembers.map(\n (member): InactiveMemberRow => ({ ...member, key: member.memberId }),\n ),\n [inactiveMembers],\n );\n const inactiveMemberColumns = useMemo(\n (): TableColumn<InactiveMemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n {\n dataIndex: 'openTaskCount',\n key: 'openTaskCount',\n title: '待簽數',\n width: 96,\n },\n ],\n [],\n );\n const inactiveMemberActions = useMemo(\n (): TableActions<InactiveMemberRow> => ({\n render: (): ReturnType<TableActions<InactiveMemberRow>['render']> => [\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember({\n customFieldsJson: '{}',\n email: record.email,\n memberId: record.memberId,\n name: record.name,\n });\n },\n },\n ],\n variant: 'base-secondary',\n width: 112,\n }),\n [],\n );\n\n const rows = useMemo(\n (): MemberRow[] =>\n members.map((member) => ({\n ...member,\n key: member.memberId,\n })),\n [members],\n );\n\n const openDetail = useCallback(\n async (member: MemberProfileRecord): Promise<void> => {\n setDetailMember(member);\n setDetailManagerProfile(null);\n setError(null);\n\n try {\n const [memberships, resolvedManager] = await Promise.all([\n listMemberships({ memberId: member.memberId }),\n readResolvedManager(member.memberId),\n ]);\n\n setDetailMemberships(memberships);\n setDetailResolvedManager(resolvedManager);\n setDetailManagerProfile(\n (\n await resolveMembers(\n resolvedManager.managerMemberId\n ? [resolvedManager.managerMemberId]\n : [],\n )\n )[0] ?? null,\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n }\n },\n [],\n );\n\n const columns = useMemo(\n (): TableColumn<MemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<MemberRow> => ({\n render: (): ReturnType<TableActions<MemberRow>['render']> => [\n {\n name: '檢視',\n onClick: (record): void => {\n void openDetail(record);\n },\n },\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember(record);\n },\n },\n ],\n variant: 'base-secondary',\n width: 176,\n }),\n [openDetail],\n );\n\n function closeDetail(): void {\n setDetailMember(null);\n setDetailManagerProfile(null);\n setDetailMemberships([]);\n setDetailResolvedManager(null);\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"會員資料由 host member resolver 提供,BPM 僅維護組織歸屬與主管解析。\"\n title=\"會員對照\"\n />\n </PageHeader>\n\n <SectionGroup>\n {inactiveMemberRows.length || inactiveMembersError ? (\n <Section\n contentHeader={\n <ContentHeader\n description=\"這些會員已停用,身上仍有待簽,請改派給在職的人。\"\n title=\"已停用、仍有待簽的會員\"\n />\n }\n >\n <div data-inactive-members=\"\">\n {inactiveMembersError ? (\n <Typography color=\"text-error\" variant=\"body\">\n {inactiveMembersError}\n </Typography>\n ) : (\n <Table\n actions={inactiveMemberActions}\n columns={inactiveMemberColumns}\n dataSource={inactiveMemberRows}\n fullWidth\n />\n )}\n </div>\n </Section>\n ) : null}\n <Section\n filterArea={\n <FilterArea className={styles.memberFilterArea}>\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"memberSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setMemberPage(1);\n }}\n placeholder=\"搜尋姓名或信箱\"\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n pagination={{\n current: memberPage,\n onChange: (page): void => {\n setMemberPage(page);\n },\n onChangePageSize: (pageSize): void => {\n setMemberPage(1);\n setMemberPageSize(pageSize);\n },\n pageSize: memberPageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: MEMBER_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: memberTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n\n <MemberTaskReassignModal\n member={reassignMember}\n onClose={(): void => {\n setReassignMember(null);\n // A reassignment may have cleared someone off the list.\n void refreshInactiveMembers();\n }}\n />\n\n <MemberDetailModal\n managerProfile={detailManagerProfile}\n member={detailMember}\n memberships={detailMemberships}\n onClose={closeDetail}\n orgUnitsById={orgUnitsById}\n positionsById={positionsById}\n resolvedManager={detailResolvedManager}\n />\n </>\n );\n}\n\nfunction MemberDetailModal({\n managerProfile,\n member,\n memberships,\n onClose,\n orgUnitsById,\n positionsById,\n resolvedManager,\n}: {\n readonly managerProfile: MemberProfileRecord | null;\n readonly member: MemberProfileRecord | null;\n readonly memberships: readonly MembershipRecord[];\n readonly onClose: () => void;\n readonly orgUnitsById: ReadonlyMap<string, OrgUnitRecord>;\n readonly positionsById: ReadonlyMap<string, PositionRecord>;\n readonly resolvedManager: ResolvedManagerRecord | null;\n}): ReactElement {\n return (\n <Modal\n cancelText=\"關閉\"\n confirmText=\"關閉\"\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={onClose}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member?.name ?? '會員明細'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <BaseCard title=\"基本資料\">\n <div className={styles.detailSection}>\n <Typography variant=\"body\">\n 信箱:{member.email?.trim() ? member.email : '未設定'}\n </Typography>\n </div>\n </BaseCard>\n <BaseCard title=\"BPM 組織歸屬\">\n <div className={styles.membershipList}>\n {memberships.length ? (\n memberships.map((membership) => (\n <Typography key={membership.id} variant=\"body\">\n {readOrgUnitLabel(orgUnitsById.get(membership.orgUnitId))}\n {' / '}\n {membership.positionId\n ? readPositionLabel(\n positionsById.get(membership.positionId),\n )\n : '未指定職位'}\n {' / '}\n {membership.isPrimary ? '主要' : '一般'}\n </Typography>\n ))\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 尚未建立 BPM 組織歸屬\n </Typography>\n )}\n </div>\n </BaseCard>\n <BaseCard title=\"主管解析\">\n <Typography variant=\"body\">\n {resolvedManager?.managerMemberId\n ? readMemberLabel(managerProfile)\n : '尚未解析到主管'}\n </Typography>\n </BaseCard>\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOrgUnitLabel(orgUnit: OrgUnitRecord | undefined): string {\n return orgUnit ? `${orgUnit.name} · ${orgUnit.code}` : '未知組織';\n}\n\nfunction readPositionLabel(position: PositionRecord | undefined): string {\n return position ? `${position.name} · ${position.code}` : '未知職位';\n}\n\nfunction readMemberLabel(member: MemberProfileRecord | null): string {\n return member\n ? formatMemberLabel(member.name, member.email, 'dot')\n : '主管資料尚未載入';\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":"users-EqSzDhuj.cjs","names":["useState","useRef","useCallback","listMemberOpenTasks","readErrorMessage","useMemo","reassignMemberTasks","Modal","styles","Typography","Table","BPMFormField","MemberPicker","Input","Button","useState","useMemo","useCallback","listMemberDirectoryPage","readOrganizationDashboard","useRef","listInactiveMembersWithOpenTasks","listMemberships","readResolvedManager","resolveMembers","_Fragment","PageHeader","ContentHeader","SectionGroup","Section","Typography","Table","FilterArea","styles","FilterLine","Filter","FormField","FormFieldLayout","Input","Modal","BaseCard","formatMemberLabel","require_rolldown_runtime","require_format_member_label","require_bpm_form_field","require_admin_pickers","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_organization","users_module_default","MemberTaskReassignModal","tasks","setTasks","tasksLoading","setTasksLoading","target","setTarget","reason","setReason","preview","setPreview","committed","setCommitted","busy","setBusy","error","setError","trimmedReason","inputKey","previewIsCurrent","canConfirm","result","latestRequestRef","loadTasks","request","loaded","memberId","requestError","readErrorMessage$1","member","titleById","task","runReassignment","outcomes","dryRun","shownResultRows","shownResults","shownTitleById","readOutcomeLabel","taskColumns","record","resultColumns","onClose","option","event","outcome","MEMBER_PAGE_SIZE_OPTIONS","AdminUsersView","detailMember","setDetailMember","detailMemberships","setDetailMemberships","detailManagerProfile","setDetailManagerProfile","detailResolvedManager","setDetailResolvedManager","inactiveMembers","setInactiveMembers","inactiveMembersError","setInactiveMembersError","loading","setLoading","memberPage","setMemberPage","memberPageSize","setMemberPageSize","memberTotalCount","setMemberTotalCount","members","setMembers","orgUnits","setOrgUnits","positions","setPositions","reassignMember","setReassignMember","searchText","setSearchText","orgUnitsById","orgUnit","positionsById","position","refreshMembers","memberPageResult","organization","readErrorMessage","latestInactiveRequestRef","refreshInactiveMembers","inactiveMemberRows","inactiveMemberColumns","inactiveMemberActions","rows","openDetail","memberships","resolvedManager","columns","tableActions","closeDetail","page","pageSize","from","to","total","MemberDetailModal","readOrgUnitLabel","membership","readPositionLabel","readMemberLabel","managerProfile"],"sources":["../../src/views/admin/users/MemberTaskReassignModal.tsx","../../src/views/admin/users/AdminUsersView.tsx"],"sourcesContent":["'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { Button, Input, Modal, Table, Typography } from '@mezzanine-ui/react';\nimport type { TableColumn } from '@mezzanine-ui/core/table';\nimport type { MemberProfileRecord } from '@rytass/bpm-core-client';\nimport {\n listMemberOpenTasks,\n type MemberOpenTaskRecord,\n reassignMemberTasks,\n type TaskReassignmentResultRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { MemberOption, MemberPicker } from '../../../components/admin-pickers';\nimport styles from './users.module.scss';\n\ntype TaskRow = Readonly<\n Record<string, unknown> &\n MemberOpenTaskRecord & {\n key: string;\n }\n>;\n\ntype ResultRow = Readonly<\n Record<string, unknown> & {\n instanceTitle: string;\n key: string;\n message: string | null;\n outcomeLabel: string;\n }\n>;\n\ninterface PreviewState {\n readonly inputKey: string;\n readonly results: readonly TaskReassignmentResultRecord[];\n}\n\n/**\n * A committed run keeps the titles it was started with: the task list reloads\n * right after, and a member whose every task moved no longer lists any of them.\n */\ninterface CommittedState {\n readonly results: readonly TaskReassignmentResultRecord[];\n readonly titleById: ReadonlyMap<string, string>;\n}\n\n/**\n * Administrator reassignment of a member's open tasks. Lists what the member\n * holds, takes a target and a reason, previews every task's outcome (dry run),\n * and only then commits. Confirm stays disabled until the preview matches the\n * current target and reason. Replacing a seat is not a decision: no signature\n * is written, and the task keeps its id.\n */\nexport function MemberTaskReassignModal({\n member,\n onClose,\n}: {\n readonly member: MemberProfileRecord | null;\n readonly onClose: () => void;\n}): ReactElement {\n const [tasks, setTasks] = useState<readonly MemberOpenTaskRecord[]>([]);\n const [tasksLoading, setTasksLoading] = useState(false);\n const [target, setTarget] = useState<MemberOption | null>(null);\n const [reason, setReason] = useState('');\n const [preview, setPreview] = useState<PreviewState | null>(null);\n const [committed, setCommitted] = useState<CommittedState | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const trimmedReason = reason.trim();\n const inputKey = `${target?.id ?? ''}|${trimmedReason}`;\n const previewIsCurrent = preview !== null && preview.inputKey === inputKey;\n const canConfirm =\n preview !== null &&\n previewIsCurrent &&\n preview.results.some((result) => result.outcome === 'WOULD_REASSIGN');\n\n // Only the latest request may write: switching members while an earlier\n // listing is in flight must not let its late answer replace the current one.\n const latestRequestRef = useRef(0);\n\n const loadTasks = useCallback(async (memberId: string): Promise<void> => {\n const request = latestRequestRef.current + 1;\n\n latestRequestRef.current = request;\n setTasksLoading(true);\n\n try {\n const loaded = await listMemberOpenTasks(memberId);\n\n if (latestRequestRef.current === request) {\n setTasks(loaded);\n }\n } catch (requestError: unknown) {\n if (latestRequestRef.current === request) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (latestRequestRef.current === request) {\n setTasksLoading(false);\n }\n }\n }, []);\n\n useEffect((): void => {\n setTarget(null);\n setReason('');\n setPreview(null);\n setCommitted(null);\n setError(null);\n\n if (!member) {\n latestRequestRef.current += 1;\n setTasks([]);\n setTasksLoading(false);\n\n return;\n }\n\n setTasks([]);\n void loadTasks(member.memberId);\n }, [member, loadTasks]);\n\n const titleById = useMemo(\n (): ReadonlyMap<string, string> =>\n new Map(tasks.map((task) => [task.taskId, task.instanceTitle])),\n [tasks],\n );\n\n async function runReassignment(dryRun: boolean): Promise<void> {\n if (!member || !target || !trimmedReason) {\n return;\n }\n\n setBusy(true);\n setError(null);\n\n try {\n const outcomes = await reassignMemberTasks({\n dryRun,\n fromMemberId: member.memberId,\n reason: trimmedReason,\n toMemberId: target.id,\n });\n\n if (dryRun) {\n setPreview({ inputKey, results: outcomes });\n setCommitted(null);\n } else {\n setCommitted({ results: outcomes, titleById });\n setPreview(null);\n await loadTasks(member.memberId);\n }\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setBusy(false);\n }\n }\n\n const shownResultRows = useMemo((): ResultRow[] => {\n const shownResults = committed?.results ?? preview?.results ?? [];\n const shownTitleById = committed?.titleById ?? titleById;\n\n return shownResults.map((result) => ({\n instanceTitle: shownTitleById.get(result.taskId) ?? result.taskId,\n key: result.taskId,\n message: result.message,\n outcomeLabel: readOutcomeLabel(result.outcome),\n }));\n }, [committed, preview, titleById]);\n\n const taskColumns = useMemo(\n (): TableColumn<TaskRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'nodeLabel',\n key: 'nodeLabel',\n title: '節點',\n width: 160,\n },\n {\n key: 'memberRole',\n render: (record: TaskRow): string =>\n record.memberRole === 'ASSIGNEE' ? '指派人' : '會簽候選人',\n title: '身分',\n width: 120,\n },\n ],\n [],\n );\n const resultColumns = useMemo(\n (): TableColumn<ResultRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'outcomeLabel',\n key: 'outcomeLabel',\n title: '結果',\n width: 100,\n },\n {\n dataIndex: 'message',\n key: 'message',\n title: '說明',\n width: 160,\n },\n ],\n [],\n );\n\n return (\n <Modal\n cancelText=\"關閉\"\n confirmButtonProps={{ disabled: !canConfirm || busy }}\n confirmText=\"確認改派\"\n loading={busy}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void => {\n void runReassignment(false);\n }}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member ? `改派待辦:${member.name}` : '改派待辦'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <Typography variant=\"body\">\n 改派會保留任務編號,但不產生簽核紀錄;原簽核人的待辦會結案為已轉交,\n 接手人會收到新的待辦通知。\n </Typography>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {tasks.length ? (\n <Table\n columns={taskColumns}\n dataSource={tasks.map((task): TaskRow => ({\n ...task,\n key: task.taskId,\n }))}\n fullWidth\n loading={tasksLoading}\n />\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n {tasksLoading ? '載入待辦中…' : '此成員目前沒有待簽任務。'}\n </Typography>\n )}\n <BPMFormField label=\"接手人\" name=\"reassignTarget\">\n <MemberPicker\n name=\"reassignTarget\"\n onChange={(option): void => {\n setTarget(option);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"搜尋接手人姓名或信箱\"\n value={target}\n />\n </BPMFormField>\n <BPMFormField label=\"改派原因\" name=\"reassignReason\">\n <Input\n fullWidth\n name=\"reassignReason\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setReason(event.target.value);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"例如:原簽核人已離職\"\n value={reason}\n />\n </BPMFormField>\n <div className={styles.membershipList}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 先按「預覽」確認每筆任務的結果,確認無誤後再按「確認改派」。\n </Typography>\n <div>\n <Button\n disabled={\n busy || !target || !trimmedReason || tasks.length === 0\n }\n onClick={(): void => {\n void runReassignment(true);\n }}\n variant=\"base-secondary\"\n >\n 預覽\n </Button>\n </div>\n </div>\n {shownResultRows.length ? (\n <Table\n columns={resultColumns}\n dataSource={shownResultRows}\n fullWidth\n />\n ) : null}\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOutcomeLabel(\n outcome: TaskReassignmentResultRecord['outcome'],\n): string {\n if (outcome === 'WOULD_REASSIGN') {\n return '會改派';\n }\n\n if (outcome === 'REASSIGNED') {\n return '已改派';\n }\n\n return '會被拒';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '改派待辦失敗。';\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n BaseCard,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { formatMemberLabel } from '../../../lib/format-member-label';\nimport styles from './users.module.scss';\nimport { MemberTaskReassignModal } from './MemberTaskReassignModal';\nimport {\n listMemberDirectoryPage,\n MemberProfileRecord,\n resolveMembers,\n} from '@rytass/bpm-core-client';\nimport {\n listMemberships,\n MembershipRecord,\n OrgUnitRecord,\n PositionRecord,\n readOrganizationDashboard,\n readResolvedManager,\n ResolvedManagerRecord,\n} from '@rytass/bpm-core-client/organization';\nimport {\n type InactiveMemberWithOpenTasksRecord,\n listInactiveMembersWithOpenTasks,\n} from '@rytass/bpm-core-client/workflow';\n\ntype MemberRow = Readonly<\n Record<string, unknown> &\n MemberProfileRecord & {\n key: string;\n }\n>;\n\ntype InactiveMemberRow = Readonly<\n Record<string, unknown> &\n InactiveMemberWithOpenTasksRecord & {\n key: string;\n }\n>;\n\nconst MEMBER_PAGE_SIZE_OPTIONS = [10, 20, 50];\n\nexport function AdminUsersView(): ReactElement {\n const [detailMember, setDetailMember] = useState<MemberProfileRecord | null>(\n null,\n );\n const [detailMemberships, setDetailMemberships] = useState<\n readonly MembershipRecord[]\n >([]);\n const [detailManagerProfile, setDetailManagerProfile] =\n useState<MemberProfileRecord | null>(null);\n const [detailResolvedManager, setDetailResolvedManager] =\n useState<ResolvedManagerRecord | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [inactiveMembers, setInactiveMembers] = useState<\n readonly InactiveMemberWithOpenTasksRecord[]\n >([]);\n const [inactiveMembersError, setInactiveMembersError] = useState<\n string | null\n >(null);\n const [loading, setLoading] = useState(true);\n const [memberPage, setMemberPage] = useState(1);\n const [memberPageSize, setMemberPageSize] = useState(10);\n const [memberTotalCount, setMemberTotalCount] = useState(0);\n const [members, setMembers] = useState<readonly MemberProfileRecord[]>([]);\n const [orgUnits, setOrgUnits] = useState<readonly OrgUnitRecord[]>([]);\n const [positions, setPositions] = useState<readonly PositionRecord[]>([]);\n const [reassignMember, setReassignMember] =\n useState<MemberProfileRecord | null>(null);\n const [searchText, setSearchText] = useState('');\n\n const orgUnitsById = useMemo(\n (): ReadonlyMap<string, OrgUnitRecord> =>\n new Map(orgUnits.map((orgUnit) => [orgUnit.id, orgUnit])),\n [orgUnits],\n );\n const positionsById = useMemo(\n (): ReadonlyMap<string, PositionRecord> =>\n new Map(positions.map((position) => [position.id, position])),\n [positions],\n );\n\n const refreshMembers = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const [memberPageResult, organization] = await Promise.all([\n listMemberDirectoryPage({\n page: memberPage,\n pageSize: memberPageSize,\n searchText,\n }),\n readOrganizationDashboard(),\n ]);\n\n setMembers(memberPageResult.members);\n setMemberTotalCount(memberPageResult.totalCount);\n setOrgUnits(organization.orgUnits);\n setPositions(organization.positions);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [memberPage, memberPageSize, searchText]);\n\n useEffect((): void => {\n void refreshMembers();\n }, [refreshMembers]);\n\n const latestInactiveRequestRef = useRef(0);\n\n // Loaded on its own so a failure here leaves the member directory usable.\n // Only the latest request may write: a reload started when the reassignment\n // closes must not be overwritten by an earlier one answering late.\n const refreshInactiveMembers = useCallback(async (): Promise<void> => {\n const request = latestInactiveRequestRef.current + 1;\n\n latestInactiveRequestRef.current = request;\n\n try {\n const loaded = await listInactiveMembersWithOpenTasks();\n\n if (latestInactiveRequestRef.current === request) {\n setInactiveMembers(loaded);\n setInactiveMembersError(null);\n }\n } catch (requestError: unknown) {\n if (latestInactiveRequestRef.current === request) {\n setInactiveMembersError(readErrorMessage(requestError));\n }\n }\n }, []);\n\n useEffect((): void => {\n void refreshInactiveMembers();\n }, [refreshInactiveMembers]);\n\n const inactiveMemberRows = useMemo(\n (): InactiveMemberRow[] =>\n inactiveMembers.map(\n (member): InactiveMemberRow => ({ ...member, key: member.memberId }),\n ),\n [inactiveMembers],\n );\n const inactiveMemberColumns = useMemo(\n (): TableColumn<InactiveMemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n {\n dataIndex: 'openTaskCount',\n key: 'openTaskCount',\n title: '待簽數',\n width: 96,\n },\n ],\n [],\n );\n const inactiveMemberActions = useMemo(\n (): TableActions<InactiveMemberRow> => ({\n render: (): ReturnType<TableActions<InactiveMemberRow>['render']> => [\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember({\n customFieldsJson: '{}',\n email: record.email,\n memberId: record.memberId,\n name: record.name,\n });\n },\n },\n ],\n variant: 'base-secondary',\n width: 112,\n }),\n [],\n );\n\n const rows = useMemo(\n (): MemberRow[] =>\n members.map((member) => ({\n ...member,\n key: member.memberId,\n })),\n [members],\n );\n\n const openDetail = useCallback(\n async (member: MemberProfileRecord): Promise<void> => {\n setDetailMember(member);\n setDetailManagerProfile(null);\n setError(null);\n\n try {\n const [memberships, resolvedManager] = await Promise.all([\n listMemberships({ memberId: member.memberId }),\n readResolvedManager(member.memberId),\n ]);\n\n setDetailMemberships(memberships);\n setDetailResolvedManager(resolvedManager);\n setDetailManagerProfile(\n (\n await resolveMembers(\n resolvedManager.managerMemberId\n ? [resolvedManager.managerMemberId]\n : [],\n )\n )[0] ?? null,\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n }\n },\n [],\n );\n\n const columns = useMemo(\n (): TableColumn<MemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<MemberRow> => ({\n render: (): ReturnType<TableActions<MemberRow>['render']> => [\n {\n name: '檢視',\n onClick: (record): void => {\n void openDetail(record);\n },\n },\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember(record);\n },\n },\n ],\n variant: 'base-secondary',\n width: 176,\n }),\n [openDetail],\n );\n\n function closeDetail(): void {\n setDetailMember(null);\n setDetailManagerProfile(null);\n setDetailMemberships([]);\n setDetailResolvedManager(null);\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"會員資料由 host member resolver 提供,BPM 僅維護組織歸屬與主管解析。\"\n title=\"會員對照\"\n />\n </PageHeader>\n\n <SectionGroup>\n {inactiveMemberRows.length || inactiveMembersError ? (\n <Section\n contentHeader={\n <ContentHeader\n description=\"這些會員已停用,身上仍有待簽,請改派給在職的人。\"\n title=\"已停用、仍有待簽的會員\"\n />\n }\n >\n <div data-inactive-members=\"\">\n {inactiveMembersError ? (\n <Typography color=\"text-error\" variant=\"body\">\n {inactiveMembersError}\n </Typography>\n ) : (\n <Table\n actions={inactiveMemberActions}\n columns={inactiveMemberColumns}\n dataSource={inactiveMemberRows}\n fullWidth\n />\n )}\n </div>\n </Section>\n ) : null}\n <Section\n filterArea={\n <FilterArea className={styles.memberFilterArea}>\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"memberSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setMemberPage(1);\n }}\n placeholder=\"搜尋姓名或信箱\"\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n pagination={{\n current: memberPage,\n onChange: (page): void => {\n setMemberPage(page);\n },\n onChangePageSize: (pageSize): void => {\n setMemberPage(1);\n setMemberPageSize(pageSize);\n },\n pageSize: memberPageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: MEMBER_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: memberTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n\n <MemberTaskReassignModal\n member={reassignMember}\n onClose={(): void => {\n setReassignMember(null);\n // A reassignment may have cleared someone off the list.\n void refreshInactiveMembers();\n }}\n />\n\n <MemberDetailModal\n managerProfile={detailManagerProfile}\n member={detailMember}\n memberships={detailMemberships}\n onClose={closeDetail}\n orgUnitsById={orgUnitsById}\n positionsById={positionsById}\n resolvedManager={detailResolvedManager}\n />\n </>\n );\n}\n\nfunction MemberDetailModal({\n managerProfile,\n member,\n memberships,\n onClose,\n orgUnitsById,\n positionsById,\n resolvedManager,\n}: {\n readonly managerProfile: MemberProfileRecord | null;\n readonly member: MemberProfileRecord | null;\n readonly memberships: readonly MembershipRecord[];\n readonly onClose: () => void;\n readonly orgUnitsById: ReadonlyMap<string, OrgUnitRecord>;\n readonly positionsById: ReadonlyMap<string, PositionRecord>;\n readonly resolvedManager: ResolvedManagerRecord | null;\n}): ReactElement {\n return (\n <Modal\n cancelText=\"關閉\"\n confirmText=\"關閉\"\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={onClose}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member?.name ?? '會員明細'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <BaseCard title=\"基本資料\">\n <div className={styles.detailSection}>\n <Typography variant=\"body\">\n 信箱:{member.email?.trim() ? member.email : '未設定'}\n </Typography>\n </div>\n </BaseCard>\n <BaseCard title=\"BPM 組織歸屬\">\n <div className={styles.membershipList}>\n {memberships.length ? (\n memberships.map((membership) => (\n <Typography key={membership.id} variant=\"body\">\n {readOrgUnitLabel(orgUnitsById.get(membership.orgUnitId))}\n {' / '}\n {membership.positionId\n ? readPositionLabel(\n positionsById.get(membership.positionId),\n )\n : '未指定職位'}\n {' / '}\n {membership.isPrimary ? '主要' : '一般'}\n </Typography>\n ))\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 尚未建立 BPM 組織歸屬\n </Typography>\n )}\n </div>\n </BaseCard>\n <BaseCard title=\"主管解析\">\n <Typography variant=\"body\">\n {resolvedManager?.managerMemberId\n ? readMemberLabel(managerProfile)\n : '尚未解析到主管'}\n </Typography>\n </BaseCard>\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOrgUnitLabel(orgUnit: OrgUnitRecord | undefined): string {\n return orgUnit ? `${orgUnit.name} · ${orgUnit.code}` : '未知組織';\n}\n\nfunction readPositionLabel(position: PositionRecord | undefined): string {\n return position ? `${position.name} · ${position.code}` : '未知職位';\n}\n\nfunction readMemberLabel(member: MemberProfileRecord | null): string {\n return member\n ? formatMemberLabel(member.name, member.email, 'dot')\n : '主管資料尚未載入';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '讀取會員資料失敗。';\n}\n"],"mappings":"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"}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["useAuth","useNotificationDrawer","useNotificationUnread","styles","NavigationIconButton","NotificationUnreadIcon","require_auth_provider","require_format_date_time","require_organization_time_zone_provider","require_providers","require_router_adapter","require_routes_config","require_use_bpm_member","require_admin_pickers","require_approval_instance_list_page","require_bpm_form_field","require_dashboard_page","_mezzanine_ui_react","react_jsx_runtime","_mezzanine_ui_icons","useBPMLogout","logout","bpm_notification_bell_button_module_default","BPMNotificationBellButton","ariaLabel","unreadCount","label","open"],"sources":["../src/lib/use-bpm-logout.ts","../src/components/bpm-notification-bell-button.
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["useAuth","useNotificationDrawer","useNotificationUnread","styles","NavigationIconButton","NotificationUnreadIcon","require_auth_provider","require_format_date_time","require_organization_time_zone_provider","require_providers","require_router_adapter","require_routes_config","require_use_bpm_member","require_admin_pickers","require_approval_instance_list_page","require_bpm_form_field","require_dashboard_page","_mezzanine_ui_react","react_jsx_runtime","_mezzanine_ui_icons","useBPMLogout","logout","bpm_notification_bell_button_module_default","BPMNotificationBellButton","ariaLabel","unreadCount","label","open"],"sources":["../src/lib/use-bpm-logout.ts","../src/components/bpm-notification-bell-button.tsx"],"sourcesContent":["'use client';\n\nimport { useAuth } from './auth-provider';\n\n/**\n * Drop-in logout handler for host navigation menus. Wraps the BPM auth\n * context's logout flow — calls `logoutApi()` against the BPM REST\n * session endpoint, clears the in-memory member, then redirects to the\n * configured `loginPath`.\n *\n * Hosts mount this on their own logout buttons / menu items so they do\n * not need to touch `useAuth()` directly. To customize the post-logout\n * destination, override the `loginPath` prop on `<BPMNextProviders>` or\n * `<AuthProvider>`.\n */\nexport function useBPMLogout(): () => Promise<void> {\n const { logout } = useAuth();\n return logout;\n}\n","'use client';\n\nimport type { ReactElement } from 'react';\nimport { NavigationIconButton } from '@mezzanine-ui/react';\nimport { NotificationUnreadIcon } from '@mezzanine-ui/icons';\nimport { useNotificationDrawer } from '../lib/notification-drawer-provider';\nimport { useNotificationUnread } from '../lib/notification-unread-provider';\nimport styles from './bpm-notification-bell-button.module.scss';\n\nexport interface BPMNotificationBellButtonProps {\n /** Override the aria-label / tooltip. Defaults to `通知中心`. */\n readonly label?: string;\n}\n\n/**\n * Drop-in notification bell. Reads the unread count from\n * `<NotificationUnreadProvider>`, opens the BPM `<NotificationDrawer />`\n * mounted by `<Providers>` (or `<BPMNextProviders>`) on click, and\n * renders a small red badge with the unread count.\n *\n * Use this when the host navigation wants the BPM notification UX with\n * minimum wiring. Hosts that need a fully custom button can skip this\n * widget and consume `useNotificationDrawer()` + `useNotificationUnread()`\n * directly to wire their own trigger.\n *\n * Visual: uses Mezzanine `NavigationIconButton` so the bell aligns with\n * surrounding Mezzanine navigation chrome. The button is decoupled from\n * the `<Navigation>` container — it does not require a Mezzanine\n * navigation tree to render.\n */\nexport function BPMNotificationBellButton({\n label = '通知中心',\n}: BPMNotificationBellButtonProps = {}): ReactElement {\n const { open } = useNotificationDrawer();\n const { unreadCount } = useNotificationUnread();\n const ariaLabel = unreadCount > 0 ? `${label},${unreadCount} 則未讀` : label;\n return (\n <span className={styles.root}>\n <NavigationIconButton\n aria-label={ariaLabel}\n icon={NotificationUnreadIcon}\n onClick={(): void => {\n open();\n }}\n title={label}\n type=\"button\"\n />\n {unreadCount > 0 ? (\n <span className={styles.badge}>\n {unreadCount > 99 ? '99+' : unreadCount}\n </span>\n ) : null}\n </span>\n );\n}\n"],"mappings":"A,yvBAeA,SAAgBoB,GAAoC,CAClD,GAAM,CAAE,UAAWpB,EAAAA,EAAQ,EAC3B,OAAOqB,CACT,C,sDCYA,SAAgBE,EAA0B,CACxC,QAAQ,QAC0B,CAAC,EAAiB,CACpD,GAAM,CAAE,QAAStB,EAAAA,EAAsB,EACjC,CAAE,eAAgBC,EAAAA,EAAsB,EACxCsB,EAAYC,EAAc,EAAI,GAAGC,EAAM,GAAGD,EAAY,MAAQC,EACpE,OACE,EAAAR,EAAA,KAAA,CAAC,OAAD,CAAM,UAAWf,EAAO,KAAxB,SAAA,EACE,EAAAe,EAAA,IAAA,CAACd,EAAAA,qBAAD,CACE,aAAYoB,EACZ,KAAMnB,EAAAA,uBACN,YAAqB,CACnBsB,EAAK,CACP,EACA,MAAOD,EACP,KAAK,QACN,CAAA,EACAD,EAAc,GACb,EAAAP,EAAA,IAAA,CAAC,OAAD,CAAM,UAAWf,EAAO,MACrB,SAAAsB,EAAc,GAAK,MAAQA,CACxB,CAAA,EACJ,IACA,C,EAEV,C"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["styles","useAuth","formatDateTime","DEFAULT_BPM_LANGUAGE","useBPMOrganizationTimeZone","BPMLanguageProvider","BPMOrganizationTimeZoneProvider","NotificationDrawerProvider","useNotificationUnread","NotificationDrawer","useNotificationDrawer","NotificationUnreadProvider","Providers","defaultBrowserSearchParams","useRouterAdapter","RouterAdapterProvider","createDefaultBPMRoutes","useBPMRoutes","BPMRoutesProvider","useBPMMember","isBPMAdminMember","readOrgUnitOption","readMemberOption","OrgUnitPicker","readPositionOption","PositionPicker","MemberPicker","ApprovalInstanceListPage","BPMFormField","DashboardPage","useBPMLogout","logout","bpm_notification_bell_button_module_default","BPMNotificationBellButton","ariaLabel","unreadCount","label","NavigationIconButton","NotificationUnreadIcon","AuthProvider","BPM_LANGUAGES","useBPMLanguage"],"sources":["../src/lib/use-bpm-logout.ts","../src/components/bpm-notification-bell-button.
|
|
1
|
+
{"version":3,"file":"index.js","names":["styles","useAuth","formatDateTime","DEFAULT_BPM_LANGUAGE","useBPMOrganizationTimeZone","BPMLanguageProvider","BPMOrganizationTimeZoneProvider","NotificationDrawerProvider","useNotificationUnread","NotificationDrawer","useNotificationDrawer","NotificationUnreadProvider","Providers","defaultBrowserSearchParams","useRouterAdapter","RouterAdapterProvider","createDefaultBPMRoutes","useBPMRoutes","BPMRoutesProvider","useBPMMember","isBPMAdminMember","readOrgUnitOption","readMemberOption","OrgUnitPicker","readPositionOption","PositionPicker","MemberPicker","ApprovalInstanceListPage","BPMFormField","DashboardPage","useBPMLogout","logout","bpm_notification_bell_button_module_default","BPMNotificationBellButton","ariaLabel","unreadCount","label","NavigationIconButton","NotificationUnreadIcon","AuthProvider","BPM_LANGUAGES","useBPMLanguage"],"sources":["../src/lib/use-bpm-logout.ts","../src/components/bpm-notification-bell-button.tsx"],"sourcesContent":["'use client';\n\nimport { useAuth } from './auth-provider';\n\n/**\n * Drop-in logout handler for host navigation menus. Wraps the BPM auth\n * context's logout flow — calls `logoutApi()` against the BPM REST\n * session endpoint, clears the in-memory member, then redirects to the\n * configured `loginPath`.\n *\n * Hosts mount this on their own logout buttons / menu items so they do\n * not need to touch `useAuth()` directly. To customize the post-logout\n * destination, override the `loginPath` prop on `<BPMNextProviders>` or\n * `<AuthProvider>`.\n */\nexport function useBPMLogout(): () => Promise<void> {\n const { logout } = useAuth();\n return logout;\n}\n","'use client';\n\nimport type { ReactElement } from 'react';\nimport { NavigationIconButton } from '@mezzanine-ui/react';\nimport { NotificationUnreadIcon } from '@mezzanine-ui/icons';\nimport { useNotificationDrawer } from '../lib/notification-drawer-provider';\nimport { useNotificationUnread } from '../lib/notification-unread-provider';\nimport styles from './bpm-notification-bell-button.module.scss';\n\nexport interface BPMNotificationBellButtonProps {\n /** Override the aria-label / tooltip. Defaults to `通知中心`. */\n readonly label?: string;\n}\n\n/**\n * Drop-in notification bell. Reads the unread count from\n * `<NotificationUnreadProvider>`, opens the BPM `<NotificationDrawer />`\n * mounted by `<Providers>` (or `<BPMNextProviders>`) on click, and\n * renders a small red badge with the unread count.\n *\n * Use this when the host navigation wants the BPM notification UX with\n * minimum wiring. Hosts that need a fully custom button can skip this\n * widget and consume `useNotificationDrawer()` + `useNotificationUnread()`\n * directly to wire their own trigger.\n *\n * Visual: uses Mezzanine `NavigationIconButton` so the bell aligns with\n * surrounding Mezzanine navigation chrome. The button is decoupled from\n * the `<Navigation>` container — it does not require a Mezzanine\n * navigation tree to render.\n */\nexport function BPMNotificationBellButton({\n label = '通知中心',\n}: BPMNotificationBellButtonProps = {}): ReactElement {\n const { open } = useNotificationDrawer();\n const { unreadCount } = useNotificationUnread();\n const ariaLabel = unreadCount > 0 ? `${label},${unreadCount} 則未讀` : label;\n return (\n <span className={styles.root}>\n <NavigationIconButton\n aria-label={ariaLabel}\n icon={NotificationUnreadIcon}\n onClick={(): void => {\n open();\n }}\n title={label}\n type=\"button\"\n />\n {unreadCount > 0 ? (\n <span className={styles.badge}>\n {unreadCount > 99 ? '99+' : unreadCount}\n </span>\n ) : null}\n </span>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,SAAgB8B,IAAoC;CAClD,IAAM,EAAE,cAAW7B,EAAQ;CAC3B,OAAO8B;AACT;;;;;;ACYA,SAAgBE,EAA0B,EACxC,WAAQ,WAC0B,CAAC,GAAiB;CACpD,IAAM,EAAE,YAASvB,EAAsB,GACjC,EAAE,mBAAgBF,EAAsB,GACxC0B,IAAYC,IAAc,IAAI,GAAGC,EAAM,GAAGD,EAAY,QAAQC;CACpE,OACE,kBAAC,QAAD;EAAM,WAAWpC,EAAO;EAAxB,UAAA,CACE,kBAACqC,GAAD;GACE,cAAYH;GACZ,MAAMI;GACN,eAAqB;IACnB,EAAK;GACP;GACA,OAAOF;GACP,MAAK;EACN,CAAA,GACAD,IAAc,IACb,kBAAC,QAAD;GAAM,WAAWnC,EAAO;GACrB,UAAAmC,IAAc,KAAK,QAAQA;EACxB,CAAA,IACJ,IACA;;AAEV"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/detail-
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/detail-BLhZp1mO.cjs");let t=require("react/jsx-runtime");var n={title:`案件詳情 | BPM Admin`};async function r({params:n}){let{id:r}=await n;return(0,t.jsx)(e.t,{instanceId:r})}exports.default=r,exports.metadata=n;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/compose-
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/compose-NHbyjV73.cjs");let t=require("react/jsx-runtime"),n=require("next/server");var r={title:`建立模板(表單 + 流程) | BPM Admin`,description:`以精靈式流程一次完成 BPM 表單與簽核流程設計並發佈。`};async function i(){return await(0,n.connection)(),(0,t.jsx)(e.t,{aiAssistantAvailable:!!process.env.OPENAI_API_KEY,showAiAssistant:process.env.BPM_AI_ASSISTANT_ENABLED===`true`})}exports.default=i,exports.metadata=r;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/designer-
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/designer-oDGvHWBJ.cjs");let t=require("react/jsx-runtime");var n={title:`流程設計器 | BPM Admin`,description:`以視覺化設計器編輯 BPM 簽核流程節點、條件與發佈版本。`};async function r({params:n}){let{id:r}=await n;return(0,t.jsx)(e.t,{aiAssistantAvailable:!!process.env.OPENAI_API_KEY,showAiAssistant:process.env.BPM_AI_ASSISTANT_ENABLED===`true`,showDryRun:process.env.BPM_TEMPLATE_DRY_RUN_ENABLED!==`false`,templateId:r})}exports.default=r,exports.metadata=n;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/FormBuilderView-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/FormBuilderView-Bq4TXdxF.cjs");exports.FormBuilderView=e.t;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as FormBuilderView } from "../../../chunks/FormBuilderView-
|
|
1
|
+
export { t as FormBuilderView } from "../../../chunks/FormBuilderView-DNsFwZgk.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The height every option menu in the form renderer stops growing at. Without
|
|
3
|
+
* a cap Mezzanine's dropdown list grows with its options and never scrolls, so
|
|
4
|
+
* a long page overflows the layout and `onReachBottom` — the only way to load
|
|
5
|
+
* the next page — can never fire. Matches the admin pickers' menus.
|
|
6
|
+
*/
|
|
7
|
+
export declare const FORM_CONTROL_MENU_MAX_HEIGHT = 320;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The height every option menu in the form renderer stops growing at. Without
|
|
3
|
+
* a cap Mezzanine's dropdown list grows with its options and never scrolls, so
|
|
4
|
+
* a long page overflows the layout and `onReachBottom` — the only way to load
|
|
5
|
+
* the next page — can never fire. Matches the admin pickers' menus.
|
|
6
|
+
*/
|
|
7
|
+
export declare const FORM_CONTROL_MENU_MAX_HEIGHT = 320;
|
|
@@ -16,7 +16,19 @@ export interface FormDataSourceFieldState {
|
|
|
16
16
|
readonly error: string | null;
|
|
17
17
|
readonly hasValue: boolean;
|
|
18
18
|
readonly hasNextPage: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* True while the pending query is a next page rather than a first page. An
|
|
21
|
+
* AutoComplete in async mode empties its list whenever it is told it is
|
|
22
|
+
* loading, so the view keeps the loaded options on screen while paging.
|
|
23
|
+
*/
|
|
24
|
+
readonly loadingNextPage: boolean;
|
|
19
25
|
readonly invalidValues: readonly string[];
|
|
26
|
+
/**
|
|
27
|
+
* Call when the control's menu opens. A control that only queries on search
|
|
28
|
+
* (AutoComplete) loads its first page here, so opening it lists options
|
|
29
|
+
* instead of an empty menu; it is a no-op once that page is loaded.
|
|
30
|
+
*/
|
|
31
|
+
readonly onOpen: () => void;
|
|
20
32
|
readonly onReachBottom: () => void;
|
|
21
33
|
readonly onSearch: (searchText: string) => void;
|
|
22
34
|
readonly options: readonly FormFieldOption[];
|
|
@@ -16,7 +16,19 @@ export interface FormDataSourceFieldState {
|
|
|
16
16
|
readonly error: string | null;
|
|
17
17
|
readonly hasValue: boolean;
|
|
18
18
|
readonly hasNextPage: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* True while the pending query is a next page rather than a first page. An
|
|
21
|
+
* AutoComplete in async mode empties its list whenever it is told it is
|
|
22
|
+
* loading, so the view keeps the loaded options on screen while paging.
|
|
23
|
+
*/
|
|
24
|
+
readonly loadingNextPage: boolean;
|
|
19
25
|
readonly invalidValues: readonly string[];
|
|
26
|
+
/**
|
|
27
|
+
* Call when the control's menu opens. A control that only queries on search
|
|
28
|
+
* (AutoComplete) loads its first page here, so opening it lists options
|
|
29
|
+
* instead of an empty menu; it is a no-op once that page is loaded.
|
|
30
|
+
*/
|
|
31
|
+
readonly onOpen: () => void;
|
|
20
32
|
readonly onReachBottom: () => void;
|
|
21
33
|
readonly onSearch: (searchText: string) => void;
|
|
22
34
|
readonly options: readonly FormFieldOption[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/FormRendererView-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/FormRendererView-ZIfSRWPi.cjs");exports.FormRenderer=e.t,exports.FormRendererView=e.t,exports.isFormDataSourceFieldSubmissionBlocked=e.s,exports.readFileUploadSubmissionBlockMessage=e.a,exports.readFormDataSourceFieldStatusMessage=e.c,exports.readFormDataSourceSubmissionBlockMessage=e.l,exports.useFormDataSourceField=e.u;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as FormRenderer, t as FormRendererView, s as isFormDataSourceFieldSubmissionBlocked, a as readFileUploadSubmissionBlockMessage, c as readFormDataSourceFieldStatusMessage, l as readFormDataSourceSubmissionBlockMessage, u as useFormDataSourceField } from "../../../chunks/FormRendererView-
|
|
1
|
+
export { t as FormRenderer, t as FormRendererView, s as isFormDataSourceFieldSubmissionBlocked, a as readFileUploadSubmissionBlockMessage, c as readFormDataSourceFieldStatusMessage, l as readFormDataSourceSubmissionBlockMessage, u as useFormDataSourceField } from "../../../chunks/FormRendererView-BF8Ge0Zk.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/detail-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/detail-BLhZp1mO.cjs");exports.InstanceAttachmentsSection=e.o,exports.InstanceDetailView=e.t,exports.InstanceFormSection=e.s,exports.InstanceHistorySection=e.r,exports.InstanceSignaturesSection=e.i,exports.InstanceTasksSection=e.a,exports.InstanceWebhookDeliveriesSection=e.n;
|