Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit288ec77

Browse files
authored
feat: add workspace build status to task page (#18520)
While a workspace is starting, display the build status and a progress bar.
1 parenta8e2c75 commit288ec77

File tree

3 files changed

+81
-23
lines changed

3 files changed

+81
-23
lines changed

‎site/src/pages/TaskPage/TaskPage.stories.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
importtype{Meta,StoryObj}from"@storybook/react";
22
import{expect,spyOn,within}from"@storybook/test";
3+
import{API}from"api/api";
34
importtype{
45
Workspace,
56
WorkspaceApp,
@@ -9,6 +10,7 @@ import {
910
MockFailedWorkspace,
1011
MockStartingWorkspace,
1112
MockStoppedWorkspace,
13+
MockTemplate,
1214
MockWorkspace,
1315
MockWorkspaceAgent,
1416
MockWorkspaceApp,
@@ -59,6 +61,16 @@ export const WaitingOnBuild: Story = {
5961
},
6062
};
6163

64+
exportconstWaitingOnBuildWithTemplate:Story={
65+
beforeEach:()=>{
66+
spyOn(API,"getTemplate").mockResolvedValue(MockTemplate);
67+
spyOn(data,"fetchTask").mockResolvedValue({
68+
prompt:"Create competitors page",
69+
workspace:MockStartingWorkspace,
70+
});
71+
},
72+
};
73+
6274
exportconstWaitingOnStatus:Story={
6375
beforeEach:()=>{
6476
spyOn(data,"fetchTask").mockResolvedValue({

‎site/src/pages/TaskPage/TaskPage.tsx

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import{API}from"api/api";
22
import{getErrorDetail,getErrorMessage}from"api/errors";
3+
import{templateastemplateQueryOptions}from"api/queries/templates";
34
importtype{Workspace,WorkspaceStatus}from"api/typesGenerated";
45
import{Button}from"components/Button/Button";
56
import{Loader}from"components/Loader/Loader";
67
import{Margins}from"components/Margins/Margins";
78
import{Spinner}from"components/Spinner/Spinner";
9+
import{useWorkspaceBuildLogs}from"hooks/useWorkspaceBuildLogs";
810
import{ArrowLeftIcon,RotateCcwIcon}from"lucide-react";
911
import{AI_PROMPT_PARAMETER_NAME,typeTask}from"modules/tasks/tasks";
1012
importtype{ReactNode}from"react";
@@ -14,6 +16,10 @@ import { useParams } from "react-router-dom";
1416
import{LinkasRouterLink}from"react-router-dom";
1517
import{ellipsizeText}from"utils/ellipsizeText";
1618
import{pageTitle}from"utils/page";
19+
import{
20+
ActiveTransition,
21+
WorkspaceBuildProgress,
22+
}from"../WorkspacePage/WorkspaceBuildProgress";
1723
import{TaskApps}from"./TaskApps";
1824
import{TaskSidebar}from"./TaskSidebar";
1925

@@ -32,6 +38,19 @@ const TaskPage = () => {
3238
refetchInterval:5_000,
3339
});
3440

41+
const{data:template}=useQuery({
42+
...templateQueryOptions(task?.workspace.template_id??""),
43+
enabled:Boolean(task),
44+
});
45+
46+
constwaitingStatuses:WorkspaceStatus[]=["starting","pending"];
47+
constshouldStreamBuildLogs=
48+
task&&waitingStatuses.includes(task.workspace.latest_build.status);
49+
constbuildLogs=useWorkspaceBuildLogs(
50+
task?.workspace.latest_build.id??"",
51+
shouldStreamBuildLogs,
52+
);
53+
3554
if(error){
3655
return(
3756
<>
@@ -77,7 +96,6 @@ const TaskPage = () => {
7796
}
7897

7998
letcontent:ReactNode=null;
80-
constwaitingStatuses:WorkspaceStatus[]=["starting","pending"];
8199
constterminatedStatuses:WorkspaceStatus[]=[
82100
"canceled",
83101
"canceling",
@@ -88,16 +106,25 @@ const TaskPage = () => {
88106
];
89107

90108
if(waitingStatuses.includes(task.workspace.latest_build.status)){
109+
// If no template yet, use an indeterminate progress bar.
110+
consttransition=(template&&
111+
ActiveTransition(template,task.workspace))||{P50:0,P95:null};
112+
constlastStage=
113+
buildLogs?.[buildLogs.length-1]?.stage||"Waiting for build status";
91114
content=(
92-
<divclassName="w-full min-h-80 flex items-center justify-center">
93-
<divclassName="flex flex-col items-center">
94-
<SpinnerloadingclassName="mb-4"/>
115+
<divclassName="w-full min-h-80 flex flex-col">
116+
<divclassName="flex flex-col items-center grow justify-center">
95117
<h3className="m-0 font-medium text-content-primary text-base">
96118
Starting your workspace
97119
</h3>
98-
<spanclassName="text-content-secondary text-sm">
99-
This should take a few minutes
100-
</span>
120+
<divclassName="text-content-secondary text-sm">{lastStage}</div>
121+
</div>
122+
<divclassName="w-full">
123+
<WorkspaceBuildProgress
124+
workspace={task.workspace}
125+
transitionStats={transition}
126+
variant="task"
127+
/>
101128
</div>
102129
</div>
103130
);

‎site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,18 @@ const estimateFinish = (
6262
interfaceWorkspaceBuildProgressProps{
6363
workspace:Workspace;
6464
transitionStats:TransitionStats;
65+
// variant changes how the progress bar is displayed: with the workspace
66+
// variant the workspace transition and time remaining are displayed under the
67+
// bar aligned to the left and right respectively. With the task variant the
68+
// workspace transition is not displayed and the time remaining is displayed
69+
// centered above the bar, and the bar's border radius is removed.
70+
variant?:"workspace"|"task";
6571
}
6672

6773
exportconstWorkspaceBuildProgress:FC<WorkspaceBuildProgressProps>=({
6874
workspace,
6975
transitionStats,
76+
variant,
7077
})=>{
7178
constjob=workspace.latest_build.job;
7279
const[progressValue,setProgressValue]=useState<number|undefined>(0);
@@ -114,6 +121,13 @@ export const WorkspaceBuildProgress: FC<WorkspaceBuildProgressProps> = ({
114121
}
115122
return(
116123
<divcss={styles.stack}>
124+
{variant==="task"&&(
125+
<divclassName="mb-1 text-center">
126+
<divcss={styles.label}data-chromatic="ignore">
127+
{progressText}
128+
</div>
129+
</div>
130+
)}
117131
<LinearProgress
118132
data-chromatic="ignore"
119133
value={progressValue!==undefined ?progressValue :0}
@@ -126,26 +140,36 @@ export const WorkspaceBuildProgress: FC<WorkspaceBuildProgressProps> = ({
126140
?"determinate"
127141
:"indeterminate"
128142
}
129-
// If a transition is set, there is a moment on new load where the
130-
// bar accelerates to progressValue and then rapidly decelerates, which
131-
// is not indicative of true progress.
132-
classes={{bar:classNames.bar}}
143+
classes={{
144+
// If a transition is set, there is a moment on new load where the bar
145+
// accelerates to progressValue and then rapidly decelerates, which is
146+
// not indicative of true progress.
147+
bar:classNames.bar,
148+
// With the "task" variant, the progress bar is fullscreen, so remove
149+
// the border radius.
150+
root:variant==="task" ?classNames.root :undefined,
151+
}}
133152
/>
134-
<divcss={styles.barHelpers}>
135-
<divcss={styles.label}>
136-
{capitalize(workspace.latest_build.status)} workspace...
137-
</div>
138-
<divcss={styles.label}data-chromatic="ignore">
139-
{progressText}
153+
{variant!=="task"&&(
154+
<divclassName="flex mt-1 justify-between">
155+
<divcss={styles.label}>
156+
{capitalize(workspace.latest_build.status)} workspace...
157+
</div>
158+
<divcss={styles.label}data-chromatic="ignore">
159+
{progressText}
160+
</div>
140161
</div>
141-
</div>
162+
)}
142163
</div>
143164
);
144165
};
145166

146167
constclassNames={
147168
bar:css`
148169
transition: none;
170+
`,
171+
root:css`
172+
border-radius:0;
149173
`,
150174
};
151175

@@ -154,11 +178,6 @@ const styles = {
154178
paddingLeft:2,
155179
paddingRight:2,
156180
},
157-
barHelpers:{
158-
display:"flex",
159-
justifyContent:"space-between",
160-
marginTop:4,
161-
},
162181
label:(theme)=>({
163182
fontSize:12,
164183
display:"block",

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp