Skip to content

[codex] Improve sidebar group management UX#3745

Merged
Kitenite merged 1 commit into
mainfrom
sections-sidebar-ux
Apr 26, 2026
Merged

[codex] Improve sidebar group management UX#3745
Kitenite merged 1 commit into
mainfrom
sections-sidebar-ux

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Apr 26, 2026

Summary

  • Improves v2 dashboard sidebar group management copy and controls, including hover-only group actions and shared right-click/dropdown action content.
  • Keeps the existing section model intact by treating top-level ordering as a combined lane of ungrouped workspaces and section headers.
  • Fixes group creation and ungroup/delete behavior so workspaces do not accidentally remain visually grouped or fall under another group.
  • Starts inline rename when a new group is created, and splits the section action menu into focused files.

Root Cause

Sections visually own the following workspace rows. Some actions were assigning workspace or section tabOrder using only one side of that top-level lane, which could place ungrouped workspaces after a section header and make them appear grouped again.

Validation

  • bunx @biomejs/biome@2.4.2 check --write apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar
  • bun run --cwd apps/desktop typecheck
  • git diff --cached --check

Summary by cubic

Improves the v2 dashboard sidebar group management with a unified actions menu, an auto-rename flow, and safer ordering. New groups auto-start rename (including from a workspace) and expand the project if collapsed; ungroup/delete now place workspaces correctly.

  • New Features

    • Shared actions used by both right‑click and a hover "..." dropdown on group headers.
    • Auto-rename via DashboardSidebarSectionRenameProvider; creating a group from a workspace moves that workspace into it and opens the project if collapsed.
    • Updated copy: "New group", "New group from workspace", "Move to group", "Ungroup"; refined header UI (chevron+grip, count).
  • Bug Fixes

    • Treats top-level as a single lane of ungrouped workspaces and group headers with deterministic reindexing to prevent tabOrder collisions.
    • Ungroup and delete move workspaces to top-level (before the first group) and keep their order.
    • Context/dropdown menus stop event propagation and prevent focus jumps to avoid accidental header actions.

Written for commit a3c7651. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Added an actions dropdown for section controls (rename, color, delete).
    • Added a shared “rename pending” flow that auto-prompts rename after creating a new group.
  • UI/UX Improvements

    • Replaced “Section” wording with “group” across menus and actions.
    • Section headers updated with combined grip+chevron affordance and refined typography.
    • Sidebar ordering treats ungrouped items and groups as a single top-level sequence for smoother reordering.
  • Bug Fixes

    • More reliable rename and workspace-move behavior.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

📝 Walkthrough

Walkthrough

Introduces a shared rename-request provider for sidebar sections, centralizes rename initiation and auto-rename on creation, extracts section action menu items into reusable context/dropdown components, updates UI copy from "Section" → "group", and refactors sidebar ordering to treat ungrouped workspaces and sections as a single top-level sequence.

Changes

Cohort / File(s) Summary
Rename Provider
apps/desktop/src/renderer/.../DashboardSidebarSectionRenameContext/DashboardSidebarSectionRenameContext.tsx, .../DashboardSidebarSectionRenameContext/index.ts
Add DashboardSidebarSectionRenameProvider and useDashboardSidebarSectionRename to hold pendingRenameSectionId, with request/clear helpers and public re-exports.
Top-level Sidebar Wrapper
apps/desktop/src/renderer/.../DashboardSidebar/DashboardSidebar.tsx
Wrap entire sidebar render tree with DashboardSidebarSectionRenameProvider.
Section Actions UI
.../SectionActionsMenuItems/SectionActionsMenuItems.tsx, .../SectionActionsMenuItems/index.ts, .../DashboardSidebarSectionActionsDropdown/DashboardSidebarSectionActionsDropdown.tsx, .../DashboardSidebarSectionActionsDropdown/index.ts
Add SectionActionsMenuItems (shared menu items for rename/color/delete) and DashboardSidebarSectionActionsDropdown (dropdown trigger/content) supporting both context-menu and dropdown variants with event-propagation controls.
Context Menu Refactor & Types
.../DashboardSidebarSectionContextMenu/DashboardSidebarSectionContextMenu.tsx, .../types.ts, .../index.ts
Refactor context menu to render SectionActionsMenuItems, update props to DashboardSidebarSectionActionsProps, adjust ContextMenuContent focus/propagation behavior, and re-export dropdown.
Section Header / Sortable Header
.../DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx, .../SortableSectionHeader/SortableSectionHeader.tsx
Remove header-local onStartRename prop, add optional actions slot, update visuals, and drive rename start via shared useDashboardSidebarSectionRename (Sortable header starts local rename when pending ID matches).
Deleted Section Components
.../DashboardSidebarSection/DashboardSidebarSection.tsx, .../DashboardSidebarSection/components/DashboardSidebarSectionContent/DashboardSidebarSectionContent.tsx, .../DashboardSidebarSection/index.ts, .../DashboardSidebarSection/components/DashboardSidebarSectionContent/index.ts
Remove DashboardSidebarSection and DashboardSidebarSectionContent implementations and related re-exports (rename/collapse/content logic migrated to headers/provider).
Hooks: Create/Auto-rename & Move Logic
.../useDashboardSidebarProjectSectionActions/.../useDashboardSidebarProjectSectionActions.ts, .../useDashboardSidebarWorkspaceItemActions/.../useDashboardSidebarWorkspaceItemActions.ts
On new section creation, capture sectionId, call requestSectionRename(sectionId), and auto-expand parent project if collapsed; workspace→new-group flow moves workspace into created group and requests rename.
Sidebar State Ordering
apps/desktop/src/renderer/.../useDashboardSidebarState/useDashboardSidebarState.ts
Unify ordering: treat ungrouped workspaces (sectionId === null) and sections as a single top-level lane, compute tabOrder across both collections, refactor create/move/delete/un-group flows, and change default section name to "New group".
Context Menu Label Updates
.../DashboardSidebarProjectContextMenu/DashboardSidebarProjectContextMenu.tsx, .../DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx, .../DashboardSidebarProjectSectionContextMenu/DashboardSidebarProjectContextMenu.tsx
Update copy: "New Section" → "New group", "Create Section Below" → "New group from workspace", "Move to Section" → "Move to group", "Remove from Group" → "Ungroup".

