Skip to content

Workspace selector and management UI; simplify File menu for multi-workspace flow #408

Description

@BorisTyshkevich

Goal

Add the user-facing multi-workspace workflow on top of #406 and #407:

  • switch workspaces from the header;
  • create, rename, export, and delete workspaces;
  • preserve Dashboard surface/mode while switching;
  • handle dirty editor drafts safely;
  • rework the File menu so it contains file/import/export operations rather than local workspace selection.

Dependencies

Product decisions

  • The current workspace title in the application header becomes the workspace selector.
  • The selector shows a flat list of local workspaces plus New workspace… and Manage workspaces….
  • Workspace switching is normal navigation, not file opening.
  • Destructive deletion is performed from a dedicated management dialog, not directly from each dropdown row.
  • Workspaces are sorted alphabetically by display name.
  • No recents, favorites, pinning, grouping, or nested menus in the first version.

Header structure

Target conceptual layout:

[File ▾] [ClickHouse Operations ▾] [Workspace | Dashboard] [View | Edit]

The exact responsive styling should reuse current header/menu primitives.

Workspace selector dropdown

Example:

✓ ClickHouse Operations
  Customer Analytics
  Production Debugging
  QA Investigations
────────────────────────
  New workspace…
  Manage workspaces…

Requirements:

  • Current workspace is visibly marked.
  • Selecting another workspace updates the ws URL parameter.
  • Preserve current Dashboard surface/mode:
/sql?ws=a&surface=dashboard&mode=view
-> /sql?ws=b&surface=dashboard&mode=view
  • From the Workbench surface, switch to the target Workbench:
/sql?ws=a -> /sql?ws=b
  • Update the last-used workspace only after the target resolves successfully.
  • For a modest list, use the normal menu. If the list exceeds a reasonable threshold (approximately 8-10), provide search/filter rather than an unbounded menu.
  • Keyboard navigation, focus restoration, Escape, and outside-click behavior must match existing menu accessibility.

Dirty-draft switching policy

Editor tabs are runtime session state and must not leak across workspaces.

When switching away from a workspace:

No dirty/unsaved tabs

Switch immediately.

Dirty or unsaved tabs exist

Show a confirmation dialog with exactly these outcomes:

  • Stay: cancel navigation and preserve all state.
  • Discard and switch: discard the current workspace's runtime tab drafts and navigate in the same tab.
  • Open target workspace in new tab: leave the current tab untouched and open the selected workspace URL in a new browser tab.

Do not silently carry tabs or savedId bindings into the target workspace.

The dialog should summarize the number of affected tabs. It need not provide per-tab save controls in the first version.

New workspace flow

The selector and File menu may both invoke the same command, but there must be one implementation.

Dialog fields:

Behavior:

  • Validate key syntax and uniqueness before commit.
  • On success, navigate to /sql?ws=<new-key> in the current tab.
  • Initialize an empty query collection and no dashboard.
  • If current tabs are dirty, apply the same confirmation policy as workspace switching before creating/navigating.

Manage Workspaces dialog

Provide a dedicated management surface listing all local workspaces.

Each row shows:

  • display name;
  • immutable key;
  • query count;
  • Dashboard or No dashboard status;
  • actions: Rename, Export, Delete.

Example:

ClickHouse Operations
clickhouse_operations
14 queries · Dashboard
[Rename] [Export] [Delete]

Requirements:

  • Sort by last time opened/saved
  • Clearly mark the active workspace.
  • Keep the dialog usable for long lists (scrolling and/or search).
  • Actions operate on the row's workspace, not implicitly on the active one.

Rename behavior

Rename changes only the display name.

  • Never change id or key.
  • Existing bookmarks remain valid.
  • Empty/whitespace-only names are rejected.
  • On success update the selector and header immediately.
  • Renaming another workspace must not switch to it.

The existing click-to-rename title behavior may be retained or replaced, but there should be one rename command and consistent validation.

Delete behavior

Deletion is permanent; there is no trash.

Confirmation dialog:

Delete “ClickHouse Operations”?

This permanently removes:
- 14 saved queries
- 1 dashboard

Require typing the immutable workspace key to enable deletion. This is justified because deletion is unrecoverable.

Post-delete behavior:

Deleting a non-active workspace

  • Close/return to management list.
  • Active workspace and URL are unchanged.

Deleting the active workspace

  • If other workspaces exist, choose the deterministic first workspace sorted by display name/key and navigate with history.replaceState() so Back does not reopen the deleted workspace.
  • If no workspace remains, create a default workspace and replace the URL with its key.
  • Clear/update last-used preference.

