@plumile/backoffice-react 0.1.198 → 0.1.200
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/README.md +5 -0
- package/lib/esm/auth/backofficeAuthHeaders.js +18 -0
- package/lib/esm/auth/backofficeAuthHeaders.js.map +1 -0
- package/lib/esm/index.js +76 -75
- package/lib/esm/pages/BackofficeAcceptInvitationPage.js +7 -7
- package/lib/esm/pages/BackofficeEntityDetailPage.view-helpers.js +6 -4
- package/lib/esm/pages/BackofficeEntityDetailPage.view-helpers.js.map +1 -1
- package/lib/esm/pages/BackofficeLayoutPage.js +41 -41
- package/lib/esm/pages/BackofficeLayoutPage.js.map +1 -1
- package/lib/esm/pages/BackofficeLoginPage.js +11 -11
- package/lib/esm/pages/BackofficePasswordResetCompletePage.js +14 -14
- package/lib/esm/pages/BackofficeVerifyEmailPage.js +14 -14
- package/lib/esm/provider/BackofficeProvider.js +78 -77
- package/lib/esm/provider/BackofficeProvider.js.map +1 -1
- package/lib/esm/provider/useBackofficeAuthRouteGate.js +39 -0
- package/lib/esm/provider/useBackofficeAuthRouteGate.js.map +1 -0
- package/lib/esm/router/backofficeAuthPaths.js +11 -2
- package/lib/esm/router/backofficeAuthPaths.js.map +1 -1
- package/lib/esm/router/createBackofficeRoutes.js +4 -4
- package/lib/esm/router/createBackofficeRoutes.js.map +1 -1
- package/lib/types/auth/backofficeAuthHeaders.d.ts +5 -0
- package/lib/types/auth/backofficeAuthHeaders.d.ts.map +1 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/provider/BackofficeProvider.d.ts.map +1 -1
- package/lib/types/provider/useBackofficeAuthRouteGate.d.ts +2 -0
- package/lib/types/provider/useBackofficeAuthRouteGate.d.ts.map +1 -0
- package/lib/types/router/backofficeAuthPaths.d.ts +1 -0
- package/lib/types/router/backofficeAuthPaths.d.ts.map +1 -1
- package/package.json +16 -16
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { getBackofficeLoginPath as e } from "../router/backofficeAuthPaths.js";
|
|
2
|
+
import { useBackofficeReactTranslation as t } from "../i18n/useBackofficeReactTranslation.js";
|
|
3
|
+
import { useBackofficeConfig as n } from "../provider/BackofficeConfigContext.js";
|
|
4
|
+
import { BackofficeTopbarPortalContextProvider as r } from "../components/backoffice/layout/breadcrumb/BackofficeTopbarPortalContext.js";
|
|
5
|
+
import { resolveActiveEntityId as i, resolveSidebarGroups as a, resolveVisibleEntityIds as ee } from "../components/backoffice/layout/sidebarUtils.js";
|
|
6
|
+
import { BackofficePermissionsProvider as o } from "../components/backoffice/layout/BackofficePermissionsContext.js";
|
|
7
|
+
import { buildSidebarSections as s } from "../components/backoffice/layout/buildSidebarSections.js";
|
|
7
8
|
import te from "../components/backoffice/layout/mapViewerToSidebarProfileView.js";
|
|
8
9
|
import { BackofficeContentBoundary as ne } from "../components/backoffice/routing/BackofficeContentBoundary.js";
|
|
9
10
|
import { resetRelayStore as re } from "../relay/environment.js";
|
|
10
11
|
import { useRelayEnvironment as ie } from "../relay/useRelayEnvironment.js";
|
|
11
12
|
import ae from "../hooks/useBackofficeSidebarPins.js";
|
|
12
13
|
import oe from "../hooks/useSidebarGroupCollapse.js";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { ToastProvider as f } from "@plumile/ui/atomic/molecules/toast/ToastProvider.js";
|
|
14
|
+
import { useCallback as se, useContext as ce, useEffect as c, useMemo as l, useState as u } from "react";
|
|
15
|
+
import { jsx as d } from "react/jsx-runtime";
|
|
16
|
+
import { useTranslation as le } from "react-i18next";
|
|
17
|
+
import { commitMutation as ue, usePreloadedQuery as f } from "react-relay";
|
|
18
|
+
import { ToastProvider as de } from "@plumile/ui/atomic/molecules/toast/ToastProvider.js";
|
|
19
19
|
import fe from "@plumile/router/routing/RoutingContext.js";
|
|
20
20
|
import { GlobalSearchInput as pe } from "@plumile/ui/backoffice/molecules/global_search_input/GlobalSearchInput.js";
|
|
21
21
|
import me from "@plumile/router/routing/useLocation.js";
|
|
@@ -40,16 +40,16 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
|
|
|
40
40
|
if (!(typeof window > "u")) try {
|
|
41
41
|
window.localStorage.setItem(e, JSON.stringify(t));
|
|
42
42
|
} catch {}
|
|
43
|
-
}, m = ({ children:
|
|
44
|
-
let { t: _ } =
|
|
43
|
+
}, m = ({ children: f, permissions: m, authStatus: h, activeGroupId: g }) => {
|
|
44
|
+
let { t: _ } = le(), { t: v } = t(), { pathname: y } = me(), b = ce(fe), x = ie(), { auth: S, basePath: C, dashboards: w, entities: T, sidebar: E } = n(), [D, be] = u(""), O = E?.preferences?.storageKey ?? _e, k = E?.preferences?.persistCollapsed === !0, [A, xe] = u(() => {
|
|
45
45
|
if (!k || typeof window > "u") return !1;
|
|
46
46
|
try {
|
|
47
47
|
return window.localStorage.getItem(`${O}:collapsed`) === "true";
|
|
48
48
|
} catch {
|
|
49
49
|
return !1;
|
|
50
50
|
}
|
|
51
|
-
}), [j, M] =
|
|
52
|
-
|
|
51
|
+
}), [j, M] = u(!1), [N, P] = u(null), F = E?.recentItems, I = F?.enabled === !0, L = F?.storageKey ?? ge, R = F?.maxItems ?? 8, [z, Se] = u(() => I ? ve(L) : []);
|
|
52
|
+
c(() => {
|
|
53
53
|
if (!(!k || typeof window > "u")) try {
|
|
54
54
|
window.localStorage.setItem(`${O}:collapsed`, String(A));
|
|
55
55
|
} catch {}
|
|
@@ -58,13 +58,13 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
|
|
|
58
58
|
k,
|
|
59
59
|
O
|
|
60
60
|
]);
|
|
61
|
-
let B =
|
|
61
|
+
let B = l(() => a(T, E), [T, E]), Ce = l(() => Object.keys(B), [B]), we = l(() => Object.fromEntries(Object.entries(B).map(([e, t]) => [e, t.behavior?.defaultCollapsed ?? !0])), [B]), Te = l(() => ee(B, T, E, m), [
|
|
62
62
|
T,
|
|
63
63
|
B,
|
|
64
64
|
m,
|
|
65
65
|
E
|
|
66
|
-
]), V =
|
|
67
|
-
|
|
66
|
+
]), V = l(() => i(y, T), [T, y]);
|
|
67
|
+
c(() => {
|
|
68
68
|
if (!I || V == null) return;
|
|
69
69
|
let e = T[V];
|
|
70
70
|
if (e == null || e.kind !== "tool" && !e.hasList) return;
|
|
@@ -103,7 +103,7 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
|
|
|
103
103
|
defaultCollapsedByGroupId: we,
|
|
104
104
|
persist: E?.preferences?.persistGroups === !0,
|
|
105
105
|
storageKey: K
|
|
106
|
-
}), ke =
|
|
106
|
+
}), ke = l(() => s({
|
|
107
107
|
basePath: C,
|
|
108
108
|
pathname: y,
|
|
109
109
|
entities: T,
|
|
@@ -136,7 +136,7 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
|
|
|
136
136
|
W,
|
|
137
137
|
v,
|
|
138
138
|
_
|
|
139
|
-
]), Ae =
|
|
139
|
+
]), Ae = l(() => s({
|
|
140
140
|
basePath: C,
|
|
141
141
|
pathname: y,
|
|
142
142
|
entities: T,
|
|
@@ -169,22 +169,22 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
|
|
|
169
169
|
W,
|
|
170
170
|
v,
|
|
171
171
|
_
|
|
172
|
-
]), Y =
|
|
172
|
+
]), Y = se(() => {
|
|
173
173
|
j || (M(!0), (async () => {
|
|
174
174
|
try {
|
|
175
|
-
let
|
|
176
|
-
await new Promise((
|
|
177
|
-
|
|
178
|
-
mutation:
|
|
175
|
+
let t = await S.logout.load();
|
|
176
|
+
await new Promise((e, n) => {
|
|
177
|
+
ue(x, {
|
|
178
|
+
mutation: t.logoutMutation,
|
|
179
179
|
variables: {},
|
|
180
180
|
onCompleted: () => {
|
|
181
|
-
|
|
181
|
+
e();
|
|
182
182
|
},
|
|
183
183
|
onError: (e) => {
|
|
184
184
|
n(e);
|
|
185
185
|
}
|
|
186
186
|
});
|
|
187
|
-
}), localStorage.removeItem("auth_token"), localStorage.removeItem("remember_me"), re(), b?.history.push({ pathname:
|
|
187
|
+
}), localStorage.removeItem("auth_token"), localStorage.removeItem("remember_me"), re(), b?.history.push({ pathname: e(C) });
|
|
188
188
|
} finally {
|
|
189
189
|
M(!1);
|
|
190
190
|
}
|
|
@@ -195,10 +195,10 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
|
|
|
195
195
|
j,
|
|
196
196
|
x,
|
|
197
197
|
b
|
|
198
|
-
]), X = h?.me ?? null, Z =
|
|
198
|
+
]), X = h?.me ?? null, Z = l(() => te({
|
|
199
199
|
viewer: X,
|
|
200
200
|
unknownUserLabel: v("sidebar.profile.unknownUser")
|
|
201
|
-
}), [v, X]), je = /* @__PURE__ */
|
|
201
|
+
}), [v, X]), je = /* @__PURE__ */ d(p, {
|
|
202
202
|
collapsed: !1,
|
|
203
203
|
viewer: Z,
|
|
204
204
|
labels: {
|
|
@@ -208,7 +208,7 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
|
|
|
208
208
|
},
|
|
209
209
|
onSignOut: Y,
|
|
210
210
|
isSigningOut: j
|
|
211
|
-
}), Me = /* @__PURE__ */
|
|
211
|
+
}), Me = /* @__PURE__ */ d(p, {
|
|
212
212
|
collapsed: !1,
|
|
213
213
|
viewer: Z,
|
|
214
214
|
labels: {
|
|
@@ -219,14 +219,14 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
|
|
|
219
219
|
onSignOut: Y,
|
|
220
220
|
isSigningOut: j
|
|
221
221
|
}), Q = null;
|
|
222
|
-
N != null && (Q = /* @__PURE__ */
|
|
223
|
-
let $ = /* @__PURE__ */
|
|
222
|
+
N != null && (Q = /* @__PURE__ */ d(ne, { children: f }));
|
|
223
|
+
let $ = /* @__PURE__ */ d(pe, {
|
|
224
224
|
value: D,
|
|
225
225
|
onChange: be,
|
|
226
226
|
placeholder: v("sidebar.search.placeholder"),
|
|
227
227
|
ariaLabel: v("sidebar.search.placeholder")
|
|
228
228
|
});
|
|
229
|
-
return /* @__PURE__ */
|
|
229
|
+
return /* @__PURE__ */ d(de, { children: /* @__PURE__ */ d(he, {
|
|
230
230
|
sidebar: {
|
|
231
231
|
sections: ke,
|
|
232
232
|
search: $,
|
|
@@ -245,11 +245,11 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
|
|
|
245
245
|
hideCollapseToggle: !0,
|
|
246
246
|
navigationAriaLabel: v("sidebar.navigationAriaLabel")
|
|
247
247
|
},
|
|
248
|
-
topbar: { breadcrumb: /* @__PURE__ */
|
|
248
|
+
topbar: { breadcrumb: /* @__PURE__ */ d("div", { ref: P }) },
|
|
249
249
|
contentScrollMode: "contained",
|
|
250
|
-
children: /* @__PURE__ */
|
|
250
|
+
children: /* @__PURE__ */ d(o, {
|
|
251
251
|
permissions: m,
|
|
252
|
-
children: /* @__PURE__ */
|
|
252
|
+
children: /* @__PURE__ */ d(r, {
|
|
253
253
|
value: {
|
|
254
254
|
target: N,
|
|
255
255
|
dashboardHref: C,
|
|
@@ -260,20 +260,20 @@ var ge = "plumile:backoffice:recent-items", _e = "plumile:backoffice:sidebar", v
|
|
|
260
260
|
})
|
|
261
261
|
}) });
|
|
262
262
|
}, h = ({ children: e, permissionsQuery: t, prepared: n, authStatus: r, activeGroupId: i }) => {
|
|
263
|
-
let a =
|
|
264
|
-
return /* @__PURE__ */
|
|
263
|
+
let a = f(t, n);
|
|
264
|
+
return /* @__PURE__ */ d(m, {
|
|
265
265
|
permissions: a,
|
|
266
266
|
authStatus: r,
|
|
267
267
|
activeGroupId: i,
|
|
268
268
|
children: e
|
|
269
269
|
});
|
|
270
|
-
}, g = ({ children: e, permissionsQuery: t, prepared: n, authStatus: r, activeGroupId: i }) => t != null && n != null ? /* @__PURE__ */
|
|
270
|
+
}, g = ({ children: e, permissionsQuery: t, prepared: n, authStatus: r, activeGroupId: i }) => t != null && n != null ? /* @__PURE__ */ d(h, {
|
|
271
271
|
permissionsQuery: t,
|
|
272
272
|
prepared: n,
|
|
273
273
|
authStatus: r,
|
|
274
274
|
activeGroupId: i,
|
|
275
275
|
children: e
|
|
276
|
-
}) : /* @__PURE__ */
|
|
276
|
+
}) : /* @__PURE__ */ d(m, {
|
|
277
277
|
permissions: null,
|
|
278
278
|
authStatus: r,
|
|
279
279
|
activeGroupId: i,
|
|
@@ -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 { GlobalSearchInput } from '@plumile/ui/backoffice/molecules/global_search_input/GlobalSearchInput.js';\nimport { SidebarProfileMenu } from '@plumile/ui/components/navigation/sidebar/SidebarProfileMenu.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 pinningEnabled = sidebar?.pinnedItems?.enabled === true;\n\n const {\n pins,\n toggle: togglePin,\n reorder: reorderPin,\n } = useBackofficeSidebarPins({\n enabled: pinningEnabled,\n storageKey: sidebar?.pinnedItems?.storageKey,\n visibleEntityIds,\n });\n\n let sidebarPinnedEntityIds: readonly string[] | undefined;\n let sidebarTogglePin: ((entityId: string) => void) | undefined;\n let sidebarReorderPin: ((fromId: string, toId: string) => void) | undefined;\n if (pinningEnabled) {\n sidebarPinnedEntityIds = pins;\n sidebarTogglePin = togglePin;\n sidebarReorderPin = reorderPin;\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: sidebarPinnedEntityIds,\n recentItems,\n onTogglePin: sidebarTogglePin,\n onReorderPin: sidebarReorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange: setCollapsed,\n sidebarCollapsed: false,\n });\n }, [\n basePath,\n collapsedByGroupId,\n entities,\n dashboards,\n pathname,\n permissions,\n recentItems,\n setCollapsed,\n sidebar,\n sidebarPinnedEntityIds,\n sidebarQuery,\n sidebarReorderPin,\n sidebarTogglePin,\n t,\n tApp,\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: sidebarPinnedEntityIds,\n recentItems,\n onTogglePin: sidebarTogglePin,\n onReorderPin: sidebarReorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange: setCollapsed,\n sidebarCollapsed: false,\n });\n }, [\n basePath,\n collapsedByGroupId,\n entities,\n dashboards,\n pathname,\n permissions,\n recentItems,\n setCollapsed,\n sidebar,\n sidebarPinnedEntityIds,\n sidebarQuery,\n sidebarReorderPin,\n sidebarTogglePin,\n t,\n tApp,\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 <SidebarProfileMenu\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 <SidebarProfileMenu\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 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 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":";;;;;;;;;;;;;;;;;;;;;;;;AAwEA,IAAM,KAAmC,mCACnC,KAAoC,8BAEpC,MACJ,MAC2C;CAC3C,IAAI,OAAO,SAAW,KACpB,OAAO,CAAC;CAEV,IAAI;EACF,IAAM,IAAM,OAAO,aAAa,QAAQ,CAAU;EAClD,IAAI,KAAO,MACT,OAAO,CAAC;EAEV,IAAM,IAAS,KAAK,MAAM,CAAG;EAI7B,OAHK,MAAM,QAAQ,CAAM,IAGlB,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;EAEnC,CAAC,IAdQ,CAAC;CAeZ,QAAQ;EACN,OAAO,CAAC;CACV;AACF,GAEM,MACJ,GACA,MACS;CACL,aAAO,SAAW,MAGtB,IAAI;EACF,OAAO,aAAa,QAAQ,GAAY,KAAK,UAAU,CAAK,CAAC;CAC/D,QAAQ,CAER;AACF,GAEM,KAAyB,EAC7B,aACA,gBACA,eACA,uBACmC;CACnC,IAAM,EAAE,GAAG,MAAS,GAAe,GAC7B,EAAE,SAAM,EAA8B,GACtC,EAAE,gBAAa,GAAY,GAC3B,IAAU,GAAW,EAAc,GACnC,IAAmB,GAAoB,GACvC,EACJ,MAAM,GACN,aACA,eACA,aACA,eACE,EAAoB,GAClB,CAAC,GAAc,MAAmB,EAAS,EAAE,GAC7C,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,WAClC,MAAM;EAEV,QAAQ;GACN,OAAO;EACT;CACF,CAAC,GACK,CAAC,GAAc,KAAmB,EAAS,EAAK,GAChD,CAAC,GAAc,KAAmB,EAAgC,IAAI,GACtE,IAAoB,GAAS,aAC7B,IAAqB,GAAmB,YAAY,IACpD,IACJ,GAAmB,cAAc,IAC7B,IAAsB,GAAmB,YAAY,GACrD,CAAC,GAAa,MAAkB,QAG/B,IAGE,GAAgB,CAAqB,IAFnC,CAAC,CAGX;CAED,QAAgB;EACV,OAAC,KAA2B,OAAO,SAAW,MAGlD,IAAI;GACF,OAAO,aAAa,QAClB,GAAG,EAA6B,aAChC,OAAO,CAAkB,CAC3B;EACF,QAAQ,CAER;CACF,GAAG;EACD;EACA;EACA;CACF,CAAC;CAED,IAAM,IAAS,QACN,EAAqB,GAAU,CAAO,GAC5C,CAAC,GAAU,CAAO,CAAC,GAEhB,KAAW,QACR,OAAO,KAAK,CAAM,GACxB,CAAC,CAAM,CAAC,GAEL,KAA4B,QACzB,OAAO,YACZ,OAAO,QAAQ,CAAM,CAAC,CAAC,KAAK,CAAC,GAAS,OAC7B,CAAC,GAAS,EAAM,UAAU,oBAAoB,EAAI,CAC1D,CACH,GACC,CAAC,CAAM,CAAC,GAEL,KAAmB,QAChB,EAAwB,GAAQ,GAAU,GAAS,CAAW,GACpE;EAAC;EAAU;EAAQ;EAAa;CAAO,CAAC,GAErC,IAAiB,QACd,EAAsB,GAAU,CAAQ,GAC9C,CAAC,GAAU,CAAQ,CAAC;CAEvB,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,CAAI;GACxB;GACA,WAAW,KAAK,IAAI;EACtB;EACA,IAAgB,MAAS;GACvB,IAAM,IAAO,CACX,GACA,GAAG,EAAK,QAAQ,MACP,EAAM,OAAO,EAAK,MAAM,EAAM,SAAS,EAAK,IACpD,CACH,CAAC,CAAC,MAAM,GAAG,CAAmB;GAE9B,OADA,GAAiB,GAAuB,CAAI,GACrC;EACT,CAAC;CACH,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,IAAM,IAAiB,GAAS,aAAa,YAAY,IAEnD,EACJ,UACA,QAAQ,IACR,SAAS,OACP,GAAyB;EAC3B,SAAS;EACT,YAAY,GAAS,aAAa;EAClC;CACF,CAAC,GAEG,GACA,GACA;CACJ,AAAI,MACF,IAAyB,IACzB,IAAmB,IACnB,IAAoB;CAGtB,IAAI;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;CACd,CAAC,GAEK,KAAW,QACR,EAAqB;EAC1B;EACA;EACA;EACA;EACA;EACA;EACA,aAAa;EACb;EACA;EACA,iBAAiB;EACjB;EACA,aAAa;EACb,cAAc;EACd;EACA,wBAAwB;EACxB,kBAAkB;CACpB,CAAC,GACA;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,GAEK,KAAiB,QACd,EAAqB;EAC1B;EACA;EACA;EACA;EACA;EACA;EACA,aAAa;EACb;EACA;EACA,iBAAiB;EACjB;EACA,aAAa;EACb,cAAc;EACd;EACA,wBAAwB;EACxB,kBAAkB;CACpB,CAAC,GACA;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,GAEK,IAAgB,SAAkB;EAClC,MASJ,EAAgB,EAAI,IA0BpB,YAxB8C;GAC5C,IAAI;IACF,IAAM,IAAS,MAAM,EAAW,OAAO,KAAK;IAgB5C,AAfA,MAAM,IAAI,SAAe,GAAS,MAAW;KAC3C,GAA+B,GAAkB;MAC/C,UAAU,EAAO;MACjB,WAAW,CAAC;MACZ,mBAAmB;OACjB,EAAQ;MACV;MACA,UAAU,MAAU;OAClB,EAAO,CAAK;MACd;KACF,CAAC;IACH,CAAC,GACD,aAAa,WAAW,YAAY,GACpC,aAAa,WAAW,aAAa,GACrC,GAAgB,GAChB,GAAS,QAAQ,KAAK,EAAE,UAAU,GAAuB,CAAQ,EAAE,CAAC;GACtE,UAAU;IACR,EAAgB,EAAK;GACvB;EACF,EAEA,CAAW,CAAC,CAAC,YAAY,CAEzB,CAAC;CACH,GAAG;EAAC,EAAW;EAAQ;EAAU;EAAc;EAAkB;CAAO,CAAC,GAEnE,IAAS,GAAY,MAAM,MAC3B,IAAiB,QACd,GAA8B;EACnC;EACA,kBAAkB,EAAE,6BAA6B;CACnD,CAAC,GACA,CAAC,GAAG,CAAM,CAAC,GAER,KACJ,kBAAC,GAAD;EACE,WAAW;EACX,QAAQ;EACR,QAAQ;GACN,cAAc,EAAE,uBAAuB;GACvC,eAAe,EAAE,+BAA+B;GAChD,SAAS,EAAE,iCAAiC;EAC9C;EACA,WAAW;EACG;CACf,CAAA,GAGG,KACJ,kBAAC,GAAD;EACE,WAAW;EACX,QAAQ;EACR,QAAQ;GACN,cAAc,EAAE,uBAAuB;GACvC,eAAe,EAAE,+BAA+B;GAChD,SAAS,EAAE,iCAAiC;EAC9C;EACA,WAAW;EACG;CACf,CAAA,GAGC,IAAkC;CACtC,AAAI,KAAgB,SAClB,IACE,kBAAC,IAAD,EAA4B,YAAoC,CAAA;CAIpE,IAAM,IACJ,kBAAC,IAAD;EACE,OAAO;EACP,UAAU;EACV,aAAa,EAAE,4BAA4B;EAC3C,WAAW,EAAE,4BAA4B;CAC1C,CAAA;CAGH,OACE,kBAAC,GAAD,EAAA,UACE,kBAAC,IAAD;EACE,SAAS;GACP;GACA,QAAQ;GACR,QAAQ;GACR,aAAa;GACb,mBAAmB;GACnB,qBAAqB,EAAE,iCAAiC;GACxD,mBAAmB,EAAE,+BAA+B;GACpD,qBAAqB,EAAE,6BAA6B;EACtD;EACA,eAAe;GACb,UAAU;GACV,QAAQ;GACR,QAAQ;GACR,aAAa;GACb,oBAAoB;GACpB,qBAAqB,EAAE,6BAA6B;EACtD;EACA,QAAQ,EACN,YAAY,kBAAC,OAAD,EAAK,KAAK,EAAkB,CAAA,EAC1C;EACA,mBAAkB;EAElB,UAAA,kBAAC,IAAD;GAA4C;GAC1C,UAAA,kBAAC,GAAD;IACE,OAAO;KACL,QAAQ;KACR,eAAe;KACf,gBAAgB,EAAE,yBAAyB;IAC7C;IAEC,UAAA;GACoC,CAAA;EACV,CAAA;CACf,CAAA,EACL,CAAA;AAEnB,GAaM,KAAyB,EAC7B,aACA,qBACA,aACA,eACA,uBAC6C;CAC7C,IAAM,IAAc,EAAkB,GAAkB,CAAQ;CAEhE,OACE,kBAAC,GAAD;EACe;EACD;EACG;EAEd;CACoB,CAAA;AAE3B,GAEa,KAAwB,EACnC,aACA,qBACA,aACA,eACA,uBAEI,KAAoB,QAAQ,KAAY,OAExC,kBAAC,GAAD;CACoB;CACR;CACE;CACG;CAEd;AACoB,CAAA,IAKzB,kBAAC,GAAD;CACE,aAAa;CACD;CACG;CAEd;AACoB,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 { GlobalSearchInput } from '@plumile/ui/backoffice/molecules/global_search_input/GlobalSearchInput.js';\nimport { SidebarProfileMenu } from '@plumile/ui/components/navigation/sidebar/SidebarProfileMenu.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 pinningEnabled = sidebar?.pinnedItems?.enabled === true;\n\n const {\n pins,\n toggle: togglePin,\n reorder: reorderPin,\n } = useBackofficeSidebarPins({\n enabled: pinningEnabled,\n storageKey: sidebar?.pinnedItems?.storageKey,\n visibleEntityIds,\n });\n\n let sidebarPinnedEntityIds: readonly string[] | undefined;\n let sidebarTogglePin: ((entityId: string) => void) | undefined;\n let sidebarReorderPin: ((fromId: string, toId: string) => void) | undefined;\n if (pinningEnabled) {\n sidebarPinnedEntityIds = pins;\n sidebarTogglePin = togglePin;\n sidebarReorderPin = reorderPin;\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: sidebarPinnedEntityIds,\n recentItems,\n onTogglePin: sidebarTogglePin,\n onReorderPin: sidebarReorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange: setCollapsed,\n sidebarCollapsed: false,\n });\n }, [\n basePath,\n collapsedByGroupId,\n entities,\n dashboards,\n pathname,\n permissions,\n recentItems,\n setCollapsed,\n sidebar,\n sidebarPinnedEntityIds,\n sidebarQuery,\n sidebarReorderPin,\n sidebarTogglePin,\n t,\n tApp,\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: sidebarPinnedEntityIds,\n recentItems,\n onTogglePin: sidebarTogglePin,\n onReorderPin: sidebarReorderPin,\n collapsedByGroupId,\n onGroupCollapsedChange: setCollapsed,\n sidebarCollapsed: false,\n });\n }, [\n basePath,\n collapsedByGroupId,\n entities,\n dashboards,\n pathname,\n permissions,\n recentItems,\n setCollapsed,\n sidebar,\n sidebarPinnedEntityIds,\n sidebarQuery,\n sidebarReorderPin,\n sidebarTogglePin,\n t,\n tApp,\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 <SidebarProfileMenu\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 <SidebarProfileMenu\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 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 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,17 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import { getBackofficePasswordResetPath as e } from "../router/backofficeAuthPaths.js";
|
|
2
|
+
import { LoginFlow as t } from "../auth/login/LoginFlow.js";
|
|
3
|
+
import { synchronizeAuthStatusQuery as n } from "../auth/login/synchronizeAuthStatusQuery.js";
|
|
4
|
+
import { useBackofficeConfig as r } from "../provider/BackofficeConfigContext.js";
|
|
5
|
+
import { useRelayEnvironment as i } from "../relay/useRelayEnvironment.js";
|
|
6
|
+
import { useBackofficeAuth as a } from "../hooks/useBackofficeAuth.js";
|
|
7
|
+
import { useBackofficeAuthLoginConfig as o } from "../provider/useBackofficeLazyValue.js";
|
|
8
8
|
import { useCallback as s, useContext as c, useRef as l } from "react";
|
|
9
9
|
import { jsx as u } from "react/jsx-runtime";
|
|
10
10
|
import * as d from "react-relay";
|
|
11
11
|
import f from "@plumile/router/routing/RoutingContext.js";
|
|
12
12
|
//#region src/pages/BackofficeLoginPage.tsx
|
|
13
13
|
var { usePreloadedQuery: p } = d, m = ({ prepared: d }) => {
|
|
14
|
-
let m = c(f), { auth: h, basePath: g } =
|
|
14
|
+
let m = c(f), { auth: h, basePath: g } = r(), _ = o(), v = a(), y = i(), b = l(!1), x = p(_.loginQuery, d.query).oidcProviders ?? [], S = s(() => {
|
|
15
15
|
b.current || (b.current = !0, (async () => {
|
|
16
16
|
try {
|
|
17
17
|
let e = await h.session.load();
|
|
@@ -19,7 +19,7 @@ var { usePreloadedQuery: p } = d, m = ({ prepared: d }) => {
|
|
|
19
19
|
m?.history.push({ pathname: g });
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
|
-
if (await h.lifecycle?.onLoginSuccess?.(), !await
|
|
22
|
+
if (await h.lifecycle?.onLoginSuccess?.(), !await n(y, e.authStatusQuery)) return;
|
|
23
23
|
m?.history.push({ pathname: g });
|
|
24
24
|
} catch {} finally {
|
|
25
25
|
b.current = !1;
|
|
@@ -32,9 +32,9 @@ var { usePreloadedQuery: p } = d, m = ({ prepared: d }) => {
|
|
|
32
32
|
y,
|
|
33
33
|
m?.history
|
|
34
34
|
]), C = s(() => {
|
|
35
|
-
m?.history.push({ pathname:
|
|
35
|
+
m?.history.push({ pathname: e(g) });
|
|
36
36
|
}, [g, m?.history]);
|
|
37
|
-
return /* @__PURE__ */ u(
|
|
37
|
+
return /* @__PURE__ */ u(t, {
|
|
38
38
|
auth: v,
|
|
39
39
|
oidcProviders: x,
|
|
40
40
|
onLoginSuccess: S,
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { getBackofficeLoginPath as e } from "../router/backofficeAuthPaths.js";
|
|
2
|
+
import { useBackofficeReactTranslation as t } from "../i18n/useBackofficeReactTranslation.js";
|
|
3
|
+
import { PasswordResetCompleteScreen as n } from "../auth/pages/PasswordResetCompleteScreen.js";
|
|
4
|
+
import { requireField as r, resolveMutationOutcome as i } from "../relay/mutationResult.js";
|
|
5
|
+
import { useBackofficeConfig as a } from "../provider/BackofficeConfigContext.js";
|
|
6
|
+
import { useBackofficeAuthPasswordResetCompleteConfig as o } from "../provider/useBackofficeLazyValue.js";
|
|
7
7
|
import { useCallback as s, useContext as c } from "react";
|
|
8
8
|
import { jsx as l } from "react/jsx-runtime";
|
|
9
9
|
import * as u from "react-relay";
|
|
10
10
|
import d from "@plumile/router/routing/RoutingContext.js";
|
|
11
11
|
//#region src/pages/BackofficePasswordResetCompletePage.tsx
|
|
12
12
|
var { useMutation: f } = u, p = () => {
|
|
13
|
-
let u = c(d), { basePath: p } =
|
|
14
|
-
u?.history.push({ pathname:
|
|
13
|
+
let u = c(d), { basePath: p } = a(), m = o(), { t: h } = t(), [g] = f(m.completePasswordResetMutation), _ = s(() => {
|
|
14
|
+
u?.history.push({ pathname: e(p) });
|
|
15
15
|
}, [p, u?.history]), v = s(async (e) => {
|
|
16
|
-
let t = h("auth.passwordResetComplete.errors.invalid"),
|
|
16
|
+
let t = h("auth.passwordResetComplete.errors.invalid"), n = t;
|
|
17
17
|
return new Promise((a, o) => {
|
|
18
18
|
g({
|
|
19
19
|
variables: { input: e },
|
|
20
20
|
onCompleted: (e) => {
|
|
21
|
-
let s =
|
|
22
|
-
defaultErrorMessage:
|
|
21
|
+
let s = i(e.completePasswordReset ?? null, {
|
|
22
|
+
defaultErrorMessage: n,
|
|
23
23
|
mapReason: (e) => {
|
|
24
24
|
switch (e) {
|
|
25
25
|
case "INVALID_TOKEN": return t;
|
|
@@ -34,7 +34,7 @@ var { useMutation: f } = u, p = () => {
|
|
|
34
34
|
o(Error(s.message));
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
|
-
let c =
|
|
37
|
+
let c = r(s.payload.success ?? null, n);
|
|
38
38
|
if (!c.ok) {
|
|
39
39
|
o(Error(c.message));
|
|
40
40
|
return;
|
|
@@ -42,12 +42,12 @@ var { useMutation: f } = u, p = () => {
|
|
|
42
42
|
a(c.value);
|
|
43
43
|
},
|
|
44
44
|
onError: () => {
|
|
45
|
-
o(Error(
|
|
45
|
+
o(Error(n));
|
|
46
46
|
}
|
|
47
47
|
});
|
|
48
48
|
});
|
|
49
49
|
}, [g, h]);
|
|
50
|
-
return /* @__PURE__ */ l(
|
|
50
|
+
return /* @__PURE__ */ l(n, {
|
|
51
51
|
onBackToLogin: _,
|
|
52
52
|
onCompletePasswordReset: v
|
|
53
53
|
});
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { getBackofficeLoginPath as e } from "../router/backofficeAuthPaths.js";
|
|
2
|
+
import { useBackofficeReactTranslation as t } from "../i18n/useBackofficeReactTranslation.js";
|
|
3
|
+
import { VerifyEmailScreen as n } from "../auth/pages/VerifyEmailScreen.js";
|
|
4
|
+
import { requireField as r, resolveMutationOutcome as i } from "../relay/mutationResult.js";
|
|
5
|
+
import { useBackofficeConfig as a } from "../provider/BackofficeConfigContext.js";
|
|
6
|
+
import { useBackofficeAuthVerifyEmailConfig as o } from "../provider/useBackofficeLazyValue.js";
|
|
7
7
|
import { useCallback as s, useContext as c } from "react";
|
|
8
8
|
import { jsx as l } from "react/jsx-runtime";
|
|
9
9
|
import * as u from "react-relay";
|
|
10
10
|
import d from "@plumile/router/routing/RoutingContext.js";
|
|
11
11
|
//#region src/pages/BackofficeVerifyEmailPage.tsx
|
|
12
12
|
var { useMutation: f } = u, p = () => {
|
|
13
|
-
let u = c(d), { basePath: p } =
|
|
14
|
-
u?.history.push({ pathname:
|
|
13
|
+
let u = c(d), { basePath: p } = a(), m = o(), { t: h } = t(), [g] = f(m.verifyEmailMutation), _ = s(() => {
|
|
14
|
+
u?.history.push({ pathname: e(p) });
|
|
15
15
|
}, [p, u?.history]), v = s(async (e) => {
|
|
16
|
-
let t = h("auth.verifyEmail.errors.invalid"),
|
|
16
|
+
let t = h("auth.verifyEmail.errors.invalid"), n = t;
|
|
17
17
|
return new Promise((a, o) => {
|
|
18
18
|
g({
|
|
19
19
|
variables: { input: e },
|
|
20
20
|
onCompleted: (e) => {
|
|
21
|
-
let s =
|
|
22
|
-
defaultErrorMessage:
|
|
21
|
+
let s = i(e.verifyEmail ?? null, {
|
|
22
|
+
defaultErrorMessage: n,
|
|
23
23
|
mapReason: (e) => {
|
|
24
24
|
switch (e) {
|
|
25
25
|
case "INVALID_TOKEN": return t;
|
|
@@ -34,7 +34,7 @@ var { useMutation: f } = u, p = () => {
|
|
|
34
34
|
o(Error(s.message));
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
|
-
let c =
|
|
37
|
+
let c = r(s.payload.success ?? null, n);
|
|
38
38
|
if (!c.ok) {
|
|
39
39
|
o(Error(c.message));
|
|
40
40
|
return;
|
|
@@ -42,12 +42,12 @@ var { useMutation: f } = u, p = () => {
|
|
|
42
42
|
a(c.value);
|
|
43
43
|
},
|
|
44
44
|
onError: () => {
|
|
45
|
-
o(Error(
|
|
45
|
+
o(Error(n));
|
|
46
46
|
}
|
|
47
47
|
});
|
|
48
48
|
});
|
|
49
49
|
}, [g, h]);
|
|
50
|
-
return /* @__PURE__ */ l(
|
|
50
|
+
return /* @__PURE__ */ l(n, {
|
|
51
51
|
onBackToLogin: _,
|
|
52
52
|
onVerifyEmail: v
|
|
53
53
|
});
|