Skip to content

feat(desktop): add JetBrains IDEs submenu to Open button - #277

Merged
Kitenite merged 3 commits into
mainfrom
formal-reindeer-f940fd
Dec 7, 2025
Merged

Kitenite merged 3 commits into
mainfrom
formal-reindeer-f940fd

Conversation

@Kitenite

@Kitenite Kitenite commented Dec 7, 2025 •

Copy link
Copy Markdown
Member

Summary

  • Add a JetBrains submenu under the Open dropdown button in the desktop app
  • Include all major JetBrains IDEs: IntelliJ IDEA, WebStorm, PyCharm, PhpStorm, RubyMine, GoLand, CLion, Rider, DataGrip, AppCode, Fleet, and RustRover
  • Use react-icons/si for JetBrains icons (no custom assets needed)

Changes

  • apps/desktop/src/main/lib/db/schemas.ts - Added 12 JetBrains IDE types to EXTERNAL_APPS
  • apps/desktop/src/lib/trpc/routers/external/index.ts - Added macOS open commands for all JetBrains IDEs
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx - Added JetBrains submenu with icons from react-icons

Test plan

  • Open the desktop app and click the "Open" dropdown
  • Verify JetBrains submenu appears with arrow indicator
  • Hover over JetBrains to see the submenu with all IDEs
  • Click on a JetBrains IDE to verify it opens (if installed)
  • Verify selected JetBrains IDE becomes the default "Open in" option

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added support for 12 JetBrains IDEs (IntelliJ, WebStorm, PyCharm, PhpStorm, RubyMine, GoLand, CLion, Rider, DataGrip, AppCode, Fleet, RustRover) for opening projects from the app.
    • Introduced a JetBrains submenu in the Open menu for convenient IDE selection, updated app option listing, and expanded IDE icons for clearer visual selection.

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

Add a JetBrains submenu under the Open dropdown that includes all major
JetBrains IDEs: IntelliJ IDEA, WebStorm, PyCharm, PhpStorm, RubyMine,
GoLand, CLion, Rider, DataGrip, AppCode, Fleet, and RustRover.

Uses react-icons/si for JetBrains icons instead of custom assets.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Dec 7, 2025 •

Copy link
Copy Markdown

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

Project Deployment Preview Comments Updated (UTC)
website Ready Ready Preview Comment Dec 7, 2025 11:34pm

@coderabbitai

coderabbitai Bot commented Dec 7, 2025 •

Copy link
Copy Markdown
Contributor

Walkthrough

Adds twelve JetBrains IDEs as supported external apps: registers them in the desktop schema, adds router branches returning native open commands, and exposes them in the renderer's OpenInButton via a JetBrains submenu and expanded app option/icon handling. (50 words)

Changes

Cohort / File(s) Change Summary
Backend: EXTERNAL_APPS & types
apps/desktop/src/main/lib/db/schemas.ts
Added JetBrains IDE identifiers (intellij, webstorm, pycharm, phpstorm, rubymine, goland, clion, rider, datagrip, appcode, fleet, rustrover) to EXTERNAL_APPS, expanding the ExternalApp union.
Router: getAppCommand mappings
apps/desktop/src/lib/trpc/routers/external/index.ts
Added case branches for each new JetBrains IDE in getAppCommand, returning { command: "open", args: ["-a", "<IDE Name>", targetPath] } where applicable; default behavior unchanged.
Renderer: OpenInButton UI & icons
apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
Introduced a JetBrains submenu with new IDE options and icons; merged JetBrains options into ALL_APP_OPTIONS; updated option lookup to use ALL_APP_OPTIONS; added submenu components and multiple JetBrains icon imports.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to:
    • Consistency across the twelve getAppCommand cases and argument formatting.
    • ALL_APP_OPTIONS lookup and fallback behavior (last-used/current app resolution).
    • Dropdown submenu nesting and event/keyboard interactions in OpenInButton.
    • Icon rendering branches (image vs. React component discrimination).

Possibly related PRs

Poem

🐰 Twelve IDEs hop into the glade,
Icons bright where choices are made.
Open, flutter, hope in one click—
JetBrains runners, tidy and quick.
A bunny cheers: "More tools, more play!"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding a JetBrains IDEs submenu to the Open button in the desktop application.
Description check ✅ Passed The description covers the main objectives, lists specific files changed with their modifications, and includes a test plan. However, it does not follow the provided template structure with formal sections.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch formal-reindeer-f940fd

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.

@github-actions

github-actions Bot commented Dec 7, 2025 •

Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

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

127-128: Hardcoded array index for fallback is fragile.

The fallback APP_OPTIONS[1] relies on array ordering. If APP_OPTIONS is reordered, this could silently return an unexpected default.

Consider using a named constant or finding by ID:

