Skip to content

feat(desktop): confirm before removing workspace from sidebar#4524

Merged
Kitenite merged 1 commit into
mainfrom
sidebar-remove-dialog
May 13, 2026
Merged

feat(desktop): confirm before removing workspace from sidebar#4524
Kitenite merged 1 commit into
mainfrom
sidebar-remove-dialog

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented May 13, 2026

Summary

  • Routes every "Remove from sidebar" entry point (sidebar row minus button, sidebar context menu, command palette, Workspaces page row) through the shared useRemoveFromSidebarIntent store.
  • Converts RemoveFromSidebarMount from an auto-executing effect into an AlertDialog that warns the user and notes the workspace can be re-added from the Workspaces page.
  • Adds workspaceName to the intent target so the dialog can name what's being removed.

Test plan

  • Sidebar row hover → click minus icon → confirm dialog appears, "Remove" hides/removes, "Cancel" leaves sidebar untouched.
  • Sidebar row right-click → "Remove from Sidebar" → same dialog flow.
  • ⌘K command palette → "Remove from sidebar" → same dialog flow.
  • Workspaces page → minus button on a sidebar-pinned row → dialog flow; the current-route row still shows the disabled tooltip and is not removable.
  • Main workspace (always-shown) removal still routes through hideWorkspaceInSidebar; non-main routes through removeWorkspaceFromSidebar.

Summary by cubic

Add a confirmation dialog before removing a workspace from the sidebar and route all remove actions through a shared intent store. This prevents accidental removals and keeps behavior consistent across the sidebar, context menu, command palette, and Workspaces page.

  • New Features
    • All “Remove from sidebar” entry points now use useRemoveFromSidebarIntent.
    • Converted the auto-executing mount to an AlertDialog (@superset/ui/alert-dialog, @superset/ui/button) that names the workspace and notes it can be re-added from the Workspaces page.
    • Intent target now includes workspaceName; main workspaces still call hideWorkspaceInSidebar, others call removeWorkspaceFromSidebar.

Written for commit 38646bb. Summary will update on new commits.

Summary by CodeRabbit

Release Notes

  • New Features
    • Added a confirmation dialog when removing a workspace from the sidebar, providing users with an additional safety measure before the action is completed.

Review Change Stack

Wires every "Remove from sidebar" entry point (sidebar minus button,
context menu, command palette, Workspaces page row) through the
existing remove-from-sidebar intent store, which now drives an
AlertDialog that reminds users the workspace can be re-added from the
Workspaces page.
@capy-ai
Copy link
Copy Markdown

capy-ai Bot commented May 13, 2026

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d1a984c0-1c9e-4e8e-9b9c-c56619f0f6d5

📥 Commits

Reviewing files that changed from the base of the PR and between 9f10750 and 38646bb.

📒 Files selected for processing (5)
  • apps/desktop/src/renderer/commandPalette/modules/workspace/commands.tsx
  • apps/desktop/src/renderer/commandPalette/ui/RemoveFromSidebarMount/RemoveFromSidebarMount.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspaces/components/V2WorkspacesList/components/V2WorkspaceRow/V2WorkspaceRow.tsx
  • apps/desktop/src/renderer/stores/remove-workspace-from-sidebar-intent.ts

📝 Walkthrough

Walkthrough

The PR adds workspace name to the remove-from-sidebar workflow and replaces tick-based mount logic with a visible AlertDialog confirmation. Multiple UI entry points now pass workspace name through the intent request, which the confirmation dialog displays before removal.

Changes

Remove Workspace from Sidebar Intent Flow

