@plumile/backoffice-react 0.1.115 → 0.1.117

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.
Files changed (72) hide show
  1. package/lib/esm/auth/authRefreshNotice.css.js +1 -0
  2. package/lib/esm/components/backoffice/billing/BackofficeBillingUsageChart.js +60 -0
  3. package/lib/esm/components/backoffice/billing/BackofficeBillingUsageChart.js.map +1 -0
  4. package/lib/esm/components/backoffice/billing/backofficeBillingUsageChart.css.js +7 -0
  5. package/lib/esm/components/backoffice/billing/backofficeBillingUsageChart.css.js.map +1 -0
  6. package/lib/esm/components/backoffice/columns/buildDataTableColumns.js +6 -6
  7. package/lib/esm/components/backoffice/detail/BackofficeDetailFlagTag.css.js +0 -1
  8. package/lib/esm/components/backoffice/layout/buildSidebarSections.js +154 -135
  9. package/lib/esm/components/backoffice/layout/buildSidebarSections.js.map +1 -1
  10. package/lib/esm/components/backoffice/layout/sidebarUtils.js +24 -21
  11. package/lib/esm/components/backoffice/layout/sidebarUtils.js.map +1 -1
  12. package/lib/esm/components/backoffice/links/resolveBackofficeLink.js +62 -54
  13. package/lib/esm/components/backoffice/links/resolveBackofficeLink.js.map +1 -1
  14. package/lib/esm/components/backoffice/links/resolveBackofficeTargetIcon.js +1 -1
  15. package/lib/esm/components/backoffice/links/resolveBackofficeTargetIcon.js.map +1 -1
  16. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js +271 -263
  17. package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js.map +1 -1
  18. package/lib/esm/components/backoffice/scaffolds/backofficeEntityListScaffold.css.js +2 -2
  19. package/lib/esm/components/backoffice/scaffolds/backofficeEntityListScaffold.css.js.map +1 -1
  20. package/lib/esm/components/backoffice/scaffolds/backofficeListScrollMode.js +6 -0
  21. package/lib/esm/components/backoffice/scaffolds/backofficeListScrollMode.js.map +1 -0
  22. package/lib/esm/index.js +75 -74
  23. package/lib/esm/pages/BackofficeDashboardPage.helpers.js +1 -0
  24. package/lib/esm/pages/BackofficeDashboardPage.helpers.js.map +1 -1
  25. package/lib/esm/pages/BackofficeDashboardPage.js +181 -154
  26. package/lib/esm/pages/BackofficeDashboardPage.js.map +1 -1
  27. package/lib/esm/pages/BackofficeEntityDetailPage.js +12 -12
  28. package/lib/esm/pages/BackofficeLayoutPage.js +134 -129
  29. package/lib/esm/pages/BackofficeLayoutPage.js.map +1 -1
  30. package/lib/esm/provider/BackofficeConfigContext.js.map +1 -1
  31. package/lib/esm/provider/BackofficeProvider.js +126 -121
  32. package/lib/esm/provider/BackofficeProvider.js.map +1 -1
  33. package/lib/esm/provider/dashboardRegistrations.js +17 -0
  34. package/lib/esm/provider/dashboardRegistrations.js.map +1 -0
  35. package/lib/esm/router/createBackofficeRoutes.js +148 -131
  36. package/lib/esm/router/createBackofficeRoutes.js.map +1 -1
  37. package/lib/types/components/backoffice/billing/BackofficeBillingUsageChart.d.ts +25 -0
  38. package/lib/types/components/backoffice/billing/BackofficeBillingUsageChart.d.ts.map +1 -0
  39. package/lib/types/components/backoffice/billing/BackofficeBillingUsageChart.stories.d.ts +41 -0
  40. package/lib/types/components/backoffice/billing/BackofficeBillingUsageChart.stories.d.ts.map +1 -0
  41. package/lib/types/components/backoffice/billing/backofficeBillingUsageChart.css.d.ts +4 -0
  42. package/lib/types/components/backoffice/billing/backofficeBillingUsageChart.css.d.ts.map +1 -0
  43. package/lib/types/components/backoffice/layout/buildSidebarSections.d.ts +2 -1
  44. package/lib/types/components/backoffice/layout/buildSidebarSections.d.ts.map +1 -1
  45. package/lib/types/components/backoffice/layout/sidebarUtils.d.ts +1 -0
  46. package/lib/types/components/backoffice/layout/sidebarUtils.d.ts.map +1 -1
  47. package/lib/types/components/backoffice/links/resolveBackofficeLink.d.ts.map +1 -1
  48. package/lib/types/components/backoffice/links/types.d.ts +1 -0
  49. package/lib/types/components/backoffice/links/types.d.ts.map +1 -1
  50. package/lib/types/components/backoffice/scaffolds/BackofficeEntityListScaffold.d.ts.map +1 -1
  51. package/lib/types/components/backoffice/scaffolds/backofficeEntityListScaffold.css.d.ts +1 -0
  52. package/lib/types/components/backoffice/scaffolds/backofficeEntityListScaffold.css.d.ts.map +1 -1
  53. package/lib/types/components/backoffice/scaffolds/backofficeListScrollMode.d.ts +2 -0
  54. package/lib/types/components/backoffice/scaffolds/backofficeListScrollMode.d.ts.map +1 -0
  55. package/lib/types/index.d.ts +2 -1
  56. package/lib/types/index.d.ts.map +1 -1
  57. package/lib/types/pages/BackofficeDashboardPage.d.ts +5 -1
  58. package/lib/types/pages/BackofficeDashboardPage.d.ts.map +1 -1
  59. package/lib/types/pages/BackofficeDashboardPage.helpers.d.ts.map +1 -1
  60. package/lib/types/pages/BackofficeDashboardPage.stories.d.ts +9 -0
  61. package/lib/types/pages/BackofficeDashboardPage.stories.d.ts.map +1 -0
  62. package/lib/types/pages/BackofficeLayoutPage.d.ts.map +1 -1
  63. package/lib/types/provider/BackofficeConfigContext.d.ts +2 -1
  64. package/lib/types/provider/BackofficeConfigContext.d.ts.map +1 -1
  65. package/lib/types/provider/BackofficeProvider.d.ts.map +1 -1
  66. package/lib/types/provider/dashboardRegistrations.d.ts +4 -0
  67. package/lib/types/provider/dashboardRegistrations.d.ts.map +1 -0
  68. package/lib/types/provider/types.d.ts +8 -1
  69. package/lib/types/provider/types.d.ts.map +1 -1
  70. package/lib/types/router/createBackofficeRoutes.d.ts +8 -2
  71. package/lib/types/router/createBackofficeRoutes.d.ts.map +1 -1
  72. package/package.json +13 -13
@@ -7,23 +7,23 @@ import { buildSidebarSections as a } from "../components/backoffice/layout/build
7
7
  import ne from "../components/backoffice/layout/mapViewerToSidebarProfileView.js";
8
8
  import { BackofficeContentBoundary as re } from "../components/backoffice/routing/BackofficeContentBoundary.js";
9
9
  import { resetRelayStore as ie } from "../relay/environment.js";
