feat(desktop): promote "Create Section Below" to top-level on workspace menu#3537
Conversation
…ce menu The workspace context menu previously hid section creation inside the "Move to Section" submenu, and the new section always appended to the end of the project — making "create" and "move" feel like the same action. Promote section creation to a top-level item, inserting an empty section directly below the right-clicked workspace so it matches the label, and leave "Move to Section" as a list of existing sections (hidden entirely when none exist).
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughExpose a top-level "Create Section Below" context-menu action and route it to a new placement-aware section creation flow; adjust menu rendering and update section-creation logic to accept an insertion anchor and compute tabOrder accordingly. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ContextMenu
participant ActionHook as useDashboardSidebarWorkspaceItemActions
participant StateHook as useDashboardSidebarState (store)
User->>ContextMenu: click "Create Section Below"
ContextMenu->>ActionHook: onCreateSection(workspaceId, projectId)
ActionHook->>StateHook: createSection(projectId, { insertAfterWorkspaceId: workspaceId })
StateHook->>StateHook: compute anchorTabOrder, shift orders, set new section tabOrder
StateHook-->>ActionHook: newSectionId
ActionHook-->>ContextMenu: confirm/create complete
ContextMenu-->>User: UI updated (new section shown)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/hooks/useDashboardSidebarState/useDashboardSidebarState.ts`:
- Around line 199-236: The current branch assumes insertAfterWorkspaceId
resolves to a valid workspace and uses a default anchorTabOrder of 0, causing
mass reorders if the id is stale; update the logic in useDashboardSidebarState
so you first retrieve anchorWorkspace and guard that it exists and its
sidebarState.projectId === projectId (check insertAfterWorkspaceId,
anchorWorkspace, and anchorWorkspace.sidebarState.projectId), and if the guard
fails fall through to the append-at-end branch (i.e., treat as no
insertAfterWorkspaceId) instead of computing anchorTabOrder = 0 and bumping
every item in collections.v2WorkspaceLocalState / collections.v2SidebarSections;
keep the subsequent reordering code unchanged but only execute it when the
anchor is valid.
🪄 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: a589987e-b4d1-4911-911a-cf7a939b77e0
📒 Files selected for processing (3)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.tsapps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts
| if (insertAfterWorkspaceId) { | ||
| const anchorWorkspace = collections.v2WorkspaceLocalState.get( | ||
| insertAfterWorkspaceId, | ||
| ); | ||
| const anchorTabOrder = anchorWorkspace?.sidebarState.sectionId | ||
| ? (collections.v2SidebarSections.get( | ||
| anchorWorkspace.sidebarState.sectionId, | ||
| )?.tabOrder ?? 0) | ||
| : (anchorWorkspace?.sidebarState.tabOrder ?? 0); | ||
|
|
||
| for (const workspace of collections.v2WorkspaceLocalState.state.values()) { | ||
| if ( | ||
| workspace.sidebarState.projectId === projectId && | ||
| workspace.sidebarState.sectionId === null && | ||
| workspace.sidebarState.tabOrder > anchorTabOrder | ||
| ) { | ||
| const nextOrder = workspace.sidebarState.tabOrder + 1; | ||
| collections.v2WorkspaceLocalState.update( | ||
| workspace.workspaceId, | ||
| (draft) => { | ||
| draft.sidebarState.tabOrder = nextOrder; | ||
| }, | ||
| ); | ||
| } | ||
| } | ||
| for (const section of collections.v2SidebarSections.state.values()) { | ||
| if ( | ||
| section.projectId === projectId && | ||
| section.tabOrder > anchorTabOrder | ||
| ) { | ||
| const nextOrder = section.tabOrder + 1; | ||
| collections.v2SidebarSections.update(section.sectionId, (draft) => { | ||
| draft.tabOrder = nextOrder; | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| tabOrder = anchorTabOrder + 1; |
There was a problem hiding this comment.
Silent fallback when insertAfterWorkspaceId is unknown.
If insertAfterWorkspaceId does not resolve to a workspace (e.g., stale id, race between menu open and state change), anchorWorkspace is undefined, anchorTabOrder falls back to 0, every top-level workspace/section in the project gets bumped +1, and the new section is inserted at tabOrder = 1 (top of the project). That's a surprising outcome for a "Create Section Below X" action — it would look like the section was created at the top and unrelated items shifted.
Consider short-circuiting (or falling through to the append-at-end branch) when the anchor workspace is missing or belongs to a different projectId:
🛡️ Proposed defensive check
- if (insertAfterWorkspaceId) {
- const anchorWorkspace = collections.v2WorkspaceLocalState.get(
- insertAfterWorkspaceId,
- );
- const anchorTabOrder = anchorWorkspace?.sidebarState.sectionId
- ? (collections.v2SidebarSections.get(
- anchorWorkspace.sidebarState.sectionId,
- )?.tabOrder ?? 0)
- : (anchorWorkspace?.sidebarState.tabOrder ?? 0);
+ const anchorWorkspace = insertAfterWorkspaceId
+ ? collections.v2WorkspaceLocalState.get(insertAfterWorkspaceId)
+ : undefined;
+ if (anchorWorkspace && anchorWorkspace.sidebarState.projectId === projectId) {
+ const anchorTabOrder = anchorWorkspace.sidebarState.sectionId
+ ? (collections.v2SidebarSections.get(
+ anchorWorkspace.sidebarState.sectionId,
+ )?.tabOrder ?? 0)
+ : anchorWorkspace.sidebarState.tabOrder;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (insertAfterWorkspaceId) { | |
| const anchorWorkspace = collections.v2WorkspaceLocalState.get( | |
| insertAfterWorkspaceId, | |
| ); | |
| const anchorTabOrder = anchorWorkspace?.sidebarState.sectionId | |
| ? (collections.v2SidebarSections.get( | |
| anchorWorkspace.sidebarState.sectionId, | |
| )?.tabOrder ?? 0) | |
| : (anchorWorkspace?.sidebarState.tabOrder ?? 0); | |
| for (const workspace of collections.v2WorkspaceLocalState.state.values()) { | |
| if ( | |
| workspace.sidebarState.projectId === projectId && | |
| workspace.sidebarState.sectionId === null && | |
| workspace.sidebarState.tabOrder > anchorTabOrder | |
| ) { | |
| const nextOrder = workspace.sidebarState.tabOrder + 1; | |
| collections.v2WorkspaceLocalState.update( | |
| workspace.workspaceId, | |
| (draft) => { | |
| draft.sidebarState.tabOrder = nextOrder; | |
| }, | |
| ); | |
| } | |
| } | |
| for (const section of collections.v2SidebarSections.state.values()) { | |
| if ( | |
| section.projectId === projectId && | |
| section.tabOrder > anchorTabOrder | |
| ) { | |
| const nextOrder = section.tabOrder + 1; | |
| collections.v2SidebarSections.update(section.sectionId, (draft) => { | |
| draft.tabOrder = nextOrder; | |
| }); | |
| } | |
| } | |
| tabOrder = anchorTabOrder + 1; | |
| const anchorWorkspace = insertAfterWorkspaceId | |
| ? collections.v2WorkspaceLocalState.get(insertAfterWorkspaceId) | |
| : undefined; | |
| if (anchorWorkspace && anchorWorkspace.sidebarState.projectId === projectId) { | |
| const anchorTabOrder = anchorWorkspace.sidebarState.sectionId | |
| ? (collections.v2SidebarSections.get( | |
| anchorWorkspace.sidebarState.sectionId, | |
| )?.tabOrder ?? 0) | |
| : anchorWorkspace.sidebarState.tabOrder; | |
| for (const workspace of collections.v2WorkspaceLocalState.state.values()) { | |
| if ( | |
| workspace.sidebarState.projectId === projectId && | |
| workspace.sidebarState.sectionId === null && | |
| workspace.sidebarState.tabOrder > anchorTabOrder | |
| ) { | |
| const nextOrder = workspace.sidebarState.tabOrder + 1; | |
| collections.v2WorkspaceLocalState.update( | |
| workspace.workspaceId, | |
| (draft) => { | |
| draft.sidebarState.tabOrder = nextOrder; | |
| }, | |
| ); | |
| } | |
| } | |
| for (const section of collections.v2SidebarSections.state.values()) { | |
| if ( | |
| section.projectId === projectId && | |
| section.tabOrder > anchorTabOrder | |
| ) { | |
| const nextOrder = section.tabOrder + 1; | |
| collections.v2SidebarSections.update(section.sectionId, (draft) => { | |
| draft.tabOrder = nextOrder; | |
| }); | |
| } | |
| } | |
| tabOrder = anchorTabOrder + 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 199 - 236, The current branch assumes insertAfterWorkspaceId
resolves to a valid workspace and uses a default anchorTabOrder of 0, causing
mass reorders if the id is stale; update the logic in useDashboardSidebarState
so you first retrieve anchorWorkspace and guard that it exists and its
sidebarState.projectId === projectId (check insertAfterWorkspaceId,
anchorWorkspace, and anchorWorkspace.sidebarState.projectId), and if the guard
fails fall through to the append-at-end branch (i.e., treat as no
insertAfterWorkspaceId) instead of computing anchorTabOrder = 0 and bumping
every item in collections.v2WorkspaceLocalState / collections.v2SidebarSections;
keep the subsequent reordering code unchanged but only execute it when the
anchor is valid.
Greptile SummaryThis PR improves the workspace context-menu UX by surfacing "Create Section Below" as a top-level action and decluttering "Move to Section" to only appear when sections exist. Key changes:
Confidence Score: 5/5Safe to merge — the logic is sound and backward-compatible; one P2 defensive-coding suggestion but no blocking bugs. All three test-plan scenarios are correctly implemented. The
|
| Filename | Overview |
|---|---|
| apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts | Adds insertAfterWorkspaceId option to createSection; logic for bumping subsequent items is correct, but the fallback to anchorTabOrder = 0 when the anchor workspace is missing could silently place the new section at the top of the sidebar. |
| apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx | Promotes "Create Section Below" to a top-level menu item and guards "Move to Section" submenu behind sections.length > 0; clean change with no issues. |
| apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts | Removes the old moveWorkspaceToSection call after creating a section; now delegates positioning entirely to createSection via insertAfterWorkspaceId. Backward-compatible with the project-level menu path. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User right-clicks workspace] --> B[DashboardSidebarWorkspaceContextMenu]
B --> C{"sections.length > 0?"}
C -- Yes --> D[Show 'Move to Section' submenu\nwith existing sections only]
C -- No --> E[Hide 'Move to Section']
B --> F["'Create Section Below' top-level item"]
F --> G[handleCreateSection\nin useDashboardSidebarWorkspaceItemActions]
G --> H["createSection(projectId, { insertAfterWorkspaceId })"]
H --> I{insertAfterWorkspaceId\nprovided?}
I -- Yes --> J[Resolve anchor workspace\nfrom v2WorkspaceLocalState]
J --> K{Is anchor\nin a section?}
K -- Yes --> L[anchorTabOrder = parent section's tabOrder]
K -- No --> M[anchorTabOrder = workspace's tabOrder]
L --> N[Bump ungrouped workspaces\nand sections with tabOrder > anchorTabOrder by +1]
M --> N
N --> O["Insert section at tabOrder = anchorTabOrder + 1"]
I -- No --> P[getNextTabOrder from existing sections\nAppend at end]
P --> O
O --> Q[Workspace stays in place\nNew empty section appears below]
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: 199-207
Comment:
**Missing guard for unknown anchor workspace**
If `insertAfterWorkspaceId` is provided but the workspace is not found in `v2WorkspaceLocalState` (e.g., stale state, timing edge case), `anchorWorkspace` is `undefined`. Both optional chains resolve to `undefined`, so `anchorTabOrder` silently defaults to `0`. This causes every top-level workspace and section in the project to be bumped by +1 and the new section to land at `tabOrder = 1` (the very top of the sidebar) — the opposite of the user's intent.
Consider adding a guard to fall back to the append behavior when the anchor cannot be resolved:
```ts
if (insertAfterWorkspaceId) {
const anchorWorkspace = collections.v2WorkspaceLocalState.get(
insertAfterWorkspaceId,
);
if (!anchorWorkspace) {
// Anchor not found – fall back to append
const sectionOrders = Array.from(
collections.v2SidebarSections.state.values(),
).filter((item) => item.projectId === projectId);
tabOrder = getNextTabOrder(sectionOrders);
} else {
const anchorTabOrder = anchorWorkspace.sidebarState.sectionId
? (collections.v2SidebarSections.get(
anchorWorkspace.sidebarState.sectionId,
)?.tabOrder ?? 0)
: anchorWorkspace.sidebarState.tabOrder;
// ... bump loop and tabOrder assignment ...
}
}
```
This also applies if the section pointed to by `sidebarState.sectionId` has been deleted — the `?.tabOrder ?? 0` fallback inside the ternary has the same problem.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "feat(desktop): promote "Create Section B..." | Re-trigger Greptile
| if (insertAfterWorkspaceId) { | ||
| const anchorWorkspace = collections.v2WorkspaceLocalState.get( | ||
| insertAfterWorkspaceId, | ||
| ); | ||
| const anchorTabOrder = anchorWorkspace?.sidebarState.sectionId | ||
| ? (collections.v2SidebarSections.get( | ||
| anchorWorkspace.sidebarState.sectionId, | ||
| )?.tabOrder ?? 0) | ||
| : (anchorWorkspace?.sidebarState.tabOrder ?? 0); |
There was a problem hiding this comment.
Missing guard for unknown anchor workspace
If insertAfterWorkspaceId is provided but the workspace is not found in v2WorkspaceLocalState (e.g., stale state, timing edge case), anchorWorkspace is undefined. Both optional chains resolve to undefined, so anchorTabOrder silently defaults to 0. This causes every top-level workspace and section in the project to be bumped by +1 and the new section to land at tabOrder = 1 (the very top of the sidebar) — the opposite of the user's intent.
Consider adding a guard to fall back to the append behavior when the anchor cannot be resolved:
if (insertAfterWorkspaceId) {
const anchorWorkspace = collections.v2WorkspaceLocalState.get(
insertAfterWorkspaceId,
);
if (!anchorWorkspace) {
// Anchor not found – fall back to append
const sectionOrders = Array.from(
collections.v2SidebarSections.state.values(),
).filter((item) => item.projectId === projectId);
tabOrder = getNextTabOrder(sectionOrders);
} else {
const anchorTabOrder = anchorWorkspace.sidebarState.sectionId
? (collections.v2SidebarSections.get(
anchorWorkspace.sidebarState.sectionId,
)?.tabOrder ?? 0)
: anchorWorkspace.sidebarState.tabOrder;
// ... bump loop and tabOrder assignment ...
}
}This also applies if the section pointed to by sidebarState.sectionId has been deleted — the ?.tabOrder ?? 0 fallback inside the ternary has the same problem.
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: 199-207
Comment:
**Missing guard for unknown anchor workspace**
If `insertAfterWorkspaceId` is provided but the workspace is not found in `v2WorkspaceLocalState` (e.g., stale state, timing edge case), `anchorWorkspace` is `undefined`. Both optional chains resolve to `undefined`, so `anchorTabOrder` silently defaults to `0`. This causes every top-level workspace and section in the project to be bumped by +1 and the new section to land at `tabOrder = 1` (the very top of the sidebar) — the opposite of the user's intent.
Consider adding a guard to fall back to the append behavior when the anchor cannot be resolved:
```ts
if (insertAfterWorkspaceId) {
const anchorWorkspace = collections.v2WorkspaceLocalState.get(
insertAfterWorkspaceId,
);
if (!anchorWorkspace) {
// Anchor not found – fall back to append
const sectionOrders = Array.from(
collections.v2SidebarSections.state.values(),
).filter((item) => item.projectId === projectId);
tabOrder = getNextTabOrder(sectionOrders);
} else {
const anchorTabOrder = anchorWorkspace.sidebarState.sectionId
? (collections.v2SidebarSections.get(
anchorWorkspace.sidebarState.sectionId,
)?.tabOrder ?? 0)
: anchorWorkspace.sidebarState.tabOrder;
// ... bump loop and tabOrder assignment ...
}
}
```
This also applies if the section pointed to by `sidebarState.sectionId` has been deleted — the `?.tabOrder ?? 0` fallback inside the ternary has the same problem.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
1 issue found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts">
<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts:199">
P2: When `insertAfterWorkspaceId` doesn't resolve to a workspace (stale ID or race condition), `anchorWorkspace` is `undefined` and `anchorTabOrder` falls back to `0`. This causes every top-level item with `tabOrder > 0` to be bumped and the new section to land at the top of the project — silently corrupting the sidebar order.
Guard against this by checking that `anchorWorkspace` actually resolved before entering the bump logic, and fall through to the append-at-end branch otherwise:
```ts
const anchorWorkspace = insertAfterWorkspaceId
? collections.v2WorkspaceLocalState.get(insertAfterWorkspaceId)
: undefined;
if (anchorWorkspace && anchorWorkspace.sidebarState.projectId === projectId) {
// ... bump logic with anchorTabOrder
} else {
// append-at-end
}
```</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| if (insertAfterWorkspaceId) { | ||
| const anchorWorkspace = collections.v2WorkspaceLocalState.get( | ||
| insertAfterWorkspaceId, | ||
| ); |
There was a problem hiding this comment.
P2: When insertAfterWorkspaceId doesn't resolve to a workspace (stale ID or race condition), anchorWorkspace is undefined and anchorTabOrder falls back to 0. This causes every top-level item with tabOrder > 0 to be bumped and the new section to land at the top of the project — silently corrupting the sidebar order.
Guard against this by checking that anchorWorkspace actually resolved before entering the bump logic, and fall through to the append-at-end branch otherwise:
const anchorWorkspace = insertAfterWorkspaceId
? collections.v2WorkspaceLocalState.get(insertAfterWorkspaceId)
: undefined;
if (anchorWorkspace && anchorWorkspace.sidebarState.projectId === projectId) {
// ... bump logic with anchorTabOrder
} else {
// append-at-end
}Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts, line 199:
<comment>When `insertAfterWorkspaceId` doesn't resolve to a workspace (stale ID or race condition), `anchorWorkspace` is `undefined` and `anchorTabOrder` falls back to `0`. This causes every top-level item with `tabOrder > 0` to be bumped and the new section to land at the top of the project — silently corrupting the sidebar order.
Guard against this by checking that `anchorWorkspace` actually resolved before entering the bump logic, and fall through to the append-at-end branch otherwise:
```ts
const anchorWorkspace = insertAfterWorkspaceId
? collections.v2WorkspaceLocalState.get(insertAfterWorkspaceId)
: undefined;
if (anchorWorkspace && anchorWorkspace.sidebarState.projectId === projectId) {
// ... bump logic with anchorTabOrder
} else {
// append-at-end
}
```</comment>
<file context>
@@ -182,25 +182,71 @@ export function useDashboardSidebarState() {
].value;
+ let tabOrder: number;
+ if (insertAfterWorkspaceId) {
+ const anchorWorkspace = collections.v2WorkspaceLocalState.get(
+ insertAfterWorkspaceId,
</file context>
| if (insertAfterWorkspaceId) { | |
| const anchorWorkspace = collections.v2WorkspaceLocalState.get( | |
| insertAfterWorkspaceId, | |
| ); | |
| const anchorWorkspace = insertAfterWorkspaceId | |
| ? collections.v2WorkspaceLocalState.get(insertAfterWorkspaceId) | |
| : undefined; | |
| if (anchorWorkspace && anchorWorkspace.sidebarState.projectId === projectId) { |
…ion" with divider
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
…ce menu (superset-sh#3537) * feat(desktop): promote "Create Section Below" to top-level on workspace menu The workspace context menu previously hid section creation inside the "Move to Section" submenu, and the new section always appended to the end of the project — making "create" and "move" feel like the same action. Promote section creation to a top-level item, inserting an empty section directly below the right-clicked workspace so it matches the label, and leave "Move to Section" as a list of existing sections (hidden entirely when none exist). * refactor(desktop): separate "Create Section Below" from "Move to Section" with divider
…ction-below upstream取り込み: Create Section Below を top-level に昇格 (superset-sh#3537)
Upstream commits processed (cherry-picked, then adapted where needed): - 07c1ee0 fix(desktop): Cmd+O firing open-in twice on v1 workspace route (superset-sh#3511) → PR #302 (with fork tearoff-window adaptation for Cmd+O) - 4a1f41a chore(deps): upgrade tanstack/db + electric, drop durable-streams patch (superset-sh#3509) → PR #303 (fork keeps fstream patch) - a3df489 feat(desktop): v2 PR checkout via widened checkout procedure (superset-sh#3525) → PR #304 (clean) - c504a50 feat(desktop): v2 file editor — foundation, views, and stability pass (superset-sh#3526) → PR #310 (foundation: 58 files path-checkout) → PR #311 (adaptation: 20 files manual port with SpreadsheetViewer/memo/fork-hotkeys preserved) - 78b7dc8 feat(desktop): promote "Create Section Below" to top-level on workspace menu (superset-sh#3537) → PR #308 Record merge so upstream/main..main shows 0 behind.
Summary
useDashboardSidebarState.createSectiongained aninsertAfterWorkspaceIdoption that bumps subsequent top-level items (ungrouped workspaces + sections) by +1 to make room. Default append-at-end behavior preserved for the project-level menu.Test plan
Summary by cubic
Promote section creation to a top-level “Create Section Below” in the workspace context menu. New sections appear directly under the clicked workspace (or its parent section) for predictable placement.
useDashboardSidebarState.createSectionacceptsinsertAfterWorkspaceIdto insert after a workspace and shift following top-level items; default append remains for the project menu.Written for commit 43b8268. Summary will update on new commits.
Summary by CodeRabbit