feat(FN-3384): simplify org chart node metadata in AgentsView

- Remove org chart node subtitle metadata rendering from AgentsView
- Update AgentsView tests to assert the simplified node content and behavior
- Document the org chart skill simplification in docs/agents.md

Fusion-Task-Id: FN-3384
This commit is contained in:
Fusion
2026-05-04 21:16:49 -07:00
committed by gsxdsm
parent bc6e1276e3
commit 499dede1e3
3 changed files with 22 additions and 20 deletions

View File

@@ -87,6 +87,7 @@ These fields can only be set during update (not on create):
The agents surface provides:
- Agent-first list/board/tree/org collection in the left pane (primary content appears first)
- Org chart nodes intentionally stay compact (role/state/health hierarchy signal only) and do not enumerate per-agent skill badges; detailed skills remain in list/board/detail surfaces
- A cross-pane **Overview** strip above the split layout with summary metrics and a disclosure to expand active/running live cards
- A compact **Controls** popup for secondary actions (state filter, Show system agents toggle, Import, and global Heartbeat Speed)
- Detail/config panels

View File

@@ -154,14 +154,12 @@ function OrgChartNode({
onSelect,
getHealthStatus,
getRoleIcon,
getSkillBadges,
selectedAgentId,
}: {
node: OrgTreeNode;
onSelect: (id: string) => void;
getHealthStatus: (agent: Agent) => AgentHealthStatus;
getRoleIcon: (role: AgentCapability) => string;
getSkillBadges: (agent: Agent) => string[];
selectedAgentId: string | null;
}) {
const { agent, children } = node;
@@ -204,21 +202,6 @@ function OrgChartNode({
{health.icon}
{!health.stateDerived && <span className="text-secondary">{health.label}</span>}
</span>
{/* Org chart: up to 2 skill badges */}
{(() => {
const skills = getSkillBadges(agent);
if (skills.length === 0) return null;
const displaySkills = skills.slice(0, 2);
const extraCount = skills.length - 2;
return (
<>
{displaySkills.map((skillId) => (
<span key={skillId} className="org-chart-node__skill">{formatAgentSkillBadgeLabel(skillId)}</span>
))}
{extraCount > 0 && <span className="org-chart-node__skill">+{extraCount}</span>}
</>
);
})()}
</div>
</div>
{children.length > 0 && (
@@ -230,7 +213,6 @@ function OrgChartNode({
onSelect={onSelect}
getHealthStatus={getHealthStatus}
getRoleIcon={getRoleIcon}
getSkillBadges={getSkillBadges}
selectedAgentId={selectedAgentId}
/>
))}
@@ -1025,7 +1007,6 @@ export function AgentsView({ addToast, projectId, onOpenTaskLogs, agentOnboardin
onSelect={openAgentDetail}
getHealthStatus={getHealthStatus}
getRoleIcon={getRoleIcon}
getSkillBadges={getSkillBadges}
selectedAgentId={selectedAgentId}
/>
))

View File

@@ -1193,7 +1193,9 @@ describe("AgentsView", () => {
lastHeartbeatAt: new Date().toISOString(),
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
metadata: {},
metadata: {
skills: ["auto::skills/../../.agents/skills/review/SKILL.md", "auto::skills/../../.agents/skills/fusion/SKILL.md"],
},
},
children: [
{
@@ -1291,6 +1293,24 @@ describe("AgentsView", () => {
});
});
it("keeps org chart node metadata compact without skill badges", async () => {
mockFetchOrgTree.mockResolvedValue(orgTree);
render(<AgentsView addToast={mockAddToast} />);
fireEvent.click(screen.getByRole("button", { name: "Org Chart view" }));
await waitFor(() => {
expect(screen.getByText("Chief Agent")).toBeTruthy();
});
const rootCard = document.querySelector('[class*="org-chart-node-card--"]');
expect(rootCard).toBeTruthy();
expect(within(rootCard as HTMLElement).queryByText("review")).toBeNull();
expect(within(rootCard as HTMLElement).queryByText("fusion")).toBeNull();
expect(within(rootCard as HTMLElement).queryByText("+1")).toBeNull();
expect((rootCard as HTMLElement).querySelector(".org-chart-node__skill")).toBeNull();
});
it("sizes org chart subtree containers based on descendant leaf counts", async () => {
mockFetchOrgTree.mockResolvedValue(orgTree);
const { container } = render(<AgentsView addToast={mockAddToast} />);