Sequence Diagram

sequenceDiagram
    participant User
    participant ProjectSection as ProjectSectionComponent
    participant Hook as useDashboardSidebarProjectSectionActions
    participant Provider as RenameProvider
    participant API as ServerAPI

    User->>ProjectSection: Click "New group"
    ProjectSection->>Hook: handleNewSection()
    Hook->>API: createSection("New group")
    API-->>Hook: { sectionId }
    Hook->>Provider: requestSectionRename(sectionId)
    Provider-->>ProjectSection: pendingRenameSectionId set
    ProjectSection->>ProjectSection: Start rename UI for sectionId
    User->>ProjectSection: Submit new name
    ProjectSection->>API: updateSectionName(sectionId, name)
    API-->>ProjectSection: success
    ProjectSection->>Provider: clearPendingSectionRename(sectionId)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through groups with gentle cheer,
New groups named softly when they appear,
I nudged the sidebar, tidy and spry,
Tabs reordered as I gave them a try,
Hop-hop—rename requested, then clear!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.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
Title check ✅ Passed The title clearly summarizes the main change—improving sidebar group management UX—which aligns with the PR's core objectives of refactoring group actions, fixing ordering logic, and enhancing the user experience.
Description check ✅ Passed The description includes a clear summary of changes, root cause analysis, validation steps, and type of change context. While the description is well-structured and comprehensive, it deviates from the template by omitting the explicit 'Type of Change' section with checkboxes.
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 sections-sidebar-ux

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx (1)

41-62: ⚠️ Potential issue | 🟡 Minor

Keyboard activation on the actions trigger will also toggle the section.

The header <div> handles Enter/Space to call onToggleCollapse. The actions dropdown trigger button (rendered inside this div) only stops propagation on click/pointerdown/contextmenu — not on keydown. When a keyboard user focuses the ellipsis button and presses Enter (or Space) to open the menu, the keydown still bubbles to this header and toggles collapse alongside opening the dropdown.

Two options:

  • Stop keydown propagation on the dropdown trigger button (in DashboardSidebarSectionActionsDropdown.tsx), or
  • Guard this handler so it ignores events whose event.target is not the header itself (e.g., if (event.currentTarget !== event.target) return;).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx`
around lines 41 - 62, The header's onKeyDown in DashboardSidebarSectionHeader is
catching Enter/Space from child controls (like the ellipsis actions button) and
toggling collapse; update the onKeyDown handler in DashboardSidebarSectionHeader
to ignore key events not targeted at the header itself by returning early when
event.currentTarget !== event.target before handling Enter/Space, so only direct
key activation of the header toggles collapse; alternatively, if you prefer
handling in the actions component, add an onKeyDown on the dropdown trigger in
DashboardSidebarSectionActionsDropdown to stop propagation for Enter/Space
(i.e., call event.stopPropagation() for those keys) so opening the menu doesn't
bubble to onToggleCollapse.
🧹 Nitpick comments (4)
apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts (1)

304-347: Optional: unify the insertAfterWorkspaceId branch with the new top-level ordering helpers.

The other mutations (moveWorkspaceToSection, deleteSection, no-anchor createSection) all funnel through getProjectTopLevelItems + writeProjectTopLevelOrder. This branch still uses the older "manually bump tabOrder by 1" approach, which works but mixes models. Consider building the unified list, splicing the new section after the anchor, and rewriting via writeProjectTopLevelOrder — it deduplicates the in-section vs. top-level anchor logic and avoids the dual update loops.

Sketch (illustrative):

const anchorWorkspace = collections.v2WorkspaceLocalState.get(insertAfterWorkspaceId);
const anchorId = anchorWorkspace?.sidebarState.sectionId ?? insertAfterWorkspaceId;
const anchorType: ProjectTopLevelItem["type"] = anchorWorkspace?.sidebarState.sectionId
  ? "section"
  : "workspace";

const items = getProjectTopLevelItems(collections, projectId);
const anchorIndex = items.findIndex(i => i.type === anchorType && i.id === anchorId);
const insertIndex = anchorIndex === -1 ? items.length : anchorIndex + 1;

items.splice(insertIndex, 0, { type: "section", id: sectionId, tabOrder: 0 });
writeProjectTopLevelOrder(collections, projectId, items);
tabOrder = insertIndex + 1;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts`
around lines 304 - 347, Unify the insertAfterWorkspaceId branch with the
top-level ordering helpers: instead of manually incrementing tabOrder via two
loops on collections.v2WorkspaceLocalState and collections.v2SidebarSections,
build the project top-level list with getProjectTopLevelItems(collections,
projectId), compute the anchor by mapping insertAfterWorkspaceId to either a
section id or workspace id (mirroring the existing anchor logic), find
anchorIndex, splice a new {type: "section", id: sectionId, tabOrder: 0} into
items at anchorIndex+1 (or push if not found), then call
writeProjectTopLevelOrder(collections, projectId, items) to persist the order
and set tabOrder = insertIndex + 1; this keeps behavior consistent with
moveWorkspaceToSection, deleteSection and the no-anchor createSection flow.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/DashboardSidebarSection.tsx (1)

