fix(dashboard): split active vs running counts in agents overview label

The Overview dropdown previously rendered "X active · Y running" where
both X (stats.activeCount) and Y (activeAgents.length) counted agents
whose state was either "active" or "running" — so an agent that was
merely enabled but idle would still inflate the "running" tally. The
label now counts each state distinctly so "running" only reflects
agents that are mid-heartbeat. Adds AgentsOverviewBar.test.tsx to lock
in the new contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-05-06 08:04:47 -07:00
parent c2f3d92b5c
commit 8231fef06b
3 changed files with 111 additions and 1 deletions

View File

@@ -0,0 +1,10 @@
---
"@runfusion/fusion": patch
---
Fix the misleading "X active · Y running" label in the Agents overview
dropdown. Both numbers previously counted agents whose state was either
`active` or `running`, so the "running" tally over-reported by including
idle-but-enabled agents. The label now counts each state distinctly:
"active" reflects only `state === "active"` and "running" reflects only
`state === "running"`.

View File

@@ -36,7 +36,7 @@ export function AgentsOverviewBar({
<span className="agents-overview-bar__title">Overview</span> <span className="agents-overview-bar__title">Overview</span>
</span> </span>
<span className="agents-overview-bar__meta text-secondary"> <span className="agents-overview-bar__meta text-secondary">
{stats?.activeCount ?? 0} active · {activeAgents.length} running {activeAgents.filter((a) => a.state === "active").length} active · {activeAgents.filter((a) => a.state === "running").length} running
</span> </span>
</button> </button>
{isOpen ? ( {isOpen ? (

View File

@@ -0,0 +1,100 @@
import { describe, it, expect, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import { AgentsOverviewBar } from "../AgentsOverviewBar";
import type { Agent } from "../../api";
vi.mock("lucide-react", async () => {
const actual = await vi.importActual("lucide-react");
return {
...actual,
ChevronDown: () => <span data-testid="chevron-down" />,
ChevronRight: () => <span data-testid="chevron-right" />,
};
});
vi.mock("../AgentMetricsBar", () => ({
AgentMetricsBar: () => <div data-testid="agent-metrics-bar" />,
}));
vi.mock("../ActiveAgentsPanel", () => ({
ActiveAgentsPanel: () => <div data-testid="active-agents-panel" />,
}));
function makeAgent(id: string, state: Agent["state"]): Agent {
return {
id,
name: id,
role: "executor",
state,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
metadata: {},
};
}
describe("AgentsOverviewBar", () => {
it("counts active and running states separately in the meta label", () => {
// Three in 'active' (idle/enabled) and one in 'running' (mid-heartbeat).
// The label must reflect the distinction — previously both buckets were
// displayed under "running", which was misleading when only some were
// actually executing.
const agents = [
makeAgent("a-1", "active"),
makeAgent("a-2", "active"),
makeAgent("a-3", "active"),
makeAgent("a-4", "running"),
];
render(
<AgentsOverviewBar
stats={null}
activeAgents={agents}
isOpen={false}
onToggle={() => {}}
/>,
);
expect(screen.getByText("3 active · 1 running")).toBeInTheDocument();
});
it("shows zero counts when no agents are active or running", () => {
render(
<AgentsOverviewBar
stats={null}
activeAgents={[]}
isOpen={false}
onToggle={() => {}}
/>,
);
expect(screen.getByText("0 active · 0 running")).toBeInTheDocument();
});
it("renders metrics bar and active agents panel when open", () => {
render(
<AgentsOverviewBar
stats={null}
activeAgents={[]}
isOpen
onToggle={() => {}}
/>,
);
expect(screen.getByTestId("agent-metrics-bar")).toBeInTheDocument();
expect(screen.getByTestId("active-agents-panel")).toBeInTheDocument();
});
it("hides content when collapsed", () => {
render(
<AgentsOverviewBar
stats={null}
activeAgents={[]}
isOpen={false}
onToggle={() => {}}
/>,
);
expect(screen.queryByTestId("agent-metrics-bar")).toBeNull();
expect(screen.queryByTestId("active-agents-panel")).toBeNull();
});
});