diff --git a/AgentCompany-New/src/renderer/src/pages/TeamPage.tsx b/AgentCompany-New/src/renderer/src/pages/TeamPage.tsx index 28994b0a..bd653072 100644 --- a/AgentCompany-New/src/renderer/src/pages/TeamPage.tsx +++ b/AgentCompany-New/src/renderer/src/pages/TeamPage.tsx @@ -81,27 +81,9 @@ export function TeamPage({ snapshot, actions }: PageProps) { {" "}{agents.length} {agents.length === 1 ? "agent" : "agents"}

-
+
Org
- {employees[0] ? ( -
- -
- ) : null} - {agents.length > 0 && } -
- {agents.map((agent) => ( - - ))} -
+
Roster
@@ -210,27 +192,50 @@ function OrgCard({ name, role, human = false }: { name: string; role: string; hu ); } -function OrgConnector({ slots }: { slots: number }) { - if (slots <= 1) { - return ( - - ); - } - const count = Math.min(4, slots); - const step = 100 / (count * 2); - const positions = Array.from({ length: count }, (_, i) => step * (2 * i + 1)); - const left = positions[0]; - const right = positions[positions.length - 1]; +function OrgChart({ boardChair, agents }: { boardChair: EmployeeRecord | null; agents: AgentRecord[] }) { + const childrenByManager = useMemo(() => { + const known = new Set(agents.map((agent) => agent.id)); + const map = new Map(); + for (const agent of agents) { + // Agents whose manager is missing (or the top-level CEO) hang off the root. + const key = agent.managerAgentId && known.has(agent.managerAgentId) ? agent.managerAgentId : "__root__"; + const list = map.get(key) ?? []; + list.push(agent); + map.set(key, list); + } + return map; + }, [agents]); + + const roots = childrenByManager.get("__root__") ?? []; + if (!boardChair && roots.length === 0) return null; + return ( - +
+
    +
  • + {boardChair ? : } + {roots.length > 0 && ( +
      + {roots.map((agent) => )} +
    + )} +
  • +
+
+ ); +} + +function OrgNode({ agent, childrenByManager }: { agent: AgentRecord; childrenByManager: Map }) { + const reports = childrenByManager.get(agent.id) ?? []; + return ( +
  • + + {reports.length > 0 && ( +
      + {reports.map((report) => )} +
    + )} +
  • ); } diff --git a/AgentCompany-New/src/renderer/src/styles.css b/AgentCompany-New/src/renderer/src/styles.css index f26882ea..ccbbd9c7 100644 --- a/AgentCompany-New/src/renderer/src/styles.css +++ b/AgentCompany-New/src/renderer/src/styles.css @@ -385,3 +385,48 @@ a { color: inherit; } gap: 2px; min-height: 0; } + +/* Hierarchical org chart: a real reporting tree with connector lines. */ +.org-tree { display: inline-block; min-width: 100%; text-align: center; margin-top: 18px; } +.org-tree ul { + position: relative; + display: flex; + justify-content: center; + margin: 0; + padding: 22px 0 0 0; + list-style: none; +} +.org-tree li { + position: relative; + padding: 22px 8px 0 8px; + list-style: none; +} +.org-tree li::before, .org-tree li::after { + content: ""; + position: absolute; + top: 0; + right: 50%; + width: 50%; + height: 22px; + border-top: 1px solid var(--border-strong); +} +.org-tree li::after { + right: auto; + left: 50%; + border-left: 1px solid var(--border-strong); +} +.org-tree li:only-child::before, .org-tree li:only-child::after { display: none; } +.org-tree li:only-child { padding-top: 22px; } +.org-tree li:first-child::before, .org-tree li:last-child::after { border: 0 none; } +.org-tree li:last-child::before { border-right: 1px solid var(--border-strong); } +.org-tree ul ul::before { + content: ""; + position: absolute; + top: 0; + left: 50%; + width: 0; + height: 22px; + border-left: 1px solid var(--border-strong); +} +.org-tree > ul { padding-top: 0; } +.org-tree > ul > li:only-child { padding-top: 0; }