61-82: DRY: same color/onRename/onSetColor/onDelete wiring duplicated for context menu and dropdown.

The four action handlers are passed identically to DashboardSidebarSectionContextMenu and DashboardSidebarSectionActionsDropdown. Consider extracting a single sectionActionsProps object (typed as DashboardSidebarSectionActionsProps) to spread into both, which also keeps them in lockstep going forward.

♻️ Proposed refactor
+const sectionActionsProps: DashboardSidebarSectionActionsProps = {
+  color: section.color,
+  onRename: startRename,
+  onSetColor: (color) => setSectionColor(section.id, color),
+  onDelete: () => onDelete(section.id),
+};
+
 return (
   <div style={sectionBorderStyle}>
-    <DashboardSidebarSectionContextMenu
-      color={section.color}
-      onRename={startRename}
-      onSetColor={(color) => setSectionColor(section.id, color)}
-      onDelete={() => onDelete(section.id)}
-    >
+    <DashboardSidebarSectionContextMenu {...sectionActionsProps}>
       <DashboardSidebarSectionHeader
         ...
-        actions={
-          <DashboardSidebarSectionActionsDropdown
-            color={section.color}
-            onRename={startRename}
-            onSetColor={(color) => setSectionColor(section.id, color)}
-            onDelete={() => onDelete(section.id)}
-          />
-        }
+        actions={<DashboardSidebarSectionActionsDropdown {...sectionActionsProps} />}
       />
     </DashboardSidebarSectionContextMenu>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/DashboardSidebarSection.tsx`
around lines 61 - 82, Extract the repeated props into a single object so the
ContextMenu and ActionsDropdown stay in sync: create a const sectionActionsProps
typed as DashboardSidebarSectionActionsProps containing color: section.color,
onRename: startRename, onSetColor: (color) => setSectionColor(section.id,
color), and onDelete: () => onDelete(section.id), then spread
{...sectionActionsProps} into both DashboardSidebarSectionContextMenu and
DashboardSidebarSectionActionsDropdown instead of passing the four props twice.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx (1)

63-71: Decorative chevron/grip lack a discernible accessibility hint.

The chevron previously lived in a dedicated toggle button with implicit semantics; now the header div carries the button role and the chevron is purely decorative. Consider adding aria-expanded={!section.isCollapsed} to the header div so screen readers announce the collapsed/expanded state. (Currently only the rotating icon conveys it.)

♿ Proposed change
 <div
   ref={ref}
   role={isRenaming ? undefined : "button"}
   tabIndex={isRenaming ? undefined : 0}
+  aria-expanded={isRenaming ? undefined : !section.isCollapsed}
   onClick={isRenaming ? undefined : onToggleCollapse}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx`
around lines 63 - 71, In DashboardSidebarSectionHeader, the header div that acts
as the toggle (the container rendering HiChevronRight and LuGripVertical and
referencing section.isCollapsed) lacks a machine-readable expanded state; add
aria-expanded={!section.isCollapsed} to that header div (the element that
currently carries role="button") so assistive tech can announce collapse/expand
changes for the toggle implemented in DashboardSidebarSectionHeader and tied to
section.isCollapsed.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/SectionActionsMenuItems.tsx (1)

87-113: Consider memoizing colorOptions/colorItems.

colorOptions and the resulting colorItems JSX are rebuilt on every render even though their inputs (PROJECT_COLORS, PROJECT_COLOR_DEFAULT, plus color/handlers) rarely change. Wrapping them in useMemo (or hoisting colorOptions to module scope, since it's static) avoids needless work when the parent re-renders for unrelated reasons. Optional polish.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/SectionActionsMenuItems.tsx`
around lines 87 - 113, The colorOptions array and the colorItems JSX are being
recreated on every render; wrap their creation in React.useMemo (or hoist static
PROJECT_COLORS/PROJECT_COLOR_DEFAULT to module scope) to avoid unnecessary
recomputation inside the DashboardSidebarSectionContextMenu component: memoize
the computation that maps PROJECT_COLORS to colorOptions and the map that
produces colorItems (which uses selectedValue, onSetColor, renderItem) so they
only recompute when their real dependencies change
(PROJECT_COLORS/PROJECT_COLOR_DEFAULT, selectedValue, onSetColor, renderItem).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/DashboardSidebarSectionActionsDropdown/DashboardSidebarSectionActionsDropdown.tsx`:
- Around line 1-47: Create a barrel export for the
DashboardSidebarSectionActionsDropdown component by adding an index.ts in the
same folder that re-exports the component; ensure it exports the named symbol
DashboardSidebarSectionActionsDropdown so imports elsewhere can use the folder
path rather than the full file path and update any imports if necessary to use
the barrel.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/SectionActionsMenuItems.tsx`:
- Around line 152-165: The trash icon coloring is inconsistent because in the
context menu you add text-destructive directly to LuTrash2 but in the dropdown
you rely on DropdownMenuItem variant="destructive" to color descendants; update
the rendering in SectionActionsMenuItems so LuTrash2 always receives the
destructive class when the action is destructive (use the existing destructive
prop or check kind) so the icon gets text-destructive in both flows (look for
renderItem usage, the onDelete action, LuTrash2, and DropdownMenuItem
variant="destructive" to apply the change).

---

Outside diff comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx`:
- Around line 41-62: The header's onKeyDown in DashboardSidebarSectionHeader is
catching Enter/Space from child controls (like the ellipsis actions button) and
toggling collapse; update the onKeyDown handler in DashboardSidebarSectionHeader
to ignore key events not targeted at the header itself by returning early when
event.currentTarget !== event.target before handling Enter/Space, so only direct
key activation of the header toggles collapse; alternatively, if you prefer
handling in the actions component, add an onKeyDown on the dropdown trigger in
DashboardSidebarSectionActionsDropdown to stop propagation for Enter/Space
(i.e., call event.stopPropagation() for those keys) so opening the menu doesn't
bubble to onToggleCollapse.

---

Nitpick comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/SectionActionsMenuItems.tsx`:
- Around line 87-113: The colorOptions array and the colorItems JSX are being
recreated on every render; wrap their creation in React.useMemo (or hoist static
PROJECT_COLORS/PROJECT_COLOR_DEFAULT to module scope) to avoid unnecessary
recomputation inside the DashboardSidebarSectionContextMenu component: memoize
the computation that maps PROJECT_COLORS to colorOptions and the map that
produces colorItems (which uses selectedValue, onSetColor, renderItem) so they
only recompute when their real dependencies change
(PROJECT_COLORS/PROJECT_COLOR_DEFAULT, selectedValue, onSetColor, renderItem).

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx`:
- Around line 63-71: In DashboardSidebarSectionHeader, the header div that acts
as the toggle (the container rendering HiChevronRight and LuGripVertical and
referencing section.isCollapsed) lacks a machine-readable expanded state; add
aria-expanded={!section.isCollapsed} to that header div (the element that
currently carries role="button") so assistive tech can announce collapse/expand
changes for the toggle implemented in DashboardSidebarSectionHeader and tied to
section.isCollapsed.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/DashboardSidebarSection.tsx`:
- Around line 61-82: Extract the repeated props into a single object so the
ContextMenu and ActionsDropdown stay in sync: create a const sectionActionsProps
typed as DashboardSidebarSectionActionsProps containing color: section.color,
onRename: startRename, onSetColor: (color) => setSectionColor(section.id,
color), and onDelete: () => onDelete(section.id), then spread
{...sectionActionsProps} into both DashboardSidebarSectionContextMenu and
DashboardSidebarSectionActionsDropdown instead of passing the four props twice.

In
`@apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts`:
- Around line 304-347: Unify the insertAfterWorkspaceId branch with the
top-level ordering helpers: instead of manually incrementing tabOrder via two
loops on collections.v2WorkspaceLocalState and collections.v2SidebarSections,
build the project top-level list with getProjectTopLevelItems(collections,
projectId), compute the anchor by mapping insertAfterWorkspaceId to either a
section id or workspace id (mirroring the existing anchor logic), find
anchorIndex, splice a new {type: "section", id: sectionId, tabOrder: 0} into
items at anchorIndex+1 (or push if not found), then call
writeProjectTopLevelOrder(collections, projectId, items) to persist the order
and set tabOrder = insertIndex + 1; this keeps behavior consistent with
moveWorkspaceToSection, deleteSection and the no-anchor createSection flow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 453272d3-6f62-44be-8662-7e09bff53a19

📥 Commits

Reviewing files that changed from the base of the PR and between 583fa5d and f44d41b.

📒 Files selected for processing (18)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/DashboardSidebar.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarProjectSection/components/DashboardSidebarProjectContextMenu/DashboardSidebarProjectContextMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarProjectSection/hooks/useDashboardSidebarProjectSectionActions/useDashboardSidebarProjectSectionActions.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/DashboardSidebarSection.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/DashboardSidebarSectionContextMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/DashboardSidebarSectionActionsDropdown/DashboardSidebarSectionActionsDropdown.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/DashboardSidebarSectionActionsDropdown/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/SectionActionsMenuItems.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSectionRenameContext/DashboardSidebarSectionRenameContext.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSectionRenameContext/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/SortableSectionHeader/SortableSectionHeader.tsx
  • apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts

Comment on lines +1 to +47
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
} from "@superset/ui/dropdown-menu";
import { LuEllipsis } from "react-icons/lu";
import type { DashboardSidebarSectionActionsProps } from "../../types";
import { SectionActionsMenuItems } from "../SectionActionsMenuItems";

export function DashboardSidebarSectionActionsDropdown({
color,
onRename,
onSetColor,
onDelete,
}: DashboardSidebarSectionActionsProps) {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button
type="button"
onPointerDown={(event) => event.stopPropagation()}
onClick={(event) => event.stopPropagation()}
onContextMenu={(event) => event.stopPropagation()}
className="flex size-5 shrink-0 items-center justify-center rounded text-muted-foreground/80 opacity-0 transition-[opacity,color,background-color] hover:bg-muted hover:text-foreground group-hover:opacity-100 focus-visible:opacity-100 data-[state=open]:opacity-100"
aria-label="Group actions"
>
<LuEllipsis className="size-3.5" />
</button>
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
className="w-44"
onCloseAutoFocus={(event) => event.preventDefault()}
onClick={(event) => event.stopPropagation()}
onPointerDown={(event) => event.stopPropagation()}
>
<SectionActionsMenuItems
color={color}
kind="dropdown"
onRename={onRename}
onSetColor={onSetColor}
onDelete={onDelete}
/>
</DropdownMenuContent>
</DropdownMenu>
);
}
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.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -t f 'index.ts' --full-path '*DashboardSidebarSectionActionsDropdown*'
fd -t f -a 'DashboardSidebarSectionActionsDropdown'

