Skip to content

feat(web): add global command palette and remap shortcuts#367

Merged
ColeMurray merged 5 commits intoColeMurray:mainfrom
dharmateja03:feature/global-command-palette-shortcuts
Mar 18, 2026
Merged

feat(web): add global command palette and remap shortcuts#367
ColeMurray merged 5 commits intoColeMurray:mainfrom
dharmateja03:feature/global-command-palette-shortcuts

Conversation

@dharmateja03
Copy link
Copy Markdown
Contributor

  • map Cmd/Ctrl+K to open the global command menu
  • remap New Session to Cmd/Ctrl+Shift+O
  • add shadcn-style CommandDialog/Command UI with shortcut hints
  • allow Cmd/Ctrl+K even when input is focused
  • update keyboard shortcuts settings page

Refs #337

- map Cmd/Ctrl+K to open the global command menu
- remap New Session to Cmd/Ctrl+Shift+O
- add shadcn-style CommandDialog/Command UI with shortcut hints
- allow Cmd/Ctrl+K even when input is focused
- update keyboard shortcuts settings page

Refs ColeMurray#337
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 17, 2026

Greptile Summary

This PR adds a global command palette (Cmd/Ctrl+K) backed by cmdk and remaps "New Session" to Cmd/Ctrl+Shift+O. The overall architecture is sound: shortcut detection is cleanly action-aware, accessibility attributes (DialogTitle/DialogDescription with sr-only) are in place, and the SWR sessions data is reused rather than fetched again.

Two issues were found:

  • cmdk value collision (P1)CommandItem.value for session items is \${sessionTitle} ${repoLabel}`. When titleisnull, sessionTitlefalls back torepoOwner/repoName, so multiple unnamed sessions in the same repo get identical valueprops. Because cmdk tracks items in an internalMapkeyed byvalue, the second item silently overwrites the first, causing sessions to disappear from the list. Adding session.id` to the value string fixes this.

  • Cmd+K can't close the palette (P2)handleOpenCommandMenu always calls setIsCommandMenuOpen(true) rather than toggling. Since shouldIgnoreGlobalShortcutForAction explicitly allows Cmd+K through even when an input is focused, pressing Cmd+K while the palette is open fires the handler but produces no visible change. Users familiar with VS Code/Linear-style command menus will expect the same shortcut to dismiss the palette.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: packages/web/src/components/global-command-menu.tsx
Line: 108

Comment:
**cmdk value collision hides duplicate sessions**

The `value` prop passed to `CommandItem` is `\`${sessionTitle} ${repoLabel}\``. Since `sessionTitle` falls back to `\`${session.repoOwner}/${session.repoName}\`` when `title` is `null`, any two unnamed sessions in the same repo will share an identical `value` string.

The `cmdk` library uses `value` as the key in an internal `Map` to track items for filtering and selection. When two items share the same value, the second registration overwrites the first, causing one of the sessions to silently disappear from the list.

This is reproducible whenever a user has multiple active (non-archived) sessions in the same repository without custom titles.

Fix: include `session.id` in the `value` so every item is guaranteed to be unique while still being searchable by title and repo:

```suggestion
                      value={`${session.id} ${sessionTitle} ${repoLabel}`}
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: packages/web/src/components/sidebar-layout.tsx
Line: 65-67

Comment:
**Cmd/Ctrl+K can't close the command menu**

`handleOpenCommandMenu` unconditionally sets `isCommandMenuOpen` to `true`. Because `shouldIgnoreGlobalShortcutForAction` returns `false` for `"open-command-menu"` even inside editable elements, pressing Cmd/Ctrl+K while the dialog's `CommandInput` is focused will re-fire this callback — but since the state is already `true`, it is silently a no-op.

Standard command-palette UX (VS Code, Linear, etc.) expects the same shortcut to both open and close the palette. Users who press Cmd+K to dismiss the menu will instead find nothing happens until they reach for Escape.

Consider toggling the state instead:

```suggestion
  const handleOpenCommandMenu = useCallback(() => {
    setIsCommandMenuOpen((prev) => !prev);
  }, []);
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: ad483cd

dharmateja03 and others added 2 commits March 17, 2026 18:23
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Owner

@ColeMurray ColeMurray left a comment

Choose a reason for hiding this comment

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

Nit (non-blocking): This useSWR call works correctly via SWR's cache deduplication with the sidebar's fetch — no extra network request. However, it keeps the sessions data referenced in component state even when the command menu is closed. Consider conditionally passing the key so sessions are only held when the menu is open:

const { data: sessionsResponse } = useSWR<SessionListResponse>(
  status === "authenticated" && Boolean(session) && isCommandMenuOpen
    ? SIDEBAR_SESSIONS_KEY
    : null
);

SWR's cache already has the data from the sidebar, so activating the key when the menu opens returns cached results instantly — no loading flash. At current scale (25 items max) this is negligible, but worth noting if session payloads grow.

Conditionally pass the SWR key so sessions data is only referenced
when the command menu is open. SWR cache deduplication ensures
instant results from the sidebar's existing fetch.
@ColeMurray ColeMurray merged commit a0c0371 into ColeMurray:main Mar 18, 2026
11 checks passed
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.

2 participants