Skip to content

Add modal to view hotkeys, have hotkeys work even when focusing terminals#166

Merged
saddlepaddle merged 8 commits intomainfrom
pearl-wind-69
Nov 28, 2025
Merged

Add modal to view hotkeys, have hotkeys work even when focusing terminals#166
saddlepaddle merged 8 commits intomainfrom
pearl-wind-69

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented Nov 28, 2025

  • feat(desktop): centralize hotkeys with modal and terminal forwarding
  • WIP

Description

Related Issues

Type of Change

  • Bug fix
  • New feature
  • Documentation
  • Refactor
  • Other (please describe):

Testing

Screenshots (if applicable)

Additional Notes

Summary by CodeRabbit

  • New Features

    • Keyboard shortcuts modal showing categorized shortcuts (Workspace, Terminal, Layout, Window, Help)
    • Centralized hotkey system with consistent display, matching, and formatting
    • Workspace navigation via number keys 1–9 (single combined binding)
    • Terminal forwards app hotkeys so app shortcuts work while typing
    • Global shortcuts to open the shortcuts modal and perform common actions
  • Chore

    • Exposed keyboard UI components (Kbd, KbdGroup) in the UI package exports

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Copy Markdown

vercel Bot commented Nov 28, 2025

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

Project Deployment Preview Comments Updated (UTC)
website Ready Ready Preview Comment Nov 28, 2025 7:38am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 28, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a centralized HOTKEYS registry and utilities, a HotkeyModal UI and Kbd UI primitives, wires HOTKEYS into main screens and terminal initialization, forwards app hotkeys from XTerm to global handlers, and replaces prior numeric workspace/tab hotkeys with consolidated meta+1..meta+9 handling.

Changes

Cohort / File(s) Summary
Hotkey core & utilities
apps/desktop/src/shared/hotkeys.ts
New centralized HOTKEYS constant, types (HotkeyCategory, HotkeyDefinition, HotkeyId) and exported utilities: getHotkeysByCategory, formatKeysForDisplay, matchesHotkey, findMatchingHotkey, isAppHotkey.
HotkeyModal component
apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx, apps/desktop/src/renderer/components/HotkeyModal/index.ts
New HotkeyModal React component (controlled via open / onOpenChange) that renders categorized hotkeys and consolidates workspace jump entries; index.ts re-exports it.
Keyboard UI primitives
packages/ui/src/components/kbd.tsx, packages/ui/package.json
New Kbd and KbdGroup components for rendering keyboard keys; adds ./kbd export to UI package exports.
Main screen integration
apps/desktop/src/renderer/screens/main/index.tsx
Adds local state for showing HotkeyModal, imports HOTKEYS, registers global hotkeys via useHotkeys (show modal, toggle sidebar, split actions) and renders HotkeyModal.
Workspace tab hotkeys
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
Replaces left/right bindings with numeric meta+1..meta+9 handlers mapping numbers to workspace indices and calling setActiveWorkspace.
WorkspaceView terminal hotkeys
apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
Replaces hard-coded terminal hotkey strings with HOTKEYS.*.keys (NEW_TERMINAL, CLOSE_TERMINAL, PREV_TERMINAL, NEXT_TERMINAL); removes previous jump-to-tab-by-number handlers.
Terminal shortcut forwarding
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
Adds setupShortcutForwarding(xterm) to intercept Ctrl/Meta combos, use isAppHotkey to detect app hotkeys, re-dispatch matching events to document, and let XTerm ignore them; createTerminalInstance calls this.
Desktop package manifest
apps/desktop/package.json
Adds runtime dependency dnd-core ^16.0.1 to desktop app manifest.
Tests & mocks
apps/desktop/src/renderer/stores/tabs/store.test.ts
Replaces earlier terminal cleanup mock with a Map-backed window.electronStore mock, adds trpc-client mock, uses dynamic import timing, and restores initial store state between tests.
Manifests & config edits
packages/constants/*, packages/db/package.json, packages/typescript-config/base.json, various apps' package.json and tsconfig updates
Removes packages/constants/package.json and its tsconfig; removes @superset/constants dep from packages/db; adjusts bun-types typing entries; bumps three in multiple apps; adds various deps (react-icons, zod, @types/three, react-devtools-core, bun-types, dnd-core).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant XTerm as XTerm (terminal)
    participant Helper as Terminal Helper
    participant Utils as Hotkey Utils
    participant Document as Document (global)
    participant App as App Handler
    participant Modal as HotkeyModal

    User->>XTerm: press keys (e.g., Meta+1 or Meta+T)
    XTerm->>Helper: keydown event (terminal focused)
    Helper->>Utils: isAppHotkey(event)?
    alt matches app hotkey
        Utils-->>Helper: true
        Helper->>Document: re-dispatch event (global)
        Helper-->>XTerm: prevent terminal handling
        Document->>App: global hotkey handler invoked
        alt show hotkeys
            App->>Modal: set open = true
            Modal-->>User: render shortcuts dialog
        else perform action
            App->>App: execute action (switch workspace / split / toggle)
        end
    else not an app hotkey
        Utils-->>Helper: false
        Helper-->>XTerm: allow XTerm to handle input
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Inspect HOTKEYS definitions and category assignments for completeness and collisions.
  • Verify matchesHotkey/findMatchingHotkey edge cases (modifier normalization, platform meta vs ctrl).
  • Review consolidateWorkspaceJumps logic and the numeric workspace-index mapping in workspace tab handlers.
  • Confirm setupShortcutForwarding re-dispatch avoids double-handling and preserves terminal input behavior.
  • Check package.json/tsconfig changes for unintended type/packaging side effects.

Possibly related PRs

Poem

🐰 I hop on keys both near and far,
I gather shortcuts, one by one,
A modal bright to show them all,
Terminals now let globals run,
Tap a key — the rabbit's done! 🎶

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is largely incomplete with only a summary line and WIP status; most required template sections lack meaningful content. Fill in Description, Related Issues, select a Type of Change, document Testing steps, and provide Additional Notes to complete the template.
Docstring Coverage ⚠️ Warning Docstring coverage is 41.18% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the two main changes: adding a hotkey modal component and enabling hotkeys to work in terminal focus contexts.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c723f2 and 77e204d.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (20)
  • apps/blog/package.json (1 hunks)
  • apps/cli/package.json (1 hunks)
  • apps/cli/tsconfig.json (1 hunks)
  • apps/desktop/package.json (2 hunks)
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx (1 hunks)
  • apps/desktop/src/renderer/components/HotkeyModal/index.ts (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts (2 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx (2 hunks)
  • apps/desktop/src/renderer/screens/main/index.tsx (4 hunks)
  • apps/desktop/src/renderer/stores/tabs/store.test.ts (1 hunks)
  • apps/desktop/src/shared/hotkeys.ts (1 hunks)
  • apps/docs/package.json (1 hunks)
  • apps/website/package.json (2 hunks)
  • packages/constants/package.json (0 hunks)
  • packages/constants/tsconfig.json (0 hunks)
  • packages/db/package.json (0 hunks)
  • packages/typescript-config/base.json (1 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/ui/src/components/kbd.tsx (1 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
apps/desktop/src/shared/hotkeys.ts (1)

147-164: Consider making category order explicit.

The function iterates over Object.values(HOTKEYS), but object iteration order in JavaScript is guaranteed only for integer-keyed properties. While modern engines preserve insertion order for string keys, you might want to define an explicit category order array if display order matters.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx (1)

5-5: Remove unused import.

HOTKEYS is imported but not used in this file. Either remove the import or use the centralized constants (e.g., iterate over HOTKEYS.JUMP_TO_WORKSPACE_* definitions) instead of dynamically generating the key string on line 31.

-import { HOTKEYS } from "shared/hotkeys";
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 025a449 and 6766cdf.

📒 Files selected for processing (9)
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx (1 hunks)
  • apps/desktop/src/renderer/components/HotkeyModal/index.ts (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx (2 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts (2 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx (2 hunks)
  • apps/desktop/src/renderer/screens/main/index.tsx (4 hunks)
  • apps/desktop/src/shared/hotkeys.ts (1 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/ui/src/components/kbd.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Biome formatting, linting, and import organization at the root level for all code files

Files:

  • packages/ui/package.json
  • apps/desktop/src/renderer/components/HotkeyModal/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/shared/hotkeys.ts
  • packages/ui/src/components/kbd.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid using any type; use type-safe approaches instead, unless necessary
Ensure TypeScript type checking passes across all packages using bun run typecheck

Files:

  • apps/desktop/src/renderer/components/HotkeyModal/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/shared/hotkeys.ts
  • packages/ui/src/components/kbd.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
apps/**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

apps/**/*.{tsx,ts}: Structure React applications with one folder per component following the pattern: ComponentName/ComponentName.tsx with index.ts barrel export
Co-locate component dependencies (hooks, utils, constants, tests, stories) next to the file using them

Files:

  • apps/desktop/src/renderer/components/HotkeyModal/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/shared/hotkeys.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
apps/desktop/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/renderer/components/HotkeyModal/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/shared/hotkeys.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: Please use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary

Files:

  • apps/desktop/src/renderer/components/HotkeyModal/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/shared/hotkeys.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
