Content-Length: 8407 | pFad | http://github.com/coder/coder/pull/18984.patch

thub.com From 75a456289275c33907048b990039b66bd46a3708 Mon Sep 17 00:00:00 2001 From: "blink-so[bot]" <211532188+blink-so[bot]@users.noreply.github.com> Date: Tue, 22 Jul 2025 00:29:50 +0000 Subject: [PATCH] feat: add visual distinction for workspaces with running startup scripts - Add helper function hasStartingAgents to check agent lifecycle states - Update getDisplayWorkspaceStatus to show 'Running (Starting...)' when agents are still starting - Enhance WorkspaceStatusIndicator with tooltips for starting workspaces - Add comprehensive tests for the new functionality --- .../WorkspaceStatusIndicator.tsx | 51 +++++--- site/src/utils/workspace.test.ts | 123 ++++++++++++++++++ site/src/utils/workspace.tsx | 20 ++- 3 files changed, 173 insertions(+), 21 deletions(-) diff --git a/site/src/modules/workspaces/WorkspaceStatusIndicator/WorkspaceStatusIndicator.tsx b/site/src/modules/workspaces/WorkspaceStatusIndicator/WorkspaceStatusIndicator.tsx index 972096314e1ee..f017b8325b6c0 100644 --- a/site/src/modules/workspaces/WorkspaceStatusIndicator/WorkspaceStatusIndicator.tsx +++ b/site/src/modules/workspaces/WorkspaceStatusIndicator/WorkspaceStatusIndicator.tsx @@ -41,12 +41,24 @@ export const WorkspaceStatusIndicator: FC = ({ let { text, type } = getDisplayWorkspaceStatus( workspace.latest_build.status, workspace.latest_build.job, + workspace, ); if (!workspace.health.healthy) { type = "warning"; } + // Check if workspace is running but agents are still starting + const isStarting = + workspace.latest_build.status === "running" && + workspace.latest_build.resources.some((resource) => + resource.agents?.some( + (agent) => + agent.lifecycle_state === "starting" || + agent.lifecycle_state === "created", + ), + ); + const statusIndicator = ( @@ -55,24 +67,27 @@ export const WorkspaceStatusIndicator: FC = ({ ); - if (workspace.health.healthy) { - return statusIndicator; + // Show tooltip for unhealthy or starting workspaces + if (!workspace.health.healthy || isStarting) { + const tooltipMessage = !workspace.health.healthy + ? "Your workspace is running but some agents are unhealthy." + : "Your workspace is running but startup scripts are still executing."; + + return ( + + + + + + Workspace status: {text} + {children} + + + {tooltipMessage} + + + ); } - return ( - - - - - - Workspace status: {text} - {children} - - - - Your workspace is running but some agents are unhealthy. - - - - ); + return statusIndicator; }; diff --git a/site/src/utils/workspace.test.ts b/site/src/utils/workspace.test.ts index 4e6f4b287fe0e..a3ba68060831f 100644 --- a/site/src/utils/workspace.test.ts +++ b/site/src/utils/workspace.test.ts @@ -7,6 +7,8 @@ import { getDisplayVersionStatus, getDisplayWorkspaceBuildInitiatedBy, getDisplayWorkspaceTemplateName, + getDisplayWorkspaceStatus, + hasStartingAgents, isWorkspaceOn, } from "./workspace"; @@ -157,4 +159,125 @@ describe("util > workspace", () => { expect(displayed).toEqual(workspace.template_display_name); }); }); + + describe("hasStartingAgents", () => { + it("returns true when agents are starting", () => { + const workspace: TypesGen.Workspace = { + ...Mocks.MockWorkspace, + latest_build: { + ...Mocks.MockWorkspaceBuild, + resources: [ + { + ...Mocks.MockWorkspaceResource, + agents: [ + { + ...Mocks.MockWorkspaceAgent, + lifecycle_state: "starting", + }, + ], + }, + ], + }, + }; + expect(hasStartingAgents(workspace)).toBe(true); + }); + + it("returns true when agents are created", () => { + const workspace: TypesGen.Workspace = { + ...Mocks.MockWorkspace, + latest_build: { + ...Mocks.MockWorkspaceBuild, + resources: [ + { + ...Mocks.MockWorkspaceResource, + agents: [ + { + ...Mocks.MockWorkspaceAgent, + lifecycle_state: "created", + }, + ], + }, + ], + }, + }; + expect(hasStartingAgents(workspace)).toBe(true); + }); + + it("returns false when all agents are ready", () => { + const workspace: TypesGen.Workspace = { + ...Mocks.MockWorkspace, + latest_build: { + ...Mocks.MockWorkspaceBuild, + resources: [ + { + ...Mocks.MockWorkspaceResource, + agents: [ + { + ...Mocks.MockWorkspaceAgent, + lifecycle_state: "ready", + }, + ], + }, + ], + }, + }; + expect(hasStartingAgents(workspace)).toBe(false); + }); + }); + + describe("getDisplayWorkspaceStatus with starting agents", () => { + it("shows 'Running (Starting...)' when workspace is running with starting agents", () => { + const workspace: TypesGen.Workspace = { + ...Mocks.MockWorkspace, + latest_build: { + ...Mocks.MockWorkspaceBuild, + status: "running", + resources: [ + { + ...Mocks.MockWorkspaceResource, + agents: [ + { + ...Mocks.MockWorkspaceAgent, + lifecycle_state: "starting", + }, + ], + }, + ], + }, + }; + const status = getDisplayWorkspaceStatus("running", undefined, workspace); + expect(status.text).toBe("Running (Starting...)"); + expect(status.type).toBe("active"); + }); + + it("shows 'Running' when workspace is running with all agents ready", () => { + const workspace: TypesGen.Workspace = { + ...Mocks.MockWorkspace, + latest_build: { + ...Mocks.MockWorkspaceBuild, + status: "running", + resources: [ + { + ...Mocks.MockWorkspaceResource, + agents: [ + { + ...Mocks.MockWorkspaceAgent, + lifecycle_state: "ready", + }, + ], + }, + ], + }, + }; + const status = getDisplayWorkspaceStatus("running", undefined, workspace); + expect(status.text).toBe("Running"); + expect(status.type).toBe("success"); + }); + + it("shows 'Running' when workspace parameter is not provided", () => { + const status = getDisplayWorkspaceStatus("running", undefined); + expect(status.text).toBe("Running"); + expect(status.type).toBe("success"); + }); + }); }); diff --git a/site/src/utils/workspace.tsx b/site/src/utils/workspace.tsx index c88ffc9d8edaa..0866cf98fb735 100644 --- a/site/src/utils/workspace.tsx +++ b/site/src/utils/workspace.tsx @@ -182,9 +182,21 @@ type DisplayWorkspaceStatus = { icon: React.ReactNode; }; +// Helper function to check if any agents are still starting +export const hasStartingAgents = (workspace: TypesGen.Workspace): boolean => { + return workspace.latest_build.resources.some((resource) => + resource.agents?.some( + (agent) => + agent.lifecycle_state === "starting" || + agent.lifecycle_state === "created", + ), + ); +}; + export const getDisplayWorkspaceStatus = ( workspaceStatus: TypesGen.WorkspaceStatus, provisionerJob?: TypesGen.ProvisionerJob, + workspace?: TypesGen.Workspace, ): DisplayWorkspaceStatus => { switch (workspaceStatus) { case undefined: @@ -194,10 +206,12 @@ export const getDisplayWorkspaceStatus = ( icon: , } as const; case "running": + // Check if workspace has agents that are still starting + const isStarting = workspace && hasStartingAgents(workspace); return { - type: "success", - text: "Running", - icon: , + type: isStarting ? "active" : "success", + text: isStarting ? "Running (Starting...)" : "Running", + icon: isStarting ? : , } as const; case "starting": return {








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/coder/coder/pull/18984.patch

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy