diff --git a/frontend/src/renderer/components/Sidebar.test.tsx b/frontend/src/renderer/components/Sidebar.test.tsx index cd71be74..8c26c235 100644 --- a/frontend/src/renderer/components/Sidebar.test.tsx +++ b/frontend/src/renderer/components/Sidebar.test.tsx @@ -1,6 +1,5 @@ import { SidebarProvider } from "@/components/ui/sidebar"; -import { render, screen, waitFor } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; +import { render, screen } from "@testing-library/react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { Sidebar } from "./Sidebar"; import type { WorkspaceSummary } from "../types/workspace"; @@ -25,24 +24,20 @@ const workspace: WorkspaceSummary = { sessions: [], }; -function renderSidebar(onRemoveProject = vi.fn().mockResolvedValue(undefined)) { +function renderSidebar() { render( , ); - return onRemoveProject; } beforeEach(() => { navigateMock.mockReset(); - vi.spyOn(window, "confirm").mockReturnValue(true); - vi.spyOn(window, "alert").mockImplementation(() => undefined); }); afterEach(() => { @@ -50,30 +45,6 @@ afterEach(() => { }); describe("Sidebar", () => { - it("confirms project removal before calling the remove handler", async () => { - const user = userEvent.setup(); - const onRemoveProject = renderSidebar(); - - await user.click(screen.getByLabelText("Project actions for Project One")); - await user.click(await screen.findByRole("menuitem", { name: "Remove project" })); - - expect(window.confirm).toHaveBeenCalledWith( - "Remove project Project One? This stops its live sessions and removes it from the sidebar, but keeps the repository folder and stored history on disk.", - ); - await waitFor(() => expect(onRemoveProject).toHaveBeenCalledTimes(1)); - }); - - it("does not remove the project when confirmation is cancelled", async () => { - vi.mocked(window.confirm).mockReturnValue(false); - const user = userEvent.setup(); - const onRemoveProject = renderSidebar(); - - await user.click(screen.getByLabelText("Project actions for Project One")); - await user.click(await screen.findByRole("menuitem", { name: "Remove project" })); - - expect(onRemoveProject).not.toHaveBeenCalled(); - }); - it("hides the worker count in every state that reveals project actions", () => { renderSidebar(); diff --git a/frontend/src/renderer/components/Sidebar.tsx b/frontend/src/renderer/components/Sidebar.tsx index affc9e1a..0397ee67 100644 --- a/frontend/src/renderer/components/Sidebar.tsx +++ b/frontend/src/renderer/components/Sidebar.tsx @@ -1,16 +1,5 @@ import { useNavigate, useParams, useRouterState } from "@tanstack/react-router"; -import { - ChevronRight, - GitPullRequest, - Moon, - MoreHorizontal, - Plus, - Search, - Settings, - Sun, - Trash2, - Waypoints, -} from "lucide-react"; +import { ChevronRight, GitPullRequest, Moon, Plus, Search, Settings, Sun, Waypoints } from "lucide-react"; import { useState } from "react"; import { attentionZone, @@ -377,25 +366,6 @@ function ProjectItem({ } }; - const removeProject = async () => { - setRemoveError(null); - const confirmed = window.confirm( - `Remove project ${workspace.name}? This stops its live sessions and removes it from the sidebar, but keeps the repository folder and stored history on disk.`, - ); - if (!confirmed) return; - - setIsRemoving(true); - try { - await onRemoveProject(); - } catch (err) { - const message = err instanceof Error ? err.message : "Could not remove project"; - setRemoveError(message); - window.alert(message); - } finally { - setIsRemoving(false); - } - }; - return ( {/* project-sidebar__proj-row */} diff --git a/frontend/src/renderer/routes/_shell.tsx b/frontend/src/renderer/routes/_shell.tsx index 65674f44..9c2bbbcb 100644 --- a/frontend/src/renderer/routes/_shell.tsx +++ b/frontend/src/renderer/routes/_shell.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, Outlet, useNavigate, useParams } from "@tanstack/react-router"; +import { createFileRoute, Outlet, useNavigate } from "@tanstack/react-router"; import { useQueryClient } from "@tanstack/react-query"; -import { useCallback, useEffect, useState } from "react"; +import { type CSSProperties, useCallback, useEffect } from "react"; import { ShellTopbar } from "../components/ShellTopbar"; import { Sidebar } from "../components/Sidebar"; import { SidebarProvider } from "../components/ui/sidebar"; @@ -34,7 +34,6 @@ function errorMessage(error: unknown) { // instead of Zustand. The daemon-status effect runs here exactly once. function ShellLayout() { const navigate = useNavigate(); - const params = useParams({ strict: false }) as { projectId?: string }; const queryClient = useQueryClient(); const workspaceQuery = useWorkspaceQuery(); const workspaces = workspaceQuery.data ?? []; @@ -67,20 +66,6 @@ function ShellLayout() { [navigate, updateWorkspaces], ); - const removeProject = useCallback( - async (projectId: string) => { - const { error } = await apiClient.DELETE("/api/v1/projects/{id}", { params: { path: { id: projectId } } }); - if (error) throw new Error(apiErrorMessage(error)); - - updateWorkspaces((current) => current.filter((item) => item.id !== projectId)); - await queryClient.invalidateQueries({ queryKey: workspaceQueryKey }); - if (params.projectId === projectId) { - void navigate({ to: "/" }); - } - }, - [navigate, params.projectId, queryClient, updateWorkspaces], - ); - useEffect(() => { document.documentElement.dataset.theme = theme; document.documentElement.style.colorScheme = theme; @@ -113,7 +98,7 @@ function ShellLayout() { }, [navigate, workspaces]); return ( - + {/* The topbar spans the full window width above the sidebar row (the macOS traffic lights + TitlebarNav cluster sit in its left inset), and the sidebar hangs below it — so the sidebar border stops at the @@ -130,7 +115,7 @@ function ShellLayout() { onOpenChange={(open) => open !== isSidebarOpen && toggleSidebar()} open={isSidebarOpen} style={ - { "--sidebar-width": "var(--ao-sidebar-w, 240px)", "--sidebar-width-icon": "48px" } as React.CSSProperties + { "--sidebar-width": "var(--ao-sidebar-w, 240px)", "--sidebar-width-icon": "48px" } as CSSProperties } > - ); }