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; }