cmux NEXT Home: search finds message text and lists matching messages, as in Messages

AU
4d ago
+455-102

Fixes https://github.com/manaflow-ai/cmux/issues/27950

Changelog

Changed: searching the Home (Chief) list now also finds messages whose text matches, under a Messages section with the conversation, the matching text and its time, as in Messages. Choosing one opens the conversation at that message.

What was wrong

  • Content: the list's search matched only conversation names, participants and each one's newest preview. The conversation owner already answers a full-text message search (conversation-search, HomeStore.search), but the list never asked it.
  • Icon layout: the magnifier, the "Search" text and the filter circle drew off-centre, and the typed text slid over the magnifier. https://github.com/manaflow-ai/cmux/pull/28021 fixed that today for https://github.com/manaflow-ai/cmux/issues/27967, and this PR does not change the field or the header. The captures below re-check it at this head: the magnifier, the text and the filter share one centre line at rest and while typing.

Change

  • Vendored list (MessagesLabSidebar): takes any number of host search sections, each under its own title. The single extraStart/extraTitle became SidebarSectionMarks, which owns the row geometry: row top and its inverse, title rects, hit testing, separators, and the search queue's prerender. A request can answer twice: the quick sections first, then the slow ones replace that answer. Cancelling the request (the next keystroke, or an emptied field) cancels the slow task, and an older query's answer is dropped.
  • CmuxSidebarView: searchSections (sync, shown at once) plus laterSearchSections (async). A result can carry an avatar and a date. VoiceOver reads that date.
  • HomeSidebarView: Teammates show at once. Messages arrive from searchMessages; a hit is shown only for a conversation the list shows, and gets that conversation's name and avatar. Choosing one calls onOpenMessage.
  • TopHomePageView: searchMessages is homeStore.search(query, limit: 20), local owner only (the router's cloud has no home.search yet, so Cloud conversations get no message hits). onOpenMessage uses the permalink path show(HomeDockSelection(conversation:message:)), which reveals the message.
  • DEBUG only: debug.home.sidebar_fixture takes messages [{row, text}] and query for screenshots. There's a new tour, home-search. One new string, home.list.searchMessages ("Messages"), translated in all 21 catalog locales.

Tests

SearchSectionsTests (MessagesLabSidebar) drives a real CmuxSidebarView in a window:

  • everySectionShowsUnderItsOwnTitleAfterTheConversations: Teammates shows before the held message search answers. Then the Messages section joins: each title sits on its first row, no row overlaps a title, every row's middle hits that row, a title hits nothing, and a message row carries its text and time and reports its host id when chosen.
  • anOlderQuerysLateAnswerIsNeverShown: holds the "lun" answer past its cancellation and releases it after "lunch" has shown. The list keeps "lunch"'s sections only.

Fleet runs:

  • Step 8c084307974df7d15d2508e3 at be6ae7cedf68 (package-test-lane.sh suite Packages/Shared/CmuxMessagesLab SearchSectionsTests,PinnedUnreadDotLayoutTests,PinDragMotionTests): all 3 suites pass.
  • Step d4e7a686571b10f06004be3f at b71cb3627513, the first version: all 3 pass.
  • Commits after be6ae7cedf68 change only the tour JSON.

These tests are new, so there is no red run on the base: the multi-section API they call does not exist there.

Dev build and captures

Tag 27950-chief-search-messages: fleet build 6e44e1550aa9a465b9d298c1 at a693f53402a5 (this head). The captures below come from build 30dcd0c39f9875137d3069b6 at 2781def26c96; the only later commit is the French heading text, which no capture shows.

Viewed after image: yes
Visual verdict: Yes: the Messages section reads like iMessage's search results, in the list's own row style, and the header stays on one centre line.

"lunch" (three messages, no name match), "Aziz" (the name match, then a message mentioning him), and Home at rest:

Capture steps-38032e9241 at 2781def26c96 (fleet build, capture mini, text checked for private data)

LightDark
lightdark

Capture steps-e95fe29296 at 2781def26c96 (fleet build, capture mini, text checked for private data)

LightDark
lightdark

Capture tour-home at 2781def26c96 (fleet build, capture mini, text checked for private data)

LightDark
lightdark

Review

A correctness review subagent at edc61729e503 found nothing blocking. Its should-fix items are fixed in be6ae7cedf68:

  • Teammates waited on the message search.
  • An emptied field didn't cancel the slow task.
  • The late-answer test didn't really hold the answer.
  • VoiceOver skipped the result's time.
  • The fixture copied the production wiring.

Not changed: one owner search per keystroke. Each search is local and cancelled by the next keystroke, and the repo rules say not to debounce visible work.

Observed / Not run

  • Observed:
    • Fleet suites above.
    • Real-app captures on the tagged build at this head: the "lunch" and "Aziz" searches, and tour:home for the header at rest.
    • The base tour:home at 3e65269f80c9, the header before.
  • Not run:
    • A real daemon conversation-search round trip in the app. The captures use the DEBUG fixture's hits; the daemon command has its own Rust tests (conversation_tests.rs), unchanged here.
    • Clicking a message result in the app (the test selects the row under the point).
    • Real keyboard typing (no focus-free route).
    • The full CmuxNext suite.

šŸ¤– Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Home list search now matches message text, not just conversation names and latest previews. Matching messages appear in a new Messages section under Teammates — each row shows the conversation's name, the matched text, and the message's time — and choosing one opens the conversation at that message, as in Messages.

  • Teammates show immediately; message results arrive asynchronously from the conversation owner's search.
  • The vendored list now supports multiple search sections, each with its own title; a newer keystroke or an emptied field cancels an older query's answer.
  • Message hits appear only for conversations the list already shows; Cloud conversations get none because the cloud router lacks home.search yet.

Tests

  • SearchSectionsTests drives a real CmuxSidebarView: every section shows under its own title after the conversations, no row overlaps a title, and choosing a message row reports its host id.
  • A late answer for an older query is never shown once a newer query has run.