agents sidebar: fold org/company/team/agent tree into one pane
The Agents tier used to render a flat list of agent cards with an "Add to teams" button pinned to the bottom. Swap that for the same nested tree the Visualizations tier already uses so the whole workforce reads from one collapsible view. - treeRoots is now worldRoots on both tiers (no more clawNode flat fallback); the Agents tier's selectLevel stays "claw" so the Wrench → select → Delete flow keeps its agent-only scope. - Drop the "Add to teams" footer button plus its addTeamOpen state, AddToTeamModal render, and import. - Header on the Agents tier now shows the full breakdown: N ORGS · N CO · N TEAMS · N AGENTS.
This commit is contained in:
@@ -22,7 +22,7 @@ import { panelParsers, type DeviceSize } from "@/lib/url/panel-params";
|
|||||||
import { type FlowItem } from "./flow/TopologyFlow";
|
import { type FlowItem } from "./flow/TopologyFlow";
|
||||||
import { WorldCanvas } from "../world/WorldCanvas";
|
import { WorldCanvas } from "../world/WorldCanvas";
|
||||||
import { ObservePanel } from "../observe/ObservePanel";
|
import { ObservePanel } from "../observe/ObservePanel";
|
||||||
import { StructureTree, orgNode, clawNode, type TreeItem } from "./StructureTree";
|
import { StructureTree, orgNode, type TreeItem } from "./StructureTree";
|
||||||
import { ResearchList } from "./ResearchList";
|
import { ResearchList } from "./ResearchList";
|
||||||
import { ResearchCanvas } from "./ResearchCanvas";
|
import { ResearchCanvas } from "./ResearchCanvas";
|
||||||
import { LoopsList } from "./LoopsList";
|
import { LoopsList } from "./LoopsList";
|
||||||
@@ -43,7 +43,6 @@ import { BrainRegistryPanel } from "./BrainRegistryPanel";
|
|||||||
import { BrainHistoryModal } from "./BrainHistoryModal";
|
import { BrainHistoryModal } from "./BrainHistoryModal";
|
||||||
import { TeamRunsModal } from "./TeamRunsModal";
|
import { TeamRunsModal } from "./TeamRunsModal";
|
||||||
import { ReapProgressModal, type ReapKind } from "./ReapProgressModal";
|
import { ReapProgressModal, type ReapKind } from "./ReapProgressModal";
|
||||||
import { AddToTeamModal } from "./AddToTeamModal";
|
|
||||||
import { AddToCompanyModal } from "./AddToCompanyModal";
|
import { AddToCompanyModal } from "./AddToCompanyModal";
|
||||||
import { AddToOrgModal } from "./AddToOrgModal";
|
import { AddToOrgModal } from "./AddToOrgModal";
|
||||||
import { DevicePanel } from "@/components/computer/DevicePanel";
|
import { DevicePanel } from "@/components/computer/DevicePanel";
|
||||||
@@ -280,7 +279,6 @@ export function Dashboard({ user, orgs, claws }: { user?: { display_name?: strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Grouping modals: claws→team, teams→company, companies→org.
|
// Grouping modals: claws→team, teams→company, companies→org.
|
||||||
const [addTeamOpen, setAddTeamOpen] = useState(false);
|
|
||||||
const [addCompanyOpen, setAddCompanyOpen] = useState(false);
|
const [addCompanyOpen, setAddCompanyOpen] = useState(false);
|
||||||
const [addOrgOpen, setAddOrgOpen] = useState(false);
|
const [addOrgOpen, setAddOrgOpen] = useState(false);
|
||||||
|
|
||||||
@@ -508,7 +506,11 @@ export function Dashboard({ user, orgs, claws }: { user?: { display_name?: strin
|
|||||||
return roots;
|
return roots;
|
||||||
};
|
};
|
||||||
const worldCanvasRoots: TreeItem[] = narrowRoots(worldRoots, worldSel);
|
const worldCanvasRoots: TreeItem[] = narrowRoots(worldRoots, worldSel);
|
||||||
const treeRoots: TreeItem[] = isClaw ? allAgents.map(clawNode) : worldRoots;
|
// Both the World and Agents tiers now share the same collapsible org →
|
||||||
|
// company → team → agent tree — a single pane onto the whole workforce.
|
||||||
|
// `selectLevel` below still constrains selection to agents on the Agents
|
||||||
|
// tier so bulk-delete stays claw-scoped.
|
||||||
|
const treeRoots: TreeItem[] = worldRoots;
|
||||||
const treeActiveId = isClaw ? agentId : worldSel;
|
const treeActiveId = isClaw ? agentId : worldSel;
|
||||||
const treeAutoExpand: string[] = [];
|
const treeAutoExpand: string[] = [];
|
||||||
|
|
||||||
@@ -607,7 +609,7 @@ export function Dashboard({ user, orgs, claws }: { user?: { display_name?: strin
|
|||||||
) : isInfra || isResearch || isLoops || isRepos ? null : (
|
) : isInfra || isResearch || isLoops || isRepos ? null : (
|
||||||
<div style={{ padding: "16px 16px 12px", borderBottom: "1px solid rgba(255,255,255,.06)", display: "flex", alignItems: "flex-start", gap: 8 }}>
|
<div style={{ padding: "16px 16px 12px", borderBottom: "1px solid rgba(255,255,255,.06)", display: "flex", alignItems: "flex-start", gap: 8 }}>
|
||||||
<div style={{ flex: 1, minWidth: 0 }}>
|
<div style={{ flex: 1, minWidth: 0 }}>
|
||||||
<div style={{ fontFamily: mono, fontSize: 10, letterSpacing: ".12em", color: "#5a5a62", marginBottom: 6 }}>{allAgents.length} AGENT{allAgents.length === 1 ? "" : "S"}</div>
|
<div style={{ fontFamily: mono, fontSize: 10, letterSpacing: ".12em", color: "#5a5a62", marginBottom: 6 }}>{orgs.length} ORG{orgs.length === 1 ? "" : "S"} · {allCompanies.length} CO · {orgs.flatMap((o) => o.companies).reduce((n, c) => n + c.teams.length, 0)} TEAM{orgs.flatMap((o) => o.companies).reduce((n, c) => n + c.teams.length, 0) === 1 ? "" : "S"} · {allAgents.length} AGENT{allAgents.length === 1 ? "" : "S"}</div>
|
||||||
<div style={{ fontSize: 18, fontWeight: 700, color: "#f3f3f5", letterSpacing: "-.01em" }}>Agents</div>
|
<div style={{ fontSize: 18, fontWeight: 700, color: "#f3f3f5", letterSpacing: "-.01em" }}>Agents</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" onClick={() => { setSelectMode((v) => { if (v) setSelectedAgents(new Set()); return !v; }); }} title="Select agents to manage" aria-label="Select agents" style={{ flex: "none", width: 34, height: 34, borderRadius: 9, border: `1px solid ${selectMode ? "rgba(255,111,97,.5)" : "rgba(255,255,255,.12)"}`, background: selectMode ? "rgba(255,111,97,.12)" : "transparent", color: selectMode ? "#ff6f61" : "#9a9aa2", cursor: "pointer", display: "inline-flex", alignItems: "center", justifyContent: "center" }}><Wrench aria-hidden size={16} /></button>
|
<button type="button" onClick={() => { setSelectMode((v) => { if (v) setSelectedAgents(new Set()); return !v; }); }} title="Select agents to manage" aria-label="Select agents" style={{ flex: "none", width: 34, height: 34, borderRadius: 9, border: `1px solid ${selectMode ? "rgba(255,111,97,.5)" : "rgba(255,255,255,.12)"}`, background: selectMode ? "rgba(255,111,97,.12)" : "transparent", color: selectMode ? "#ff6f61" : "#9a9aa2", cursor: "pointer", display: "inline-flex", alignItems: "center", justifyContent: "center" }}><Wrench aria-hidden size={16} /></button>
|
||||||
@@ -663,10 +665,6 @@ export function Dashboard({ user, orgs, claws }: { user?: { display_name?: strin
|
|||||||
<button type="button" onClick={() => { setSelectMode(false); setSelectedAgents(new Set()); }} style={{ flex: "none", padding: "9px 14px", borderRadius: 9, border: "1px solid rgba(255,255,255,.14)", background: "transparent", color: "#9a9aa2", fontSize: 12.5, fontWeight: 600, cursor: "pointer" }}>Cancel</button>
|
<button type="button" onClick={() => { setSelectMode(false); setSelectedAgents(new Set()); }} style={{ flex: "none", padding: "9px 14px", borderRadius: 9, border: "1px solid rgba(255,255,255,.14)", background: "transparent", color: "#9a9aa2", fontSize: 12.5, fontWeight: 600, cursor: "pointer" }}>Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : isClaw ? (
|
|
||||||
<div style={{ flex: "none", borderTop: "1px solid rgba(255,255,255,.08)", padding: "10px 12px" }}>
|
|
||||||
<button type="button" onClick={() => setAddTeamOpen(true)} style={{ width: "100%", display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 7, padding: "9px 0", borderRadius: 9, border: "1px solid rgba(94,200,216,.35)", background: "rgba(94,200,216,.08)", color: "#5ec8d8", fontSize: 12.5, fontWeight: 600, cursor: "pointer" }}><Users aria-hidden size={14} /> Add to teams</button>
|
|
||||||
</div>
|
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -906,7 +904,6 @@ export function Dashboard({ user, orgs, claws }: { user?: { display_name?: strin
|
|||||||
{reapOpen ? <ReapProgressModal items={selectedItems} kind={reapKind} onClose={() => setReapOpen(false)} onDone={() => { setReapOpen(false); setSelectMode(false); setSelectedAgents(new Set()); router.refresh(); }} /> : null}
|
{reapOpen ? <ReapProgressModal items={selectedItems} kind={reapKind} onClose={() => setReapOpen(false)} onDone={() => { setReapOpen(false); setSelectMode(false); setSelectedAgents(new Set()); router.refresh(); }} /> : null}
|
||||||
|
|
||||||
{/* Group existing claws into a new named team, then land on its team page. */}
|
{/* Group existing claws into a new named team, then land on its team page. */}
|
||||||
{addTeamOpen ? <AddToTeamModal claws={claws} onClose={() => setAddTeamOpen(false)} /> : null}
|
|
||||||
|
|
||||||
{/* Group existing teams into a new named company, then land on its page. */}
|
{/* Group existing teams into a new named company, then land on its page. */}
|
||||||
{addCompanyOpen ? (
|
{addCompanyOpen ? (
|
||||||
|
|||||||
Reference in New Issue
Block a user