-const getAppOption = (id: ExternalApp) =>
-	ALL_APP_OPTIONS.find((app) => app.id === id) ?? APP_OPTIONS[1];
+const DEFAULT_APP_OPTION = APP_OPTIONS.find((app) => app.id === "cursor") ?? APP_OPTIONS[0];
+
+const getAppOption = (id: ExternalApp) =>
+	ALL_APP_OPTIONS.find((app) => app.id === id) ?? DEFAULT_APP_OPTION;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00d31e0 and 017f210.

📒 Files selected for processing (3)
  • apps/desktop/src/lib/trpc/routers/external/index.ts (1 hunks)
  • apps/desktop/src/main/lib/db/schemas.ts (1 hunks)
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx (4 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
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/main/lib/db/schemas.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.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/main/lib/db/schemas.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Co-locate component dependencies (utils, hooks, constants, config, tests, stories) next to the file using them
Avoid any type in TypeScript unless absolutely necessary

Files:

  • apps/desktop/src/main/lib/db/schemas.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
apps/desktop/src/{main,renderer,shared}/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use type-safe IPC system for communication between Electron main and renderer processes

Files:

  • apps/desktop/src/main/lib/db/schemas.ts
**/{components,pages}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/{components,pages}/**/*.tsx: Use one folder per component with structure ComponentName/ComponentName.tsx plus index.ts for barrel export
Create one component per file - do not use multi-component files

Files:

  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
apps/desktop/src/{renderer,shared,preload}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules in renderer process code or shared code in the desktop app

Files:

  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
🧠 Learnings (2)
📚 Learning: 2025-11-24T21:33:13.267Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-11-24T21:33:13.267Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : Please use alias as defined in `tsconfig.json` when possible

Applied to files:

  • apps/desktop/src/main/lib/db/schemas.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
📚 Learning: 2025-12-06T18:44:13.290Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T18:44:13.290Z
Learning: Applies to src/components/{ui,ai-elements,react-flow}/**/*.tsx : Shadcn/ui components in `src/components/ui/`, `src/components/ai-elements`, and `src/components/react-flow/` use kebab-case single files (e.g., `button.tsx`) for shadcn CLI compatibility

Applied to files:

  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
🧬 Code graph analysis (1)
apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx (2)
apps/desktop/src/main/lib/db/schemas.ts (1)
  • ExternalApp (96-96)
packages/ui/src/components/dropdown-menu.tsx (4)
  • DropdownMenuItem (251-251)
  • DropdownMenuSub (257-257)
  • DropdownMenuSubTrigger (258-258)
  • DropdownMenuSubContent (259-259)
⏰ 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 (6)
apps/desktop/src/main/lib/db/schemas.ts (1)

81-93: LGTM! Clean extension of the EXTERNAL_APPS constant.

The JetBrains IDE identifiers follow the existing naming convention (lowercase, single-word) and are properly grouped with a comment. The derived ExternalApp type will automatically include these new values.

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

8-30: Imports are well-organized.

The new imports for dropdown sub-menu components, ComponentType, and JetBrains icons are appropriate. The type-only import from main/lib/db/schemas (line 14) is acceptable since it only imports a type and doesn't pull in Node.js runtime code.


41-55: Good use of discriminated union for icon types.

The iconType discriminator enables type-safe handling when rendering different icon formats. This is a clean pattern for supporting both image URLs and React components.


73-123: JETBRAINS_OPTIONS array is well-structured.

The fallback to SiJetbrains for AppCode, Fleet, and RustRover (with explanatory comment) is a reasonable approach when specific icons aren't available. All IDs correctly align with the schema and router definitions.


130-148: AppIcon component is clean and type-safe.

The discriminated union pattern enables proper type narrowing, and the component correctly handles both icon formats. The implementation is straightforward and easy to maintain.


242-264: JetBrains submenu implementation is well-structured.

The submenu cleanly groups all JetBrains IDEs, preventing menu clutter. The implementation correctly uses the @superset/ui dropdown sub-menu components and maintains consistency with the main menu items (including keyboard shortcut display when applicable).

Replace react-icons monochrome icons with official JetBrains color SVG
logos from https://github.com/JetBrains/logos repository.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace the JetBrains logo with text to the icon-only version for
better appearance in the dropdown menu.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 0

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

73-76: getAppOption fallback is slightly brittle to APP_OPTIONS reordering

Using ALL_APP_OPTIONS for lookup correctly supports both built‑in and JetBrains apps. The fallback APP_OPTIONS[1] (cursor) works today but couples behavior to the array index.

Consider making the fallback explicit by id to avoid accidental changes if APP_OPTIONS is reordered:

-const ALL_APP_OPTIONS = [...APP_OPTIONS, ...JETBRAINS_OPTIONS];
-
-const getAppOption = (id: ExternalApp) =>
-  ALL_APP_OPTIONS.find((app) => app.id === id) ?? APP_OPTIONS[1];
+const ALL_APP_OPTIONS = [...APP_OPTIONS, ...JETBRAINS_OPTIONS];
+
+const DEFAULT_APP_ID: ExternalApp = "cursor";
+
+const getAppOption = (id: ExternalApp) =>
+  ALL_APP_OPTIONS.find((app) => app.id === id) ??
+  ALL_APP_OPTIONS.find((app) => app.id === DEFAULT_APP_ID)!;

178-208: JetBrains submenu integrates correctly; consider DRYing item rendering

The DropdownMenuSub for JetBrains looks correctly wired: trigger label and icon are clear, and JETBRAINS_OPTIONS map to items with the same structure and shortcut hint behavior as the main list. Functionally this is solid.

There is some duplication between the main APP_OPTIONS.map block and the JETBRAINS_OPTIONS.map block (same item layout and shortcut logic). If it starts to grow further, you could introduce a small non‑component helper to render an item to reduce repetition while still honoring the “one component per file” guideline.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 017f210 and e81a0d3.

⛔ Files ignored due to path filters (13)
  • apps/desktop/src/renderer/assets/app-icons/appcode.svg is excluded by !**/*.svg
  • apps/desktop/src/renderer/assets/app-icons/clion.svg is excluded by !**/*.svg
  • apps/desktop/src/renderer/assets/app-icons/datagrip.svg is excluded by !**/*.svg
  • apps/desktop/src/renderer/assets/app-icons/fleet.svg is excluded by !**/*.svg
  • apps/desktop/src/renderer/assets/app-icons/goland.svg is excluded by !**/*.svg
  • apps/desktop/src/renderer/assets/app-icons/intellij.svg is excluded by !**/*.svg
  • apps/desktop/src/renderer/assets/app-icons/jetbrains.svg is excluded by !**/*.svg
  • apps/desktop/src/renderer/assets/app-icons/phpstorm.svg is excluded by !**/*.svg
  • apps/desktop/src/renderer/assets/app-icons/pycharm.svg is excluded by !**/*.svg
  • apps/desktop/src/renderer/assets/app-icons/rider.svg is excluded by !**/*.svg
  • apps/desktop/src/renderer/assets/app-icons/rubymine.svg is excluded by !**/*.svg
  • apps/desktop/src/renderer/assets/app-icons/rustrover.svg is excluded by !**/*.svg
  • apps/desktop/src/renderer/assets/app-icons/webstorm.svg is excluded by !**/*.svg
📒 Files selected for processing (1)
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx (3 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
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/OpenInButton/OpenInButton.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/OpenInButton/OpenInButton.tsx
**/{components,pages}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/{components,pages}/**/*.tsx: Use one folder per component with structure ComponentName/ComponentName.tsx plus index.ts for barrel export
Create one component per file - do not use multi-component files

Files:

  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Co-locate component dependencies (utils, hooks, constants, config, tests, stories) next to the file using them
Avoid any type in TypeScript unless absolutely necessary

Files:

  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
apps/desktop/src/{renderer,shared,preload}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules in renderer process code or shared code in the desktop app

Files:

  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
🧬 Code graph analysis (1)
apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx (2)
apps/desktop/src/main/lib/db/schemas.ts (1)
  • ExternalApp (96-96)
packages/ui/src/components/dropdown-menu.tsx (4)
  • DropdownMenuSub (257-257)
  • DropdownMenuSubTrigger (258-258)
  • DropdownMenuSubContent (259-259)
  • DropdownMenuItem (251-251)
⏰ 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 (3)
apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx (3)

3-12: Correct use of dropdown submenu primitives

Importing DropdownMenuSub, DropdownMenuSubContent, and DropdownMenuSubTrigger from the shared UI layer cleanly aligns the new JetBrains submenu with existing dropdown patterns; no issues here.

As per coding guidelines, this keeps renderer code using shared UI components without pulling in Node APIs.


18-38: JetBrains icon imports look consistent with existing asset usage

The new JetBrains icon imports follow the existing renderer/assets/app-icons/* pattern and keep all icons as static resources in the renderer, which is consistent with current usage and respects the “no Node modules in renderer” rule.

As per coding guidelines, using renderer/* aliases here is appropriate.


58-71: JETBRAINS_OPTIONS mapping is straightforward and type‑safe

JETBRAINS_OPTIONS cleanly maps each JetBrains ExternalApp id to a label and icon, mirroring the existing APP_OPTIONS structure. Assuming the ids are present in EXTERNAL_APPS, this should remain type‑safe and future‑proof.

@Kitenite
Kitenite merged commit 9810396 into main Dec 7, 2025
8 checks passed
@Kitenite
Kitenite deleted the formal-reindeer-f940fd branch December 7, 2025 23:41

This branch was successfully deployed

1 active deployment
Preview — e81a0d3e Deployed Dec 7, 2025 by vercel[bot]
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