diff --git a/server/src/routes/agents.ts b/server/src/routes/agents.ts index d14e08a9..8e6ace2c 100644 --- a/server/src/routes/agents.ts +++ b/server/src/routes/agents.ts @@ -906,6 +906,7 @@ export function agentRoutes(db: Db) { agentId: heartbeatRuns.agentId, agentName: agentsTable.name, adapterType: agentsTable.adapterType, + issueId: sql`${heartbeatRuns.contextSnapshot} ->> 'issueId'`.as("issueId"), }) .from(heartbeatRuns) .innerJoin(agentsTable, eq(heartbeatRuns.agentId, agentsTable.id)) diff --git a/ui/src/api/heartbeats.ts b/ui/src/api/heartbeats.ts index 9acf0d8b..50d26082 100644 --- a/ui/src/api/heartbeats.ts +++ b/ui/src/api/heartbeats.ts @@ -18,6 +18,7 @@ export interface LiveRunForIssue { agentId: string; agentName: string; adapterType: string; + issueId?: string | null; } export const heartbeatsApi = { diff --git a/ui/src/pages/Issues.tsx b/ui/src/pages/Issues.tsx index cb29bae0..4ff8c82b 100644 --- a/ui/src/pages/Issues.tsx +++ b/ui/src/pages/Issues.tsx @@ -1,8 +1,9 @@ -import { useEffect } from "react"; +import { useEffect, useMemo } from "react"; import { useNavigate, useLocation } from "react-router-dom"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { issuesApi } from "../api/issues"; import { agentsApi } from "../api/agents"; +import { heartbeatsApi } from "../api/heartbeats"; import { useCompany } from "../context/CompanyContext"; import { useDialog } from "../context/DialogContext"; import { useBreadcrumbs } from "../context/BreadcrumbContext"; @@ -69,6 +70,21 @@ export function Issues() { enabled: !!selectedCompanyId, }); + const { data: liveRuns } = useQuery({ + queryKey: queryKeys.liveRuns(selectedCompanyId!), + queryFn: () => heartbeatsApi.liveRunsForCompany(selectedCompanyId!), + enabled: !!selectedCompanyId, + refetchInterval: 5000, + }); + + const liveIssueIds = useMemo(() => { + const ids = new Set(); + for (const run of liveRuns ?? []) { + if (run.issueId) ids.add(run.issueId); + } + return ids; + }, [liveRuns]); + useEffect(() => { setBreadcrumbs([{ label: "Issues" }]); }, [setBreadcrumbs]); @@ -169,6 +185,15 @@ export function Issues() { } trailing={
+ {liveIssueIds.has(issue.id) && ( + + + + + + Live + + )} {issue.assigneeAgentId && (() => { const name = agentName(issue.assigneeAgentId); return name