feat: complete workspace-first-ui cleanup and tests
- Delete dead repo-workspace code: RepoWorkspacePage, useRepoWorkspace, WorkspaceLayout, FileBrowser, old git components (git-toolbar, file-editor, commit-panel), and repo-workspace.css. - Fix stale backend test imports for moved models/services. - Add GitOperations unit tests. - Add integration tests for workspace files, git, and instances endpoints. - Add frontend tests for WorkspaceDetailPage and ProjectCard. - Update OpenSpec workspace-first-ui tasks and mark change completed. - Regenerate project maps. Quality gates: npm run typecheck, npm run lint, npm test -- --run (87 passed), python3 -m py_compile on changed backend files, pytest backend workspace tests.
This commit is contained in:
@@ -2,13 +2,14 @@
|
||||
dir: apps/web/src/components/features/project
|
||||
|
||||
## role
|
||||
Provides UI components for managing projects, including cards, dialogs, and repository settings with full CRUD operations and Git integration.
|
||||
Provides React components for project management UI including project cards, creation/editing dialogs, and repository settings with CRUD operations.
|
||||
## parent
|
||||
index: apps/web/src/components/features/.pi-map.index.md
|
||||
map: apps/web/src/components/features/.pi-map.md
|
||||
## children
|
||||
-
|
||||
## files
|
||||
- ProjectCard.test.tsx
|
||||
- ProjectCard.tsx
|
||||
- ProjectDialog.tsx
|
||||
- repositories-settings-tab.test.tsx
|
||||
@@ -21,6 +22,6 @@ map: apps/web/src/components/features/project/.pi-map.md
|
||||
- change project behavior
|
||||
read: ProjectCard.tsx, ProjectDialog.tsx, repositories-settings-tab.tsx
|
||||
- update project tests
|
||||
read: repositories-settings-tab.test.tsx
|
||||
read: ProjectCard.test.tsx, repositories-settings-tab.test.tsx
|
||||
## dirty
|
||||
-
|
||||
|
||||
@@ -4,17 +4,18 @@ dir: apps/web/src/components/features/project
|
||||
index: apps/web/src/components/features/project/.pi-map.index.md
|
||||
|
||||
## role
|
||||
Provides UI components for managing projects, including cards, dialogs, and repository settings with full CRUD operations and Git integration.
|
||||
Provides React components for project management UI including project cards, creation/editing dialogs, and repository settings with CRUD operations.
|
||||
## files
|
||||
- ProjectCard.test.tsx | Unit tests for the ProjectCard component verifying rendering, workspace creation, and delete confirmation behavior. | dep: @testing-library/jest-dom/vitest, @testing-library/react, react-router-dom, vitest, ./ProjectCard, ../../../types, @testing-library/jest-dom, ProjectCard, types
|
||||
- ProjectCard.tsx | Renders an expandable project card displaying project info, repositories, and associated workspaces with CRUD actions. | exp: ProjectCard | dep: ../../icon, ../workspace/workspace-create-form, ../../../types, Icon, WorkspaceCreateForm, ProjectWithRepos, WorkspaceSummary
|
||||
- ProjectDialog.tsx | Renders a modal dialog for creating or editing a project with name/description inputs and cancel/submit actions. | exp: ProjectDialog | dep: ../../icon, React, icon
|
||||
- repositories-settings-tab.test.tsx | Tests the RepositoriesSettingsTab component's repository creation flows including full URL cloning, owner/repo mode with SSH key selection, and SSH URL validation. | dep: @testing-library/react, vitest, ./repositories-settings-tab, ../../../api/git-repositories, ../../../api/ssh-keys, react-router-dom
|
||||
- repositories-settings-tab.tsx | A React component that displays and manages Git repositories for a project, allowing users to list, create, and delete repositories. | exp: RepositoriesSettingsTab | dep: react, react-router-dom, ../../../api/git-repositories, ./repository-create-dialog, ../../icon
|
||||
- repository-create-dialog.tsx | React dialog component for creating or cloning Git repositories with URL validation and SSH key selection. | exp: RepositoryCreateDialog | dep: react, ../../../api/git-repositories, ../../../api/ssh-keys, ../../icon
|
||||
## arch
|
||||
Feature-based component architecture with compound UI patterns (card/dialog/tab), form handling for CRUD, and SSH-aware Git repository management with validation testing.
|
||||
Feature-based component architecture with compound component patterns (card + dialog), test co-location, and separation of presentational components from business logic through dialog-based workflows.
|
||||
## tags
|
||||
repositories, project, dialog, react, create, settings, icon, repository
|
||||
project, repositories, dialog, react, create, settings, icon, repository
|
||||
## symbols
|
||||
- ProjectCard
|
||||
- ProjectDialog
|
||||
@@ -24,6 +25,6 @@ repositories, project, dialog, react, create, settings, icon, repository
|
||||
- change project behavior
|
||||
read: ProjectCard.tsx, ProjectDialog.tsx, repositories-settings-tab.tsx
|
||||
- update project tests
|
||||
read: repositories-settings-tab.test.tsx
|
||||
read: ProjectCard.test.tsx, repositories-settings-tab.test.tsx
|
||||
## dirty
|
||||
-
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
|
||||
import { MemoryRouter } from "react-router-dom";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
import { ProjectCard } from "./ProjectCard";
|
||||
import type { ProjectWithRepos } from "../../../types";
|
||||
|
||||
const mockProject: ProjectWithRepos = {
|
||||
id: "proj-1",
|
||||
name: "Alpha Project",
|
||||
description: "First project",
|
||||
owner_id: "user-1",
|
||||
default_ssh_key_id: null,
|
||||
created_at: "2026-06-01T00:00:00Z",
|
||||
repositories: [
|
||||
{
|
||||
id: "repo-1",
|
||||
name: "my-repo",
|
||||
remote_url: "https://example.com/repo.git",
|
||||
workspaces: [
|
||||
{
|
||||
id: "ws-1",
|
||||
name: "dev",
|
||||
branch: "main",
|
||||
status: "ready",
|
||||
instance_count: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
describe("ProjectCard", () => {
|
||||
it("renders project name and repository", () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<ProjectCard
|
||||
project={mockProject}
|
||||
expanded={true}
|
||||
deleteConfirm={false}
|
||||
workspaceLoading={null}
|
||||
showCreateForm={null}
|
||||
onToggle={vi.fn()}
|
||||
onEdit={vi.fn()}
|
||||
onDelete={vi.fn()}
|
||||
onConfirmDelete={vi.fn()}
|
||||
onCancelDelete={vi.fn()}
|
||||
onCreateWorkspace={vi.fn()}
|
||||
onWorkspaceAction={vi.fn()}
|
||||
onCancelCreate={vi.fn()}
|
||||
onCreated={vi.fn()}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
expect(screen.getByText("Alpha Project")).toBeInTheDocument();
|
||||
expect(screen.getByText("my-repo")).toBeInTheDocument();
|
||||
expect(screen.getByText("dev")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls onCreateWorkspace when new workspace button is clicked", () => {
|
||||
const onCreateWorkspace = vi.fn();
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<ProjectCard
|
||||
project={mockProject}
|
||||
expanded={true}
|
||||
deleteConfirm={false}
|
||||
workspaceLoading={null}
|
||||
showCreateForm={null}
|
||||
onToggle={vi.fn()}
|
||||
onEdit={vi.fn()}
|
||||
onDelete={vi.fn()}
|
||||
onConfirmDelete={vi.fn()}
|
||||
onCancelDelete={vi.fn()}
|
||||
onCreateWorkspace={onCreateWorkspace}
|
||||
onWorkspaceAction={vi.fn()}
|
||||
onCancelCreate={vi.fn()}
|
||||
onCreated={vi.fn()}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: /new workspace/i }));
|
||||
expect(onCreateWorkspace).toHaveBeenCalledWith("repo-1");
|
||||
});
|
||||
|
||||
it("shows delete confirmation", () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<ProjectCard
|
||||
project={mockProject}
|
||||
expanded={true}
|
||||
deleteConfirm={true}
|
||||
workspaceLoading={null}
|
||||
showCreateForm={null}
|
||||
onToggle={vi.fn()}
|
||||
onEdit={vi.fn()}
|
||||
onDelete={vi.fn()}
|
||||
onConfirmDelete={vi.fn()}
|
||||
onCancelDelete={vi.fn()}
|
||||
onCreateWorkspace={vi.fn()}
|
||||
onWorkspaceAction={vi.fn()}
|
||||
onCancelCreate={vi.fn()}
|
||||
onCreated={vi.fn()}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
expect(screen.getByText(/are you sure/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user