@the-portland-company/shell 0.36.0 → 0.36.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app-chrome.cjs +215 -94
- package/dist/app-chrome.cjs.map +1 -1
- package/dist/app-chrome.js +40 -3
- package/dist/app-chrome.js.map +1 -1
- package/dist/{chunk-QX2UNWSE.js → chunk-LIGKGXFT.js} +97 -95
- package/dist/chunk-LIGKGXFT.js.map +1 -0
- package/dist/chunk-LL6LSJAH.js +92 -0
- package/dist/chunk-LL6LSJAH.js.map +1 -0
- package/dist/logout-signal.cjs +99 -0
- package/dist/logout-signal.cjs.map +1 -0
- package/dist/logout-signal.d.cts +56 -0
- package/dist/logout-signal.d.ts +56 -0
- package/dist/logout-signal.js +3 -0
- package/dist/logout-signal.js.map +1 -0
- package/dist/native.cjs +95 -93
- package/dist/native.cjs.map +1 -1
- package/dist/native.js +1 -1
- package/package.json +6 -1
- package/dist/chunk-QX2UNWSE.js.map +0 -1
package/dist/app-chrome.cjs
CHANGED
|
@@ -2154,116 +2154,118 @@ function NavTopBar({
|
|
|
2154
2154
|
}
|
|
2155
2155
|
) })
|
|
2156
2156
|
] }),
|
|
2157
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 z-30 mt-2 w-72 rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]", children: [
|
|
2157
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 z-30 mt-2 flex max-h-[calc(100vh-5rem)] w-72 flex-col overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]", children: [
|
|
2158
2158
|
/* @__PURE__ */ jsxRuntime.jsx(TopBarPanelArrow, {}),
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2183
|
-
|
|
2184
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
2185
|
-
|
|
2186
|
-
"
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2193
|
-
|
|
2194
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2195
|
-
|
|
2159
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto overscroll-contain", children: [
|
|
2160
|
+
userMenu?.myProfileHref ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2161
|
+
"a",
|
|
2162
|
+
{
|
|
2163
|
+
href: safeHref(userMenu.myProfileHref),
|
|
2164
|
+
className: "flex w-full items-center gap-2.5 px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)]",
|
|
2165
|
+
children: [
|
|
2166
|
+
/* @__PURE__ */ jsxRuntime.jsx(ProfileIcon, {}),
|
|
2167
|
+
"My Profile"
|
|
2168
|
+
]
|
|
2169
|
+
}
|
|
2170
|
+
) : null,
|
|
2171
|
+
userMenu?.organizationSettingsHref ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2172
|
+
"a",
|
|
2173
|
+
{
|
|
2174
|
+
href: safeHref(userMenu.organizationSettingsHref),
|
|
2175
|
+
className: "flex w-full items-center gap-2.5 border-t border-[color:var(--line)] px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)]",
|
|
2176
|
+
children: [
|
|
2177
|
+
/* @__PURE__ */ jsxRuntime.jsx(BriefcaseIcon, {}),
|
|
2178
|
+
"Organization Settings"
|
|
2179
|
+
]
|
|
2180
|
+
}
|
|
2181
|
+
) : null,
|
|
2182
|
+
userMenu?.roles && userMenu.roles.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-[color:var(--line)] px-4 py-3", children: [
|
|
2183
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: "Roles & Organizations" }),
|
|
2184
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-1.5", children: userMenu.roles.map((r, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex flex-wrap items-center gap-1.5 text-sm", children: [
|
|
2185
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-md bg-[color:var(--panel)] px-2 py-0.5 text-xs font-bold uppercase tracking-wide text-[color:var(--foreground)]", children: r.role }),
|
|
2186
|
+
r.orgName ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[color:var(--muted)]", children: [
|
|
2187
|
+
"in ",
|
|
2188
|
+
r.orgName
|
|
2189
|
+
] }) : null
|
|
2190
|
+
] }, `${r.role}-${i}`)) })
|
|
2191
|
+
] }) : null,
|
|
2192
|
+
userMenu?.accounts && userMenu.accounts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-[color:var(--line)] px-4 py-3", children: [
|
|
2193
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: "Accounts" }),
|
|
2194
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-1", children: userMenu.accounts.map((a) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center gap-2.5", children: [
|
|
2195
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2196
|
+
"button",
|
|
2197
|
+
{
|
|
2198
|
+
type: "button",
|
|
2199
|
+
onClick: () => {
|
|
2200
|
+
if (!a.active) userMenu.onSwitchAccount?.(a.id);
|
|
2201
|
+
},
|
|
2202
|
+
className: "flex min-w-0 flex-1 items-center gap-2.5 rounded-lg px-1 py-1 text-left hover:bg-[color:var(--panel)]",
|
|
2203
|
+
children: [
|
|
2204
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-race-red)] text-[11px] font-bold text-white", children: a.avatarUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: a.avatarUrl, alt: "", className: "h-full w-full object-cover" }) : (a.name ?? a.email ?? "?").slice(0, 2).toUpperCase() }),
|
|
2205
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col leading-tight", children: [
|
|
2206
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2207
|
+
"span",
|
|
2208
|
+
{
|
|
2209
|
+
className: [
|
|
2210
|
+
"truncate text-sm font-semibold",
|
|
2211
|
+
a.active ? "text-[color:var(--color-race-red)]" : "text-[color:var(--foreground)]"
|
|
2212
|
+
].join(" "),
|
|
2213
|
+
children: a.name ?? a.email ?? a.id.slice(0, 8)
|
|
2214
|
+
}
|
|
2215
|
+
),
|
|
2216
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs text-[color:var(--muted)]", children: a.active ? "Active" : a.email ?? "" })
|
|
2217
|
+
] })
|
|
2218
|
+
]
|
|
2219
|
+
}
|
|
2220
|
+
),
|
|
2221
|
+
!a.active && userMenu.onRemoveAccount ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2222
|
+
"button",
|
|
2223
|
+
{
|
|
2224
|
+
type: "button",
|
|
2225
|
+
"aria-label": `Remove ${a.name ?? a.email ?? "account"}`,
|
|
2226
|
+
onClick: () => userMenu.onRemoveAccount?.(a.id),
|
|
2227
|
+
className: "shrink-0 rounded p-1 text-[color:var(--color-race-red)] hover:bg-[color:var(--panel)]",
|
|
2228
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {})
|
|
2229
|
+
}
|
|
2230
|
+
) : null
|
|
2231
|
+
] }, a.id)) }),
|
|
2232
|
+
userMenu.addAccountHref || userMenu.onAddAccount ? userMenu.addAccountHref ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2233
|
+
"a",
|
|
2196
2234
|
{
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
if (!a.active) userMenu.onSwitchAccount?.(a.id);
|
|
2200
|
-
},
|
|
2201
|
-
className: "flex min-w-0 flex-1 items-center gap-2.5 rounded-lg px-1 py-1 text-left hover:bg-[color:var(--panel)]",
|
|
2235
|
+
href: safeHref(userMenu.addAccountHref),
|
|
2236
|
+
className: "mt-1.5 flex items-center gap-2.5 rounded-lg px-1 py-1.5 text-sm font-semibold text-[color:var(--color-race-red)] hover:bg-[color:var(--panel)]",
|
|
2202
2237
|
children: [
|
|
2203
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2204
|
-
|
|
2205
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2206
|
-
"span",
|
|
2207
|
-
{
|
|
2208
|
-
className: [
|
|
2209
|
-
"truncate text-sm font-semibold",
|
|
2210
|
-
a.active ? "text-[color:var(--color-race-red)]" : "text-[color:var(--foreground)]"
|
|
2211
|
-
].join(" "),
|
|
2212
|
-
children: a.name ?? a.email ?? a.id.slice(0, 8)
|
|
2213
|
-
}
|
|
2214
|
-
),
|
|
2215
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs text-[color:var(--muted)]", children: a.active ? "Active" : a.email ?? "" })
|
|
2216
|
-
] })
|
|
2238
|
+
/* @__PURE__ */ jsxRuntime.jsx(AddUserIcon, {}),
|
|
2239
|
+
"Add Account"
|
|
2217
2240
|
]
|
|
2218
2241
|
}
|
|
2219
|
-
)
|
|
2220
|
-
!a.active && userMenu.onRemoveAccount ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2242
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2221
2243
|
"button",
|
|
2222
2244
|
{
|
|
2223
2245
|
type: "button",
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2246
|
+
onClick: userMenu.onAddAccount,
|
|
2247
|
+
className: "mt-1.5 flex w-full items-center gap-2.5 rounded-lg px-1 py-1.5 text-left text-sm font-semibold text-[color:var(--color-race-red)] hover:bg-[color:var(--panel)]",
|
|
2248
|
+
children: [
|
|
2249
|
+
/* @__PURE__ */ jsxRuntime.jsx(AddUserIcon, {}),
|
|
2250
|
+
"Add Account"
|
|
2251
|
+
]
|
|
2228
2252
|
}
|
|
2229
2253
|
) : null
|
|
2230
|
-
] }
|
|
2231
|
-
userMenu
|
|
2232
|
-
|
|
2254
|
+
] }) : null,
|
|
2255
|
+
userMenu?.theme ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[color:var(--line)]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2256
|
+
NavThemeControl,
|
|
2233
2257
|
{
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
children: [
|
|
2237
|
-
/* @__PURE__ */ jsxRuntime.jsx(AddUserIcon, {}),
|
|
2238
|
-
"Add Account"
|
|
2239
|
-
]
|
|
2258
|
+
value: userMenu.theme.value,
|
|
2259
|
+
onChange: userMenu.theme.onChange
|
|
2240
2260
|
}
|
|
2241
|
-
) :
|
|
2242
|
-
|
|
2243
|
-
{
|
|
2244
|
-
type: "button",
|
|
2245
|
-
onClick: userMenu.onAddAccount,
|
|
2246
|
-
className: "mt-1.5 flex w-full items-center gap-2.5 rounded-lg px-1 py-1.5 text-left text-sm font-semibold text-[color:var(--color-race-red)] hover:bg-[color:var(--panel)]",
|
|
2247
|
-
children: [
|
|
2248
|
-
/* @__PURE__ */ jsxRuntime.jsx(AddUserIcon, {}),
|
|
2249
|
-
"Add Account"
|
|
2250
|
-
]
|
|
2251
|
-
}
|
|
2252
|
-
) : null
|
|
2253
|
-
] }) : null,
|
|
2254
|
-
userMenu?.theme ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[color:var(--line)]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2255
|
-
NavThemeControl,
|
|
2256
|
-
{
|
|
2257
|
-
value: userMenu.theme.value,
|
|
2258
|
-
onChange: userMenu.theme.onChange
|
|
2259
|
-
}
|
|
2260
|
-
) }) : null,
|
|
2261
|
+
) }) : null
|
|
2262
|
+
] }),
|
|
2261
2263
|
onSignOut ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2262
2264
|
"button",
|
|
2263
2265
|
{
|
|
2264
2266
|
type: "button",
|
|
2265
2267
|
onClick: onSignOut,
|
|
2266
|
-
className: "flex w-full items-center gap-2.5 border-t border-[color:var(--line)] px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)] hover:text-[color:var(--color-race-red)]",
|
|
2268
|
+
className: "flex w-full shrink-0 items-center gap-2.5 border-t border-[color:var(--line)] px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)] hover:text-[color:var(--color-race-red)]",
|
|
2267
2269
|
children: [
|
|
2268
2270
|
/* @__PURE__ */ jsxRuntime.jsx(SignOutIcon, {}),
|
|
2269
2271
|
"Sign out"
|
|
@@ -2602,6 +2604,89 @@ function resolveIdentity(input) {
|
|
|
2602
2604
|
loaded: input.loaded ?? false
|
|
2603
2605
|
};
|
|
2604
2606
|
}
|
|
2607
|
+
|
|
2608
|
+
// src/logout-signal.ts
|
|
2609
|
+
var LOGOUT_COOKIE = "politogy_logout_at";
|
|
2610
|
+
var LOGOUT_CHANNEL = "politogy-logout";
|
|
2611
|
+
var POLL_MS = 1e3;
|
|
2612
|
+
function parseTimestamp(value) {
|
|
2613
|
+
if (!value) return null;
|
|
2614
|
+
const n = Number(value);
|
|
2615
|
+
return Number.isFinite(n) && n > 0 ? n : null;
|
|
2616
|
+
}
|
|
2617
|
+
function isSessionRevoked(logoutCookieValue, authTime) {
|
|
2618
|
+
const loggedOutAt = parseTimestamp(logoutCookieValue);
|
|
2619
|
+
if (loggedOutAt === null) return false;
|
|
2620
|
+
if (authTime == null || !Number.isFinite(authTime) || authTime <= 0) return true;
|
|
2621
|
+
const authMs = authTime < 1e12 ? authTime * 1e3 : authTime;
|
|
2622
|
+
return authMs < loggedOutAt;
|
|
2623
|
+
}
|
|
2624
|
+
function readLogoutCookie() {
|
|
2625
|
+
if (typeof document === "undefined") return null;
|
|
2626
|
+
try {
|
|
2627
|
+
const m = document.cookie.match(new RegExp(`(?:^|;\\s*)${LOGOUT_COOKIE}=([^;]+)`));
|
|
2628
|
+
return parseTimestamp(m ? decodeURIComponent(m[1]) : null);
|
|
2629
|
+
} catch {
|
|
2630
|
+
return null;
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
function broadcastLogout(at = Date.now()) {
|
|
2634
|
+
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
2635
|
+
const host = window.location.hostname;
|
|
2636
|
+
const domainAttr = /(^|\.)politogyvrm\.com$/i.test(host) ? "; Domain=.politogyvrm.com" : "";
|
|
2637
|
+
const secure = window.location.protocol === "https:" ? "; Secure" : "";
|
|
2638
|
+
document.cookie = `${LOGOUT_COOKIE}=${at}; Path=/; Max-Age=2592000; SameSite=Lax${domainAttr}${secure}`;
|
|
2639
|
+
try {
|
|
2640
|
+
new BroadcastChannel(LOGOUT_CHANNEL).postMessage(at);
|
|
2641
|
+
} catch {
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
function watchLogout(onLogout, options = {}) {
|
|
2645
|
+
if (typeof document === "undefined" || typeof window === "undefined") {
|
|
2646
|
+
return () => {
|
|
2647
|
+
};
|
|
2648
|
+
}
|
|
2649
|
+
const { authTime = null, intervalMs = POLL_MS } = options;
|
|
2650
|
+
const baseline = readLogoutCookie() ?? 0;
|
|
2651
|
+
let done = false;
|
|
2652
|
+
const fire = (at) => {
|
|
2653
|
+
if (done) return;
|
|
2654
|
+
if (at <= baseline) return;
|
|
2655
|
+
if (authTime != null && !isSessionRevoked(String(at), authTime)) return;
|
|
2656
|
+
done = true;
|
|
2657
|
+
cleanup();
|
|
2658
|
+
onLogout();
|
|
2659
|
+
};
|
|
2660
|
+
const check = () => {
|
|
2661
|
+
const at = readLogoutCookie();
|
|
2662
|
+
if (at !== null) fire(at);
|
|
2663
|
+
};
|
|
2664
|
+
let channel = null;
|
|
2665
|
+
try {
|
|
2666
|
+
channel = new BroadcastChannel(LOGOUT_CHANNEL);
|
|
2667
|
+
channel.onmessage = (event) => {
|
|
2668
|
+
const at = typeof event.data === "number" ? event.data : readLogoutCookie();
|
|
2669
|
+
if (at !== null) fire(at);
|
|
2670
|
+
};
|
|
2671
|
+
} catch {
|
|
2672
|
+
channel = null;
|
|
2673
|
+
}
|
|
2674
|
+
const timer = window.setInterval(check, intervalMs);
|
|
2675
|
+
window.addEventListener("visibilitychange", check);
|
|
2676
|
+
window.addEventListener("focus", check);
|
|
2677
|
+
window.addEventListener("pageshow", check);
|
|
2678
|
+
function cleanup() {
|
|
2679
|
+
window.clearInterval(timer);
|
|
2680
|
+
window.removeEventListener("visibilitychange", check);
|
|
2681
|
+
window.removeEventListener("focus", check);
|
|
2682
|
+
window.removeEventListener("pageshow", check);
|
|
2683
|
+
try {
|
|
2684
|
+
channel?.close();
|
|
2685
|
+
} catch {
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
return cleanup;
|
|
2689
|
+
}
|
|
2605
2690
|
var CORE_APP = "vrm";
|
|
2606
2691
|
var POLITOGY_APPS = {
|
|
2607
2692
|
vrm: { title: "Politogy VRM", origin: "https://app.politogyvrm.com", storagePrefix: "vrm" },
|
|
@@ -2678,6 +2763,42 @@ function FrameBody({
|
|
|
2678
2763
|
}) {
|
|
2679
2764
|
const meta = POLITOGY_APPS[app];
|
|
2680
2765
|
const chrome = useChromeState();
|
|
2766
|
+
const signOutRef = react.useRef(onSignOut);
|
|
2767
|
+
signOutRef.current = onSignOut;
|
|
2768
|
+
const signingOutRef = react.useRef(false);
|
|
2769
|
+
const handleSignOut = react.useCallback(() => {
|
|
2770
|
+
signingOutRef.current = true;
|
|
2771
|
+
broadcastLogout();
|
|
2772
|
+
signOutRef.current();
|
|
2773
|
+
window.setTimeout(() => {
|
|
2774
|
+
window.location.replace(window.location.href);
|
|
2775
|
+
}, 2e3);
|
|
2776
|
+
}, []);
|
|
2777
|
+
react.useEffect(
|
|
2778
|
+
() => (
|
|
2779
|
+
// A tab that learns of a sign-out elsewhere forces a real NAVIGATION
|
|
2780
|
+
// rather than calling the app's own sign-out handler.
|
|
2781
|
+
//
|
|
2782
|
+
// Measured against production before this landed: calling the app's
|
|
2783
|
+
// handler did nothing at all. Apps wire it as
|
|
2784
|
+
// `onSignOut={() => { void signOutAction(); }}` — a server action invoked
|
|
2785
|
+
// outside a transition, so the `redirect()` inside it can never be
|
|
2786
|
+
// applied by the client and the tab just sits there. Building cross-tab
|
|
2787
|
+
// logout on that path made the whole feature a no-op.
|
|
2788
|
+
//
|
|
2789
|
+
// A hard navigation cannot fail that way, and it hands the decision to
|
|
2790
|
+
// the authority rather than guessing: the app's middleware sees a session
|
|
2791
|
+
// whose auth_time predates `politogy_logout_at`, treats it as revoked,
|
|
2792
|
+
// and redirects to Politogy ID. Server-side truth decides; the client
|
|
2793
|
+
// only forces the request. No re-broadcast — the signal that woke us is
|
|
2794
|
+
// already on record for every tab.
|
|
2795
|
+
watchLogout(() => {
|
|
2796
|
+
if (signingOutRef.current) return;
|
|
2797
|
+
window.location.replace(window.location.href);
|
|
2798
|
+
})
|
|
2799
|
+
),
|
|
2800
|
+
[]
|
|
2801
|
+
);
|
|
2681
2802
|
const core = app === CORE_APP ? data?.core : void 0;
|
|
2682
2803
|
const identity = useChromeIdentity({ userName: session.userName, email: session.email });
|
|
2683
2804
|
const derivedUserMenu = useChromeUserMenu({
|
|
@@ -2760,7 +2881,7 @@ function FrameBody({
|
|
|
2760
2881
|
role: session.role
|
|
2761
2882
|
},
|
|
2762
2883
|
userMenu,
|
|
2763
|
-
onSignOut,
|
|
2884
|
+
onSignOut: handleSignOut,
|
|
2764
2885
|
// The action cluster is IDENTICAL everywhere — core included. Page
|
|
2765
2886
|
// actions sit BEFORE it, never inside it, so the Alerts bell keeps its
|
|
2766
2887
|
// required position: farthest right, immediately before My Account.
|