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

Commitffbd583

Browse files
fix(site): fix render crash when no embedded apps are defined for task (#19215)
Fixes#19101We now gracefully handle the scenario where there are no embedded appsdefined for a task.
1 parent6ba5521 commitffbd583

File tree

2 files changed

+230
-62
lines changed

2 files changed

+230
-62
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
importtype{Meta,StoryObj}from"@storybook/react";
2+
importtype{WorkspaceApp}from"api/typesGenerated";
3+
import{
4+
MockTasks,
5+
MockWorkspace,
6+
MockWorkspaceAgent,
7+
MockWorkspaceApp,
8+
}from"testHelpers/entities";
9+
import{withProxyProvider}from"testHelpers/storybook";
10+
import{TaskApps}from"./TaskApps";
11+
12+
constmeta:Meta<typeofTaskApps>={
13+
title:"pages/TaskPage/TaskApps",
14+
component:TaskApps,
15+
decorators:[withProxyProvider()],
16+
parameters:{
17+
layout:"fullscreen",
18+
},
19+
};
20+
21+
exportdefaultmeta;
22+
typeStory=StoryObj<typeofTaskApps>;
23+
24+
constmockAgentNoApps={
25+
...MockWorkspaceAgent,
26+
apps:[],
27+
};
28+
29+
constmockExternalApp:WorkspaceApp={
30+
...MockWorkspaceApp,
31+
external:true,
32+
};
33+
34+
constmockEmbeddedApp:WorkspaceApp={
35+
...MockWorkspaceApp,
36+
external:false,
37+
};
38+
39+
consttaskWithNoApps={
40+
...MockTasks[0],
41+
workspace:{
42+
...MockWorkspace,
43+
latest_build:{
44+
...MockWorkspace.latest_build,
45+
resources:[
46+
{
47+
...MockWorkspace.latest_build.resources[0],
48+
agents:[mockAgentNoApps],
49+
},
50+
],
51+
},
52+
},
53+
};
54+
55+
exportconstNoEmbeddedApps:Story={
56+
args:{
57+
task:taskWithNoApps,
58+
},
59+
};
60+
61+
exportconstWithExternalAppsOnly:Story={
62+
args:{
63+
task:{
64+
...MockTasks[0],
65+
workspace:{
66+
...MockWorkspace,
67+
latest_build:{
68+
...MockWorkspace.latest_build,
69+
resources:[
70+
{
71+
...MockWorkspace.latest_build.resources[0],
72+
agents:[
73+
{
74+
...MockWorkspaceAgent,
75+
apps:[mockExternalApp],
76+
},
77+
],
78+
},
79+
],
80+
},
81+
},
82+
},
83+
},
84+
};
85+
86+
exportconstWithEmbeddedApps:Story={
87+
args:{
88+
task:{
89+
...MockTasks[0],
90+
workspace:{
91+
...MockWorkspace,
92+
latest_build:{
93+
...MockWorkspace.latest_build,
94+
resources:[
95+
{
96+
...MockWorkspace.latest_build.resources[0],
97+
agents:[
98+
{
99+
...MockWorkspaceAgent,
100+
apps:[mockEmbeddedApp],
101+
},
102+
],
103+
},
104+
],
105+
},
106+
},
107+
},
108+
},
109+
};
110+
111+
exportconstWithMixedApps:Story={
112+
args:{
113+
task:{
114+
...MockTasks[0],
115+
workspace:{
116+
...MockWorkspace,
117+
latest_build:{
118+
...MockWorkspace.latest_build,
119+
resources:[
120+
{
121+
...MockWorkspace.latest_build.resources[0],
122+
agents:[
123+
{
124+
...MockWorkspaceAgent,
125+
apps:[mockEmbeddedApp,mockExternalApp],
126+
},
127+
],
128+
},
129+
],
130+
},
131+
},
132+
},
133+
},
134+
};

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

Lines changed: 96 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
importtype{WorkspaceApp}from"api/typesGenerated";
1+
importtype{WorkspaceAgent,WorkspaceApp}from"api/typesGenerated";
22
import{Button}from"components/Button/Button";
33
import{
44
DropdownMenu,
@@ -8,13 +8,15 @@ import {
88
}from"components/DropdownMenu/DropdownMenu";
99
import{ExternalImage}from"components/ExternalImage/ExternalImage";
1010
import{InfoTooltip}from"components/InfoTooltip/InfoTooltip";
11+
import{Link}from"components/Link/Link";
1112
import{ChevronDownIcon,LayoutGridIcon}from"lucide-react";
1213
import{useAppLink}from"modules/apps/useAppLink";
1314
importtype{Task}from"modules/tasks/tasks";
1415
importtypeReactfrom"react";
1516
import{typeFC,useState}from"react";
1617
import{LinkasRouterLink}from"react-router-dom";
1718
import{cn}from"utils/cn";
19+
import{docs}from"utils/docs";
1820
import{TaskAppIFrame}from"./TaskAppIframe";
1921

2022
typeTaskAppsProps={
@@ -37,25 +39,9 @@ export const TaskApps: FC<TaskAppsProps> = ({ task }) => {
3739
constembeddedApps=apps.filter((app)=>!app.external);
3840
constexternalApps=apps.filter((app)=>app.external);
3941

40-
const[activeAppId,setActiveAppId]=useState<string>(()=>{
41-
constappId=embeddedApps[0]?.id;
42-
if(!appId){
43-
thrownewError("No apps found in task");
44-
}
45-
returnappId;
46-
});
47-
48-
constactiveApp=apps.find((app)=>app.id===activeAppId);
49-
if(!activeApp){
50-
thrownewError(`Active app with ID${activeAppId} not found in task`);
51-
}
52-
53-
constagent=agents.find((a)=>
54-
a.apps.some((app)=>app.id===activeAppId),
42+
const[activeAppId,setActiveAppId]=useState<string|undefined>(
43+
embeddedApps[0]?.id,
5544
);
56-
if(!agent){
57-
thrownewError(`Agent for app${activeAppId} not found in task workspace`);
58-
}
5945

6046
return(
6147
<mainclassName="flex flex-col">
@@ -76,56 +62,104 @@ export const TaskApps: FC<TaskAppsProps> = ({ task }) => {
7662
</div>
7763

7864
{externalApps.length>0&&(
79-
<divclassName="ml-auto">
80-
<DropdownMenu>
81-
<DropdownMenuTriggerasChild>
82-
<Buttonsize="sm"variant="subtle">
83-
Open locally
84-
<ChevronDownIcon/>
85-
</Button>
86-
</DropdownMenuTrigger>
87-
<DropdownMenuContent>
88-
{externalApps.map((app)=>{
89-
constlink=useAppLink(app,{
90-
agent,
91-
workspace:task.workspace,
92-
});
93-
94-
return(
95-
<DropdownMenuItemkey={app.id}asChild>
96-
<RouterLinkto={link.href}>
97-
{app.icon ?(
98-
<ExternalImagesrc={app.icon}/>
99-
) :(
100-
<LayoutGridIcon/>
101-
)}
102-
{link.label}
103-
</RouterLink>
104-
</DropdownMenuItem>
105-
);
106-
})}
107-
</DropdownMenuContent>
108-
</DropdownMenu>
109-
</div>
65+
<TaskExternalAppsDropdown
66+
task={task}
67+
agents={agents}
68+
externalApps={externalApps}
69+
/>
11070
)}
11171
</div>
11272

113-
<divclassName="flex-1">
114-
{embeddedApps.map((app)=>{
115-
return(
116-
<TaskAppIFrame
117-
key={app.id}
118-
active={activeAppId===app.id}
119-
app={app}
120-
task={task}
121-
/>
122-
);
123-
})}
124-
</div>
73+
{embeddedApps.length>0 ?(
74+
<divclassName="flex-1">
75+
{embeddedApps.map((app)=>{
76+
return(
77+
<TaskAppIFrame
78+
key={app.id}
79+
active={activeAppId===app.id}
80+
app={app}
81+
task={task}
82+
/>
83+
);
84+
})}
85+
</div>
86+
) :(
87+
<divclassName="mx-auto my-auto flex flex-col items-center">
88+
<h3className="font-medium text-content-primary text-base">
89+
No embedded apps found.
90+
</h3>
91+
92+
<spanclassName="text-content-secondary text-sm">
93+
<Link
94+
href={docs("/ai-coder/tasks")}
95+
target="_blank"
96+
rel="noreferrer"
97+
>
98+
Learn how to configure apps
99+
</Link>{" "}
100+
for your tasks.
101+
</span>
102+
</div>
103+
)}
125104
</main>
126105
);
127106
};
128107

108+
typeTaskExternalAppsDropdownProps={
109+
task:Task;
110+
agents:WorkspaceAgent[];
111+
externalApps:WorkspaceApp[];
112+
};
113+
114+
constTaskExternalAppsDropdown:FC<TaskExternalAppsDropdownProps>=({
115+
task,
116+
agents,
117+
externalApps,
118+
})=>{
119+
return(
120+
<divclassName="ml-auto">
121+
<DropdownMenu>
122+
<DropdownMenuTriggerasChild>
123+
<Buttonsize="sm"variant="subtle">
124+
Open locally
125+
<ChevronDownIcon/>
126+
</Button>
127+
</DropdownMenuTrigger>
128+
<DropdownMenuContent>
129+
{externalApps.map((app)=>{
130+
constagent=agents.find((agent)=>
131+
agent.apps.some((a)=>a.id===app.id),
132+
);
133+
if(!agent){
134+
thrownewError(
135+
`Agent for app${app.id} not found in task workspace`,
136+
);
137+
}
138+
139+
constlink=useAppLink(app,{
140+
agent,
141+
workspace:task.workspace,
142+
});
143+
144+
return(
145+
<DropdownMenuItemkey={app.id}asChild>
146+
<RouterLinkto={link.href}>
147+
{app.icon ?(
148+
<ExternalImagesrc={app.icon}/>
149+
) :(
150+
<LayoutGridIcon/>
151+
)}
152+
{link.label}
153+
</RouterLink>
154+
</DropdownMenuItem>
155+
);
156+
})}
157+
</DropdownMenuContent>
158+
</DropdownMenu>
159+
</div>
160+
);
161+
};
162+
129163
typeTaskAppTabProps={
130164
task:Task;
131165
app:WorkspaceApp;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp