diff --git a/frontend/app/onboarding/onboarding-features.tsx b/frontend/app/onboarding/onboarding-features.tsx
index 595a69938d..53f89298fb 100644
--- a/frontend/app/onboarding/onboarding-features.tsx
+++ b/frontend/app/onboarding/onboarding-features.tsx
@@ -19,7 +19,7 @@ import { FakeLayout } from "./onboarding-layout";
type FeaturePageName = "waveai" | "durable" | "magnify" | "files";
-const WaveAIPage = ({ onNext, onSkip }: { onNext: () => void; onSkip: () => void }) => {
+export const WaveAIPage = ({ onNext, onSkip }: { onNext: () => void; onSkip: () => void }) => {
const isMac = isMacOS();
const shortcutKey = isMac ? "⌘-Shift-A" : "Alt-Shift-A";
const [fireClicked, setFireClicked] = useState(false);
@@ -106,7 +106,7 @@ const WaveAIPage = ({ onNext, onSkip }: { onNext: () => void; onSkip: () => void
);
};
-const MagnifyBlocksPage = ({
+export const MagnifyBlocksPage = ({
onNext,
onSkip,
onPrev,
@@ -149,13 +149,13 @@ const MagnifyBlocksPage = ({
better view.
Use the magnify feature to work with complex outputs and large files more efficiently.
-
+
You can also magnify a block by clicking on the{" "}
{" "}
icon in the block header.
-
+
A quick {shortcutKey}-M to magnify and another {shortcutKey}-M to unmagnify
@@ -172,12 +172,25 @@ const MagnifyBlocksPage = ({
);
};
-const FilesPage = ({ onFinish, onPrev }: { onFinish: () => void; onPrev?: () => void }) => {
+export const FilesPage = ({ onFinish, onPrev }: { onFinish: () => void; onPrev?: () => void }) => {
const [fireClicked, setFireClicked] = useState(false);
const isMac = isMacOS();
const [commandIndex, setCommandIndex] = useState(0);
const [key, setKey] = useState(0);
+ const commands = [
+ (onComplete: () => void) => ,
+ (onComplete: () => void) => ,
+ (onComplete: () => void) => ,
+ ];
+
+ const handleCommandComplete = () => {
+ setTimeout(() => {
+ setCommandIndex((prev) => (prev + 1) % commands.length);
+ setKey((prev) => prev + 1);
+ }, 2500);
+ };
+
const handleFireClick = () => {
setFireClicked(!fireClicked);
if (!fireClicked) {
@@ -191,19 +204,30 @@ const FilesPage = ({ onFinish, onPrev }: { onFinish: () => void; onPrev?: () =>
}
};
- const commands = [
- (onComplete: () => void) => ,
- (onComplete: () => void) => ,
- (onComplete: () => void) => ,
- ];
-
- const handleCommandComplete = () => {
- setTimeout(() => {
- setCommandIndex((prev) => (prev + 1) % commands.length);
- setKey((prev) => prev + 1);
- }, 2500);
- };
+ return (
+
+ );
+};
+export const FilesPageContent = ({
+ onFinish,
+ onPrev,
+ fireClicked,
+ onFireClick,
+ rightPanel,
+}: {
+ onFinish: () => void;
+ onPrev?: () => void;
+ fireClicked: boolean;
+ onFireClick: () => void;
+ rightPanel: React.ReactNode;
+}) => {
return (
@@ -252,14 +276,12 @@ const FilesPage = ({ onFinish, onPrev }: { onFinish: () => void; onPrev?: () =>
and edit files wherever they are.
-
+
-
- {commands[commandIndex](handleCommandComplete)}
-
+ {rightPanel}
diff --git a/frontend/app/onboarding/onboarding-upgrade-patch.tsx b/frontend/app/onboarding/onboarding-upgrade-patch.tsx
index fc2a0ee3ac..a4e09945de 100644
--- a/frontend/app/onboarding/onboarding-upgrade-patch.tsx
+++ b/frontend/app/onboarding/onboarding-upgrade-patch.tsx
@@ -29,7 +29,7 @@ interface VersionConfig {
nextText?: string;
}
-const versions: VersionConfig[] = [
+export const UpgradeOnboardingVersions: VersionConfig[] = [
{
version: "v0.12.1",
content: () => ,
@@ -69,11 +69,11 @@ const versions: VersionConfig[] = [
const UpgradeOnboardingPatch = () => {
const modalRef = useRef(null);
const [isCompact, setIsCompact] = useState(window.innerHeight < 800);
- const [currentIndex, setCurrentIndex] = useState(versions.length - 1);
+ const [currentIndex, setCurrentIndex] = useState(UpgradeOnboardingVersions.length - 1);
- const currentVersion = versions[currentIndex];
+ const currentVersion = UpgradeOnboardingVersions[currentIndex];
const hasPrev = currentIndex > 0;
- const hasNext = currentIndex < versions.length - 1;
+ const hasNext = currentIndex < UpgradeOnboardingVersions.length - 1;
const updateModalHeight = () => {
const windowHeight = window.innerHeight;
diff --git a/frontend/app/store/global.ts b/frontend/app/store/global.ts
index 2cfb5945ae..628ae03626 100644
--- a/frontend/app/store/global.ts
+++ b/frontend/app/store/global.ts
@@ -25,7 +25,9 @@ import {
isBlank,
isLocalConnName,
isWslConnName,
+ NullAtom,
} from "@/util/util";
+import { isPreviewWindow } from "./windowtype";
import { atom, Atom, PrimitiveAtom, useAtomValue } from "jotai";
import {
atoms,
@@ -168,6 +170,7 @@ function useOrefMetaKeyAtom(oref: string, key: T): Met
}
function getConnConfigKeyAtom(connName: string, key: T): Atom {
+ if (isPreviewWindow()) return NullAtom as Atom;
let connCache = getSingleConnAtomCache(connName);
const keyAtomName = "#conn-" + key;
let keyAtom = connCache.get(keyAtomName);
@@ -185,6 +188,7 @@ function getConnConfigKeyAtom(connName: string, ke
const settingsAtomCache = new Map>();
function getOverrideConfigAtom(blockId: string, key: T): Atom {
+ if (isPreviewWindow()) return NullAtom as Atom;
const blockCache = getSingleBlockAtomCache(blockId);
const overrideAtomName = "#settingsoverride-" + key;
let overrideAtom = blockCache.get(overrideAtomName);
@@ -223,6 +227,7 @@ function useOverrideConfigAtom(blockId: string | n
}
function getSettingsKeyAtom(key: T): Atom {
+ if (isPreviewWindow()) return NullAtom as Atom;
let settingsKeyAtom = settingsAtomCache.get(key) as Atom;
if (settingsKeyAtom == null) {
settingsKeyAtom = atom((get) => {
@@ -242,6 +247,7 @@ function useSettingsKeyAtom(key: T): SettingsType[
}
function getSettingsPrefixAtom(prefix: string): Atom {
+ if (isPreviewWindow()) return NullAtom as Atom;
let settingsPrefixAtom = settingsAtomCache.get(prefix + ":");
if (settingsPrefixAtom == null) {
// create a stable, closured reference to use as the deepCompareReturnPrev key
@@ -745,6 +751,7 @@ function setActiveTab(tabId: string) {
}
function recordTEvent(event: string, props?: TEventProps) {
+ if (isPreviewWindow()) return;
if (props == null) {
props = {};
}
diff --git a/frontend/preview/preview.tsx b/frontend/preview/preview.tsx
index e481ed351a..c38c9fe297 100644
--- a/frontend/preview/preview.tsx
+++ b/frontend/preview/preview.tsx
@@ -93,7 +93,7 @@ function PreviewApp() {
return (
<>
-
+
diff --git a/frontend/preview/previews/onboarding.preview.tsx b/frontend/preview/previews/onboarding.preview.tsx
new file mode 100644
index 0000000000..6ea2312d3e
--- /dev/null
+++ b/frontend/preview/previews/onboarding.preview.tsx
@@ -0,0 +1,64 @@
+// Copyright 2026, Command Line Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+import Logo from "@/app/asset/logo.svg";
+import { DurableSessionPage } from "@/app/onboarding/onboarding-durable";
+import { FilesPage, MagnifyBlocksPage, WaveAIPage } from "@/app/onboarding/onboarding-features";
+import { UpgradeOnboardingVersions } from "@/app/onboarding/onboarding-upgrade-patch";
+
+function OnboardingFeaturesV() {
+ const noop = () => {};
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+function UpgradeOnboardingPatchV() {
+ return (
+
+ {UpgradeOnboardingVersions.map((version) => (
+
+
+
+
+
{version.content()}
+
+
+ ))}
+
+ );
+}
+
+export function OnboardingPreview() {
+ return (
+
+
Onboarding features
+
+
Onboarding patch updates
+
+
+ );
+}
diff --git a/frontend/util/endpoints.ts b/frontend/util/endpoints.ts
index 849c7a9404..4c073a3afc 100644
--- a/frontend/util/endpoints.ts
+++ b/frontend/util/endpoints.ts
@@ -1,12 +1,19 @@
-// Copyright 2025, Command Line Inc.
+// Copyright 2026, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
+import { isPreviewWindow } from "@/app/store/windowtype";
import { getEnv } from "./getenv";
import { lazy } from "./util";
export const WebServerEndpointVarName = "WAVE_SERVER_WEB_ENDPOINT";
export const WSServerEndpointVarName = "WAVE_SERVER_WS_ENDPOINT";
-export const getWebServerEndpoint = lazy(() => `http://${getEnv(WebServerEndpointVarName)}`);
+export const getWebServerEndpoint = lazy(() => {
+ if (isPreviewWindow()) return null;
+ return `http://${getEnv(WebServerEndpointVarName)}`;
+});
-export const getWSServerEndpoint = lazy(() => `ws://${getEnv(WSServerEndpointVarName)}`);
+export const getWSServerEndpoint = lazy(() => {
+ if (isPreviewWindow()) return null;
+ return `ws://${getEnv(WSServerEndpointVarName)}`;
+});
diff --git a/frontend/util/util.ts b/frontend/util/util.ts
index 2eea82f82e..2e5a3b5a13 100644
--- a/frontend/util/util.ts
+++ b/frontend/util/util.ts
@@ -534,6 +534,7 @@ export {
makeExternLink,
makeIconClass,
mergeMeta,
+ NullAtom,
parseDataUrl,
sleep,
sortByDisplayOrder,