Skip to content

[codex] Fix changes sidebar modifier click behavior#4644

Merged
Kitenite merged 2 commits into
mainfrom
sidebar-cmd-click-shortcu
May 16, 2026
Merged

[codex] Fix changes sidebar modifier click behavior#4644
Kitenite merged 2 commits into
mainfrom
sidebar-cmd-click-shortcu

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented May 16, 2026

Summary

  • Add a centralized changes-sidebar click policy that translates the existing sidebar file-link settings into changes-specific intents.
  • Update grouped and tree changes rows so Cmd/Ctrl-click opens the actual file pane, while Cmd/Ctrl-Shift-click opens the external editor.
  • Update sidebar file-link defaults and read-time preference healing so users on the old default get the corrected Cmd/Ctrl behavior without losing custom mappings.

Impact

Plain clicks still open diffs, Shift-click still opens diffs in a new tab, and existing settings remain the source of truth for modifier behavior. Menu shortcut labels and hover hints now come from the same centralized policy.

Validation

  • bun test apps/desktop/src/renderer/lib/clickPolicy/policies/changesSidebarFilePolicy.test.ts apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.test.ts
  • bun run typecheck --filter=@superset/desktop
  • bun run lint:fix
  • bun run lint
  • git diff --check

Open in Stage

Summary by cubic

Centralized the changes sidebar click policy and updated the tree and row components to use it. Hover hints and menu shortcuts now come from one source, and unbound tiers are respected.

  • Bug Fixes

    • Plain click opens the diff. Shift-click opens the diff in a new tab.
    • Cmd/Ctrl-click opens the file pane. Cmd/Ctrl-Shift-click opens the external editor.
    • Unbound modifier tiers do nothing.
  • Migration

    • Auto-heals legacy sidebarFileLinks defaults to the new default (meta: pane, metaShift: external) without changing custom mappings.

Written for commit 7324c93. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Enhanced changes sidebar click routing: modifier keys (Shift, Cmd/Ctrl) now control opening diffs, files, or external editor; keyboard shortcut hints updated.
  • Chores

    • Changed default action for one modifier to open in-pane instead of external editor.
    • Centralized and improved click-intent resolution across the changes sidebar.
  • Tests

    • Added unit tests covering intent resolution and tier mappings.

Review Change Stack

@capy-ai
Copy link
Copy Markdown

capy-ai Bot commented May 16, 2026

Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 16, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e79c58ab-1a00-408d-be96-c652b148d882

📥 Commits

Reviewing files that changed from the base of the PR and between 6d4c289 and 7324c93.

📒 Files selected for processing (2)
  • apps/desktop/src/renderer/lib/clickPolicy/policies/changesSidebarFilePolicy.test.ts
  • apps/desktop/src/renderer/lib/clickPolicy/usePierreChangesSidebarRowClickPolicy.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/desktop/src/renderer/lib/clickPolicy/policies/changesSidebarFilePolicy.test.ts
  • apps/desktop/src/renderer/lib/clickPolicy/usePierreChangesSidebarRowClickPolicy.ts

📝 Walkthrough

Walkthrough

Adds intent-based click policy for the changes sidebar (diff, diffNewTab, file, external), a row-click handler hook, UI wiring in tree/file rows and context menus, barrel re-exports, tests, and migration of legacy sidebar file-link defaults.

Changes

Changes Sidebar Click Policy

