feat(KB-175): move file browser to header with workspace support
- Add workspace file APIs and hooks for session-scoped file browsing - Create WorkspaceSelector component for switching between workspaces - Update FileBrowserModal with workspace mode and improved UX - Add files button to header with workspace-aware file browsing - Add session files indicator to task cards for quick file access - Include comprehensive tests for all new components and hooks
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen, within } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { WorkspaceSelector } from "../WorkspaceSelector";
|
||||
import type { WorkspaceInfo } from "../../hooks/useWorkspaces";
|
||||
|
||||
const workspaces: WorkspaceInfo[] = [
|
||||
{
|
||||
id: "KB-123",
|
||||
label: "KB-123",
|
||||
title: "Implement a very long task title that should be truncated in the dropdown list",
|
||||
worktree: "/repo/.worktrees/kb-123",
|
||||
kind: "task",
|
||||
},
|
||||
{
|
||||
id: "KB-200",
|
||||
label: "KB-200",
|
||||
title: "Short title",
|
||||
worktree: "/repo/.worktrees/kb-200",
|
||||
kind: "task",
|
||||
},
|
||||
];
|
||||
|
||||
describe("WorkspaceSelector", () => {
|
||||
it("shows the project name when project root is selected", () => {
|
||||
render(
|
||||
<WorkspaceSelector
|
||||
currentWorkspace="project"
|
||||
projectName="kb"
|
||||
workspaces={workspaces}
|
||||
onSelect={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByRole("button", { name: /kb/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("opens the menu and highlights the current workspace", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<WorkspaceSelector
|
||||
currentWorkspace="KB-200"
|
||||
projectName="kb"
|
||||
workspaces={workspaces}
|
||||
onSelect={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
await user.click(screen.getByRole("button", { name: /KB-200/i }));
|
||||
|
||||
expect(screen.getByText("Project Root")).toBeInTheDocument();
|
||||
const menu = screen.getByRole("listbox", { name: /select workspace/i });
|
||||
const activeOption = within(menu).getByRole("button", { name: /KB-200 Short title/i });
|
||||
expect(activeOption.className).toContain("active");
|
||||
});
|
||||
|
||||
it("calls onSelect and closes when choosing a workspace", async () => {
|
||||
const user = userEvent.setup();
|
||||
const onSelect = vi.fn();
|
||||
render(
|
||||
<WorkspaceSelector
|
||||
currentWorkspace="project"
|
||||
projectName="kb"
|
||||
workspaces={workspaces}
|
||||
onSelect={onSelect}
|
||||
/>,
|
||||
);
|
||||
|
||||
await user.click(screen.getByRole("button", { name: /kb/i }));
|
||||
await user.click(screen.getByRole("button", { name: /KB-123/i }));
|
||||
|
||||
expect(onSelect).toHaveBeenCalledWith("KB-123");
|
||||
expect(screen.queryByText("Task Worktrees")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("truncates long task titles in the dropdown", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<WorkspaceSelector
|
||||
currentWorkspace="project"
|
||||
projectName="kb"
|
||||
workspaces={workspaces}
|
||||
onSelect={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
await user.click(screen.getByRole("button", { name: /kb/i }));
|
||||
|
||||
expect(screen.getByText(/Implement a very long task title that shoul/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/…$/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user