apps/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Use one component per file; do not create multi-component files

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
apps/desktop/src/renderer/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Define keyboard shortcuts using the centralized system in apps/desktop/src/renderer/lib/shortcuts.ts with Arc Browser-inspired shortcut definitions

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
packages/ui/**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use TailwindCSS v4 and shadcn/ui for UI component styling and design

Files:

  • packages/ui/src/components/kbd.tsx
🧠 Learnings (14)
📓 Common learnings
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to apps/desktop/src/renderer/**/*.tsx : Define keyboard shortcuts using the centralized system in apps/desktop/src/renderer/lib/shortcuts.ts with Arc Browser-inspired shortcut definitions
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to apps/**/*.{tsx,ts} : Co-locate component dependencies (hooks, utils, constants, tests, stories) next to the file using them

Applied to files:

  • packages/ui/package.json
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to apps/**/*.{tsx,ts} : Structure React applications with one folder per component following the pattern: ComponentName/ComponentName.tsx with index.ts barrel export

Applied to files:

  • packages/ui/package.json
📚 Learning: 2025-11-24T21:33:13.244Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-11-24T21:33:13.244Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : Please use alias as defined in `tsconfig.json` when possible

Applied to files:

  • packages/ui/package.json
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to **/*.{ts,tsx,js,jsx,json} : Apply Biome formatting, linting, and import organization at the root level for all code files

Applied to files:

  • packages/ui/package.json
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to apps/desktop/src/renderer/**/*.tsx : Define keyboard shortcuts using the centralized system in apps/desktop/src/renderer/lib/shortcuts.ts with Arc Browser-inspired shortcut definitions

Applied to files:

  • packages/ui/package.json
  • apps/desktop/src/renderer/components/HotkeyModal/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/shared/hotkeys.ts
  • packages/ui/src/components/kbd.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to apps/**/*.test.{ts,tsx} : Co-locate tests with their corresponding components (e.g., Component.test.tsx next to Component.tsx)

Applied to files:

  • packages/ui/package.json
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to apps/**/*.tsx : Use one component per file; do not create multi-component files

Applied to files:

  • packages/ui/package.json
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to @(apps/desktop/src/renderer|apps/desktop/src/shared)/**/*.{ts,tsx} : Never import Node.js modules in Electron renderer process or shared code; use IPC for communication between main and renderer processes

Applied to files:

  • packages/ui/package.json
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to **/*.{ts,tsx} : Ensure TypeScript type checking passes across all packages using bun run typecheck

Applied to files:

  • packages/ui/package.json
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to packages/ui/**/*.{tsx,ts} : Use TailwindCSS v4 and shadcn/ui for UI component styling and design

Applied to files:

  • packages/ui/package.json
  • packages/ui/src/components/kbd.tsx
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to apps/desktop/src/main/lib/*-ipcs.ts : Implement Electron IPC handlers in dedicated files under apps/desktop/src/main/lib/ (e.g., workspace-ipcs.ts, terminal-ipcs.ts)

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/shared/hotkeys.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
📚 Learning: 2025-11-24T21:33:13.244Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-11-24T21:33:13.244Z
Learning: Applies to apps/desktop/**/*.{ts,tsx,js,jsx} : For Electron interprocess communication, ALWAYS use tRPC as defined in `src/lib/trpc`

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to apps/desktop/src/shared/ipc-channels.ts : Define all Electron IPC channel types in apps/desktop/src/shared/ipc-channels.ts before implementing handlers

Applied to files:

  • apps/desktop/src/shared/hotkeys.ts
🧬 Code graph analysis (5)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts (1)
apps/desktop/src/shared/hotkeys.ts (1)
  • isAppHotkey (253-255)
apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx (3)
apps/desktop/src/shared/hotkeys.ts (4)
  • HotkeyCategory (6-11)
  • HotkeyDefinition (13-22)
  • formatKeysForDisplay (169-191)
  • getHotkeysByCategory (147-164)
packages/ui/src/components/kbd.tsx (2)
  • KbdGroup (28-28)
  • Kbd (28-28)
packages/ui/src/components/dialog.tsx (4)
  • Dialog (132-132)
  • DialogContent (134-134)
  • DialogHeader (137-137)
  • DialogTitle (140-140)
packages/ui/src/components/kbd.tsx (1)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop/src/renderer/screens/main/index.tsx (2)
apps/desktop/src/shared/hotkeys.ts (1)
  • HOTKEYS (28-140)
apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx (1)
  • HotkeyModal (90-111)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx (1)
apps/desktop/src/shared/hotkeys.ts (1)
  • HOTKEYS (28-140)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build
🔇 Additional comments (18)
apps/desktop/src/shared/hotkeys.ts (2)

1-23: Well-structured type definitions.

The type system is clean with proper use of union types for HotkeyCategory and a well-defined interface. The as const satisfies pattern on the HOTKEYS object preserves literal types while ensuring type safety.


