From f9045a983a160398e7cd56855064f1d8d1c4c21e Mon Sep 17 00:00:00 2001 From: Asher Date: Mon, 23 Jun 2025 18:55:33 -0800 Subject: [PATCH 1/7] feat: add workspace build status to task page --- site/src/pages/TaskPage/TaskPage.stories.tsx | 12 +++++++ site/src/pages/TaskPage/TaskPage.tsx | 36 ++++++++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/site/src/pages/TaskPage/TaskPage.stories.tsx b/site/src/pages/TaskPage/TaskPage.stories.tsx index a24968d483e38..03f8cfe739d89 100644 --- a/site/src/pages/TaskPage/TaskPage.stories.tsx +++ b/site/src/pages/TaskPage/TaskPage.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react"; import { expect, spyOn, within } from "@storybook/test"; +import { API } from "api/api"; import type { Workspace, WorkspaceApp, @@ -9,6 +10,7 @@ import { MockFailedWorkspace, MockStartingWorkspace, MockStoppedWorkspace, + MockTemplate, MockWorkspace, MockWorkspaceAgent, MockWorkspaceApp, @@ -59,6 +61,16 @@ export const WaitingOnBuild: Story = { }, }; +export const WaitingOnBuildWithTemplate: Story = { + beforeEach: () => { + spyOn(API, "getTemplate").mockResolvedValue(MockTemplate); + spyOn(data, "fetchTask").mockResolvedValue({ + prompt: "Create competitors page", + workspace: MockStartingWorkspace, + }); + }, +}; + export const WaitingOnStatus: Story = { beforeEach: () => { spyOn(data, "fetchTask").mockResolvedValue({ diff --git a/site/src/pages/TaskPage/TaskPage.tsx b/site/src/pages/TaskPage/TaskPage.tsx index a46e0f09c7cc9..bb2d8baa0e0ae 100644 --- a/site/src/pages/TaskPage/TaskPage.tsx +++ b/site/src/pages/TaskPage/TaskPage.tsx @@ -1,10 +1,12 @@ import { API } from "api/api"; import { getErrorDetail, getErrorMessage } from "api/errors"; +import { template as templateQueryOptions } from "api/queries/templates"; import type { Workspace, WorkspaceStatus } from "api/typesGenerated"; import { Button } from "components/Button/Button"; import { Loader } from "components/Loader/Loader"; import { Margins } from "components/Margins/Margins"; import { Spinner } from "components/Spinner/Spinner"; +import { useWorkspaceBuildLogs } from "hooks/useWorkspaceBuildLogs"; import { ArrowLeftIcon, RotateCcwIcon } from "lucide-react"; import { AI_PROMPT_PARAMETER_NAME, type Task } from "modules/tasks/tasks"; import type { ReactNode } from "react"; @@ -14,6 +16,10 @@ import { useParams } from "react-router-dom"; import { Link as RouterLink } from "react-router-dom"; import { ellipsizeText } from "utils/ellipsizeText"; import { pageTitle } from "utils/page"; +import { + ActiveTransition, + WorkspaceBuildProgress, +} from "../WorkspacePage/WorkspaceBuildProgress"; import { TaskApps } from "./TaskApps"; import { TaskSidebar } from "./TaskSidebar"; @@ -32,6 +38,19 @@ const TaskPage = () => { refetchInterval: 5_000, }); + const { data: template } = useQuery({ + ...templateQueryOptions(task?.workspace.template_id ?? ""), + enabled: Boolean(task), + }); + + const waitingStatuses: WorkspaceStatus[] = ["starting", "pending"]; + const shouldStreamBuildLogs = + task && waitingStatuses.includes(task.workspace.latest_build.status); + const buildLogs = useWorkspaceBuildLogs( + task?.workspace.latest_build.id ?? "", + shouldStreamBuildLogs, + ); + if (error) { return ( <> @@ -77,7 +96,6 @@ const TaskPage = () => { } let content: ReactNode = null; - const waitingStatuses: WorkspaceStatus[] = ["starting", "pending"]; const terminatedStatuses: WorkspaceStatus[] = [ "canceled", "canceling", @@ -88,10 +106,13 @@ const TaskPage = () => { ]; if (waitingStatuses.includes(task.workspace.latest_build.status)) { + // If no template yet, use an indeterminate progress bar. + const transition = (template && + ActiveTransition(template, task.workspace)) || { P50: 0, P95: null }; + const lastStage = buildLogs?.[buildLogs.length - 1]?.stage; content = ( -
+
-

Starting your workspace

