From 50a7196b3e4fc0bc0d1d4e4134b64b1e8b7dfe46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Fri, 17 Apr 2026 19:43:12 -0400 Subject: [PATCH] refactor(org): drop legacy adapterLabels / claude_compat fallback; unify connector label resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OrgChart and AgentRoster both carried a `claude_compat`-prefix fallback chained against `adapterLabels[connectorId] ?? connectorId` to paper over the pre-pi-mono connector id space (claude_local / codex_local / gemini_local / claude_compat_2..10). The migration to pi-mono's catalog retired those ids months ago — the fallback is dead code that still runs `String.prototype.startsWith` on every render and forks the label resolution into two subtly different shapes in two files. Replaced with `formatConnectorLabel(connector, fallbackId)` in lib/formatters.ts, used by both OrgChart and AgentRoster. Also in this commit (typography polish bundled because touching the same render paths): - OrgChart connector label: 9px uppercase tracking-0.08em → 11px tracking-tight. The 9px chip was unreadable at default zoom. - OrgChart zoom controls: `+` / `−` / "Fit" mixed text + character ops replaced with Plus / Minus / CornersOut icons (imported from the existing icon barrel) + a focus-visible ring for keyboard users. No rendering changes for the non-cosmetic path (status dots, card layout, edges). The removed `adapterLabels` map was exported from orgTreeLayout.ts and had no other importers. Covers J1 / J3 / J4 / J6 from the team-page audit. --- .../components/organization/AgentRoster.tsx | 3 ++- .../components/organization/OrgChart.tsx | 22 +++++++++++-------- .../components/organization/orgTreeLayout.ts | 16 -------------- src/renderer/components/ui/icons.ts | 1 + src/renderer/lib/formatters.ts | 13 +++++++++++ 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/renderer/components/organization/AgentRoster.tsx b/src/renderer/components/organization/AgentRoster.tsx index 10e951ae..34353203 100644 --- a/src/renderer/components/organization/AgentRoster.tsx +++ b/src/renderer/components/organization/AgentRoster.tsx @@ -5,6 +5,7 @@ import type { AgentRecord, ConnectorRecord, WorkspaceRecord } from "@shared/type import { EmptyState, StatusPill } from "../ui" import { useT } from "../../i18n" import { useRovingTabIndex } from "../../lib/keyboard" +import { formatConnectorLabel } from "../../lib/formatters" import { BudgetBar } from "./helpers" export function AgentRoster({ @@ -96,7 +97,7 @@ export function AgentRoster({
- {t("org.connectorLabel")} {connector?.id.startsWith("claude_compat") && connector.notes ? connector.notes : connector?.label ?? agent.connectorId} + {t("org.connectorLabel")} {formatConnectorLabel(connector, agent.connectorId)} {workspace && {t("org.workspaceLabel")} {workspace.name}}
diff --git a/src/renderer/components/organization/OrgChart.tsx b/src/renderer/components/organization/OrgChart.tsx index 03c4a7fe..338cdb60 100644 --- a/src/renderer/components/organization/OrgChart.tsx +++ b/src/renderer/components/organization/OrgChart.tsx @@ -1,10 +1,10 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { Heartbeat } from "../ui/icons"; +import { CornersOut, Heartbeat, Minus, Plus } from "../ui/icons"; import type { AgentRecord, ConnectorRecord } from "@shared/types"; -import { getAgentInitials } from "../../lib/formatters"; +import { formatConnectorLabel, getAgentInitials } from "../../lib/formatters"; import { EmptyState } from "../ui"; import { useT } from "../../i18n"; -import { buildOrgTree, layoutForest, flattenLayout, collectEdges, statusDotColor, adapterLabels, CARD_W, CARD_H, CHART_PADDING } from "./orgTreeLayout"; +import { buildOrgTree, layoutForest, flattenLayout, collectEdges, statusDotColor, CARD_W, CARD_H, CHART_PADDING } from "./orgTreeLayout"; export function OrgChart({ agents, connectors, onSelectAgent }: { agents: AgentRecord[]; connectors?: ConnectorRecord[]; onSelectAgent?: (agentId: string) => void }) { const t = useT(); @@ -75,8 +75,14 @@ export function OrgChart({ agents, connectors, onSelectAgent }: { agents: AgentR return (
- {[{ label: "+", ariaLabel: t("org.zoomIn"), action: zoomIn }, { label: "\u2212", ariaLabel: t("org.zoomOut"), action: zoomOut }, { label: t("org.fit"), ariaLabel: t("org.fitChart"), action: fitToScreen }].map((btn) => ( - + {[ + { icon: Plus, ariaLabel: t("org.zoomIn"), action: zoomIn }, + { icon: Minus, ariaLabel: t("org.zoomOut"), action: zoomOut }, + { icon: CornersOut, ariaLabel: t("org.fitChart"), action: fitToScreen }, + ].map(({ icon: Icon, ariaLabel, action }) => ( + ))}
@@ -93,9 +99,7 @@ export function OrgChart({ agents, connectors, onSelectAgent }: { agents: AgentR {allNodes.map((node) => { const dotColor = statusDotColor[node.agent.status] ?? "var(--muted-foreground)"; const connectorRecord = connectors?.find((c) => c.id === node.agent.connectorId); - const connectorLabel = (connectorRecord?.id.startsWith("claude_compat") && connectorRecord.notes) - ? connectorRecord.notes - : adapterLabels[node.agent.connectorId] ?? node.agent.connectorId; + const connectorLabel = formatConnectorLabel(connectorRecord, node.agent.connectorId); const initials = getAgentInitials(node.agent.name); const isRunning = node.agent.status === "running"; const isActive = node.agent.status === "active" || isRunning; @@ -122,7 +126,7 @@ export function OrgChart({ agents, connectors, onSelectAgent }: { agents: AgentR {node.agent.name} {node.agent.title || node.agent.role}
- {connectorLabel} + {connectorLabel} {node.agent.heartbeatEnabled ? : null}
diff --git a/src/renderer/components/organization/orgTreeLayout.ts b/src/renderer/components/organization/orgTreeLayout.ts index 742d3373..cefc7dad 100644 --- a/src/renderer/components/organization/orgTreeLayout.ts +++ b/src/renderer/components/organization/orgTreeLayout.ts @@ -94,19 +94,3 @@ export const statusDotColor: Record = { terminated: "var(--muted-foreground)", pending_approval: "var(--destructive)", }; - -export const adapterLabels: Record = { - claude_local: "Claude", - claude_compatible: "Compatible", - claude_compat_2: "Compatible 2", - claude_compat_3: "Compatible 3", - claude_compat_4: "Compatible 4", - claude_compat_5: "Compatible 5", - claude_compat_6: "Compatible 6", - claude_compat_7: "Compatible 7", - claude_compat_8: "Compatible 8", - claude_compat_9: "Compatible 9", - claude_compat_10: "Compatible 10", - codex_local: "Codex", - gemini_local: "Gemini", -}; diff --git a/src/renderer/components/ui/icons.ts b/src/renderer/components/ui/icons.ts index ac6e1e98..4097b841 100644 --- a/src/renderer/components/ui/icons.ts +++ b/src/renderer/components/ui/icons.ts @@ -43,6 +43,7 @@ export { Clock, ClockCounterClockwise, Command, + CornersOut, Copy, Cpu, CurrencyCircleDollar, diff --git a/src/renderer/lib/formatters.ts b/src/renderer/lib/formatters.ts index b480fb85..fe432551 100644 --- a/src/renderer/lib/formatters.ts +++ b/src/renderer/lib/formatters.ts @@ -46,6 +46,19 @@ export function getAgentInitials(name: string): string { .toUpperCase(); } +/** + * Resolve the user-visible label for a connector reference. The org chart + * and agent roster share this so there is one definition of "what do I + * show for `agent.connectorId`?" — prefer the registered label, fall + * back to the raw id when a connector row is missing (e.g. pending sync). + */ +export function formatConnectorLabel( + connector: { label?: string | null; id?: string | null } | null | undefined, + fallbackConnectorId: string, +): string { + return connector?.label || connector?.id || fallbackConnectorId; +} + export function formatDuration(seconds: number): string { if (seconds < 60) return `${seconds}s`; const minutes = Math.floor(seconds / 60);