Repository: superset-sh/superset

Length of output: 490


Create missing index.ts barrel export for this component folder.

The component file exists at DashboardSidebarSectionActionsDropdown/DashboardSidebarSectionActionsDropdown.tsx, but the required index.ts barrel export is missing. Per coding guidelines, all components must use the structure: ComponentName/ComponentName.tsx + index.ts for barrel export.

Add index.ts:

export { DashboardSidebarSectionActionsDropdown } from "./DashboardSidebarSectionActionsDropdown";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/DashboardSidebarSectionActionsDropdown/DashboardSidebarSectionActionsDropdown.tsx`
around lines 1 - 47, Create a barrel export for the
DashboardSidebarSectionActionsDropdown component by adding an index.ts in the
same folder that re-exports the component; ensure it exports the named symbol
DashboardSidebarSectionActionsDropdown so imports elsewhere can use the folder
path rather than the full file path and update any imports if necessary to use
the barrel.

@Kitenite Kitenite force-pushed the sections-sidebar-ux branch from f44d41b to 434f3bf Compare April 26, 2026 00:31
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 18 files

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 26, 2026

Greptile Summary

This PR improves the v2 dashboard sidebar group management UX by: adding hover-only action dropdowns on section headers, unifying context-menu and dropdown actions through a shared SectionActionsMenuItems component, introducing DashboardSidebarSectionRenameContext to auto-start inline rename on group creation, and refactoring moveWorkspaceToSection/deleteSection to use a unified getProjectTopLevelItems/writeProjectTopLevelOrder abstraction that correctly re-indexes the combined lane of ungrouped workspaces and section headers.

Confidence Score: 5/5

Safe to merge; one minor dead-code comment is the only finding.

All findings are P2. The state-management refactor is logically sound — writeProjectTopLevelOrder correctly reindexes the combined lane, and both deleteSection and moveWorkspaceToSection(null) now place ungrouped workspaces before the first remaining section header. The rename-context pattern is race-condition-free. No P0/P1 issues found.

apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts — dead insertAfterWorkspaceId branch worth removing.

Important Files Changed

Filename Overview
apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts Core state-management refactor; new helper functions correctly handle top-level reordering, but the insertAfterWorkspaceId option in createSection is now dead code with no callers.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSectionRenameContext/DashboardSidebarSectionRenameContext.tsx New React context for cross-component rename signalling; clean implementation with correct functional setState in clearPendingSectionRename.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/SortableSectionHeader/SortableSectionHeader.tsx Correctly consumes rename context via useEffect; startRename is memoized with section.name as a dep; no infinite-loop risk in the effect.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/SectionActionsMenuItems.tsx New shared component driving both context-menu and dropdown surfaces; key props on colorItems are correctly applied inside the renderItem helper.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/DashboardSidebarSectionActionsDropdown/DashboardSidebarSectionActionsDropdown.tsx New hover-only actions dropdown; event propagation is correctly stopped on onPointerDown, onClick, and onContextMenu to prevent triggering collapse or context menu.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx Header refactored to make the entire row the collapse toggle target; drag handle and chevron share the same grid cell with opacity cross-fade on hover; actions slot replaces onStartRename callback.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts "New group from workspace" now creates the section then immediately moves the workspace into it and requests rename — cleaner than the prior insertAfterWorkspaceId approach.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarProjectSection/hooks/useDashboardSidebarProjectSectionActions/useDashboardSidebarProjectSectionActions.ts Project-level "New group" now requests rename and auto-expands the project if collapsed — correct ordering since the section isn't rendered until the project expands.

Sequence Diagram

sequenceDiagram
    participant User
    participant ProjectActions as useDashboardSidebarProjectSectionActions
    participant WorkspaceActions as useDashboardSidebarWorkspaceItemActions
    participant SidebarState as useDashboardSidebarState
    participant RenameCtx as DashboardSidebarSectionRenameContext
    participant Header as SortableSectionHeader

    Note over User,Header: "New group" from project context menu
    User->>ProjectActions: onCreateSection()
    ProjectActions->>SidebarState: createSection(projectId)
    SidebarState-->>ProjectActions: sectionId
    ProjectActions->>RenameCtx: requestSectionRename(sectionId)
    ProjectActions->>SidebarState: toggleProjectCollapsed(projectId) [if collapsed]
    Note over Header: Section renders in expanded project
    RenameCtx-->>Header: pendingRenameSectionId === section.id
    Header->>Header: useEffect → startRename()
    Header->>RenameCtx: clearPendingSectionRename(sectionId)

    Note over User,Header: "New group from workspace" from workspace context menu
    User->>WorkspaceActions: handleCreateSection()
    WorkspaceActions->>SidebarState: createSection(projectId)
    SidebarState-->>WorkspaceActions: sectionId
    WorkspaceActions->>SidebarState: moveWorkspaceToSection(workspaceId, projectId, sectionId)
    WorkspaceActions->>RenameCtx: requestSectionRename(sectionId)
    RenameCtx-->>Header: pendingRenameSectionId === section.id
    Header->>Header: useEffect → startRename()
    Header->>RenameCtx: clearPendingSectionRename(sectionId)

    Note over User,Header: "Delete group" / "Ungroup"
    User->>Header: onDelete / onMoveToSection(null)
    Header->>SidebarState: deleteSection(sectionId) / moveWorkspaceToSection(id, pid, null)
    SidebarState->>SidebarState: getProjectTopLevelItems (excl. deleted)
    SidebarState->>SidebarState: splice workspaces before first section
    SidebarState->>SidebarState: writeProjectTopLevelOrder (full reindex)
Loading

Comments Outside Diff (1)

  1. apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts, line 293-362 (link)

    P2 Dead code: insertAfterWorkspaceId option

    The insertAfterWorkspaceId option is no longer passed by any caller — handleCreateSection in useDashboardSidebarWorkspaceItemActions was its only call site and was updated to use createSection + moveWorkspaceToSection instead. The entire if (insertAfterWorkspaceId) { … } branch (lines 305–342) is now unreachable. Consider removing the option and the branch to avoid confusion about supported behaviour.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts
    Line: 293-362
    
    Comment:
    **Dead code: `insertAfterWorkspaceId` option**
    
    The `insertAfterWorkspaceId` option is no longer passed by any caller — `handleCreateSection` in `useDashboardSidebarWorkspaceItemActions` was its only call site and was updated to use `createSection` + `moveWorkspaceToSection` instead. The entire `if (insertAfterWorkspaceId) { … }` branch (lines 305–342) is now unreachable. Consider removing the option and the branch to avoid confusion about supported behaviour.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts
Line: 293-362

Comment:
**Dead code: `insertAfterWorkspaceId` option**

The `insertAfterWorkspaceId` option is no longer passed by any caller — `handleCreateSection` in `useDashboardSidebarWorkspaceItemActions` was its only call site and was updated to use `createSection` + `moveWorkspaceToSection` instead. The entire `if (insertAfterWorkspaceId) { … }` branch (lines 305–342) is now unreachable. Consider removing the option and the branch to avoid confusion about supported behaviour.

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

Reviews (1): Last reviewed commit: "Improve sidebar group management UX" | Re-trigger Greptile

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: 1

🧹 Nitpick comments (4)
apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts (2)

88-110: writeProjectTopLevelOrder forces sectionId = null and projectId = projectId on every workspace item — make sure callers only pass workspaces that should be ungrouped.

This silently moves any passed-in workspace to ungrouped/projectId. Today both call sites (moveWorkspaceToSection ungroup, deleteSection) only pass top-level/orphaned workspaces, so this is fine, but the function name doesn't communicate that it also mutates sectionId/projectId. A short JSDoc clarifying this contract would help future callers avoid accidentally re-parenting workspaces.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts`
around lines 88 - 110, writeProjectTopLevelOrder currently resets workspace
sidebar state (it sets draft.sidebarState.projectId = projectId and
draft.sidebarState.sectionId = null) which re-parents workspaces to the provided
project; add a short JSDoc above writeProjectTopLevelOrder stating its contract:
that it mutates workspace sidebarState to assign the given projectId and clear
sectionId (i.e., unnests/ungroups the workspace), and therefore callers such as
moveWorkspaceToSection and deleteSection must only pass workspaces that are
intended to be ungrouped; ensure the JSDoc names the mutated fields
(sidebarState.projectId and sidebarState.sectionId) so future callers won’t
accidentally re-parent workspaces.