28-140: LGTM - Centralized hotkey definitions.

Good organization by category with consistent structure. The as const satisfies Record<string, HotkeyDefinition> pattern ensures type safety while preserving literal key types for HotkeyId. This aligns with the coding guidelines for centralizing keyboard shortcuts.

apps/desktop/src/renderer/components/HotkeyModal/index.ts (1)

1-1: LGTM - Proper barrel export.

Follows the component folder pattern with index.ts barrel export as per coding guidelines.

packages/ui/package.json (1)

25-25: LGTM - New kbd component export.

The export follows the existing pattern for UI component exports and is correctly placed in the exports map.

apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts (2)

110-111: Good placement of shortcut forwarding setup.

Setting up hotkey forwarding after terminal is opened but before fitting addons ensures shortcuts work correctly when terminal has focus.


124-141: The concern about isTrusted: false is technically valid but has no practical impact in this codebase.

Web search confirmed that synthetic events created via dispatchEvent(new KeyboardEvent(...)) will have isTrusted: false. However, examining the actual codebase reveals:

  1. No handlers check isTrusted: All 8 useHotkeys handlers found in the codebase are simple callbacks (toggling sidebar, opening modals, splitting terminals) with no event authenticity checks.

  2. react-hotkeys-hook v5.2.1 processes synthetic events normally: The library does not auto-filter events based on isTrusted. It will process the re-dispatched synthetic events correctly.

  3. The implementation works as intended: The function successfully forwards app hotkeys from the terminal to React components, allowing useHotkeys handlers to execute when expected.

Since no handlers rely on isTrusted, the synthetic nature of the re-dispatched event is irrelevant to the current implementation. The code functions correctly.

packages/ui/src/components/kbd.tsx (1)

3-16: Clean implementation of Kbd component.

Good use of TailwindCSS with cn utility for class composition. The contextual styling for tooltip content is a nice touch.

apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx (2)

11-11: LGTM - Centralized hotkey import.

Correctly uses the shared/hotkeys tsconfig alias as per coding guidelines.


38-66: LGTM - Proper migration to centralized HOTKEYS constants.

All terminal management shortcuts now use HOTKEYS.*.keys instead of hardcoded strings, improving maintainability and ensuring consistency with the hotkey modal display.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx (1)

30-40: LGTM!

The workspace switching logic is clean and correctly maps meta+1-9 to workspace indices. The use of Number(event.key) with range validation is appropriate for this use case.

apps/desktop/src/renderer/screens/main/index.tsx (3)

1-13: LGTM!

Imports are well-organized, and the centralized HOTKEYS constants are properly used as per the coding guidelines.


42-52: Verify the split direction mapping is intentional.

The hotkey-to-action mapping appears inverted:

  • SPLIT_HORIZONTAL ("Split Horizontal") calls splitTabVertical
  • SPLIT_VERTICAL ("Split Vertical") calls splitTabHorizontal

This could be intentional if "horizontal split" means splitting side-by-side (creating a vertical divider), but the naming is confusing. Please verify this matches the expected behavior or consider renaming for clarity.


27-27: LGTM!

The HotkeyModal integration follows the controlled component pattern correctly. The empty dependency array in useHotkeys is appropriate since setHotkeyModalOpen is a stable reference from useState.

Also applies to: 36-36, 65-65

apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx (5)

28-41: LGTM!

HotkeyRow is a clean presentational component. Using array index as the key is acceptable here since the keys list is static and derived from the hotkey definition.


43-65: LGTM!

HotkeySection handles empty categories gracefully with an early return and uses hotkey.keys as a stable unique key.


67-88: LGTM!

The consolidation logic is clean and improves UX by displaying workspace shortcuts as a single "⌘+1-9" entry instead of nine separate rows. The synthetic "meta+1-9" key string is display-only and won't conflict with actual hotkey registration.


90-111: LGTM!

The HotkeyModal component is well-structured as a controlled dialog. While getHotkeysByCategory() is called on each render, it operates on static data, so memoization would be premature optimization.


1-111: Note on file structure.

The file contains multiple components (HotkeyRow, HotkeySection, HotkeyModal), but since only HotkeyModal is exported and the others are tightly-coupled internal helpers, this is an acceptable pattern. The coding guideline for "one component per file" is primarily concerned with preventing multiple public exports.

Comment thread apps/desktop/src/shared/hotkeys.ts
Comment on lines +18 to +26
function KbdGroup({ className, ...props }: React.ComponentProps<"div">) {
return (
<kbd
data-slot="kbd-group"
className={cn("inline-flex items-center gap-1", className)}
{...props}
/>
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Type mismatch: props typed as <div> but renders <kbd>.

KbdGroup accepts React.ComponentProps<"div"> but renders a <kbd> element. This mismatch could cause issues if div-specific attributes are passed that aren't valid on <kbd>.

-function KbdGroup({ className, ...props }: React.ComponentProps<"div">) {
+function KbdGroup({ className, ...props }: React.ComponentProps<"kbd">) {
 	return (
 		<kbd
 			data-slot="kbd-group"
 			className={cn("inline-flex items-center gap-1", className)}
 			{...props}
 		/>
 	);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function KbdGroup({ className, ...props }: React.ComponentProps<"div">) {
return (
<kbd
data-slot="kbd-group"
className={cn("inline-flex items-center gap-1", className)}
{...props}
/>
);
}
function KbdGroup({ className, ...props }: React.ComponentProps<"kbd">) {
return (
<kbd
data-slot="kbd-group"
className={cn("inline-flex items-center gap-1", className)}
{...props}
/>
);
}
🤖 Prompt for AI Agents
In packages/ui/src/components/kbd.tsx around lines 18 to 26, the component types
props as React.ComponentProps<"div"> but renders a <kbd>, causing a mismatch;
change the prop type to React.ComponentProps<"kbd"> (or
React.HTMLAttributes<HTMLElement> if broader) and keep the destructuring of
className and ...props so only attributes valid on <kbd> are allowed; update any
imports/types if needed and run typecheck.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
apps/desktop/src/shared/hotkeys.ts (1)

196-236: matchesHotkey parses ctrl but never validates it, and meta/ctrl are conflated

You strip "ctrl" out of parts when deriving key, but never track a requiresCtrl flag. At the same time hasMeta is computed as event.metaKey || event.ctrlKey, so ctrl-only combos can interfere with meta-only definitions and ctrl+... hotkeys can never be expressed cleanly. This was already raised on an earlier commit; re-raising here so it gets fixed.

A minimal, self-contained fix that preserves “meta = Cmd on Mac, Ctrl on Windows/Linux” while adding proper ctrl handling would look like:

 export function matchesHotkey(
   event: KeyboardEvent,
   hotkeyString: string,
 ): boolean {
   const parts = hotkeyString.toLowerCase().split("+");

   const requiresMeta = parts.includes("meta");
   const requiresShift = parts.includes("shift");
   const requiresAlt = parts.includes("alt");
+  const requiresCtrl = parts.includes("ctrl");

   // Get the actual key (last part that's not a modifier)
   const key = parts.find((p) => !["meta", "shift", "alt", "ctrl"].includes(p));

   if (!key) return false;

-  const hasMeta = event.metaKey || event.ctrlKey;
+  const hasMeta = event.metaKey;
+  const hasCtrl = event.ctrlKey;
   const hasShift = event.shiftKey;
   const hasAlt = event.altKey;

-  if (requiresMeta !== hasMeta) return false;
+  // "meta" maps to Cmd on Mac, Ctrl on Windows/Linux
+  if (requiresMeta && !event.metaKey && !event.ctrlKey) return false;
+  if (!requiresMeta && (event.metaKey || event.ctrlKey) && !requiresCtrl) return false;
+  if (requiresCtrl !== hasCtrl) return false;
   if (requiresShift !== hasShift) return false;
   if (requiresAlt !== hasAlt) return false;

   // Match the key
   const eventKey = event.key.toLowerCase();
   const eventCode = event.code.toLowerCase();

This keeps existing meta+… behaviour while making ctrl+… hotkeys first-class and avoids accidental matches when extra modifiers are held.

🧹 Nitpick comments (2)
apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx (1)

68-88: Workspace jump consolidation depends on labels; consider a more structural approach

consolidateWorkspaceJumps currently identifies jump shortcuts via the label regex ^Switch to Workspace \d$. This makes the behaviour fragile if labels are ever edited or localized, since the modal logic is now coupled to exact copy:

const workspaceJumpPattern = /^Switch to Workspace \d$/;

const filtered = hotkeys.filter((h) => !workspaceJumpPattern.test(h.label));
filtered.unshift({
	keys: "meta+1-9",
	label: "Switch to Workspace 1-9",
	category: "Workspace",
});

If possible, consider matching on something more stable, e.g.:

  • A HotkeyId (by exposing the ID alongside HotkeyDefinition from getHotkeysByCategory), or
  • The keys pattern (e.g. /^meta\+[1-9]$/ in combination with category === "Workspace").

That would make consolidation resilient to copy and i18n changes.

Separately, this file currently defines three React components (HotkeyRow, HotkeySection, HotkeyModal). To align more strictly with the “one component per file” guideline for apps/**/*.tsx, you could either extract the helper components into their own files or convert them to non-component helpers (e.g. lowercase functions returning JSX).

As per coding guidelines, apps/**/*.tsx should prefer one component per file.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx (1)

29-39: Reuse centralized HOTKEYS for workspace shortcuts to avoid duplication

The workspace shortcut handler works correctly but hardcodes the key combinations. Since JUMP_TO_WORKSPACE_1..9 are already defined in HOTKEYS, derive the key list from those definitions to prevent drift if the central map is updated:

+import { HOTKEYS } from "shared/hotkeys";-// Workspace switching shortcuts (⌘+1-9) - combined into single hook call
-const workspaceKeys = Array.from({ length: 9 }, (_, i) => `meta+${i + 1}`).join(", ");
+// Workspace switching shortcuts (⌘+1-9) - derived from HOTKEYS
+const workspaceKeys = [
+	HOTKEYS.JUMP_TO_WORKSPACE_1.keys,
+	HOTKEYS.JUMP_TO_WORKSPACE_2.keys,
+	HOTKEYS.JUMP_TO_WORKSPACE_3.keys,
+	HOTKEYS.JUMP_TO_WORKSPACE_4.keys,
+	HOTKEYS.JUMP_TO_WORKSPACE_5.keys,
+	HOTKEYS.JUMP_TO_WORKSPACE_6.keys,
+	HOTKEYS.JUMP_TO_WORKSPACE_7.keys,
+	HOTKEYS.JUMP_TO_WORKSPACE_8.keys,
+	HOTKEYS.JUMP_TO_WORKSPACE_9.keys,
+];
 useHotkeys(workspaceKeys, (event) => {

This ensures the handler stays synchronized with centralized hotkey definitions without manual maintenance.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6766cdf and e20f53c.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx (1 hunks)
  • apps/desktop/src/renderer/components/HotkeyModal/index.ts (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts (2 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx (2 hunks)
  • apps/desktop/src/renderer/screens/main/index.tsx (4 hunks)
  • apps/desktop/src/shared/hotkeys.ts (1 hunks)
  • packages/ui/package.json (1 hunks)
  • packages/ui/src/components/kbd.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/ui/src/components/kbd.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • packages/ui/package.json
  • apps/desktop/src/renderer/components/HotkeyModal/index.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Biome formatting, linting, and import organization at the root level for all code files

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/shared/hotkeys.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid using any type; use type-safe approaches instead, unless necessary
Ensure TypeScript type checking passes across all packages using bun run typecheck

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/shared/hotkeys.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
apps/**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

apps/**/*.{tsx,ts}: Structure React applications with one folder per component following the pattern: ComponentName/ComponentName.tsx with index.ts barrel export
Co-locate component dependencies (hooks, utils, constants, tests, stories) next to the file using them

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/shared/hotkeys.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
apps/desktop/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/shared/hotkeys.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: Please use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/shared/hotkeys.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
apps/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Use one component per file; do not create multi-component files

Files:

  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
apps/desktop/src/renderer/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Define keyboard shortcuts using the centralized system in apps/desktop/src/renderer/lib/shortcuts.ts with Arc Browser-inspired shortcut definitions

Files:

  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to apps/desktop/src/renderer/**/*.tsx : Define keyboard shortcuts using the centralized system in apps/desktop/src/renderer/lib/shortcuts.ts with Arc Browser-inspired shortcut definitions
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to apps/desktop/src/renderer/**/*.tsx : Define keyboard shortcuts using the centralized system in apps/desktop/src/renderer/lib/shortcuts.ts with Arc Browser-inspired shortcut definitions

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/shared/hotkeys.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to apps/desktop/src/main/lib/*-ipcs.ts : Implement Electron IPC handlers in dedicated files under apps/desktop/src/main/lib/ (e.g., workspace-ipcs.ts, terminal-ipcs.ts)

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx
  • apps/desktop/src/shared/hotkeys.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
📚 Learning: 2025-11-24T21:33:13.244Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-11-24T21:33:13.244Z
Learning: Applies to apps/desktop/**/*.{ts,tsx,js,jsx} : For Electron interprocess communication, ALWAYS use tRPC as defined in `src/lib/trpc`

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
📚 Learning: 2025-11-24T21:32:46.559Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T21:32:46.559Z
Learning: Applies to apps/desktop/src/shared/ipc-channels.ts : Define all Electron IPC channel types in apps/desktop/src/shared/ipc-channels.ts before implementing handlers

Applied to files:

  • apps/desktop/src/shared/hotkeys.ts
📚 Learning: 2025-11-24T21:33:13.244Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-11-24T21:33:13.244Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : Please use alias as defined in `tsconfig.json` when possible

Applied to files:

  • apps/desktop/src/shared/hotkeys.ts
🧬 Code graph analysis (1)
apps/desktop/src/renderer/screens/main/index.tsx (2)
apps/desktop/src/shared/hotkeys.ts (1)
  • HOTKEYS (28-140)
apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx (1)
  • HotkeyModal (90-111)
🪛 GitHub Actions: CI
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/index.tsx

[error] 28-46: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

🔇 Additional comments (5)
apps/desktop/src/shared/hotkeys.ts (1)

24-191: Centralized HOTKEYS + helpers are well-structured and strongly typed

The HOTKEYS map, category typing, getHotkeysByCategory, and formatKeysForDisplay form a clean, strongly-typed API that should scale well as you add more shortcuts. The as const + HotkeyId pattern is especially nice for keeping usages in sync.

apps/desktop/src/renderer/screens/main/index.tsx (2)

1-5: MainScreen hotkey wiring and HotkeyModal integration look solid

Using HOTKEYS for global shortcuts and gating actions on isWorkspaceView/activeWorkspaceId keeps behaviour predictable, and the HotkeyModal state/placement at the root of MainScreen is appropriate. This should make it easy for users to discover shortcuts without impacting existing layout logic.

Also applies to: 27-37, 65-66


42-52: I'll help you verify the review comment about the SPLIT_HORIZONTAL/SPLIT_VERTICAL mapping. Let me gather the necessary information from the codebase.
<function_calls>


#!/bin/bash

First, find the shortcuts definition file

find apps/desktop -name "shortcuts.ts" -o -name "shortcuts.js"


</function_calls>

I'll search for the shortcuts and split tab implementations:

#!/bin/bash
# Find shortcuts file and examine HOTKEYS definition
fd -t f shortcuts \. apps/desktop/src/renderer/lib/
</parameter>
</invoke>
</function_calls>

```shell
#!/bin/bash
# Search for SPLIT_HORIZONTAL and SPLIT_VERTICAL hotkey definitions
rg -n "SPLIT_HORIZONTAL|SPLIT_VERTICAL" apps/desktop/src/renderer/lib/ -A 2 -B 2
</parameter>
</invoke>
</function_calls>

```shell
#!/bin/bash
# Search for splitTabVertical and splitTabHorizontal implementations
rg -n "splitTabVertical|splitTabHorizontal" apps/desktop/src/renderer/ -A 5 -B 2 --type ts --type tsx
</parameter>
</invoke>
</function_calls>

```shell
#!/bin/bash
# Get more context from the main/index.tsx file
cat -n apps/desktop/src/renderer/screens/main/index.tsx | head -70 | tail -40
</parameter>
</invoke>
</function_calls>

Let me run these scripts to understand the split tab behavior:

</blockquote></details>
<details>
<summary>apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts (1)</summary><blockquote>

`110-141`: **Terminal hotkey forwarding to app handlers is well-contained**

The `setupShortcutForwarding` handler cleanly forwards only meta/ctrl keydowns that match `isAppHotkey` to `document`, and returns `false` so XTerm ignores those events. This keeps terminal input behaviour intact while letting global app shortcuts continue to work when the terminal is focused, without introducing extra listeners or cleanup complexity.

</blockquote></details>
<details>
<summary>apps/desktop/src/renderer/components/HotkeyModal/HotkeyModal.tsx (1)</summary><blockquote>

`90-110`: **HotkeyModal composition and use of shared hotkey utilities look good**

The modal correctly pulls from `getHotkeysByCategory`, uses a fixed `CATEGORY_ORDER`, and renders keys via `formatKeysForDisplay` + `KbdGroup`, which keeps the UI in sync with the centralized HOTKEYS map. The props surface (`open`, `onOpenChange`) also matches typical dialog patterns, making it easy to host from `MainScreen`.

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
apps/desktop/src/shared/hotkeys.ts (1)

197-241: ctrl modifier is parsed but never enforced; ctrl‑only hotkeys won’t work.

In matchesHotkey, "ctrl" is excluded from key (Line 208) but there’s no requiresCtrl / hasCtrl check, and hasMeta is currently event.metaKey || event.ctrlKey. That means:

  • A hotkey defined as "ctrl+k" will never match (because requiresMeta is false but hasMeta becomes true when Ctrl is pressed).
  • There’s no way to require Ctrl separately from Meta.

This is the same latent bug called out in the earlier review and still needs a fix.

Minimal patch to distinguish Meta vs Ctrl and actually support "ctrl+...":

 export function matchesHotkey(
   event: KeyboardEvent,
   hotkeyString: string,
 ): boolean {
   const parts = hotkeyString.toLowerCase().split("+");

   const requiresMeta = parts.includes("meta");
   const requiresShift = parts.includes("shift");
   const requiresAlt = parts.includes("alt");
+  const requiresCtrl = parts.includes("ctrl");

   // Get the actual key (last part that's not a modifier)
   const key = parts.find((p) => !["meta", "shift", "alt", "ctrl"].includes(p));

   if (!key) return false;

-  const hasMeta = event.metaKey || event.ctrlKey;
+  const hasMeta = event.metaKey;
+  const hasCtrl = event.ctrlKey;
   const hasShift = event.shiftKey;
   const hasAlt = event.altKey;

-  if (requiresMeta !== hasMeta) return false;
+  // meta maps to Cmd on macOS and Ctrl on Windows/Linux
+  if (requiresMeta && !event.metaKey && !event.ctrlKey) return false;
+  if (!requiresMeta && (event.metaKey || event.ctrlKey) && !requiresCtrl) return false;
+  if (requiresCtrl !== hasCtrl) return false;
   if (requiresShift !== hasShift) return false;
   if (requiresAlt !== hasAlt) return false;

This keeps the “meta = Cmd/Ctrl” semantics while allowing explicit "ctrl+..." hotkeys to behave correctly.

🧹 Nitpick comments (2)
apps/desktop/src/shared/hotkeys.ts (2)

169-192: Display mapping is good; consider OS‑aware meta and explicit space handling.

The symbol map is nice, but today meta always displays as ⌘ and space would display as " " (since only event.code is “space” while display here is string‑based). If you ever add meta or space bindings on Windows/Linux, consider:

  • Making the meta glyph OS‑aware (e.g., “Ctrl” on non‑macOS).
  • Normalizing "space" to a visible symbol consistently (you already have "space": "␣"; ensure callers don’t pass a literal " " instead).

Not urgent, but worth tracking if you tune cross‑platform UX.


246-260: findMatchingHotkey / isAppHotkey are fine for current scale.

Linear scan over HOTKEYS is acceptable given the small set, and isAppHotkey is a clean wrapper for the terminal forwarding path. If the hotkey set grows substantially, you could later index by normalized key/modifier tuple to avoid scanning, but that’s not necessary now.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e20f53c and 3c723f2.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • apps/desktop/package.json (1 hunks)
  • apps/desktop/src/shared/hotkeys.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
apps/desktop/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/shared/hotkeys.ts
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: Please use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary

Files:

  • apps/desktop/src/shared/hotkeys.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid using any type - use explicit types instead for type safety
Use camelCase for variable and function names following existing codebase patterns
Keep diffs minimal with targeted edits only - avoid unnecessary changes when making modifications
Follow existing patterns and match the codebase style when writing new code

Files:

  • apps/desktop/src/shared/hotkeys.ts
🧠 Learnings (1)
📚 Learning: 2025-11-28T01:03:47.951Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.951Z
Learning: Applies to apps/desktop/src/renderer/**/*.{ts,tsx} : Never import Node.js modules (fs, path, os, net, etc.) in renderer process code - browser environment only

Applied to files:

  • apps/desktop/package.json
🔇 Additional comments (3)
apps/desktop/src/shared/hotkeys.ts (2)

6-140: Centralized HOTKEYS shape and typing look solid.

Typed HotkeyCategory, HotkeyDefinition, and HOTKEYS with as const satisfies Record<string, HotkeyDefinition> give you nice safety, and HotkeyId is a good derived type. This is a clean foundation for the modal and for wiring shortcuts across the app.


147-164: getHotkeysByCategory is straightforward and type‑safe.

Initialization covers all HotkeyCategory variants explicitly and the grouping loop is clear; no issues here.

apps/desktop/package.json (1)

53-53: dnd-core is correctly declared and necessary — it's directly imported in the codebase.

The concern is resolved. dnd-core@^16.0.1 is appropriately declared because the project directly imports createDragDropManager from it in apps/desktop/src/renderer/lib/dnd.ts. The version aligns perfectly with react-dnd@16.0.1, and react-dnd 16.x has peer dependency react >= 16.14, which is compatible with React 19.1.1 used in this project. No action needed.

saddlepaddle and others added 4 commits November 27, 2025 23:05
- Add centralized HOTKEYS constants in shared/hotkeys.ts with categories
- Add HotkeyModal component (⌘+/) to display all keyboard shortcuts
- Add Kbd component from shadcn/ui for displaying key combinations
- Forward app hotkeys from terminal to document so useHotkeys works when terminal is focused
- Update shortcut scheme: ⌘+1-9 for workspaces, ⌘+Up/Down for terminals

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@saddlepaddle saddlepaddle merged commit cbc5339 into main Nov 28, 2025
6 of 7 checks passed
@Kitenite Kitenite deleted the pearl-wind-69 branch November 29, 2025 06:30
@coderabbitai coderabbitai Bot mentioned this pull request Dec 1, 2025
2 tasks
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