Skip to content

feat(search): actions, fuzzy matching, and highlighting in cmd+k palette#5110

Merged
waleedlatif1 merged 3 commits into
stagingfrom
feat/cmdk-actions-fuzzy
Jun 17, 2026
Merged

feat(search): actions, fuzzy matching, and highlighting in cmd+k palette#5110
waleedlatif1 merged 3 commits into
stagingfrom
feat/cmdk-actions-fuzzy

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Add a context-aware actions layer to cmd+k — verbs that do something, not just navigate: Run workflow, Create workflow/folder, Import workflow, Fit workflow to view, Copy workflow link, Invite teammates, Toggle theme. Create/import are canEdit-gated; Run/Fit/Copy show only on workflow pages.
  • Replace the substring matcher with a boundary-anchored fuzzy matcher — initialisms (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.
  • Highlight matched characters in every result row.
  • Rank against clean human text (names, types, aliases, folder paths) instead of structural <type>-<id>/uuid tokens, so short queries no longer scatter-match unrelated items.
  • Expose 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

  • New feature

Testing

  • Added utils.test.ts (18 assertions): strict-superset no-regression check across 40 query shapes, ranking wins, noise control, and highlight positions. All passing.
  • Typecheck + biome clean. Tested manually.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

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.
@cursor

cursor Bot commented Jun 17, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
UI-only search and palette behavior with tests for matcher regression; invoke reuses existing command handlers without changing auth or data paths.

Overview
The workspace cmd+k palette gains a top Actions group for verbs (run/fit workflow via registered shortcuts, create/import workflow and folder when canEdit, copy link, invite teammates, toggle theme), with workflow-only actions gated by page context and PostHog action selections.

Global commands expose invoke(id) and useInvokeGlobalCommand() so the palette can run the same handlers as keyboard shortcuts and safely no-op when a command is not mounted (e.g. run off-canvas).

Search replaces the old substring scorer with fuzzyMatch / filterAndSort: boundary-anchored subsequences for initialisms and typos, multi-word token fallback, and ranking on display text (names, keywords, folder paths) instead of cmdk type-id tokens. Result rows use HighlightedText for matched characters; block search values drop redundant block-{id} suffixes in the store.

Adds utils.test.ts asserting the new matcher is a strict superset of the legacy one for top ranks and results.

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.
@vercel

vercel Bot commented Jun 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jun 17, 2026 5:25pm

Request Review

@greptile-apps

greptile-apps Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This 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.

  • Actions layer (search-modal.tsx, search-groups.tsx): New ActionItem type with context field gates workflow-only verbs to workflow pages; canEdit gates create/import verbs; handleActionSelect closes the modal before invoking item.run() so theme transitions and command invocations happen without the overlay flashing.
  • Fuzzy matcher (utils.ts): Multi-pass algorithm — exact/prefix/contains → scattered subsequence anchored at hard word boundaries → order-independent token fallback. Proven a strict superset of the old matcher by 18 test assertions in utils.test.ts.
  • Highlighting (command-items.tsx): HighlightedText calls fuzzyMatch on the display label to recover match positions, then wraps matched segments in font-semibold spans; components are memoized on (text, query) to avoid unnecessary re-renders.

Confidence Score: 5/5

Safe 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

Filename Overview
apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/utils.ts Replaces simple substring scorer with a multi-pass fuzzy matcher (exact → scattered → token fallback); adds ActionItem/ActionContext types and SearchModalProps extensions; NO_MATCH singleton uses Object.freeze([]) and positions is typed readonly.
apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx Adds actions layer with context/canEdit gating, handleActionSelect, and filteredActions; cleans up filterAndSort value strings across all entity types to remove structural id/type tokens; passes query prop to all groups.
apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/command-items/command-items.tsx Adds HighlightedText (memoized by text+query), MemoizedActionItem, and query prop to every existing memoized component; memo comparators updated to include query.
apps/sim/app/workspace/[workspaceId]/providers/global-commands-provider.tsx Adds invoke(id) to the context and useInvokeGlobalCommand hook; invoke wraps the registered handler in a try/catch and creates a bare KeyboardEvent; stable via useCallback([]).
apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/utils.test.ts 18 assertions covering no-regression vs old matcher, initialism wins, noise control, and highlight positions; tests use the old value format which differs from production, but that covers the no-regression guarantee adequately.
apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/components/search-groups/search-groups.tsx Adds ActionsGroup and threads query prop through every existing group to MemoizedActionItem/existing memoized items.
apps/sim/stores/modals/search/store.ts Removes block-${block.type} structural token from searchValue, leaving name + type + commandSearchable options; consistent with the PR intent to rank against human-readable text only.
apps/sim/lib/posthog/events.ts Adds 'action' to result_type union and optional action_id field for PostHog event tracking.

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]
Loading
%%{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]
Loading

Reviews (3): Last reviewed commit: "fix(search): log clipboard copy failures..." | Re-trigger Greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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.

@waleedlatif1 waleedlatif1 merged commit 05cd7d9 into staging Jun 17, 2026
16 checks passed
@waleedlatif1 waleedlatif1 deleted the feat/cmdk-actions-fuzzy branch June 17, 2026 17:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant