@hexclave/next 1.0.49 → 1.0.52
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/{admin-app-impl-Cmhx-Gnk.d.ts → admin-app-impl-Bga0o6cL.d.ts} +5 -2
- package/dist/{admin-app-impl-Cmhx-Gnk.d.ts.map → admin-app-impl-Bga0o6cL.d.ts.map} +1 -1
- package/dist/clickmap/clickmap-core.d.ts +1 -1
- package/dist/clickmap/index.d.ts +1 -1
- package/dist/{client-app-Majjw8Xp.d.ts → client-app-B0kBC67Z.d.ts} +2 -1
- package/dist/{client-app-Majjw8Xp.d.ts.map → client-app-B0kBC67Z.d.ts.map} +1 -1
- package/dist/common-BK_sydxF.d.ts.map +1 -1
- package/dist/components/selected-team-switcher.d.ts +1 -1
- package/dist/components/team-icon.d.ts +1 -1
- package/dist/components/team-switcher.d.ts +1 -1
- package/dist/components-page/account-settings/active-sessions/active-sessions-page.js +1 -1
- package/dist/components-page/account-settings/api-keys/api-keys-page.js +2 -2
- package/dist/components-page/account-settings/payments/payments-page.d.ts +1 -1
- package/dist/components-page/account-settings/teams/leave-team-section.d.ts +1 -1
- package/dist/components-page/account-settings/teams/team-api-keys-section.d.ts +1 -1
- package/dist/components-page/account-settings/teams/team-api-keys-section.js +2 -2
- package/dist/components-page/account-settings/teams/team-display-name-section.d.ts +1 -1
- package/dist/components-page/account-settings/teams/team-member-invitation-section.d.ts +1 -1
- package/dist/components-page/account-settings/teams/team-member-list-section.d.ts +1 -1
- package/dist/components-page/account-settings/teams/team-page.d.ts +1 -1
- package/dist/components-page/account-settings/teams/team-profile-image-section.d.ts +1 -1
- package/dist/components-page/account-settings/teams/team-profile-user-section.d.ts +1 -1
- package/dist/components-page/hexclave-handler-client.d.ts +1 -1
- package/dist/components-page/hexclave-handler.d.ts +1 -1
- package/dist/components-page/sign-out.js +11 -2
- package/dist/components-page/sign-out.js.map +1 -1
- package/dist/components-page/sign-out.test.d.ts +1 -0
- package/dist/components-page/sign-out.test.js +157 -0
- package/dist/components-page/sign-out.test.js.map +1 -0
- package/dist/dev-tool/dev-tool-core.d.ts +1 -1
- package/dist/dev-tool/dev-tool-core.d.ts.map +1 -1
- package/dist/dev-tool/dev-tool-core.js +58 -28
- package/dist/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/dev-tool/dev-tool-styles.js +35 -0
- package/dist/dev-tool/dev-tool-styles.js.map +1 -1
- package/dist/dev-tool/index.d.ts +1 -1
- package/dist/esm/components-page/account-settings/active-sessions/active-sessions-page.js +1 -1
- package/dist/esm/components-page/account-settings/api-keys/api-keys-page.js +2 -2
- package/dist/esm/components-page/account-settings/teams/team-api-keys-section.js +2 -2
- package/dist/esm/components-page/sign-out.d.ts.map +1 -1
- package/dist/esm/components-page/sign-out.js +12 -3
- package/dist/esm/components-page/sign-out.js.map +1 -1
- package/dist/esm/components-page/sign-out.test.d.ts +1 -0
- package/dist/esm/components-page/sign-out.test.js +156 -0
- package/dist/esm/components-page/sign-out.test.js.map +1 -0
- package/dist/esm/dev-tool/dev-tool-core.d.ts.map +1 -1
- package/dist/esm/dev-tool/dev-tool-core.js +58 -28
- package/dist/esm/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/esm/dev-tool/dev-tool-styles.js +35 -0
- package/dist/esm/dev-tool/dev-tool-styles.js.map +1 -1
- package/dist/esm/generated/global-css.d.ts +1 -1
- package/dist/esm/generated/global-css.js +1 -1
- package/dist/esm/generated/global-css.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +97 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +26 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js +21 -4
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts +37 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.js +89 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.test.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.test.js +134 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-back-state.test.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts +8 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js +73 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js +92 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js.map +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js +27 -6
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -0
- package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
- package/dist/esm/pushed-config-error-overlay/index.js +1 -1
- package/dist/esm/pushed-config-error-overlay/index.js.map +1 -1
- package/dist/esm/utils/session-storage.d.ts +12 -0
- package/dist/esm/utils/session-storage.d.ts.map +1 -0
- package/dist/esm/utils/session-storage.js +30 -0
- package/dist/esm/utils/session-storage.js.map +1 -0
- package/dist/generated/global-css.d.ts +1 -1
- package/dist/generated/global-css.js +1 -1
- package/dist/generated/global-css.js.map +1 -1
- package/dist/{hexclave-provider-IAd7nlbi.d.ts → hexclave-provider-BQ9wrtBt.d.ts} +2 -2
- package/dist/{hexclave-provider-IAd7nlbi.d.ts.map → hexclave-provider-BQ9wrtBt.d.ts.map} +1 -1
- package/dist/{hooks-BKXOF6jh.d.ts → hooks-ykQ7Wsco.d.ts} +2 -2
- package/dist/{hooks-BKXOF6jh.d.ts.map → hooks-ykQ7Wsco.d.ts.map} +1 -1
- package/dist/{index-Ck1qKoin.d.ts → index-DwE1cNLH.d.ts} +2 -2
- package/dist/{index-Ck1qKoin.d.ts.map → index-DwE1cNLH.d.ts.map} +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +97 -0
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +26 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/common.js +21 -4
- package/dist/lib/hexclave-app/apps/implementations/common.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts +37 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.d.ts.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.js +92 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.test.d.ts +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.test.js +133 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-back-state.test.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts +8 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.d.ts.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js +74 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.d.ts +1 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js +91 -0
- package/dist/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.js.map +1 -0
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js +27 -6
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/admin-app.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
- package/dist/lib/hexclave-app/apps/interfaces/server-app.d.ts +1 -1
- package/dist/lib/hexclave-app/index.d.ts +1 -1
- package/dist/lib/hexclave-app/projects/index.d.ts +1 -1
- package/dist/lib/hexclave-app/teams/index.d.ts +1 -1
- package/dist/lib/hexclave-app/users/index.d.ts +1 -1
- package/dist/lib/hooks.d.ts +1 -1
- package/dist/providers/hexclave-context.d.ts +1 -1
- package/dist/providers/hexclave-provider-client.d.ts +1 -1
- package/dist/providers/hexclave-provider.d.ts +1 -1
- package/dist/pushed-config-error-overlay/index.d.ts +1 -1
- package/dist/pushed-config-error-overlay/index.js +1 -1
- package/dist/pushed-config-error-overlay/index.js.map +1 -1
- package/dist/sign-out-DBnSkfDz.d.ts.map +1 -1
- package/dist/utils/session-storage.d.ts +12 -0
- package/dist/utils/session-storage.d.ts.map +1 -0
- package/dist/utils/session-storage.js +33 -0
- package/dist/utils/session-storage.js.map +1 -0
- package/package.json +4 -4
- package/src/components-page/sign-out.test.tsx +190 -0
- package/src/components-page/sign-out.tsx +22 -3
- package/src/dev-tool/dev-tool-core.ts +100 -35
- package/src/dev-tool/dev-tool-styles.ts +35 -0
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts +127 -0
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +34 -1
- package/src/lib/hexclave-app/apps/implementations/common.ts +18 -1
- package/src/lib/hexclave-app/apps/implementations/redirect-back-state.test.ts +134 -0
- package/src/lib/hexclave-app/apps/implementations/redirect-back-state.ts +140 -0
- package/src/lib/hexclave-app/apps/implementations/redirect-loop-breaker.test.ts +127 -0
- package/src/lib/hexclave-app/apps/implementations/redirect-loop-breaker.ts +117 -0
- package/src/lib/hexclave-app/apps/implementations/server-app-impl.ts +31 -5
- package/src/lib/hexclave-app/apps/interfaces/client-app.ts +1 -0
- package/src/pushed-config-error-overlay/index.ts +1 -1
- package/src/utils/session-storage.ts +45 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
const require_rolldown_runtime = require("../rolldown-runtime-D6vf50IK.js");
|
|
2
|
+
let ___lib_hexclave_app_common_js = require("../lib/hexclave-app/common.js");
|
|
3
|
+
let react = require("react");
|
|
4
|
+
react = require_rolldown_runtime.__toESM(react);
|
|
5
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
6
|
+
let react_dom_client = require("react-dom/client");
|
|
7
|
+
let vitest = require("vitest");
|
|
8
|
+
let __sign_out_js = require("./sign-out.js");
|
|
9
|
+
let ___providers_translation_provider_client_js = require("../providers/translation-provider-client.js");
|
|
10
|
+
//#region src/components-page/sign-out.test.tsx
|
|
11
|
+
// @vitest-environment jsdom
|
|
12
|
+
const appMockState = vitest.vi.hoisted(() => ({
|
|
13
|
+
app: null,
|
|
14
|
+
user: null
|
|
15
|
+
}));
|
|
16
|
+
vitest.vi.mock("..", () => ({
|
|
17
|
+
useStackApp: () => {
|
|
18
|
+
if (appMockState.app == null) throw new Error("Expected test app to be set before rendering.");
|
|
19
|
+
return appMockState.app;
|
|
20
|
+
},
|
|
21
|
+
useUser: () => appMockState.user
|
|
22
|
+
}));
|
|
23
|
+
vitest.vi.mock("@hexclave/shared/dist/utils/react", async (importOriginal) => {
|
|
24
|
+
const original = await importOriginal();
|
|
25
|
+
const promiseStates = /* @__PURE__ */ new WeakMap();
|
|
26
|
+
return {
|
|
27
|
+
...original,
|
|
28
|
+
use: (promise) => {
|
|
29
|
+
const state = promiseStates.get(promise);
|
|
30
|
+
if (state == null) {
|
|
31
|
+
promiseStates.set(promise, { status: "pending" });
|
|
32
|
+
promise.then((value) => promiseStates.set(promise, {
|
|
33
|
+
status: "ok",
|
|
34
|
+
value
|
|
35
|
+
}), (error) => promiseStates.set(promise, {
|
|
36
|
+
status: "error",
|
|
37
|
+
error
|
|
38
|
+
}));
|
|
39
|
+
throw promise;
|
|
40
|
+
}
|
|
41
|
+
switch (state.status) {
|
|
42
|
+
case "pending": throw promise;
|
|
43
|
+
case "error": throw state.error;
|
|
44
|
+
case "ok": return state.value;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
vitest.vi.mock("@hexclave/ui", async () => {
|
|
50
|
+
await import("react");
|
|
51
|
+
return {
|
|
52
|
+
Button: (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
53
|
+
type: "button",
|
|
54
|
+
onClick: props.onClick,
|
|
55
|
+
children: props.children
|
|
56
|
+
}),
|
|
57
|
+
Typography: (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: props.children }),
|
|
58
|
+
cn: (...classes) => classes.filter(Boolean).join(" ")
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
const previousActEnvironment = Reflect.get(globalThis, "IS_REACT_ACT_ENVIRONMENT");
|
|
62
|
+
function createAppTestDouble(options) {
|
|
63
|
+
return {
|
|
64
|
+
redirectToSignIn: vitest.vi.fn(async () => {}),
|
|
65
|
+
[___lib_hexclave_app_common_js.hexclaveAppInternalsSymbol]: { isTrustedRedirectUrl: vitest.vi.fn(async (url) => options.trustedUrls.includes(url)) }
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function createUserTestDouble() {
|
|
69
|
+
return { signOut: vitest.vi.fn(async () => {}) };
|
|
70
|
+
}
|
|
71
|
+
const originalLocation = window.location;
|
|
72
|
+
let locationReplaceMock = vitest.vi.fn();
|
|
73
|
+
let root = null;
|
|
74
|
+
let container = null;
|
|
75
|
+
async function renderSignOut(options) {
|
|
76
|
+
appMockState.app = options.app;
|
|
77
|
+
appMockState.user = options.user;
|
|
78
|
+
container = document.createElement("div");
|
|
79
|
+
document.body.append(container);
|
|
80
|
+
root = (0, react_dom_client.createRoot)(container);
|
|
81
|
+
await (0, react.act)(async () => {
|
|
82
|
+
root?.render(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(___providers_translation_provider_client_js.TranslationProviderClient, {
|
|
83
|
+
quetzalKeys: /* @__PURE__ */ new Map(),
|
|
84
|
+
quetzalLocale: /* @__PURE__ */ new Map(),
|
|
85
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Suspense, {
|
|
86
|
+
fallback: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { "data-testid": "suspense-fallback" }),
|
|
87
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__sign_out_js.SignOut, { searchParams: options.searchParams })
|
|
88
|
+
})
|
|
89
|
+
}));
|
|
90
|
+
});
|
|
91
|
+
await (0, react.act)(async () => {
|
|
92
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
(0, vitest.describe)("SignOut", () => {
|
|
96
|
+
(0, vitest.beforeEach)(() => {
|
|
97
|
+
Reflect.set(globalThis, "IS_REACT_ACT_ENVIRONMENT", true);
|
|
98
|
+
locationReplaceMock = vitest.vi.fn();
|
|
99
|
+
Reflect.deleteProperty(window, "location");
|
|
100
|
+
Reflect.set(window, "location", {
|
|
101
|
+
href: "https://demo.example.test/handler/sign-out",
|
|
102
|
+
replace: locationReplaceMock
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
(0, vitest.afterEach)(() => {
|
|
106
|
+
(0, react.act)(() => {
|
|
107
|
+
root?.unmount();
|
|
108
|
+
});
|
|
109
|
+
container?.remove();
|
|
110
|
+
root = null;
|
|
111
|
+
container = null;
|
|
112
|
+
appMockState.app = null;
|
|
113
|
+
appMockState.user = null;
|
|
114
|
+
Reflect.set(window, "location", originalLocation);
|
|
115
|
+
vitest.vi.restoreAllMocks();
|
|
116
|
+
Reflect.set(globalThis, "IS_REACT_ACT_ENVIRONMENT", previousActEnvironment);
|
|
117
|
+
});
|
|
118
|
+
(0, vitest.it)("signs out with a trusted after_auth_return_to redirect URL", async () => {
|
|
119
|
+
const app = createAppTestDouble({ trustedUrls: ["/dashboard"] });
|
|
120
|
+
const user = createUserTestDouble();
|
|
121
|
+
await renderSignOut({
|
|
122
|
+
app,
|
|
123
|
+
user,
|
|
124
|
+
searchParams: { after_auth_return_to: "/dashboard" }
|
|
125
|
+
});
|
|
126
|
+
(0, vitest.expect)(user.signOut).toHaveBeenCalledWith({ redirectUrl: "/dashboard" });
|
|
127
|
+
});
|
|
128
|
+
(0, vitest.it)("ignores an untrusted after_auth_return_to and falls back to the default sign-out redirect", async () => {
|
|
129
|
+
const app = createAppTestDouble({ trustedUrls: [] });
|
|
130
|
+
const user = createUserTestDouble();
|
|
131
|
+
await renderSignOut({
|
|
132
|
+
app,
|
|
133
|
+
user,
|
|
134
|
+
searchParams: { after_auth_return_to: "https://evil.example.test/phishing" }
|
|
135
|
+
});
|
|
136
|
+
(0, vitest.expect)(user.signOut).toHaveBeenCalledWith({ redirectUrl: void 0 });
|
|
137
|
+
});
|
|
138
|
+
(0, vitest.it)("does not follow an untrusted after_auth_return_to when already signed out", async () => {
|
|
139
|
+
await renderSignOut({
|
|
140
|
+
app: createAppTestDouble({ trustedUrls: [] }),
|
|
141
|
+
user: null,
|
|
142
|
+
searchParams: { after_auth_return_to: "https://evil.example.test/phishing-signed-out" }
|
|
143
|
+
});
|
|
144
|
+
(0, vitest.expect)(locationReplaceMock).not.toHaveBeenCalled();
|
|
145
|
+
});
|
|
146
|
+
(0, vitest.it)("follows a trusted after_auth_return_to when already signed out", async () => {
|
|
147
|
+
await renderSignOut({
|
|
148
|
+
app: createAppTestDouble({ trustedUrls: ["/trusted-dashboard"] }),
|
|
149
|
+
user: null,
|
|
150
|
+
searchParams: { after_auth_return_to: "/trusted-dashboard" }
|
|
151
|
+
});
|
|
152
|
+
(0, vitest.expect)(locationReplaceMock).toHaveBeenCalledWith("/trusted-dashboard");
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
//#endregion
|
|
156
|
+
|
|
157
|
+
//# sourceMappingURL=sign-out.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-out.test.js","names":["vi","hexclaveAppInternalsSymbol","TranslationProviderClient","React","SignOut"],"sources":["../../src/components-page/sign-out.test.tsx"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n// @vitest-environment jsdom\n\nimport React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport type { CurrentUser } from \"../lib/hexclave-app\";\nimport type { StackClientApp } from \"../lib/hexclave-app/apps/interfaces/client-app\";\nimport { hexclaveAppInternalsSymbol } from \"../lib/hexclave-app/common\";\nimport { TranslationProviderClient } from \"../providers/translation-provider-client\";\nimport { SignOut } from \"./sign-out\";\n\nconst appMockState = vi.hoisted(() => ({\n app: null as unknown,\n user: null as unknown,\n}));\n\nvi.mock(\"..\", () => ({\n useStackApp: () => {\n if (appMockState.app == null) {\n throw new Error(\"Expected test app to be set before rendering.\");\n }\n return appMockState.app;\n },\n useUser: () => appMockState.user,\n}));\n\n// The real `use` delegates to React.use, which breaks in this test setup because the shared\n// package and react-dom resolve different React instances. Replace it with an equivalent\n// Suspense-compatible implementation that doesn't depend on the React dispatcher.\nvi.mock(\"@hexclave/shared/dist/utils/react\", async (importOriginal) => {\n const original = await importOriginal<typeof import(\"@hexclave/shared/dist/utils/react\")>();\n type PromiseState = { status: \"pending\" } | { status: \"ok\", value: unknown } | { status: \"error\", error: unknown };\n const promiseStates = new WeakMap<Promise<unknown>, PromiseState>();\n return {\n ...original,\n use: <T,>(promise: Promise<T>): T => {\n const state = promiseStates.get(promise);\n if (state == null) {\n promiseStates.set(promise, { status: \"pending\" });\n promise.then(\n (value) => promiseStates.set(promise, { status: \"ok\", value }),\n (error) => promiseStates.set(promise, { status: \"error\", error }),\n );\n throw promise;\n }\n switch (state.status) {\n case \"pending\": {\n throw promise;\n }\n case \"error\": {\n throw state.error;\n }\n case \"ok\": {\n // This cast is safe because the value was stored from this exact promise's resolution;\n // the WeakMap just can't express the per-key type relationship.\n return state.value as T;\n }\n }\n },\n };\n});\n\nvi.mock(\"@hexclave/ui\", async () => {\n const React = await import(\"react\");\n return {\n Button: (props: { children: React.ReactNode, onClick?: () => void }) => (\n <button type=\"button\" onClick={props.onClick}>{props.children}</button>\n ),\n Typography: (props: { children: React.ReactNode }) => <div>{props.children}</div>,\n cn: (...classes: (string | false | null | undefined)[]) => classes.filter(Boolean).join(\" \"),\n };\n});\n\nconst previousActEnvironment = Reflect.get(globalThis, \"IS_REACT_ACT_ENVIRONMENT\");\n\nfunction createAppTestDouble(options: {\n trustedUrls: string[],\n}) {\n const app = {\n redirectToSignIn: vi.fn(async () => {}),\n [hexclaveAppInternalsSymbol]: {\n isTrustedRedirectUrl: vi.fn(async (url: string) => options.trustedUrls.includes(url)),\n },\n };\n\n // This test double intentionally implements only the StackClientApp surface that SignOut and\n // the rendered signed-out card touch.\n return app as unknown as StackClientApp<true>;\n}\n\nfunction createUserTestDouble() {\n const user = {\n signOut: vi.fn(async () => {}),\n };\n // Same as the app test double: only the surface SignOut touches.\n return user as unknown as CurrentUser & { signOut: ReturnType<typeof vi.fn> };\n}\n\n// jsdom's window.location is not configurable, so it can't be spied on; replace it wholesale.\nconst originalLocation = window.location;\nlet locationReplaceMock = vi.fn();\n\nlet root: Root | null = null;\nlet container: HTMLDivElement | null = null;\n\nasync function renderSignOut(options: {\n app: StackClientApp<true>,\n user: unknown,\n searchParams?: Record<string, string>,\n}) {\n appMockState.app = options.app;\n appMockState.user = options.user;\n container = document.createElement(\"div\");\n document.body.append(container);\n root = createRoot(container);\n await act(async () => {\n root?.render(\n <TranslationProviderClient quetzalKeys={new Map()} quetzalLocale={new Map()}>\n <React.Suspense fallback={<div data-testid=\"suspense-fallback\" />}>\n <SignOut searchParams={options.searchParams} />\n </React.Suspense>\n </TranslationProviderClient>\n );\n });\n await act(async () => {\n await new Promise((resolve) => setTimeout(resolve, 0));\n });\n}\n\ndescribe(\"SignOut\", () => {\n beforeEach(() => {\n Reflect.set(globalThis, \"IS_REACT_ACT_ENVIRONMENT\", true);\n locationReplaceMock = vi.fn();\n Reflect.deleteProperty(window, \"location\");\n Reflect.set(window, \"location\", { href: \"https://demo.example.test/handler/sign-out\", replace: locationReplaceMock });\n });\n\n afterEach(() => {\n act(() => {\n root?.unmount();\n });\n container?.remove();\n root = null;\n container = null;\n appMockState.app = null;\n appMockState.user = null;\n Reflect.set(window, \"location\", originalLocation);\n vi.restoreAllMocks();\n Reflect.set(globalThis, \"IS_REACT_ACT_ENVIRONMENT\", previousActEnvironment);\n });\n\n it(\"signs out with a trusted after_auth_return_to redirect URL\", async () => {\n const app = createAppTestDouble({ trustedUrls: [\"/dashboard\"] });\n const user = createUserTestDouble();\n\n await renderSignOut({ app, user, searchParams: { after_auth_return_to: \"/dashboard\" } });\n\n expect(user.signOut).toHaveBeenCalledWith({ redirectUrl: \"/dashboard\" });\n });\n\n it(\"ignores an untrusted after_auth_return_to and falls back to the default sign-out redirect\", async () => {\n const app = createAppTestDouble({ trustedUrls: [] });\n const user = createUserTestDouble();\n\n await renderSignOut({ app, user, searchParams: { after_auth_return_to: \"https://evil.example.test/phishing\" } });\n\n // The untrusted URL is dropped entirely; sign-out proceeds with the default destination.\n expect(user.signOut).toHaveBeenCalledWith({ redirectUrl: undefined });\n });\n\n it(\"does not follow an untrusted after_auth_return_to when already signed out\", async () => {\n const app = createAppTestDouble({ trustedUrls: [] });\n\n await renderSignOut({ app, user: null, searchParams: { after_auth_return_to: \"https://evil.example.test/phishing-signed-out\" } });\n\n expect(locationReplaceMock).not.toHaveBeenCalled();\n });\n\n it(\"follows a trusted after_auth_return_to when already signed out\", async () => {\n const app = createAppTestDouble({ trustedUrls: [\"/trusted-dashboard\"] });\n\n await renderSignOut({ app, user: null, searchParams: { after_auth_return_to: \"/trusted-dashboard\" } });\n\n expect(locationReplaceMock).toHaveBeenCalledWith(\"/trusted-dashboard\");\n });\n});\n"],"mappings":";;;;;;;;;;;AAeA,MAAM,eAAeA,OAAAA,GAAG,eAAe;CACrC,KAAK;CACL,MAAM;AACR,EAAE;AAEFA,OAAAA,GAAG,KAAK,aAAa;CACnB,mBAAmB;EACjB,IAAI,aAAa,OAAO,MACtB,MAAM,IAAI,MAAM,+CAA+C;EAEjE,OAAO,aAAa;CACtB;CACA,eAAe,aAAa;AAC9B,EAAE;AAKFA,OAAAA,GAAG,KAAK,qCAAqC,OAAO,mBAAmB;CACrE,MAAM,WAAW,MAAM,eAAmE;CAE1F,MAAM,gCAAgB,IAAI,QAAwC;CAClE,OAAO;EACL,GAAG;EACH,MAAU,YAA2B;GACnC,MAAM,QAAQ,cAAc,IAAI,OAAO;GACvC,IAAI,SAAS,MAAM;IACjB,cAAc,IAAI,SAAS,EAAE,QAAQ,UAAU,CAAC;IAChD,QAAQ,MACL,UAAU,cAAc,IAAI,SAAS;KAAE,QAAQ;KAAM;IAAM,CAAC,IAC5D,UAAU,cAAc,IAAI,SAAS;KAAE,QAAQ;KAAS;IAAM,CAAC,CAClE;IACA,MAAM;GACR;GACA,QAAQ,MAAM,QAAd;IACE,KAAK,WACH,MAAM;IAER,KAAK,SACH,MAAM,MAAM;IAEd,KAAK,MAGH,OAAO,MAAM;GAEjB;EACF;CACF;AACF,CAAC;AAEDA,OAAAA,GAAG,KAAK,gBAAgB,YAAY;CACpB,MAAM,OAAO;CAC3B,OAAO;EACL,SAAS,UACP,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GAAQ,MAAK;GAAS,SAAS,MAAM;aAAU,MAAM;EAAiB,CAAA;EAExE,aAAa,UAAyC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAAA,UAAM,MAAM,SAAc,CAAA;EAChF,KAAK,GAAG,YAAmD,QAAQ,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAC7F;AACF,CAAC;AAED,MAAM,yBAAyB,QAAQ,IAAI,YAAY,0BAA0B;AAEjF,SAAS,oBAAoB,SAE1B;CAUD,OAAO;EARL,kBAAkBA,OAAAA,GAAG,GAAG,YAAY,CAAC,CAAC;GACrCC,8BAAAA,6BAA6B,EAC5B,sBAAsBD,OAAAA,GAAG,GAAG,OAAO,QAAgB,QAAQ,YAAY,SAAS,GAAG,CAAC,EACtF;CAKO;AACX;AAEA,SAAS,uBAAuB;CAK9B,OAAO,EAHL,SAASA,OAAAA,GAAG,GAAG,YAAY,CAAC,CAAC,EAGrB;AACZ;AAGA,MAAM,mBAAmB,OAAO;AAChC,IAAI,sBAAsBA,OAAAA,GAAG,GAAG;AAEhC,IAAI,OAAoB;AACxB,IAAI,YAAmC;AAEvC,eAAe,cAAc,SAI1B;CACD,aAAa,MAAM,QAAQ;CAC3B,aAAa,OAAO,QAAQ;CAC5B,YAAY,SAAS,cAAc,KAAK;CACxC,SAAS,KAAK,OAAO,SAAS;CAC9B,QAAA,GAAA,iBAAA,WAAA,CAAkB,SAAS;CAC3B,OAAA,GAAA,MAAA,IAAA,CAAU,YAAY;EACpB,MAAM,OACJ,iBAAA,GAAA,kBAAA,IAAA,CAACE,4CAAAA,2BAAD;GAA2B,6BAAa,IAAI,IAAI;GAAG,+BAAe,IAAI,IAAI;aACxE,iBAAA,GAAA,kBAAA,IAAA,CAACC,MAAAA,QAAM,UAAP;IAAgB,UAAU,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAAK,eAAY,oBAAqB,CAAA;cAC9D,iBAAA,GAAA,kBAAA,IAAA,CAACC,cAAAA,SAAD,EAAS,cAAc,QAAQ,aAAe,CAAA;GAChC,CAAA;EACS,CAAA,CAC7B;CACF,CAAC;CACD,OAAA,GAAA,MAAA,IAAA,CAAU,YAAY;EACpB,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,CAAC,CAAC;CACvD,CAAC;AACH;qBAES,iBAAiB;CACxB,CAAA,GAAA,OAAA,WAAA,OAAiB;EACf,QAAQ,IAAI,YAAY,4BAA4B,IAAI;EACxD,sBAAsBJ,OAAAA,GAAG,GAAG;EAC5B,QAAQ,eAAe,QAAQ,UAAU;EACzC,QAAQ,IAAI,QAAQ,YAAY;GAAE,MAAM;GAA8C,SAAS;EAAoB,CAAC;CACtH,CAAC;CAED,CAAA,GAAA,OAAA,UAAA,OAAgB;EACd,CAAA,GAAA,MAAA,IAAA,OAAU;GACR,MAAM,QAAQ;EAChB,CAAC;EACD,WAAW,OAAO;EAClB,OAAO;EACP,YAAY;EACZ,aAAa,MAAM;EACnB,aAAa,OAAO;EACpB,QAAQ,IAAI,QAAQ,YAAY,gBAAgB;EAChD,OAAA,GAAG,gBAAgB;EACnB,QAAQ,IAAI,YAAY,4BAA4B,sBAAsB;CAC5E,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,8DAA8D,YAAY;EAC3E,MAAM,MAAM,oBAAoB,EAAE,aAAa,CAAC,YAAY,EAAE,CAAC;EAC/D,MAAM,OAAO,qBAAqB;EAElC,MAAM,cAAc;GAAE;GAAK;GAAM,cAAc,EAAE,sBAAsB,aAAa;EAAE,CAAC;EAEvF,CAAA,GAAA,OAAA,OAAA,CAAO,KAAK,OAAO,CAAC,CAAC,qBAAqB,EAAE,aAAa,aAAa,CAAC;CACzE,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,6FAA6F,YAAY;EAC1G,MAAM,MAAM,oBAAoB,EAAE,aAAa,CAAC,EAAE,CAAC;EACnD,MAAM,OAAO,qBAAqB;EAElC,MAAM,cAAc;GAAE;GAAK;GAAM,cAAc,EAAE,sBAAsB,qCAAqC;EAAE,CAAC;EAG/G,CAAA,GAAA,OAAA,OAAA,CAAO,KAAK,OAAO,CAAC,CAAC,qBAAqB,EAAE,aAAa,KAAA,EAAU,CAAC;CACtE,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,6EAA6E,YAAY;EAG1F,MAAM,cAAc;GAAE,KAFV,oBAAoB,EAAE,aAAa,CAAC,EAAE,CAE1B;GAAG,MAAM;GAAM,cAAc,EAAE,sBAAsB,gDAAgD;EAAE,CAAC;EAEhI,CAAA,GAAA,OAAA,OAAA,CAAO,mBAAmB,CAAC,CAAC,IAAI,iBAAiB;CACnD,CAAC;CAED,CAAA,GAAA,OAAA,GAAA,CAAG,kEAAkE,YAAY;EAG/E,MAAM,cAAc;GAAE,KAFV,oBAAoB,EAAE,aAAa,CAAC,oBAAoB,EAAE,CAE9C;GAAG,MAAM;GAAM,cAAc,EAAE,sBAAsB,qBAAqB;EAAE,CAAC;EAErG,CAAA,GAAA,OAAA,OAAA,CAAO,mBAAmB,CAAC,CAAC,qBAAqB,oBAAoB;CACvE,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-tool-core.d.ts","names":[],"sources":["../../src/dev-tool/dev-tool-core.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"dev-tool-core.d.ts","names":[],"sources":["../../src/dev-tool/dev-tool-core.ts"],"mappings":";;iBAkyEgB,aAAA,CAAc,GAAyB,EAApB,cAAc"}
|
|
@@ -5,7 +5,6 @@ let ___in_page_ui_dom_js = require("../in-page-ui/dom.js");
|
|
|
5
5
|
let ___lib_hexclave_app_common_js = require("../lib/hexclave-app/common.js");
|
|
6
6
|
let _hexclave_shared_dist_utils_urls = require("@hexclave/shared/dist/utils/urls");
|
|
7
7
|
let ___lib_hexclave_app_url_targets_js = require("../lib/hexclave-app/url-targets.js");
|
|
8
|
-
let ___generated_env_js = require("../generated/env.js");
|
|
9
8
|
let ___lib_hexclave_app_apps_implementations_common_js = require("../lib/hexclave-app/apps/implementations/common.js");
|
|
10
9
|
let __dev_tool_styles_js = require("./dev-tool-styles.js");
|
|
11
10
|
let __dev_tool_trigger_position_js = require("./dev-tool-trigger-position.js");
|
|
@@ -18,6 +17,8 @@ const MAX_LOG_ENTRIES = 500;
|
|
|
18
17
|
const CONSOLE_LOG_BATCH_SIZE = 100;
|
|
19
18
|
const DRAG_THRESHOLD = 5;
|
|
20
19
|
const DOCS_URL = "https://docs.hexclave.com";
|
|
20
|
+
const LOCAL_DASHBOARD_ORIGIN = "http://localhost:26700";
|
|
21
|
+
const HOSTED_DASHBOARD_URL = "https://app.hexclave.com";
|
|
21
22
|
const TABS = [
|
|
22
23
|
{
|
|
23
24
|
id: "overview",
|
|
@@ -137,33 +138,35 @@ function nextId() {
|
|
|
137
138
|
function resolveApiBaseUrl(app) {
|
|
138
139
|
return (0, ___lib_hexclave_app_apps_implementations_common_js.getBaseUrl)(app[___lib_hexclave_app_common_js.hexclaveAppInternalsSymbol].getConstructorOptions().baseUrl);
|
|
139
140
|
}
|
|
140
|
-
function
|
|
141
|
-
return
|
|
141
|
+
function localDashboardProjectUrl(app) {
|
|
142
|
+
return `${LOCAL_DASHBOARD_ORIGIN}/projects/${encodeURIComponent(app.projectId)}`;
|
|
142
143
|
}
|
|
143
|
-
function
|
|
144
|
-
if (
|
|
145
|
-
return
|
|
144
|
+
function parseProjectAvailabilityResponse(body) {
|
|
145
|
+
if (typeof body !== "object" || body === null) return false;
|
|
146
|
+
return "project_available" in body && body.project_available === true;
|
|
146
147
|
}
|
|
147
|
-
|
|
148
|
+
const LOCAL_DASHBOARD_PROBE_TIMEOUT_MS = 3e3;
|
|
149
|
+
function canReachLocalDashboard() {
|
|
150
|
+
return (0, _hexclave_shared_dist_utils_urls.isLocalhost)(window.location.href) && window.location.protocol === "http:";
|
|
151
|
+
}
|
|
152
|
+
async function isLocalDashboardProjectAvailable(app) {
|
|
153
|
+
if (!canReachLocalDashboard()) return false;
|
|
154
|
+
const url = `${LOCAL_DASHBOARD_ORIGIN}/api/development-environment/project-availability?project_id=${encodeURIComponent(app.projectId)}`;
|
|
155
|
+
const controller = new AbortController();
|
|
156
|
+
const timeout = setTimeout(() => controller.abort(), LOCAL_DASHBOARD_PROBE_TIMEOUT_MS);
|
|
148
157
|
try {
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (url.hostname.startsWith("api.")) {
|
|
156
|
-
url.hostname = "app." + url.hostname.slice(4);
|
|
157
|
-
return url.origin;
|
|
158
|
-
}
|
|
159
|
-
return url.origin;
|
|
158
|
+
const response = await fetch(url, {
|
|
159
|
+
method: "GET",
|
|
160
|
+
signal: controller.signal
|
|
161
|
+
});
|
|
162
|
+
if (!response.ok) return false;
|
|
163
|
+
return parseProjectAvailabilityResponse(await response.json());
|
|
160
164
|
} catch {
|
|
161
|
-
return
|
|
165
|
+
return false;
|
|
166
|
+
} finally {
|
|
167
|
+
clearTimeout(timeout);
|
|
162
168
|
}
|
|
163
169
|
}
|
|
164
|
-
function resolveDashboardUrl(app) {
|
|
165
|
-
return `${deriveDashboardBaseUrl(resolveApiBaseUrl(app))}/projects/${encodeURIComponent(app.projectId)}`;
|
|
166
|
-
}
|
|
167
170
|
function formatTimestamp(ts) {
|
|
168
171
|
return new Date(ts).toLocaleTimeString([], {
|
|
169
172
|
hour: "2-digit",
|
|
@@ -428,8 +431,8 @@ function createTabBar(tabs, activeTab, onTabChange, opts) {
|
|
|
428
431
|
setActive
|
|
429
432
|
};
|
|
430
433
|
}
|
|
431
|
-
function
|
|
432
|
-
|
|
434
|
+
function populateIframeTab(container, src, title, loadingMsg = "Loading…", errorMsg = "Unable to load content", errorDetail, openExternallyLabel) {
|
|
435
|
+
container.innerHTML = "";
|
|
433
436
|
if (openExternallyLabel != null) container.appendChild((0, ___in_page_ui_dom_js.h)("div", { className: "sdt-iframe-toolbar" }, (0, ___in_page_ui_dom_js.h)("a", {
|
|
434
437
|
href: src,
|
|
435
438
|
target: "_blank",
|
|
@@ -458,7 +461,7 @@ function createIframeTab(src, title, loadingMsg = "Loading…", errorMsg = "Unab
|
|
|
458
461
|
} }, errorDetail));
|
|
459
462
|
const retryBtn = (0, ___in_page_ui_dom_js.h)("button", { className: "sdt-iframe-error-btn" }, "Retry");
|
|
460
463
|
retryBtn.addEventListener("click", () => {
|
|
461
|
-
container
|
|
464
|
+
populateIframeTab(container, src, title, loadingMsg, errorMsg, errorDetail, openExternallyLabel);
|
|
462
465
|
});
|
|
463
466
|
errDiv.appendChild(retryBtn);
|
|
464
467
|
const link = (0, ___in_page_ui_dom_js.h)("a", {
|
|
@@ -475,7 +478,6 @@ function createIframeTab(src, title, loadingMsg = "Loading…", errorMsg = "Unab
|
|
|
475
478
|
container.appendChild(errDiv);
|
|
476
479
|
});
|
|
477
480
|
container.appendChild(iframe);
|
|
478
|
-
return container;
|
|
479
481
|
}
|
|
480
482
|
function hasPersistentTokenStoreForDevTool(app) {
|
|
481
483
|
return app[___lib_hexclave_app_common_js.hexclaveAppInternalsSymbol].getConstructorOptions().tokenStore !== null;
|
|
@@ -1421,7 +1423,35 @@ function createAITab(app) {
|
|
|
1421
1423
|
return container;
|
|
1422
1424
|
}
|
|
1423
1425
|
function createDashboardTab(app) {
|
|
1424
|
-
|
|
1426
|
+
const container = (0, ___in_page_ui_dom_js.h)("div", { className: "sdt-iframe-container" });
|
|
1427
|
+
function showChecking() {
|
|
1428
|
+
container.innerHTML = "";
|
|
1429
|
+
container.appendChild((0, ___in_page_ui_dom_js.h)("div", { className: "sdt-iframe-loading" }, "Checking development environment…"));
|
|
1430
|
+
}
|
|
1431
|
+
function showUnavailable() {
|
|
1432
|
+
container.innerHTML = "";
|
|
1433
|
+
const message = (0, ___in_page_ui_dom_js.h)("div", { className: "sdt-dashboard-unavailable" });
|
|
1434
|
+
const text = (0, ___in_page_ui_dom_js.h)("div", { className: "sdt-dashboard-unavailable-text" });
|
|
1435
|
+
text.appendChild(document.createTextNode("Navigate to "));
|
|
1436
|
+
text.appendChild((0, ___in_page_ui_dom_js.h)("a", {
|
|
1437
|
+
className: "sdt-dashboard-unavailable-link",
|
|
1438
|
+
href: HOSTED_DASHBOARD_URL,
|
|
1439
|
+
target: "_blank",
|
|
1440
|
+
rel: "noopener noreferrer"
|
|
1441
|
+
}, HOSTED_DASHBOARD_URL));
|
|
1442
|
+
text.appendChild(document.createTextNode(" to view this project's dashboard"));
|
|
1443
|
+
message.appendChild(text);
|
|
1444
|
+
container.appendChild(message);
|
|
1445
|
+
}
|
|
1446
|
+
async function check() {
|
|
1447
|
+
showChecking();
|
|
1448
|
+
const available = await isLocalDashboardProjectAvailable(app);
|
|
1449
|
+
if (!container.isConnected) return;
|
|
1450
|
+
if (available) populateIframeTab(container, localDashboardProjectUrl(app), "Hexclave Dashboard", "Loading dashboard…", "Unable to load dashboard", "The dashboard may require authentication or block framing", "Open in New Tab");
|
|
1451
|
+
else showUnavailable();
|
|
1452
|
+
}
|
|
1453
|
+
(0, _hexclave_shared_dist_utils_promises.runAsynchronously)(check);
|
|
1454
|
+
return container;
|
|
1425
1455
|
}
|
|
1426
1456
|
function createSupportTab(app) {
|
|
1427
1457
|
const container = (0, ___in_page_ui_dom_js.h)("div", { className: "sdt-support-tab" });
|
|
@@ -1817,7 +1847,7 @@ function createPanel(app, state, logStore, onClose) {
|
|
|
1817
1847
|
panel.style.width = state.get().panelWidth + "px";
|
|
1818
1848
|
panel.style.height = state.get().panelHeight + "px";
|
|
1819
1849
|
}
|
|
1820
|
-
const tabs =
|
|
1850
|
+
const tabs = TABS;
|
|
1821
1851
|
const storedActiveTab = state.get().activeTab;
|
|
1822
1852
|
const activeTab = tabs.some((tab) => tab.id === storedActiveTab) ? storedActiveTab : DEFAULT_STATE.activeTab;
|
|
1823
1853
|
applyPanelMode(activeTab);
|