@@ -99,6 +120,15 @@ const TaskPage = () => { This should take a few minutes
+ {lastStage && ( +
{lastStage}
+ )} +
+ +
); } else if (task.workspace.latest_build.status === "failed") { From 1a59d0bdc85f871a4c896702b0c7ea8be1503493 Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 24 Jun 2025 11:07:09 -0800 Subject: [PATCH 2/7] Remove redundant starting text --- site/src/pages/TaskPage/TaskPage.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/site/src/pages/TaskPage/TaskPage.tsx b/site/src/pages/TaskPage/TaskPage.tsx index bb2d8baa0e0ae..4d390dfa42e54 100644 --- a/site/src/pages/TaskPage/TaskPage.tsx +++ b/site/src/pages/TaskPage/TaskPage.tsx @@ -116,9 +116,6 @@ const TaskPage = () => {

Starting your workspace

- - This should take a few minutes -
{lastStage && (
{lastStage}
From a5a511ee853e71330b931320166e4cf72d9d620f Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 24 Jun 2025 11:22:39 -0800 Subject: [PATCH 3/7] Stack progress text on tasks --- site/src/pages/TaskPage/TaskPage.tsx | 1 + .../src/pages/WorkspacePage/WorkspaceBuildProgress.tsx | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/site/src/pages/TaskPage/TaskPage.tsx b/site/src/pages/TaskPage/TaskPage.tsx index 4d390dfa42e54..b586985d30bb6 100644 --- a/site/src/pages/TaskPage/TaskPage.tsx +++ b/site/src/pages/TaskPage/TaskPage.tsx @@ -124,6 +124,7 @@ const TaskPage = () => { diff --git a/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx b/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx index 715ceb136c262..d31dbcd46fed6 100644 --- a/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx @@ -62,11 +62,14 @@ const estimateFinish = ( interface WorkspaceBuildProgressProps { workspace: Workspace; transitionStats: TransitionStats; + // stack indicates to stack the text vertically, otherwise put it on one line. + stack?: boolean; } export const WorkspaceBuildProgress: FC = ({ workspace, transitionStats, + stack, }) => { const job = workspace.latest_build.job; const [progressValue, setProgressValue] = useState(0); @@ -131,7 +134,7 @@ export const WorkspaceBuildProgress: FC = ({ // is not indicative of true progress. classes={{ bar: classNames.bar }} /> -
+
{capitalize(workspace.latest_build.status)} workspace...
@@ -154,11 +157,6 @@ const styles = { paddingLeft: 2, paddingRight: 2, }, - barHelpers: { - display: "flex", - justifyContent: "space-between", - marginTop: 4, - }, label: (theme) => ({ fontSize: 12, display: "block", From d0bc61d35c22735d9c121b2e1f5675868ed1e039 Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 24 Jun 2025 11:32:12 -0800 Subject: [PATCH 4/7] Move progress to bottom And remove the duplicate "Starting workspace..." text. --- site/src/pages/TaskPage/TaskPage.tsx | 17 ++++----- .../WorkspacePage/WorkspaceBuildProgress.tsx | 36 +++++++++++++------ 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/site/src/pages/TaskPage/TaskPage.tsx b/site/src/pages/TaskPage/TaskPage.tsx index b586985d30bb6..6c7191d0bf9a0 100644 --- a/site/src/pages/TaskPage/TaskPage.tsx +++ b/site/src/pages/TaskPage/TaskPage.tsx @@ -109,22 +109,23 @@ const TaskPage = () => { // If no template yet, use an indeterminate progress bar. const transition = (template && ActiveTransition(template, task.workspace)) || { P50: 0, P95: null }; - const lastStage = buildLogs?.[buildLogs.length - 1]?.stage; + const lastStage = + buildLogs?.[buildLogs.length - 1]?.stage || "Waiting for build status"; content = ( -
-
+
+

Starting your workspace

+ {lastStage && ( +
{lastStage}
+ )}
- {lastStage && ( -
{lastStage}
- )} -
+
diff --git a/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx b/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx index d31dbcd46fed6..98ccd2978e63c 100644 --- a/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx @@ -62,14 +62,13 @@ const estimateFinish = ( interface WorkspaceBuildProgressProps { workspace: Workspace; transitionStats: TransitionStats; - // stack indicates to stack the text vertically, otherwise put it on one line. - stack?: boolean; + style?: "workspace" | "task"; } export const WorkspaceBuildProgress: FC = ({ workspace, transitionStats, - stack, + style, }) => { const job = workspace.latest_build.job; const [progressValue, setProgressValue] = useState(0); @@ -117,6 +116,13 @@ export const WorkspaceBuildProgress: FC = ({ } return (
+ {style === "task" && ( +
+
+ {progressText} +
+
+ )} = ({ // If a transition is set, there is a moment on new load where the // bar accelerates to progressValue and then rapidly decelerates, which // is not indicative of true progress. - classes={{ bar: classNames.bar }} + classes={{ + bar: classNames.bar, + root: style === "task" ? classNames.root : undefined, + }} /> -
-
- {capitalize(workspace.latest_build.status)} workspace... -
-
- {progressText} + {style !== "task" && ( +
+
+ {capitalize(workspace.latest_build.status)} workspace... +
+
+ {progressText} +
-
+ )}
); }; @@ -149,6 +160,9 @@ export const WorkspaceBuildProgress: FC = ({ const classNames = { bar: css` transition: none; + `, + root: css` + border-radius: 0; `, }; From c16557a28f9b022cc258b66647a4c2bd2c8853ef Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 24 Jun 2025 12:59:36 -0800 Subject: [PATCH 5/7] Omit useless braces --- site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx b/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx index 98ccd2978e63c..9b406c2e5fca3 100644 --- a/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx @@ -117,7 +117,7 @@ export const WorkspaceBuildProgress: FC = ({ return (
{style === "task" && ( -
+
{progressText}
@@ -144,7 +144,7 @@ export const WorkspaceBuildProgress: FC = ({ }} /> {style !== "task" && ( -
+
{capitalize(workspace.latest_build.status)} workspace...
From 77e3034fbf7b20b14436a7e1fcb32549743f2d26 Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 24 Jun 2025 13:03:46 -0800 Subject: [PATCH 6/7] Rename style to variant --- site/src/pages/TaskPage/TaskPage.tsx | 2 +- .../WorkspacePage/WorkspaceBuildProgress.tsx | 23 ++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/site/src/pages/TaskPage/TaskPage.tsx b/site/src/pages/TaskPage/TaskPage.tsx index 6c7191d0bf9a0..b56e69827846d 100644 --- a/site/src/pages/TaskPage/TaskPage.tsx +++ b/site/src/pages/TaskPage/TaskPage.tsx @@ -125,7 +125,7 @@ const TaskPage = () => {
diff --git a/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx b/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx index 9b406c2e5fca3..306da719be0ca 100644 --- a/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx @@ -62,13 +62,18 @@ const estimateFinish = ( interface WorkspaceBuildProgressProps { workspace: Workspace; transitionStats: TransitionStats; - style?: "workspace" | "task"; + // variant changes how the progress bar is displayed: with the workspace + // variant the workspace transition and time remaining are displayed under the + // bar aligned to the left and right respectively. With the task variant the + // workspace transition is not displayed and the time remaining is displayed + // centered above the bar, and the bar's border radius is removed. + variant?: "workspace" | "task"; } export const WorkspaceBuildProgress: FC = ({ workspace, transitionStats, - style, + variant, }) => { const job = workspace.latest_build.job; const [progressValue, setProgressValue] = useState(0); @@ -116,7 +121,7 @@ export const WorkspaceBuildProgress: FC = ({ } return (
- {style === "task" && ( + {variant === "task" && (
{progressText} @@ -135,15 +140,17 @@ export const WorkspaceBuildProgress: FC = ({ ? "determinate" : "indeterminate" } - // If a transition is set, there is a moment on new load where the - // bar accelerates to progressValue and then rapidly decelerates, which - // is not indicative of true progress. classes={{ + // If a transition is set, there is a moment on new load where the bar + // accelerates to progressValue and then rapidly decelerates, which is + // not indicative of true progress. bar: classNames.bar, - root: style === "task" ? classNames.root : undefined, + // With the "task" variant, the progress bar is fullscreen, so remove + // the border radius. + root: variant === "task" ? classNames.root : undefined, }} /> - {style !== "task" && ( + {variant !== "task" && (
{capitalize(workspace.latest_build.status)} workspace... From 20c1823496bba55a262b212b15a1f60954bf7aff Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 24 Jun 2025 13:07:47 -0800 Subject: [PATCH 7/7] Build stage var is always set now --- site/src/pages/TaskPage/TaskPage.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/site/src/pages/TaskPage/TaskPage.tsx b/site/src/pages/TaskPage/TaskPage.tsx index b56e69827846d..c340a96cfef11 100644 --- a/site/src/pages/TaskPage/TaskPage.tsx +++ b/site/src/pages/TaskPage/TaskPage.tsx @@ -117,9 +117,7 @@ const TaskPage = () => {

Starting your workspace

- {lastStage && ( -
{lastStage}
- )} +
{lastStage}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy