From 195f00ba837bc7128ccc19dfd96fb3dc1c45d887 Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Wed, 18 Mar 2026 18:41:57 +0100 Subject: [PATCH] fix: remove sidebar search button --- src/features/app/components/Sidebar.test.tsx | 18 +- src/features/app/components/Sidebar.tsx | 162 ++---------------- src/features/app/components/SidebarHeader.tsx | 18 -- src/styles/sidebar.css | 125 -------------- 4 files changed, 16 insertions(+), 307 deletions(-) diff --git a/src/features/app/components/Sidebar.test.tsx b/src/features/app/components/Sidebar.test.tsx index 64800bcb7..daee34425 100644 --- a/src/features/app/components/Sidebar.test.tsx +++ b/src/features/app/components/Sidebar.test.tsx @@ -70,25 +70,11 @@ const baseProps = { }; describe("Sidebar", () => { - it("toggles the search bar from the header icon", () => { + it("does not render the removed sidebar search controls", () => { render(); - const toggleButton = screen.getByRole("button", { name: "Toggle search" }); + expect(screen.queryByRole("button", { name: "Toggle search" })).toBeNull(); expect(screen.queryByLabelText("Search projects")).toBeNull(); - - fireEvent.click(toggleButton); - const input = screen.getByLabelText("Search projects") as HTMLInputElement; - expect(input).toBeTruthy(); - - fireEvent.change(input, { target: { value: "alpha" } }); - expect(input.value).toBe("alpha"); - - fireEvent.click(toggleButton); - expect(screen.queryByLabelText("Search projects")).toBeNull(); - - fireEvent.click(toggleButton); - const reopened = screen.getByLabelText("Search projects") as HTMLInputElement; - expect(reopened.value).toBe(""); }); it("opens thread sort menu from the header filter button", () => { diff --git a/src/features/app/components/Sidebar.tsx b/src/features/app/components/Sidebar.tsx index 53ce98a06..b476b0137 100644 --- a/src/features/app/components/Sidebar.tsx +++ b/src/features/app/components/Sidebar.tsx @@ -14,7 +14,6 @@ import { FolderOpen } from "lucide-react"; import Copy from "lucide-react/dist/esm/icons/copy"; import GitBranch from "lucide-react/dist/esm/icons/git-branch"; import Plus from "lucide-react/dist/esm/icons/plus"; -import X from "lucide-react/dist/esm/icons/x"; import { PopoverMenuItem, PopoverSurface, @@ -33,7 +32,6 @@ import { useMenuController } from "../hooks/useMenuController"; import { useSidebarMenus } from "../hooks/useSidebarMenus"; import { useSidebarScrollFade } from "../hooks/useSidebarScrollFade"; import { useThreadRows } from "../hooks/useThreadRows"; -import { useDebouncedValue } from "../../../hooks/useDebouncedValue"; import { getUsageLabels } from "../utils/usageLabels"; import { formatRelativeTimeShort } from "../../../utils/time"; import type { ThreadStatusById } from "../../../utils/threadStatus"; @@ -180,8 +178,6 @@ export const Sidebar = memo(function Sidebar({ const [expandedWorkspaces, setExpandedWorkspaces] = useState( new Set(), ); - const [searchQuery, setSearchQuery] = useState(""); - const [isSearchOpen, setIsSearchOpen] = useState(false); const [addMenuAnchor, setAddMenuAnchor] = useState<{ workspaceId: string; top: number; @@ -228,8 +224,6 @@ export const Sidebar = memo(function Sidebar({ creditsLabel, showWeekly, } = getUsageLabels(accountRateLimits, usageShowRemaining); - const debouncedQuery = useDebouncedValue(searchQuery, 150); - const normalizedQuery = debouncedQuery.trim().toLowerCase(); const pendingUserInputKeys = useMemo( () => new Set( @@ -244,48 +238,6 @@ export const Sidebar = memo(function Sidebar({ [userInputRequests], ); - const isWorkspaceMatch = useCallback( - (workspace: WorkspaceInfo) => { - if (!normalizedQuery) { - return true; - } - return workspace.name.toLowerCase().includes(normalizedQuery); - }, - [normalizedQuery], - ); - - const renderHighlightedName = useCallback( - (name: string) => { - if (!normalizedQuery) { - return name; - } - const lower = name.toLowerCase(); - const parts: React.ReactNode[] = []; - let cursor = 0; - let matchIndex = lower.indexOf(normalizedQuery, cursor); - - while (matchIndex !== -1) { - if (matchIndex > cursor) { - parts.push(name.slice(cursor, matchIndex)); - } - parts.push( - - {name.slice(matchIndex, matchIndex + normalizedQuery.length)} - , - ); - cursor = matchIndex + normalizedQuery.length; - matchIndex = lower.indexOf(normalizedQuery, cursor); - } - - if (cursor < name.length) { - parts.push(name.slice(cursor)); - } - - return parts.length ? parts : name; - }, - [normalizedQuery], - ); - const accountEmail = accountInfo?.email?.trim() ?? ""; const accountButtonLabel = accountEmail ? accountEmail @@ -310,9 +262,6 @@ export const Sidebar = memo(function Sidebar({ }> = []; workspaces.forEach((workspace) => { - if (!isWorkspaceMatch(workspace)) { - return; - } const threads = threadsByWorkspace[workspace.id] ?? []; if (!threads.length) { return; @@ -369,41 +318,8 @@ export const Sidebar = memo(function Sidebar({ getThreadRows, getPinTimestamp, pinnedThreadsVersion, - isWorkspaceMatch, ]); - const cloneSourceIdsMatchingQuery = useMemo(() => { - if (!normalizedQuery) { - return new Set(); - } - const ids = new Set(); - workspaces.forEach((workspace) => { - const sourceId = workspace.settings.cloneSourceWorkspaceId?.trim(); - if (!sourceId) { - return; - } - if (isWorkspaceMatch(workspace)) { - ids.add(sourceId); - } - }); - return ids; - }, [isWorkspaceMatch, normalizedQuery, workspaces]); - - const filteredGroupedWorkspaces = useMemo( - () => - groupedWorkspaces - .map((group) => ({ - ...group, - workspaces: group.workspaces.filter( - (workspace) => - isWorkspaceMatch(workspace) || - cloneSourceIdsMatchingQuery.has(workspace.id), - ), - })) - .filter((group) => group.workspaces.length > 0), - [cloneSourceIdsMatchingQuery, groupedWorkspaces, isWorkspaceMatch], - ); - const getSortTimestamp = useCallback( (thread: ThreadSummary | undefined) => { if (!thread) { @@ -443,15 +359,10 @@ export const Sidebar = memo(function Sidebar({ cloneWorkspacesBySourceId.set(sourceId, list); }); - filteredGroupedWorkspaces.forEach((group) => { + groupedWorkspaces.forEach((group) => { group.workspaces.forEach((workspace) => { const rootThreads = threadsByWorkspace[workspace.id] ?? []; - const visibleClones = - normalizedQuery && !isWorkspaceMatch(workspace) - ? (cloneWorkspacesBySourceId.get(workspace.id) ?? []).filter((clone) => - isWorkspaceMatch(clone), - ) - : (cloneWorkspacesBySourceId.get(workspace.id) ?? []); + const visibleClones = cloneWorkspacesBySourceId.get(workspace.id) ?? []; let hasThreads = rootThreads.length > 0; let timestamp = getSortTimestamp(rootThreads[0]); @@ -472,19 +383,17 @@ export const Sidebar = memo(function Sidebar({ }); return activityById; }, [ - filteredGroupedWorkspaces, getSortTimestamp, - isWorkspaceMatch, - normalizedQuery, + groupedWorkspaces, threadsByWorkspace, workspaces, ]); const sortedGroupedWorkspaces = useMemo(() => { if (threadListOrganizeMode !== "by_project_activity") { - return filteredGroupedWorkspaces; + return groupedWorkspaces; } - return filteredGroupedWorkspaces.map((group) => ({ + return groupedWorkspaces.map((group) => ({ ...group, workspaces: group.workspaces.slice().sort((a, b) => { const aActivity = workspaceActivityById.get(a.id) ?? { @@ -505,7 +414,7 @@ export const Sidebar = memo(function Sidebar({ return a.name.localeCompare(b.name); }), })); - }, [filteredGroupedWorkspaces, threadListOrganizeMode, workspaceActivityById]); + }, [groupedWorkspaces, threadListOrganizeMode, workspaceActivityById]); const flatThreadRows = useMemo(() => { if (threadListOrganizeMode !== "threads_only") { @@ -519,7 +428,7 @@ export const Sidebar = memo(function Sidebar({ rows: FlatThreadRow[]; }> = []; - filteredGroupedWorkspaces.forEach((group) => { + groupedWorkspaces.forEach((group) => { group.workspaces.forEach((workspace) => { const threads = threadsByWorkspace[workspace.id] ?? []; if (!threads.length) { @@ -591,10 +500,10 @@ export const Sidebar = memo(function Sidebar({ }) .flatMap((group) => group.rows); }, [ - filteredGroupedWorkspaces, getPinTimestamp, getSortTimestamp, getThreadRows, + groupedWorkspaces, pinnedThreadsVersion, threadListOrganizeMode, threadsByWorkspace, @@ -606,7 +515,6 @@ export const Sidebar = memo(function Sidebar({ flatThreadRows, threadsByWorkspace, expandedWorkspaces, - normalizedQuery, threadListOrganizeMode, ], [ @@ -614,7 +522,6 @@ export const Sidebar = memo(function Sidebar({ flatThreadRows, threadsByWorkspace, expandedWorkspaces, - normalizedQuery, threadListOrganizeMode, ], ); @@ -636,7 +543,7 @@ export const Sidebar = memo(function Sidebar({ const groupedWorkspacesForRender = threadListOrganizeMode === "by_project_activity" ? sortedGroupedWorkspaces - : filteredGroupedWorkspaces; + : groupedWorkspaces; const isThreadsOnlyMode = threadListOrganizeMode === "threads_only"; const handleAllThreadsAddMenuToggle = useCallback( @@ -669,7 +576,6 @@ export const Sidebar = memo(function Sidebar({ }, [onAddAgent], ); - const isSearchActive = Boolean(normalizedQuery); const worktreesByParent = useMemo(() => { const worktrees = new Map(); @@ -779,15 +685,9 @@ export const Sidebar = memo(function Sidebar({ }; }, [allThreadsAddMenuAnchor]); - useEffect(() => { - if (!isSearchOpen && searchQuery) { - setSearchQuery(""); - } - }, [isSearchOpen, searchQuery]); - return (