Fix live run indicator: only show blue dot when a run is actually active

Previously used routine run status ("received"/"issue_created") which
are not the right signal. Now queries heartbeatsApi.liveRunsForIssue()
on the active issue to check if an agent is actually running — the same
source of truth the LiveRunWidget uses.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta
2026-03-20 06:22:51 -05:00
parent 4fc80bdc16
commit 8cc8540597

View File

@@ -16,6 +16,7 @@ import {
Zap, Zap,
} from "lucide-react"; } from "lucide-react";
import { routinesApi, type RoutineTriggerResponse, type RotateRoutineTriggerResponse } from "../api/routines"; import { routinesApi, type RoutineTriggerResponse, type RotateRoutineTriggerResponse } from "../api/routines";
import { heartbeatsApi } from "../api/heartbeats";
import { LiveRunWidget } from "../components/LiveRunWidget"; import { LiveRunWidget } from "../components/LiveRunWidget";
import { agentsApi } from "../api/agents"; import { agentsApi } from "../api/agents";
import { projectsApi } from "../api/projects"; import { projectsApi } from "../api/projects";
@@ -281,18 +282,20 @@ export function RoutineDetail() {
queryFn: () => routinesApi.get(routineId!), queryFn: () => routinesApi.get(routineId!),
enabled: !!routineId, enabled: !!routineId,
}); });
const activeIssueId = routine?.activeIssue?.id;
const { data: liveRuns } = useQuery({
queryKey: queryKeys.issues.liveRuns(activeIssueId!),
queryFn: () => heartbeatsApi.liveRunsForIssue(activeIssueId!),
enabled: !!activeIssueId,
refetchInterval: 3000,
});
const hasLiveRun = (liveRuns ?? []).length > 0;
const { data: routineRuns } = useQuery({ const { data: routineRuns } = useQuery({
queryKey: queryKeys.routines.runs(routineId!), queryKey: queryKeys.routines.runs(routineId!),
queryFn: () => routinesApi.listRuns(routineId!), queryFn: () => routinesApi.listRuns(routineId!),
enabled: !!routineId, enabled: !!routineId,
refetchInterval: (query) => { refetchInterval: hasLiveRun ? 3000 : false,
const runs = query.state.data ?? [];
return runs.some((r) => r.status === "received" || r.status === "issue_created") ? 3000 : false;
},
}); });
const hasLiveRun = (routineRuns ?? []).some(
(run) => run.status === "received" || run.status === "issue_created",
);
const relatedActivityIds = useMemo( const relatedActivityIds = useMemo(
() => ({ () => ({
triggerIds: routine?.triggers.map((trigger) => trigger.id) ?? [], triggerIds: routine?.triggers.map((trigger) => trigger.id) ?? [],
@@ -985,12 +988,9 @@ export function RoutineDetail() {
</TabsContent> </TabsContent>
<TabsContent value="runs" className="space-y-4"> <TabsContent value="runs" className="space-y-4">
{hasLiveRun && (() => { {hasLiveRun && activeIssueId && routine && (
const liveRun = (routineRuns ?? []).find((r) => r.status === "received" || r.status === "issue_created"); <LiveRunWidget issueId={activeIssueId} companyId={routine.companyId} />
const issueId = liveRun?.linkedIssue?.id ?? routine?.activeIssue?.id; )}
if (!issueId || !routine) return null;
return <LiveRunWidget issueId={issueId} companyId={routine.companyId} />;
})()}
{(routineRuns ?? []).length === 0 ? ( {(routineRuns ?? []).length === 0 ? (
<p className="text-xs text-muted-foreground">No runs yet.</p> <p className="text-xs text-muted-foreground">No runs yet.</p>
) : ( ) : (