@rytass/bpm-core-react 0.3.1 → 0.3.2
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 +131 -0
- package/dist/chunks/app-navigation-BSkMsEhy.js +268 -0
- package/dist/chunks/app-navigation-BSkMsEhy.js.map +1 -0
- package/dist/chunks/app-navigation-KnlJCUp1.cjs +2 -0
- package/dist/chunks/app-navigation-KnlJCUp1.cjs.map +1 -0
- package/dist/chunks/approval-instance-list-page-CVXgE2K3.cjs +2 -0
- package/dist/chunks/approval-instance-list-page-CVXgE2K3.cjs.map +1 -0
- package/dist/chunks/{approval-instance-list-page-nmzMrj0b.js → approval-instance-list-page-CqNdoZqx.js} +73 -72
- package/dist/chunks/approval-instance-list-page-CqNdoZqx.js.map +1 -0
- package/dist/chunks/builder-CMlJfQHE.cjs +3 -0
- package/dist/chunks/builder-CMlJfQHE.cjs.map +1 -0
- package/dist/chunks/{builder-DqZskyXC.js → builder-D950gct_.js} +492 -491
- package/dist/chunks/builder-D950gct_.js.map +1 -0
- package/dist/chunks/categories-5yEM3p3N.cjs +2 -0
- package/dist/chunks/categories-5yEM3p3N.cjs.map +1 -0
- package/dist/chunks/{categories-DTEl182t.js → categories-BIpOG451.js} +115 -114
- package/dist/chunks/categories-BIpOG451.js.map +1 -0
- package/dist/chunks/dashboard-page-1K_jQXQk.cjs +2 -0
- package/dist/chunks/dashboard-page-1K_jQXQk.cjs.map +1 -0
- package/dist/chunks/dashboard-page-R_T2OEiE.js +122 -0
- package/dist/chunks/dashboard-page-R_T2OEiE.js.map +1 -0
- package/dist/chunks/{delegations-C5PzZ5Kn.js → delegations-B2j-wNEO.js} +193 -192
- package/dist/chunks/delegations-B2j-wNEO.js.map +1 -0
- package/dist/chunks/delegations-CsB9ozLu.cjs +2 -0
- package/dist/chunks/delegations-CsB9ozLu.cjs.map +1 -0
- package/dist/chunks/delegations-CvtwTXNP.cjs +2 -0
- package/dist/chunks/delegations-CvtwTXNP.cjs.map +1 -0
- package/dist/chunks/{delegations-C-ZrwzvU.js → delegations-dKodb0WW.js} +175 -174
- package/dist/chunks/delegations-dKodb0WW.js.map +1 -0
- package/dist/chunks/{detail-CfFyU5zC.js → detail-BcGAqJ_R.js} +465 -464
- package/dist/chunks/detail-BcGAqJ_R.js.map +1 -0
- package/dist/chunks/detail-CqjqLd65.cjs +2 -0
- package/dist/chunks/detail-CqjqLd65.cjs.map +1 -0
- package/dist/chunks/{format-date-time-isOa3e9q.cjs → format-date-time-26_pFvv4.cjs} +2 -2
- package/dist/chunks/{format-date-time-isOa3e9q.cjs.map → format-date-time-26_pFvv4.cjs.map} +1 -1
- package/dist/chunks/notifications-2swRqDPF.js +198 -0
- package/dist/chunks/notifications-2swRqDPF.js.map +1 -0
- package/dist/chunks/notifications-BaYDebFt.cjs +2 -0
- package/dist/chunks/notifications-BaYDebFt.cjs.map +1 -0
- package/dist/chunks/{orgs-xrdhb3hS.js → orgs-CuHxxd_n.js} +608 -607
- package/dist/chunks/orgs-CuHxxd_n.js.map +1 -0
- package/dist/chunks/orgs-YMiVLNvL.cjs +2 -0
- package/dist/chunks/orgs-YMiVLNvL.cjs.map +1 -0
- package/dist/chunks/routes-config-2aKbWq2H.cjs +2 -0
- package/dist/chunks/routes-config-2aKbWq2H.cjs.map +1 -0
- package/dist/chunks/routes-config-dxahImVe.js +43 -0
- package/dist/chunks/routes-config-dxahImVe.js.map +1 -0
- package/dist/chunks/templates-DTkbSgFY.cjs +2 -0
- package/dist/chunks/templates-DTkbSgFY.cjs.map +1 -0
- package/dist/chunks/templates-DoDWM68t.js +384 -0
- package/dist/chunks/templates-DoDWM68t.js.map +1 -0
- package/dist/chunks/users-3ySyUW4u.cjs +2 -0
- package/dist/chunks/users-3ySyUW4u.cjs.map +1 -0
- package/dist/chunks/{users-CY4-NK3j.js → users-sMfrSjRQ.js} +75 -74
- package/dist/chunks/users-sMfrSjRQ.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +101 -99
- package/dist/index.js.map +1 -1
- package/dist/lib/routes-config.d.ts +96 -0
- package/dist/next/index.cjs +1 -1
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.ts +1 -0
- package/dist/next/index.js +22 -21
- package/dist/next/index.js.map +1 -1
- package/dist/pages/admin/delegations/index.cjs +1 -1
- package/dist/pages/admin/delegations/index.js +1 -1
- package/dist/pages/admin/orgs/index.cjs +1 -1
- package/dist/pages/admin/orgs/index.js +1 -1
- package/dist/pages/admin/users/index.cjs +1 -1
- package/dist/pages/admin/users/index.js +1 -1
- package/dist/pages/delegations/index.cjs +1 -1
- package/dist/pages/delegations/index.js +1 -1
- package/dist/pages/forms/builder/index.cjs +1 -1
- package/dist/pages/forms/builder/index.js +1 -1
- package/dist/pages/instances/detail/index.cjs +1 -1
- package/dist/pages/instances/detail/index.js +1 -1
- package/dist/pages/settings/notifications/index.cjs +1 -1
- package/dist/pages/settings/notifications/index.js +1 -1
- package/dist/pages/templates/categories/index.cjs +1 -1
- package/dist/pages/templates/categories/index.js +1 -1
- package/dist/pages/templates/index.cjs +1 -1
- package/dist/pages/templates/index.js +1 -1
- package/dist/views/admin/delegations/index.cjs +1 -1
- package/dist/views/admin/delegations/index.js +1 -1
- package/dist/views/admin/index.cjs +1 -1
- package/dist/views/admin/index.js +3 -3
- package/dist/views/admin/orgs/index.cjs +1 -1
- package/dist/views/admin/orgs/index.js +1 -1
- package/dist/views/admin/users/index.cjs +1 -1
- package/dist/views/admin/users/index.js +1 -1
- package/dist/views/cc/index.cjs +1 -1
- package/dist/views/cc/index.js +1 -1
- package/dist/views/dashboard/index.cjs +1 -1
- package/dist/views/dashboard/index.js +1 -1
- package/dist/views/delegations/index.cjs +1 -1
- package/dist/views/delegations/index.js +1 -1
- package/dist/views/forms/builder/index.cjs +1 -1
- package/dist/views/forms/builder/index.js +1 -1
- package/dist/views/forms/index.cjs +1 -1
- package/dist/views/forms/index.cjs.map +1 -1
- package/dist/views/forms/index.js +78 -77
- package/dist/views/forms/index.js.map +1 -1
- package/dist/views/inbox/index.cjs +1 -1
- package/dist/views/inbox/index.cjs.map +1 -1
- package/dist/views/inbox/index.js +106 -105
- package/dist/views/inbox/index.js.map +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.cjs.map +1 -1
- package/dist/views/instances/new/index.js +90 -89
- package/dist/views/instances/new/index.js.map +1 -1
- package/dist/views/search/index.cjs +1 -1
- package/dist/views/search/index.js +1 -1
- package/dist/views/sent/index.cjs +1 -1
- package/dist/views/sent/index.js +1 -1
- package/dist/views/settings/index.cjs +1 -1
- package/dist/views/settings/index.js +1 -1
- package/dist/views/settings/notifications/index.cjs +1 -1
- package/dist/views/settings/notifications/index.js +1 -1
- package/dist/views/templates/categories/index.cjs +1 -1
- package/dist/views/templates/categories/index.js +1 -1
- package/dist/views/templates/designer/index.cjs +6 -6
- package/dist/views/templates/designer/index.cjs.map +1 -1
- package/dist/views/templates/designer/index.js +589 -588
- package/dist/views/templates/designer/index.js.map +1 -1
- package/dist/views/templates/index.cjs +1 -1
- package/dist/views/templates/index.js +2 -2
- package/dist/views/templates/versions/index.cjs +1 -1
- package/dist/views/templates/versions/index.cjs.map +1 -1
- package/dist/views/templates/versions/index.js +44 -43
- package/dist/views/templates/versions/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunks/app-navigation-C_mbz7jx.cjs +0 -2
- package/dist/chunks/app-navigation-C_mbz7jx.cjs.map +0 -1
- package/dist/chunks/app-navigation-uwbNEw9P.js +0 -262
- package/dist/chunks/app-navigation-uwbNEw9P.js.map +0 -1
- package/dist/chunks/approval-instance-list-page-Mo6wpDPb.cjs +0 -2
- package/dist/chunks/approval-instance-list-page-Mo6wpDPb.cjs.map +0 -1
- package/dist/chunks/approval-instance-list-page-nmzMrj0b.js.map +0 -1
- package/dist/chunks/builder-DPhAH381.cjs +0 -3
- package/dist/chunks/builder-DPhAH381.cjs.map +0 -1
- package/dist/chunks/builder-DqZskyXC.js.map +0 -1
- package/dist/chunks/categories-DEijUOnw.cjs +0 -2
- package/dist/chunks/categories-DEijUOnw.cjs.map +0 -1
- package/dist/chunks/categories-DTEl182t.js.map +0 -1
- package/dist/chunks/dashboard-page-DCmuB0Rw.cjs +0 -2
- package/dist/chunks/dashboard-page-DCmuB0Rw.cjs.map +0 -1
- package/dist/chunks/dashboard-page-Dx5PeEeN.js +0 -117
- package/dist/chunks/dashboard-page-Dx5PeEeN.js.map +0 -1
- package/dist/chunks/delegations-C-ZrwzvU.js.map +0 -1
- package/dist/chunks/delegations-C5PzZ5Kn.js.map +0 -1
- package/dist/chunks/delegations-DOGDvybX.cjs +0 -2
- package/dist/chunks/delegations-DOGDvybX.cjs.map +0 -1
- package/dist/chunks/delegations-DkDBWOQ7.cjs +0 -2
- package/dist/chunks/delegations-DkDBWOQ7.cjs.map +0 -1
- package/dist/chunks/detail-B2gcOPkd.cjs +0 -2
- package/dist/chunks/detail-B2gcOPkd.cjs.map +0 -1
- package/dist/chunks/detail-CfFyU5zC.js.map +0 -1
- package/dist/chunks/notifications-CPQ-nVar.cjs +0 -2
- package/dist/chunks/notifications-CPQ-nVar.cjs.map +0 -1
- package/dist/chunks/notifications-DweexUVy.js +0 -197
- package/dist/chunks/notifications-DweexUVy.js.map +0 -1
- package/dist/chunks/orgs-DgZ0DQ3-.cjs +0 -2
- package/dist/chunks/orgs-DgZ0DQ3-.cjs.map +0 -1
- package/dist/chunks/orgs-xrdhb3hS.js.map +0 -1
- package/dist/chunks/templates-PK_VYvcy.js +0 -383
- package/dist/chunks/templates-PK_VYvcy.js.map +0 -1
- package/dist/chunks/templates-x1OJZmsG.cjs +0 -2
- package/dist/chunks/templates-x1OJZmsG.cjs.map +0 -1
- package/dist/chunks/users-CY4-NK3j.js.map +0 -1
- package/dist/chunks/users-DHnu_056.cjs +0 -2
- package/dist/chunks/users-DHnu_056.cjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,172 +1,174 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { a as e, i as t, n, r, t as i } from "./chunks/auth-provider-Bnox5gsx.js";
|
|
3
3
|
import { t as a } from "./chunks/format-date-time-CB-LxzqT.js";
|
|
4
|
-
import { a as o, i as s, n as c, r as l, t as u } from "./chunks/app-navigation-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { t as
|
|
8
|
-
import { t as
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
14
|
-
import
|
|
4
|
+
import { a as o, i as s, n as c, r as l, t as u } from "./chunks/app-navigation-BSkMsEhy.js";
|
|
5
|
+
import { n as d, r as f, t as p } from "./chunks/routes-config-dxahImVe.js";
|
|
6
|
+
import { a as m, i as h, n as g, o as _, r as v, t as y } from "./chunks/admin-pickers-DLlG_1du.js";
|
|
7
|
+
import { t as b } from "./chunks/approval-instance-list-page-CqNdoZqx.js";
|
|
8
|
+
import { t as x } from "./chunks/bpm-form-field-Cao0rMol.js";
|
|
9
|
+
import { t as S } from "./chunks/dashboard-page-R_T2OEiE.js";
|
|
10
|
+
import { Fragment as C, useCallback as w, useEffect as T, useMemo as E, useState as D } from "react";
|
|
11
|
+
import { jsx as O, jsxs as k } from "react/jsx-runtime";
|
|
12
|
+
import { listNotifications as A, markAllNotificationsRead as j, markNotificationRead as M } from "@rytass/bpm-core-client/workflow";
|
|
13
|
+
import { CalendarConfigProviderMoment as N, CalendarLocale as P } from "@mezzanine-ui/react/moment";
|
|
14
|
+
import F from "@mezzanine-ui/react/Drawer";
|
|
15
|
+
import I from "@mezzanine-ui/react/NotificationCenter";
|
|
15
16
|
//#region src/components/notification-drawer.tsx
|
|
16
|
-
var
|
|
17
|
+
var L = [
|
|
17
18
|
"today",
|
|
18
19
|
"yesterday",
|
|
19
20
|
"past7Days",
|
|
20
21
|
"earlier"
|
|
21
|
-
],
|
|
22
|
+
], R = {
|
|
22
23
|
earlier: "更早",
|
|
23
24
|
past7Days: "過去七天",
|
|
24
25
|
today: "今天",
|
|
25
26
|
yesterday: "昨天"
|
|
26
|
-
},
|
|
27
|
-
function
|
|
28
|
-
let t = e(), { member:
|
|
29
|
-
if (
|
|
30
|
-
|
|
27
|
+
}, z = 50;
|
|
28
|
+
function B() {
|
|
29
|
+
let t = e(), r = f(), { member: i } = n(), { close: a, isOpen: s } = o(), { refreshUnreadCount: c } = l(), u = i?.memberId ?? null, [d, p] = D([]), [m, h] = D(0), [g, _] = D(1), [v, y] = D(!1), [b, x] = D(!1), [S, N] = D(null), [P, B] = D("all"), W = w(async (e, t) => {
|
|
30
|
+
if (u) {
|
|
31
|
+
y(!0), N(null);
|
|
31
32
|
try {
|
|
32
|
-
let n = await
|
|
33
|
+
let n = await A({
|
|
33
34
|
includeRead: !0,
|
|
34
35
|
page: e,
|
|
35
|
-
pageSize:
|
|
36
|
-
recipientMemberId:
|
|
36
|
+
pageSize: z,
|
|
37
|
+
recipientMemberId: u
|
|
37
38
|
});
|
|
38
|
-
|
|
39
|
+
p((e) => t ? [...e, ...n.notifications] : n.notifications), h(n.totalCount), _(e), await c();
|
|
39
40
|
} catch (e) {
|
|
40
|
-
|
|
41
|
+
N(U(e));
|
|
41
42
|
} finally {
|
|
42
|
-
|
|
43
|
+
y(!1);
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
|
-
}, [
|
|
46
|
-
|
|
47
|
-
!
|
|
46
|
+
}, [u, c]);
|
|
47
|
+
T(() => {
|
|
48
|
+
!s || !u || W(1, !1);
|
|
48
49
|
}, [
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
s,
|
|
51
|
+
u,
|
|
52
|
+
W
|
|
52
53
|
]);
|
|
53
|
-
let
|
|
54
|
+
let G = w((e) => {
|
|
54
55
|
let t = e.target.value;
|
|
55
|
-
(t === "all" || t === "read" || t === "unread") &&
|
|
56
|
-
}, []),
|
|
57
|
-
if (!(!
|
|
58
|
-
|
|
56
|
+
(t === "all" || t === "read" || t === "unread") && B(t);
|
|
57
|
+
}, []), K = w(async () => {
|
|
58
|
+
if (!(!u || b)) {
|
|
59
|
+
x(!0), N(null);
|
|
59
60
|
try {
|
|
60
|
-
await
|
|
61
|
+
await j({ recipientMemberId: u }), await W(1, !1);
|
|
61
62
|
} catch (e) {
|
|
62
|
-
|
|
63
|
+
N(U(e));
|
|
63
64
|
} finally {
|
|
64
|
-
|
|
65
|
+
x(!1);
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
}, [
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
]),
|
|
72
|
-
|
|
69
|
+
b,
|
|
70
|
+
u,
|
|
71
|
+
W
|
|
72
|
+
]), q = w(() => {
|
|
73
|
+
v || W(g + 1, !0);
|
|
73
74
|
}, [
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
]),
|
|
78
|
-
if (
|
|
79
|
-
await
|
|
75
|
+
v,
|
|
76
|
+
W,
|
|
77
|
+
g
|
|
78
|
+
]), J = w(async (e) => {
|
|
79
|
+
if (u) try {
|
|
80
|
+
await M({
|
|
80
81
|
id: e,
|
|
81
|
-
readerMemberId:
|
|
82
|
-
}), await
|
|
82
|
+
readerMemberId: u
|
|
83
|
+
}), await W(1, !1);
|
|
83
84
|
} catch (e) {
|
|
84
|
-
|
|
85
|
+
N(U(e));
|
|
85
86
|
}
|
|
86
|
-
}, [
|
|
87
|
-
if (!(!e.instanceId || !
|
|
88
|
-
e.status !== "READ" && (await
|
|
87
|
+
}, [u, W]), Y = w(async (e) => {
|
|
88
|
+
if (!(!e.instanceId || !u)) try {
|
|
89
|
+
e.status !== "READ" && (await M({
|
|
89
90
|
id: e.id,
|
|
90
|
-
readerMemberId:
|
|
91
|
-
}), await
|
|
91
|
+
readerMemberId: u
|
|
92
|
+
}), await c()), a(), t.push(r.caseDetail(e.instanceId));
|
|
92
93
|
} catch (e) {
|
|
93
|
-
|
|
94
|
+
N(U(e));
|
|
94
95
|
}
|
|
95
96
|
}, [
|
|
96
|
-
|
|
97
|
+
a,
|
|
98
|
+
u,
|
|
97
99
|
c,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
]),
|
|
101
|
-
let e = /* @__PURE__ */ new Date(), t =
|
|
100
|
+
t,
|
|
101
|
+
r
|
|
102
|
+
]), X = E(() => d.filter((e) => P === "all" ? !0 : P === "read" ? e.status === "READ" : e.status !== "READ"), [P, d]), Z = E(() => {
|
|
103
|
+
let e = /* @__PURE__ */ new Date(), t = L.reduce((e, t) => (e[t] = [], e), {
|
|
102
104
|
earlier: [],
|
|
103
105
|
past7Days: [],
|
|
104
106
|
today: [],
|
|
105
107
|
yesterday: []
|
|
106
108
|
});
|
|
107
|
-
return
|
|
108
|
-
t[
|
|
109
|
-
}),
|
|
110
|
-
}, [
|
|
111
|
-
return
|
|
112
|
-
bottomGhostActionDisabled:
|
|
113
|
-
bottomGhostActionLoading:
|
|
109
|
+
return X.forEach((n) => {
|
|
110
|
+
t[H(n.createdAt, e)].push(n);
|
|
111
|
+
}), L.map((e) => [e, t[e]]).filter(([, e]) => e.length > 0);
|
|
112
|
+
}, [X]), Q = d.length < m;
|
|
113
|
+
return u ? /* @__PURE__ */ O(F, {
|
|
114
|
+
bottomGhostActionDisabled: b || v,
|
|
115
|
+
bottomGhostActionLoading: b,
|
|
114
116
|
bottomGhostActionText: "全部標為已讀",
|
|
115
117
|
bottomOnGhostActionClick: () => {
|
|
116
|
-
|
|
118
|
+
K();
|
|
117
119
|
},
|
|
118
120
|
bottomOnPrimaryActionClick: () => {
|
|
119
|
-
|
|
121
|
+
q();
|
|
120
122
|
},
|
|
121
|
-
bottomPrimaryActionDisabled: !
|
|
122
|
-
bottomPrimaryActionLoading:
|
|
123
|
-
bottomPrimaryActionText:
|
|
124
|
-
contentKey: `${
|
|
123
|
+
bottomPrimaryActionDisabled: !Q || v,
|
|
124
|
+
bottomPrimaryActionLoading: v && Q,
|
|
125
|
+
bottomPrimaryActionText: Q ? "載入更多" : "已顯示全部",
|
|
126
|
+
contentKey: `${P}:${d.length}`,
|
|
125
127
|
filterAreaAllRadioLabel: "全部",
|
|
126
|
-
filterAreaOnRadioChange:
|
|
128
|
+
filterAreaOnRadioChange: G,
|
|
127
129
|
filterAreaReadRadioLabel: "已讀",
|
|
128
130
|
filterAreaShow: !0,
|
|
129
131
|
filterAreaUnreadRadioLabel: "未讀",
|
|
130
|
-
filterAreaValue:
|
|
132
|
+
filterAreaValue: P,
|
|
131
133
|
headerTitle: "通知中心",
|
|
132
134
|
isBottomDisplay: !0,
|
|
133
135
|
isHeaderDisplay: !0,
|
|
134
|
-
onClose:
|
|
135
|
-
open:
|
|
136
|
+
onClose: a,
|
|
137
|
+
open: s,
|
|
136
138
|
size: "medium",
|
|
137
|
-
children: /* @__PURE__ */
|
|
139
|
+
children: /* @__PURE__ */ k("div", {
|
|
138
140
|
role: "list",
|
|
139
141
|
children: [
|
|
140
|
-
|
|
142
|
+
S ? /* @__PURE__ */ O("p", {
|
|
141
143
|
role: "alert",
|
|
142
144
|
style: {
|
|
143
145
|
color: "var(--mzn-color-text-error, #d92d20)",
|
|
144
146
|
padding: "12px 16px"
|
|
145
147
|
},
|
|
146
|
-
children:
|
|
148
|
+
children: S
|
|
147
149
|
}) : null,
|
|
148
|
-
|
|
150
|
+
Z.length === 0 ? /* @__PURE__ */ O("p", {
|
|
149
151
|
style: {
|
|
150
152
|
color: "var(--mzn-color-text-secondary, #6b7280)",
|
|
151
153
|
padding: "24px 16px",
|
|
152
154
|
textAlign: "center"
|
|
153
155
|
},
|
|
154
|
-
children:
|
|
156
|
+
children: v ? "載入中…" : "目前沒有通知"
|
|
155
157
|
}) : null,
|
|
156
|
-
|
|
157
|
-
appendTips: n ===
|
|
158
|
+
Z.map(([e, t], n) => /* @__PURE__ */ O(C, { children: t.map((r, i) => /* @__PURE__ */ O(I, {
|
|
159
|
+
appendTips: n === Z.length - 1 && i === t.length - 1 && !Q ? "已顯示全部通知" : void 0,
|
|
158
160
|
cancelButtonText: r.status === "READ" ? void 0 : "標為已讀",
|
|
159
161
|
description: r.body,
|
|
160
162
|
onCancel: r.status === "READ" ? void 0 : () => {
|
|
161
|
-
|
|
163
|
+
J(r.id);
|
|
162
164
|
},
|
|
163
165
|
onConfirm: r.instanceId ? () => {
|
|
164
|
-
|
|
166
|
+
Y(r);
|
|
165
167
|
} : void 0,
|
|
166
168
|
confirmButtonText: r.instanceId ? "查看案件" : void 0,
|
|
167
|
-
prependTips: i === 0 ?
|
|
169
|
+
prependTips: i === 0 ? R[e] : void 0,
|
|
168
170
|
reference: r.id,
|
|
169
|
-
severity:
|
|
171
|
+
severity: V(r.type),
|
|
170
172
|
showBadge: r.status !== "READ",
|
|
171
173
|
timeStamp: r.createdAt,
|
|
172
174
|
title: r.title,
|
|
@@ -176,10 +178,10 @@ function L() {
|
|
|
176
178
|
})
|
|
177
179
|
}) : null;
|
|
178
180
|
}
|
|
179
|
-
function
|
|
181
|
+
function V(e) {
|
|
180
182
|
return e === "SLA_OVERDUE" ? "error" : e === "SLA_WARNING" ? "warning" : e === "INSTANCE_COMPLETED" ? "success" : "info";
|
|
181
183
|
}
|
|
182
|
-
function
|
|
184
|
+
function H(e, t) {
|
|
183
185
|
let n = new Date(e);
|
|
184
186
|
if (Number.isNaN(n.getTime())) return "earlier";
|
|
185
187
|
let r = new Date(t.getFullYear(), t.getMonth(), t.getDate()), i = new Date(n.getFullYear(), n.getMonth(), n.getDate());
|
|
@@ -187,22 +189,22 @@ function z(e, t) {
|
|
|
187
189
|
let a = new Date(r);
|
|
188
190
|
return a.setDate(a.getDate() - 1), i.getTime() === a.getTime() ? "yesterday" : (t.getTime() - n.getTime()) / (1e3 * 60 * 60 * 24) <= 7 ? "past7Days" : "earlier";
|
|
189
191
|
}
|
|
190
|
-
function
|
|
192
|
+
function U(e) {
|
|
191
193
|
return e instanceof Error ? e.message : "發生未知錯誤";
|
|
192
194
|
}
|
|
193
195
|
//#endregion
|
|
194
196
|
//#region src/lib/providers.tsx
|
|
195
|
-
function
|
|
196
|
-
return /* @__PURE__ */
|
|
197
|
+
function W({ children: e, locale: t = P.ZH_TW, publicPaths: n, loginPath: r }) {
|
|
198
|
+
return /* @__PURE__ */ O(N, {
|
|
197
199
|
locale: t,
|
|
198
|
-
children: /* @__PURE__ */
|
|
200
|
+
children: /* @__PURE__ */ O(i, {
|
|
199
201
|
publicPaths: n,
|
|
200
202
|
loginPath: r,
|
|
201
|
-
children: /* @__PURE__ */
|
|
203
|
+
children: /* @__PURE__ */ O(c, { children: /* @__PURE__ */ k(s, { children: [e, /* @__PURE__ */ O(B, {})] }) })
|
|
202
204
|
})
|
|
203
205
|
});
|
|
204
206
|
}
|
|
205
207
|
//#endregion
|
|
206
|
-
export { u as AppLayout,
|
|
208
|
+
export { u as AppLayout, b as ApprovalInstanceListPage, i as AuthProvider, x as BPMFormField, p as BPMRoutesProvider, S as DashboardPage, y as MemberPicker, B as NotificationDrawer, s as NotificationDrawerProvider, c as NotificationUnreadProvider, g as OrgUnitPicker, v as PositionPicker, W as Providers, r as RouterAdapterProvider, d as createDefaultBPMRoutes, t as defaultBrowserSearchParams, a as formatDateTime, h as readMemberOption, m as readOrgUnitOption, _ as readPositionOption, n as useAuth, f as useBPMRoutes, o as useNotificationDrawer, l as useNotificationUnread, e as useRouterAdapter };
|
|
207
209
|
|
|
208
210
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/components/notification-drawer.tsx","../src/lib/providers.tsx"],"sourcesContent":["'use client';\n\nimport {\n Fragment,\n useCallback,\n useEffect,\n useMemo,\n useState,\n type ChangeEvent,\n type ReactElement,\n} from 'react';\nimport Drawer from '@mezzanine-ui/react/Drawer';\nimport NotificationCenter from '@mezzanine-ui/react/NotificationCenter';\nimport type { NotificationSeverity } from '@mezzanine-ui/core/notification-center';\nimport {\n listNotifications,\n markAllNotificationsRead,\n markNotificationRead,\n type NotificationRecord,\n type NotificationType,\n} from '@rytass/bpm-core-client/workflow';\nimport { useAuth } from '../lib/auth-provider';\nimport { useNotificationDrawer } from '../lib/notification-drawer-provider';\nimport { useNotificationUnread } from '../lib/notification-unread-provider';\nimport { useRouterAdapter } from '../lib/router-adapter';\n\ntype FilterValue = 'all' | 'read' | 'unread';\n\ntype TimeGroup = 'today' | 'yesterday' | 'past7Days' | 'earlier';\n\nconst TIME_GROUP_ORDER: readonly TimeGroup[] = [\n 'today',\n 'yesterday',\n 'past7Days',\n 'earlier',\n];\n\nconst TIME_GROUP_LABEL: Readonly<Record<TimeGroup, string>> = {\n earlier: '更早',\n past7Days: '過去七天',\n today: '今天',\n yesterday: '昨天',\n};\n\nconst PAGE_SIZE = 50;\n\n/**\n * Right-side notification drawer mounted at the root by `<Providers>`.\n * Opens / closes via `useNotificationDrawer()`, polls\n * `listNotifications()` for the current member, supports filter\n * (`all` / `read` / `unread`), per-row mark-read, bulk mark-all-read, and\n * load-more pagination. Clicking a row with an `instanceId` navigates to\n * `/instances/<id>` via the host's router adapter.\n */\nexport function NotificationDrawer(): ReactElement | null {\n const router = useRouterAdapter();\n const { member } = useAuth();\n const { close, isOpen } = useNotificationDrawer();\n const { refreshUnreadCount } = useNotificationUnread();\n const currentMemberId = member?.memberId ?? null;\n const [rows, setRows] = useState<readonly NotificationRecord[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [page, setPage] = useState(1);\n const [loading, setLoading] = useState(false);\n const [bulkLoading, setBulkLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [filter, setFilter] = useState<FilterValue>('all');\n\n const loadPage = useCallback(\n async (nextPage: number, append: boolean): Promise<void> => {\n if (!currentMemberId) return;\n setLoading(true);\n setError(null);\n try {\n const result = await listNotifications({\n includeRead: true,\n page: nextPage,\n pageSize: PAGE_SIZE,\n recipientMemberId: currentMemberId,\n });\n setRows((current): readonly NotificationRecord[] =>\n append ? [...current, ...result.notifications] : result.notifications,\n );\n setTotalCount(result.totalCount);\n setPage(nextPage);\n await refreshUnreadCount();\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n } finally {\n setLoading(false);\n }\n },\n [currentMemberId, refreshUnreadCount],\n );\n\n useEffect((): void => {\n if (!isOpen || !currentMemberId) return;\n void loadPage(1, false);\n }, [isOpen, currentMemberId, loadPage]);\n\n const handleFilterChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>): void => {\n const next = event.target.value;\n if (next === 'all' || next === 'read' || next === 'unread') setFilter(next);\n },\n [],\n );\n\n const handleMarkAllRead = useCallback(async (): Promise<void> => {\n if (!currentMemberId || bulkLoading) return;\n setBulkLoading(true);\n setError(null);\n try {\n await markAllNotificationsRead({ recipientMemberId: currentMemberId });\n await loadPage(1, false);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n } finally {\n setBulkLoading(false);\n }\n }, [bulkLoading, currentMemberId, loadPage]);\n\n const handleLoadMore = useCallback((): void => {\n if (loading) return;\n void loadPage(page + 1, true);\n }, [loading, loadPage, page]);\n\n const handleMarkRead = useCallback(\n async (id: string): Promise<void> => {\n if (!currentMemberId) return;\n try {\n await markNotificationRead({ id, readerMemberId: currentMemberId });\n await loadPage(1, false);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n }\n },\n [currentMemberId, loadPage],\n );\n\n const handleOpenInstance = useCallback(\n async (record: NotificationRecord): Promise<void> => {\n if (!record.instanceId || !currentMemberId) return;\n try {\n if (record.status !== 'READ') {\n await markNotificationRead({\n id: record.id,\n readerMemberId: currentMemberId,\n });\n await refreshUnreadCount();\n }\n close();\n router.push(`/instances/${record.instanceId}`);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n }\n },\n [close, currentMemberId, refreshUnreadCount, router],\n );\n\n const filteredRows = useMemo(\n (): readonly NotificationRecord[] =>\n rows.filter((row): boolean => {\n if (filter === 'all') return true;\n if (filter === 'read') return row.status === 'READ';\n return row.status !== 'READ';\n }),\n [filter, rows],\n );\n\n const groupedRows = useMemo(\n (): ReadonlyArray<readonly [TimeGroup, readonly NotificationRecord[]]> => {\n const now = new Date();\n const buckets = TIME_GROUP_ORDER.reduce<\n Record<TimeGroup, NotificationRecord[]>\n >(\n (accumulator, group) => {\n accumulator[group] = [];\n return accumulator;\n },\n { earlier: [], past7Days: [], today: [], yesterday: [] },\n );\n filteredRows.forEach((row): void => {\n buckets[resolveTimeGroup(row.createdAt, now)].push(row);\n });\n return TIME_GROUP_ORDER.map(\n (group) => [group, buckets[group]] as const,\n ).filter(([, items]) => items.length > 0);\n },\n [filteredRows],\n );\n\n const hasMore = rows.length < totalCount;\n\n if (!currentMemberId) return null;\n\n return (\n <Drawer\n bottomGhostActionDisabled={bulkLoading || loading}\n bottomGhostActionLoading={bulkLoading}\n bottomGhostActionText=\"全部標為已讀\"\n bottomOnGhostActionClick={(): void => {\n void handleMarkAllRead();\n }}\n bottomOnPrimaryActionClick={(): void => {\n handleLoadMore();\n }}\n bottomPrimaryActionDisabled={!hasMore || loading}\n bottomPrimaryActionLoading={loading && hasMore}\n bottomPrimaryActionText={hasMore ? '載入更多' : '已顯示全部'}\n contentKey={`${filter}:${rows.length}`}\n filterAreaAllRadioLabel=\"全部\"\n filterAreaOnRadioChange={handleFilterChange}\n filterAreaReadRadioLabel=\"已讀\"\n filterAreaShow\n filterAreaUnreadRadioLabel=\"未讀\"\n filterAreaValue={filter}\n headerTitle=\"通知中心\"\n isBottomDisplay\n isHeaderDisplay\n onClose={close}\n open={isOpen}\n size=\"medium\"\n >\n <div role=\"list\">\n {error ? (\n <p\n role=\"alert\"\n style={{\n color: 'var(--mzn-color-text-error, #d92d20)',\n padding: '12px 16px',\n }}\n >\n {error}\n </p>\n ) : null}\n {groupedRows.length === 0 ? (\n <p\n style={{\n color: 'var(--mzn-color-text-secondary, #6b7280)',\n padding: '24px 16px',\n textAlign: 'center',\n }}\n >\n {loading ? '載入中…' : '目前沒有通知'}\n </p>\n ) : null}\n {groupedRows.map(([group, items], groupIndex) => (\n <Fragment key={group}>\n {items.map((record, itemIndex) => (\n <NotificationCenter\n appendTips={\n groupIndex === groupedRows.length - 1 &&\n itemIndex === items.length - 1 &&\n !hasMore\n ? '已顯示全部通知'\n : undefined\n }\n cancelButtonText={\n record.status !== 'READ' ? '標為已讀' : undefined\n }\n description={record.body}\n key={record.id}\n onCancel={\n record.status !== 'READ'\n ? (): void => {\n void handleMarkRead(record.id);\n }\n : undefined\n }\n onConfirm={\n record.instanceId\n ? (): void => {\n void handleOpenInstance(record);\n }\n : undefined\n }\n confirmButtonText={record.instanceId ? '查看案件' : undefined}\n prependTips={itemIndex === 0 ? TIME_GROUP_LABEL[group] : undefined}\n reference={record.id}\n severity={toSeverity(record.type)}\n showBadge={record.status !== 'READ'}\n timeStamp={record.createdAt}\n title={record.title}\n type=\"drawer\"\n />\n ))}\n </Fragment>\n ))}\n </div>\n </Drawer>\n );\n}\n\nfunction toSeverity(type: NotificationType): NotificationSeverity {\n if (type === 'SLA_OVERDUE') return 'error';\n if (type === 'SLA_WARNING') return 'warning';\n if (type === 'INSTANCE_COMPLETED') return 'success';\n return 'info';\n}\n\nfunction resolveTimeGroup(value: string, now: Date): TimeGroup {\n const notificationDate = new Date(value);\n if (Number.isNaN(notificationDate.getTime())) return 'earlier';\n const nowStartOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const notificationStartOfDay = new Date(\n notificationDate.getFullYear(),\n notificationDate.getMonth(),\n notificationDate.getDate(),\n );\n if (notificationStartOfDay.getTime() === nowStartOfDay.getTime()) return 'today';\n const yesterdayStartOfDay = new Date(nowStartOfDay);\n yesterdayStartOfDay.setDate(yesterdayStartOfDay.getDate() - 1);\n if (notificationStartOfDay.getTime() === yesterdayStartOfDay.getTime())\n return 'yesterday';\n const diffInDays =\n (now.getTime() - notificationDate.getTime()) / (1000 * 60 * 60 * 24);\n if (diffInDays <= 7) return 'past7Days';\n return 'earlier';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n","'use client';\n\nimport type { ReactElement, ReactNode } from 'react';\nimport {\n CalendarConfigProviderMoment,\n CalendarLocale,\n} from '@mezzanine-ui/react/moment';\nimport { AuthProvider } from './auth-provider';\nimport { NotificationDrawer } from '../components/notification-drawer';\nimport { NotificationDrawerProvider } from './notification-drawer-provider';\nimport { NotificationUnreadProvider } from './notification-unread-provider';\n\ninterface ProvidersProps {\n readonly children: ReactNode;\n /** Override Mezzanine calendar locale. Defaults to `CalendarLocale.ZH_TW`. */\n readonly locale?: CalendarLocale;\n /**\n * Public paths that should not trigger redirect to `/login` when there\n * is no session. Forwarded to `<AuthProvider>`. Defaults to `['/login']`.\n */\n readonly publicPaths?: readonly string[];\n /** Where to send unauthenticated users. Defaults to `'/login'`. */\n readonly loginPath?: string;\n}\n\n/**\n * One-stop BPM admin provider stack. Wires:\n *\n * - Mezzanine UI calendar locale (moment-based, `ZH_TW` by default)\n * - `<AuthProvider>` (BPM session via REST `/auth/*`)\n * - `<NotificationUnreadProvider>` (polls unread count)\n * - `<NotificationDrawerProvider>` (controls drawer open/close state)\n * - `<NotificationDrawer />` mounted at the root so the bell-icon button in\n * `<AppLayout />` can open it.\n *\n * Consumer hosts wrap this **inside** a `<RouterAdapterProvider>` (provided\n * by the `pages/*` subpath shims when consuming via Next.js, or wired by\n * hand for other frameworks).\n */\nexport function Providers({\n children,\n locale = CalendarLocale.ZH_TW,\n publicPaths,\n loginPath,\n}: ProvidersProps): ReactElement {\n return (\n <CalendarConfigProviderMoment locale={locale}>\n <AuthProvider publicPaths={publicPaths} loginPath={loginPath}>\n <NotificationUnreadProvider>\n <NotificationDrawerProvider>\n {children}\n <NotificationDrawer />\n </NotificationDrawerProvider>\n </NotificationUnreadProvider>\n </AuthProvider>\n </CalendarConfigProviderMoment>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/components/notification-drawer.tsx","../src/lib/providers.tsx"],"sourcesContent":["'use client';\n\nimport {\n Fragment,\n useCallback,\n useEffect,\n useMemo,\n useState,\n type ChangeEvent,\n type ReactElement,\n} from 'react';\nimport Drawer from '@mezzanine-ui/react/Drawer';\nimport NotificationCenter from '@mezzanine-ui/react/NotificationCenter';\nimport type { NotificationSeverity } from '@mezzanine-ui/core/notification-center';\nimport {\n listNotifications,\n markAllNotificationsRead,\n markNotificationRead,\n type NotificationRecord,\n type NotificationType,\n} from '@rytass/bpm-core-client/workflow';\nimport { useAuth } from '../lib/auth-provider';\nimport { useNotificationDrawer } from '../lib/notification-drawer-provider';\nimport { useNotificationUnread } from '../lib/notification-unread-provider';\nimport { useRouterAdapter } from '../lib/router-adapter';\nimport { useBPMRoutes } from '../lib/routes-config';\n\ntype FilterValue = 'all' | 'read' | 'unread';\n\ntype TimeGroup = 'today' | 'yesterday' | 'past7Days' | 'earlier';\n\nconst TIME_GROUP_ORDER: readonly TimeGroup[] = [\n 'today',\n 'yesterday',\n 'past7Days',\n 'earlier',\n];\n\nconst TIME_GROUP_LABEL: Readonly<Record<TimeGroup, string>> = {\n earlier: '更早',\n past7Days: '過去七天',\n today: '今天',\n yesterday: '昨天',\n};\n\nconst PAGE_SIZE = 50;\n\n/**\n * Right-side notification drawer mounted at the root by `<Providers>`.\n * Opens / closes via `useNotificationDrawer()`, polls\n * `listNotifications()` for the current member, supports filter\n * (`all` / `read` / `unread`), per-row mark-read, bulk mark-all-read, and\n * load-more pagination. Clicking a row with an `instanceId` navigates to\n * `/instances/<id>` via the host's router adapter.\n */\nexport function NotificationDrawer(): ReactElement | null {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const { close, isOpen } = useNotificationDrawer();\n const { refreshUnreadCount } = useNotificationUnread();\n const currentMemberId = member?.memberId ?? null;\n const [rows, setRows] = useState<readonly NotificationRecord[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [page, setPage] = useState(1);\n const [loading, setLoading] = useState(false);\n const [bulkLoading, setBulkLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [filter, setFilter] = useState<FilterValue>('all');\n\n const loadPage = useCallback(\n async (nextPage: number, append: boolean): Promise<void> => {\n if (!currentMemberId) return;\n setLoading(true);\n setError(null);\n try {\n const result = await listNotifications({\n includeRead: true,\n page: nextPage,\n pageSize: PAGE_SIZE,\n recipientMemberId: currentMemberId,\n });\n setRows((current): readonly NotificationRecord[] =>\n append ? [...current, ...result.notifications] : result.notifications,\n );\n setTotalCount(result.totalCount);\n setPage(nextPage);\n await refreshUnreadCount();\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n } finally {\n setLoading(false);\n }\n },\n [currentMemberId, refreshUnreadCount],\n );\n\n useEffect((): void => {\n if (!isOpen || !currentMemberId) return;\n void loadPage(1, false);\n }, [isOpen, currentMemberId, loadPage]);\n\n const handleFilterChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>): void => {\n const next = event.target.value;\n if (next === 'all' || next === 'read' || next === 'unread') setFilter(next);\n },\n [],\n );\n\n const handleMarkAllRead = useCallback(async (): Promise<void> => {\n if (!currentMemberId || bulkLoading) return;\n setBulkLoading(true);\n setError(null);\n try {\n await markAllNotificationsRead({ recipientMemberId: currentMemberId });\n await loadPage(1, false);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n } finally {\n setBulkLoading(false);\n }\n }, [bulkLoading, currentMemberId, loadPage]);\n\n const handleLoadMore = useCallback((): void => {\n if (loading) return;\n void loadPage(page + 1, true);\n }, [loading, loadPage, page]);\n\n const handleMarkRead = useCallback(\n async (id: string): Promise<void> => {\n if (!currentMemberId) return;\n try {\n await markNotificationRead({ id, readerMemberId: currentMemberId });\n await loadPage(1, false);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n }\n },\n [currentMemberId, loadPage],\n );\n\n const handleOpenInstance = useCallback(\n async (record: NotificationRecord): Promise<void> => {\n if (!record.instanceId || !currentMemberId) return;\n try {\n if (record.status !== 'READ') {\n await markNotificationRead({\n id: record.id,\n readerMemberId: currentMemberId,\n });\n await refreshUnreadCount();\n }\n close();\n router.push(routes.caseDetail(record.instanceId));\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n }\n },\n [close, currentMemberId, refreshUnreadCount, router, routes],\n );\n\n const filteredRows = useMemo(\n (): readonly NotificationRecord[] =>\n rows.filter((row): boolean => {\n if (filter === 'all') return true;\n if (filter === 'read') return row.status === 'READ';\n return row.status !== 'READ';\n }),\n [filter, rows],\n );\n\n const groupedRows = useMemo(\n (): ReadonlyArray<readonly [TimeGroup, readonly NotificationRecord[]]> => {\n const now = new Date();\n const buckets = TIME_GROUP_ORDER.reduce<\n Record<TimeGroup, NotificationRecord[]>\n >(\n (accumulator, group) => {\n accumulator[group] = [];\n return accumulator;\n },\n { earlier: [], past7Days: [], today: [], yesterday: [] },\n );\n filteredRows.forEach((row): void => {\n buckets[resolveTimeGroup(row.createdAt, now)].push(row);\n });\n return TIME_GROUP_ORDER.map(\n (group) => [group, buckets[group]] as const,\n ).filter(([, items]) => items.length > 0);\n },\n [filteredRows],\n );\n\n const hasMore = rows.length < totalCount;\n\n if (!currentMemberId) return null;\n\n return (\n <Drawer\n bottomGhostActionDisabled={bulkLoading || loading}\n bottomGhostActionLoading={bulkLoading}\n bottomGhostActionText=\"全部標為已讀\"\n bottomOnGhostActionClick={(): void => {\n void handleMarkAllRead();\n }}\n bottomOnPrimaryActionClick={(): void => {\n handleLoadMore();\n }}\n bottomPrimaryActionDisabled={!hasMore || loading}\n bottomPrimaryActionLoading={loading && hasMore}\n bottomPrimaryActionText={hasMore ? '載入更多' : '已顯示全部'}\n contentKey={`${filter}:${rows.length}`}\n filterAreaAllRadioLabel=\"全部\"\n filterAreaOnRadioChange={handleFilterChange}\n filterAreaReadRadioLabel=\"已讀\"\n filterAreaShow\n filterAreaUnreadRadioLabel=\"未讀\"\n filterAreaValue={filter}\n headerTitle=\"通知中心\"\n isBottomDisplay\n isHeaderDisplay\n onClose={close}\n open={isOpen}\n size=\"medium\"\n >\n <div role=\"list\">\n {error ? (\n <p\n role=\"alert\"\n style={{\n color: 'var(--mzn-color-text-error, #d92d20)',\n padding: '12px 16px',\n }}\n >\n {error}\n </p>\n ) : null}\n {groupedRows.length === 0 ? (\n <p\n style={{\n color: 'var(--mzn-color-text-secondary, #6b7280)',\n padding: '24px 16px',\n textAlign: 'center',\n }}\n >\n {loading ? '載入中…' : '目前沒有通知'}\n </p>\n ) : null}\n {groupedRows.map(([group, items], groupIndex) => (\n <Fragment key={group}>\n {items.map((record, itemIndex) => (\n <NotificationCenter\n appendTips={\n groupIndex === groupedRows.length - 1 &&\n itemIndex === items.length - 1 &&\n !hasMore\n ? '已顯示全部通知'\n : undefined\n }\n cancelButtonText={\n record.status !== 'READ' ? '標為已讀' : undefined\n }\n description={record.body}\n key={record.id}\n onCancel={\n record.status !== 'READ'\n ? (): void => {\n void handleMarkRead(record.id);\n }\n : undefined\n }\n onConfirm={\n record.instanceId\n ? (): void => {\n void handleOpenInstance(record);\n }\n : undefined\n }\n confirmButtonText={record.instanceId ? '查看案件' : undefined}\n prependTips={itemIndex === 0 ? TIME_GROUP_LABEL[group] : undefined}\n reference={record.id}\n severity={toSeverity(record.type)}\n showBadge={record.status !== 'READ'}\n timeStamp={record.createdAt}\n title={record.title}\n type=\"drawer\"\n />\n ))}\n </Fragment>\n ))}\n </div>\n </Drawer>\n );\n}\n\nfunction toSeverity(type: NotificationType): NotificationSeverity {\n if (type === 'SLA_OVERDUE') return 'error';\n if (type === 'SLA_WARNING') return 'warning';\n if (type === 'INSTANCE_COMPLETED') return 'success';\n return 'info';\n}\n\nfunction resolveTimeGroup(value: string, now: Date): TimeGroup {\n const notificationDate = new Date(value);\n if (Number.isNaN(notificationDate.getTime())) return 'earlier';\n const nowStartOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const notificationStartOfDay = new Date(\n notificationDate.getFullYear(),\n notificationDate.getMonth(),\n notificationDate.getDate(),\n );\n if (notificationStartOfDay.getTime() === nowStartOfDay.getTime()) return 'today';\n const yesterdayStartOfDay = new Date(nowStartOfDay);\n yesterdayStartOfDay.setDate(yesterdayStartOfDay.getDate() - 1);\n if (notificationStartOfDay.getTime() === yesterdayStartOfDay.getTime())\n return 'yesterday';\n const diffInDays =\n (now.getTime() - notificationDate.getTime()) / (1000 * 60 * 60 * 24);\n if (diffInDays <= 7) return 'past7Days';\n return 'earlier';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n","'use client';\n\nimport type { ReactElement, ReactNode } from 'react';\nimport {\n CalendarConfigProviderMoment,\n CalendarLocale,\n} from '@mezzanine-ui/react/moment';\nimport { AuthProvider } from './auth-provider';\nimport { NotificationDrawer } from '../components/notification-drawer';\nimport { NotificationDrawerProvider } from './notification-drawer-provider';\nimport { NotificationUnreadProvider } from './notification-unread-provider';\n\ninterface ProvidersProps {\n readonly children: ReactNode;\n /** Override Mezzanine calendar locale. Defaults to `CalendarLocale.ZH_TW`. */\n readonly locale?: CalendarLocale;\n /**\n * Public paths that should not trigger redirect to `/login` when there\n * is no session. Forwarded to `<AuthProvider>`. Defaults to `['/login']`.\n */\n readonly publicPaths?: readonly string[];\n /** Where to send unauthenticated users. Defaults to `'/login'`. */\n readonly loginPath?: string;\n}\n\n/**\n * One-stop BPM admin provider stack. Wires:\n *\n * - Mezzanine UI calendar locale (moment-based, `ZH_TW` by default)\n * - `<AuthProvider>` (BPM session via REST `/auth/*`)\n * - `<NotificationUnreadProvider>` (polls unread count)\n * - `<NotificationDrawerProvider>` (controls drawer open/close state)\n * - `<NotificationDrawer />` mounted at the root so the bell-icon button in\n * `<AppLayout />` can open it.\n *\n * Consumer hosts wrap this **inside** a `<RouterAdapterProvider>` (provided\n * by the `pages/*` subpath shims when consuming via Next.js, or wired by\n * hand for other frameworks).\n */\nexport function Providers({\n children,\n locale = CalendarLocale.ZH_TW,\n publicPaths,\n loginPath,\n}: ProvidersProps): ReactElement {\n return (\n <CalendarConfigProviderMoment locale={locale}>\n <AuthProvider publicPaths={publicPaths} loginPath={loginPath}>\n <NotificationUnreadProvider>\n <NotificationDrawerProvider>\n {children}\n <NotificationDrawer />\n </NotificationDrawerProvider>\n </NotificationUnreadProvider>\n </AuthProvider>\n </CalendarConfigProviderMoment>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Framework-agnostic path mapping every BPM view uses for internal
|
|
4
|
+
* cross-navigation. When a host embeds BPM under a non-root prefix
|
|
5
|
+
* (e.g. `/workspace/bpm/*`) it provides its own implementation through
|
|
6
|
+
* `<BPMRoutesProvider value={...}>`; otherwise the default factory
|
|
7
|
+
* preserves the historical `/instances/:id`, `/templates`, etc. paths.
|
|
8
|
+
*
|
|
9
|
+
* Function-shape (instead of string templates) means:
|
|
10
|
+
* - Optional and multi-param routes can branch on argument presence
|
|
11
|
+
* (`caseNew(templateId?)`).
|
|
12
|
+
* - Query-string composition stays inside the host's resolver, not the
|
|
13
|
+
* view.
|
|
14
|
+
* - TypeScript flags missing arguments at compile time.
|
|
15
|
+
*
|
|
16
|
+
* Mirror sibling: {@link RouterAdapter} owns *navigation primitives*
|
|
17
|
+
* (`push`, `replace`, `pathname`); `BPMRoutes` owns *path strings*. The
|
|
18
|
+
* two compose: views call `router.push(routes.caseDetail(id))`.
|
|
19
|
+
*/
|
|
20
|
+
export interface BPMRoutes {
|
|
21
|
+
/** Workflow dashboard landing. Used by sidebar + dashboard tiles. */
|
|
22
|
+
dashboard(): string;
|
|
23
|
+
/** Inbox (待簽) — pending tasks assigned to the current member. */
|
|
24
|
+
inbox(): string;
|
|
25
|
+
/** Sent (我發起的) — instances the current member initiated. */
|
|
26
|
+
sent(): string;
|
|
27
|
+
/** CC (抄送給我) — instances the current member is copied on. */
|
|
28
|
+
cc(): string;
|
|
29
|
+
/** Cross-view search. */
|
|
30
|
+
search(): string;
|
|
31
|
+
/** Personal delegation rules. */
|
|
32
|
+
delegations(): string;
|
|
33
|
+
/** Notification list. */
|
|
34
|
+
notifications(): string;
|
|
35
|
+
/** Detail page for one approval instance. */
|
|
36
|
+
caseDetail(instanceId: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Launch a new approval instance. When `templateId` is passed, the
|
|
39
|
+
* launch form is pre-populated for that template.
|
|
40
|
+
*/
|
|
41
|
+
caseNew(templateId?: string): string;
|
|
42
|
+
/** Template index. */
|
|
43
|
+
templates(): string;
|
|
44
|
+
/** Template designer (xyflow canvas). */
|
|
45
|
+
templateDesigner(templateId: string): string;
|
|
46
|
+
/** Template version history. */
|
|
47
|
+
templateVersions(templateId: string): string;
|
|
48
|
+
/** Template categories admin. */
|
|
49
|
+
templateCategories(): string;
|
|
50
|
+
/** Form definitions index. */
|
|
51
|
+
forms(): string;
|
|
52
|
+
/** Form-builder (CodeMirror schema editor + preview). */
|
|
53
|
+
formBuilder(formId: string): string;
|
|
54
|
+
/** Per-member notification preferences. */
|
|
55
|
+
notificationSettings(): string;
|
|
56
|
+
/** Admin: organization tree management. */
|
|
57
|
+
adminOrgs(): string;
|
|
58
|
+
/** Admin: member directory mapping. */
|
|
59
|
+
adminUsers(): string;
|
|
60
|
+
/** Admin: delegation rule management. */
|
|
61
|
+
adminDelegations(): string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Factory for the default `BPMRoutes` value. Reproduces the exact path
|
|
65
|
+
* literals BPM views used before `BPMRoutesContext` existed, so existing
|
|
66
|
+
* hosts (no provider mounted) keep working unchanged.
|
|
67
|
+
*/
|
|
68
|
+
export declare function createDefaultBPMRoutes(): BPMRoutes;
|
|
69
|
+
export interface BPMRoutesProviderProps {
|
|
70
|
+
/**
|
|
71
|
+
* Override the path mapping. Provide a full implementation, or spread
|
|
72
|
+
* the default and override individual entries:
|
|
73
|
+
*
|
|
74
|
+
* ```tsx
|
|
75
|
+
* <BPMRoutesProvider value={{
|
|
76
|
+
* ...createDefaultBPMRoutes(),
|
|
77
|
+
* caseDetail: (id) => `/workspace/cases/${id}`,
|
|
78
|
+
* }}>
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
readonly value?: BPMRoutes;
|
|
82
|
+
readonly children: ReactNode;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Wraps the BPM React tree with a {@link BPMRoutes} value. Mounting the
|
|
86
|
+
* provider is **optional** — `useBPMRoutes()` falls back to
|
|
87
|
+
* {@link createDefaultBPMRoutes} when no provider is present. Use it
|
|
88
|
+
* only when the host needs to remap BPM's internal paths.
|
|
89
|
+
*/
|
|
90
|
+
export declare function BPMRoutesProvider({ value, children, }: BPMRoutesProviderProps): React.ReactElement;
|
|
91
|
+
/**
|
|
92
|
+
* Reads the host-configured {@link BPMRoutes}. Falls back to
|
|
93
|
+
* {@link createDefaultBPMRoutes} when no `<BPMRoutesProvider>` ancestor
|
|
94
|
+
* is mounted, so views remain self-contained.
|
|
95
|
+
*/
|
|
96
|
+
export declare function useBPMRoutes(): BPMRoutes;
|
package/dist/next/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});
|
|
1
|
+
"use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../chunks/routes-config-2aKbWq2H.cjs");let t=require("react"),n=require("react/jsx-runtime"),r=require("next/navigation"),i=require("@rytass/bpm-core-react");function a({children:e}){let a=(0,r.useRouter)(),o=(0,r.usePathname)(),s=(0,r.useSearchParams)();return(0,n.jsx)(i.RouterAdapterProvider,{value:(0,t.useMemo)(()=>({pathname:o,push:e=>a.push(e),replace:e=>a.replace(e),back:()=>a.back(),searchParams:()=>new URLSearchParams(s?.toString()??``)}),[a,o,s]),children:(0,n.jsx)(i.Providers,{children:e})})}function o({children:e}){return(0,n.jsx)(t.Suspense,{fallback:null,children:(0,n.jsx)(a,{children:e})})}exports.BPMNextProviders=o,exports.BPMRoutesProvider=e.t,exports.createDefaultBPMRoutes=e.n,exports.useBPMRoutes=e.r;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/next/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/next/BPMNextProviders.tsx"],"sourcesContent":["'use client';\n\n// One-line Next.js App Router shim for BPM. Reads `next/navigation` hooks,\n// builds a `RouterAdapter`, then composes `<RouterAdapterProvider>` and the\n// shared `<BPMProviders>`. Wrapped in `<Suspense>` so static prerender of\n// routes like `/404` does not fail on `useSearchParams()` during `next build`.\n\nimport { Suspense, useMemo, type ReactElement, type ReactNode } from 'react';\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation';\nimport {\n Providers as BPMProviders,\n RouterAdapterProvider,\n type RouterAdapter,\n} from '@rytass/bpm-core-react';\n\ninterface BPMNextProvidersProps {\n readonly children: ReactNode;\n}\n\nfunction BPMNextProvidersBody({\n children,\n}: BPMNextProvidersProps): ReactElement {\n const nextRouter = useRouter();\n const pathname = usePathname();\n const searchParams = useSearchParams();\n\n const adapter = useMemo<RouterAdapter>(\n () => ({\n pathname,\n push: (href: string): void => nextRouter.push(href),\n replace: (href: string): void => nextRouter.replace(href),\n back: (): void => nextRouter.back(),\n searchParams: (): URLSearchParams =>\n new URLSearchParams(searchParams?.toString() ?? ''),\n }),\n [nextRouter, pathname, searchParams],\n );\n\n return (\n <RouterAdapterProvider value={adapter}>\n <BPMProviders>{children}</BPMProviders>\n </RouterAdapterProvider>\n );\n}\n\nexport function BPMNextProviders({\n children,\n}: BPMNextProvidersProps): ReactElement {\n return (\n <Suspense fallback={null}>\n <BPMNextProvidersBody>{children}</BPMNextProvidersBody>\n </Suspense>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/next/BPMNextProviders.tsx"],"sourcesContent":["'use client';\n\n// One-line Next.js App Router shim for BPM. Reads `next/navigation` hooks,\n// builds a `RouterAdapter`, then composes `<RouterAdapterProvider>` and the\n// shared `<BPMProviders>`. Wrapped in `<Suspense>` so static prerender of\n// routes like `/404` does not fail on `useSearchParams()` during `next build`.\n\nimport { Suspense, useMemo, type ReactElement, type ReactNode } from 'react';\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation';\nimport {\n Providers as BPMProviders,\n RouterAdapterProvider,\n type RouterAdapter,\n} from '@rytass/bpm-core-react';\n\ninterface BPMNextProvidersProps {\n readonly children: ReactNode;\n}\n\nfunction BPMNextProvidersBody({\n children,\n}: BPMNextProvidersProps): ReactElement {\n const nextRouter = useRouter();\n const pathname = usePathname();\n const searchParams = useSearchParams();\n\n const adapter = useMemo<RouterAdapter>(\n () => ({\n pathname,\n push: (href: string): void => nextRouter.push(href),\n replace: (href: string): void => nextRouter.replace(href),\n back: (): void => nextRouter.back(),\n searchParams: (): URLSearchParams =>\n new URLSearchParams(searchParams?.toString() ?? ''),\n }),\n [nextRouter, pathname, searchParams],\n );\n\n return (\n <RouterAdapterProvider value={adapter}>\n <BPMProviders>{children}</BPMProviders>\n </RouterAdapterProvider>\n );\n}\n\nexport function BPMNextProviders({\n children,\n}: BPMNextProvidersProps): ReactElement {\n return (\n <Suspense fallback={null}>\n <BPMNextProvidersBody>{children}</BPMNextProvidersBody>\n </Suspense>\n );\n}\n"],"mappings":"+PAmBA,SAAS,EAAqB,CAC5B,YACsC,CACtC,IAAM,GAAA,EAAA,EAAA,WAAuB,EACvB,GAAA,EAAA,EAAA,aAAuB,EACvB,GAAA,EAAA,EAAA,iBAA+B,EAcrC,OACE,EAAA,EAAA,KAAC,EAAA,sBAAD,CAAuB,OAAA,EAAA,EAAA,cAZhB,CACL,WACA,KAAO,GAAuB,EAAW,KAAK,CAAI,EAClD,QAAU,GAAuB,EAAW,QAAQ,CAAI,EACxD,SAAkB,EAAW,KAAK,EAClC,iBACE,IAAI,gBAAgB,GAAc,SAAS,GAAK,EAAE,CACtD,GACA,CAAC,EAAY,EAAU,CAAY,CAIL,YAC5B,EAAA,EAAA,KAAC,EAAA,UAAD,CAAe,UAAuB,CAAA,CACjB,CAAA,CAE3B,CAEA,SAAgB,EAAiB,CAC/B,YACsC,CACtC,OACE,EAAA,EAAA,KAAC,EAAA,SAAD,CAAU,SAAU,eAClB,EAAA,EAAA,KAAC,EAAD,CAAuB,UAA+B,CAAA,CAC9C,CAAA,CAEd"}
|
package/dist/next/index.d.ts
CHANGED
package/dist/next/index.js
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { n as e, r as t, t as n } from "../chunks/routes-config-dxahImVe.js";
|
|
3
|
+
import { Suspense as r, useMemo as i } from "react";
|
|
4
|
+
import { jsx as a } from "react/jsx-runtime";
|
|
5
|
+
import { usePathname as o, useRouter as s, useSearchParams as c } from "next/navigation";
|
|
6
|
+
import { Providers as l, RouterAdapterProvider as u } from "@rytass/bpm-core-react";
|
|
6
7
|
//#region src/next/BPMNextProviders.tsx
|
|
7
|
-
function
|
|
8
|
-
let
|
|
9
|
-
return /* @__PURE__ */
|
|
10
|
-
value:
|
|
11
|
-
pathname:
|
|
12
|
-
push: (e) =>
|
|
13
|
-
replace: (e) =>
|
|
14
|
-
back: () =>
|
|
15
|
-
searchParams: () => new URLSearchParams(
|
|
8
|
+
function d({ children: e }) {
|
|
9
|
+
let t = s(), n = o(), r = c();
|
|
10
|
+
return /* @__PURE__ */ a(u, {
|
|
11
|
+
value: i(() => ({
|
|
12
|
+
pathname: n,
|
|
13
|
+
push: (e) => t.push(e),
|
|
14
|
+
replace: (e) => t.replace(e),
|
|
15
|
+
back: () => t.back(),
|
|
16
|
+
searchParams: () => new URLSearchParams(r?.toString() ?? "")
|
|
16
17
|
}), [
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
t,
|
|
19
|
+
n,
|
|
20
|
+
r
|
|
20
21
|
]),
|
|
21
|
-
children: /* @__PURE__ */
|
|
22
|
+
children: /* @__PURE__ */ a(l, { children: e })
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
|
-
function
|
|
25
|
-
return /* @__PURE__ */
|
|
25
|
+
function f({ children: e }) {
|
|
26
|
+
return /* @__PURE__ */ a(r, {
|
|
26
27
|
fallback: null,
|
|
27
|
-
children: /* @__PURE__ */
|
|
28
|
+
children: /* @__PURE__ */ a(d, { children: e })
|
|
28
29
|
});
|
|
29
30
|
}
|
|
30
31
|
//#endregion
|
|
31
|
-
export {
|
|
32
|
+
export { f as BPMNextProviders, n as BPMRoutesProvider, e as createDefaultBPMRoutes, t as useBPMRoutes };
|
|
32
33
|
|
|
33
34
|
//# sourceMappingURL=index.js.map
|
package/dist/next/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/next/BPMNextProviders.tsx"],"sourcesContent":["'use client';\n\n// One-line Next.js App Router shim for BPM. Reads `next/navigation` hooks,\n// builds a `RouterAdapter`, then composes `<RouterAdapterProvider>` and the\n// shared `<BPMProviders>`. Wrapped in `<Suspense>` so static prerender of\n// routes like `/404` does not fail on `useSearchParams()` during `next build`.\n\nimport { Suspense, useMemo, type ReactElement, type ReactNode } from 'react';\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation';\nimport {\n Providers as BPMProviders,\n RouterAdapterProvider,\n type RouterAdapter,\n} from '@rytass/bpm-core-react';\n\ninterface BPMNextProvidersProps {\n readonly children: ReactNode;\n}\n\nfunction BPMNextProvidersBody({\n children,\n}: BPMNextProvidersProps): ReactElement {\n const nextRouter = useRouter();\n const pathname = usePathname();\n const searchParams = useSearchParams();\n\n const adapter = useMemo<RouterAdapter>(\n () => ({\n pathname,\n push: (href: string): void => nextRouter.push(href),\n replace: (href: string): void => nextRouter.replace(href),\n back: (): void => nextRouter.back(),\n searchParams: (): URLSearchParams =>\n new URLSearchParams(searchParams?.toString() ?? ''),\n }),\n [nextRouter, pathname, searchParams],\n );\n\n return (\n <RouterAdapterProvider value={adapter}>\n <BPMProviders>{children}</BPMProviders>\n </RouterAdapterProvider>\n );\n}\n\nexport function BPMNextProviders({\n children,\n}: BPMNextProvidersProps): ReactElement {\n return (\n <Suspense fallback={null}>\n <BPMNextProvidersBody>{children}</BPMNextProvidersBody>\n </Suspense>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/next/BPMNextProviders.tsx"],"sourcesContent":["'use client';\n\n// One-line Next.js App Router shim for BPM. Reads `next/navigation` hooks,\n// builds a `RouterAdapter`, then composes `<RouterAdapterProvider>` and the\n// shared `<BPMProviders>`. Wrapped in `<Suspense>` so static prerender of\n// routes like `/404` does not fail on `useSearchParams()` during `next build`.\n\nimport { Suspense, useMemo, type ReactElement, type ReactNode } from 'react';\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation';\nimport {\n Providers as BPMProviders,\n RouterAdapterProvider,\n type RouterAdapter,\n} from '@rytass/bpm-core-react';\n\ninterface BPMNextProvidersProps {\n readonly children: ReactNode;\n}\n\nfunction BPMNextProvidersBody({\n children,\n}: BPMNextProvidersProps): ReactElement {\n const nextRouter = useRouter();\n const pathname = usePathname();\n const searchParams = useSearchParams();\n\n const adapter = useMemo<RouterAdapter>(\n () => ({\n pathname,\n push: (href: string): void => nextRouter.push(href),\n replace: (href: string): void => nextRouter.replace(href),\n back: (): void => nextRouter.back(),\n searchParams: (): URLSearchParams =>\n new URLSearchParams(searchParams?.toString() ?? ''),\n }),\n [nextRouter, pathname, searchParams],\n );\n\n return (\n <RouterAdapterProvider value={adapter}>\n <BPMProviders>{children}</BPMProviders>\n </RouterAdapterProvider>\n );\n}\n\nexport function BPMNextProviders({\n children,\n}: BPMNextProvidersProps): ReactElement {\n return (\n <Suspense fallback={null}>\n <BPMNextProvidersBody>{children}</BPMNextProvidersBody>\n </Suspense>\n );\n}\n"],"mappings":";;;;;;;AAmBA,SAAS,EAAqB,EAC5B,eACsC;CACtC,IAAM,IAAa,EAAU,GACvB,IAAW,EAAY,GACvB,IAAe,EAAgB;CAcrC,OACE,kBAAC,GAAD;EAAuB,OAbT,SACP;GACL;GACA,OAAO,MAAuB,EAAW,KAAK,CAAI;GAClD,UAAU,MAAuB,EAAW,QAAQ,CAAI;GACxD,YAAkB,EAAW,KAAK;GAClC,oBACE,IAAI,gBAAgB,GAAc,SAAS,KAAK,EAAE;EACtD,IACA;GAAC;GAAY;GAAU;EAAY,CAIL;YAC5B,kBAAC,GAAD,EAAe,YAAuB,CAAA;CACjB,CAAA;AAE3B;AAEA,SAAgB,EAAiB,EAC/B,eACsC;CACtC,OACE,kBAAC,GAAD;EAAU,UAAU;YAClB,kBAAC,GAAD,EAAuB,YAA+B,CAAA;CAC9C,CAAA;AAEd"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/delegations-
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/delegations-CvtwTXNP.cjs");let t=require("react/jsx-runtime");var n={title:`代理設定 | BPM Admin`,description:`設定簽核代理規則,讓符合範圍的待簽任務自動改派給代理人。`};function r(){return(0,t.jsx)(e.t,{})}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/orgs-
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/orgs-YMiVLNvL.cjs");let t=require("react/jsx-runtime");var n={title:`組織管理 | BPM Admin`,description:`維護組織樹、職位、會員歸屬與簽核主管解析規則。`};function r(){return(0,t.jsx)(e.t,{})}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/users-
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../../../chunks/users-3ySyUW4u.cjs");let t=require("react/jsx-runtime");var n={title:`會員對照 | BPM Admin`,description:`檢視 BPM 內部會員組織歸屬與主管解析。`};function r(){return(0,t.jsx)(e.t,{})}exports.default=r,exports.metadata=n;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|