290-347: Optional: anchor branch of createSection could reuse the new top-level helpers.

The else branch (Lines 343-347) now derives tabOrder from getProjectTopLevelItems, but the insertAfterWorkspaceId branch (Lines 305-342) still hand-rolls two parallel loops to bump workspace and section orders. You can collapse that to a single splice into the combined list followed by writeProjectTopLevelOrder, which would unify the two code paths and remove the manual +1 bumping. Not blocking.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts`
around lines 290 - 347, The insertAfterWorkspaceId branch inside createSection
currently manually iterates v2WorkspaceLocalState and v2SidebarSections to bump
tabOrder; replace that with the same top-level helpers used in the else branch:
call getProjectTopLevelItems(collections, projectId) to build the combined
ordered list, find the anchor index using insertAfterWorkspaceId (by matching
workspaceId or sectionId as appropriate), splice the new sectionId into that
array at anchorIndex+1, then call writeProjectTopLevelOrder(collections,
projectId, newOrderedArray) to persist all tabOrders in one pass; remove the two
for-loops and the manual +1 increment logic and set tabOrder to the computed
position from the newOrderedArray (or use getNextTabOrder on the updated array
if needed).
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts (1)

80-86: Minor: drop the redundant name: "New group" override.

createSection's default name was just changed to "New group" in useDashboardSidebarState.ts, so passing it explicitly here duplicates the literal. If the default ever changes again, both call sites need to be kept in sync.

♻️ Proposed cleanup
 	const handleCreateSection = () => {
-		const sectionId = createSection(projectId, {
-			name: "New group",
-		});
+		const sectionId = createSection(projectId);
 		moveWorkspaceToSection(workspaceId, projectId, sectionId);
 		requestSectionRename(sectionId);
 	};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts`
