Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6d1a9ea
Add onboarding flow, workflow improvements, and plugin UI updates
leszko Mar 24, 2026
ade3233
fix: add missing mythical-creature thumbnail + onError fallback
Mar 24, 2026
fa9f391
fix: allow disconnecting cloud even when isSignedIn state is stale
Mar 24, 2026
93da875
feat: onboarding survey screens, simple workflows, post-onboarding to…
hthillman Mar 24, 2026
377dbef
fix: default workflow picker to teaching style when no style is set
hthillman Mar 25, 2026
ab3c423
fix: resolve onboarding review issues
leszko Mar 25, 2026
9afca88
fix: use configurable base dir for onboarding file path
leszko Mar 25, 2026
06daca0
refactor: remove dead onboarding code and simplify
leszko Mar 25, 2026
367c3f1
style: fix Prettier formatting in 10 frontend files
leszko Mar 25, 2026
37c02d8
refactor: deduplicate FogOfWarBackground between app and frontend
leszko Mar 25, 2026
ffc9ebe
fix: remove hardcoded /tmp/ paths from starter workflow LoRA nodes
hthillman Mar 25, 2026
b2d1043
feat: swap workflows, rename, add starter chip + workflows tab section
hthillman Mar 25, 2026
1899ac5
fix: resolve dual React instance crash in Electron app
leszko Mar 26, 2026
fbd992d
fix: connect record node to last pipeline in starter workflows
leszko Mar 26, 2026
d1c2606
feat: local-mode workflow, back button, Windows fog-of-war fix
hthillman Mar 26, 2026
f500f48
fix: survey back navigation + Camera Preview as 4th local workflow
hthillman Mar 26, 2026
14dabcd
fix: wider grid for 4 workflows, swap camera check workflow, camera icon
hthillman Mar 26, 2026
b41a5d3
fix: move survey back button to upper-left corner for consistency
hthillman Mar 26, 2026
2511205
feat: filter onboarding workflows by GPU availability
leszko Mar 27, 2026
7bd153b
feat: toolbar enhancements and onboarding tour fixes
gioelecerati Mar 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' http://localhost:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:*; font-src 'self' data:; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; upgrade-insecure-requests;" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https:; connect-src 'self' http://localhost:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:*; font-src 'self' data: https://fonts.gstatic.com; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; upgrade-insecure-requests;" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="./src/index.css" />
<title>Daydream Scope</title>
</head>
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class ErrorBoundary extends Component<Props, State> {
height: '100vh',
background: 'hsl(0, 0%, 6%)',
color: 'hsl(0, 0%, 90%)',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
fontFamily: 'Manrope, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
padding: '20px',
textAlign: 'center',
}}>
Expand Down
29 changes: 13 additions & 16 deletions app/src/components/ServerLoading.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,20 @@
import React, { useEffect, useState } from 'react';
import FogOfWarBackground from '@shared/onboarding/FogOfWarBackground';

interface ServerLoadingProps {
onComplete: () => void;
onError: (error: string) => void;
}

declare global {
interface Window {
scope: {
onServerStatus: (callback: (isRunning: boolean) => void) => void;
onServerError: (callback: (error: string) => void) => void;
getServerStatus: () => Promise<{ isRunning: boolean }>;
};
}
}