10
- import { useRelayEnvironment as o } from "../relay/useRelayEnvironment.js";
11
- import ae from "../hooks/useBackofficeSidebarPins.js";
12
- import oe from "../hooks/useSidebarGroupCollapse.js";
13
- import { getBackofficeLoginPath as se } from "../router/backofficeAuthPaths.js";
14
- import { useCallback as ce, useContext as le, useEffect as s, useMemo as c, useState as l } from "react";
15
- import { jsx as u } from "react/jsx-runtime";
16
- import { useTranslation as ue } from "react-i18next";
17
- import { commitMutation as de, usePreloadedQuery as d } from "react-relay";
18
- import { ToastProvider as f } from "@plumile/ui/atomic/molecules/toast/ToastProvider.js";
19
- import fe from "@plumile/router/routing/RoutingContext.js";
20
- import { GlobalSearchInput as pe } from "@plumile/ui/backoffice/molecules/global_search_input/GlobalSearchInput.js";
21
- import me from "@plumile/router/routing/useLocation.js";
22
- import { AdminShellLayout as he } from "@plumile/ui/admin/templates/admin_shell_layout/AdminShellLayout.js";
23
- import { EnvironmentBadge as p } from "@plumile/ui/backoffice/atoms/environment_badge/EnvironmentBadge.js";
24
- import { BackofficeSidebarProfileMenu as m } from "@plumile/ui/backoffice/molecules/sidebar_profile_menu/BackofficeSidebarProfileMenu.js";
10
+ import { useRelayEnvironment as ae } from "../relay/useRelayEnvironment.js";
11
+ import oe from "../hooks/useBackofficeSidebarPins.js";
12
+ import se from "../hooks/useSidebarGroupCollapse.js";
13
+ import { getBackofficeLoginPath as ce } from "../router/backofficeAuthPaths.js";
14
+ import { useCallback as le, useContext as ue, useEffect as o, useMemo as s, useState as c } from "react";
15
+ import { jsx as l } from "react/jsx-runtime";
16
+ import { useTranslation as de } from "react-i18next";
17
+ import { commitMutation as fe, usePreloadedQuery as u } from "react-relay";
18
+ import { ToastProvider as pe } from "@plumile/ui/atomic/molecules/toast/ToastProvider.js";
19
+ import me from "@plumile/router/routing/RoutingContext.js";
20
+ import { GlobalSearchInput as he } from "@plumile/ui/backoffice/molecules/global_search_input/GlobalSearchInput.js";
21
+ import ge from "@plumile/router/routing/useLocation.js";
22
+ import { AdminShellLayout as _e } from "@plumile/ui/admin/templates/admin_shell_layout/AdminShellLayout.js";
23
+ import { EnvironmentBadge as d } from "@plumile/ui/backoffice/atoms/environment_badge/EnvironmentBadge.js";
24
+ import { BackofficeSidebarProfileMenu as f } from "@plumile/ui/backoffice/molecules/sidebar_profile_menu/BackofficeSidebarProfileMenu.js";
25
25
  //#region src/pages/BackofficeLayoutPage.tsx
