Skip to content

feat: add JetBrains IDE suite to Open In Apps presets#7938

Open
Jonezzyboy wants to merge 4 commits into
stablyai:mainfrom
Jonezzyboy:jetbrains-open-in-presets
Open

feat: add JetBrains IDE suite to Open In Apps presets#7938
Jonezzyboy wants to merge 4 commits into
stablyai:mainfrom
Jonezzyboy:jetbrains-open-in-presets

Conversation

@Jonezzyboy

@Jonezzyboy Jonezzyboy commented Jul 9, 2026

Copy link
Copy Markdown

Summary

Adds the JetBrains IDE suite as built-in presets in Settings → General → Open In Apps → Add app: IntelliJ IDEA, WebStorm, PyCharm, PhpStorm, GoLand, Rider, CLion, RubyMine, DataGrip, and RustRover.

  • Presets are grouped under a JetBrains IDEs submenu (keeps the Add app dropdown compact; VS Code / Cursor / Zed / Custom app stay top-level).
  • Each preset command matches the launcher script generated by JetBrains Toolbox (idea, webstorm, pycharm, …), which is the same cross-platform launcher name on macOS, Linux, and Windows.
  • Each preset ships with the official JetBrains product icon SVG bundled in resources/ via a new optional iconSrc field on OpenInAppPreset. The existing Google favicon lookup can't distinguish JetBrains products (they all share jetbrains.com), so bundled icons take precedence and the favicon path remains the fallback for the existing presets.
  • Adds jetbrains / intellij / webstorm settings-search keywords so the section is discoverable, plus the corresponding i18n catalog entries for all five locales (brand names, identical across locales).
  • Users who previously added a JetBrains IDE as a custom app with a matching command (e.g. webstorm) automatically get the preset icon/label treatment, since presets are matched by command.

Screenshots

orca-jetbrains-submenu

Testing

  • pnpm lint — passes except one pre-existing switch-exhaustiveness-check error in src/main/ipc/notification-authorization-status.ts:76, reproduced identically on a clean main checkout; this branch does not touch that file.
  • pnpm typecheck
  • pnpm test — all tests in the changed areas pass. The full suite shows ~39–49 environment-sensitive failures (git/relay/ssh/daemon/release-script integration tests) on this machine; the same files fail identically on a clean main checkout, and the count varies between runs, so they are unrelated to this change.
  • pnpm build
  • Added tests: preset grouping and ordering of the JetBrains suite, stable preset row creation (createPresetOpenInApplication), and that JetBrains presets render their bundled icon rather than the shared favicon fallback (OpenInMenuSetting.test.ts).

Also verified end-to-end in the running dev app: opened Settings → General → Open In Apps → Add app, confirmed the JetBrains IDEs submenu renders all ten presets with distinct product icons, and that adding a preset creates the expected row.

AI Review Report

Reviewed with Claude Code. Main risks checked and outcomes:

  • Cross-platform (macOS / Linux / Windows): preset commands are JetBrains Toolbox launcher names, identical on all three platforms (Toolbox generates .cmd shims on Windows); launching goes through the existing Open In command path, unchanged by this PR. No keyboard shortcuts, shortcut labels, file paths, or Electron platform APIs are touched. Icons are bundled static assets, so no platform-dependent network or filesystem behavior.
  • Type safety: the array literal initially widened group: 'jetbrains' to string; fixed by annotating the catalog factory as (): OpenInAppPreset[].
  • Regression risk to existing presets: VS Code / Cursor / Zed rows are untouched; iconSrc is optional and the favicon fallback is preserved. Preset matching by command is unchanged.
  • UI consistency: the submenu uses the existing shadcn DropdownMenuSub primitives already present in components/ui/dropdown-menu.tsx; item rendering is shared between top-level and submenu entries (extracted renderPresetItem), including the disabled/"Added" states and the 8-app limit.
  • Localization: i18n keys follow the repo's hash-key scheme; verify:localization-catalog, verify:localization-coverage, and locale-parity checks pass for all five locales.

