From 411e444f638ba87efa1f2234b6a25395f445bbb4 Mon Sep 17 00:00:00 2001 From: Samuel K Date: Thu, 24 Sep 2026 08:50:13 -0600 Subject: [PATCH] fix(desktop): simplify compact workspace status rendering --- .../workspace/WorkspaceOperation.svelte | 61 +++++++++++-------- .../workspace/WorkspaceOperation.test.ts | 56 ++++++++++++++--- .../renderer/src/pages/WorkspacesPage.svelte | 2 +- .../stop-and-delete-a-workspace.mdx | 6 +- 4 files changed, 85 insertions(+), 40 deletions(-) diff --git a/desktop/src/renderer/src/lib/components/workspace/WorkspaceOperation.svelte b/desktop/src/renderer/src/lib/components/workspace/WorkspaceOperation.svelte index 1844a9c21..56ea119f7 100644 --- a/desktop/src/renderer/src/lib/components/workspace/WorkspaceOperation.svelte +++ b/desktop/src/renderer/src/lib/components/workspace/WorkspaceOperation.svelte @@ -52,37 +52,44 @@ const badgeVariant = $derived( ) -
+
{#if view.busy} - - {#if view.error} - {view.error}{#if density === "expanded"}{" · "}{/if} - {:else if view.recovery} - ⚠ {view.recovery.message}{#if density === "expanded" && view.recovery.canRetry}{" · "}{/if} - {:else if view.phase} - {view.phase} - {:else} - - {/if} - + aria-label="View logs for {id}" + onclick={viewLogs}>View logs + {:else if view.recovery} + ⚠ {view.recovery.message}{#if view.recovery.canRetry}{" · "}{/if} + {:else if view.phase} + {view.phase} + {/if} + + {/if}
diff --git a/desktop/src/renderer/src/lib/components/workspace/WorkspaceOperation.test.ts b/desktop/src/renderer/src/lib/components/workspace/WorkspaceOperation.test.ts index 5e0e4b84c..d680393b2 100644 --- a/desktop/src/renderer/src/lib/components/workspace/WorkspaceOperation.test.ts +++ b/desktop/src/renderer/src/lib/components/workspace/WorkspaceOperation.test.ts @@ -23,12 +23,20 @@ beforeEach(() => { vi.clearAllMocks() }) describe("WorkspaceOperation", () => { - it("shows the observed lifecycle with the phase line reserved", () => { - const ui = render(WorkspaceOperation, { id: "ws", status: "Running" }) + it("renders compact lifecycle status as a single-line badge", () => { + const ui = render(WorkspaceOperation, { + id: "ws", + status: "Running", + density: "compact", + }) expect(ui.getByText("Running")).toBeTruthy() const region = ui.getByRole("status") expect(region.getAttribute("aria-busy")).toBe("false") - expect(region.querySelector('[aria-hidden="true"]')).toBeTruthy() + expect(region.querySelector('[aria-hidden="true"]')).toBeNull() + expect( + region.querySelector('[data-slot="workspace-operation-detail"]'), + ).toBeNull() + expect(region.classList.contains("min-h-10")).toBe(false) }) it("keeps the active command ahead of a stale runtime observation", () => { workspaceJobs.set({ @@ -39,12 +47,16 @@ describe("WorkspaceOperation", () => { phase: "closing_connections", }, }) - const ui = render(WorkspaceOperation, { id: "ws", status: "Running" }) + const ui = render(WorkspaceOperation, { + id: "ws", + status: "Running", + density: "compact", + }) expect(ui.getByText("Deleting")).toBeTruthy() - expect(ui.getByText("Closing connections")).toBeTruthy() + expect(ui.queryByText("Closing connections")).toBeNull() expect(ui.queryByText("Running")).toBeNull() }) - it("says Confirming removal while a delete awaits confirmation, never Deleted", () => { + it("shows the delete headline without confirmation details in compact density", () => { workspaceJobs.set({ ws: { commandId: "delete", @@ -53,12 +65,36 @@ describe("WorkspaceOperation", () => { phase: "Refreshing list", }, }) - const ui = render(WorkspaceOperation, { id: "ws", status: "Running" }) + const ui = render(WorkspaceOperation, { + id: "ws", + status: "Running", + density: "compact", + }) expect(ui.getByText("Deleting")).toBeTruthy() - expect(ui.getByText("Confirming removal")).toBeTruthy() + expect(ui.queryByText("Confirming removal")).toBeNull() expect(ui.queryByText("Deleted")).toBeNull() expect(ui.getByRole("status").getAttribute("aria-busy")).toBe("true") }) + it("retains the operation phase in expanded density", () => { + workspaceJobs.set({ + ws: { + commandId: "delete", + activity: "deleting", + state: "reconciling", + phase: "Refreshing list", + }, + }) + const ui = render(WorkspaceOperation, { + id: "ws", + status: "Running", + density: "expanded", + }) + expect(ui.getByText("Deleting")).toBeTruthy() + expect(ui.getByText("Confirming removal")).toBeTruthy() + expect( + ui.getByRole("status").querySelector('[data-slot="workspace-operation-detail"]'), + ).toBeTruthy() + }) it("shows recovery wording with an expanded Retry that only re-refreshes", async () => { workspaceJobs.set({ ws: { @@ -128,6 +164,7 @@ describe("WorkspaceOperation", () => { }) const ui = render(WorkspaceOperation, { id: "ws", status: "Running" }) expect(ui.getByText("Stop failed")).toBeTruthy() + expect(ui.queryByText(/provider unavailable/)).toBeNull() expect(ui.queryByRole("button", { name: "View logs for ws" })).toBeNull() }) @@ -143,7 +180,8 @@ describe("WorkspaceOperation", () => { }) const ui = render(WorkspaceOperation, { id: "ws", status: "Running" }) - expect(ui.getByText(/List may be out of date/)).toBeTruthy() + expect(ui.getByText("Deleting")).toBeTruthy() + expect(ui.queryByText(/List may be out of date/)).toBeNull() expect(ui.queryByRole("button", { name: "Retry status for ws" })).toBeNull() }) diff --git a/desktop/src/renderer/src/pages/WorkspacesPage.svelte b/desktop/src/renderer/src/pages/WorkspacesPage.svelte index 8d19c12f8..3ddede6d3 100644 --- a/desktop/src/renderer/src/pages/WorkspacesPage.svelte +++ b/desktop/src/renderer/src/pages/WorkspacesPage.svelte @@ -212,7 +212,7 @@ async function handleDelete() { {/if} - + {timeAgo(ws.lastUsed)} diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/stop-and-delete-a-workspace.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/stop-and-delete-a-workspace.mdx index ff0c4d2b1..904ad8729 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/stop-and-delete-a-workspace.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/stop-and-delete-a-workspace.mdx @@ -12,7 +12,7 @@ Devsy will automatically determine what specific action to take when a workspace ### Devsy Desktop -In the 'Workspaces' view, open the actions menu for a running workspace and choose 'Stop'. The workspace immediately shows **Stopping** and its current step, including closing connections before the stop command begins. Once stopped, the menu will show a 'Start' option to resume the workspace. +In the 'Workspaces' view, open the actions menu for a running workspace and choose 'Stop'. The workspace immediately shows a **Stopping** status badge. Once stopped, the menu will show a 'Start' option to resume the workspace. Detailed operation progress remains available on the workspace detail surface. ### Devsy CLI @@ -40,9 +40,9 @@ Devsy will automatically determine what specific action to take when a workspace ### Devsy Desktop -In the 'Workspaces' view, open the actions menu for the workspace and choose 'Delete', then confirm the deletion dialog. The workspace immediately shows **Deleting** and its current step. The row disappears after deletion finishes and the workspace list confirms removal. +In the 'Workspaces' view, open the actions menu for the workspace and choose 'Delete', then confirm the deletion dialog. The workspace immediately shows a **Deleting** status badge. The row disappears after deletion finishes and the workspace list confirms removal. Detailed operation progress, errors, and refresh recovery controls remain available on the workspace detail surface. -Progress for desktop actions stays available when you navigate between pages or reload the window. If the action fails, its error remains visible and you can open the workspace logs for details. If the action finishes but refreshing its status fails, use **Retry refresh**; this refreshes the observation without repeating the action. A **Deleted** label with **Refreshing list** means deletion completed and the list is still catching up. +Progress for desktop actions stays available when you navigate between pages or reload the window. If the action fails, its error remains visible on the workspace detail surface and you can open the workspace logs for details. If the action finishes but refreshing its status fails, use **Retry refresh** there; this refreshes the observation without repeating the action. Live action progress covers commands initiated by the desktop. Commands launched in a separate terminal are reflected by periodic status refreshes. Progress recovery after fully quitting and restarting the desktop is not supported.