Layer / File(s) Summary
Intent/tier policy core
apps/desktop/src/renderer/lib/clickPolicy/policies/changesSidebarFilePolicy.ts, apps/desktop/src/renderer/lib/clickPolicy/policies/changesSidebarFilePolicy.test.ts
New ChangesSidebarFileIntent union and functions: resolveChangesSidebarFileIntent, tierForChangesSidebarFileIntent, and buildChangesSidebarFileHint; tests validate intent↔tier mapping across modifier combinations.
Policy hook wrapper
apps/desktop/src/renderer/lib/clickPolicy/policies/useChangesSidebarFilePolicy.ts
useChangesSidebarFilePolicy composes useSidebarFilePolicy and exposes getIntent, tierForIntent, and hint memoized from policy.map.
Row-click handler hook
apps/desktop/src/renderer/lib/clickPolicy/usePierreChangesSidebarRowClickPolicy.ts
usePierreChangesSidebarRowClickPolicy provides findFileRow and onClickCapture to locate data-item-path rows, resolve intents (folder vs file), and route to openInExternalEditor, onOpenFile, or onSelectDiff.
Public API exports
apps/desktop/src/renderer/lib/clickPolicy/index.ts
Barrel re-exports new click-policy types/functions (ChangesSidebarFileIntent, resolveChangesSidebarFileIntent, tierForChangesSidebarFileIntent, buildChangesSidebarFileHint) and hooks (useChangesSidebarFilePolicy, usePierreChangesSidebarRowClickPolicy).
UI component integration
apps/desktop/src/renderer/.../ChangesTreeView/ChangesTreeView.tsx, .../FileRow/FileRow.tsx, .../FileRowContextMenuItems/FileRowContextMenuItems.tsx
Components now use useChangesSidebarFilePolicy + usePierreChangesSidebarRowClickPolicy; click handlers and keyboard shortcut hints use intent-based tiers (diffNewTab, file, external); onOpenFile converts relative to absolute workspace paths before calling handler.
Sidebar file-link defaults and migration
apps/desktop/src/renderer/routes/.../dashboardSidebarLocal/schema.ts, schema.test.ts
Updates default sidebarFileLinks (changes meta default), defines LEGACY_SIDEBAR_FILE_LINKS, adds helpers for map equality/completeness, and modifies healV2UserPreferences to detect and migrate legacy stored values; test added verifying migration.

Sequence Diagram

sequenceDiagram
  participant User
  participant FileRow
  participant usePierreChangesSidebarRowClickPolicy
  participant useChangesSidebarFilePolicy
  participant ActionHandler
  User->>FileRow: click (with modifiers)
  FileRow->>usePierreChangesSidebarRowClickPolicy: onClickCapture(event)
  usePierreChangesSidebarRowClickPolicy->>useChangesSidebarFilePolicy: getIntent(event)
  useChangesSidebarFilePolicy->>usePierreChangesSidebarRowClickPolicy: intent
  usePierreChangesSidebarRowClickPolicy->>ActionHandler: call openInExternalEditor / onOpenFile / onSelectDiff
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • superset-sh/superset#4442: Introduced the base row click-policy hook (usePierreRowClickPolicy) and related click-routing changes that this PR extends and specializes for the changes sidebar.

Poem

🐰 A click, a shift, a meta-key dance,
Intent resolved at every glance!
Sidebar rows now route with care,
Files and folders handled fair.
Defaults healed, shortcuts bright — hops of delight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% 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
Title check ✅ Passed The title clearly describes the main change: a fix for click behavior in the changes sidebar when using modifier keys (Cmd/Ctrl and variants).
Description check ✅ Passed The description includes all required sections: a clear summary of changes, impact statement, validation steps, and related context. However, no related GitHub issues are explicitly linked.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sidebar-cmd-click-shortcu

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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.

@stage-review
Copy link
Copy Markdown

stage-review Bot commented May 16, 2026

Ready to review this PR? Stage has broken it down into 5 individual chapters for you:

Title
1 Update sidebar file-link defaults and migration
2 Define centralized changes-sidebar click policy
3 Implement specialized row click policy hook
4 Wire click policy into ChangesTreeView
5 Update FileRow and context menus
Open in Stage

Chapters generated by Stage for commit 7324c93 on May 16, 2026 9:38pm UTC.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 16, 2026

Greptile Summary