Security Audit

  • No new command execution: presets only add label/command pairs to the same allowlist-style catalog the existing presets use; launching still goes through the unchanged Open In execution path. No user-controlled input is introduced.
  • No network changes: the new icons are bundled SVGs (sourced from JetBrains' official brand assets at resources.jetbrains.com) imported at build time; they reduce runtime reliance on the external favicon service for these entries.
  • No IPC, auth, secrets, or dependency changes. No new dependencies; the SVGs contain only vector paths/gradients (no scripts, no external references).
  • Follow-up: none identified.

Notes

  • All ten icon SVGs are JetBrains' official product marks, used to reference their products per JetBrains brand guidelines.
  • The existing OPEN_IN_APPLICATIONS_MAX = 8 cap still limits how many apps a user can add in total; the preset list itself is not capped.
  • JetBrains Fleet was intentionally omitted (product direction pivoted away from a general-purpose editor); Android Studio was omitted as it is a Google product. Both are easy one-entry additions if wanted.

🤖 Generated with Claude Code

Adds IntelliJ IDEA, WebStorm, PyCharm, PhpStorm, GoLand, Rider, CLion,
RubyMine, DataGrip, and RustRover as presets in the Add app dropdown,
grouped under a JetBrains IDEs submenu. Commands match the launcher
scripts generated by JetBrains Toolbox.

Each preset uses the bundled official product icon SVG instead of the
domain favicon, since all JetBrains products share one favicon domain.
Also adds jetbrains/intellij/webstorm settings-search keywords.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This change adds JetBrains IDE support to the Open In application menu. The preset catalog now includes JetBrains entries with bundled icons and new iconSrc and group fields. The dropdown menu groups JetBrains presets under a “JetBrains IDEs” submenu. Search keywords for jetbrains, intellij, and webstorm were added, along with locale updates across English, Spanish, Japanese, Korean, and Chinese. New tests cover JetBrains preset ordering, icon sourcing, and preset row generation.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: adding JetBrains IDE presets to Open In Apps.
Description check ✅ Passed The description matches the template well, with summary, screenshots, testing, AI review, security audit, and notes all covered.

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.

Satisfies the PR docstring-coverage check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Jonezzyboy

Copy link
Copy Markdown
Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

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

🧹 Nitpick comments (1)
src/renderer/src/lib/open-in-app-catalog.tsx (1)

7-16: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider a data-driven approach to reduce repetition across the 10 JetBrains presets.

Each JetBrains preset (Lines 55-134) repeats the same shape (id, label, command, faviconDomain: 'jetbrains.com', iconSrc, group: 'jetbrains'), differing only in the id/label/command/icon. This works correctly today, but adding/removing a JetBrains IDE means touching multiple parallel lists (imports, preset objects) that must stay in sync by hand.

♻️ Suggested refactor sketch
+const jetbrainsProducts = [
+  { id: 'intellij-idea', command: 'idea', icon: intellijIdeaIcon, key: '00451c5ef5', fallback: 'IntelliJ IDEA' },
+  { id: 'webstorm', command: 'webstorm', icon: webstormIcon, key: '20e6751d0c', fallback: 'WebStorm' },
+  // ...remaining products
+] as const
+
+// inside getOpenInAppPresets():
+...jetbrainsProducts.map((product) => ({
+  id: product.id,
+  label: translate(`auto.lib.open.in.app.catalog.${product.key}`, product.fallback),
+  command: product.command,
+  faviconDomain: 'jetbrains.com',
+  iconSrc: product.icon,
+  group: 'jetbrains' as const
+}))

Also applies to: 33-135


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ecdfb753-984d-44a8-a7a8-a3dc5d175c69

📥 Commits

Reviewing files that changed from the base of the PR and between 6fb3036 and 7c7fd15.

⛔ Files ignored due to path filters (10)
  • resources/jetbrains-clion.svg is excluded by !**/*.svg
  • resources/jetbrains-datagrip.svg is excluded by !**/*.svg
  • resources/jetbrains-goland.svg is excluded by !**/*.svg
  • resources/jetbrains-intellijidea.svg is excluded by !**/*.svg
  • resources/jetbrains-phpstorm.svg is excluded by !**/*.svg
  • resources/jetbrains-pycharm.svg is excluded by !**/*.svg
  • resources/jetbrains-rider.svg is excluded by !**/*.svg
  • resources/jetbrains-rubymine.svg is excluded by !**/*.svg
  • resources/jetbrains-rustrover.svg is excluded by !**/*.svg
  • resources/jetbrains-webstorm.svg is excluded by !**/*.svg
📒 Files selected for processing (9)
  • src/renderer/src/components/settings/OpenInMenuSetting.test.ts
  • src/renderer/src/components/settings/OpenInMenuSetting.tsx
  • src/renderer/src/components/settings/general-search.ts
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/zh.json
  • src/renderer/src/lib/open-in-app-catalog.tsx

Addresses CodeRabbit nitpick: per-product fields live in one list and the
shared faviconDomain/group are applied in a single map. Labels keep literal
translate() keys because the localization catalog scanner only verifies
string-literal keys.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Jonezzyboy

Copy link
Copy Markdown
Author

@coderabbitai Regarding the nitpick on src/renderer/src/lib/open-in-app-catalog.tsx (data-driven JetBrains presets): applied in e7825ee, with one deliberate deviation from the suggested sketch.

The sketch derives the i18n key with a template literal (translate(`auto.lib.open.in.app.catalog.${product.key}`, product.fallback)), but this repo's localization tooling (config/scripts/verify-localization-catalog.mjs) only records translate() calls whose first argument is ts.isStringLiteralLike. A computed key wouldn't fail the check — it would silently drop those ten labels out of catalog verification entirely.

So the refactor keeps each label as a literal translate('auto…', 'WebStorm') call and deduplicates everything that's safe to data-drive: the per-product fields (id, label, command, iconSrc) live in a single getJetBrainsPresets() list, and the shared faviconDomain/group are applied once in a .map(). Adding or removing an IDE is now one entry plus its icon import. A comment on the function records why the labels aren't fully data-driven.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
git log --oneline -5
git show e7825eee0 --stat 2>/dev/null || echo "commit not found, trying full sha search"
git log --all --grep="jetbrains" -i --oneline | head -20

Length of output: 1369


🏁 Script executed:

#!/bin/bash
sed -n '1,220p' src/renderer/src/lib/open-in-app-catalog.tsx

Length of output: 5956


This confirms the refactor as described. getJetBrainsPresets() now holds the per-product id/label/command/iconSrc in a single array, with the shared faviconDomain: 'jetbrains.com' and group: 'jetbrains' applied once via .map(). Each translate() call still uses a literal key string (e.g., 'auto.lib.open.in.app.catalog.20e6751d0c'), so verify-localization-catalog.mjs's ts.isStringLiteralLike check still picks up all ten labels. The doc comment on getJetBrainsPresets() explains the rationale clearly.

That's a solid tradeoff — fully data-driving the translate key would have silently broken catalog verification without a lint failure to catch it, which is a worse outcome than a few extra lines of per-product literals. Adding/removing an IDE is now a one-entry change plus its icon import, exactly as intended. Thanks for the detailed explanation and for applying the dedup in e7825ee.

@Jonezzyboy

Copy link
Copy Markdown
Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

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

🧹 Nitpick comments (1)
src/renderer/src/components/settings/OpenInMenuSetting.tsx (1)

298-323: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Partition logic is type-safe today, but silently drops presets with any future third group value.

standalonePresets/jetbrainsPresets are computed by checking exact values (undefined / 'jetbrains'). If OpenInAppPreset.group is ever extended with another literal, unmatched presets simply vanish from the "Add app" menu instead of erroring. Not an issue today since the type only allows these two states, but worth a defensive comment or an exhaustive partition (e.g., default all non-undefined groups into their own submenus) if more groups are added later.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 460ff5a3-bf82-4376-9f5e-ddaccc408430

📥 Commits

Reviewing files that changed from the base of the PR and between 6fb3036 and e7825ee.

⛔ Files ignored due to path filters (10)
  • resources/jetbrains-clion.svg is excluded by !**/*.svg
  • resources/jetbrains-datagrip.svg is excluded by !**/*.svg
  • resources/jetbrains-goland.svg is excluded by !**/*.svg
  • resources/jetbrains-intellijidea.svg is excluded by !**/*.svg
  • resources/jetbrains-phpstorm.svg is excluded by !**/*.svg
  • resources/jetbrains-pycharm.svg is excluded by !**/*.svg
  • resources/jetbrains-rider.svg is excluded by !**/*.svg
  • resources/jetbrains-rubymine.svg is excluded by !**/*.svg
  • resources/jetbrains-rustrover.svg is excluded by !**/*.svg
  • resources/jetbrains-webstorm.svg is excluded by !**/*.svg
📒 Files selected for processing (9)
  • src/renderer/src/components/settings/OpenInMenuSetting.test.ts
  • src/renderer/src/components/settings/OpenInMenuSetting.tsx
  • src/renderer/src/components/settings/general-search.ts
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/zh.json
  • src/renderer/src/lib/open-in-app-catalog.tsx

A future third group literal on OpenInAppPreset would silently drop its
presets from the dropdown; this fails CI instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Jonezzyboy

Copy link
Copy Markdown
Author

@coderabbitai Regarding the nitpick on OpenInMenuSetting.tsx (partition silently drops presets with a future third group value): addressed in 731bfb0, taking the cheapest option that actually catches the failure rather than just documenting it.

Instead of building submenu-per-group machinery now (nothing needs it yet), OpenInMenuSetting.test.ts gains an exhaustiveness assertion: every preset from getOpenInAppPresets() must land in one of the two partitions the dropdown renders (group === undefined or group === 'jetbrains'). If a third group literal is ever added to OpenInAppPreset without a corresponding submenu, CI fails with a pointer to the partition site instead of presets silently vanishing from the Add app menu.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
git show 731bfb0b0 --stat 2>/dev/null || echo "commit not found"
git show 731bfb0b0 -- src/renderer/src/components/settings/OpenInMenuSetting.test.ts 2>/dev/null | head -100

Length of output: 2303


@Jonezzyboy Verified in commit 731bfb0b0. The new test renders every preset in one of the Add app menu partitions in OpenInMenuSetting.test.ts filters getOpenInAppPresets() into standalone (group === undefined) and jetbrains (group === 'jetbrains'), then asserts standalone.length + jetbrains.length === presets.length.

That's a good exhaustiveness check for the cost — no premature submenu-per-group abstraction, but if someone adds a third group literal to OpenInAppPreset without updating the dropdown partitioning, this test fails immediately and points straight at the partition site in OpenInMenuSetting.tsx, rather than the regression surfacing only as "my new presets aren't showing up" during manual QA. Nice, minimal fix.

@Jonezzyboy

Copy link
Copy Markdown
Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@Jonezzyboy

Copy link
Copy Markdown
Author

@coderabbitai Which functions in this PR's diff are missing docstrings for the Docstring Coverage check? Please list them by file and line.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
cd /tmp && rm -rf orca_repo
git clone --depth 50 https://github.com/stablyai/orca.git orca_repo 2>&1 | tail -5
cd orca_repo
git fetch origin pull/7938/head:pr7938 2>&1 | tail -5
git checkout pr7938 2>&1 | tail -5
git diff origin/main...pr7938 -- src/renderer/src/lib/open-in-app-catalog.tsx src/renderer/src/components/settings/OpenInMenuSetting.tsx src/renderer/src/components/settings/OpenInMenuSetting.test.ts src/renderer/src/components/settings/general-search.ts

Length of output: 15916


@Jonezzyboy I checked every function added or modified in this PR's diff and found none missing docstrings — the author (or the refactor commits) added JSDoc comments to all of them:

src/renderer/src/lib/open-in-app-catalog.tsx

  • getJetBrainsPresets() — documented (explains why translate keys stay literal)
  • getOpenInAppPresets — documented
  • getOpenInAppPreset() — documented
  • isOpenInAppPresetAdded() — documented
  • OpenInApplicationIcon() — documented (icon precedence order)

src/renderer/src/components/settings/OpenInMenuSetting.tsx

  • createPresetOpenInApplication() — documented
  • shouldCommitOpenInApplicationsDraft() — documented
  • OpenInMenuSetting() — documented
  • renderPresetItem (local const arrow function) — documented

src/renderer/src/components/settings/general-search.ts and OpenInMenuSetting.test.ts introduce no new function declarations requiring docstrings — the former only adds data entries to an existing array literal, and the latter only adds it(...) test callbacks, which aren't typically flagged by the Docstring Coverage check.

So there's nothing to flag here for this metric — the diff is fully covered.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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.

3 participants