@plumile/backoffice-react 0.1.98 → 0.1.101
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/lib/esm/AcceptInvitationScreen-B1IPafwD.js.map +1 -1
- package/lib/esm/BackofficeAcceptInvitationPage-CEtApVwL.js.map +1 -1
- package/lib/esm/{BackofficeDashboardPage-YWvoQODn.js → BackofficeDashboardPage-r8vK_JA6.js} +4 -2
- package/lib/esm/BackofficeDashboardPage-r8vK_JA6.js.map +1 -0
- package/lib/esm/BackofficeDetailPayload-P61MDRLE.js.map +1 -1
- package/lib/esm/BackofficeEntityActionFormDialog-BgRTJ_JS.js.map +1 -1
- package/lib/esm/BackofficeEntityDetailLayoutContext-C_tBqkVq.js.map +1 -1
- package/lib/esm/BackofficeEntityDetailLayoutPage-DXjRqvcZ.js.map +1 -1
- package/lib/esm/{BackofficeEntityDetailPage-DPFXbJxC.js → BackofficeEntityDetailPage-CwzKp_Yw.js} +25 -17
- package/lib/esm/BackofficeEntityDetailPage-CwzKp_Yw.js.map +1 -0
- package/lib/esm/BackofficeEntityDetailUnknownPageRedirect-DRWTeox-.js.map +1 -1
- package/lib/esm/{BackofficeEntityListPage-C8Ucmc_E.js → BackofficeEntityListPage-DVT3rrfa.js} +5 -3
- package/lib/esm/BackofficeEntityListPage-DVT3rrfa.js.map +1 -0
- package/lib/esm/BackofficeErrorBoundary-BwRVSDHU.js.map +1 -1
- package/lib/esm/BackofficeLayoutPage-DQ0sVv24.js +609 -0
- package/lib/esm/BackofficeLayoutPage-DQ0sVv24.js.map +1 -0
- package/lib/esm/BackofficeLoginPage-Cc3kcOQV.js.map +1 -1
- package/lib/esm/BackofficePasswordResetCompletePage-CF_0t3Nq.js.map +1 -1
- package/lib/esm/BackofficePasswordResetRequestPage-BJOrQXcy.js.map +1 -1
- package/lib/esm/{BackofficeRightPageLayout-DZQvIHnj.js → BackofficeRightPageLayout-hexJmpam.js} +36 -30
- package/lib/esm/BackofficeRightPageLayout-hexJmpam.js.map +1 -0
- package/lib/esm/BackofficeTopbarPortalContext-iD7dm4_h.js.map +1 -1
- package/lib/esm/BackofficeVerifyEmailPage-C81LlsNM.js.map +1 -1
- package/lib/esm/EntityFilterValue-BWUdPBwp.js.map +1 -1
- package/lib/esm/EntityIdPickerDialog-Yhmr-WsV.js.map +1 -1
- package/lib/esm/{LazyBackofficeEntityActionFormDialog-DVPQyWlr.js → LazyBackofficeEntityActionFormDialog-L8xwaGqH.js} +110 -123
- package/lib/esm/LazyBackofficeEntityActionFormDialog-L8xwaGqH.js.map +1 -0
- package/lib/esm/PasswordResetCompleteScreen-Cgg96DPo.js.map +1 -1
- package/lib/esm/PasswordResetRequestScreen-I1nFvGLd.js.map +1 -1
- package/lib/esm/VerifyEmailScreen-Br5KyHjg.js.map +1 -1
- package/lib/esm/backoffice-react.js +11 -5
- package/lib/esm/backoffice-react.js.map +1 -1
- package/lib/esm/backofficeAuthPaths-BiJvoI5Q.js.map +1 -1
- package/lib/esm/buildBreadcrumbs-CqF9Nh6x.js.map +1 -1
- package/lib/esm/environment-DQfVyWHJ.js.map +1 -1
- package/lib/esm/mutationResult-CcQMY13J.js.map +1 -1
- package/lib/esm/pageResolution-hAQA5C6S.js.map +1 -1
- package/lib/esm/sidebarUtils-DVkLmFbS.js +52 -0
- package/lib/esm/sidebarUtils-DVkLmFbS.js.map +1 -0
- package/lib/esm/synchronizeAuthStatusQuery-BoPKMrP1.js.map +1 -1
- package/lib/esm/toastViewAction-BGTS7vqm.js.map +1 -1
- package/lib/esm/useAuth-CheTnq60.js.map +1 -1
- package/lib/esm/useBackofficeAuth-ers1FUGe.js.map +1 -1
- package/lib/esm/useBackofficeLazyValue-Bh_13h8A.js.map +1 -1
- package/lib/esm/useBackofficeListUrlState-D4fx5O7u.js.map +1 -1
- package/lib/esm/useBackofficeReactTranslation-Btt58EIo.js.map +1 -1
- package/lib/types/components/backoffice/columns/buildDataTableColumns.d.ts.map +1 -1
- package/lib/types/components/backoffice/layout/buildSidebarSections.d.ts +2 -1
- package/lib/types/components/backoffice/layout/buildSidebarSections.d.ts.map +1 -1
- package/lib/types/components/backoffice/layout/sidebarUtils.d.ts +4 -1
- package/lib/types/components/backoffice/layout/sidebarUtils.d.ts.map +1 -1
- package/lib/types/components/backoffice/scaffolds/BackofficeEntityListScaffold.d.ts.map +1 -1
- package/lib/types/hooks/useSidebarGroupCollapse.d.ts +1 -0
- package/lib/types/hooks/useSidebarGroupCollapse.d.ts.map +1 -1
- package/lib/types/i18n/resources.d.ts +2 -0
- package/lib/types/i18n/resources.d.ts.map +1 -1
- package/lib/types/pages/BackofficeDashboardPage.d.ts.map +1 -1
- package/lib/types/pages/BackofficeDashboardPage.helpers.d.ts.map +1 -1
- package/lib/types/pages/BackofficeEntityDetailPage.d.ts.map +1 -1
- package/lib/types/pages/BackofficeEntityDetailPage.view-helpers.d.ts +1 -0
- package/lib/types/pages/BackofficeEntityDetailPage.view-helpers.d.ts.map +1 -1
- package/lib/types/pages/BackofficeEntityListPage.d.ts.map +1 -1
- package/lib/types/pages/BackofficeEntityListPage.helpers.d.ts.map +1 -1
- package/lib/types/pages/BackofficeLayoutPage.d.ts.map +1 -1
- package/lib/types/provider/types.d.ts +64 -1
- package/lib/types/provider/types.d.ts.map +1 -1
- package/package.json +14 -14
- package/lib/esm/BackofficeDashboardPage-YWvoQODn.js.map +0 -1
- package/lib/esm/BackofficeEntityDetailPage-DPFXbJxC.js.map +0 -1
- package/lib/esm/BackofficeEntityListPage-C8Ucmc_E.js.map +0 -1
- package/lib/esm/BackofficeLayoutPage-CKXS0nDO.js +0 -485
- package/lib/esm/BackofficeLayoutPage-CKXS0nDO.js.map +0 -1
- package/lib/esm/BackofficeRightPageLayout-DZQvIHnj.js.map +0 -1
- package/lib/esm/LazyBackofficeEntityActionFormDialog-DVPQyWlr.js.map +0 -1
- package/lib/esm/sidebarUtils-CuwJ_3mD.js +0 -34
- package/lib/esm/sidebarUtils-CuwJ_3mD.js.map +0 -1
|
@@ -1,485 +0,0 @@
|
|
|
1
|
-
import { o as e } from "./environment-DQfVyWHJ.js";
|
|
2
|
-
import { t } from "./useRelayEnvironment-vQ86aW-n.js";
|
|
3
|
-
import { r as n, t as r } from "./useBackofficeReactTranslation-Btt58EIo.js";
|
|
4
|
-
import { a as i, i as a, n as o, r as s, t as c } from "./sidebarUtils-CuwJ_3mD.js";
|
|
5
|
-
import { t as l } from "./BackofficeErrorBoundary-BwRVSDHU.js";
|
|
6
|
-
import { t as u } from "./BackofficeTopbarPortalContext-iD7dm4_h.js";
|
|
7
|
-
import { t as d } from "./backofficeAuthPaths-BiJvoI5Q.js";
|
|
8
|
-
import { Suspense as f, useCallback as p, useContext as m, useEffect as h, useMemo as g, useState as _ } from "react";
|
|
9
|
-
import { useTranslation as v } from "react-i18next";
|
|
10
|
-
import { RoutingContext as y, useLocation as b } from "@plumile/router";
|
|
11
|
-
import { AdminShellLayout as x, BackofficeSidebarProfileMenu as S, Button as C, EnvironmentBadge as ee, GlobalSearchInput as w, GripDotsSvg as T, InlineBanner as E, PinFilledSvg as D, PinSvg as O, SidebarHomeSvg as k, SidebarTasksSvg as A, Skeleton as j, ToastProvider as M } from "@plumile/ui";
|
|
12
|
-
import { commitMutation as te, usePreloadedQuery as N } from "react-relay";
|
|
13
|
-
import { jsx as P, jsxs as F } from "react/jsx-runtime";
|
|
14
|
-
//#region src/hooks/useBackofficeSidebarPins.ts
|
|
15
|
-
var I = "backoffice.sidebar.pins.v1", L = (e) => {
|
|
16
|
-
if (typeof window > "u") return [];
|
|
17
|
-
try {
|
|
18
|
-
let t = window.localStorage.getItem(e);
|
|
19
|
-
if (t == null) return [];
|
|
20
|
-
let n = JSON.parse(t);
|
|
21
|
-
return Array.isArray(n) ? n.filter((e) => typeof e == "string") : [];
|
|
22
|
-
} catch {
|
|
23
|
-
return [];
|
|
24
|
-
}
|
|
25
|
-
}, R = (e, t) => {
|
|
26
|
-
let n = [], r = /* @__PURE__ */ new Set();
|
|
27
|
-
return e.forEach((e) => {
|
|
28
|
-
t.has(e) && (r.has(e) || (r.add(e), n.push(e)));
|
|
29
|
-
}), n;
|
|
30
|
-
}, ne = (e) => {
|
|
31
|
-
let { storageKey: t = I, visibleEntityIds: n } = e, r = g(() => new Set(n), [n]), [i, a] = _(() => R(L(t), r));
|
|
32
|
-
h(() => {
|
|
33
|
-
a((e) => {
|
|
34
|
-
let t = R(e, r);
|
|
35
|
-
if (t.length === e.length) {
|
|
36
|
-
let n = !0;
|
|
37
|
-
for (let r = 0; r < t.length; r += 1) if (t[r] !== e[r]) {
|
|
38
|
-
n = !1;
|
|
39
|
-
break;
|
|
40
|
-
}
|
|
41
|
-
if (n) return e;
|
|
42
|
-
}
|
|
43
|
-
return t;
|
|
44
|
-
});
|
|
45
|
-
}, [r]), h(() => {
|
|
46
|
-
a(R(L(t), r));
|
|
47
|
-
}, [t, r]), h(() => {
|
|
48
|
-
if (!(typeof window > "u")) try {
|
|
49
|
-
window.localStorage.setItem(t, JSON.stringify(i));
|
|
50
|
-
} catch {}
|
|
51
|
-
}, [i, t]);
|
|
52
|
-
let o = g(() => new Set(i), [i]), s = p((e) => {
|
|
53
|
-
r.has(e) && a((t) => t.includes(e) ? t : [...t, e]);
|
|
54
|
-
}, [r]), c = p((e) => {
|
|
55
|
-
a((t) => t.filter((t) => t !== e));
|
|
56
|
-
}, []), l = p((e) => {
|
|
57
|
-
o.has(e) ? c(e) : s(e);
|
|
58
|
-
}, [
|
|
59
|
-
s,
|
|
60
|
-
o,
|
|
61
|
-
c
|
|
62
|
-
]), u = p((e, t) => {
|
|
63
|
-
e !== t && a((n) => {
|
|
64
|
-
let r = n.indexOf(e), i = n.indexOf(t);
|
|
65
|
-
if (r === -1 || i === -1 || r === i) return n;
|
|
66
|
-
let a = [...n];
|
|
67
|
-
return a.splice(r, 1), a.splice(i, 0, e), a;
|
|
68
|
-
});
|
|
69
|
-
}, []);
|
|
70
|
-
return {
|
|
71
|
-
pins: i,
|
|
72
|
-
isPinned: p((e) => o.has(e), [o]),
|
|
73
|
-
pin: s,
|
|
74
|
-
unpin: c,
|
|
75
|
-
toggle: l,
|
|
76
|
-
reorder: u
|
|
77
|
-
};
|
|
78
|
-
}, z = (e, t) => {
|
|
79
|
-
let n = {};
|
|
80
|
-
return e.forEach((e) => {
|
|
81
|
-
n[e] = !0;
|
|
82
|
-
}), t != null && e.includes(t) && (n[t] = !1), n;
|
|
83
|
-
}, re = (e) => {
|
|
84
|
-
let { groupIds: t, activeGroupId: n } = e, r = g(() => [...t], [t]), [i, a] = _(() => z(r, n));
|
|
85
|
-
return h(() => {
|
|
86
|
-
a((e) => {
|
|
87
|
-
let t = {};
|
|
88
|
-
return r.forEach((n) => {
|
|
89
|
-
t[n] = e[n] ?? !0;
|
|
90
|
-
}), n != null && r.includes(n) && (t[n] = !1), t;
|
|
91
|
-
});
|
|
92
|
-
}, [n, r]), h(() => {
|
|
93
|
-
n != null && a((e) => e[n] === !1 ? e : {
|
|
94
|
-
...e,
|
|
95
|
-
[n]: !1
|
|
96
|
-
});
|
|
97
|
-
}, [n]), {
|
|
98
|
-
collapsedByGroupId: i,
|
|
99
|
-
setCollapsed: p((e, t) => {
|
|
100
|
-
a((n) => n[e] === t ? n : {
|
|
101
|
-
...n,
|
|
102
|
-
[e]: t
|
|
103
|
-
});
|
|
104
|
-
}, [])
|
|
105
|
-
};
|
|
106
|
-
}, B = "_1xws1b00 txvbqb9jg txvbqbcp txvbqbdoy txvbqbtxp txvbqbc6p txvbqb1rg txvbqb12g txvbqb1py txvbqblag txvbqbv0t txvbqbva1 txvbqbv txvbqb78 txvbqb6x txvbqb7k", V = (e, t) => e == null ? t ?? null : /* @__PURE__ */ P(e, {
|
|
107
|
-
width: 18,
|
|
108
|
-
height: 18,
|
|
109
|
-
"aria-hidden": "true"
|
|
110
|
-
});
|
|
111
|
-
function ie(e) {
|
|
112
|
-
let { basePath: t, pathname: n, entities: r, sidebar: i, permissions: l, searchQuery: u, tApp: d, t: f, pinnedEntityIds: p = [], onTogglePin: m, onReorderPin: h, collapsedByGroupId: g, onGroupCollapsedChange: _ } = e, v = a(r, i), y = Object.entries(v), b = new Set(p), x = f("sidebar.actions.pin"), S = f("sidebar.actions.unpin"), C = f("sidebar.actions.reorder"), ee = c(v), w = u?.trim().toLowerCase() ?? "", E = (e) => {
|
|
113
|
-
if (m == null) return null;
|
|
114
|
-
let t = b.has(e), n = x, r = O;
|
|
115
|
-
return t && (n = S, r = D), /* @__PURE__ */ P("button", {
|
|
116
|
-
type: "button",
|
|
117
|
-
className: B,
|
|
118
|
-
"aria-pressed": t,
|
|
119
|
-
"aria-label": n,
|
|
120
|
-
title: n,
|
|
121
|
-
onClick: (t) => {
|
|
122
|
-
t.preventDefault(), t.stopPropagation(), m(e);
|
|
123
|
-
},
|
|
124
|
-
children: /* @__PURE__ */ P(r, {
|
|
125
|
-
width: 14,
|
|
126
|
-
height: 14,
|
|
127
|
-
"aria-hidden": "true"
|
|
128
|
-
})
|
|
129
|
-
});
|
|
130
|
-
}, j = (e) => {
|
|
131
|
-
let { entityId: t, groupId: a, groupIcon: c, enableReorder: u } = e, f = r[t];
|
|
132
|
-
if (f == null) return null;
|
|
133
|
-
let p = {
|
|
134
|
-
kind: "entity",
|
|
135
|
-
id: t
|
|
136
|
-
};
|
|
137
|
-
if (f.kind === "tool" && (p = {
|
|
138
|
-
kind: "tool",
|
|
139
|
-
id: t
|
|
140
|
-
}), i?.isItemVisible?.(p, l) === !1) return null;
|
|
141
|
-
if (f.kind === "tool") {
|
|
142
|
-
let e = s(f.label, d);
|
|
143
|
-
return w !== "" && !e.toLowerCase().includes(w) ? null : {
|
|
144
|
-
id: `tool-${t}`,
|
|
145
|
-
data: {
|
|
146
|
-
kind: "tool",
|
|
147
|
-
id: t,
|
|
148
|
-
groupId: a
|
|
149
|
-
},
|
|
150
|
-
label: e,
|
|
151
|
-
href: f.routes.list,
|
|
152
|
-
icon: V(c, /* @__PURE__ */ P(A, {
|
|
153
|
-
width: 18,
|
|
154
|
-
height: 18,
|
|
155
|
-
"aria-hidden": "true"
|
|
156
|
-
})),
|
|
157
|
-
isActive: o(n, f.routes.list),
|
|
158
|
-
ariaLabel: e,
|
|
159
|
-
actionSlot: E(t)
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
if (!f.hasList) return null;
|
|
163
|
-
let m = s(f.label, d);
|
|
164
|
-
if (w !== "" && !m.toLowerCase().includes(w)) return null;
|
|
165
|
-
let g, _, v, y, b = !1;
|
|
166
|
-
u === !0 && h != null && (b = !0, g = /* @__PURE__ */ P(T, {
|
|
167
|
-
width: 14,
|
|
168
|
-
height: 14,
|
|
169
|
-
"aria-hidden": "true"
|
|
170
|
-
}), _ = (e) => {
|
|
171
|
-
let { dataTransfer: n } = e;
|
|
172
|
-
n.effectAllowed = "move", n.setData("text/plain", t);
|
|
173
|
-
}, v = (e) => {
|
|
174
|
-
e.preventDefault();
|
|
175
|
-
let { dataTransfer: t } = e;
|
|
176
|
-
t.dropEffect = "move";
|
|
177
|
-
}, y = (e) => {
|
|
178
|
-
e.preventDefault();
|
|
179
|
-
let n = e.dataTransfer.getData("text/plain");
|
|
180
|
-
n === "" || n === t || h(n, t);
|
|
181
|
-
});
|
|
182
|
-
let x;
|
|
183
|
-
return g != null && (x = C), {
|
|
184
|
-
id: t,
|
|
185
|
-
data: {
|
|
186
|
-
kind: "entity",
|
|
187
|
-
id: t,
|
|
188
|
-
groupId: a
|
|
189
|
-
},
|
|
190
|
-
label: m,
|
|
191
|
-
href: f.routes.list,
|
|
192
|
-
icon: V(c, /* @__PURE__ */ P(A, {
|
|
193
|
-
width: 18,
|
|
194
|
-
height: 18,
|
|
195
|
-
"aria-hidden": "true"
|
|
196
|
-
})),
|
|
197
|
-
isActive: o(n, f.routes.list),
|
|
198
|
-
ariaLabel: m,
|
|
199
|
-
actionSlot: E(t),
|
|
200
|
-
dragHandleSlot: g,
|
|
201
|
-
dragHandleLabel: x,
|
|
202
|
-
draggable: b,
|
|
203
|
-
onDragStart: _,
|
|
204
|
-
onDragOver: v,
|
|
205
|
-
onDrop: y
|
|
206
|
-
};
|
|
207
|
-
}, M = [];
|
|
208
|
-
if (p.length > 0) {
|
|
209
|
-
let e = p.map((e) => {
|
|
210
|
-
let t = ee.get(e);
|
|
211
|
-
return j({
|
|
212
|
-
entityId: e,
|
|
213
|
-
groupId: t?.groupId,
|
|
214
|
-
groupIcon: t?.icon,
|
|
215
|
-
enableReorder: !0
|
|
216
|
-
});
|
|
217
|
-
}).filter((e) => e != null);
|
|
218
|
-
e.length > 0 && M.push({
|
|
219
|
-
id: "pinned",
|
|
220
|
-
title: f("sidebar.sections.pinned"),
|
|
221
|
-
items: e,
|
|
222
|
-
collapsible: !1
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
return y.forEach(([e, r], a) => {
|
|
226
|
-
if (r.isVisible != null && !r.isVisible(l)) return;
|
|
227
|
-
let c = [];
|
|
228
|
-
if (a === 0 && i?.isItemVisible?.({
|
|
229
|
-
kind: "dashboard",
|
|
230
|
-
id: "dashboard"
|
|
231
|
-
}, l) !== !1) {
|
|
232
|
-
let r = f("sidebar.items.dashboard");
|
|
233
|
-
if (w !== "" && !r.toLowerCase().includes(w)) return;
|
|
234
|
-
c.push({
|
|
235
|
-
id: "dashboard",
|
|
236
|
-
data: {
|
|
237
|
-
kind: "dashboard",
|
|
238
|
-
id: "dashboard",
|
|
239
|
-
groupId: e
|
|
240
|
-
},
|
|
241
|
-
label: r,
|
|
242
|
-
href: t,
|
|
243
|
-
icon: V(void 0, /* @__PURE__ */ P(k, {
|
|
244
|
-
width: 18,
|
|
245
|
-
height: 18,
|
|
246
|
-
"aria-hidden": "true"
|
|
247
|
-
})),
|
|
248
|
-
isActive: o(n, t),
|
|
249
|
-
ariaLabel: f("sidebar.items.dashboard")
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
if (r.entities != null && r.entities.forEach((t) => {
|
|
253
|
-
let n = j({
|
|
254
|
-
entityId: t,
|
|
255
|
-
groupId: e,
|
|
256
|
-
groupIcon: r.icon
|
|
257
|
-
});
|
|
258
|
-
n != null && c.push(n);
|
|
259
|
-
}), c.length === 0) return;
|
|
260
|
-
let u;
|
|
261
|
-
r.title != null && (u = s(r.title, d));
|
|
262
|
-
let p = g?.[e], m;
|
|
263
|
-
_ != null && (m = (t) => {
|
|
264
|
-
_(e, t);
|
|
265
|
-
}), M.push({
|
|
266
|
-
id: e,
|
|
267
|
-
title: u,
|
|
268
|
-
items: c,
|
|
269
|
-
collapsible: !0,
|
|
270
|
-
defaultCollapsed: !0,
|
|
271
|
-
isCollapsed: p,
|
|
272
|
-
onCollapsedChange: m
|
|
273
|
-
});
|
|
274
|
-
}), M;
|
|
275
|
-
}
|
|
276
|
-
//#endregion
|
|
277
|
-
//#region src/components/backoffice/routing/backofficeContentError.css.ts
|
|
278
|
-
var H = "txvbqb9ip txvbqbai7 txvbqbu7g", U = "txvbqbwy", W = (e) => {
|
|
279
|
-
if (e instanceof Error) {
|
|
280
|
-
let t = e.message.trim();
|
|
281
|
-
return t.length > 0 ? t : null;
|
|
282
|
-
}
|
|
283
|
-
if (typeof e == "string") {
|
|
284
|
-
let t = e.trim();
|
|
285
|
-
return t.length > 0 ? t : null;
|
|
286
|
-
}
|
|
287
|
-
return null;
|
|
288
|
-
}, G = ({ error: e, onRetry: t }) => {
|
|
289
|
-
let { t: n } = r(), i = W(e);
|
|
290
|
-
return /* @__PURE__ */ P("div", {
|
|
291
|
-
className: H,
|
|
292
|
-
role: "alert",
|
|
293
|
-
children: /* @__PURE__ */ P(E, {
|
|
294
|
-
tone: "danger",
|
|
295
|
-
className: U,
|
|
296
|
-
actions: /* @__PURE__ */ P(C, {
|
|
297
|
-
type: "button",
|
|
298
|
-
variant: "secondary",
|
|
299
|
-
size: "small",
|
|
300
|
-
onClick: t,
|
|
301
|
-
children: n("common.actions.retry")
|
|
302
|
-
}),
|
|
303
|
-
children: i
|
|
304
|
-
})
|
|
305
|
-
});
|
|
306
|
-
}, K = "txvbqb9ip txvbqbai7 txvbqbaop txvbqbu7g txvbqbjs7", q = "txvbqbjfg", J = "txvbqb9iy txvbqbaop txvbqbc17", Y = "txvbqb9ip txvbqbai7 txvbqbaog txvbqblbg txvbqbjny txvbqb1ry txvbqb1cp txvbqb1qg txvbqbwp txvbqbv45", X = () => /* @__PURE__ */ F("div", {
|
|
307
|
-
className: K,
|
|
308
|
-
role: "status",
|
|
309
|
-
"aria-live": "polite",
|
|
310
|
-
"aria-busy": "true",
|
|
311
|
-
children: [
|
|
312
|
-
/* @__PURE__ */ P(j, {
|
|
313
|
-
variant: "text",
|
|
314
|
-
width: "38%",
|
|
315
|
-
className: q
|
|
316
|
-
}),
|
|
317
|
-
/* @__PURE__ */ P(j, {
|
|
318
|
-
variant: "text",
|
|
319
|
-
width: "62%"
|
|
320
|
-
}),
|
|
321
|
-
/* @__PURE__ */ P("div", {
|
|
322
|
-
className: J,
|
|
323
|
-
children: Array.from({ length: 4 }, (e, t) => /* @__PURE__ */ F("div", {
|
|
324
|
-
className: Y,
|
|
325
|
-
children: [
|
|
326
|
-
/* @__PURE__ */ P(j, {
|
|
327
|
-
variant: "text",
|
|
328
|
-
width: "46%"
|
|
329
|
-
}),
|
|
330
|
-
/* @__PURE__ */ P(j, {
|
|
331
|
-
variant: "text",
|
|
332
|
-
width: "82%",
|
|
333
|
-
lines: 2
|
|
334
|
-
}),
|
|
335
|
-
/* @__PURE__ */ P(j, {
|
|
336
|
-
variant: "block",
|
|
337
|
-
width: "100%",
|
|
338
|
-
height: 120
|
|
339
|
-
})
|
|
340
|
-
]
|
|
341
|
-
}, `content-skeleton-${t}`))
|
|
342
|
-
})
|
|
343
|
-
]
|
|
344
|
-
}), Z = "txvbqb9ip txvbqbai7 txvbqbjs7 txvbqbu7g txvbqbk5y", ae = ({ children: e }) => /* @__PURE__ */ P("div", {
|
|
345
|
-
className: Z,
|
|
346
|
-
children: /* @__PURE__ */ P(l, {
|
|
347
|
-
fallback: ({ error: e, reset: t }) => /* @__PURE__ */ P(G, {
|
|
348
|
-
error: e,
|
|
349
|
-
onRetry: t
|
|
350
|
-
}),
|
|
351
|
-
children: /* @__PURE__ */ P(f, {
|
|
352
|
-
fallback: /* @__PURE__ */ P(X, {}),
|
|
353
|
-
children: e
|
|
354
|
-
})
|
|
355
|
-
})
|
|
356
|
-
}), Q = (e) => e?.trim() ?? "", oe = ({ viewer: e, unknownUserLabel: t }) => {
|
|
357
|
-
let n = [Q(e?.firstName), Q(e?.lastName)].filter((e) => e !== "").join(" ").trim();
|
|
358
|
-
n === "" && (n = t);
|
|
359
|
-
let r = Q(e?.email), i = Q(e?.initials);
|
|
360
|
-
i === "" && (i = "?");
|
|
361
|
-
let a = [n];
|
|
362
|
-
return r !== "" && a.push(r), {
|
|
363
|
-
displayName: n,
|
|
364
|
-
email: r,
|
|
365
|
-
initials: i,
|
|
366
|
-
ariaLabel: a.join(" - ")
|
|
367
|
-
};
|
|
368
|
-
}, $ = ({ children: o, permissions: s, authStatus: c, activeGroupId: l }) => {
|
|
369
|
-
let { t: f } = v(), { t: h } = r(), { pathname: C } = b(), T = m(y), E = t(), { auth: D, basePath: O, entities: k, sidebar: A } = n(), [j, N] = _(""), [F, I] = _(!1), [L, R] = _(!1), [z, B] = _(null), V = g(() => a(k, A), [k, A]), H = g(() => Object.keys(V), [V]), { pins: U, toggle: W, reorder: G } = ne({ visibleEntityIds: g(() => i(V, k, A, s), [
|
|
370
|
-
k,
|
|
371
|
-
V,
|
|
372
|
-
s,
|
|
373
|
-
A
|
|
374
|
-
]) }), { collapsedByGroupId: K, setCollapsed: q } = re({
|
|
375
|
-
groupIds: H,
|
|
376
|
-
activeGroupId: l
|
|
377
|
-
}), J = g(() => ie({
|
|
378
|
-
basePath: O,
|
|
379
|
-
pathname: C,
|
|
380
|
-
entities: k,
|
|
381
|
-
sidebar: A,
|
|
382
|
-
permissions: s,
|
|
383
|
-
searchQuery: j,
|
|
384
|
-
tApp: f,
|
|
385
|
-
t: h,
|
|
386
|
-
pinnedEntityIds: U,
|
|
387
|
-
onTogglePin: W,
|
|
388
|
-
onReorderPin: G,
|
|
389
|
-
collapsedByGroupId: K,
|
|
390
|
-
onGroupCollapsedChange: q
|
|
391
|
-
}), [
|
|
392
|
-
O,
|
|
393
|
-
K,
|
|
394
|
-
k,
|
|
395
|
-
C,
|
|
396
|
-
s,
|
|
397
|
-
U,
|
|
398
|
-
G,
|
|
399
|
-
q,
|
|
400
|
-
A,
|
|
401
|
-
j,
|
|
402
|
-
h,
|
|
403
|
-
f,
|
|
404
|
-
W
|
|
405
|
-
]), Y = g(() => import.meta.env?.DEV === !0 ? "dev" : "prod", []), X = p(() => {
|
|
406
|
-
L || (R(!0), (async () => {
|
|
407
|
-
try {
|
|
408
|
-
let t = await D.logout.load();
|
|
409
|
-
await new Promise((e, n) => {
|
|
410
|
-
te(E, {
|
|
411
|
-
mutation: t.logoutMutation,
|
|
412
|
-
variables: {},
|
|
413
|
-
onCompleted: () => {
|
|
414
|
-
e();
|
|
415
|
-
},
|
|
416
|
-
onError: (e) => {
|
|
417
|
-
n(e);
|
|
418
|
-
}
|
|
419
|
-
});
|
|
420
|
-
}), localStorage.removeItem("auth_token"), localStorage.removeItem("remember_me"), e(), T?.history.push({ pathname: d(O) });
|
|
421
|
-
} finally {
|
|
422
|
-
R(!1);
|
|
423
|
-
}
|
|
424
|
-
})().catch(() => {}));
|
|
425
|
-
}, [
|
|
426
|
-
D.logout,
|
|
427
|
-
O,
|
|
428
|
-
L,
|
|
429
|
-
E,
|
|
430
|
-
T
|
|
431
|
-
]), Z = c?.me ?? null, Q = /* @__PURE__ */ P(S, {
|
|
432
|
-
collapsed: F,
|
|
433
|
-
viewer: g(() => oe({
|
|
434
|
-
viewer: Z,
|
|
435
|
-
unknownUserLabel: h("sidebar.profile.unknownUser")
|
|
436
|
-
}), [h, Z]),
|
|
437
|
-
labels: {
|
|
438
|
-
sectionTitle: h("sidebar.profile.title"),
|
|
439
|
-
menuAriaLabel: h("sidebar.profile.menuAriaLabel"),
|
|
440
|
-
signOut: h("sidebar.profile.actions.signOut")
|
|
441
|
-
},
|
|
442
|
-
onSignOut: X,
|
|
443
|
-
isSigningOut: L
|
|
444
|
-
}), $ = null;
|
|
445
|
-
return z != null && ($ = /* @__PURE__ */ P(ae, { children: o })), /* @__PURE__ */ P(M, { children: /* @__PURE__ */ P(x, {
|
|
446
|
-
sidebar: {
|
|
447
|
-
sections: J,
|
|
448
|
-
header: /* @__PURE__ */ P(ee, { environment: Y }),
|
|
449
|
-
search: /* @__PURE__ */ P(w, {
|
|
450
|
-
value: j,
|
|
451
|
-
onChange: N,
|
|
452
|
-
placeholder: h("sidebar.search.placeholder"),
|
|
453
|
-
ariaLabel: h("sidebar.search.placeholder")
|
|
454
|
-
}),
|
|
455
|
-
footer: Q,
|
|
456
|
-
isCollapsed: F,
|
|
457
|
-
onCollapsedChange: I
|
|
458
|
-
},
|
|
459
|
-
topbar: { breadcrumb: /* @__PURE__ */ P("div", { ref: B }) },
|
|
460
|
-
children: /* @__PURE__ */ P(u, {
|
|
461
|
-
value: { target: z },
|
|
462
|
-
children: $
|
|
463
|
-
})
|
|
464
|
-
}) });
|
|
465
|
-
}, se = ({ children: e, permissionsQuery: t, prepared: n, authStatus: r, activeGroupId: i }) => /* @__PURE__ */ P($, {
|
|
466
|
-
permissions: N(t, n),
|
|
467
|
-
authStatus: r,
|
|
468
|
-
activeGroupId: i,
|
|
469
|
-
children: e
|
|
470
|
-
}), ce = ({ children: e, permissionsQuery: t, prepared: n, authStatus: r, activeGroupId: i }) => t != null && n != null ? /* @__PURE__ */ P(se, {
|
|
471
|
-
permissionsQuery: t,
|
|
472
|
-
prepared: n,
|
|
473
|
-
authStatus: r,
|
|
474
|
-
activeGroupId: i,
|
|
475
|
-
children: e
|
|
476
|
-
}) : /* @__PURE__ */ P($, {
|
|
477
|
-
permissions: null,
|
|
478
|
-
authStatus: r,
|
|
479
|
-
activeGroupId: i,
|
|
480
|
-
children: e
|
|
481
|
-
});
|
|
482
|
-
//#endregion
|
|
483
|
-
export { ce as BackofficeLayoutPage, ce as default };
|
|
484
|
-
|
|
485
|
-
//# sourceMappingURL=BackofficeLayoutPage-CKXS0nDO.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BackofficeLayoutPage-CKXS0nDO.js","names":[],"sources":["../../src/hooks/useBackofficeSidebarPins.ts","../../src/hooks/useSidebarGroupCollapse.ts","../../src/components/backoffice/layout/backofficeSidebarActions.css.ts","../../src/components/backoffice/layout/buildSidebarSections.tsx","../../src/components/backoffice/routing/backofficeContentError.css.ts","../../src/components/backoffice/routing/BackofficeContentError.tsx","../../src/components/backoffice/routing/backofficeContentFallback.css.ts","../../src/components/backoffice/routing/BackofficeContentFallback.tsx","../../src/components/backoffice/routing/backofficeContentBoundary.css.ts","../../src/components/backoffice/routing/BackofficeContentBoundary.tsx","../../src/components/backoffice/layout/mapViewerToSidebarProfileView.ts","../../src/pages/BackofficeLayoutPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react';\n\nconst DEFAULT_STORAGE_KEY = 'backoffice.sidebar.pins.v1';\n\ntype PinsPayload = unknown;\n\nconst readPinsFromStorage = (storageKey: string): string[] => {\n if (typeof window === 'undefined') {\n return [];\n }\n try {\n const raw = window.localStorage.getItem(storageKey);\n if (raw == null) {\n return [];\n }\n const parsed = JSON.parse(raw) as PinsPayload;\n if (!Array.isArray(parsed)) {\n return [];\n }\n return parsed.filter((entry): entry is string => {\n return typeof entry === 'string';\n });\n } catch {\n return [];\n }\n};\n\nconst normalizePins = (\n pins: readonly string[],\n validIds: Set<string>,\n): string[] => {\n const output: string[] = [];\n const seen = new Set<string>();\n pins.forEach((entry) => {\n if (!validIds.has(entry)) {\n return;\n }\n if (seen.has(entry)) {\n return;\n }\n seen.add(entry);\n output.push(entry);\n });\n return output;\n};\n\nexport type SidebarPinsState = {\n pins: readonly string[];\n isPinned: (id: string) => boolean;\n pin: (id: string) => void;\n unpin: (id: string) => void;\n toggle: (id: string) => void;\n reorder: (fromId: string, toId: string) => void;\n};\n\nexport type UseBackofficeSidebarPinsInput = {\n storageKey?: string;\n visibleEntityIds: readonly string[];\n};\n\nexport const useBackofficeSidebarPins = (\n input: UseBackofficeSidebarPinsInput,\n): SidebarPinsState => {\n const { storageKey = DEFAULT_STORAGE_KEY, visibleEntityIds } = input;\n const validIds = useMemo(() => {\n return new Set(visibleEntityIds);\n }, [visibleEntityIds]);\n\n const [pins, setPins] = useState<string[]>(() => {\n const stored = readPinsFromStorage(storageKey);\n return normalizePins(stored, validIds);\n });\n\n useEffect(() => {\n setPins((prev) => {\n const normalized = normalizePins(prev, validIds);\n if (normalized.length === prev.length) {\n let unchanged = true;\n for (let index = 0; index < normalized.length; index += 1) {\n if (normalized[index] !== prev[index]) {\n unchanged = false;\n break;\n }\n }\n if (unchanged) {\n return prev;\n }\n }\n return normalized;\n });\n }, [validIds]);\n\n useEffect(() => {\n const stored = readPinsFromStorage(storageKey);\n setPins(normalizePins(stored, validIds));\n }, [storageKey, validIds]);\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(storageKey, JSON.stringify(pins));\n } catch {\n // Ignore storage errors in non-browser or restricted environments.\n }\n }, [pins, storageKey]);\n\n const pinsSet = useMemo(() => {\n return new Set(pins);\n }, [pins]);\n\n const pin = useCallback(\n (id: string) => {\n if (!validIds.has(id)) {\n return;\n }\n setPins((prev) => {\n if (prev.includes(id)) {\n return prev;\n }\n return [...prev, id];\n });\n },\n [validIds],\n );\n\n const unpin = useCallback((id: string) => {\n setPins((prev) => {\n return prev.filter((entry) => {\n return entry !== id;\n });\n });\n }, []);\n\n const toggle = useCallback(\n (id: string) => {\n if (pinsSet.has(id)) {\n unpin(id);\n } else {\n pin(id);\n }\n },\n [pin, pinsSet, unpin],\n );\n\n const reorder = useCallback((fromId: string, toId: string) => {\n if (fromId === toId) {\n return;\n }\n setPins((prev) => {\n const fromIndex = prev.indexOf(fromId);\n const toIndex = prev.indexOf(toId);\n if (fromIndex === -1 || toIndex === -1) {\n return prev;\n }\n if (fromIndex === toIndex) {\n return prev;\n }\n const next = [...prev];\n next.splice(fromIndex, 1);\n next.splice(toIndex, 0, fromId);\n return next;\n });\n }, []);\n\n const isPinned = useCallback(\n (id: string) => {\n return pinsSet.has(id);\n },\n [pinsSet],\n );\n\n return {\n pins,\n isPinned,\n pin,\n unpin,\n toggle,\n reorder,\n };\n};\n\nexport const __test = {\n normalizePins,\n readPinsFromStorage,\n};\n\nexport default useBackofficeSidebarPins;\n","import { useCallback, useEffect, useMemo, useState } from 'react';\n\nexport type SidebarGroupCollapseState = Record<string, boolean | undefined>;\n\nexport type UseSidebarGroupCollapseInput = {\n groupIds: readonly string[];\n activeGroupId?: string | null;\n};\n\nconst buildInitialState = (\n groupIds: readonly string[],\n activeGroupId?: string | null,\n): SidebarGroupCollapseState => {\n const state: SidebarGroupCollapseState = {};\n groupIds.forEach((groupId) => {\n state[groupId] = true;\n });\n if (activeGroupId != null && groupIds.includes(activeGroupId)) {\n state[activeGroupId] = false;\n }\n return state;\n};\n\nexport const useSidebarGroupCollapse = (\n input: UseSidebarGroupCollapseInput,\n): {\n collapsedByGroupId: SidebarGroupCollapseState;\n setCollapsed: (groupId: string, collapsed: boolean) => void;\n} => {\n const { groupIds, activeGroupId } = input;\n\n const groupIdList = useMemo(() => {\n return [...groupIds];\n }, [groupIds]);\n\n const [collapsedByGroupId, setCollapsedByGroupId] =\n useState<SidebarGroupCollapseState>(() => {\n return buildInitialState(groupIdList, activeGroupId);\n });\n\n useEffect(() => {\n setCollapsedByGroupId((prev) => {\n const next: SidebarGroupCollapseState = {};\n\n groupIdList.forEach((groupId) => {\n const existing = prev[groupId];\n next[groupId] = existing ?? true;\n });\n\n if (activeGroupId != null && groupIdList.includes(activeGroupId)) {\n next[activeGroupId] = false;\n }\n\n return next;\n });\n }, [activeGroupId, groupIdList]);\n\n useEffect(() => {\n if (activeGroupId == null) {\n return;\n }\n setCollapsedByGroupId((prev) => {\n if (prev[activeGroupId] === false) {\n return prev;\n }\n return {\n ...prev,\n [activeGroupId]: false,\n };\n });\n }, [activeGroupId]);\n\n const setCollapsed = useCallback((groupId: string, collapsed: boolean) => {\n setCollapsedByGroupId((prev) => {\n if (prev[groupId] === collapsed) {\n return prev;\n }\n return {\n ...prev,\n [groupId]: collapsed,\n };\n });\n }, []);\n\n return {\n collapsedByGroupId,\n setCollapsed,\n };\n};\n\nexport default useSidebarGroupCollapse;\n","import { style } from '@vanilla-extract/css';\n\nimport { sprinkles, vars } from '@plumile/ui';\n\nexport const actionButton = style([\n sprinkles({\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 6,\n height: 6,\n borderRadius: 'md',\n borderWidth: 0,\n borderStyle: 'none',\n padding: 0,\n backgroundColor: 'transparent',\n color: 'textSecondary',\n cursor: 'pointer',\n transitionProperty: 'colors',\n transitionDuration: 150,\n transitionTimingFunction: 'ease',\n }),\n {\n selectors: {\n '&:hover': {\n backgroundColor: vars.colors.surfaceMuted,\n color: vars.colors.text,\n },\n '&:focus-visible': {\n outline: `2px solid ${vars.colors['blue-500']}`,\n outlineOffset: 2,\n },\n },\n },\n]);\n","import { type DragEvent, type ReactNode } from 'react';\nimport type { TFunction } from 'i18next';\n\nimport type { BackofficeEntityManifestMap } from '@plumile/backoffice-core/types.js';\nimport type {\n BackofficeSidebarConfig,\n BackofficeSidebarItemDescriptor,\n BackofficeIconComponent,\n} from '../../../provider/types.js';\nimport {\n type AdminSidebarSection,\n type SidebarNavSectionItem,\n GripDotsSvg,\n PinFilledSvg,\n PinSvg,\n SidebarHomeSvg,\n SidebarTasksSvg,\n} from '@plumile/ui';\nimport type { SidebarGroupCollapseState } from '../../../hooks/useSidebarGroupCollapse.js';\nimport * as styles from './backofficeSidebarActions.css.js';\nimport {\n buildEntityGroupLookup,\n isActivePath,\n resolveLabel,\n resolveSidebarGroups,\n} from './sidebarUtils.js';\n\nconst renderIcon = (\n Icon?: BackofficeIconComponent,\n fallback?: ReactNode,\n): ReactNode => {\n if (Icon != null) {\n return <Icon width={18} height={18} aria-hidden=\"true\" />;\n }\n return fallback ?? null;\n};\n\nexport type BuildSidebarSectionsInput = {\n basePath: string;\n pathname: string;\n entities: BackofficeEntityManifestMap;\n sidebar?: BackofficeSidebarConfig;\n permissions: unknown;\n searchQuery?: string;\n tApp: TFunction;\n t: TFunction;\n pinnedEntityIds?: readonly string[];\n onTogglePin?: (entityId: string) => void;\n onReorderPin?: (fromId: string, toId: string) => void;\n collapsedByGroupId?: SidebarGroupCollapseState;\n onGroupCollapsedChange?: (groupId: string, collapsed: boolean) => void;\n};\n\n/**\n * Builds the sidebar sections for the backoffice layout.\n */\nexport function buildSidebarSections(\n input: BuildSidebarSectionsInput,\n): readonly AdminSidebarSection[] {\n const {\n basePath,\n pathname,\n entities,\n sidebar,\n permissions,\n searchQuery,\n tApp,\n t,\n pinnedEntityIds = [],\n onTogglePin,\n onReorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange,\n } = input;\n\n const groups = resolveSidebarGroups(entities, sidebar);\n const entries = Object.entries(groups);\n const pinnedSet = new Set(pinnedEntityIds);\n const pinLabel = t('sidebar.actions.pin');\n const unpinLabel = t('sidebar.actions.unpin');\n const reorderLabel = t('sidebar.actions.reorder');\n const entityGroupLookup = buildEntityGroupLookup(groups);\n const normalizedQuery = searchQuery?.trim().toLowerCase() ?? '';\n\n const renderPinAction = (entityId: string): ReactNode | null => {\n if (onTogglePin == null) {\n return null;\n }\n const isPinned = pinnedSet.has(entityId);\n let label = pinLabel;\n let Icon = PinSvg;\n if (isPinned) {\n label = unpinLabel;\n Icon = PinFilledSvg;\n }\n\n return (\n <button\n type=\"button\"\n className={styles.actionButton}\n aria-pressed={isPinned}\n aria-label={label}\n title={label}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onTogglePin(entityId);\n }}\n >\n <Icon width={14} height={14} aria-hidden=\"true\" />\n </button>\n );\n };\n\n const buildEntityItem = (inputItem: {\n entityId: string;\n groupId?: string;\n groupIcon?: BackofficeIconComponent;\n enableReorder?: boolean;\n }): SidebarNavSectionItem | null => {\n const { entityId, groupId, groupIcon, enableReorder } = inputItem;\n const config = entities[entityId];\n if (config == null) {\n return null;\n }\n\n let descriptor: BackofficeSidebarItemDescriptor = {\n kind: 'entity',\n id: entityId,\n };\n if (config.kind === 'tool') {\n descriptor = { kind: 'tool', id: entityId };\n }\n const isEntityVisible = sidebar?.isItemVisible?.(descriptor, permissions);\n if (isEntityVisible === false) {\n return null;\n }\n\n if (config.kind === 'tool') {\n const label = resolveLabel(config.label, tApp);\n if (\n normalizedQuery !== '' &&\n !label.toLowerCase().includes(normalizedQuery)\n ) {\n return null;\n }\n return {\n id: `tool-${entityId}`,\n data: {\n kind: 'tool',\n id: entityId,\n groupId,\n },\n label,\n href: config.routes.list,\n icon: renderIcon(\n groupIcon,\n <SidebarTasksSvg width={18} height={18} aria-hidden=\"true\" />,\n ),\n isActive: isActivePath(pathname, config.routes.list),\n ariaLabel: label,\n actionSlot: renderPinAction(entityId),\n };\n }\n\n if (!config.hasList) {\n return null;\n }\n\n const label = resolveLabel(config.label, tApp);\n if (\n normalizedQuery !== '' &&\n !label.toLowerCase().includes(normalizedQuery)\n ) {\n return null;\n }\n\n let dragHandleSlot: ReactNode | undefined;\n let onDragStart: ((event: DragEvent) => void) | undefined;\n let onDragOver: ((event: DragEvent) => void) | undefined;\n let onDrop: ((event: DragEvent) => void) | undefined;\n let draggable = false;\n\n if (enableReorder === true && onReorderPin != null) {\n draggable = true;\n dragHandleSlot = (\n <GripDotsSvg width={14} height={14} aria-hidden=\"true\" />\n );\n onDragStart = (event) => {\n const { dataTransfer } = event;\n dataTransfer.effectAllowed = 'move';\n dataTransfer.setData('text/plain', entityId);\n };\n onDragOver = (event) => {\n event.preventDefault();\n const { dataTransfer } = event;\n dataTransfer.dropEffect = 'move';\n };\n onDrop = (event) => {\n event.preventDefault();\n const fromId = event.dataTransfer.getData('text/plain');\n if (fromId === '' || fromId === entityId) {\n return;\n }\n onReorderPin(fromId, entityId);\n };\n }\n\n let dragHandleLabel: string | undefined;\n if (dragHandleSlot != null) {\n dragHandleLabel = reorderLabel;\n }\n\n return {\n id: entityId,\n data: {\n kind: 'entity',\n id: entityId,\n groupId,\n },\n label,\n href: config.routes.list,\n icon: renderIcon(\n groupIcon,\n <SidebarTasksSvg width={18} height={18} aria-hidden=\"true\" />,\n ),\n isActive: isActivePath(pathname, config.routes.list),\n ariaLabel: label,\n actionSlot: renderPinAction(entityId),\n dragHandleSlot,\n dragHandleLabel,\n draggable,\n onDragStart,\n onDragOver,\n onDrop,\n };\n };\n\n const sections: AdminSidebarSection[] = [];\n\n if (pinnedEntityIds.length > 0) {\n const pinnedItems = pinnedEntityIds\n .map((entityId) => {\n const groupMeta = entityGroupLookup.get(entityId);\n return buildEntityItem({\n entityId,\n groupId: groupMeta?.groupId,\n groupIcon: groupMeta?.icon,\n enableReorder: true,\n });\n })\n .filter((item): item is SidebarNavSectionItem => {\n return item != null;\n });\n\n if (pinnedItems.length > 0) {\n sections.push({\n id: 'pinned',\n title: t('sidebar.sections.pinned'),\n items: pinnedItems,\n collapsible: false,\n });\n }\n }\n\n entries.forEach(([groupId, group], index) => {\n if (group.isVisible != null && !group.isVisible(permissions)) {\n return;\n }\n\n const items: SidebarNavSectionItem[] = [];\n\n if (index === 0) {\n const dashboardDescriptor: BackofficeSidebarItemDescriptor = {\n kind: 'dashboard',\n id: 'dashboard',\n };\n const isDashboardVisible = sidebar?.isItemVisible?.(\n dashboardDescriptor,\n permissions,\n );\n if (isDashboardVisible !== false) {\n const dashboardLabel = t('sidebar.items.dashboard');\n if (\n normalizedQuery !== '' &&\n !dashboardLabel.toLowerCase().includes(normalizedQuery)\n ) {\n return;\n }\n items.push({\n id: 'dashboard',\n data: {\n kind: 'dashboard',\n id: 'dashboard',\n groupId,\n },\n label: dashboardLabel,\n href: basePath,\n icon: renderIcon(\n undefined,\n <SidebarHomeSvg width={18} height={18} aria-hidden=\"true\" />,\n ),\n isActive: isActivePath(pathname, basePath),\n ariaLabel: t('sidebar.items.dashboard'),\n });\n }\n }\n\n if (group.entities != null) {\n group.entities.forEach((entityId) => {\n const item = buildEntityItem({\n entityId,\n groupId,\n groupIcon: group.icon,\n });\n if (item != null) {\n items.push(item);\n }\n });\n }\n\n if (items.length === 0) {\n return;\n }\n\n let title: string | undefined;\n if (group.title != null) {\n title = resolveLabel(group.title, tApp);\n }\n\n const isCollapsed = collapsedByGroupId?.[groupId];\n let onCollapsedChange: ((collapsed: boolean) => void) | undefined;\n if (onGroupCollapsedChange != null) {\n onCollapsedChange = (collapsed: boolean) => {\n onGroupCollapsedChange(groupId, collapsed);\n };\n }\n\n sections.push({\n id: groupId,\n title,\n items,\n collapsible: true,\n defaultCollapsed: true,\n isCollapsed,\n onCollapsedChange,\n });\n });\n\n return sections;\n}\n","import { sprinkles } from '@plumile/ui';\n\nexport const root = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n width: 'full',\n});\n\nexport const banner = sprinkles({\n borderColor: 'borderStrong',\n});\n","import { type JSX } from 'react';\n\nimport { Button, InlineBanner } from '@plumile/ui';\nimport { useBackofficeReactTranslation } from '../../../i18n/useBackofficeReactTranslation.js';\n\nimport * as styles from './backofficeContentError.css.js';\n\ntype BackofficeContentErrorProps = {\n error: unknown;\n onRetry: () => void;\n};\n\nconst resolveErrorMessage = (error: unknown): string | null => {\n if (error instanceof Error) {\n const message = error.message.trim();\n if (message.length > 0) {\n return message;\n }\n return null;\n }\n if (typeof error === 'string') {\n const message = error.trim();\n if (message.length > 0) {\n return message;\n }\n return null;\n }\n return null;\n};\n\nexport const BackofficeContentError = ({\n error,\n onRetry,\n}: BackofficeContentErrorProps): JSX.Element => {\n const { t } = useBackofficeReactTranslation();\n const description = resolveErrorMessage(error);\n\n return (\n <div className={styles.root} role=\"alert\">\n <InlineBanner\n tone=\"danger\"\n className={styles.banner}\n actions={\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={onRetry}\n >\n {t('common.actions.retry')}\n </Button>\n }\n >\n {description}\n </InlineBanner>\n </div>\n );\n};\n\nexport default BackofficeContentError;\n","import { sprinkles } from '@plumile/ui';\n\nexport const container = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n width: 'full',\n minHeight: 'full',\n});\n\nexport const title = sprinkles({\n maxWidth: 'md',\n});\n\nexport const grid = sprinkles({\n display: 'grid',\n gap: 4,\n gridTemplateColumns: 'autoFitMinmax240',\n});\n\nexport const card = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n gap: 3,\n padding: 4,\n minHeight: 44,\n borderRadius: 'xl',\n borderWidth: 'default',\n borderStyle: 'solid',\n borderColor: 'borderSubtle',\n backgroundColor: 'surfaceMuted',\n});\n","import { type JSX } from 'react';\n\nimport { Skeleton } from '@plumile/ui';\n\nimport * as styles from './backofficeContentFallback.css.js';\n\nexport const BackofficeContentFallback = (): JSX.Element => {\n return (\n <div\n className={styles.container}\n role=\"status\"\n aria-live=\"polite\"\n aria-busy=\"true\"\n >\n <Skeleton variant=\"text\" width=\"38%\" className={styles.title} />\n <Skeleton variant=\"text\" width=\"62%\" />\n <div className={styles.grid}>\n {Array.from({ length: 4 }, (_, index) => {\n return (\n <div key={`content-skeleton-${index}`} className={styles.card}>\n <Skeleton variant=\"text\" width=\"46%\" />\n <Skeleton variant=\"text\" width=\"82%\" lines={2} />\n <Skeleton variant=\"block\" width=\"100%\" height={120} />\n </div>\n );\n })}\n </div>\n </div>\n );\n};\n\nexport default BackofficeContentFallback;\n","import { sprinkles } from '@plumile/ui';\n\nexport const root = sprinkles({\n display: 'flex',\n flexDirection: 'column',\n minHeight: 'full',\n width: 'full',\n minWidth: 0,\n});\n","import { Suspense, type JSX, type ReactNode } from 'react';\n\nimport { BackofficeErrorBoundary } from '../errors/BackofficeErrorBoundary.js';\n\nimport { BackofficeContentError } from './BackofficeContentError.js';\nimport { BackofficeContentFallback } from './BackofficeContentFallback.js';\nimport * as styles from './backofficeContentBoundary.css.js';\n\nexport type BackofficeContentBoundaryProps = {\n children: ReactNode;\n};\n\nexport const BackofficeContentBoundary = ({\n children,\n}: BackofficeContentBoundaryProps): JSX.Element => {\n return (\n <div className={styles.root}>\n <BackofficeErrorBoundary\n fallback={({ error, reset }) => {\n return <BackofficeContentError error={error} onRetry={reset} />;\n }}\n >\n <Suspense fallback={<BackofficeContentFallback />}>{children}</Suspense>\n </BackofficeErrorBoundary>\n </div>\n );\n};\n\nexport default BackofficeContentBoundary;\n","import type { BackofficeSidebarProfileViewer } from '@plumile/ui';\n\nexport type BackofficeViewerIdentity = {\n id: string;\n firstName: string;\n lastName: string;\n email: string;\n initials: string;\n};\n\ntype MapViewerToSidebarProfileViewInput = {\n viewer: BackofficeViewerIdentity | null | undefined;\n unknownUserLabel: string;\n};\n\nconst sanitizeToken = (value: string | null | undefined): string => {\n return value?.trim() ?? '';\n};\n\nexport const mapViewerToSidebarProfileView = ({\n viewer,\n unknownUserLabel,\n}: MapViewerToSidebarProfileViewInput): BackofficeSidebarProfileViewer => {\n const firstName = sanitizeToken(viewer?.firstName);\n const lastName = sanitizeToken(viewer?.lastName);\n const joinedDisplayName = [firstName, lastName]\n .filter((token) => {\n return token !== '';\n })\n .join(' ')\n .trim();\n let displayName = joinedDisplayName;\n if (displayName === '') {\n displayName = unknownUserLabel;\n }\n\n const email = sanitizeToken(viewer?.email);\n const initialsToken = sanitizeToken(viewer?.initials);\n let initials = initialsToken;\n if (initials === '') {\n initials = '?';\n }\n\n const ariaParts = [displayName];\n if (email !== '') {\n ariaParts.push(email);\n }\n\n return {\n displayName,\n email,\n initials,\n ariaLabel: ariaParts.join(' - '),\n };\n};\n\nexport default mapViewerToSidebarProfileView;\n","import {\n useMemo,\n type JSX,\n type ReactNode,\n useCallback,\n useContext,\n useState,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n commitMutation,\n usePreloadedQuery,\n type PreloadedQuery,\n} from 'react-relay';\nimport type {\n GraphQLTaggedNode,\n MutationParameters,\n OperationType,\n} from 'relay-runtime';\nimport { RoutingContext, useLocation } from '@plumile/router';\n\nimport {\n AdminShellLayout,\n BackofficeSidebarProfileMenu,\n EnvironmentBadge,\n GlobalSearchInput,\n ToastProvider,\n} from '@plumile/ui';\n\nimport { useBackofficeReactTranslation } from '../i18n/useBackofficeReactTranslation.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport type { LogoutResponse, LogoutVariables } from '../hooks/useAuth.js';\nimport { useBackofficeSidebarPins } from '../hooks/useBackofficeSidebarPins.js';\nimport { useSidebarGroupCollapse } from '../hooks/useSidebarGroupCollapse.js';\nimport { buildSidebarSections } from '../components/backoffice/layout/buildSidebarSections.js';\nimport { BackofficeContentBoundary } from '../components/backoffice/routing/BackofficeContentBoundary.js';\nimport {\n resolveSidebarGroups,\n resolveVisibleEntityIds,\n} from '../components/backoffice/layout/sidebarUtils.js';\nimport { BackofficeTopbarPortalContextProvider } from '../components/backoffice/layout/breadcrumb/BackofficeTopbarPortalContext.js';\nimport {\n mapViewerToSidebarProfileView,\n type BackofficeViewerIdentity,\n} from '../components/backoffice/layout/mapViewerToSidebarProfileView.js';\nimport { resetRelayStore } from '../relay/environment.js';\nimport { useRelayEnvironment } from '../relay/useRelayEnvironment.js';\nimport { getBackofficeLoginPath } from '../router/backofficeAuthPaths.js';\n\nexport type BackofficeLayoutPageProps = {\n children: ReactNode;\n permissionsQuery?: GraphQLTaggedNode;\n prepared?: PreloadedQuery<OperationType> | null;\n authStatus?: {\n isLoggedIn?: boolean | null;\n me?: BackofficeViewerIdentity | null;\n } | null;\n activeGroupId?: string | null;\n};\n\ntype LayoutShellProps = {\n children: ReactNode;\n permissions: unknown;\n authStatus?: {\n isLoggedIn?: boolean | null;\n me?: BackofficeViewerIdentity | null;\n } | null;\n activeGroupId?: string | null;\n};\n\nconst BackofficeLayoutShell = ({\n children,\n permissions,\n authStatus,\n activeGroupId,\n}: LayoutShellProps): JSX.Element => {\n const { t: tApp } = useTranslation();\n const { t } = useBackofficeReactTranslation();\n const { pathname } = useLocation();\n const routing = useContext(RoutingContext);\n const relayEnvironment = useRelayEnvironment();\n const {\n auth: authConfig,\n basePath,\n entities,\n sidebar,\n } = useBackofficeConfig();\n const [sidebarQuery, setSidebarQuery] = useState('');\n const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);\n const [isSigningOut, setIsSigningOut] = useState(false);\n const [topbarTarget, setTopbarTarget] = useState<HTMLDivElement | null>(null);\n\n const groups = useMemo(() => {\n return resolveSidebarGroups(entities, sidebar);\n }, [entities, sidebar]);\n\n const groupIds = useMemo(() => {\n return Object.keys(groups);\n }, [groups]);\n\n const visibleEntityIds = useMemo(() => {\n return resolveVisibleEntityIds(groups, entities, sidebar, permissions);\n }, [entities, groups, permissions, sidebar]);\n\n const {\n pins,\n toggle: togglePin,\n reorder: reorderPin,\n } = useBackofficeSidebarPins({ visibleEntityIds });\n\n const { collapsedByGroupId, setCollapsed } = useSidebarGroupCollapse({\n groupIds,\n activeGroupId,\n });\n\n const sections = useMemo(() => {\n return buildSidebarSections({\n basePath,\n pathname,\n entities,\n sidebar,\n permissions,\n searchQuery: sidebarQuery,\n tApp,\n t,\n pinnedEntityIds: pins,\n onTogglePin: togglePin,\n onReorderPin: reorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange: setCollapsed,\n });\n }, [\n basePath,\n collapsedByGroupId,\n entities,\n pathname,\n permissions,\n pins,\n reorderPin,\n setCollapsed,\n sidebar,\n sidebarQuery,\n t,\n tApp,\n togglePin,\n ]);\n\n const environment = useMemo(() => {\n const meta = import.meta as unknown as { env?: Record<string, unknown> };\n if (meta.env?.DEV === true) {\n return 'dev' as const;\n }\n return 'prod' as const;\n }, []);\n\n const handleSignOut = useCallback(() => {\n if (isSigningOut) {\n return;\n }\n\n type LogoutMutation = MutationParameters & {\n response: LogoutResponse;\n variables: LogoutVariables;\n };\n\n setIsSigningOut(true);\n\n const runSignOut = async (): Promise<void> => {\n try {\n const config = await authConfig.logout.load();\n await new Promise<void>((resolve, reject) => {\n commitMutation<LogoutMutation>(relayEnvironment, {\n mutation: config.logoutMutation,\n variables: {},\n onCompleted: () => {\n resolve();\n },\n onError: (error) => {\n reject(error);\n },\n });\n });\n localStorage.removeItem('auth_token');\n localStorage.removeItem('remember_me');\n resetRelayStore();\n routing?.history.push({ pathname: getBackofficeLoginPath(basePath) });\n } finally {\n setIsSigningOut(false);\n }\n };\n\n runSignOut().catch(() => {\n /* noop */\n });\n }, [authConfig.logout, basePath, isSigningOut, relayEnvironment, routing]);\n\n const viewer = authStatus?.me ?? null;\n const sidebarProfile = useMemo(() => {\n return mapViewerToSidebarProfileView({\n viewer,\n unknownUserLabel: t('sidebar.profile.unknownUser'),\n });\n }, [t, viewer]);\n\n const sidebarFooter = (\n <BackofficeSidebarProfileMenu\n collapsed={isSidebarCollapsed}\n viewer={sidebarProfile}\n labels={{\n sectionTitle: t('sidebar.profile.title'),\n menuAriaLabel: t('sidebar.profile.menuAriaLabel'),\n signOut: t('sidebar.profile.actions.signOut'),\n }}\n onSignOut={handleSignOut}\n isSigningOut={isSigningOut}\n />\n );\n\n let contentNode: JSX.Element | null = null;\n if (topbarTarget != null) {\n contentNode = (\n <BackofficeContentBoundary>{children}</BackofficeContentBoundary>\n );\n }\n\n return (\n <ToastProvider>\n <AdminShellLayout\n sidebar={{\n sections,\n header: <EnvironmentBadge environment={environment} />,\n search: (\n <GlobalSearchInput\n value={sidebarQuery}\n onChange={setSidebarQuery}\n placeholder={t('sidebar.search.placeholder')}\n ariaLabel={t('sidebar.search.placeholder')}\n />\n ),\n footer: sidebarFooter,\n isCollapsed: isSidebarCollapsed,\n onCollapsedChange: setIsSidebarCollapsed,\n }}\n topbar={{\n breadcrumb: <div ref={setTopbarTarget} />,\n }}\n >\n <BackofficeTopbarPortalContextProvider value={{ target: topbarTarget }}>\n {contentNode}\n </BackofficeTopbarPortalContextProvider>\n </AdminShellLayout>\n </ToastProvider>\n );\n};\n\ntype LayoutWithPermissionsProps = {\n children: ReactNode;\n permissionsQuery: GraphQLTaggedNode;\n prepared: PreloadedQuery<OperationType>;\n authStatus?: {\n isLoggedIn?: boolean | null;\n me?: BackofficeViewerIdentity | null;\n } | null;\n activeGroupId?: string | null;\n};\n\nconst LayoutWithPermissions = ({\n children,\n permissionsQuery,\n prepared,\n authStatus,\n activeGroupId,\n}: LayoutWithPermissionsProps): JSX.Element => {\n const permissions = usePreloadedQuery(permissionsQuery, prepared);\n\n return (\n <BackofficeLayoutShell\n permissions={permissions}\n authStatus={authStatus}\n activeGroupId={activeGroupId}\n >\n {children}\n </BackofficeLayoutShell>\n );\n};\n\nexport const BackofficeLayoutPage = ({\n children,\n permissionsQuery,\n prepared,\n authStatus,\n activeGroupId,\n}: BackofficeLayoutPageProps): JSX.Element => {\n if (permissionsQuery != null && prepared != null) {\n return (\n <LayoutWithPermissions\n permissionsQuery={permissionsQuery}\n prepared={prepared}\n authStatus={authStatus}\n activeGroupId={activeGroupId}\n >\n {children}\n </LayoutWithPermissions>\n );\n }\n\n return (\n <BackofficeLayoutShell\n permissions={null}\n authStatus={authStatus}\n activeGroupId={activeGroupId}\n >\n {children}\n </BackofficeLayoutShell>\n );\n};\n\nexport default BackofficeLayoutPage;\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BackofficeRightPageLayout-DZQvIHnj.js","names":[],"sources":["../../src/components/backoffice/columns/buildDataTableColumns.tsx","../../src/components/backoffice/layout/breadcrumb/assertValidBreadcrumb.ts","../../src/components/backoffice/layout/breadcrumb/BackofficeTopbarPortal.tsx","../../src/components/backoffice/layout/breadcrumb/backofficeTopbarBreadcrumb.css.ts","../../src/components/backoffice/layout/breadcrumb/BackofficeTopbarBreadcrumb.tsx","../../src/components/backoffice/layout/breadcrumb/BackofficeRightPageLayout.tsx"],"sourcesContent":["import { BACKOFFICE_DATE_TIME_OPTIONS } from '@plumile/backoffice-core/constants.js';\nimport type {\n BackofficeColumnSpec,\n BackofficeFieldSize,\n I18nLabel,\n} from '@plumile/backoffice-core/types.js';\nimport type { TFunction } from 'i18next';\nimport { Link } from '@plumile/router';\nimport { FormattedDate, Tag, type DataTableColumn } from '@plumile/ui';\n\nconst resolveLabel = (label: I18nLabel, tApp: TFunction): string => {\n return label(tApp);\n};\n\nconst resolveTextValue = (\n value: string | number | null,\n fallback: string,\n): string => {\n if (value == null) {\n return fallback;\n }\n if (typeof value === 'string' && value.trim() === '') {\n return fallback;\n }\n return String(value);\n};\n\nexport type BuildDataTableColumnsOptions = {\n tApp: TFunction;\n t: TFunction;\n resolveEntityHref?: (entityId: string, refId: string) => string | null;\n};\n\nexport type BackofficeSizedDataTableColumn<Row> = DataTableColumn<Row> & {\n size: BackofficeFieldSize;\n};\n\n/**\n *\n */\nexport function buildDataTableColumns<Row>(\n columns: readonly BackofficeColumnSpec<Row>[],\n options: BuildDataTableColumnsOptions,\n): readonly BackofficeSizedDataTableColumn<Row>[] {\n const { tApp, t, resolveEntityHref } = options;\n const fallback = t('common.notAvailable');\n const filteredColumns = columns.filter((column) => {\n return column.key !== 'id';\n });\n\n return filteredColumns.map((column) => {\n return {\n id: column.key,\n header: resolveLabel(column.header, tApp),\n size: column.size,\n cell: (row) => {\n const { cell } = column;\n switch (cell.type) {\n case 'text': {\n return resolveTextValue(cell.value(row), fallback);\n }\n case 'link': {\n const value = cell.value(row);\n if (\n value == null ||\n (typeof value === 'string' && value.trim() === '')\n ) {\n return fallback;\n }\n return <Link to={cell.to(row)}>{value}</Link>;\n }\n case 'badge': {\n const value = cell.value(row);\n if (value == null || value.trim() === '') {\n return fallback;\n }\n let { tone } = cell;\n if (typeof tone === 'function') {\n tone = tone(row);\n }\n return <Tag tone={tone}>{value}</Tag>;\n }\n case 'dateTime': {\n const value = cell.value(row);\n return (\n <FormattedDate\n value={value}\n fallback={fallback}\n options={BACKOFFICE_DATE_TIME_OPTIONS}\n />\n );\n }\n case 'entityRef': {\n const id = cell.value(row);\n if (id.trim() === '') {\n return fallback;\n }\n const href = resolveEntityHref?.(cell.entity, id) ?? null;\n if (href != null) {\n return <Link to={href}>{t('actions.view')}</Link>;\n }\n return fallback;\n }\n case 'custom': {\n const rendered = cell.render(row);\n if (rendered == null || rendered === '') {\n return fallback;\n }\n return <>{rendered}</>;\n }\n default: {\n return fallback;\n }\n }\n },\n };\n });\n}\n","import type {\n BackofficeTopbarBreadcrumbItem,\n BreadcrumbContractErrorCode,\n} from './types.js';\n\nconst formatContractError = (\n code: BreadcrumbContractErrorCode,\n details?: string,\n): Error => {\n if (details == null) {\n return new Error(`Invalid breadcrumb contract: ${code}`);\n }\n return new Error(`Invalid breadcrumb contract: ${code} (${details})`);\n};\n\nexport const assertValidBreadcrumb = (\n items: readonly BackofficeTopbarBreadcrumbItem[] | null | undefined,\n): readonly BackofficeTopbarBreadcrumbItem[] => {\n if (items == null) {\n throw formatContractError('MISSING_BREADCRUMB');\n }\n if (items.length === 0) {\n throw formatContractError('EMPTY_BREADCRUMB');\n }\n\n const seen = new Set<string>();\n items.forEach((item, index) => {\n if (typeof item.id !== 'string' || item.id.trim() === '') {\n throw formatContractError('INVALID_SEGMENT_ID', `index=${index}`);\n }\n\n if (seen.has(item.id)) {\n throw formatContractError(\n 'INVALID_SEGMENT_ID',\n `duplicate id=\"${item.id}\"`,\n );\n }\n seen.add(item.id);\n });\n\n const last = items[items.length - 1];\n if (last?.isCurrent !== true) {\n throw formatContractError('MISSING_CURRENT_SEGMENT');\n }\n\n return items;\n};\n","import { type JSX, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { useBackofficeTopbarPortalContext } from './BackofficeTopbarPortalContext.js';\n\nexport type BackofficeTopbarPortalProps = {\n children: ReactNode;\n};\n\nexport const BackofficeTopbarPortal = ({\n children,\n}: BackofficeTopbarPortalProps): JSX.Element | null => {\n const { target } = useBackofficeTopbarPortalContext();\n if (target == null) {\n throw new Error(\n 'Backoffice topbar target is missing. Ensure BackofficeLayoutPage provides a topbar breadcrumb mount target before rendering right-side pages.',\n );\n }\n return createPortal(children, target);\n};\n\nexport default BackofficeTopbarPortal;\n","import { sprinkles } from '@plumile/ui';\nimport { style } from '@vanilla-extract/css';\n\nconst INLINE_FLEX = 'inline-flex' as const;\n\nexport const nav = sprinkles({\n display: INLINE_FLEX,\n alignItems: 'center',\n});\n\nexport const list = style([\n sprinkles({\n display: INLINE_FLEX,\n alignItems: 'center',\n gap: 2,\n }),\n {\n margin: 0,\n padding: 0,\n listStyle: 'none',\n },\n]);\n\nexport const item = sprinkles({\n display: INLINE_FLEX,\n alignItems: 'center',\n gap: 2,\n});\n\nexport const separator = sprinkles({\n color: 'textSecondary',\n fontSize: 'sm',\n lineHeight: 'normal',\n});\n\nexport const link = style([\n sprinkles({\n color: 'textSecondary',\n fontSize: 'sm',\n lineHeight: 'normal',\n }),\n {\n textDecoration: 'none',\n selectors: {\n '&:hover': {\n textDecoration: 'underline',\n },\n },\n },\n]);\n\nexport const current = sprinkles({\n color: 'text',\n fontSize: 'sm',\n lineHeight: 'normal',\n fontWeight: 'semibold',\n});\n","import { type JSX } from 'react';\nimport { Link } from '@plumile/router';\n\nimport type { BackofficeTopbarBreadcrumbItem } from './types.js';\nimport * as styles from './backofficeTopbarBreadcrumb.css.js';\n\nexport type BackofficeTopbarBreadcrumbProps = {\n items: readonly BackofficeTopbarBreadcrumbItem[];\n};\n\nexport const BackofficeTopbarBreadcrumb = ({\n items,\n}: BackofficeTopbarBreadcrumbProps): JSX.Element => {\n return (\n <nav className={styles.nav} aria-label=\"Breadcrumb\">\n <ol className={styles.list}>\n {items.map((item, index) => {\n const isFirst = index === 0;\n const isCurrent = item.isCurrent === true;\n const key = `${item.id}-${index}`;\n const shouldRenderLink = item.to != null && !isCurrent;\n let content: JSX.Element;\n\n if (shouldRenderLink) {\n content = (\n <Link to={item.to} className={styles.link}>\n {item.label}\n </Link>\n );\n } else {\n let className = styles.link;\n if (isCurrent) {\n className = styles.current;\n }\n content = <span className={className}>{item.label}</span>;\n }\n\n return (\n <li key={key} className={styles.item}>\n {!isFirst && (\n <span className={styles.separator} aria-hidden=\"true\">\n /\n </span>\n )}\n {content}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n};\n\nexport default BackofficeTopbarBreadcrumb;\n","import { type JSX, type ReactNode } from 'react';\n\nimport { assertValidBreadcrumb } from './assertValidBreadcrumb.js';\nimport { BackofficeTopbarPortal } from './BackofficeTopbarPortal.js';\nimport { BackofficeTopbarBreadcrumb } from './BackofficeTopbarBreadcrumb.js';\nimport type { BackofficeTopbarBreadcrumbItem } from './types.js';\n\nexport type BackofficeRightPageLayoutProps = {\n breadcrumb: readonly BackofficeTopbarBreadcrumbItem[];\n children: ReactNode;\n};\n\nexport const BackofficeRightPageLayout = ({\n breadcrumb,\n children,\n}: BackofficeRightPageLayoutProps): JSX.Element => {\n const items = assertValidBreadcrumb(breadcrumb);\n\n return (\n <>\n <BackofficeTopbarPortal>\n <BackofficeTopbarBreadcrumb items={items} />\n </BackofficeTopbarPortal>\n <>{children}</>\n </>\n );\n};\n\nexport default BackofficeRightPageLayout;\n"],"mappings":"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"}
|