around lines 80 - 86, Remove the redundant explicit name override when creating
a section: in useDashboardSidebarWorkspaceItemActions, update
handleCreateSection so it calls createSection(projectId) without passing { name:
"New group" } (since createSection already defaults name to "New group" in
useDashboardSidebarState.ts), then continue to call
moveWorkspaceToSection(workspaceId, projectId, sectionId) and
requestSectionRename(sectionId) as before.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx (1)

2-17: Import ReactNode directly instead of using the React.* namespace.

React.ReactNode relies on a global React namespace that isn't imported here (only ComponentPropsWithoutRef and forwardRef are). This works only if the project's tsconfig/global types still expose the React namespace — fragile under modern jsx: "react-jsx" setups and inconsistent with the rest of this file.

♻️ Proposed fix
-import { type ComponentPropsWithoutRef, forwardRef } from "react";
+import { type ComponentPropsWithoutRef, forwardRef, type ReactNode } from "react";
@@
-	actions?: React.ReactNode;
+	actions?: ReactNode;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx`
around lines 2 - 17, The props type uses the global React namespace for the
actions prop (actions?: React.ReactNode) but React isn't imported; update the
import list from "react" to also pull in ReactNode and change the actions type
to use that imported symbol (e.g., actions?: ReactNode) inside the
DashboardSidebarSectionHeaderProps interface in
DashboardSidebarSectionHeader.tsx so the type does not rely on a global React
namespace.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx`:
- Around line 86-93: The header's outer interactive region (role="button",
onClick={onToggleCollapse}, Space/Enter handlers) allows clicks and key events
from the actions slot to bubble up and toggle collapse; to fix, render the
actions slot (the actions variable) inside a non-interactive container that
stops propagation of mouse and keyboard events (e.g., wrap actions in a <div>
and call event.stopPropagation() on onClick and onKeyDown, specifically
preventing Space/Enter from bubbling) so callers don't need to handle
propagation; update the DashboardSidebarSectionHeader component where isRenaming
and actions are used and ensure onToggleCollapse and the header's keyboard
handlers remain unchanged.

