sidebar history: drop workspace filter, project-only

Removes the Workspace section from the Sessions filter dropdown.
Final dropdown is All + Project. Simplifies the filter discriminated
union (drops the "workspace" variant), the predicate, and the
hook-derived option list. Workspace mapping is still used internally
to map session cwd to project for the Project filter and for hiding
unmapped agents.

E2E journey simplified — the workspace-filter step is gone, including
its brittle accessible-name regex.
This commit is contained in:
Mohamed Boudra
2026-05-08 18:31:35 +07:00
parent e9c3753466
commit 670e6a6fdd
8 changed files with 16 additions and 106 deletions
@@ -256,10 +256,6 @@ async function chooseSessionsFilter(page: Page, name: string | RegExp) {
await page.getByRole("button", { name }).click();
}
async function chooseWorkspaceSessionsFilter(page: Page, workspaceId: string) {
await chooseSessionsFilter(page, new RegExp(`^${escapeRegex(workspaceId)}\\s`));
}
async function chooseProjectSessionsFilter(page: Page, projectName: string) {
await chooseSessionsFilter(page, new RegExp(`^${escapeRegex(projectName)}$`));
}
@@ -319,11 +315,6 @@ async function runSidebarHistorySessionsJourney(page: Page) {
await switchSidebarToWorkspaces(page, seeded);
await switchSidebarToSessions(page);
await chooseWorkspaceSessionsFilter(page, seeded.firstWorkspace.workspaceId);
await expectOnlySidebarSessionRows(page, {
visible: [middle, oldest],
hidden: [newest],
});
await chooseProjectSessionsFilter(page, seeded.secondProjectName);
await expectOnlySidebarSessionRows(page, {
visible: [newest],
@@ -351,9 +342,7 @@ async function runSidebarHistorySessionsJourney(page: Page) {
test.describe("Sidebar History Sessions journey", () => {
test.describe.configure({ timeout: 300_000 });
test("toggles sessions, filters by workspace and project, and opens a session tab", async ({
page,
}) => {
test("toggles sessions, filters by project, and opens a session tab", async ({ page }) => {
await runSidebarHistorySessionsJourney(page);
});
});
@@ -14,14 +14,14 @@ describe("useSidebarSessionsController", () => {
act(() => {
result.current.setSidebarSessionFilter({
type: "workspace",
workspaceKey: "server-1:workspace-1",
type: "project",
projectKey: "project-a",
});
});
expect(result.current.sidebarSessionFilter).toEqual({
type: "workspace",
workspaceKey: "server-1:workspace-1",
type: "project",
projectKey: "project-a",
});
rerender({ serverId: "server-2" });
@@ -76,20 +76,6 @@ describe("sidebar session filtering", () => {
expect(visibleIds).toEqual(["main", "docs", "api"]);
});
it("filters by workspace", () => {
const lookup = createSidebarSessionWorkspaceLookup(WORKSPACES);
const visibleIds = AGENTS.filter((agent) =>
shouldIncludeSidebarSessionAgent({
agent,
filter: { type: "workspace", workspaceKey: "server-1:workspace-2" },
lookup,
}),
).map((agent) => agent.id);
expect(visibleIds).toEqual(["docs"]);
});
it("filters by project", () => {
const lookup = createSidebarSessionWorkspaceLookup(WORKSPACES);
@@ -121,7 +107,6 @@ describe("sidebar session filtering", () => {
});
expect(availability).toEqual({
workspaceKeys: ["server-1:workspace-1"],
projectKeys: ["project-a"],
});
const filterProjects = deriveSidebarSessionFilterProjects({
@@ -192,11 +177,13 @@ describe("sidebar session filtering", () => {
},
],
availability,
workspaceNameByKey: new Map([["server-1:workspace-1", "Main"]]),
});
expect(filterProjects.map(projectWorkspaceKeys)).toEqual([
{ projectKey: "project-a", workspaceKeys: ["server-1:workspace-1"] },
{
projectKey: "project-a",
workspaceKeys: ["server-1:workspace-1", "server-1:workspace-3"],
},
]);
});
});
@@ -8,7 +8,6 @@ export interface SidebarSessionWorkspaceLookup {
}
export interface SidebarSessionFilterAvailability {
workspaceKeys: readonly string[];
projectKeys: readonly string[];
}
@@ -75,9 +74,6 @@ export function shouldIncludeSidebarSessionAgent(input: {
if (input.filter.type === "all") {
return true;
}
if (input.filter.type === "workspace") {
return workspace.workspaceKey === input.filter.workspaceKey;
}
return workspace.projectKey === input.filter.projectKey;
}
@@ -85,7 +81,6 @@ export function deriveSidebarSessionFilterAvailability(input: {
agents: readonly SidebarSessionAgent[];
lookup: SidebarSessionWorkspaceLookup;
}): SidebarSessionFilterAvailability {
const workspaceKeys = new Set<string>();
const projectKeys = new Set<string>();
for (const agent of input.agents) {
@@ -96,12 +91,10 @@ export function deriveSidebarSessionFilterAvailability(input: {
if (!workspace) {
continue;
}
workspaceKeys.add(workspace.workspaceKey);
projectKeys.add(workspace.projectKey);
}
return {
workspaceKeys: Array.from(workspaceKeys).sort(),
projectKeys: Array.from(projectKeys).sort(),
};
}
@@ -109,13 +102,11 @@ export function deriveSidebarSessionFilterAvailability(input: {
export function deriveSidebarSessionFilterProjects(input: {
projects: readonly SidebarProjectEntry[];
availability: SidebarSessionFilterAvailability;
workspaceNameByKey: ReadonlyMap<string, string>;
}): SidebarProjectEntry[] {
if (input.projects.length === 0 || input.availability.workspaceKeys.length === 0) {
if (input.projects.length === 0 || input.availability.projectKeys.length === 0) {
return [];
}
const visibleWorkspaceKeys = new Set(input.availability.workspaceKeys);
const visibleProjectKeys = new Set(input.availability.projectKeys);
const projects: SidebarProjectEntry[] = [];
@@ -123,16 +114,7 @@ export function deriveSidebarSessionFilterProjects(input: {
if (!visibleProjectKeys.has(project.projectKey)) {
continue;
}
const workspaces = project.workspaces
.filter((workspace) => visibleWorkspaceKeys.has(workspace.workspaceKey))
.map((workspace) => {
const name = input.workspaceNameByKey.get(workspace.workspaceKey);
return name && name !== workspace.name ? Object.assign({}, workspace, { name }) : workspace;
});
if (workspaces.length === 0) {
continue;
}
projects.push({ ...project, workspaces });
projects.push(project);
}
return projects;
@@ -128,22 +128,6 @@ function SidebarSessionsFilterMenu({
</DropdownMenuItem>
{visibleFilterProjects.length > 0 ? (
<>
<DropdownMenuSeparator />
<FilterSectionHeading>Workspace</FilterSectionHeading>
{visibleFilterProjects.flatMap((project) =>
project.workspaces.map((workspace) => (
<WorkspaceFilterItem
key={workspace.workspaceKey}
selected={
filter.type === "workspace" && filter.workspaceKey === workspace.workspaceKey
}
label={workspace.name}
description={project.projectName}
workspaceKey={workspace.workspaceKey}
onFilterChange={onFilterChange}
/>
)),
)}
<DropdownMenuSeparator />
<FilterSectionHeading>Project</FilterSectionHeading>
{visibleFilterProjects.map((project) => (
@@ -225,30 +209,6 @@ function FilterSectionHeading({ children }: { children: string }) {
);
}
function WorkspaceFilterItem({
selected,
label,
description,
workspaceKey,
onFilterChange,
}: {
selected: boolean;
label: string;
description: string;
workspaceKey: string;
onFilterChange: (filter: SidebarSessionFilter) => void;
}) {
const handleSelect = useCallback(() => {
onFilterChange({ type: "workspace", workspaceKey });
}, [onFilterChange, workspaceKey]);
return (
<DropdownMenuItem selected={selected} description={description} onSelect={handleSelect}>
{label}
</DropdownMenuItem>
);
}
function ProjectFilterItem({
selected,
label,
+1 -4
View File
@@ -2,10 +2,7 @@ import type { AggregatedAgent } from "@/hooks/use-aggregated-agents";
export type SidebarSessionViewMode = "workspaces" | "sessions";
export type SidebarSessionFilter =
| { type: "all" }
| { type: "workspace"; workspaceKey: string }
| { type: "project"; projectKey: string };
export type SidebarSessionFilter = { type: "all" } | { type: "project"; projectKey: string };
export interface SidebarSessionWorkspace {
serverId: string;
@@ -97,7 +97,7 @@ afterEach(() => {
});
describe("useVisibleSidebarSessionFilterProjects", () => {
it("uses the hydrated workspace branch label for workspace filter options", () => {
it("returns projects with mapped active sessions", () => {
act(() => {
useSessionStore.getState().initializeSession("server-1", {} as unknown as DaemonClient);
useSessionStore.getState().setWorkspaces("server-1", new Map([["workspace-1", WORKSPACE]]));
@@ -111,8 +111,6 @@ describe("useVisibleSidebarSessionFilterProjects", () => {
}),
);
expect(result.current[0]?.workspaces[0]?.name).toBe("feat-foo");
expect(result.current[0]?.workspaces[0]?.name).not.toBe("/abs/path/to/repo");
expect(result.current[0]?.workspaces[0]?.name).not.toBe("repo");
expect(result.current.map((project) => project.projectKey)).toEqual(["project-a"]);
});
});
@@ -14,7 +14,7 @@ import {
} from "./session-filtering";
const EMPTY_WORKSPACES: SidebarSessionWorkspace[] = [];
const EMPTY_AVAILABILITY = { workspaceKeys: [], projectKeys: [] } as const;
const EMPTY_AVAILABILITY = { projectKeys: [] } as const;
export function useSidebarSessionWorkspaces(input: {
serverId: string | null;
@@ -108,10 +108,7 @@ export function useVisibleSidebarSessionFilterProjects(input: {
deriveSidebarSessionFilterProjects({
projects: input.projects,
availability,
workspaceNameByKey: new Map(
workspaces.map((workspace) => [workspace.workspaceKey, workspace.workspaceName]),
),
}),
[availability, input.projects, workspaces],
[availability, input.projects],
);
}