feat(search): actions, fuzzy matching, and highlighting in cmd+k palette#5110
Conversation
Add a context-aware actions layer to the cmd+k search palette (Run workflow, Create workflow/folder, Import workflow, Fit to view, Copy link, Invite teammates, Toggle theme), replace the substring matcher with a boundary-anchored fuzzy matcher (initialisms, typos, multi-word) that is a strict superset of the old behavior, highlight matched characters, and rank against clean human text instead of structural id/uuid tokens. Expose invoke() on the global commands provider so the palette runs real registered commands.
PR SummaryLow Risk Overview Global commands expose Search replaces the old substring scorer with Adds Reviewed by Cursor Bugbot for commit 46c26c6. Configure here. |
…d occurrence Contiguous substring matches (exact/prefix/contains) now report the substring's own indices instead of the greedy subsequence scan positions, so HighlightedText bolds the characters the user actually matched. Restructures fuzzyMatch to handle the substring tier first; scores are unchanged for these cases.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Greptile SummaryThis PR enhances the cmd+k search palette with three major additions: a context-aware actions layer (Run workflow, Create/Import, Fit to view, Copy link, Invite teammates, Toggle theme), a boundary-anchored fuzzy matcher replacing the old substring-only approach, and per-character highlight rendering for matched items.
Confidence Score: 5/5Safe to merge — all changed code paths are well-guarded, previously flagged issues have been addressed, and the fuzzy matcher is backed by a comprehensive test suite. The actions layer is correctly gated by context and canEdit, the fuzzy matcher is a proven superset of the old one with 18 assertions, clipboard and command invocation failures are handled gracefully, and the memoization strategy is consistent with the existing codebase pattern. No functional regressions were identified. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User opens cmd+k] --> B[SearchModal renders]
B --> C{deferredSearch empty?}
C -- yes --> D[filterAndSort returns all available items]
C -- no --> E[fuzzyMatch per item]
E --> F{matched?}
F -- no --> G[exclude]
F -- yes --> H[collect with score]
H --> I[sort descending by score]
I --> D
D --> J[ActionsGroup - context filtered]
D --> K[Entity groups - workflow/global]
J --> L[MemoizedActionItem]
K --> M[Memoized*Item components]
L --> N[HighlightedText re-runs fuzzyMatch on label]
M --> N
N --> O{positions found?}
O -- yes --> P[Wrap matched chars in bold span]
O -- no --> Q[Render plain text]
L -- onSelect --> R[handleActionSelect]
R --> S[close modal]
S --> T[item.run]
T --> U{action type}
U -- run-workflow/fit-to-view --> V[invokeCommand via GlobalCommandsProvider]
V --> W[registryRef.current.get id]
W --> X[handler new KeyboardEvent keydown]
U -- toggle-theme --> Y[setTheme]
U -- create/import --> Z[onCreateWorkflow / onCreateFolder / onImportWorkflow]
U -- copy link --> AA[navigator.clipboard.writeText]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[User opens cmd+k] --> B[SearchModal renders]
B --> C{deferredSearch empty?}
C -- yes --> D[filterAndSort returns all available items]
C -- no --> E[fuzzyMatch per item]
E --> F{matched?}
F -- no --> G[exclude]
F -- yes --> H[collect with score]
H --> I[sort descending by score]
I --> D
D --> J[ActionsGroup - context filtered]
D --> K[Entity groups - workflow/global]
J --> L[MemoizedActionItem]
K --> M[Memoized*Item components]
L --> N[HighlightedText re-runs fuzzyMatch on label]
M --> N
N --> O{positions found?}
O -- yes --> P[Wrap matched chars in bold span]
O -- no --> Q[Render plain text]
L -- onSelect --> R[handleActionSelect]
R --> S[close modal]
S --> T[item.run]
T --> U{action type}
U -- run-workflow/fit-to-view --> V[invokeCommand via GlobalCommandsProvider]
V --> W[registryRef.current.get id]
W --> X[handler new KeyboardEvent keydown]
U -- toggle-theme --> Y[setTheme]
U -- create/import --> Z[onCreateWorkflow / onCreateFolder / onImportWorkflow]
U -- copy link --> AA[navigator.clipboard.writeText]
Reviews (3): Last reviewed commit: "fix(search): log clipboard copy failures..." | Re-trigger Greptile |
|
@greptile |
|
@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 af30525. Configure here.
…d-only - Copy workflow link now logs on clipboard write failure instead of silently swallowing the error, matching the sidebar's copy-link convention. - FuzzyResult.positions is now readonly and the NO_MATCH singleton's array is frozen, so the shared instance can never be mutated by a caller.
|
@greptile |
|
@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 46c26c6. Configure here.
Summary
canEdit-gated; Run/Fit/Copy show only on workflow pages.slk→Slack), camelCase (gps→Google PageSpeed), typos (githb→GitHub), and multi-word all work. It's a strict superset of the old matcher (proven by test): any result the old one returned, the new one still returns.<type>-<id>/uuid tokens, so short queries no longer scatter-match unrelated items.invoke(id)on the global commands provider so the palette runs the real registered commands (Run/Fit) with behavior identical to their keyboard shortcuts — and no-ops safely when a command isn't mounted.Type of Change
Testing
utils.test.ts(18 assertions): strict-superset no-regression check across 40 query shapes, ranking wins, noise control, and highlight positions. All passing.Checklist