mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-25 10:42:45 +00:00
Adds a group-by-project toggle to the Sessions header. When ON, the flat session list becomes a grouped list — one section per project, preview-capped at 6 agents per project with "Show N more" / "Show less" controls per group. When OFF, the flat list stays as before. Architecture preserves the Phase 7b perf model: - Controller (useSidebarSessionsController) owns groupByProject and expandedProjects state. Expansion resets on grouping-off, host change, and filter change. Group-by persists across hosts as a UI preference. - A new useOrderedAgentProjectShape selector reactively subscribes to per-agent cwd via useStoreWithEqualityFn(..., shallow). When project assignments don't change, the array reference stays stable; when an agent's project changes, the parent re-derives groups. Shape objects are reused across renders when project fields are unchanged. - deriveGroupedSidebarSessions takes the resolved shape directly (no callback indirection) and returns ordered groups with visible/hidden ids based on per-project expansion state. - Header and Footer components are React.memo'd with primitive props only, so they don't re-render on irrelevant agent updates. Per-row status indicators continue to subscribe via the shared tab descriptor path, isolated from parent renders. - Project ordering: first-occurrence in the createdAt-desc id list, matching the user's mental model of "most-recent project first" and avoiding a per-render activity-timestamp computation. Visual primitive shared between the workspace tree project row and the new Sessions group header (packages/app/src/components/sidebar/ sidebar-project-row-visual.tsx) — no two systems for project visuals. The workspace tree wraps it with its own chevron/status; the Sessions header uses it bare. Tests added: state-machine cases on the controller, pure-helper coverage on grouping derivation, render-boundary stability for grouped data references across irrelevant updates and reactivity on project changes, and a footer click test.
57 lines
1.9 KiB
TypeScript
57 lines
1.9 KiB
TypeScript
import { useCallback, useEffect, useRef, useState } from "react";
|
|
import type { SidebarSessionFilter, SidebarSessionViewMode } from "./types";
|
|
|
|
export function useSidebarSessionsController({ serverId }: { serverId: string | null }) {
|
|
const previousServerIdRef = useRef(serverId);
|
|
const [sidebarViewMode, setSidebarViewMode] = useState<SidebarSessionViewMode>("workspaces");
|
|
const [sidebarSessionFilter, setSidebarSessionFilter] = useState<SidebarSessionFilter>({
|
|
type: "all",
|
|
});
|
|
const [groupByProject, setGroupByProjectState] = useState(false);
|
|
const [expandedProjects, setExpandedProjects] = useState<ReadonlySet<string>>(() => new Set());
|
|
|
|
const setGroupByProject = useCallback((next: boolean) => {
|
|
setGroupByProjectState(next);
|
|
if (!next) {
|
|
setExpandedProjects((previous) => (previous.size === 0 ? previous : new Set()));
|
|
}
|
|
}, []);
|
|
|
|
const setSidebarSessionFilterWithReset = useCallback((next: SidebarSessionFilter) => {
|
|
setSidebarSessionFilter(next);
|
|
setExpandedProjects((previous) => (previous.size === 0 ? previous : new Set()));
|
|
}, []);
|
|
|
|
const toggleProjectExpanded = useCallback((projectKey: string) => {
|
|
setExpandedProjects((previous) => {
|
|
const next = new Set(previous);
|
|
if (next.has(projectKey)) {
|
|
next.delete(projectKey);
|
|
} else {
|
|
next.add(projectKey);
|
|
}
|
|
return next;
|
|
});
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (previousServerIdRef.current === serverId) {
|
|
return;
|
|
}
|
|
previousServerIdRef.current = serverId;
|
|
setSidebarSessionFilter({ type: "all" });
|
|
setExpandedProjects((previous) => (previous.size === 0 ? previous : new Set()));
|
|
}, [serverId]);
|
|
|
|
return {
|
|
sidebarViewMode,
|
|
setSidebarViewMode,
|
|
sidebarSessionFilter,
|
|
setSidebarSessionFilter: setSidebarSessionFilterWithReset,
|
|
groupByProject,
|
|
expandedProjects,
|
|
setGroupByProject,
|
|
toggleProjectExpanded,
|
|
};
|
|
}
|