Other browser tabs

A tab later observing that its addressed workspace was deleted must show Workspace not found. It must not silently substitute another workspace.

If dirty drafts exist in the active workspace being deleted, the delete confirmation itself is sufficient warning; deletion discards them after the typed-key confirmation.

Import/export semantics

Import workspace…

  • Read and validate a portable workspace bundle.
  • Create a new local workspace; never replace the active workspace.
  • Remint local workspace identity.
  • Prompt for/derive a unique key when the imported name/key conflicts.
  • After successful import, navigate to the imported workspace.
  • Apply dirty-draft switching confirmation before leaving the current workspace.

Export workspace…

  • Export the selected/current workspace as the existing portable bundle format.
  • From Manage Workspaces, export the row's workspace without switching to it.

Import queries…

  • Import queries into the active workspace only.
  • Existing conflict-resolution behavior remains applicable.

File menu rework

The File menu should no longer use Open workspace… for destructive replacement. In a multi-workspace product, “open workspace” means selecting a local workspace from the header.

Target File menu:

New workspace…
Import workspace…
Export workspace…
Import queries…
────────────────────
Download Markdown
Download SQL
────────────────────
Variable history
  Remember recent variable values
  Clear all recent values

Requirements:

  • Rename Open workspace… to Import workspace… and change semantics from replace-active to create-new.
  • Remove destructive whole-workspace replacement from the primary UX.
  • Reuse the same New workspace command as the header selector.
  • Preserve existing Markdown/SQL download and variable-history behavior.
  • Keep dashboard navigation out of the File menu; surface switching belongs in the header.
  • Dashboard-specific import/export should be reconsidered under the one-dashboard-per-workspace model; no separate Dashboard file menu is required by this issue unless an existing operation remains independently useful.

Workspace-not-found management

The Workspace not found state from #407 should offer:

  • open workspace selector;
  • create new workspace;
  • navigate to an existing workspace.

It must not create or select a replacement automatically for an explicit missing ws URL.

Accessibility and responsive behavior

  • Workspace dropdown has an accessible name containing the current workspace name.
  • Current item uses semantic checked/selected state where supported.
  • All dialogs trap focus and restore it on close.
  • Destructive action is visually and semantically distinguished.
  • Header controls remain usable on narrow screens; labels may collapse but accessible names remain.
  • Do not implement hover-dependent nested submenus.

Tests

Add unit/UI/integration coverage for at least:

  1. Selector lists multiple workspaces alphabetically and marks current.
  2. Selecting a workspace updates URL and last-used preference.
  3. Dashboard surface and view mode are preserved while switching.
  4. Clean workspace switch happens immediately.
  5. Dirty switch supports Stay, Discard and switch, and Open in new tab.
  6. Runtime tabs and saved bindings do not carry into another workspace.
  7. New workspace validates name/key, creates, and navigates.
  8. Rename changes name only and preserves URL key.
  9. Manage dialog summaries show correct query/dashboard counts.
  10. Delete non-active workspace leaves current workspace unchanged.
  11. Delete active workspace replaces URL with deterministic fallback.
  12. Delete last workspace creates a default workspace.
  13. Typed-key confirmation gates permanent deletion.
  14. Import workspace creates a new workspace instead of replacing active.
  15. Import key conflicts are resolved explicitly.
  16. Export from a non-active row does not switch workspace.
  17. File menu contains the settled operation names/order and preserves downloads/history.
  18. Explicit missing workspace state offers selection/creation without silent fallback.

Acceptance criteria

  • Users can switch among multiple local workspaces from the header.
  • Users can create, rename, export, and permanently delete workspaces.
  • Dirty drafts are never silently moved or discarded during switching.
  • Workspace switching preserves Dashboard surface/view mode where applicable.
  • The File menu no longer conflates local workspace selection with file import.
  • Import workspace… creates a new workspace.
  • Active-workspace deletion has deterministic, bookmark-safe navigation behavior.

Non-goals

  • Slack-style nested workspace menus.
  • Trash/recovery.
  • Editable keys after creation.
  • Workspace pinning, recents, grouping, or custom ordering.
  • Per-tab save workflow inside the switch confirmation.
  • Backend ACLs or shared remote workspaces.
  • Cross-tab live invalidation/conflict prevention; tracked separately.

Metadata

Metadata

Assignees

No one assigned

    Labels

    inboxFiled mid-task; not yet triaged into the roadmap

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions