Skip to content

fix(desktop): place new v2 workspace at top of sidebar#4139

Merged
saddlepaddle merged 1 commit into
mainfrom
check-workspace-placement
May 6, 2026
Merged

fix(desktop): place new v2 workspace at top of sidebar#4139
saddlepaddle merged 1 commit into
mainfrom
check-workspace-placement

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented May 6, 2026

Summary

Test plan

  • Open desktop on an account with multiple existing v2 workspaces in the same project; create a new workspace from the new-workspace modal — confirm it appears at the top of that project in the sidebar.
  • Create a few back-to-back; confirm each new one lands above the previous, not interleaved.
  • Drag-reorder existing workspaces, then create another; confirm the new one still lands above the dragged ones (no collision with reordered tabOrder >= 1 rows).
  • Adopt an existing worktree (server returns alreadyExists) — confirm we don't move the existing row.

Summary by cubic

Ensure new v2 workspaces always appear at the top of the project sidebar by computing a prepend tab order instead of defaulting to 0. Fixes nondeterministic ordering when existing items also had tabOrder: 0.

  • Bug Fixes
    • Added shared getPrependTabOrder/getNextTabOrder utilities in dashboardSidebarLocal/tabOrder.ts and re-exported.
    • useWorkspaceCreates now sets tabOrder to min(top-level items) - 1, checking visible workspaces and sections in the project.
    • useDashboardSidebarState now imports these helpers and removes local duplicates.

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

Summary by CodeRabbit

  • Bug Fixes
    • Fixed sidebar item ordering for newly created workspaces to properly respect existing item positions instead of always appearing at the top.

The revert of #4120 (#4135) restored a hardcoded `tabOrder: 0` in the
v2 workspace.create path. Existing rows default to `tabOrder: 0` too,
so new workspaces tied with them and ordering was non-deterministic.

Restores the `getPrependTabOrder` helper from #4120 as a shared util in
`dashboardSidebarLocal/`, and uses it from `useWorkspaceCreates` so new
rows land strictly above every existing top-level item — matching what
the pending-row injection in `useDashboardSidebarData` already assumes.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b0133a7d-065d-4e01-b6af-8d51f9d7bfc9

📥 Commits

Reviewing files that changed from the base of the PR and between f3ff72b and f1ae9fc.

📒 Files selected for processing (4)
  • apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/tabOrder.ts
  • apps/desktop/src/renderer/stores/workspace-creates/useWorkspaceCreates.ts

📝 Walkthrough

Walkthrough

Tab-ordering utility helpers are extracted from useDashboardSidebarState.ts into a centralized dashboardSidebarLocal module. The new tabOrder.ts exports getPrependTabOrder and getNextTabOrder functions. Workspace creation now uses getPrependTabOrder to dynamically compute tab order for new workspaces instead of using a static value.

Changes

Tab-Order Utility Centralization & Dynamic Workspace Ordering

Layer / File(s) Summary
Utility Definition
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/tabOrder.ts
New functions getPrependTabOrder and getNextTabOrder compute tab order as one less or one more than the min/max of existing items, with fallbacks of 1 and 0 respectively.
Module Export
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/index.ts
Re-export of tabOrder module to expose the new utilities alongside existing exports.
Hook Refactoring
apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts
Local definitions of getNextTabOrder and getPrependTabOrder are removed; functions are now imported from centralized dashboardSidebarLocal module.
Workspace Creation Integration
apps/desktop/src/renderer/stores/workspace-creates/useWorkspaceCreates.ts
Workspace creation computes topLevelItems from existing workspaces and sidebar sections, then uses getPrependTabOrder(topLevelItems) to dynamically assign tab order to new workspaces instead of static 0.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • superset-sh/superset#3619: Modifies the same tab-order utility functions and workspace creation tab-order assignment logic.

Poem

🐰 Tab orders hop and weave,
No longer static, like a sieve,
New workspaces find their place,
In the sidebar's ordered space,
Utilities shared, logic clean—
The finest refactor ever seen! ✨

✨ 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 check-workspace-placement

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.

@saddlepaddle saddlepaddle merged commit eb448bf into main May 6, 2026
9 of 10 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 6, 2026

Greptile Summary

This PR fixes new v2 workspaces landing in a non-deterministic position in the sidebar by replacing the hardcoded tabOrder: 0 with a call to getPrependTabOrder, which assigns min(existing tabOrder) − 1 so the new row is always strictly above every existing top-level item. It also extracts getPrependTabOrder and getNextTabOrder into a new shared dashboardSidebarLocal/tabOrder.ts module, removing the duplicated local copies from useDashboardSidebarState.ts.

  • New shared utility (tabOrder.ts): getPrependTabOrder and getNextTabOrder are now exported from dashboardSidebarLocal/ and consumed by both useDashboardSidebarState and useWorkspaceCreates.
  • Bug fix in useWorkspaceCreates: Before inserting a new workspace local-state record, the code now collects all visible top-level workspaces and sections for the project and derives a strictly-lower tabOrder, replacing the previous tabOrder: 0 default that caused ties with existing rows.

Confidence Score: 4/5

The change is safe to merge — the bug fix is correct and the refactoring is mechanical with no behaviour change to existing paths.

