11import { API } from "api/api" ;
22import { getErrorDetail , getErrorMessage } from "api/errors" ;
3+ import { template as templateQueryOptions } from "api/queries/templates" ;
34import type { Workspace , WorkspaceStatus } from "api/typesGenerated" ;
45import { Button } from "components/Button/Button" ;
56import { Loader } from "components/Loader/Loader" ;
67import { Margins } from "components/Margins/Margins" ;
78import { Spinner } from "components/Spinner/Spinner" ;
9+ import { useWorkspaceBuildLogs } from "hooks/useWorkspaceBuildLogs" ;
810import { ArrowLeftIcon , RotateCcwIcon } from "lucide-react" ;
911import { AI_PROMPT_PARAMETER_NAME , type Task } from "modules/tasks/tasks" ;
1012import type { ReactNode } from "react" ;
@@ -14,6 +16,10 @@ import { useParams } from "react-router-dom";
1416import { Link as RouterLink } from "react-router-dom" ;
1517import { ellipsizeText } from "utils/ellipsizeText" ;
1618import { pageTitle } from "utils/page" ;
19+ import {
20+ ActiveTransition ,
21+ WorkspaceBuildProgress ,
22+ } from "../WorkspacePage/WorkspaceBuildProgress" ;
1723import { TaskApps } from "./TaskApps" ;
1824import { TaskSidebar } from "./TaskSidebar" ;
1925
@@ -32,6 +38,19 @@ const TaskPage = () => {
3238refetchInterval :5_000 ,
3339} ) ;
3440
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+
3554if ( error ) {
3655return (
3756< >
@@ -77,7 +96,6 @@ const TaskPage = () => {
7796}
7897
7998let content :ReactNode = null ;
80- const waitingStatuses :WorkspaceStatus [ ] = [ "starting" , "pending" ] ;
8199const terminatedStatuses :WorkspaceStatus [ ] = [
82100"canceled" ,
83101"canceling" ,
@@ -88,17 +106,27 @@ const TaskPage = () => {
88106] ;
89107
90108if ( waitingStatuses . includes ( task . workspace . latest_build . status ) ) {
109+ // If no template yet, use null values for an indeterminate progress bar.
110+ const transition = ( template &&
111+ ActiveTransition ( template , task . workspace ) ) || { P50 :null , P95 :null } ;
112+ const lastStage = buildLogs ?. [ buildLogs . length - 1 ] ?. stage ;
91113content = (
92- < div className = "w-full min-h-80 flex items-center justify-center" >
114+ < div className = "w-full min-h-80 flexflex-col items-center justify-center gap-2 " >
93115< div className = "flex flex-col items-center" >
94- < Spinner loading className = "mb-4" />
95116< h3 className = "m-0 font-medium text-content-primary text-base" >
96117Starting your workspace
97118</ h3 >
98119< span className = "text-content-secondary text-sm" >
99120This should take a few minutes
100121</ span >
101122</ div >
123+ { lastStage && (
124+ < div className = "text-content-secondary text-sm" > { lastStage } </ div >
125+ ) }
126+ < WorkspaceBuildProgress
127+ workspace = { task . workspace }
128+ transitionStats = { transition }
129+ />
102130</ div >
103131) ;
104132} else if ( task . workspace . latest_build . status === "failed" ) {