From b6ce54e2c6af1026322312f49c85b4a6428dc49e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Mon, 5 Oct 2026 21:05:13 +0200 Subject: [PATCH] fix(coach): drop the search field from the conversations panel The panel lists the history grouped by recency with load-more, rename and delete; title search stays on the full /coach/conversations page. --- e2e/coach-layout.spec.ts | 7 ++-- .../__tests__/history-rail.test.tsx | 8 ++--- .../insights/coach-panel/coach-drawer.tsx | 2 +- .../coach-panel/conversations-panel.tsx | 5 ++- .../insights/coach-panel/history-rail.tsx | 36 ++++--------------- 5 files changed, 18 insertions(+), 40 deletions(-) diff --git a/e2e/coach-layout.spec.ts b/e2e/coach-layout.spec.ts index a4b432ab8..d13cf9965 100644 --- a/e2e/coach-layout.spec.ts +++ b/e2e/coach-layout.spec.ts @@ -472,7 +472,7 @@ test.describe("Coach page frame", () => { expect(Math.abs(closed.composer - open.composer)).toBeLessThanOrEqual(1); // Closed, nothing inside the panel is reachable. await expect( - panel(page).locator('[data-slot="coach-history-search"]'), + panel(page).locator('[data-slot="coach-history-select"]').first(), ).not.toBeInViewport(); await expectNoSidewaysScroll(page); await shot(page, testInfo, `coach-frame-${width}-closed`); @@ -484,7 +484,10 @@ test.describe("Coach page frame", () => { // Open again, then Escape from inside closes it, focus to the toggle. await toggle(page).click(); await expect(panel(page)).toHaveAttribute("data-state", "open"); - await panel(page).locator('[data-slot="coach-history-search"]').focus(); + await panel(page) + .locator('[data-slot="coach-history-select"]') + .first() + .focus(); await page.keyboard.press("Escape"); await expect(panel(page)).toHaveAttribute("data-state", "closed"); await expect(toggle(page)).toBeFocused(); diff --git a/src/components/insights/coach-panel/__tests__/history-rail.test.tsx b/src/components/insights/coach-panel/__tests__/history-rail.test.tsx index 1dea34a3d..121e67ccd 100644 --- a/src/components/insights/coach-panel/__tests__/history-rail.test.tsx +++ b/src/components/insights/coach-panel/__tests__/history-rail.test.tsx @@ -141,15 +141,15 @@ describe("", () => { expect(html).toContain("Your conversations will appear here."); }); - it("mounts the search input with the localised placeholder", () => { + it("carries no search field (search lives on the full conversations page)", () => { const client = makeClientWithConversations(samplePage); const html = render( {}} />, client, ); - expect(html).toMatch( - /data-slot="coach-history-search"[^>]*placeholder="Search conversations…"/, - ); + expect(html).toContain('data-slot="coach-history-list"'); + expect(html).not.toContain('type="search"'); + expect(html).not.toContain("Search conversations"); }); it("uses German strings when locale is 'de'", () => { diff --git a/src/components/insights/coach-panel/coach-drawer.tsx b/src/components/insights/coach-panel/coach-drawer.tsx index a79708cb2..c80697cb3 100644 --- a/src/components/insights/coach-panel/coach-drawer.tsx +++ b/src/components/insights/coach-panel/coach-drawer.tsx @@ -176,7 +176,7 @@ export function CoachDrawer({ // v1.21.4 (Coach-UI B) — the drawer's "Conversations" affordance now hands // off to the dedicated conversation-history page (`/coach/conversations`), - // which renders the search + recency-grouped list as a sibling of the + // which renders the recency-grouped list as a sibling of the // Coach page. The former `?view=conversations` in-page slide-in drawer is // gone; selecting a row there routes back to `/coach?c=`. const handleOpenConversations = useCallback(() => { diff --git a/src/components/insights/coach-panel/conversations-panel.tsx b/src/components/insights/coach-panel/conversations-panel.tsx index eb756f365..381d2202b 100644 --- a/src/components/insights/coach-panel/conversations-panel.tsx +++ b/src/components/insights/coach-panel/conversations-panel.tsx @@ -366,9 +366,8 @@ export function ConversationsPanel({ data-slot="coach-conversations-panel" className="w-[22rem] max-w-[90vw] gap-0 p-0 sm:max-w-[22rem]" onOpenAutoFocus={(event) => { - // Land on the sheet itself, not its first control: on a phone - // focusing the search field would raise the keyboard over the - // list the person opened the sheet to read. + // Land on the sheet itself, not its first control, so opening + // the sheet does not paint a focus ring on a header button. event.preventDefault(); (event.currentTarget as HTMLElement | null)?.focus(); }} diff --git a/src/components/insights/coach-panel/history-rail.tsx b/src/components/insights/coach-panel/history-rail.tsx index b19e423fe..44502d152 100644 --- a/src/components/insights/coach-panel/history-rail.tsx +++ b/src/components/insights/coach-panel/history-rail.tsx @@ -8,7 +8,6 @@ import { Paperclip, Pencil, RotateCw, - Search, Trash2, } from "lucide-react"; import { toast } from "sonner"; @@ -20,10 +19,8 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { Input } from "@/components/ui/input"; import { cn } from "@/lib/utils"; import { useTranslations } from "@/lib/i18n/context"; -import { useDebouncedValue } from "@/hooks/use-debounced-value"; import { useLoadMoreSentinel } from "@/hooks/use-load-more-sentinel"; import type { CoachConversationDTO } from "@/lib/ai/coach/types"; import { groupConversationsByRecency } from "@/lib/insights/coach-conversation-groups"; @@ -36,14 +33,14 @@ import { } from "./use-coach"; /** - * The Coach's conversation list: search, the full history grouped by recency + * The Coach's conversation list: the full history grouped by recency * (Today / Yesterday / This week / Earlier), and one row per conversation with * a "⋯" menu for Rename and Delete. * * It fills the Coach page's conversations panel and the drawer's history * tray. The history is cursor-paginated (`useInfiniteQuery`, loaded as the - * list scrolls near its end) and searched server-side on the title, debounced - * 200 ms. + * list scrolls near its end). Title search lives on the standalone + * `/coach/conversations` page, not here. * * Rename edits the title in place (`ConversationRename`, Enter saves, Escape * cancels without closing the panel around it) and returns focus to the row's @@ -88,8 +85,6 @@ export function HistoryRail({ onUndoDeleteActive, }: HistoryRailProps) { const { t } = useTranslations(); - const [filter, setFilter] = useState(""); - const debouncedFilter = useDebouncedValue(filter, 200); const { conversations, isLoading, @@ -98,19 +93,17 @@ export function HistoryRail({ hasNextPage, isFetchingNextPage, fetchNextPage, - } = useCoachConversationHistory({ search: debouncedFilter }); + } = useCoachConversationHistory(); const ownDeletion = useDeleteCoachConversationWithUndo(); const { pendingDeleteIds, requestDelete, undoDelete } = deletion ?? ownDeletion; - // `pendingDeleteIds` hides rows inside the undo window; the server-side - // search already resolved everything else. + // `pendingDeleteIds` hides rows inside the undo window. const visible = useMemo( () => conversations.filter((c) => !pendingDeleteIds.has(c.id)), [conversations, pendingDeleteIds], ); const groups = useMemo(() => groupConversationsByRecency(visible), [visible]); - const isSearching = debouncedFilter.trim().length > 0; // A `useState`-backed callback ref so the sentinel hook re-runs once the // scroll container exists (null on the very first render). @@ -153,21 +146,6 @@ export function HistoryRail({ {t("insights.coach.historyTitle")} )} -
-
- {isSearching - ? t("insights.coach.historySearchEmpty") - : t("insights.coach.historyEmpty")} + {t("insights.coach.historyEmpty")}

) : ( groups.map((group) => (