The topLevelItems filter in useWorkspaceCreates.ts is a hand-rolled duplicate of the private getProjectTopLevelItems in useDashboardSidebarState.ts. If the two ever drift (e.g., a new visibility condition is added in one place but not the other), getPrependTabOrder will compute from a different item set than the rest of the ordering logic, silently placing new workspaces at the wrong position. Everything else in the PR is clean and mechanically correct.

useWorkspaceCreates.ts — the duplicated filter logic is worth a second look before future changes to getProjectTopLevelItems.

Important Files Changed

Filename Overview
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/tabOrder.ts New shared utility module exporting getPrependTabOrder and getNextTabOrder; logic is identical to what was previously local in useDashboardSidebarState.
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/index.ts Re-exports the new tabOrder utilities; straightforward barrel-file change.
apps/desktop/src/renderer/routes/_authenticated/hooks/useDashboardSidebarState/useDashboardSidebarState.ts Removes local getNextTabOrder / getPrependTabOrder definitions and imports them from the shared module; no behaviour change.
apps/desktop/src/renderer/stores/workspace-creates/useWorkspaceCreates.ts Core fix: computes top-level items and calls getPrependTabOrder before inserting the new workspace local state row; duplicates the topLevelItems filter logic that already exists in getProjectTopLevelItems.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[useWorkspaceCreates: submit] --> B[workspaces.create API call]
    B --> C{existing local record?}
    C -- yes --> D[update paneLayout only\ntabOrder unchanged]
    C -- no --> E[collect topLevelItems\nworkspaces sectionId=null\n+ sections for projectId]
    E --> F[getPrependTabOrder\nmin tabOrder - 1]
    F --> G[insert new workspace\nwith prepended tabOrder]
    G --> H{alreadyExists and\nid mismatch?}
    H -- yes --> I[remove optimistic\nin-flight entry]
    H -- no --> J[return ok]
    I --> J

    subgraph dashboardSidebarLocal/tabOrder.ts
        F2[getPrependTabOrder\nlen=0 → 1\nelse min-1]
        G2[getNextTabOrder\nmax + 1]
    end

    useDashboardSidebarState --> F2
    useDashboardSidebarState --> G2
    useWorkspaceCreates --> F2
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
apps/desktop/src/renderer/stores/workspace-creates/useWorkspaceCreates.ts:90-102
**Duplicated top-level-items filter logic**

The workspace + section filtering here is a near-verbatim copy of the private `getProjectTopLevelItems` function in `useDashboardSidebarState.ts`. If that function's filter criteria evolve (e.g., a new visibility condition is added), this site will silently diverge, causing `getPrependTabOrder` to compute from a different set than everything else — leading to subtle ordering bugs. Consider extracting `getProjectTopLevelItems` (or a lightweight equivalent that accepts collections + projectId and returns `Array<{ tabOrder: number }>`) into the shared `dashboardSidebarLocal/` module alongside the tab-order utilities.

Reviews (1): Last reviewed commit: "fix(desktop): place new v2 workspace at ..." | Re-trigger Greptile

Comment on lines +90 to +102
const topLevelItems = [
...Array.from(collections.v2WorkspaceLocalState.state.values())
.filter(
(item) =>
item.sidebarState.projectId === projectId &&
item.sidebarState.sectionId === null &&
isSidebarWorkspaceVisible(item),
)
.map((item) => ({ tabOrder: item.sidebarState.tabOrder })),
...Array.from(collections.v2SidebarSections.state.values())
.filter((item) => item.projectId === projectId)
.map((item) => ({ tabOrder: item.tabOrder })),
];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Duplicated top-level-items filter logic

The workspace + section filtering here is a near-verbatim copy of the private getProjectTopLevelItems function in useDashboardSidebarState.ts. If that function's filter criteria evolve (e.g., a new visibility condition is added), this site will silently diverge, causing getPrependTabOrder to compute from a different set than everything else — leading to subtle ordering bugs. Consider extracting getProjectTopLevelItems (or a lightweight equivalent that accepts collections + projectId and returns Array<{ tabOrder: number }>) into the shared dashboardSidebarLocal/ module alongside the tab-order utilities.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/stores/workspace-creates/useWorkspaceCreates.ts
Line: 90-102

Comment:
**Duplicated top-level-items filter logic**

The workspace + section filtering here is a near-verbatim copy of the private `getProjectTopLevelItems` function in `useDashboardSidebarState.ts`. If that function's filter criteria evolve (e.g., a new visibility condition is added), this site will silently diverge, causing `getPrependTabOrder` to compute from a different set than everything else — leading to subtle ordering bugs. Consider extracting `getProjectTopLevelItems` (or a lightweight equivalent that accepts collections + projectId and returns `Array<{ tabOrder: number }>`) into the shared `dashboardSidebarLocal/` module alongside the tab-order utilities.

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

MocA-Love pushed a commit to MocA-Love/superset that referenced this pull request May 8, 2026
)

The revert of superset-sh#4120 (superset-sh#4135) restored a hardcoded `tabOrder: 0` in the
v2 workspace.create path. Existing rows default to `tabOrder: 0` too,
so new workspaces tied with them and ordering was non-deterministic.

Restores the `getPrependTabOrder` helper from superset-sh#4120 as a shared util in
`dashboardSidebarLocal/`, and uses it from `useWorkspaceCreates` so new
rows land strictly above every existing top-level item — matching what
the pending-row injection in `useDashboardSidebarData` already assumes.
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