This PR introduces a centralized changesSidebarFilePolicy that re-interprets existing sidebar file-link settings as changes-specific intents (diff, diffNewTab, file, external), fixing Cmd/Ctrl-click so it opens the file pane instead of the external editor. It also updates both the flat FileRow and the Pierre tree view to dispatch on these intents, and adds a read-time migration that silently upgrades users still on the old default (meta: \"external\") to the new default (meta: \"pane\") without touching custom configurations.

  • changesSidebarFilePolicy.ts + useChangesSidebarFilePolicy.ts: new intent layer that maps \"pane\" on a non-plain tier to \"file\", keeping \"pane\" on the plain tier as \"diff\".
  • usePierreChangesSidebarRowClickPolicy.ts: new Pierre tree hook that intercepts capture-phase clicks and dispatches to onSelectDiff, onOpenFile, or openInExternalEditor based on resolved intent.
  • schema.ts: adds LEGACY_SIDEBAR_FILE_LINKS, isSameLinkTierMap, and isCompleteLinkTierMap to gate migration only on exact-match legacy configs; shortcut labels and hover hints are now derived from the same policy map.

Confidence Score: 4/5

Safe to merge; the new click routing is well-isolated and the legacy migration is correctly gated on an exact map match.

The centralized intent layer and migration logic are solid. Two edge cases worth watching: file-row clicks always consume the event before checking intent (unlike folder rows), so an unbound modifier tier silently swallows the click; and in FileRow, a "file" intent with no absolutePath falls through all branches without opening the diff as a fallback, which could surprise any caller that omits worktreePath.

usePierreChangesSidebarRowClickPolicy.ts (event-consumption asymmetry) and FileRow.tsx (silent no-op when worktreePath is absent).

Important Files Changed

Filename Overview
apps/desktop/src/renderer/lib/clickPolicy/policies/changesSidebarFilePolicy.ts New policy module mapping LinkTierMap actions to ChangesSidebarFileIntent values; logic is clean and the "pane"-on-non-plain-tier → "file" pivot is well-isolated.
apps/desktop/src/renderer/lib/clickPolicy/policies/changesSidebarFilePolicy.test.ts Test coverage is thorough: plain, shift, cmd/ctrl, cmd/ctrl-shift, and shortcut-tier lookups are all exercised.
apps/desktop/src/renderer/lib/clickPolicy/policies/useChangesSidebarFilePolicy.ts Straightforward hook that composes useSidebarFilePolicy with the new intent helpers; memoisation is correct.
apps/desktop/src/renderer/lib/clickPolicy/usePierreChangesSidebarRowClickPolicy.ts New click policy hook correctly intercepts Pierre tree clicks; minor asymmetry: file rows unconditionally consume the event even for null intent, while folder rows return early without consuming.
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts Legacy migration is correct (exact-match guard prevents touching custom configs); the pre-computed sidebarFileLinks variable that gets discarded on migration is harmless but slightly redundant.
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.test.ts New test validates that the exact legacy default is migrated to the new default; existing heal tests unchanged.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/components/ChangesTreeView/ChangesTreeView.tsx Clean swap to usePierreChangesSidebarRowClickPolicy; onOpenFile now correctly resolves relative → absolute paths before forwarding to parent.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/components/ChangesTreeView/components/FileRowContextMenuItems/FileRowContextMenuItems.tsx Policy switch from useSidebarFilePolicy to useChangesSidebarFilePolicy is correct; new "Open File" shortcut label wired up properly.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/components/FileRow/FileRow.tsx Intent-based dispatch correctly opens file/diff/editor; silent no-op when intent is "file" and absolutePath is undefined may be unexpected for callers that omit worktreePath.
apps/desktop/src/renderer/lib/clickPolicy/index.ts New exports are clean and consistent with existing patterns.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Mouse click on sidebar row] --> B{capture phase onClickCapture}
    B --> C{data-item-path found?}
    C -- No --> D[pass through]
    C -- Yes --> E{path ends with /}
    E -- Yes folder --> F[folderIntentFor]
    F -- null --> G[return early - event NOT consumed]
    F -- external --> H[preventDefault + stopPropagation + openInExternalEditor]
    E -- No file --> I[preventDefault + stopPropagation always]
    I --> J[getFileIntent - resolveChangesSidebarFileIntent]
    J -- diff --> K[onSelectDiff openInNewTab=false]
    J -- diffNewTab --> L[onSelectDiff openInNewTab=true]
    J -- file --> M[onOpenFile abs path via worktreePath]
    J -- external --> N[openInExternalEditor]
    J -- null --> O[no-op - event already consumed]
Loading
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
apps/desktop/src/renderer/lib/clickPolicy/usePierreChangesSidebarRowClickPolicy.ts:58-65
**Silent click consumption for unbound file tiers**

For file rows, `e.preventDefault()` and `e.stopPropagation()` are called unconditionally _before_ `getFileIntent(e)` is evaluated. When `getFileIntent` returns `null` (unbound tier), the click event is fully consumed but no action is taken. In contrast, the folder branch does the opposite — it returns early without consuming the event when `folderIntentFor` returns null, allowing the tree to handle expansion/collapse normally. A user who explicitly unbinds a modifier tier for files will get a silent no-op with no visual feedback, while the same situation on a folder correctly falls through to the tree.

