diff --git a/packages/ui/src/features/loops/components/LoopDetailView.tsx b/packages/ui/src/features/loops/components/LoopDetailView.tsx
index c2f5ee7cfc..96c453f43a 100644
--- a/packages/ui/src/features/loops/components/LoopDetailView.tsx
+++ b/packages/ui/src/features/loops/components/LoopDetailView.tsx
@@ -212,7 +212,11 @@ export function LoopDetailView({ loopId }: { loopId: string }) {
) : (
{runs.map((run) => (
-
+ void runsQuery.refetch()}
+ />
))}
)}
diff --git a/packages/ui/src/features/loops/components/LoopRunRow.tsx b/packages/ui/src/features/loops/components/LoopRunRow.tsx
index 9f8c1f46b2..66defbfe8a 100644
--- a/packages/ui/src/features/loops/components/LoopRunRow.tsx
+++ b/packages/ui/src/features/loops/components/LoopRunRow.tsx
@@ -6,17 +6,20 @@ import {
type Icon,
Lightning,
Play,
+ Stop,
Timer,
Warning,
X,
} from "@phosphor-icons/react";
import type { LoopSchemas } from "@posthog/api-client/loops";
import { cn } from "@posthog/quill";
+import { StopCloudRunDialog } from "@posthog/ui/features/sessions/components/StopCloudRunDialog";
import { Badge } from "@posthog/ui/primitives/Badge";
import { Button } from "@posthog/ui/primitives/Button";
+import { toast } from "@posthog/ui/primitives/toast";
import { navigateToTaskDetail } from "@posthog/ui/router/navigationBridge";
import { Flex, Text } from "@radix-ui/themes";
-import type { ReactNode } from "react";
+import { type ReactNode, useState } from "react";
function statusColor(
status: LoopSchemas.LoopRunStatusEnum,
@@ -109,10 +112,25 @@ function MetaItem({
);
}
-export function LoopRunRow({ run }: { run: LoopSchemas.LoopRun }) {
+function isStoppable(run: LoopSchemas.LoopRun): boolean {
+ return (
+ run.environment === "cloud" &&
+ (run.status === "queued" || run.status === "in_progress")
+ );
+}
+
+export function LoopRunRow({
+ run,
+ onStopped,
+}: {
+ run: LoopSchemas.LoopRun;
+ onStopped?: () => void;
+}) {
const StatusIcon = statusIcon(run.status);
const duration = runDuration(run);
const triggered = Boolean(run.loop_trigger_id);
+ const stoppable = isStoppable(run);
+ const [stopOpen, setStopOpen] = useState(false);
return (
) : null}
-
+
+ {stoppable ? (
+
+ ) : null}
+
+
+ {stoppable || stopOpen ? (
+ {
+ toast.success("Run stopped");
+ onStopped?.();
+ }}
+ />
+ ) : null}
);
}