From 425cae479bae3518eb5f080d17ab9d1ab29c7637 Mon Sep 17 00:00:00 2001 From: AviPeltz Date: Mon, 12 Jan 2026 14:00:13 -0800 Subject: [PATCH 1/2] fix (desktop): flash rerender --- .../react-query/workspaces/useCreateWorkspace.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts b/apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts index 42070b42cb0..2960d11f05a 100644 --- a/apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts +++ b/apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts @@ -1,3 +1,4 @@ +import type { WorkspaceInitProgress } from "shared/types/workspace-init"; import { trpc } from "renderer/lib/trpc"; import { useWorkspaceInitStore } from "renderer/stores/workspace-init"; @@ -22,10 +23,24 @@ export function useCreateWorkspace( const addPendingTerminalSetup = useWorkspaceInitStore( (s) => s.addPendingTerminalSetup, ); + const updateProgress = useWorkspaceInitStore((s) => s.updateProgress); return trpc.workspaces.create.useMutation({ ...options, onSuccess: async (data, ...rest) => { + // Optimistically set init progress BEFORE query invalidation to prevent + // the "interrupted" state flash. The subscription will update with real + // progress, but this ensures isInitializing is true immediately. + if (data.isInitializing) { + const optimisticProgress: WorkspaceInitProgress = { + workspaceId: data.workspace.id, + projectId: data.projectId, + step: "pending", + message: "Preparing...", + }; + updateProgress(optimisticProgress); + } + // Auto-invalidate all workspace queries await utils.workspaces.invalidate(); From 6bda2c84187df58e1c075ca46d2105a2c828977f Mon Sep 17 00:00:00 2001 From: AviPeltz Date: Mon, 12 Jan 2026 15:37:56 -0800 Subject: [PATCH 2/2] lint fix --- .../workspaces/useCreateWorkspace.ts | 2 +- .../WorkspaceInitializingView.tsx | 27 +++++++++++++------ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts b/apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts index 2960d11f05a..a9da12d19d7 100644 --- a/apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts +++ b/apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts @@ -1,6 +1,6 @@ -import type { WorkspaceInitProgress } from "shared/types/workspace-init"; import { trpc } from "renderer/lib/trpc"; import { useWorkspaceInitStore } from "renderer/stores/workspace-init"; +import type { WorkspaceInitProgress } from "shared/types/workspace-init"; /** * Mutation hook for creating a new workspace diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceInitializingView/WorkspaceInitializingView.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceInitializingView/WorkspaceInitializingView.tsx index 3140858c253..703d24edc6c 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceInitializingView/WorkspaceInitializingView.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceInitializingView/WorkspaceInitializingView.tsx @@ -8,7 +8,7 @@ import { } from "@superset/ui/alert-dialog"; import { Button } from "@superset/ui/button"; import { cn } from "@superset/ui/utils"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { HiExclamationTriangle } from "react-icons/hi2"; import { LuCheck, LuCircle, LuGitBranch, LuLoader } from "react-icons/lu"; import { trpc } from "renderer/lib/trpc"; @@ -44,6 +44,17 @@ export function WorkspaceInitializingView({ const hasFailed = useHasWorkspaceFailed(workspaceId); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); + // Delay showing the interrupted UI to avoid flash during normal creation. + // If progress arrives within 500ms, we never show the interrupted state. + const [showInterruptedUI, setShowInterruptedUI] = useState(false); + useEffect(() => { + if (isInterrupted && !progress) { + const timer = setTimeout(() => setShowInterruptedUI(true), 500); + return () => clearTimeout(timer); + } + setShowInterruptedUI(false); + }, [isInterrupted, progress]); + const retryMutation = trpc.workspaces.retryInit.useMutation(); const deleteMutation = trpc.workspaces.delete.useMutation(); const utils = trpc.useUtils(); @@ -74,25 +85,25 @@ export function WorkspaceInitializingView({ const currentStep = progress?.step ?? "pending"; // Interrupted state (app restart during init - no in-memory progress) - if (isInterrupted && !progress) { + // Only show after delay to avoid flash during normal creation + if (isInterrupted && !progress && showInterruptedUI) { return ( <>
- {/* Warning icon */} -
- + {/* Icon */} +
+
{/* Title and description */}

- Setup was interrupted + Setup incomplete

{workspaceName}

- The app was closed before workspace setup completed. You can - retry the setup or delete this workspace. + Workspace setup didn't finish. You can retry or remove it.