---

Nitpick comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx`:
- Around line 2-17: The props type uses the global React namespace for the
actions prop (actions?: React.ReactNode) but React isn't imported; update the
import list from "react" to also pull in ReactNode and change the actions type
to use that imported symbol (e.g., actions?: ReactNode) inside the
DashboardSidebarSectionHeaderProps interface in
DashboardSidebarSectionHeader.tsx so the type does not rely on a global React
namespace.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts`:
- Around line 80-86: Remove the redundant explicit name override when creating a
section: in useDashboardSidebarWorkspaceItemActions, update handleCreateSection
so it calls createSection(projectId) without passing { name: "New group" }
(since createSection already defaults name to "New group" in
useDashboardSidebarState.ts), then continue to call
moveWorkspaceToSection(workspaceId, projectId, sectionId) and
requestSectionRename(sectionId) as before.

In
`@apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts`:
- Around line 88-110: writeProjectTopLevelOrder currently resets workspace
sidebar state (it sets draft.sidebarState.projectId = projectId and
draft.sidebarState.sectionId = null) which re-parents workspaces to the provided
project; add a short JSDoc above writeProjectTopLevelOrder stating its contract:
that it mutates workspace sidebarState to assign the given projectId and clear
sectionId (i.e., unnests/ungroups the workspace), and therefore callers such as
moveWorkspaceToSection and deleteSection must only pass workspaces that are
intended to be ungrouped; ensure the JSDoc names the mutated fields
(sidebarState.projectId and sidebarState.sectionId) so future callers won’t
accidentally re-parent workspaces.
- Around line 290-347: The insertAfterWorkspaceId branch inside createSection
currently manually iterates v2WorkspaceLocalState and v2SidebarSections to bump
tabOrder; replace that with the same top-level helpers used in the else branch:
call getProjectTopLevelItems(collections, projectId) to build the combined
ordered list, find the anchor index using insertAfterWorkspaceId (by matching
workspaceId or sectionId as appropriate), splice the new sectionId into that
array at anchorIndex+1, then call writeProjectTopLevelOrder(collections,
projectId, newOrderedArray) to persist all tabOrders in one pass; remove the two
for-loops and the manual +1 increment logic and set tabOrder to the computed
position from the newOrderedArray (or use getNextTabOrder on the updated array
if needed).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9e90f017-6609-4149-8d4a-1d7385de853c

📥 Commits

Reviewing files that changed from the base of the PR and between f44d41b and 434f3bf.

📒 Files selected for processing (21)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/DashboardSidebar.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarProjectSection/components/DashboardSidebarProjectContextMenu/DashboardSidebarProjectContextMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarProjectSection/hooks/useDashboardSidebarProjectSectionActions/useDashboardSidebarProjectSectionActions.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/DashboardSidebarSection.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContent/DashboardSidebarSectionContent.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContent/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/DashboardSidebarSectionContextMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/DashboardSidebarSectionActionsDropdown/DashboardSidebarSectionActionsDropdown.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/DashboardSidebarSectionActionsDropdown/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/SectionActionsMenuItems.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSectionRenameContext/DashboardSidebarSectionRenameContext.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSectionRenameContext/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/SortableSectionHeader/SortableSectionHeader.tsx
  • apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts
💤 Files with no reviewable changes (4)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContent/DashboardSidebarSectionContent.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContent/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/DashboardSidebarSection.tsx
✅ Files skipped from review due to trivial changes (6)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarProjectSection/components/DashboardSidebarProjectContextMenu/DashboardSidebarProjectContextMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/DashboardSidebarSectionActionsDropdown/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/DashboardSidebarSectionActionsDropdown/DashboardSidebarSectionActionsDropdown.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/types.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSectionRenameContext/DashboardSidebarSectionRenameContext.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSectionRenameContext/index.ts