### Issue 2 of 2
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/components/FileRow/FileRow.tsx:107-113
**`"file"` intent silently falls through when `absolutePath` is undefined**

When `intent === "file"` and `absolutePath` is `undefined` (i.e. `worktreePath` was not passed), the condition `intent === "file" && absolutePath` is falsy and all remaining `else if` branches also miss, leaving the click as a complete no-op. Under the old default (`meta: "external"`), Cmd/Ctrl-click reliably called `onOpenInEditor?.(file.path)` regardless of `worktreePath`. With the new default (`meta: "pane"``"file"` intent), any caller that omits `worktreePath` silently loses modifier-click behaviour after the legacy migration fires.

Reviews (1): Last reviewed commit: "Fix changes sidebar modifier click polic..." | Re-trigger Greptile

Comment on lines +58 to +65
e.preventDefault();
e.stopPropagation();

const intent = getFileIntent(e);
if (intent === "external") openInExternalEditor(trimmed);
else if (intent === "file") onOpenFile(trimmed, false);
else if (intent === "diffNewTab") onSelectDiff(trimmed, true);
else if (intent === "diff") onSelectDiff(trimmed, false);
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.

P2 Silent click consumption for unbound file tiers

For file rows, e.preventDefault() and e.stopPropagation() are called unconditionally before getFileIntent(e) is evaluated. When getFileIntent returns null (unbound tier), the click event is fully consumed but no action is taken. In contrast, the folder branch does the opposite — it returns early without consuming the event when folderIntentFor returns null, allowing the tree to handle expansion/collapse normally. A user who explicitly unbinds a modifier tier for files will get a silent no-op with no visual feedback, while the same situation on a folder correctly falls through to the tree.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/lib/clickPolicy/usePierreChangesSidebarRowClickPolicy.ts
Line: 58-65

Comment:
**Silent click consumption for unbound file tiers**

For file rows, `e.preventDefault()` and `e.stopPropagation()` are called unconditionally _before_ `getFileIntent(e)` is evaluated. When `getFileIntent` returns `null` (unbound tier), the click event is fully consumed but no action is taken. In contrast, the folder branch does the opposite — it returns early without consuming the event when `folderIntentFor` returns null, allowing the tree to handle expansion/collapse normally. A user who explicitly unbinds a modifier tier for files will get a silent no-op with no visual feedback, while the same situation on a folder correctly falls through to the tree.

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

Comment on lines +107 to 113
const intent = policy.getIntent(e);
if (intent === "external") onOpenInEditor?.(file.path);
else if (intent === "file" && absolutePath)
onOpenFile?.(absolutePath, false);
else if (intent === "diffNewTab") onSelect?.(file.path, true);
else if (intent === "diff") onSelect?.(file.path, false);
}}
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.

P2 "file" intent silently falls through when absolutePath is undefined

When intent === "file" and absolutePath is undefined (i.e. worktreePath was not passed), the condition intent === "file" && absolutePath is falsy and all remaining else if branches also miss, leaving the click as a complete no-op. Under the old default (meta: "external"), Cmd/Ctrl-click reliably called onOpenInEditor?.(file.path) regardless of worktreePath. With the new default (meta: "pane""file" intent), any caller that omits worktreePath silently loses modifier-click behaviour after the legacy migration fires.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/components/FileRow/FileRow.tsx
Line: 107-113

Comment:
**`"file"` intent silently falls through when `absolutePath` is undefined**

When `intent === "file"` and `absolutePath` is `undefined` (i.e. `worktreePath` was not passed), the condition `intent === "file" && absolutePath` is falsy and all remaining `else if` branches also miss, leaving the click as a complete no-op. Under the old default (`meta: "external"`), Cmd/Ctrl-click reliably called `onOpenInEditor?.(file.path)` regardless of `worktreePath`. With the new default (`meta: "pane"``"file"` intent), any caller that omits `worktreePath` silently loses modifier-click behaviour after the legacy migration fires.

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

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 10 files

Re-trigger cubic

@Kitenite Kitenite merged commit 6c41c69 into main May 16, 2026
10 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

sazabi Bot pushed a commit that referenced this pull request May 20, 2026
* Fix changes sidebar modifier click policy

* Respect unbound changes sidebar file click tiers
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