Layer / File(s) Summary
Store contract and command palette entry
apps/desktop/src/renderer/stores/remove-workspace-from-sidebar-intent.ts, apps/desktop/src/renderer/commandPalette/modules/workspace/commands.tsx
RemoveFromSidebarTarget interface adds workspaceName: string field. Command palette removal command passes workspace name alongside workspace ID when requesting removal.
Dashboard sidebar workspace item removal request
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts
Hook removes useNavigateAwayFromWorkspace dependency, narrows useDashboardSidebarState to retain only sidebar manipulation helpers, and builds a removal request via useRemoveFromSidebarIntent with workspace name, ID, project ID, and main flag.
V2 Workspace row removal request
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspaces/components/V2WorkspacesList/components/V2WorkspaceRow/V2WorkspaceRow.tsx
Component updates removal handler to dispatch useRemoveFromSidebarIntent request with workspace name, ID, project ID, and main flag; sidebar state usage narrowed to ensureWorkspaceInSidebar.
RemoveFromSidebarMount confirmation dialog
apps/desktop/src/renderer/commandPalette/ui/RemoveFromSidebarMount/RemoveFromSidebarMount.tsx
Replaces effect/ref tick logic with AlertDialog UI that displays workspace name and provides Cancel/Remove actions. handleConfirm performs navigation and sidebar updates; handleOpenChange closes dialog.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

A rabbit hops through sidebar views,
With workspace names now come in two,
A dialog blooms to ask "are you sure?"—
Confirmation flows both swift and pure! 🐰✨

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

Warning

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

🔧 ESLint

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

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


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Kitenite Kitenite merged commit b5dc6d3 into main May 13, 2026
9 of 10 checks passed
@Kitenite Kitenite deleted the sidebar-remove-dialog branch May 13, 2026 20:30
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 13, 2026

Greptile Summary

This PR converts the "Remove from sidebar" action from an auto-executing side-effect into a confirmation AlertDialog, routing all entry points (sidebar row, context menu, command palette, Workspaces page) through a shared useRemoveFromSidebarIntent Zustand store. It also adds workspaceName to the intent target so the dialog can display the workspace name.

  • RemoveFromSidebarMount is refactored from a useEffect-based silent executor into an AlertDialog with Cancel and Remove buttons, keeping all removal logic in one centralized place.
  • useDashboardSidebarWorkspaceItemActions and V2WorkspaceRow are updated to call useRemoveFromSidebarIntent.getState().request(...) instead of directly mutating sidebar state.
  • RemoveFromSidebarTarget gains a workspaceName field; the tick counter is still maintained in the store but is no longer consumed by RemoveFromSidebarMount.

Confidence Score: 4/5

Safe to merge; the change is well-scoped and all removal paths correctly funnel through the new dialog before any sidebar state is mutated.

The refactor is straightforward — all entry points now call the shared intent store, and the dialog confirm/cancel paths correctly call clear() to reset state. Two minor issues exist: the tick field is still being incremented in the store but is never read after the useEffect removal, and the dialog uses plain Button components instead of Radix AlertDialogAction/AlertDialogCancel, which may affect screen-reader focus order. Neither affects functional correctness for mouse or keyboard users in the common case.

The remove-workspace-from-sidebar-intent.ts store retains a tick field that no longer serves a purpose, and RemoveFromSidebarMount.tsx warrants a second look for accessibility if the team cares about screen-reader support.

Important Files Changed

Filename Overview
apps/desktop/src/renderer/commandPalette/ui/RemoveFromSidebarMount/RemoveFromSidebarMount.tsx Core UI change: replaces a silent useEffect executor with an AlertDialog; uses plain Button instead of AlertDialogAction/AlertDialogCancel primitives, and the tick field is no longer consumed here.
apps/desktop/src/renderer/stores/remove-workspace-from-sidebar-intent.ts Adds workspaceName to the target interface; tick is still incremented on every request but is no longer read anywhere after the useEffect was removed.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspaces/components/V2WorkspacesList/components/V2WorkspaceRow/V2WorkspaceRow.tsx Delegates removal to the shared intent store; AccessibleV2Workspace.projectId is typed as string so no null-coalescing guard is needed here.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts Correctly replaces direct sidebar mutations with a request to the shared intent store, passing workspaceName through.
apps/desktop/src/renderer/commandPalette/modules/workspace/commands.tsx Minimal one-line addition of workspaceName to the intent request; already guarded by the existing if (workspace.projectId) check.

Sequence Diagram