@Kitenite Kitenite force-pushed the sections-sidebar-ux branch from 434f3bf to a3c7651 Compare April 26, 2026 01:19
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.

🧹 Nitpick comments (1)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx (1)

67-75: Minor: cursor-grab on the chevron/grip wrapper, but the area also toggles collapse on click.

The inner div advertises grab affordance via cursor-grab/active:cursor-grabbing, but since {...listeners}/{...attributes} are spread onto the outer header (in SortableSectionHeader), the entire header is draggable and a click on the chevron/grip area will bubble to the header's onClick={onToggleCollapse}. In practice, dnd-kit's MouseSensor activation distance (8px) makes a quick click toggle collapse — which is probably the intent — but the cursor hint can read as "drag-only" when this region also toggles. Consider whether this should be visually presented as a chevron toggle (e.g., cursor-pointer) so users don't expect drag-only behavior in that 5x5 area.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx`
around lines 67 - 75, The chevron/grip wrapper in DashboardSidebarSectionHeader
currently uses "cursor-grab" / "active:cursor-grabbing" which suggests drag-only
but the outer SortableSectionHeader spreads {...listeners} / {...attributes} and
also handles onClick={onToggleCollapse}; update the inner div's className to use
a click affordance (e.g., "cursor-pointer") instead of
"cursor-grab"/"active:cursor-grabbing" so the small 5x5 area clearly indicates
it toggles collapse; adjust the class on the div containing HiChevronRight and
LuGripVertical (and any conditional classes referencing section.isCollapsed)
accordingly (or make it conditional: use cursor-pointer when the header handles
toggle, and cursor-grab only if you detect a pure drag-only mode).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx`:
- Around line 67-75: The chevron/grip wrapper in DashboardSidebarSectionHeader
currently uses "cursor-grab" / "active:cursor-grabbing" which suggests drag-only
but the outer SortableSectionHeader spreads {...listeners} / {...attributes} and
also handles onClick={onToggleCollapse}; update the inner div's className to use
a click affordance (e.g., "cursor-pointer") instead of
"cursor-grab"/"active:cursor-grabbing" so the small 5x5 area clearly indicates
it toggles collapse; adjust the class on the div containing HiChevronRight and
LuGripVertical (and any conditional classes referencing section.isCollapsed)
accordingly (or make it conditional: use cursor-pointer when the header handles
toggle, and cursor-grab only if you detect a pure drag-only mode).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e79af165-7717-4bd3-a8bd-381b68f1d0de

📥 Commits

Reviewing files that changed from the base of the PR and between 434f3bf and a3c7651.

📒 Files selected for processing (21)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/DashboardSidebar.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarProjectSection/components/DashboardSidebarProjectContextMenu/DashboardSidebarProjectContextMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarProjectSection/hooks/useDashboardSidebarProjectSectionActions/useDashboardSidebarProjectSectionActions.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/DashboardSidebarSection.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContent/DashboardSidebarSectionContent.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContent/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/DashboardSidebarSectionContextMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/DashboardSidebarSectionActionsDropdown/DashboardSidebarSectionActionsDropdown.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/DashboardSidebarSectionActionsDropdown/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/SectionActionsMenuItems.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionHeader/DashboardSidebarSectionHeader.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSectionRenameContext/DashboardSidebarSectionRenameContext.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSectionRenameContext/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/SortableSectionHeader/SortableSectionHeader.tsx
  • apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts
💤 Files with no reviewable changes (4)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContent/DashboardSidebarSectionContent.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContent/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/DashboardSidebarSection.tsx
✅ Files skipped from review due to trivial changes (7)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarProjectSection/components/DashboardSidebarProjectContextMenu/DashboardSidebarProjectContextMenu.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/DashboardSidebarSectionActionsDropdown/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSectionRenameContext/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/DashboardSidebarSectionActionsDropdown/DashboardSidebarSectionActionsDropdown.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarSection/components/DashboardSidebarSectionContextMenu/components/SectionActionsMenuItems/SectionActionsMenuItems.tsx
  • apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts

@Kitenite Kitenite merged commit 6b96acd into main Apr 26, 2026
6 checks passed
@Kitenite Kitenite deleted the sections-sidebar-ux branch April 26, 2026 01:27
@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! 🎉

MocA-Love added a commit to MocA-Love/superset that referenced this pull request Apr 26, 2026
3 PR (#442, #443, #444) で取り込み済みの 9 commits を git 履歴上もマージ済みに記録する。
内容差分は無し (merge -s ours)。

取り込み内容:
- 6b96acd Improve sidebar group management UX (superset-sh#3745)
- a4079e7 Update dashboard sidebar workspace icons (superset-sh#3755)
- d3753d0 [codex] Use dynamic footer copyright years (superset-sh#3754)
- ce606be Handle browser passthrough during v2 resize (superset-sh#3744)
- b1e1eb7 Refactor v2 workspace page (superset-sh#3747)
- 8693869 [codex] move v2 toggle to experimental settings (superset-sh#3748)
- ef3f381 Revert "fix(desktop): refit v2 terminal after font settle (superset-sh#3742)" (superset-sh#3750) - 手動移植 (vibrancy patch 維持)
- 25b2d52 Show terminal sessions from all workspaces in dropdown (superset-sh#3751)
- 62737db fix v1 terminal resize repaint (superset-sh#3756)
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