Skip to content

Commit 2be4511

Browse files
feat(site): add startup script error alerts to Task Page
Add warning alerts to the Task Page when workspace startup scripts fail or timeout. The alerts display inline above the log viewer to maintain debugging context while providing helpful documentation links. - Create TaskStartupAlert component with error and timeout variants - Integrate alert into TaskStartingAgent component - Extend TaskPage logic to render TaskStartingAgent for error states - Add Storybook stories for component and full page integration - Follow existing pattern from TerminalAlerts component The alerts are dismissible and link to troubleshooting documentation: - /admin/templates/troubleshooting#startup-script-exited-with-an-error - /admin/templates/troubleshooting#startup-script-issues - /admin/templates/troubleshooting#your-workspace-may-be-incomplete
1 parent a83328c commit 2be4511

File tree

4 files changed

+252
-1
lines changed

4 files changed

+252
-1
lines changed

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

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import {
99
MockWorkspace,
1010
MockWorkspaceAgentLogSource,
1111
MockWorkspaceAgentReady,
12+
MockWorkspaceAgentStartError,
1213
MockWorkspaceAgentStarting,
14+
MockWorkspaceAgentStartTimeout,
1315
MockWorkspaceApp,
1416
MockWorkspaceAppStatus,
1517
MockWorkspaceResource,
@@ -218,6 +220,111 @@ export const WaitingStartupScripts: Story = {
218220
},
219221
};
220222

223+
export const StartupScriptError: Story = {
224+
decorators: [withWebSocket],
225+
parameters: {
226+
queries: [
227+
{
228+
key: ["tasks", MockTask.owner_name, MockTask.id],
229+
data: MockTask,
230+
},
231+
{
232+
key: [
233+
"workspace",
234+
MockTask.owner_name,
235+
MockTask.workspace_name,
236+
"settings",
237+
],
238+
data: {
239+
...MockWorkspace,
240+
latest_build: {
241+
...MockWorkspace.latest_build,
242+
has_ai_task: true,
243+
resources: [
244+
{
245+
...MockWorkspaceResource,
246+
agents: [MockWorkspaceAgentStartError],
247+
},
248+
],
249+
},
250+
},
251+
},
252+
],
253+
webSocket: [
254+
{
255+
event: "message",
256+
data: JSON.stringify(
257+
[
258+
"Cloning Git repository...",
259+
"Starting application...",
260+
"\x1b[91mError: Failed to connect to database",
261+
"\x1b[91mStartup script exited with code 1",
262+
].map((line, index) => ({
263+
id: index,
264+
level: index >= 2 ? "error" : "info",
265+
output: line,
266+
source_id: MockWorkspaceAgentLogSource.id,
267+
created_at: new Date("2024-01-01T12:00:00Z").toISOString(),
268+
})),
269+
),
270+
},
271+
],
272+
},
273+
};
274+
275+
export const StartupScriptTimeout: Story = {
276+
decorators: [withWebSocket],
277+
parameters: {
278+
queries: [
279+
{
280+
key: ["tasks", MockTask.owner_name, MockTask.id],
281+
data: MockTask,
282+
},
283+
{
284+
key: [
285+
"workspace",
286+
MockTask.owner_name,
287+
MockTask.workspace_name,
288+
"settings",
289+
],
290+
data: {
291+
...MockWorkspace,
292+
latest_build: {
293+
...MockWorkspace.latest_build,
294+
has_ai_task: true,
295+
resources: [
296+
{
297+
...MockWorkspaceResource,
298+
agents: [MockWorkspaceAgentStartTimeout],
299+
},
300+
],
301+
},
302+
},
303+
},
304+
],
305+
webSocket: [
306+
{
307+
event: "message",
308+
data: JSON.stringify(
309+
[
310+
"Cloning Git repository...",
311+
"Starting application...",
312+
"Waiting for dependencies...",
313+
"Still waiting...",
314+
"\x1b[93mWarning: Startup script exceeded timeout limit",
315+
].map((line, index) => ({
316+
id: index,
317+
level: index === 4 ? "warn" : "info",
318+
output: line,
319+
source_id: MockWorkspaceAgentLogSource.id,
320+
created_at: new Date("2024-01-01T12:00:00Z").toISOString(),
321+
})),
322+
),
323+
},
324+
],
325+
},
326+
};
327+
221328
export const SidebarAppNotFound: Story = {
222329
beforeEach: () => {
223330
const [task, workspace] = mockTaskWithWorkspace(

site/src/pages/TaskPage/TaskPage.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
} from "../WorkspacePage/WorkspaceBuildProgress";
4545
import { TaskAppIFrame } from "./TaskAppIframe";
4646
import { TaskApps } from "./TaskApps";
47+
import { TaskStartupAlert } from "./TaskStartupAlert";
4748
import { TaskTopbar } from "./TaskTopbar";
4849

4950
const TaskPageLayout: FC<PropsWithChildren> = ({ children }) => {
@@ -145,7 +146,12 @@ const TaskPage = () => {
145146
);
146147
} else if (workspace.latest_build.status !== "running") {
147148
content = <WorkspaceNotRunning workspace={workspace} />;
148-
} else if (agent && ["created", "starting"].includes(agent.lifecycle_state)) {
149+
} else if (
150+
agent &&
151+
["created", "starting", "start_error", "start_timeout"].includes(
152+
agent.lifecycle_state,
153+
)
154+
) {
149155
content = <TaskStartingAgent agent={agent} />;
150156
} else {
151157
const chatApp = getAllAppsWithAgent(workspace).find(
@@ -378,6 +384,7 @@ const TaskStartingAgent: FC<TaskStartingAgentProps> = ({ agent }) => {
378384
</header>
379385

380386
<div className="w-full max-w-screen-lg flex flex-col gap-4 overflow-hidden">
387+
<TaskStartupAlert agent={agent} />
381388
<div className="h-96 border border-solid border-border rounded-lg">
382389
<AgentLogs
383390
ref={listRef}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {
2+
MockWorkspaceAgentReady,
3+
MockWorkspaceAgentStartError,
4+
MockWorkspaceAgentStartTimeout,
5+
} from "testHelpers/entities";
6+
import type { Meta, StoryObj } from "@storybook/react-vite";
7+
import { TaskStartupAlert } from "./TaskStartupAlert";
8+
9+
const meta: Meta<typeof TaskStartupAlert> = {
10+
title: "pages/TaskPage/TaskStartupAlert",
11+
component: TaskStartupAlert,
12+
parameters: {
13+
layout: "padded",
14+
},
15+
};
16+
17+
export default meta;
18+
type Story = StoryObj<typeof TaskStartupAlert>;
19+
20+
export const StartError: Story = {
21+
args: {
22+
agent: MockWorkspaceAgentStartError,
23+
},
24+
};
25+
26+
export const StartTimeout: Story = {
27+
args: {
28+
agent: MockWorkspaceAgentStartTimeout,
29+
},
30+
};
31+
32+
export const NoAlert: Story = {
33+
args: {
34+
agent: MockWorkspaceAgentReady,
35+
},
36+
};
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import Link from "@mui/material/Link";
2+
import type { WorkspaceAgent } from "api/typesGenerated";
3+
import { Alert } from "components/Alert/Alert";
4+
import type { FC } from "react";
5+
import { docs } from "utils/docs";
6+
7+
type TaskStartupAlertProps = {
8+
agent: WorkspaceAgent;
9+
};
10+
11+
export const TaskStartupAlert: FC<TaskStartupAlertProps> = ({ agent }) => {
12+
const lifecycleState = agent.lifecycle_state;
13+
14+
if (lifecycleState === "start_error") {
15+
return <ErrorScriptAlert />;
16+
}
17+
18+
if (lifecycleState === "start_timeout") {
19+
return <TimeoutScriptAlert />;
20+
}
21+
22+
return null;
23+
};
24+
25+
const ErrorScriptAlert: FC = () => {
26+
return (
27+
<Alert severity="warning" dismissible>
28+
The workspace{" "}
29+
<Link
30+
title="startup script has exited with an error"
31+
href={docs(
32+
"/admin/templates/troubleshooting#startup-script-exited-with-an-error",
33+
)}
34+
target="_blank"
35+
rel="noreferrer"
36+
>
37+
startup script has exited with an error
38+
</Link>
39+
. We recommend{" "}
40+
<Link
41+
title="debugging the startup script"
42+
href={docs("/admin/templates/troubleshooting#startup-script-issues")}
43+
target="_blank"
44+
rel="noreferrer"
45+
>
46+
debugging the startup script
47+
</Link>{" "}
48+
because{" "}
49+
<Link
50+
title="your workspace may be incomplete"
51+
href={docs(
52+
"/admin/templates/troubleshooting#your-workspace-may-be-incomplete",
53+
)}
54+
target="_blank"
55+
rel="noreferrer"
56+
>
57+
your workspace may be incomplete
58+
</Link>
59+
.
60+
</Alert>
61+
);
62+
};
63+
64+
const TimeoutScriptAlert: FC = () => {
65+
return (
66+
<Alert severity="warning" dismissible>
67+
The workspace{" "}
68+
<Link
69+
title="startup script has timed out"
70+
href={docs(
71+
"/admin/templates/troubleshooting#startup-script-exited-with-an-error",
72+
)}
73+
target="_blank"
74+
rel="noreferrer"
75+
>
76+
startup script has timed out
77+
</Link>
78+
. We recommend{" "}
79+
<Link
80+
title="debugging the startup script"
81+
href={docs("/admin/templates/troubleshooting#startup-script-issues")}
82+
target="_blank"
83+
rel="noreferrer"
84+
>
85+
debugging the startup script
86+
</Link>{" "}
87+
because{" "}
88+
<Link
89+
title="your workspace may be incomplete"
90+
href={docs(
91+
"/admin/templates/troubleshooting#your-workspace-may-be-incomplete",
92+
)}
93+
target="_blank"
94+
rel="noreferrer"
95+
>
96+
your workspace may be incomplete
97+
</Link>
98+
.
99+
</Alert>
100+
);
101+
};

0 commit comments

Comments
 (0)