26
- var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", ve = (e) => {
26
+ var ve = "plumile:backoffice:recent-items", p = "plumile:backoffice:sidebar", ye = (e) => {
27
27
  if (typeof window > "u") return [];
28
28
  try {
29
29
  let t = window.localStorage.getItem(e);
@@ -37,80 +37,81 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
37
37
  } catch {
38
38
  return [];
39
39
  }
40
- }, h = (e, t) => {
40
+ }, be = (e, t) => {
41
41
  if (!(typeof window > "u")) try {
42
42
  window.localStorage.setItem(e, JSON.stringify(t));
43
43
  } catch {}
44
- }, g = ({ children: d, permissions: g, authStatus: _, activeGroupId: v }) => {
45
- let { t: y } = ue(), { t: b } = e(), { pathname: x } = me(), S = le(fe), C = o(), { auth: w, basePath: T, entities: E, sidebar: D } = t(), [O, ye] = l(""), k = D?.preferences?.storageKey ?? _e, A = D?.preferences?.persistCollapsed === !0, [j, be] = l(() => {
46
- if (!A || typeof window > "u") return !1;
44
+ }, m = ({ children: u, permissions: m, authStatus: h, activeGroupId: g }) => {
45
+ let { t: _ } = de(), { t: v } = e(), { pathname: y } = ge(), b = ue(me), x = ae(), { auth: S, basePath: C, dashboards: w, entities: T, sidebar: E } = t(), [D, xe] = c(""), O = E?.preferences?.storageKey ?? p, k = E?.preferences?.persistCollapsed === !0, [A, j] = c(() => {
46
+ if (!k || typeof window > "u") return !1;
47
47
  try {
48
- return window.localStorage.getItem(`${k}:collapsed`) === "true";
48
+ return window.localStorage.getItem(`${O}:collapsed`) === "true";
49
49
  } catch {
50
50
  return !1;
51
51
  }
52
- }), [M, N] = l(!1), [P, xe] = l(null), F = D?.recentItems, I = F?.enabled === !0, L = F?.storageKey ?? ge, R = F?.maxItems ?? 8, [z, Se] = l(() => I ? ve(L) : []);
53
- s(() => {
54
- if (!(!A || typeof window > "u")) try {
55
- window.localStorage.setItem(`${k}:collapsed`, String(j));
52
+ }), [M, N] = c(!1), [P, Se] = c(null), F = E?.recentItems, I = F?.enabled === !0, L = F?.storageKey ?? ve, R = F?.maxItems ?? 8, [z, Ce] = c(() => I ? ye(L) : []);
53
+ o(() => {
54
+ if (!(!k || typeof window > "u")) try {
55
+ window.localStorage.setItem(`${O}:collapsed`, String(A));
56
56
  } catch {}
57
57
  }, [
58
- j,
59
58
  A,
60
- k
59
+ k,
60
+ O
61
61
  ]);
62
- let B = c(() => i(E, D), [E, D]), Ce = c(() => Object.keys(B), [B]), we = c(() => Object.fromEntries(Object.entries(B).map(([e, t]) => [e, t.behavior?.defaultCollapsed ?? !0])), [B]), Te = c(() => ee(B, E, D, g), [
63
- E,
62
+ let B = s(() => i(T, E), [T, E]), we = s(() => Object.keys(B), [B]), Te = s(() => Object.fromEntries(Object.entries(B).map(([e, t]) => [e, t.behavior?.defaultCollapsed ?? !0])), [B]), Ee = s(() => ee(B, T, E, m), [
63
+ T,
64
64
  B,
65
- g,
66
- D
67
- ]), V = c(() => r(x, E), [E, x]);
68
- s(() => {
65
+ m,
66
+ E
67
+ ]), V = s(() => r(y, T), [T, y]);
68
+ o(() => {
69
69
  if (!I || V == null) return;
70
- let e = E[V];
70
+ let e = T[V];
71
71
  if (e == null || e.kind !== "tool" && !e.hasList) return;
72
72
  let t = e.routes.list, n = "entity";
73
73
  e.kind === "tool" && (n = "tool");
74
74
  let r = {
75
75
  kind: n,
76
76
  id: V,
77
- label: e.label(y),
77
+ label: e.label(_),
78
78
  href: t,
79
79
  visitedAt: Date.now()
80
80
  };
81
- Se((e) => {
81
+ Ce((e) => {
82
82
  let t = [r, ...e.filter((e) => e.id !== r.id || e.kind !== r.kind)].slice(0, R);
83
- return h(L, t), t;
83
+ return be(L, t), t;
84
84
  });
85
85
  }, [
86
86
  V,
87
- E,
87
+ T,
88
88
  I,
89
89
  R,
90
90
  L,
91
- y
91
+ _
92
92
  ]);
93
- let { pins: H, toggle: U, reorder: W } = ae({
94
- enabled: D?.pinnedItems?.enabled === !0,
95
- storageKey: D?.pinnedItems?.storageKey,
96
- visibleEntityIds: Te
93
+ let { pins: H, toggle: U, reorder: W } = oe({
94
+ enabled: E?.pinnedItems?.enabled === !0,
95
+ storageKey: E?.pinnedItems?.storageKey,
96
+ visibleEntityIds: Ee
97
97
  }), G;
98
- D?.preferences?.storageKey != null && (G = `${D.preferences.storageKey}:groups`);
99
- let { collapsedByGroupId: K, setCollapsed: q } = oe({
100
- groupIds: Ce,
101
- activeGroupId: v,
102
- defaultCollapsedByGroupId: we,
103
- persist: D?.preferences?.persistGroups === !0,
98
+ E?.preferences?.storageKey != null && (G = `${E.preferences.storageKey}:groups`);
99
+ let { collapsedByGroupId: K, setCollapsed: q } = se({
100
+ groupIds: we,
101
+ activeGroupId: g,
102
+ defaultCollapsedByGroupId: Te,
103
+ persist: E?.preferences?.persistGroups === !0,
104
104
  storageKey: G
105
- }), Ee = c(() => a({
106
- basePath: T,
107
- pathname: x,
108
- entities: E,
109
- sidebar: D,
110
- permissions: g,
111
- searchQuery: O,
112
- tApp: y,
113
- t: b,
105
+ }), De = s(() => a({
106
+ basePath: C,
107
+ pathname: y,
108
+ entities: T,
109
+ dashboards: w,
110
+ sidebar: E,
111
+ permissions: m,
112
+ searchQuery: D,
113
+ tApp: _,
114
+ t: v,
114
115
  pinnedEntityIds: H,
115
116
  recentItems: z,
116
117
  onTogglePin: U,
@@ -119,29 +120,31 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
119
120
  onGroupCollapsedChange: q,
120
121
  sidebarCollapsed: !1
121
122
  }), [
122
- T,
123
+ C,
123
124
  K,
124
- E,
125
- x,
126
- g,
125
+ T,
126
+ w,
127
+ y,
128
+ m,
127
129
  H,
128
130
  z,
129
131
  W,
130
132
  q,
133
+ E,
131
134
  D,
132
- O,
133
- b,
134
- y,
135
+ v,
136
+ _,
135
137
  U
136
- ]), De = c(() => a({
137
- basePath: T,
138
- pathname: x,
139
- entities: E,
140
- sidebar: D,
141
- permissions: g,
142
- searchQuery: O,
143
- tApp: y,
144
- t: b,
138
+ ]), Oe = s(() => a({
139
+ basePath: C,
140
+ pathname: y,
141
+ entities: T,
142
+ dashboards: w,
143
+ sidebar: E,
144
+ permissions: m,
145
+ searchQuery: D,
146
+ tApp: _,
147
+ t: v,
145
148
  pinnedEntityIds: H,
146
149
  recentItems: z,
147
150
  onTogglePin: U,
@@ -150,26 +153,27 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
150
153
  onGroupCollapsedChange: q,
151
154
  sidebarCollapsed: !1
152
155
  }), [
153
- T,
156
+ C,
154
157
  K,
155
- E,
156
- x,
157
- g,
158
+ T,
159
+ w,
160
+ y,
161
+ m,
158
162
  H,
159
163
  z,
160
164
  W,
161
165
  q,
166
+ E,
162
167
  D,
163
- O,
164
- b,
165
- y,
168
+ v,
169
+ _,
166
170
  U
167
- ]), J = c(() => import.meta.env?.DEV === !0 ? "dev" : "prod", []), Y = ce(() => {
171
+ ]), J = s(() => import.meta.env?.DEV === !0 ? "dev" : "prod", []), Y = le(() => {
168
172
  M || (N(!0), (async () => {
169
173
  try {
170
- let e = await w.logout.load();
174
+ let e = await S.logout.load();
171
175
  await new Promise((t, n) => {
172
- de(C, {
176
+ fe(x, {
173
177
  mutation: e.logoutMutation,
174
178
  variables: {},
175
179
  onCompleted: () => {
@@ -179,100 +183,101 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
179
183
  n(e);
180
184
  }
181
185
  });
182
- }), localStorage.removeItem("auth_token"), localStorage.removeItem("remember_me"), ie(), S?.history.push({ pathname: se(T) });
186
+ }), localStorage.removeItem("auth_token"), localStorage.removeItem("remember_me"), ie(), b?.history.push({ pathname: ce(C) });
183
187
  } finally {
184
188
  N(!1);
185
189
  }
186
190
  })().catch(() => {}));
187
191
  }, [
188
- w.logout,
189
- T,
190
- M,
192
+ S.logout,
191
193
  C,
192
- S
193
- ]), X = _?.me ?? null, Z = c(() => ne({
194
+ M,
195
+ x,
196
+ b
197
+ ]), X = h?.me ?? null, Z = s(() => ne({
194
198
  viewer: X,
195
- unknownUserLabel: b("sidebar.profile.unknownUser")
196
- }), [b, X]), Oe = /* @__PURE__ */ u(m, {
199
+ unknownUserLabel: v("sidebar.profile.unknownUser")
200
+ }), [v, X]), ke = /* @__PURE__ */ l(f, {
197
201
  collapsed: !1,
198
202
  viewer: Z,
199
203
  labels: {
200
- sectionTitle: b("sidebar.profile.title"),
201
- menuAriaLabel: b("sidebar.profile.menuAriaLabel"),
202
- signOut: b("sidebar.profile.actions.signOut")
204
+ sectionTitle: v("sidebar.profile.title"),
205
+ menuAriaLabel: v("sidebar.profile.menuAriaLabel"),
206
+ signOut: v("sidebar.profile.actions.signOut")
203
207
  },
204
208
  onSignOut: Y,
205
209
  isSigningOut: M
206
- }), ke = /* @__PURE__ */ u(m, {
210
+ }), Ae = /* @__PURE__ */ l(f, {
207
211
  collapsed: !1,
208
212
  viewer: Z,
209
213
  labels: {
210
- sectionTitle: b("sidebar.profile.title"),
211
- menuAriaLabel: b("sidebar.profile.menuAriaLabel"),
212
- signOut: b("sidebar.profile.actions.signOut")
214
+ sectionTitle: v("sidebar.profile.title"),
215
+ menuAriaLabel: v("sidebar.profile.menuAriaLabel"),
216
+ signOut: v("sidebar.profile.actions.signOut")
213
217
  },
214
218
  onSignOut: Y,
215
219
  isSigningOut: M
216
220
  }), Q = null;
217
- P != null && (Q = /* @__PURE__ */ u(re, { children: d }));
218
- let $ = /* @__PURE__ */ u(pe, {
219
- value: O,
220
- onChange: ye,
221
- placeholder: b("sidebar.search.placeholder"),
222
- ariaLabel: b("sidebar.search.placeholder")
221
+ P != null && (Q = /* @__PURE__ */ l(re, { children: u }));
222
+ let $ = /* @__PURE__ */ l(he, {
223
+ value: D,
224
+ onChange: xe,
225
+ placeholder: v("sidebar.search.placeholder"),
226
+ ariaLabel: v("sidebar.search.placeholder")
223
227
  });
224
- return /* @__PURE__ */ u(f, { children: /* @__PURE__ */ u(he, {
228
+ return /* @__PURE__ */ l(pe, { children: /* @__PURE__ */ l(_e, {
225
229
  sidebar: {
226
- sections: Ee,
227
- header: /* @__PURE__ */ u(p, { environment: J }),
230
+ sections: De,
231
+ header: /* @__PURE__ */ l(d, { environment: J }),
228
232
  search: $,
229
- footer: Oe,
230
- isCollapsed: j,
231
- onCollapsedChange: be,
232
- collapseToggleLabel: b("sidebar.actions.collapseSidebar"),
233
- expandToggleLabel: b("sidebar.actions.expandSidebar"),
234
- navigationAriaLabel: b("sidebar.navigationAriaLabel")
233
+ footer: ke,
234
+ isCollapsed: A,
235
+ onCollapsedChange: j,
236
+ collapseToggleLabel: v("sidebar.actions.collapseSidebar"),
237
+ expandToggleLabel: v("sidebar.actions.expandSidebar"),
238
+ navigationAriaLabel: v("sidebar.navigationAriaLabel")
235
239
  },
236
240
  mobileSidebar: {
237
- sections: De,
238
- header: /* @__PURE__ */ u(p, { environment: J }),
241
+ sections: Oe,
242
+ header: /* @__PURE__ */ l(d, { environment: J }),
239
243
  search: $,
240
- footer: ke,
244
+ footer: Ae,
241
245
  isCollapsed: !1,
242
246
  hideCollapseToggle: !0,
243
- navigationAriaLabel: b("sidebar.navigationAriaLabel")
247
+ navigationAriaLabel: v("sidebar.navigationAriaLabel")
244
248
  },
245
- topbar: { breadcrumb: /* @__PURE__ */ u("div", { ref: xe }) },
246
- children: /* @__PURE__ */ u(te, {
247
- permissions: g,
248
- children: /* @__PURE__ */ u(n, {
249
+ topbar: { breadcrumb: /* @__PURE__ */ l("div", { ref: Se }) },
250
+ contentScrollMode: "contained",
251
+ children: /* @__PURE__ */ l(te, {
252
+ permissions: m,
253
+ children: /* @__PURE__ */ l(n, {
249
254
  value: {
250
255
  target: P,
251
- dashboardHref: T,
252
- dashboardLabel: b("sidebar.items.dashboard")
256
+ dashboardHref: C,
257
+ dashboardLabel: v("sidebar.items.dashboard")
253
258
  },
254
259
  children: Q
255
260
  })
256
261
  })
257
262
  }) });
258
- }, _ = ({ children: e, permissionsQuery: t, prepared: n, authStatus: r, activeGroupId: i }) => /* @__PURE__ */ u(g, {
259
- permissions: d(t, n),
263
+ }, h = ({ children: e, permissionsQuery: t, prepared: n, authStatus: r, activeGroupId: i }) => /* @__PURE__ */ l(m, {
264
+ permissions: u(t, n),
260
265
  authStatus: r,
261
266
  activeGroupId: i,
262
267
  children: e
263
- }), v = ({ children: e, permissionsQuery: t, prepared: n, authStatus: r, activeGroupId: i }) => t != null && n != null ? /* @__PURE__ */ u(_, {
268
+ }), g = ({ children: e, permissionsQuery: t, prepared: n, authStatus: r, activeGroupId: i }) => t != null && n != null ? /* @__PURE__ */ l(h, {
264
269
  permissionsQuery: t,
265
270
  prepared: n,
266
271
  authStatus: r,
267
272
  activeGroupId: i,
268
273
  children: e
269
- }) : /* @__PURE__ */ u(g, {
274
+ }) : /* @__PURE__ */ l(m, {
270
275
  permissions: null,
271
276
  authStatus: r,
272
277
  activeGroupId: i,
273
278
  children: e
274
279
  });
275
280
  //#endregion
276
- export { v as BackofficeLayoutPage, v as default };
281
+ export { g as BackofficeLayoutPage, g as default };
277
282
 
278
283
  //# sourceMappingURL=BackofficeLayoutPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BackofficeLayoutPage.js","names":[],"sources":["../../../src/pages/BackofficeLayoutPage.tsx"],"sourcesContent":["import {\n useEffect,\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 from '@plumile/router/routing/RoutingContext.js';\nimport useLocation from '@plumile/router/routing/useLocation.js';\n\nimport { AdminShellLayout } from '@plumile/ui/admin/templates/admin_shell_layout/AdminShellLayout.js';\nimport { ToastProvider } from '@plumile/ui/atomic/molecules/toast/ToastProvider.js';\nimport { EnvironmentBadge } from '@plumile/ui/backoffice/atoms/environment_badge/EnvironmentBadge.js';\nimport { GlobalSearchInput } from '@plumile/ui/backoffice/molecules/global_search_input/GlobalSearchInput.js';\nimport { BackofficeSidebarProfileMenu } from '@plumile/ui/backoffice/molecules/sidebar_profile_menu/BackofficeSidebarProfileMenu.js';\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 resolveActiveEntityId,\n resolveSidebarGroups,\n resolveVisibleEntityIds,\n} from '../components/backoffice/layout/sidebarUtils.js';\nimport { BackofficeTopbarPortalContextProvider } from '../components/backoffice/layout/breadcrumb/BackofficeTopbarPortalContext.js';\nimport { BackofficePermissionsProvider } from '../components/backoffice/layout/BackofficePermissionsContext.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';\nimport type { BackofficeSidebarRecentItem } from '../provider/types.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 DEFAULT_RECENT_ITEMS_STORAGE_KEY = 'plumile:backoffice:recent-items';\nconst DEFAULT_SIDEBAR_PREFS_STORAGE_KEY = 'plumile:backoffice:sidebar';\n\nconst readRecentItems = (\n storageKey: string,\n): readonly BackofficeSidebarRecentItem[] => {\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 unknown;\n if (!Array.isArray(parsed)) {\n return [];\n }\n return parsed.filter((item): item is BackofficeSidebarRecentItem => {\n if (item == null || typeof item !== 'object') {\n return false;\n }\n const candidate = item as Partial<BackofficeSidebarRecentItem>;\n return (\n (candidate.kind === 'entity' || candidate.kind === 'tool') &&\n typeof candidate.id === 'string' &&\n typeof candidate.label === 'string' &&\n typeof candidate.href === 'string' &&\n typeof candidate.visitedAt === 'number'\n );\n });\n } catch {\n return [];\n }\n};\n\nconst writeRecentItems = (\n storageKey: string,\n items: readonly BackofficeSidebarRecentItem[],\n): void => {\n if (typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(storageKey, JSON.stringify(items));\n } catch {\n // Ignore storage quota / privacy mode failures.\n }\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 sidebarPreferencesStorageKey =\n sidebar?.preferences?.storageKey ?? DEFAULT_SIDEBAR_PREFS_STORAGE_KEY;\n const persistSidebarCollapsed =\n sidebar?.preferences?.persistCollapsed === true;\n const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(() => {\n if (!persistSidebarCollapsed || typeof window === 'undefined') {\n return false;\n }\n try {\n return (\n window.localStorage.getItem(\n `${sidebarPreferencesStorageKey}:collapsed`,\n ) === 'true'\n );\n } catch {\n return false;\n }\n });\n const [isSigningOut, setIsSigningOut] = useState(false);\n const [topbarTarget, setTopbarTarget] = useState<HTMLDivElement | null>(null);\n const recentItemsConfig = sidebar?.recentItems;\n const recentItemsEnabled = recentItemsConfig?.enabled === true;\n const recentItemsStorageKey =\n recentItemsConfig?.storageKey ?? DEFAULT_RECENT_ITEMS_STORAGE_KEY;\n const recentItemsMaxItems = recentItemsConfig?.maxItems ?? 8;\n const [recentItems, setRecentItems] = useState<\n readonly BackofficeSidebarRecentItem[]\n >(() => {\n if (!recentItemsEnabled) {\n return [];\n }\n return readRecentItems(recentItemsStorageKey);\n });\n\n useEffect(() => {\n if (!persistSidebarCollapsed || typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(\n `${sidebarPreferencesStorageKey}:collapsed`,\n String(isSidebarCollapsed),\n );\n } catch {\n // Ignore storage quota / privacy mode failures.\n }\n }, [\n isSidebarCollapsed,\n persistSidebarCollapsed,\n sidebarPreferencesStorageKey,\n ]);\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 defaultCollapsedByGroupId = useMemo(() => {\n return Object.fromEntries(\n Object.entries(groups).map(([groupId, group]) => {\n return [groupId, group.behavior?.defaultCollapsed ?? true];\n }),\n );\n }, [groups]);\n\n const visibleEntityIds = useMemo(() => {\n return resolveVisibleEntityIds(groups, entities, sidebar, permissions);\n }, [entities, groups, permissions, sidebar]);\n\n const activeEntityId = useMemo(() => {\n return resolveActiveEntityId(pathname, entities);\n }, [entities, pathname]);\n\n useEffect(() => {\n if (!recentItemsEnabled || activeEntityId == null) {\n return;\n }\n const config = entities[activeEntityId];\n if (config == null) {\n return;\n }\n if (config.kind !== 'tool' && !config.hasList) {\n return;\n }\n const href = config.routes.list;\n let kind: BackofficeSidebarRecentItem['kind'] = 'entity';\n if (config.kind === 'tool') {\n kind = 'tool';\n }\n const item: BackofficeSidebarRecentItem = {\n kind,\n id: activeEntityId,\n label: config.label(tApp),\n href,\n visitedAt: Date.now(),\n };\n setRecentItems((prev) => {\n const next = [\n item,\n ...prev.filter((entry) => {\n return entry.id !== item.id || entry.kind !== item.kind;\n }),\n ].slice(0, recentItemsMaxItems);\n writeRecentItems(recentItemsStorageKey, next);\n return next;\n });\n }, [\n activeEntityId,\n entities,\n recentItemsEnabled,\n recentItemsMaxItems,\n recentItemsStorageKey,\n tApp,\n ]);\n\n const {\n pins,\n toggle: togglePin,\n reorder: reorderPin,\n } = useBackofficeSidebarPins({\n enabled: sidebar?.pinnedItems?.enabled === true,\n storageKey: sidebar?.pinnedItems?.storageKey,\n visibleEntityIds,\n });\n\n let groupCollapseStorageKey: string | undefined;\n if (sidebar?.preferences?.storageKey != null) {\n groupCollapseStorageKey = `${sidebar.preferences.storageKey}:groups`;\n }\n\n const { collapsedByGroupId, setCollapsed } = useSidebarGroupCollapse({\n groupIds,\n activeGroupId,\n defaultCollapsedByGroupId,\n persist: sidebar?.preferences?.persistGroups === true,\n storageKey: groupCollapseStorageKey,\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 recentItems,\n onTogglePin: togglePin,\n onReorderPin: reorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange: setCollapsed,\n sidebarCollapsed: false,\n });\n }, [\n basePath,\n collapsedByGroupId,\n entities,\n pathname,\n permissions,\n pins,\n recentItems,\n reorderPin,\n setCollapsed,\n sidebar,\n sidebarQuery,\n t,\n tApp,\n togglePin,\n ]);\n\n const mobileSections = 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 recentItems,\n onTogglePin: togglePin,\n onReorderPin: reorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange: setCollapsed,\n sidebarCollapsed: false,\n });\n }, [\n basePath,\n collapsedByGroupId,\n entities,\n pathname,\n permissions,\n pins,\n recentItems,\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={false}\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 const mobileSidebarFooter = (\n <BackofficeSidebarProfileMenu\n collapsed={false}\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 const sidebarSearchNode = (\n <GlobalSearchInput\n value={sidebarQuery}\n onChange={setSidebarQuery}\n placeholder={t('sidebar.search.placeholder')}\n ariaLabel={t('sidebar.search.placeholder')}\n />\n );\n\n return (\n <ToastProvider>\n <AdminShellLayout\n sidebar={{\n sections,\n header: <EnvironmentBadge environment={environment} />,\n search: sidebarSearchNode,\n footer: sidebarFooter,\n isCollapsed: isSidebarCollapsed,\n onCollapsedChange: setIsSidebarCollapsed,\n collapseToggleLabel: t('sidebar.actions.collapseSidebar'),\n expandToggleLabel: t('sidebar.actions.expandSidebar'),\n navigationAriaLabel: t('sidebar.navigationAriaLabel'),\n }}\n mobileSidebar={{\n sections: mobileSections,\n header: <EnvironmentBadge environment={environment} />,\n search: sidebarSearchNode,\n footer: mobileSidebarFooter,\n isCollapsed: false,\n hideCollapseToggle: true,\n navigationAriaLabel: t('sidebar.navigationAriaLabel'),\n }}\n topbar={{\n breadcrumb: <div ref={setTopbarTarget} />,\n }}\n >\n <BackofficePermissionsProvider permissions={permissions}>\n <BackofficeTopbarPortalContextProvider\n value={{\n target: topbarTarget,\n dashboardHref: basePath,\n dashboardLabel: t('sidebar.items.dashboard'),\n }}\n >\n {contentNode}\n </BackofficeTopbarPortalContextProvider>\n </BackofficePermissionsProvider>\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":";;;;;;;;;;;;;;;;;;;;;;;;;AAyEA,IAAM,KAAmC,mCACnC,KAAoC,8BAEpC,MACJ,MAC2C;CAC3C,IAAI,OAAO,SAAW,KACpB,OAAO,EAAE;CAEX,IAAI;EACF,IAAM,IAAM,OAAO,aAAa,QAAQ,EAAW;EACnD,IAAI,KAAO,MACT,OAAO,EAAE;EAEX,IAAM,IAAS,KAAK,MAAM,EAAI;EAI9B,OAHK,MAAM,QAAQ,EAAO,GAGnB,EAAO,QAAQ,MAA8C;GAClE,IAAoB,OAAO,KAAS,aAAhC,GACF,OAAO;GAET,IAAM,IAAY;GAClB,QACG,EAAU,SAAS,YAAY,EAAU,SAAS,WACnD,OAAO,EAAU,MAAO,YACxB,OAAO,EAAU,SAAU,YAC3B,OAAO,EAAU,QAAS,YAC1B,OAAO,EAAU,aAAc;IAEjC,GAdO,EAAE;SAeL;EACN,OAAO,EAAE;;GAIP,KACJ,GACA,MACS;CACL,aAAO,SAAW,MAGtB,IAAI;EACF,OAAO,aAAa,QAAQ,GAAY,KAAK,UAAU,EAAM,CAAC;SACxD;GAKJ,KAAyB,EAC7B,aACA,gBACA,eACA,uBACmC;CACnC,IAAM,EAAE,GAAG,MAAS,IAAgB,EAC9B,EAAE,SAAM,GAA+B,EACvC,EAAE,gBAAa,IAAa,EAC5B,IAAU,GAAW,GAAe,EACpC,IAAmB,GAAqB,EACxC,EACJ,MAAM,GACN,aACA,aACA,eACE,GAAqB,EACnB,CAAC,GAAc,MAAmB,EAAS,GAAG,EAC9C,IACJ,GAAS,aAAa,cAAc,IAChC,IACJ,GAAS,aAAa,qBAAqB,IACvC,CAAC,GAAoB,MAAyB,QAAe;EACjE,IAAI,CAAC,KAA2B,OAAO,SAAW,KAChD,OAAO;EAET,IAAI;GACF,OACE,OAAO,aAAa,QAClB,GAAG,EAA6B,YACjC,KAAK;UAEF;GACN,OAAO;;GAET,EACI,CAAC,GAAc,KAAmB,EAAS,GAAM,EACjD,CAAC,GAAc,MAAmB,EAAgC,KAAK,EACvE,IAAoB,GAAS,aAC7B,IAAqB,GAAmB,YAAY,IACpD,IACJ,GAAmB,cAAc,IAC7B,IAAsB,GAAmB,YAAY,GACrD,CAAC,GAAa,MAAkB,QAG/B,IAGE,GAAgB,EAAsB,GAFpC,EAAE,CAGX;CAEF,QAAgB;EACV,OAAC,KAA2B,OAAO,SAAW,MAGlD,IAAI;GACF,OAAO,aAAa,QAClB,GAAG,EAA6B,aAChC,OAAO,EAAmB,CAC3B;UACK;IAGP;EACD;EACA;EACA;EACD,CAAC;CAEF,IAAM,IAAS,QACN,EAAqB,GAAU,EAAQ,EAC7C,CAAC,GAAU,EAAQ,CAAC,EAEjB,KAAW,QACR,OAAO,KAAK,EAAO,EACzB,CAAC,EAAO,CAAC,EAEN,KAA4B,QACzB,OAAO,YACZ,OAAO,QAAQ,EAAO,CAAC,KAAK,CAAC,GAAS,OAC7B,CAAC,GAAS,EAAM,UAAU,oBAAoB,GAAK,CAC1D,CACH,EACA,CAAC,EAAO,CAAC,EAEN,KAAmB,QAChB,GAAwB,GAAQ,GAAU,GAAS,EAAY,EACrE;EAAC;EAAU;EAAQ;EAAa;EAAQ,CAAC,EAEtC,IAAiB,QACd,EAAsB,GAAU,EAAS,EAC/C,CAAC,GAAU,EAAS,CAAC;CAExB,QAAgB;EACd,IAAI,CAAC,KAAsB,KAAkB,MAC3C;EAEF,IAAM,IAAS,EAAS;EAIxB,IAHI,KAAU,QAGV,EAAO,SAAS,UAAU,CAAC,EAAO,SACpC;EAEF,IAAM,IAAO,EAAO,OAAO,MACvB,IAA4C;EAChD,AAAI,EAAO,SAAS,WAClB,IAAO;EAET,IAAM,IAAoC;GACxC;GACA,IAAI;GACJ,OAAO,EAAO,MAAM,EAAK;GACzB;GACA,WAAW,KAAK,KAAK;GACtB;EACD,IAAgB,MAAS;GACvB,IAAM,IAAO,CACX,GACA,GAAG,EAAK,QAAQ,MACP,EAAM,OAAO,EAAK,MAAM,EAAM,SAAS,EAAK,KACnD,CACH,CAAC,MAAM,GAAG,EAAoB;GAE/B,OADA,EAAiB,GAAuB,EAAK,EACtC;IACP;IACD;EACD;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CAEF,IAAM,EACJ,SACA,QAAQ,GACR,SAAS,MACP,GAAyB;EAC3B,SAAS,GAAS,aAAa,YAAY;EAC3C,YAAY,GAAS,aAAa;EAClC;EACD,CAAC,EAEE;CACJ,AAAI,GAAS,aAAa,cAAc,SACtC,IAA0B,GAAG,EAAQ,YAAY,WAAW;CAG9D,IAAM,EAAE,uBAAoB,oBAAiB,GAAwB;EACnE;EACA;EACA;EACA,SAAS,GAAS,aAAa,kBAAkB;EACjD,YAAY;EACb,CAAC,EAEI,KAAW,QACR,EAAqB;EAC1B;EACA;EACA;EACA;EACA;EACA,aAAa;EACb;EACA;EACA,iBAAiB;EACjB;EACA,aAAa;EACb,cAAc;EACd;EACA,wBAAwB;EACxB,kBAAkB;EACnB,CAAC,EACD;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EAEI,KAAiB,QACd,EAAqB;EAC1B;EACA;EACA;EACA;EACA;EACA,aAAa;EACb;EACA;EACA,iBAAiB;EACjB;EACA,aAAa;EACb,cAAc;EACd;EACA,wBAAwB;EACxB,kBAAkB;EACnB,CAAC,EACD;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EAEI,IAAc,QAEd,OADgB,KACX,KAAK,QAAQ,KACb,QAEF,QACN,EAAE,CAAC,EAEA,IAAgB,SAAkB;EAClC,MASJ,EAAgB,GAAK,GA0BrB,YAxB8C;GAC5C,IAAI;IACF,IAAM,IAAS,MAAM,EAAW,OAAO,MAAM;IAgB7C,AAfA,MAAM,IAAI,SAAe,GAAS,MAAW;KAC3C,GAA+B,GAAkB;MAC/C,UAAU,EAAO;MACjB,WAAW,EAAE;MACb,mBAAmB;OACjB,GAAS;;MAEX,UAAU,MAAU;OAClB,EAAO,EAAM;;MAEhB,CAAC;MACF,EACF,aAAa,WAAW,aAAa,EACrC,aAAa,WAAW,cAAc,EACtC,IAAiB,EACjB,GAAS,QAAQ,KAAK,EAAE,UAAU,GAAuB,EAAS,EAAE,CAAC;aAC7D;IACR,EAAgB,GAAM;;MAId,CAAC,YAAY,GAEvB;IACD;EAAC,EAAW;EAAQ;EAAU;EAAc;EAAkB;EAAQ,CAAC,EAEpE,IAAS,GAAY,MAAM,MAC3B,IAAiB,QACd,GAA8B;EACnC;EACA,kBAAkB,EAAE,8BAA8B;EACnD,CAAC,EACD,CAAC,GAAG,EAAO,CAAC,EAET,KACJ,kBAAC,GAAD;EACE,WAAW;EACX,QAAQ;EACR,QAAQ;GACN,cAAc,EAAE,wBAAwB;GACxC,eAAe,EAAE,gCAAgC;GACjD,SAAS,EAAE,kCAAkC;GAC9C;EACD,WAAW;EACG;EACd,CAAA,EAGE,KACJ,kBAAC,GAAD;EACE,WAAW;EACX,QAAQ;EACR,QAAQ;GACN,cAAc,EAAE,wBAAwB;GACxC,eAAe,EAAE,gCAAgC;GACjD,SAAS,EAAE,kCAAkC;GAC9C;EACD,WAAW;EACG;EACd,CAAA,EAGA,IAAkC;CACtC,AAAI,KAAgB,SAClB,IACE,kBAAC,IAAD,EAA4B,aAAqC,CAAA;CAIrE,IAAM,IACJ,kBAAC,IAAD;EACE,OAAO;EACP,UAAU;EACV,aAAa,EAAE,6BAA6B;EAC5C,WAAW,EAAE,6BAA6B;EAC1C,CAAA;CAGJ,OACE,kBAAC,GAAD,EAAA,UACE,kBAAC,IAAD;EACE,SAAS;GACP;GACA,QAAQ,kBAAC,GAAD,EAA+B,gBAAe,CAAA;GACtD,QAAQ;GACR,QAAQ;GACR,aAAa;GACb,mBAAmB;GACnB,qBAAqB,EAAE,kCAAkC;GACzD,mBAAmB,EAAE,gCAAgC;GACrD,qBAAqB,EAAE,8BAA8B;GACtD;EACD,eAAe;GACb,UAAU;GACV,QAAQ,kBAAC,GAAD,EAA+B,gBAAe,CAAA;GACtD,QAAQ;GACR,QAAQ;GACR,aAAa;GACb,oBAAoB;GACpB,qBAAqB,EAAE,8BAA8B;GACtD;EACD,QAAQ,EACN,YAAY,kBAAC,OAAD,EAAK,KAAK,IAAmB,CAAA,EAC1C;YAED,kBAAC,IAAD;GAA4C;aAC1C,kBAAC,GAAD;IACE,OAAO;KACL,QAAQ;KACR,eAAe;KACf,gBAAgB,EAAE,0BAA0B;KAC7C;cAEA;IACqC,CAAA;GACV,CAAA;EACf,CAAA,EACL,CAAA;GAed,KAAyB,EAC7B,aACA,qBACA,aACA,eACA,uBAKE,kBAAC,GAAD;CACe,aAJG,EAAkB,GAAkB,EAIvC;CACD;CACG;CAEd;CACqB,CAAA,EAIf,KAAwB,EACnC,aACA,qBACA,aACA,eACA,uBAEI,KAAoB,QAAQ,KAAY,OAExC,kBAAC,GAAD;CACoB;CACR;CACE;CACG;CAEd;CACqB,CAAA,GAK1B,kBAAC,GAAD;CACE,aAAa;CACD;CACG;CAEd;CACqB,CAAA"}
1
+ {"version":3,"file":"BackofficeLayoutPage.js","names":[],"sources":["../../../src/pages/BackofficeLayoutPage.tsx"],"sourcesContent":["import {\n useEffect,\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 from '@plumile/router/routing/RoutingContext.js';\nimport useLocation from '@plumile/router/routing/useLocation.js';\n\nimport { AdminShellLayout } from '@plumile/ui/admin/templates/admin_shell_layout/AdminShellLayout.js';\nimport { ToastProvider } from '@plumile/ui/atomic/molecules/toast/ToastProvider.js';\nimport { EnvironmentBadge } from '@plumile/ui/backoffice/atoms/environment_badge/EnvironmentBadge.js';\nimport { GlobalSearchInput } from '@plumile/ui/backoffice/molecules/global_search_input/GlobalSearchInput.js';\nimport { BackofficeSidebarProfileMenu } from '@plumile/ui/backoffice/molecules/sidebar_profile_menu/BackofficeSidebarProfileMenu.js';\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 resolveActiveEntityId,\n resolveSidebarGroups,\n resolveVisibleEntityIds,\n} from '../components/backoffice/layout/sidebarUtils.js';\nimport { BackofficeTopbarPortalContextProvider } from '../components/backoffice/layout/breadcrumb/BackofficeTopbarPortalContext.js';\nimport { BackofficePermissionsProvider } from '../components/backoffice/layout/BackofficePermissionsContext.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';\nimport type { BackofficeSidebarRecentItem } from '../provider/types.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 DEFAULT_RECENT_ITEMS_STORAGE_KEY = 'plumile:backoffice:recent-items';\nconst DEFAULT_SIDEBAR_PREFS_STORAGE_KEY = 'plumile:backoffice:sidebar';\n\nconst readRecentItems = (\n storageKey: string,\n): readonly BackofficeSidebarRecentItem[] => {\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 unknown;\n if (!Array.isArray(parsed)) {\n return [];\n }\n return parsed.filter((item): item is BackofficeSidebarRecentItem => {\n if (item == null || typeof item !== 'object') {\n return false;\n }\n const candidate = item as Partial<BackofficeSidebarRecentItem>;\n return (\n (candidate.kind === 'entity' || candidate.kind === 'tool') &&\n typeof candidate.id === 'string' &&\n typeof candidate.label === 'string' &&\n typeof candidate.href === 'string' &&\n typeof candidate.visitedAt === 'number'\n );\n });\n } catch {\n return [];\n }\n};\n\nconst writeRecentItems = (\n storageKey: string,\n items: readonly BackofficeSidebarRecentItem[],\n): void => {\n if (typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(storageKey, JSON.stringify(items));\n } catch {\n // Ignore storage quota / privacy mode failures.\n }\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 dashboards,\n entities,\n sidebar,\n } = useBackofficeConfig();\n const [sidebarQuery, setSidebarQuery] = useState('');\n const sidebarPreferencesStorageKey =\n sidebar?.preferences?.storageKey ?? DEFAULT_SIDEBAR_PREFS_STORAGE_KEY;\n const persistSidebarCollapsed =\n sidebar?.preferences?.persistCollapsed === true;\n const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(() => {\n if (!persistSidebarCollapsed || typeof window === 'undefined') {\n return false;\n }\n try {\n return (\n window.localStorage.getItem(\n `${sidebarPreferencesStorageKey}:collapsed`,\n ) === 'true'\n );\n } catch {\n return false;\n }\n });\n const [isSigningOut, setIsSigningOut] = useState(false);\n const [topbarTarget, setTopbarTarget] = useState<HTMLDivElement | null>(null);\n const recentItemsConfig = sidebar?.recentItems;\n const recentItemsEnabled = recentItemsConfig?.enabled === true;\n const recentItemsStorageKey =\n recentItemsConfig?.storageKey ?? DEFAULT_RECENT_ITEMS_STORAGE_KEY;\n const recentItemsMaxItems = recentItemsConfig?.maxItems ?? 8;\n const [recentItems, setRecentItems] = useState<\n readonly BackofficeSidebarRecentItem[]\n >(() => {\n if (!recentItemsEnabled) {\n return [];\n }\n return readRecentItems(recentItemsStorageKey);\n });\n\n useEffect(() => {\n if (!persistSidebarCollapsed || typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(\n `${sidebarPreferencesStorageKey}:collapsed`,\n String(isSidebarCollapsed),\n );\n } catch {\n // Ignore storage quota / privacy mode failures.\n }\n }, [\n isSidebarCollapsed,\n persistSidebarCollapsed,\n sidebarPreferencesStorageKey,\n ]);\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 defaultCollapsedByGroupId = useMemo(() => {\n return Object.fromEntries(\n Object.entries(groups).map(([groupId, group]) => {\n return [groupId, group.behavior?.defaultCollapsed ?? true];\n }),\n );\n }, [groups]);\n\n const visibleEntityIds = useMemo(() => {\n return resolveVisibleEntityIds(groups, entities, sidebar, permissions);\n }, [entities, groups, permissions, sidebar]);\n\n const activeEntityId = useMemo(() => {\n return resolveActiveEntityId(pathname, entities);\n }, [entities, pathname]);\n\n useEffect(() => {\n if (!recentItemsEnabled || activeEntityId == null) {\n return;\n }\n const config = entities[activeEntityId];\n if (config == null) {\n return;\n }\n if (config.kind !== 'tool' && !config.hasList) {\n return;\n }\n const href = config.routes.list;\n let kind: BackofficeSidebarRecentItem['kind'] = 'entity';\n if (config.kind === 'tool') {\n kind = 'tool';\n }\n const item: BackofficeSidebarRecentItem = {\n kind,\n id: activeEntityId,\n label: config.label(tApp),\n href,\n visitedAt: Date.now(),\n };\n setRecentItems((prev) => {\n const next = [\n item,\n ...prev.filter((entry) => {\n return entry.id !== item.id || entry.kind !== item.kind;\n }),\n ].slice(0, recentItemsMaxItems);\n writeRecentItems(recentItemsStorageKey, next);\n return next;\n });\n }, [\n activeEntityId,\n entities,\n recentItemsEnabled,\n recentItemsMaxItems,\n recentItemsStorageKey,\n tApp,\n ]);\n\n const {\n pins,\n toggle: togglePin,\n reorder: reorderPin,\n } = useBackofficeSidebarPins({\n enabled: sidebar?.pinnedItems?.enabled === true,\n storageKey: sidebar?.pinnedItems?.storageKey,\n visibleEntityIds,\n });\n\n let groupCollapseStorageKey: string | undefined;\n if (sidebar?.preferences?.storageKey != null) {\n groupCollapseStorageKey = `${sidebar.preferences.storageKey}:groups`;\n }\n\n const { collapsedByGroupId, setCollapsed } = useSidebarGroupCollapse({\n groupIds,\n activeGroupId,\n defaultCollapsedByGroupId,\n persist: sidebar?.preferences?.persistGroups === true,\n storageKey: groupCollapseStorageKey,\n });\n\n const sections = useMemo(() => {\n return buildSidebarSections({\n basePath,\n pathname,\n entities,\n dashboards,\n sidebar,\n permissions,\n searchQuery: sidebarQuery,\n tApp,\n t,\n pinnedEntityIds: pins,\n recentItems,\n onTogglePin: togglePin,\n onReorderPin: reorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange: setCollapsed,\n sidebarCollapsed: false,\n });\n }, [\n basePath,\n collapsedByGroupId,\n entities,\n dashboards,\n pathname,\n permissions,\n pins,\n recentItems,\n reorderPin,\n setCollapsed,\n sidebar,\n sidebarQuery,\n t,\n tApp,\n togglePin,\n ]);\n\n const mobileSections = useMemo(() => {\n return buildSidebarSections({\n basePath,\n pathname,\n entities,\n dashboards,\n sidebar,\n permissions,\n searchQuery: sidebarQuery,\n tApp,\n t,\n pinnedEntityIds: pins,\n recentItems,\n onTogglePin: togglePin,\n onReorderPin: reorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange: setCollapsed,\n sidebarCollapsed: false,\n });\n }, [\n basePath,\n collapsedByGroupId,\n entities,\n dashboards,\n pathname,\n permissions,\n pins,\n recentItems,\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={false}\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 const mobileSidebarFooter = (\n <BackofficeSidebarProfileMenu\n collapsed={false}\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 const sidebarSearchNode = (\n <GlobalSearchInput\n value={sidebarQuery}\n onChange={setSidebarQuery}\n placeholder={t('sidebar.search.placeholder')}\n ariaLabel={t('sidebar.search.placeholder')}\n />\n );\n\n return (\n <ToastProvider>\n <AdminShellLayout\n sidebar={{\n sections,\n header: <EnvironmentBadge environment={environment} />,\n search: sidebarSearchNode,\n footer: sidebarFooter,\n isCollapsed: isSidebarCollapsed,\n onCollapsedChange: setIsSidebarCollapsed,\n collapseToggleLabel: t('sidebar.actions.collapseSidebar'),\n expandToggleLabel: t('sidebar.actions.expandSidebar'),\n navigationAriaLabel: t('sidebar.navigationAriaLabel'),\n }}\n mobileSidebar={{\n sections: mobileSections,\n header: <EnvironmentBadge environment={environment} />,\n search: sidebarSearchNode,\n footer: mobileSidebarFooter,\n isCollapsed: false,\n hideCollapseToggle: true,\n navigationAriaLabel: t('sidebar.navigationAriaLabel'),\n }}\n topbar={{\n breadcrumb: <div ref={setTopbarTarget} />,\n }}\n contentScrollMode=\"contained\"\n >\n <BackofficePermissionsProvider permissions={permissions}>\n <BackofficeTopbarPortalContextProvider\n value={{\n target: topbarTarget,\n dashboardHref: basePath,\n dashboardLabel: t('sidebar.items.dashboard'),\n }}\n >\n {contentNode}\n </BackofficeTopbarPortalContextProvider>\n </BackofficePermissionsProvider>\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 +1 @@
1
- {"version":3,"file":"BackofficeConfigContext.js","names":[],"sources":["../../../src/provider/BackofficeConfigContext.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\n\nimport type { BackofficeEntityManifestMap } from '@plumile/backoffice-core/types.js';\n\nimport type {\n BackofficeAuthConfig,\n BackofficeDashboardModule,\n BackofficeGraphQLConfig,\n BackofficeSidebarConfig,\n} from './types.js';\nimport type { BackofficeEntityRegistry } from './entityRegistry.js';\n\nexport type BackofficeConfigContextValue = {\n basePath: string;\n entities: BackofficeEntityManifestMap;\n entityManifest: BackofficeEntityManifestMap;\n entityRegistry: BackofficeEntityRegistry;\n filterColumnAliases?: Record<string, string>;\n sidebar?: BackofficeSidebarConfig;\n dashboard?: BackofficeDashboardModule;\n auth: BackofficeAuthConfig;\n graphql: BackofficeGraphQLConfig;\n};\n\nconst BackofficeConfigContext =\n createContext<BackofficeConfigContextValue | null>(null);\n\nexport const BackofficeConfigProvider = BackofficeConfigContext.Provider;\n\n/**\n * Hook to access the Backoffice configuration context\n */\nexport function useBackofficeConfig(): BackofficeConfigContextValue {\n const context = useContext(BackofficeConfigContext);\n if (context == null) {\n throw new Error('BackofficeProvider is missing in the component tree.');\n }\n return context;\n}\n\nexport default BackofficeConfigContext;\n"],"mappings":";;AAwBA,IAAM,IACJ,EAAmD,KAAK,EAE7C,IAA2B,EAAwB;AAKhE,SAAgB,IAAoD;CAClE,IAAM,IAAU,EAAW,EAAwB;CACnD,IAAI,KAAW,MACb,MAAU,MAAM,uDAAuD;CAEzE,OAAO"}
1
+ {"version":3,"file":"BackofficeConfigContext.js","names":[],"sources":["../../../src/provider/BackofficeConfigContext.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\n\nimport type { BackofficeEntityManifestMap } from '@plumile/backoffice-core/types.js';\n\nimport type {\n BackofficeAuthConfig,\n BackofficeDashboardModule,\n BackofficeDashboardRegistration,\n BackofficeGraphQLConfig,\n BackofficeSidebarConfig,\n} from './types.js';\nimport type { BackofficeEntityRegistry } from './entityRegistry.js';\n\nexport type BackofficeConfigContextValue = {\n basePath: string;\n entities: BackofficeEntityManifestMap;\n entityManifest: BackofficeEntityManifestMap;\n entityRegistry: BackofficeEntityRegistry;\n filterColumnAliases?: Record<string, string>;\n sidebar?: BackofficeSidebarConfig;\n dashboard?: BackofficeDashboardModule;\n dashboards: readonly BackofficeDashboardRegistration[];\n auth: BackofficeAuthConfig;\n graphql: BackofficeGraphQLConfig;\n};\n\nconst BackofficeConfigContext =\n createContext<BackofficeConfigContextValue | null>(null);\n\nexport const BackofficeConfigProvider = BackofficeConfigContext.Provider;\n\n/**\n * Hook to access the Backoffice configuration context\n */\nexport function useBackofficeConfig(): BackofficeConfigContextValue {\n const context = useContext(BackofficeConfigContext);\n if (context == null) {\n throw new Error('BackofficeProvider is missing in the component tree.');\n }\n return context;\n}\n\nexport default BackofficeConfigContext;\n"],"mappings":";;AA0BA,IAAM,IACJ,EAAmD,KAAK,EAE7C,IAA2B,EAAwB;AAKhE,SAAgB,IAAoD;CAClE,IAAM,IAAU,EAAW,EAAwB;CACnD,IAAI,KAAW,MACb,MAAU,MAAM,uDAAuD;CAEzE,OAAO"}