sequenceDiagram
    participant U as User
    participant E as Entry Point
    participant S as useRemoveFromSidebarIntent
    participant D as RemoveFromSidebarMount
    participant SB as useDashboardSidebarState

    U->>E: Click "Remove from sidebar"
    E->>S: "request({ workspaceId, workspaceName, projectId, isMain })"
    S->>S: set target (tick++)
    S-->>D: target non-null → dialog opens

    alt User clicks Remove
        U->>D: onClick handleConfirm
        D->>SB: navigateAwayFromWorkspace
        alt isMain
            D->>SB: hideWorkspaceInSidebar
        else
            D->>SB: removeWorkspaceFromSidebar
        end
        D->>S: clear() → dialog closes
    else User clicks Cancel or Escape
        U->>D: onOpenChange(false)
        D->>S: clear() → dialog closes
    end
Loading
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
apps/desktop/src/renderer/stores/remove-workspace-from-sidebar-intent.ts:8
**`tick` is now dead state**

`tick` is incremented on every `request()` call but is no longer consumed anywhere — the old `useEffect` guard (`target.tick === lastTickRef.current`) was removed when `RemoveFromSidebarMount` became an `AlertDialog`. The dialog open/close state is driven entirely by `!!target`, so the field serves no runtime purpose. Consider removing `tick` from `RemoveFromSidebarTarget` and the `request` implementation to avoid confusion for future readers.

### Issue 2 of 2
apps/desktop/src/renderer/commandPalette/ui/RemoveFromSidebarMount/RemoveFromSidebarMount.tsx:59-75
**Plain `Button` bypasses `AlertDialog` accessibility primitives**

Radix UI's `AlertDialogAction` and `AlertDialogCancel` carry built-in accessibility semantics for the `alertdialog` role — `AlertDialogCancel` receives focus by default on open, and both handle keyboard dismiss correctly with their ARIA roles. Using plain `Button` components means those semantics are absent. The current implementation works visually, but screen readers and keyboard-only users may not get the expected cancel-first focus order or the correct element roles.

Reviews (1): Last reviewed commit: "feat(desktop): confirm before removing w..." | Re-trigger Greptile

workspaceName: string;
projectId: string;
isMain: boolean;
tick: number;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 tick is now dead state

tick is incremented on every request() call but is no longer consumed anywhere — the old useEffect guard (target.tick === lastTickRef.current) was removed when RemoveFromSidebarMount became an AlertDialog. The dialog open/close state is driven entirely by !!target, so the field serves no runtime purpose. Consider removing tick from RemoveFromSidebarTarget and the request implementation to avoid confusion for future readers.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/stores/remove-workspace-from-sidebar-intent.ts
Line: 8

Comment:
**`tick` is now dead state**

`tick` is incremented on every `request()` call but is no longer consumed anywhere — the old `useEffect` guard (`target.tick === lastTickRef.current`) was removed when `RemoveFromSidebarMount` became an `AlertDialog`. The dialog open/close state is driven entirely by `!!target`, so the field serves no runtime purpose. Consider removing `tick` from `RemoveFromSidebarTarget` and the `request` implementation to avoid confusion for future readers.

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

Comment on lines +59 to +75
<Button
variant="ghost"
size="sm"
className="h-7 px-3 text-xs"
onClick={() => handleOpenChange(false)}
>
Cancel
</Button>
<Button
variant="destructive"
size="sm"
className="h-7 px-3 text-xs"
onClick={handleConfirm}
>
Remove
</Button>
</AlertDialogFooter>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Plain Button bypasses AlertDialog accessibility primitives

Radix UI's AlertDialogAction and AlertDialogCancel carry built-in accessibility semantics for the alertdialog role — AlertDialogCancel receives focus by default on open, and both handle keyboard dismiss correctly with their ARIA roles. Using plain Button components means those semantics are absent. The current implementation works visually, but screen readers and keyboard-only users may not get the expected cancel-first focus order or the correct element roles.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/commandPalette/ui/RemoveFromSidebarMount/RemoveFromSidebarMount.tsx
Line: 59-75

Comment:
**Plain `Button` bypasses `AlertDialog` accessibility primitives**

Radix UI's `AlertDialogAction` and `AlertDialogCancel` carry built-in accessibility semantics for the `alertdialog` role — `AlertDialogCancel` receives focus by default on open, and both handle keyboard dismiss correctly with their ARIA roles. Using plain `Button` components means those semantics are absent. The current implementation works visually, but screen readers and keyboard-only users may not get the expected cancel-first focus order or the correct element roles.

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

@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! 🎉

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