improvement(search): redesign Cmd-K palette with curated empty state and drill-down browse#5194
improvement(search): redesign Cmd-K palette with curated empty state and drill-down browse#5194waleedlatif1 wants to merge 9 commits into
Conversation
PR SummaryMedium Risk Overview Search behavior changes: catalog groups (blocks, tools, triggers, tool ops, docs) appear only after the user types (and not while scoped). Results are capped per group (50) with a non-selectable “+N more” row when trimmed. Cross-group order uses each group’s top fuzzy score via new Implementation: search groups are unified through Reviewed by Cursor Bugbot for commit 8d9a7c9. Configure here. |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 2848a0b. Configure here.
…and drill-down browse - Stop dumping the full ~1,500-item catalog (blocks, tools, triggers, 1,000+ tool operations, docs) into the palette on open; surface them only once the user types, mirroring the existing integrations group - Add a curated empty state: frecency-ranked Recents (new persisted store) and a Browse section that drills into block/trigger/integration categories - Scope drill-down shown as a removable pill in the search bar; Backspace on empty input or Escape pops the scope - Cap each result group to keep the DOM bounded on broad queries - Derive browse categories from block category + integrationType
- Fix stale input text when entering/exiting a browse scope: the cmdk
Command.Input is uncontrolled, so resetting requires the native value
setter, not just setSearch(''). Extract the existing open-reset logic into
a shared clearInput() and reuse it for open, enter-scope, and exit-scope
- Short-circuit the recents memo when there are no recorded entries
- Use a distinct icon for the Productivity category (was reusing Core Blocks')
- Add unit coverage for the recents store and frecency scoring
…etically - Lead with workflow primitives (Core Blocks, Triggers), then pin AI first (Sim is an AI workspace) and rank remaining integration categories by breadth (most integrations first) so the richest categories surface first - Personal frequency is already covered by Recents, so the static order optimizes for discovery and self-maintains as integrations are added - Reuses the canonical integration taxonomy (INTEGRATION_TYPE_LABELS) shared with the /integrations page rather than inventing a parallel one
…tive Review-loop findings: - Recents were pruned by raw recency but ranked by frecency, so a frequently used older block could be evicted while still ranking high. Prune by the same frecencyScore used for display; add a regression test - Make the integration category icon map exhaustive over IntegrationType so a newly added category is a compile error instead of a silent generic-icon fallback; drive core-block/trigger icons off the category kind - Factor the shared gate-and-cap rule for the catalog search groups into a single cappedCatalog() helper instead of repeating it across five memos
…the palette Workflows/files/chats/tables/KBs were rendered in full at the empty state, so a workspace with thousands of them dumped thousands of rows into the DOM. Factor the catalog cap into a shared filterAndCap() and apply it to all variable-size groups, bounding palette DOM to MAX_RESULTS_PER_GROUP per group regardless of workspace size.
…es them The directory imports resolve to the search-groups and command-items barrels; BrowseGroup, RecentsGroup, RecentRenderItem, and MemoizedCategoryItem were added to the source files but not re-exported, breaking the Turbopack build (tsc resolved them via the source file and missed it).
…cideIcon
The map mixes lucide and emcn icons (Database comes from @/components/emcn/icons,
which is not a LucideIcon). Type it as ComponentType<{ className?: string }> —
the exact type MemoizedCategoryItem's icon prop consumes — which both icon
sources satisfy, keeping the exhaustive IntegrationType key check.
…-review cleanup Cmd-K performance/DX pass on top of the palette redesign: - Fix a systemic stale-closure/broken-memoization bug: every row previously got a fresh inline onSelect closure per render while the memo comparators excluded onSelect from equality checks. Replaced with useItemDispatch, a stable Map-based dispatcher shared by a new createRowGroup factory that all groups are now built from (collapses ~15 hand-copied group shells into one). - Rank the typed catalog groups by their best-matching item's fuzzy score instead of a fixed group order, so a strong Docs hit outranks a weak Blocks hit — the biggest DX gap vs. Linear/kbar-style palettes. - Add a "+N more, refine your search" row when a group's cap trims real matches, instead of silently dropping them. - Fix a real animation bug: the dialog panel toggled visible/invisible with no transition class at all, popping in/out instantly while only the backdrop faded. Fixed with the CSS-spec visibility-transition trick plus a subtle scale, animating both directions without a JS deferred-unmount hack. - content-visibility:auto + contain-intrinsic-size on rows, deferring layout/paint for off-screen rows without full virtualization (which would require reimplementing cmdk's DOM-based keyboard nav). - Drop a stray regenerated docx.cjs sandbox-bundle diff that had leaked into the branch. - Cross-review cleanup (/simplify + /cleanup): merged a duplicate MemoizedCategoryItem into MemoizedIconItem, removed 3 useCallbacks with no observer, hoisted a duplicated FALLBACK_BG_COLOR constant, migrated arbitrary z-40/z-50 to the z-modal token, simplified a dead ternary and a 4-way copy-pasted branch in the recents resolver, and split an over-broad-dependency memo so switching keystrokes inside a scope doesn't re-filter the whole tools catalog. Added search-groups.test.tsx (dispatch correctness against a real cmdk root) and filterAndScore tests in utils.test.ts.
2848a0b to
8d9a7c9
Compare
|
@cursor review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8d9a7c9. Configure here.
There was a problem hiding this comment.
Scoped trigger search mismatch
Medium Severity
Drill-down trigger search only fuzzy-matches searchValue ?? name, while global trigger results use `${name} ${id}`. Queries that match a trigger’s id/type (or other tokens not in the display name) can succeed at the root but return nothing inside the Triggers browse scope.
Reviewed by Cursor Bugbot for commit 8d9a7c9. Configure here.



Summary
What changed
category+integrationType. Selecting one scopes the list to just that category. Typing from the root still does a flat global search.Toolbar block picker (separate component) intentionally left as a follow-up to keep this PR focused.
Type of Change
Testing
store.test.tsupdated + new coverage forintegrationTypecapture and category building (5/5 passing)tscclean (0 errors), biome cleanChecklist