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 {
--- 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