feat: complete reorganize-long-files cleanup
- Extract tool instance lifecycle endpoints (start/stop/restart/delete) from api/tool/tool_instances.py into new api/tool/tool_lifecycle.py. - Register tool_lifecycle_router in main.py and api/tool/__init__.py. - Extract inline WorkspaceDetailPage components into components/features/workspace/: detail header, tab bars, file/git/tools/settings panels. Slim page from ~446 to ~62 lines. - Update OpenSpec reorganize-long-files tasks to reflect completed work and current source state; mark change completed. - Regenerate project maps. Quality gates: python3 -m py_compile (backend clean), npm run typecheck, npm run lint, npm test -- --run (87 passed), pytest workspace integration and unit tests (27 passed, 1 skipped).
This commit is contained in:
@@ -4,114 +4,114 @@ import { MemoryRouter } from "react-router-dom";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
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,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
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>
|
||||
);
|
||||
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();
|
||||
});
|
||||
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>
|
||||
);
|
||||
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");
|
||||
});
|
||||
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>
|
||||
);
|
||||
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();
|
||||
});
|
||||
expect(screen.getByText(/are you sure/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user