Skip to content

Commit c211f16

Browse files
chore(cloud): add floating hedgehog waiting screen for queued cloud tasks (#1779)
1 parent ca8c683 commit c211f16

4 files changed

Lines changed: 110 additions & 7 deletions

File tree

apps/code/src/renderer/features/command-center/components/CommandCenterSessionView.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export function CommandCenterSessionView({
3131
promptStartedAt,
3232
isInitializing,
3333
cloudBranch,
34+
cloudStatus,
3435
errorTitle,
3536
errorMessage,
3637
} = useSessionViewState(taskId, task);
@@ -68,6 +69,8 @@ export function CommandCenterSessionView({
6869
onRetry={isCloud ? undefined : handleRetry}
6970
onNewSession={isCloud ? undefined : handleNewSession}
7071
isInitializing={isInitializing}
72+
isCloud={isCloud}
73+
cloudStatus={cloudStatus}
7174
compact
7275
isActiveSession={isActiveSession}
7376
/>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { Spinner } from "@phosphor-icons/react";
2+
import { Flex, Text } from "@radix-ui/themes";
3+
import zenHedgehog from "@renderer/assets/images/zen.png";
4+
import type { TaskRunStatus } from "@shared/types";
5+
import { useEffect, useState } from "react";
6+
7+
interface CloudInitializingViewProps {
8+
cloudStatus: TaskRunStatus | null;
9+
}
10+
11+
const REVEAL_DELAY_MS = 2000;
12+
13+
function copyFor(cloudStatus: TaskRunStatus | null): {
14+
heading: string;
15+
subtitle: string;
16+
} {
17+
switch (cloudStatus) {
18+
case "queued":
19+
return {
20+
heading: "Waiting in the queue…",
21+
subtitle: "Reserving a cloud sandbox — this can take a few seconds.",
22+
};
23+
case "in_progress":
24+
return {
25+
heading: "Starting the sandbox…",
26+
subtitle: "Connecting to your cloud runner.",
27+
};
28+
default:
29+
return {
30+
heading: "Getting things ready…",
31+
subtitle: "Connecting to your cloud runner.",
32+
};
33+
}
34+
}
35+
36+
export function CloudInitializingView({
37+
cloudStatus,
38+
}: CloudInitializingViewProps) {
39+
const { heading, subtitle } = copyFor(cloudStatus);
40+
41+
const [revealed, setRevealed] = useState(false);
42+
useEffect(() => {
43+
const timer = setTimeout(() => setRevealed(true), REVEAL_DELAY_MS);
44+
return () => clearTimeout(timer);
45+
}, []);
46+
47+
if (!revealed) {
48+
return (
49+
<Flex
50+
align="center"
51+
justify="center"
52+
className="absolute inset-0 bg-background"
53+
>
54+
<Spinner size={32} className="animate-spin text-gray-9" />
55+
</Flex>
56+
);
57+
}
58+
59+
return (
60+
<Flex
61+
align="center"
62+
justify="center"
63+
direction="column"
64+
gap="5"
65+
className="absolute inset-0 bg-background"
66+
>
67+
<div className="zen-float">
68+
<img
69+
src={zenHedgehog}
70+
alt=""
71+
style={{ width: "160px", display: "block" }}
72+
/>
73+
</div>
74+
<Flex direction="column" align="center" gap="2">
75+
<Flex align="center" gap="2">
76+
<Spinner size={16} className="animate-spin text-gray-9" />
77+
<Text size="3" weight="medium">
78+
{heading}
79+
</Text>
80+
</Flex>
81+
<Text size="2" color="gray">
82+
{subtitle}
83+
</Text>
84+
</Flex>
85+
</Flex>
86+
);
87+
}

apps/code/src/renderer/features/sessions/components/SessionView.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { useIsWorkspaceCloudRun } from "@features/workspace/hooks/useWorkspace";
1515
import { useAutoFocusOnTyping } from "@hooks/useAutoFocusOnTyping";
1616
import { Pause, Spinner, Warning } from "@phosphor-icons/react";
1717
import { Box, Button, ContextMenu, Flex, Text } from "@radix-ui/themes";
18+
import type { TaskRunStatus } from "@shared/types";
1819
import {
1920
type AcpMessage,
2021
isJsonRpcNotification,
@@ -27,6 +28,7 @@ import {
2728
useSessionViewActions,
2829
useShowRawLogs,
2930
} from "../stores/sessionViewStore";
31+
import { CloudInitializingView } from "./CloudInitializingView";
3032
import { ConversationView } from "./ConversationView";
3133
import { DropZoneOverlay } from "./DropZoneOverlay";
3234
import { ModelSelector } from "./ModelSelector";
@@ -54,6 +56,8 @@ interface SessionViewProps {
5456
onRetry?: () => void;
5557
onNewSession?: () => void;
5658
isInitializing?: boolean;
59+
isCloud?: boolean;
60+
cloudStatus?: TaskRunStatus | null;
5761
slackThreadUrl?: string;
5862
compact?: boolean;
5963
isActiveSession?: boolean;
@@ -85,6 +89,8 @@ export function SessionView({
8589
onRetry,
8690
onNewSession,
8791
isInitializing = false,
92+
isCloud = false,
93+
cloudStatus = null,
8894
slackThreadUrl,
8995
compact = false,
9096
isActiveSession = true,
@@ -411,13 +417,17 @@ export function SessionView({
411417
</Box>
412418
</>
413419
) : isInitializing ? (
414-
<Flex
415-
align="center"
416-
justify="center"
417-
className="absolute inset-0 bg-background"
418-
>
419-
<Spinner size={32} className="animate-spin text-gray-9" />
420-
</Flex>
420+
isCloud ? (
421+
<CloudInitializingView cloudStatus={cloudStatus} />
422+
) : (
423+
<Flex
424+
align="center"
425+
justify="center"
426+
className="absolute inset-0 bg-background"
427+
>
428+
<Spinner size={32} className="animate-spin text-gray-9" />
429+
</Flex>
430+
)
421431
) : (
422432
<>
423433
<DropZoneOverlay isVisible={isDraggingFile} />

apps/code/src/renderer/features/task-detail/components/TaskLogsPanel.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export function TaskLogsPanel({ taskId, task, hideInput }: TaskLogsPanelProps) {
5757
promptStartedAt,
5858
isInitializing,
5959
cloudBranch,
60+
cloudStatus,
6061
errorTitle,
6162
errorMessage,
6263
} = useSessionViewState(taskId, task);
@@ -147,6 +148,8 @@ export function TaskLogsPanel({ taskId, task, hideInput }: TaskLogsPanelProps) {
147148
onRetry={handleRetry}
148149
onNewSession={isCloud ? undefined : handleNewSession}
149150
isInitializing={isInitializing}
151+
isCloud={isCloud}
152+
cloudStatus={cloudStatus}
150153
slackThreadUrl={slackThreadUrl}
151154
/>
152155
</ErrorBoundary>

0 commit comments

Comments
 (0)