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

Commita94fead

Browse files
feat(site): allow starting task workspace from task page
1 parent6d39077 commita94fead

File tree

2 files changed

+170
-26
lines changed

2 files changed

+170
-26
lines changed

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

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,19 @@ import {
1111
MockWorkspaceResource,
1212
mockApiError,
1313
}from"testHelpers/entities";
14-
import{withProxyProvider,withWebSocket}from"testHelpers/storybook";
14+
import{
15+
withGlobalSnackbar,
16+
withProxyProvider,
17+
withWebSocket,
18+
}from"testHelpers/storybook";
1519
importtype{Meta,StoryObj}from"@storybook/react-vite";
20+
import{API}from"api/api";
1621
importtype{
1722
Workspace,
1823
WorkspaceApp,
1924
WorkspaceResource,
2025
}from"api/typesGenerated";
21-
import{expect,spyOn,within}from"storybook/test";
26+
import{expect,spyOn,userEvent,waitFor,within}from"storybook/test";
2227
importTaskPage,{data,WorkspaceDoesNotHaveAITaskError}from"./TaskPage";
2328

2429
constmeta:Meta<typeofTaskPage>={
@@ -351,3 +356,74 @@ export const ActivePreview: Story = {
351356
});
352357
},
353358
};
359+
360+
exportconstWorkspaceStartFailure:Story={
361+
decorators:[withGlobalSnackbar],
362+
beforeEach:()=>{
363+
spyOn(data,"fetchTask").mockResolvedValue({
364+
prompt:"Create competitors page",
365+
workspace:MockStoppedWorkspace,
366+
});
367+
368+
spyOn(API,"getWorkspaceParameters").mockResolvedValue({
369+
templateVersionRichParameters:[],
370+
buildParameters:[],
371+
});
372+
373+
spyOn(API,"startWorkspace").mockRejectedValue(
374+
mockApiError({
375+
message:"Failed to start workspace",
376+
detail:"Insufficient resources available. Please try again later.",
377+
}),
378+
);
379+
},
380+
play:async({ canvasElement})=>{
381+
constcanvas=within(canvasElement);
382+
383+
conststartButton=awaitcanvas.findByText("Start workspace");
384+
expect(startButton).toBeInTheDocument();
385+
386+
awaituserEvent.click(startButton);
387+
388+
awaitwaitFor(async()=>{
389+
consterrorMessage=awaitcanvas.findByText("Failed to start workspace");
390+
expect(errorMessage).toBeInTheDocument();
391+
});
392+
},
393+
};
394+
395+
exportconstWorkspaceStartFailureWithDialog:Story={
396+
beforeEach:()=>{
397+
spyOn(data,"fetchTask").mockResolvedValue({
398+
prompt:"Create competitors page",
399+
workspace:MockStoppedWorkspace,
400+
});
401+
402+
spyOn(API,"getWorkspaceParameters").mockResolvedValue({
403+
templateVersionRichParameters:[],
404+
buildParameters:[],
405+
});
406+
407+
spyOn(API,"startWorkspace").mockRejectedValue({
408+
...mockApiError({
409+
message:"Bad Request",
410+
detail:"Invalid build parameters provided",
411+
}),
412+
code:"ERR_BAD_REQUEST",
413+
});
414+
},
415+
play:async({ canvasElement})=>{
416+
constcanvas=within(canvasElement);
417+
418+
conststartButton=awaitcanvas.findByText("Start workspace");
419+
expect(startButton).toBeInTheDocument();
420+
421+
awaituserEvent.click(startButton);
422+
423+
awaitwaitFor(async()=>{
424+
constbody=within(canvasElement.ownerDocument.body);
425+
constdialogTitle=awaitbody.findByText("Error building workspace");
426+
expect(dialogTitle).toBeInTheDocument();
427+
});
428+
},
429+
};

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

