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

Commit59525f8

Browse files
feat: display startup script logs while agent is starting (#19530)
Closes#19363**Screenshot:**<img width="1318" height="753" alt="Screenshot 2025-08-25 at 11 02 25"src="https://github.com/user-attachments/assets/6fa1d4c7-dddb-4db9-a9f0-86986b3628d8"/>**Demo:**https://github.com/user-attachments/assets/07a68e30-b776-44f9-b4ca-e2dd8d124281
1 parenta1546b5 commit59525f8

File tree

3 files changed

+156
-49
lines changed

3 files changed

+156
-49
lines changed

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

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ import {
22
MockFailedWorkspace,
33
MockStartingWorkspace,
44
MockStoppedWorkspace,
5-
MockTemplate,
65
MockWorkspace,
7-
MockWorkspaceAgent,
6+
MockWorkspaceAgentLogSource,
7+
MockWorkspaceAgentReady,
8+
MockWorkspaceAgentStarting,
89
MockWorkspaceApp,
910
MockWorkspaceAppStatus,
1011
MockWorkspaceResource,
1112
mockApiError,
1213
}from"testHelpers/entities";
13-
import{withProxyProvider}from"testHelpers/storybook";
14+
import{withProxyProvider,withWebSocket}from"testHelpers/storybook";
1415
importtype{Meta,StoryObj}from"@storybook/react-vite";
15-
import{API}from"api/api";
1616
importtype{
1717
Workspace,
1818
WorkspaceApp,
@@ -61,56 +61,93 @@ export const WaitingOnBuild: Story = {
6161
},
6262
};
6363

64-
exportconstWaitingOnBuildWithTemplate:Story={
64+
exportconstFailedBuild:Story={
6565
beforeEach:()=>{
66-
spyOn(API,"getTemplate").mockResolvedValue(MockTemplate);
6766
spyOn(data,"fetchTask").mockResolvedValue({
6867
prompt:"Create competitors page",
69-
workspace:MockStartingWorkspace,
68+
workspace:MockFailedWorkspace,
7069
});
7170
},
7271
};
7372

74-
exportconstWaitingOnStatus:Story={
73+
exportconstTerminatedBuild:Story={
7574
beforeEach:()=>{
7675
spyOn(data,"fetchTask").mockResolvedValue({
7776
prompt:"Create competitors page",
78-
workspace:{
79-
...MockWorkspace,
80-
latest_app_status:null,
81-
},
77+
workspace:MockStoppedWorkspace,
8278
});
8379
},
8480
};
8581

86-
exportconstFailedBuild:Story={
82+
exportconstTerminatedBuildWithStatus:Story={
8783
beforeEach:()=>{
8884
spyOn(data,"fetchTask").mockResolvedValue({
8985
prompt:"Create competitors page",
90-
workspace:MockFailedWorkspace,
86+
workspace:{
87+
...MockStoppedWorkspace,
88+
latest_app_status:MockWorkspaceAppStatus,
89+
},
9190
});
9291
},
9392
};
9493

95-
exportconstTerminatedBuild:Story={
94+
exportconstWaitingOnStatus:Story={
9695
beforeEach:()=>{
9796
spyOn(data,"fetchTask").mockResolvedValue({
9897
prompt:"Create competitors page",
99-
workspace:MockStoppedWorkspace,
98+
workspace:{
99+
...MockWorkspace,
100+
latest_app_status:null,
101+
latest_build:{
102+
...MockWorkspace.latest_build,
103+
resources:[
104+
{ ...MockWorkspaceResource,agents:[MockWorkspaceAgentReady]},
105+
],
106+
},
107+
},
100108
});
101109
},
102110
};
103111

104-
exportconstTerminatedBuildWithStatus:Story={
112+
exportconstWaitingStartupScripts:Story={
105113
beforeEach:()=>{
106114
spyOn(data,"fetchTask").mockResolvedValue({
107115
prompt:"Create competitors page",
108116
workspace:{
109-
...MockStoppedWorkspace,
110-
latest_app_status:MockWorkspaceAppStatus,
117+
...MockWorkspace,
118+
latest_build:{
119+
...MockWorkspace.latest_build,
120+
has_ai_task:true,
121+
resources:[
122+
{ ...MockWorkspaceResource,agents:[MockWorkspaceAgentStarting]},
123+
],
124+
},
111125
},
112126
});
113127
},
128+
decorators:[withWebSocket],
129+
parameters:{
130+
webSocket:[
131+
{
132+
event:"message",
133+
data:JSON.stringify(
134+
[
135+
"\x1b[91mCloning Git repository...",
136+
"\x1b[2;37;41mStarting Docker Daemon...",
137+
"\x1b[1;95mAdding some 🧙magic🧙...",
138+
"Starting VS Code...",
139+
"\r 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\r100 1475 0 1475 0 0 4231 0 --:--:-- --:--:-- --:--:-- 4238",
140+
].map((line,index)=>({
141+
id:index,
142+
level:"info",
143+
output:line,
144+
source_id:MockWorkspaceAgentLogSource.id,
145+
created_at:newDate("2024-01-01T12:00:00Z").toISOString(),
146+
})),
147+
),
148+
},
149+
],
150+
},
114151
};
115152

116153
exportconstSidebarAppHealthDisabled:Story={
@@ -223,7 +260,7 @@ const mockResources = (
223260
...MockWorkspaceResource,
224261
agents:[
225262
{
226-
...MockWorkspaceAgent,
263+
...MockWorkspaceAgentReady,
227264
apps:[
228265
...(props?.apps??[]),
229266
{

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

Lines changed: 98 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
import{API}from"api/api";
22
import{getErrorDetail,getErrorMessage}from"api/errors";
33
import{templateastemplateQueryOptions}from"api/queries/templates";
4-
importtype{Workspace,WorkspaceStatus}from"api/typesGenerated";
4+
importtype{
5+
Workspace,
6+
WorkspaceAgent,
7+
WorkspaceStatus,
8+
}from"api/typesGenerated";
59
importisChromaticfrom"chromatic/isChromatic";
610
import{Button}from"components/Button/Button";
711
import{Loader}from"components/Loader/Loader";
812
import{Margins}from"components/Margins/Margins";
913
import{ScrollArea}from"components/ScrollArea/ScrollArea";
1014
import{useWorkspaceBuildLogs}from"hooks/useWorkspaceBuildLogs";
1115
import{ArrowLeftIcon,RotateCcwIcon}from"lucide-react";
16+
import{AgentLogs}from"modules/resources/AgentLogs/AgentLogs";
17+
import{useAgentLogs}from"modules/resources/useAgentLogs";
1218
import{AI_PROMPT_PARAMETER_NAME,typeTask}from"modules/tasks/tasks";
1319
import{WorkspaceBuildLogs}from"modules/workspaces/WorkspaceBuildLogs/WorkspaceBuildLogs";
14-
import{typeFC,typeReactNode,useEffect,useRef}from"react";
20+
import{typeFC,typeReactNode,useLayoutEffect,useRef}from"react";
1521
import{Helmet}from"react-helmet-async";
1622
import{useQuery}from"react-query";
1723
import{Panel,PanelGroup,PanelResizeHandle}from"react-resizable-panels";
1824
import{LinkasRouterLink,useParams}from"react-router";
25+
importtype{FixedSizeList}from"react-window";
1926
import{pageTitle}from"utils/page";
2027
import{
2128
getActiveTransitionStats,
@@ -87,6 +94,7 @@ const TaskPage = () => {
8794
}
8895

8996
letcontent:ReactNode=null;
97+
constagent=selectAgent(task);
9098

9199
if(waitingStatuses.includes(task.workspace.latest_build.status)){
92100
content=<TaskBuildingWorkspacetask={task}/>;
@@ -132,6 +140,8 @@ const TaskPage = () => {
132140
</div>
133141
</Margins>
134142
);
143+
}elseif(agent&&["created","starting"].includes(agent.lifecycle_state)){
144+
content=<TaskStartingAgentagent={agent}/>;
135145
}else{
136146
content=(
137147
<PanelGroupautoSaveId="task"direction="horizontal">
@@ -182,7 +192,7 @@ const TaskBuildingWorkspace: FC<TaskBuildingWorkspaceProps> = ({ task }) => {
182192

183193
constscrollAreaRef=useRef<HTMLDivElement>(null);
184194
// biome-ignore lint/correctness/useExhaustiveDependencies: this effect should run when build logs change
185-
useEffect(()=>{
195+
useLayoutEffect(()=>{
186196
if(isChromatic()){
187197
return;
188198
}
@@ -196,34 +206,86 @@ const TaskBuildingWorkspace: FC<TaskBuildingWorkspaceProps> = ({ task }) => {
196206
},[buildLogs]);
197207

198208
return(
199-
<sectionclassName="w-full h-full flex justify-center items-center p-6 overflow-y-auto">
200-
<divclassName="flex flex-col gap-6 items-center w-full">
201-
<headerclassName="flex flex-col items-center text-center">
202-
<h3className="m-0 font-medium text-content-primary text-xl">
203-
Starting your workspace
204-
</h3>
205-
<divclassName="text-content-secondary">
206-
Your task will be running in a few moments
209+
<sectionclassName="p-16 overflow-y-auto">
210+
<divclassName="flex justify-center items-center w-full">
211+
<divclassName="flex flex-col gap-6 items-center w-full">
212+
<headerclassName="flex flex-col items-center text-center">
213+
<h3className="m-0 font-medium text-content-primary text-xl">
214+
Starting your workspace
215+
</h3>
216+
<pclassName="text-content-secondary m-0">
217+
Your task will be running in a few moments
218+
</p>
219+
</header>
220+
221+
<divclassName="w-full max-w-screen-lg flex flex-col gap-4 overflow-hidden">
222+
<WorkspaceBuildProgress
223+
workspace={task.workspace}
224+
transitionStats={transitionStats}
225+
variant="task"
226+
/>
227+
228+
<ScrollArea
229+
ref={scrollAreaRef}
230+
className="h-96 border border-solid border-border rounded-lg"
231+
>
232+
<WorkspaceBuildLogs
233+
sticky
234+
className="border-0 rounded-none"
235+
logs={buildLogs??[]}
236+
/>
237+
</ScrollArea>
207238
</div>
208-
</header>
239+
</div>
240+
</div>
241+
</section>
242+
);
243+
};
244+
245+
typeTaskStartingAgentProps={
246+
agent:WorkspaceAgent;
247+
};
209248

210-
<divclassName="w-full max-w-screen-lg flex flex-col gap-4 overflow-hidden">
211-
<WorkspaceBuildProgress
212-
workspace={task.workspace}
213-
transitionStats={transitionStats}
214-
variant="task"
215-
/>
249+
constTaskStartingAgent:FC<TaskStartingAgentProps>=({ agent})=>{
250+
constlogs=useAgentLogs(agent,true);
251+
constlistRef=useRef<FixedSizeList>(null);
216252

217-
<ScrollArea
218-
ref={scrollAreaRef}
219-
className="h-96 border border-solid border-border rounded-lg"
220-
>
221-
<WorkspaceBuildLogs
222-
sticky
223-
className="border-0 rounded-none"
224-
logs={buildLogs??[]}
225-
/>
226-
</ScrollArea>
253+
useLayoutEffect(()=>{
254+
if(listRef.current){
255+
listRef.current.scrollToItem(logs.length-1,"end");
256+
}
257+
},[logs]);
258+
259+
return(
260+
<sectionclassName="p-16 overflow-y-auto">
261+
<divclassName="flex justify-center items-center w-full">
262+
<divclassName="flex flex-col gap-8 items-center w-full">
263+
<headerclassName="flex flex-col items-center text-center">
264+
<h3className="m-0 font-medium text-content-primary text-xl">
265+
Running startup scripts
266+
</h3>
267+
<pclassName="text-content-secondary m-0">
268+
Your task will be running in a few moments
269+
</p>
270+
</header>
271+
272+
<divclassName="w-full max-w-screen-lg flex flex-col gap-4 overflow-hidden">
273+
<divclassName="h-96 border border-solid border-border rounded-lg">
274+
<AgentLogs
275+
logs={logs.map((l)=>({
276+
id:l.id,
277+
level:l.level,
278+
output:l.output,
279+
sourceId:l.source_id,
280+
time:l.created_at,
281+
}))}
282+
sources={agent.log_sources}
283+
height={96*4}
284+
width="100%"
285+
ref={listRef}
286+
/>
287+
</div>
288+
</div>
227289
</div>
228290
</div>
229291
</section>
@@ -265,3 +327,11 @@ export const data = {
265327
}satisfiesTask;
266328
},
267329
};
330+
331+
functionselectAgent(task:Task){
332+
constagents=task.workspace.latest_build.resources
333+
.flatMap((r)=>r.agents)
334+
.filter((a)=>!!a);
335+
336+
returnagents.at(0);
337+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type TaskTopbarProps = { task: Task };
2222

2323
exportconstTaskTopbar:FC<TaskTopbarProps>=({ task})=>{
2424
return(
25-
<headerclassName="flex items-center px-3 py-4 border-solid border-border border-0 border-b">
25+
<headerclassName="flexflex-shrink-0items-center px-3 py-4 border-solid border-border border-0 border-b">
2626
<TooltipProvider>
2727
<Tooltip>
2828
<TooltipTriggerasChild>

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp