Skip to content

Commit 9001b17

Browse files
authored
feat(loops): Add stop button to loop run rows (#3738)
1 parent 636a8d6 commit 9001b17

2 files changed

Lines changed: 60 additions & 12 deletions

File tree

packages/ui/src/features/loops/components/LoopDetailView.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,11 @@ export function LoopDetailView({ loopId }: { loopId: string }) {
212212
) : (
213213
<Flex direction="column" gap="2">
214214
{runs.map((run) => (
215-
<LoopRunRow key={run.id} run={run} />
215+
<LoopRunRow
216+
key={run.id}
217+
run={run}
218+
onStopped={() => void runsQuery.refetch()}
219+
/>
216220
))}
217221
</Flex>
218222
)}

packages/ui/src/features/loops/components/LoopRunRow.tsx

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,20 @@ import {
66
type Icon,
77
Lightning,
88
Play,
9+
Stop,
910
Timer,
1011
Warning,
1112
X,
1213
} from "@phosphor-icons/react";
1314
import type { LoopSchemas } from "@posthog/api-client/loops";
1415
import { cn } from "@posthog/quill";
16+
import { StopCloudRunDialog } from "@posthog/ui/features/sessions/components/StopCloudRunDialog";
1517
import { Badge } from "@posthog/ui/primitives/Badge";
1618
import { Button } from "@posthog/ui/primitives/Button";
19+
import { toast } from "@posthog/ui/primitives/toast";
1720
import { navigateToTaskDetail } from "@posthog/ui/router/navigationBridge";
1821
import { Flex, Text } from "@radix-ui/themes";
19-
import type { ReactNode } from "react";
22+
import { type ReactNode, useState } from "react";
2023

2124
function statusColor(
2225
status: LoopSchemas.LoopRunStatusEnum,
@@ -109,10 +112,25 @@ function MetaItem({
109112
);
110113
}
111114

112-
export function LoopRunRow({ run }: { run: LoopSchemas.LoopRun }) {
115+
function isStoppable(run: LoopSchemas.LoopRun): boolean {
116+
return (
117+
run.environment === "cloud" &&
118+
(run.status === "queued" || run.status === "in_progress")
119+
);
120+
}
121+
122+
export function LoopRunRow({
123+
run,
124+
onStopped,
125+
}: {
126+
run: LoopSchemas.LoopRun;
127+
onStopped?: () => void;
128+
}) {
113129
const StatusIcon = statusIcon(run.status);
114130
const duration = runDuration(run);
115131
const triggered = Boolean(run.loop_trigger_id);
132+
const stoppable = isStoppable(run);
133+
const [stopOpen, setStopOpen] = useState(false);
116134

117135
return (
118136
<Flex
@@ -162,15 +180,41 @@ export function LoopRunRow({ run }: { run: LoopSchemas.LoopRun }) {
162180
</Flex>
163181
) : null}
164182
</Flex>
165-
<Button
166-
variant="soft"
167-
color="gray"
168-
size="1"
169-
className="shrink-0"
170-
onClick={() => navigateToTaskDetail(run.task_id)}
171-
>
172-
View run
173-
</Button>
183+
<Flex align="center" gap="2" className="shrink-0">
184+
{stoppable ? (
185+
<Button
186+
variant="soft"
187+
color="red"
188+
size="1"
189+
onClick={() => setStopOpen(true)}
190+
>
191+
<Stop size={12} weight="bold" />
192+
Stop run
193+
</Button>
194+
) : null}
195+
<Button
196+
variant="soft"
197+
color="gray"
198+
size="1"
199+
onClick={() => navigateToTaskDetail(run.task_id)}
200+
>
201+
View run
202+
</Button>
203+
</Flex>
204+
{stoppable || stopOpen ? (
205+
<StopCloudRunDialog
206+
open={stopOpen}
207+
taskId={run.task_id}
208+
runId={run.id}
209+
title="Stop run"
210+
buttonLabel="Stop run"
211+
onOpenChange={setStopOpen}
212+
onStopped={() => {
213+
toast.success("Run stopped");
214+
onStopped?.();
215+
}}
216+
/>
217+
) : null}
174218
</Flex>
175219
);
176220
}

0 commit comments

Comments
 (0)