Lines changed: 92 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
import{API}from"api/api";
2-
import{getErrorDetail,getErrorMessage}from"api/errors";
2+
import{
3+
typeApiError,
4+
getErrorDetail,
5+
getErrorMessage,
6+
isApiError,
7+
}from"api/errors";
38
import{templateastemplateQueryOptions}from"api/queries/templates";
9+
import{startWorkspace}from"api/queries/workspaces";
410
importtype{
511
Workspace,
612
WorkspaceAgent,
713
WorkspaceStatus,
814
}from"api/typesGenerated";
915
importisChromaticfrom"chromatic/isChromatic";
1016
import{Button}from"components/Button/Button";
17+
import{displayError}from"components/GlobalSnackbar/utils";
1118
import{Loader}from"components/Loader/Loader";
1219
import{Margins}from"components/Margins/Margins";
1320
import{ScrollArea}from"components/ScrollArea/ScrollArea";
@@ -16,10 +23,17 @@ import { ArrowLeftIcon, RotateCcwIcon } from "lucide-react";
1623
import{AgentLogs}from"modules/resources/AgentLogs/AgentLogs";
1724
import{useAgentLogs}from"modules/resources/useAgentLogs";
1825
import{AI_PROMPT_PARAMETER_NAME,typeTask}from"modules/tasks/tasks";
26+
import{WorkspaceErrorDialog}from"modules/workspaces/ErrorDialog/WorkspaceErrorDialog";
1927
import{WorkspaceBuildLogs}from"modules/workspaces/WorkspaceBuildLogs/WorkspaceBuildLogs";
20-
import{typeFC,typeReactNode,useLayoutEffect,useRef}from"react";
28+
import{
29+
typeFC,
30+
typeReactNode,
31+
useLayoutEffect,
32+
useRef,
33+
useState,
34+
}from"react";
2135
import{Helmet}from"react-helmet-async";
22-
import{useQuery}from"react-query";
36+
import{useMutation,useQuery,useQueryClient}from"react-query";
2337
import{Panel,PanelGroup,PanelResizeHandle}from"react-resizable-panels";
2438
import{LinkasRouterLink,useParams}from"react-router";
2539
importtype{FixedSizeList}from"react-window";
@@ -119,27 +133,7 @@ const TaskPage = () => {
119133
</div>
120134
);
121135
}elseif(task.workspace.latest_build.status!=="running"){
122-
content=(
123-
<Margins>
124-
<divclassName="w-full min-h-80 flex items-center justify-center">
125-
<divclassName="flex flex-col items-center">
126-
<h3className="m-0 font-medium text-content-primary text-base">
127-
Workspace is not running
128-
</h3>
129-
<spanclassName="text-content-secondary text-sm">
130-
Apps and previous statuses are not available
131-
</span>
132-
<Buttonsize="sm"className="mt-4"asChild>
133-
<RouterLink
134-
to={`/@${task.workspace.owner_name}/${task.workspace.name}`}
135-
>
136-
View workspace
137-
</RouterLink>
138-
</Button>
139-
</div>
140-
</div>
141-
</Margins>
142-
);
136+
content=<WorkspaceNotRunningtask={task}/>;
143137
}elseif(agent&&["created","starting"].includes(agent.lifecycle_state)){
144138
content=<TaskStartingAgentagent={agent}/>;
145139
}else{
@@ -174,6 +168,80 @@ const TaskPage = () => {
174168

175169
exportdefaultTaskPage;
176170

171+
typeWorkspaceNotRunningProps={
172+
task:Task;
173+
};
174+
175+
constWorkspaceNotRunning:FC<WorkspaceNotRunningProps>=({ task})=>{
176+
constqueryClient=useQueryClient();
177+
178+
const{data:parameters}=useQuery({
179+
queryKey:["workspace",task.workspace.id,"parameters"],
180+
queryFn:()=>API.getWorkspaceParameters(task.workspace),
181+
});
182+
183+
const[workspaceErrorDialog,setWorkspaceErrorDialog]=useState<{
184+
open:boolean;
185+
error?:ApiError;
186+
}>({open:false});
187+
188+
consthandleError=(error:unknown)=>{
189+
if(isApiError(error)&&error.code==="ERR_BAD_REQUEST"){
190+
setWorkspaceErrorDialog({
191+
open:true,
192+
error:error,
193+
});
194+
}else{
195+
displayError(getErrorMessage(error,"Failed to build workspace."));
196+
}
197+
};
198+
199+
constmutateStartWorkspace=useMutation({
200+
...startWorkspace(task?.workspace,queryClient),
201+
onError:(error:unknown)=>{
202+
handleError(error);
203+
},
204+
});
205+
206+
return(
207+
<Margins>
208+
<divclassName="w-full min-h-80 flex items-center justify-center">
209+
<divclassName="flex flex-col items-center">
210+
<h3className="m-0 font-medium text-content-primary text-base">
211+
Workspace is not running
212+
</h3>
213+
<spanclassName="text-content-secondary text-sm">
214+
Apps and previous statuses are not available
215+
</span>
216+
<divclassName="flex flex-row mt-4 gap-4">
217+
<Button
218+
size="sm"
219+
onClick={()=>{
220+
mutateStartWorkspace.mutate({
221+
buildParameters:parameters?.buildParameters,
222+
});
223+
}}
224+
>
225+
Start workspace
226+
</Button>
227+
</div>
228+
</div>
229+
</div>
230+
231+
<WorkspaceErrorDialog
232+
open={workspaceErrorDialog.open}
233+
error={workspaceErrorDialog.error}
234+
onClose={()=>setWorkspaceErrorDialog({open:false})}
235+
showDetail={task.workspace.template_use_classic_parameter_flow}
236+
workspaceOwner={task.workspace.owner_name}
237+
workspaceName={task.workspace.name}
238+
templateVersionId={task.workspace.latest_build.template_version_id}
239+
isDeleting={false}
240+
/>
241+
</Margins>
242+
);
243+
};
244+
177245
typeTaskBuildingWorkspaceProps={task:Task};
178246

179247
constTaskBuildingWorkspace:FC<TaskBuildingWorkspaceProps>=({ task})=>{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp