Skip to content

feat(ui): add Cmd+K global search modal for issues and profiles#191

Merged
Siddhartha-singh01 merged 3 commits into
Coder-s-OG-s:mainfrom
Krirox:feat/cmd-k-search-164
May 21, 2026
Merged

feat(ui): add Cmd+K global search modal for issues and profiles#191
Siddhartha-singh01 merged 3 commits into
Coder-s-OG-s:mainfrom
Krirox:feat/cmd-k-search-164

Conversation

@Krirox
Copy link
Copy Markdown
Contributor

@Krirox Krirox commented May 20, 2026

Summary

This PR introduces a global Command Palette (Cmd+K) search feature, allowing users to quickly search across both issues and contributor profiles directly from the UI. It includes the frontend interface using cmdk and a server action to query the database efficiently.

Type of Change

  • Bug fix
  • New feature
  • UI / UX improvement
  • Refactor
  • Documentation
  • Other

Related Issue

Closes #164

What was changed?

  • Added src/components/command-palette.tsx, a new reusable command palette component triggered by Cmd+K / Ctrl+K.
  • Integrated @radix-ui/react-dialog and cmdk for an accessible, keyboard-first search experience.
  • Implemented debounced global search to prevent excessive API calls while typing.
  • Added searchGlobal server action in src/app/actions/search.ts to perform fast, case-insensitive (ilike) database queries across issues (by title) and profiles (by GitHub handle).
  • Configured search results to route locally to contributor profiles or open external issue links in a new tab.

Screenshots

Checklist

  • My code follows the project structure and conventions
  • I tested this locally (npm run dev)
  • No hardcoded secrets or credentials
  • I have updated documentation if needed

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 20, 2026

Someone is attempting to deploy a commit to the codersogs-3057's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Copy Markdown
Collaborator

@Siddhartha-singh01 Siddhartha-singh01 left a comment

Choose a reason for hiding this comment

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

Nice clean implementation @Krirox auth check is right, the drizzle ilike
parameterization means no SQL injection (I verified), and the cmdk + radix-dialog +
useTransition + 300ms debounce is exactly the right UX pattern. Cleanup on close is
good too.

A few things before this can merge:

  1. No rate limit. Every other server action in this repo rate-limits recs:get,
    recs:claim, profile:update, maint:queue, etc. searchGlobal should too. Without
    it, an authenticated user can enumerate every github_handle in the system by
    iterating 2-char prefixes (debouncing on the client doesn't stop direct calls).
    Please add:

    const limited = await rateLimit({
      namespace: 'search',
      key: user.id,
      limit: 30,
      windowSec: 60,
    });
    if (!limited.ok) return err('rate_limited', 'slow down', true);
    
  2. Tests. This is a testable server action just like recommendations.test.ts
    please mock supabase/db and cover the auth-fail, empty-query, and result-shape
    paths. Small file, would be a quick addition.

  3. Escape ILIKE wildcards. % and _ in user input are still treated as
    wildcards, so a% searches "starts with a-then-anything" instead of literal
    a%. Not a security issue (it's parameterized), but a UX one. Escape \, %,
    _ in cleanQuery before wrapping with %.

  4. Add an ORDER BY. Results are in undefined order right now feels random.
    Order by id desc, or at least something stable, so the top 5 isn't arbitrary.

  5. Radix Dialog needs a Dialog.Title. Radix logs an accessibility warning
    when DialogContent has no Title. Add a visually-hidden title for screen
    readers it's a couple of lines.

Once the rate limit is in and there's a basic test, this is good to merge. Solid
work overall

Copy link
Copy Markdown
Collaborator

@Siddhartha-singh01 Siddhartha-singh01 left a comment

Choose a reason for hiding this comment

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

Excellent follow-up @Krirox all five points are cleanly addressed:

  • Rate limit added with the exact shape suggested (search namespace, 30/60s,
    retryable: true) ✅
  • escapeIlike correctly escapes , %, _ in the right order (backslash first) ✅
  • ORDER BY on both queries desc(id) for issues, desc(level) for profiles
    stable and semantic ✅
  • DialogTitle with sr-only for the screen-reader requirement ✅
  • search.test.ts is genuinely well-built 9 tests covering unauthorized,
    no_supabase, rate_limited, short query, whitespace, happy path, empty results,
    DB error, AND a "rate limit called with correct args" assertion. The vi.hoisted
    pattern and mock chain match the repo's existing test conventions.

Once CI / check goes green on this latest commit, this is ready to merge. Great
work polishing this one through

LGTM ✅

@Siddhartha-singh01 Siddhartha-singh01 merged commit c9e3611 into Coder-s-OG-s:main May 21, 2026
2 of 3 checks passed
@Ayush-Patel-56 Ayush-Patel-56 added level:intermediate Intermediate level difficulty quality:clean Clean, well-structured contribution type:accessibility Accessibility improvement gssoc:approved Approved by GSSOC admin mentor:Ayush-Patel-56 Replace Ayush-Patel-56 with mentor's GitHub handle to credit them labels May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved Approved by GSSOC admin level:intermediate Intermediate level difficulty mentor:Ayush-Patel-56 Replace Ayush-Patel-56 with mentor's GitHub handle to credit them quality:clean Clean, well-structured contribution type:accessibility Accessibility improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cmd+K global search for issues and contributor profiles

3 participants