1
1
import { API } from "api/api";
2
2
import { getErrorDetail, getErrorMessage } from "api/errors";
3
+
import { template as templateQueryOptions } from "api/queries/templates";
3
4
import type { Workspace, WorkspaceStatus } from "api/typesGenerated";
4
5
import { Button } from "components/Button/Button";
5
6
import { Loader } from "components/Loader/Loader";
6
7
import { Margins } from "components/Margins/Margins";
7
8
import { Spinner } from "components/Spinner/Spinner";
9
+
import { useWorkspaceBuildLogs } from "hooks/useWorkspaceBuildLogs";
8
10
import { ArrowLeftIcon, RotateCcwIcon } from "lucide-react";
9
11
import { AI_PROMPT_PARAMETER_NAME, type Task } from "modules/tasks/tasks";
10
12
import type { ReactNode } from "react";
@@ -14,6 +16,10 @@ import { useParams } from "react-router-dom";
14
16
import { Link as RouterLink } from "react-router-dom";
15
17
import { ellipsizeText } from "utils/ellipsizeText";
16
18
import { pageTitle } from "utils/page";
19
+
import {
20
+
ActiveTransition,
21
+
WorkspaceBuildProgress,
22
+
} from "../WorkspacePage/WorkspaceBuildProgress";
17
23
import { TaskApps } from "./TaskApps";
18
24
import { TaskSidebar } from "./TaskSidebar";
19
25
@@ -32,6 +38,19 @@ const TaskPage = () => {
32
38
refetchInterval: 5_000,
33
39
});
34
40
41
+
const { data: template } = useQuery({
42
+
...templateQueryOptions(task?.workspace.template_id ?? ""),
43
+
enabled: Boolean(task),
44
+
});
45
+
46
+
const waitingStatuses: WorkspaceStatus[] = ["starting", "pending"];
47
+
const shouldStreamBuildLogs =
48
+
task && waitingStatuses.includes(task.workspace.latest_build.status);
49
+
const buildLogs = useWorkspaceBuildLogs(
50
+
task?.workspace.latest_build.id ?? "",
51
+
shouldStreamBuildLogs,
52
+
);
53
+
35
54
if (error) {
36
55
return (
37
56
<>
@@ -77,7 +96,6 @@ const TaskPage = () => {
77
96
}
78
97
79
98
let content: ReactNode = null;
80
-
const waitingStatuses: WorkspaceStatus[] = ["starting", "pending"];
81
99
const terminatedStatuses: WorkspaceStatus[] = [
82
100
"canceled",
83
101
"canceling",
@@ -88,16 +106,25 @@ const TaskPage = () => {
88
106
];
89
107
90
108
if (waitingStatuses.includes(task.workspace.latest_build.status)) {
109
+
// If no template yet, use an indeterminate progress bar.
110
+
const transition = (template &&
111
+
ActiveTransition(template, task.workspace)) || { P50: 0, P95: null };
112
+
const lastStage =
113
+
buildLogs?.[buildLogs.length - 1]?.stage || "Waiting for build status";
91
114
content = (
92
-
<div className="w-full min-h-80 flex items-center justify-center">
93
-
<div className="flex flex-col items-center">
94
-
<Spinner loading className="mb-4" />
115
+
<div className="w-full min-h-80 flex flex-col">
116
+
<div className="flex flex-col items-center grow justify-center">
95
117
<h3 className="m-0 font-medium text-content-primary text-base">
96
118
Starting your workspace
97
119
</h3>
98
-
<span className="text-content-secondary text-sm">
99
-
This should take a few minutes
100
-
</span>
120
+
<div className="text-content-secondary text-sm">{lastStage}</div>
121
+
</div>
122
+
<div className="w-full">
123
+
<WorkspaceBuildProgress
124
+
workspace={task.workspace}
125
+
transitionStats={transition}
126
+
variant="task"
127
+
/>
101
128
</div>
102
129
</div>
103
130
);
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4