Skip to content

Commit 8299c9d

Browse files
committed
initial commit
1 parent b0812c8 commit 8299c9d

2 files changed

Lines changed: 96 additions & 25 deletions

File tree

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/dashboards/[dashboardId]/page-client.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ function DashboardDetailContent({
391391
<PageLayout fillWidth noPadding>
392392
{/* Both panels are always in the DOM so the iframe never unmounts/reloads.
393393
The chat panel animates its width; the dashboard panel adjusts via flex-1. */}
394-
<div data-full-bleed className="flex h-full">
394+
<div data-full-bleed className="flex h-[calc(100vh-4.5rem)] dark:h-[calc(100vh-5.75rem)]">
395395
{/* Dashboard iframe panel */}
396396
<div
397397
className={cn(

apps/dashboard/src/components/commands/create-dashboard/dashboard-sandbox-host.tsx

Lines changed: 95 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,41 @@ type DashboardArtifact = {
1818
function html(strings: TemplateStringsArray, ...values: unknown[]): string {
1919
return strings.reduce<string>((result, str, i) => result + str + (values[i] ?? ''), '');
2020
}
21-
2221
const isDev = process.env.NODE_ENV === "development";
2322

23+
function getEsmFallbackVersion(version: string): string {
24+
const parts = version.split(".");
25+
const [major, minor, patchString] = parts;
26+
const patch = Number(patchString);
27+
return `${major}.${minor}.${patch - 1}`;
28+
}
29+
2430
function getDependencyScripts(esmVersion: string, esmFallbackVersion: string, dashboardUrl: string): string {
2531
if (isDev) {
2632
return html`
2733
<script type="module">
34+
function formatDependencyError(error) {
35+
return error instanceof Error ? error.message : String(error);
36+
}
37+
38+
function reportDependencyError(message, error) {
39+
window.parent.postMessage({
40+
type: 'dashboard-sandbox-dependency-error',
41+
message,
42+
stack: error instanceof Error ? error.stack : undefined,
43+
}, '*');
44+
}
45+
46+
function failDependencyLoad(message, error) {
47+
reportDependencyError(message, error);
48+
window.__depsError = {
49+
message,
50+
stack: error instanceof Error ? error.stack : undefined,
51+
};
52+
window.__depsReady = true;
53+
window.dispatchEvent(new Event('deps-ready'));
54+
}
55+
2856
import React from 'https://esm.sh/react@19.2.3';
2957
import * as ReactDOM from 'https://esm.sh/react-dom@19.2.3?deps=react@19.2.3';
3058
import * as ReactDOMClient from 'https://esm.sh/react-dom@19.2.3/client?deps=react@19.2.3';
@@ -41,14 +69,14 @@ function getDependencyScripts(esmVersion: string, esmFallbackVersion: string, da
4169
window.StackServerApp = StackSDK.StackServerApp;
4270
window.StackSDK = StackSDK;
4371
} catch (e) {
44-
window.parent.postMessage({ type: 'dashboard-error-boundary', message: '[sandbox] Stack SDK failed at version ${esmVersion}, trying fallback ${esmFallbackVersion}: ' + e?.message }, '*');
72+
reportDependencyError('[sandbox] @stackframe/js failed at version ${esmVersion}; trying fallback ${esmFallbackVersion}: ' + formatDependencyError(e), e);
4573
try {
4674
const StackSDK = await import('https://esm.sh/@stackframe/js@${esmFallbackVersion}');
4775
window.StackAdminApp = StackSDK.StackAdminApp;
4876
window.StackServerApp = StackSDK.StackServerApp;
4977
window.StackSDK = StackSDK;
5078
} catch (e2) {
51-
window.parent.postMessage({ type: 'dashboard-error-boundary', message: '[sandbox] Stack SDK fallback also failed: ' + e2?.message }, '*');
79+
failDependencyLoad('[sandbox] @stackframe/js fallback failed at version ${esmFallbackVersion}: ' + formatDependencyError(e2), e2);
5280
}
5381
}
5482
window.generateUuid = () => crypto.randomUUID();
@@ -61,17 +89,39 @@ function getDependencyScripts(esmVersion: string, esmFallbackVersion: string, da
6189
window.dispatchEvent(new Event('deps-ready'));
6290
};
6391
script.onerror = (e) => {
64-
window.parent.postMessage({
65-
type: 'dashboard-error-boundary',
66-
message: 'Failed to load dashboard-ui-components IIFE bundle',
67-
}, '*');
92+
const message = '[sandbox] Failed to load local dashboard-ui-components IIFE bundle. Run pnpm --filter @stackframe/dashboard-ui-components dev or pnpm --filter @stackframe/dashboard-ui-components build so apps/dashboard/public/dashboard-ui-components.iife.js exists.';
93+
failDependencyLoad(message, e instanceof Error ? e : new Error(message));
6894
};
6995
document.head.appendChild(script);
7096
</script>`;
7197
}
7298

7399
return html`
74100
<script type="module">
101+
const CUSTOM_DASHBOARD_LOAD_ERROR_MESSAGE = 'There was a problem loading custom dashboards. Please refresh the page and try again.';
102+
103+
function formatDependencyError(error) {
104+
return error instanceof Error ? error.message : String(error);
105+
}
106+
107+
function reportDependencyError(message, error) {
108+
window.parent.postMessage({
109+
type: 'dashboard-sandbox-dependency-error',
110+
message,
111+
stack: error instanceof Error ? error.stack : undefined,
112+
}, '*');
113+
}
114+
115+
function failDependencyLoad(message, error) {
116+
reportDependencyError(message, error);
117+
window.__depsError = {
118+
message: CUSTOM_DASHBOARD_LOAD_ERROR_MESSAGE,
119+
stack: error instanceof Error ? error.stack : undefined,
120+
};
121+
window.__depsReady = true;
122+
window.dispatchEvent(new Event('deps-ready'));
123+
}
124+
75125
import React from 'https://esm.sh/react@19.2.3';
76126
import * as ReactDOM from 'https://esm.sh/react-dom@19.2.3?deps=react@19.2.3';
77127
import * as ReactDOMClient from 'https://esm.sh/react-dom@19.2.3/client?deps=react@19.2.3';
@@ -89,21 +139,27 @@ function getDependencyScripts(esmVersion: string, esmFallbackVersion: string, da
89139
import('https://esm.sh/@stackframe/js@${esmVersion}'),
90140
]);
91141
} catch (e) {
92-
window.parent.postMessage({ type: 'dashboard-error-boundary', message: '[sandbox] Failed to load at version ${esmVersion}, trying fallback ${esmFallbackVersion}: ' + e?.message }, '*');
93-
[DashboardUIComponents, StackSDK] = await Promise.all([
94-
import('https://esm.sh/@stackframe/dashboard-ui-components@${esmFallbackVersion}?deps=react@19.2.3,react-dom@19.2.3'),
95-
import('https://esm.sh/@stackframe/js@${esmFallbackVersion}'),
96-
]);
142+
reportDependencyError('[sandbox] Custom dashboard packages failed at version ${esmVersion}; trying fallback ${esmFallbackVersion}: ' + formatDependencyError(e), e);
143+
try {
144+
[DashboardUIComponents, StackSDK] = await Promise.all([
145+
import('https://esm.sh/@stackframe/dashboard-ui-components@${esmFallbackVersion}?deps=react@19.2.3,react-dom@19.2.3'),
146+
import('https://esm.sh/@stackframe/js@${esmFallbackVersion}'),
147+
]);
148+
} catch (e2) {
149+
failDependencyLoad('[sandbox] Custom dashboard package fallback failed at version ${esmFallbackVersion}: ' + formatDependencyError(e2), e2);
150+
}
97151
}
98152
99-
window.DashboardUI = DashboardUIComponents;
100-
window.StackAdminApp = StackSDK.StackAdminApp;
101-
window.StackServerApp = StackSDK.StackServerApp;
102-
window.StackSDK = StackSDK;
103-
window.generateUuid = () => crypto.randomUUID();
153+
if (!window.__depsError) {
154+
window.DashboardUI = DashboardUIComponents;
155+
window.StackAdminApp = StackSDK.StackAdminApp;
156+
window.StackServerApp = StackSDK.StackServerApp;
157+
window.StackSDK = StackSDK;
158+
window.generateUuid = () => crypto.randomUUID();
104159
105-
window.__depsReady = true;
106-
window.dispatchEvent(new Event('deps-ready'));
160+
window.__depsReady = true;
161+
window.dispatchEvent(new Event('deps-ready'));
162+
}
107163
</script>`;
108164
}
109165

@@ -118,7 +174,7 @@ function getSandboxDocument(artifact: DashboardArtifact, baseUrl: string, dashbo
118174
const sourceCode = escapeScriptContent(artifact.runtimeCodegen.uiRuntimeSourceCode);
119175
const darkClass = initialTheme === "dark" ? "dark" : "";
120176
const esmVersion = packageJson.version;
121-
const esmFallbackVersion = "2.8.71";
177+
const esmFallbackVersion = getEsmFallbackVersion(esmVersion);
122178
const devScriptSrc = isDev ? ` ${dashboardUrl}` : '';
123179
const devConnectSrc = isDev ? ` ${dashboardUrl}` : '';
124180

@@ -307,10 +363,18 @@ function getSandboxDocument(artifact: DashboardArtifact, baseUrl: string, dashbo
307363
};
308364
309365
async function waitForDeps() {
310-
if (window.__depsReady) return;
311-
await new Promise(resolve => {
312-
window.addEventListener('deps-ready', resolve, { once: true });
313-
});
366+
if (!window.__depsReady) {
367+
await new Promise(resolve => {
368+
window.addEventListener('deps-ready', resolve, { once: true });
369+
});
370+
}
371+
if (window.__depsError) {
372+
const error = new Error(window.__depsError.message || 'There was a problem loading custom dashboards. Please refresh the page and try again.');
373+
if (window.__depsError.stack) {
374+
error.stack = window.__depsError.stack;
375+
}
376+
throw error;
377+
}
314378
}
315379
316380
async function requestAccessToken() {
@@ -735,6 +799,13 @@ export const DashboardSandboxHost = memo(function DashboardSandboxHost({
735799
return;
736800
}
737801

802+
if (type === "dashboard-sandbox-dependency-error") {
803+
const err = new Error(event.data.message ?? 'Unknown custom dashboard dependency error');
804+
if (event.data.stack) err.stack = event.data.stack;
805+
captureError('dashboard-sandbox-dependency-error', err);
806+
return;
807+
}
808+
738809
if (type === "dashboard-error-boundary") {
739810
const err = new Error(event.data.message ?? 'Unknown dashboard error');
740811
if (event.data.stack) err.stack = event.data.stack;

0 commit comments

Comments
 (0)