const ServerLoading: React.FC<ServerLoadingProps> = ({ onComplete, onError }) => {
const [serverRunning, setServerRunning] = useState(false);
const [error, setError] = useState<string | null>(null);

useEffect(() => {
const scope = window.scope;

// Query the current server status on mount
if (scope?.getServerStatus) {
scope.getServerStatus().then((result: { isRunning: boolean }) => {
if (result.isRunning) {
setServerRunning(true);
onComplete();
}
});
Expand All @@ -35,7 +23,6 @@ const ServerLoading: React.FC<ServerLoadingProps> = ({ onComplete, onError }) =>
if (scope?.onServerStatus) {
scope.onServerStatus((isRunning: boolean) => {
if (isRunning) {
setServerRunning(true);
onComplete();
}
});
Expand All @@ -59,13 +46,18 @@ const ServerLoading: React.FC<ServerLoadingProps> = ({ onComplete, onError }) =>
flexDirection: 'column',
background: 'hsl(0, 0%, 6%)',
color: 'hsl(0, 0%, 90%)',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
fontFamily: 'Manrope, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
overflow: 'hidden',
position: 'relative',
}}>
<FogOfWarBackground />
<div style={{ position: 'absolute', inset: 0, zIndex: 1, backdropFilter: 'blur(48px)', pointerEvents: 'none' }} />
<div style={{
textAlign: 'center',
maxWidth: 600,
padding: '0 24px',
position: 'relative',
zIndex: 10,
}}>
<h1 style={{
marginBottom: 48,
Expand Down Expand Up @@ -112,13 +104,18 @@ const ServerLoading: React.FC<ServerLoadingProps> = ({ onComplete, onError }) =>
flexDirection: 'column',
background: 'hsl(0, 0%, 6%)',
color: 'hsl(0, 0%, 90%)',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
fontFamily: 'Manrope, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
overflow: 'hidden',
position: 'relative',
}}>
<FogOfWarBackground />
<div style={{ position: 'absolute', inset: 0, zIndex: 1, backdropFilter: 'blur(48px)', pointerEvents: 'none' }} />
<div style={{
textAlign: 'center',
maxWidth: 600,
padding: '0 24px',
position: 'relative',
zIndex: 10,
}}>
<h1 style={{
marginBottom: 48,
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/Setup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const Setup: React.FC<SetupProps> = ({ onComplete }) => {
flexDirection: 'column',
background: 'hsl(0, 0%, 6%)',
color: 'hsl(0, 0%, 90%)',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
fontFamily: 'Manrope, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
overflow: 'hidden',
}}>
<div style={{
Expand Down
2 changes: 1 addition & 1 deletion app/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ html, body {
}

body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
font-family: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
margin: 0;
Expand Down
6 changes: 3 additions & 3 deletions app/src/renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ const App = () => {
height: '100vh',
background: 'hsl(0, 0%, 6%)',
color: 'hsl(0, 0%, 90%)',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
fontFamily: 'Manrope, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
overflow: 'hidden',
}}>
<div style={{
Expand Down Expand Up @@ -183,7 +183,7 @@ const App = () => {
height: '100vh',
background: 'hsl(0, 0%, 6%)',
color: 'hsl(0, 0%, 90%)',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
fontFamily: 'Manrope, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
overflow: 'hidden',
}}>
<div style={{
Expand Down Expand Up @@ -221,7 +221,7 @@ const App = () => {
height: '100vh',
background: 'hsl(0, 0%, 6%)',
color: 'hsl(0, 0%, 90%)',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
fontFamily: 'Manrope, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
overflow: 'hidden',
}}>
<div style={{
Expand Down
7 changes: 6 additions & 1 deletion app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@shared/*": ["../frontend/src/components/*"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
Expand Down
4 changes: 4 additions & 0 deletions app/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@shared': path.resolve(__dirname, '../frontend/src/components'),
// Force shared components to use the app's React to avoid dual-instance hook errors
react: path.resolve(__dirname, 'node_modules/react'),
'react-dom': path.resolve(__dirname, 'node_modules/react-dom'),
},
},
});
4 changes: 4 additions & 0 deletions app/vite.renderer.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@shared': path.resolve(__dirname, '../frontend/src/components'),
// Force shared components to use the app's React to avoid dual-instance hook errors
react: path.resolve(__dirname, 'node_modules/react'),
'react-dom': path.resolve(__dirname, 'node_modules/react-dom'),
},
},
});
15 changes: 14 additions & 1 deletion e2e/tests/cloud-streaming.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,23 @@ test.describe("Cloud Streaming", () => {
// Increase timeout for this test
test.setTimeout(180000); // 3 minutes

// Mock the onboarding status API to skip onboarding in e2e tests
await page.route("**/api/v1/onboarding/status", async (route) => {
if (route.request().method() === "GET") {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ completed: true, inference_mode: null }),
});
} else {
await route.fulfill({ status: 200, body: "{}" });
}
});

// Navigate to the app (running at localhost:8000)
await page.goto("/");
await expect(
page.locator("h1", { hasText: "Daydream Scope" })
page.getByRole("heading", { name: "Daydream Scope", exact: true })
).toBeVisible({ timeout: 15000 });

// Take screenshot after initial load — app loads directly into the streaming interface
Expand Down
Binary file added frontend/public/assets/onboarding/blobme.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/assets/onboarding/pixel-art.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { PluginsProvider } from "./contexts/PluginsContext";
import { ServerInfoProvider } from "./contexts/ServerInfoContext";
import { CloudProvider } from "./lib/cloudContext";
import { CloudStatusProvider } from "./hooks/useCloudStatus";
import { OnboardingProvider } from "./contexts/OnboardingContext";
import {
handleOAuthCallback,
initElectronAuthListener,
Expand Down Expand Up @@ -109,7 +110,9 @@ function App() {
<PluginsProvider>
<ServerInfoProvider>
<CloudProvider wsUrl={CLOUD_WS_URL} apiKey={CLOUD_KEY}>
<StreamPage />
<OnboardingProvider>
<StreamPage />
</OnboardingProvider>
</CloudProvider>
</ServerInfoProvider>
</PluginsProvider>
Expand Down
64 changes: 54 additions & 10 deletions frontend/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,15 @@ interface HeaderProps {
// External settings tab control
openSettingsTab?: string | null;
onSettingsTabOpened?: () => void;
// External plugins tab control (e.g. from starter workflows chip)
openPluginsTab?: string | null;
onPluginsTabOpened?: () => void;
// Graph mode toggle
graphMode?: boolean;
onGraphModeToggle?: () => void;
// Workflow loading from Workflows tab
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onLoadWorkflow?: (workflowData: Record<string, any>) => void;
}

export function Header({
Expand All @@ -31,15 +37,21 @@ export function Header({
cloudDisabled,
openSettingsTab,
onSettingsTabOpened,
openPluginsTab,
onPluginsTabOpened,
graphMode = false,
onGraphModeToggle,
onLoadWorkflow,
}: HeaderProps) {
const [settingsOpen, setSettingsOpen] = useState(false);
const [pluginsOpen, setPluginsOpen] = useState(false);
const [initialTab, setInitialTab] = useState<
"general" | "account" | "api-keys" | "loras" | "osc"
>("general");
const [initialPluginPath, setInitialPluginPath] = useState("");
const [pluginsInitialTab, setPluginsInitialTab] = useState<
string | undefined
>(undefined);

// Use shared cloud status hook - single source of truth
const { isConnected, isConnecting, lastCloseCode, lastCloseReason } =
Expand Down Expand Up @@ -117,6 +129,15 @@ export function Header({
}
}, [openSettingsTab, onSettingsTabOpened]);

// React to external requests to open a specific plugins dialog tab
useEffect(() => {
if (openPluginsTab) {
setPluginsInitialTab(openPluginsTab);
setPluginsOpen(true);
onPluginsTabOpened?.();
}
}, [openPluginsTab, onPluginsTabOpened]);

useEffect(() => {
// Handle deep link actions for plugin installation
if (window.scope?.onDeepLinkAction) {
Expand All @@ -137,6 +158,7 @@ export function Header({
const handlePluginsClose = () => {
setPluginsOpen(false);
setInitialPluginPath("");
setPluginsInitialTab(undefined);
};

return (
Expand Down Expand Up @@ -189,7 +211,7 @@ export function Header({
? "Cloud connected"
: isConnecting
? "Connecting to cloud..."
: "Enable remote inference"
: "Connect to cloud"
}
>
{isConnected ? (
Expand All @@ -204,26 +226,46 @@ export function Header({
? "Connected"
: isConnecting
? "Connecting..."
: "Enable Remote Inference"}
: "Connect to Cloud"}
</span>
</Button>
<Button
variant="ghost"
size="icon"
onClick={() => setPluginsOpen(true)}
className="hover:opacity-80 transition-opacity text-muted-foreground opacity-80 h-8 w-8"
title="Plugins"
size="sm"
onClick={() => {
setPluginsInitialTab("discover");
setPluginsOpen(true);
}}
className="hover:opacity-80 transition-opacity text-muted-foreground opacity-80 h-8 gap-1.5 px-2"
title="Nodes"
>
<Plug className="h-4 w-4" />
<span className="text-xs font-medium">Nodes</span>
</Button>
<Button
data-tour="workflows-button"
variant="ghost"
size="sm"
onClick={() => {
setPluginsInitialTab("workflows");
setPluginsOpen(true);
}}
className="hover:opacity-80 transition-opacity text-muted-foreground opacity-80 h-8 gap-1.5 px-2"
title="Workflows"
>
<Plug className="h-5 w-5" />
<Workflow className="h-4 w-4" />
<span className="text-xs font-medium">Workflows</span>
</Button>
<Button
data-tour="settings-button"
variant="ghost"
size="icon"
size="sm"
onClick={() => setSettingsOpen(true)}
className="hover:opacity-80 transition-opacity text-muted-foreground opacity-80 h-8 w-8"
className="hover:opacity-80 transition-opacity text-muted-foreground opacity-80 h-8 gap-1.5 px-2"
title="Settings"
>
<Settings className="h-5 w-5" />
<Settings className="h-4 w-4" />
<span className="text-xs font-medium">Settings</span>
</Button>
</div>
</div>
Expand All @@ -232,8 +274,10 @@ export function Header({
open={pluginsOpen}
onClose={handlePluginsClose}
initialPluginPath={initialPluginPath}
initialTab={pluginsInitialTab}
disabled={cloudDisabled || isConnecting}
cloudConnected={isConnected}
onLoadWorkflow={onLoadWorkflow}
/>

<SettingsDialog
Expand Down
Loading
Loading