You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Coordinate with: #427, which renames the lower Queries projection to Library and filters out Dashboard-owned queries.
Goal
Make the desktop left navigation foldable without adding collapse/expand buttons.
The user controls the navigation width by dragging its vertical frame border. A sufficiently narrow drag converts the current two-panel sidebar into a compact icon rail. Dragging the rail or its focused drawer wider converts it back into the normal two-panel sidebar.
The compact state must remain fully navigable: clicking a rail icon opens that section as a docked, full-height focused drawer beside the rail. The drawer consumes layout width and pushes the SQL/Dashboard work surface inward; it must not float over or obscure the work surface.
Mobile already uses a different navigation model and is explicitly out of scope.
Desktop shell geometry
The application header owns the complete top row across the viewport.
Below the header, the horizontal shell is:
wide state
[two-panel sidebar] [main Query/Dashboard surface] [optional right inspector]
rail state, drawer closed
[rail] [main Query/Dashboard surface] [optional right inspector]
rail state, focused drawer open
[rail] [focused left drawer] [main Query/Dashboard surface] [optional right inspector]
The rail, sidebar, focused drawer, main surface and right inspector all begin below the header.
The left navigation must participate in normal layout. No left-navigation state uses an overlay or backdrop on desktop.
Two presentation states
Wide state
The compact rail is absent.
Show the established two stacked navigation panes:
upper pane
Databases | Dashboards
lower pane
Queries | History
uses the remaining vertical height below the header;
consumes normal layout width;
pushes the Query/Dashboard surface instead of covering it;
shows exactly one section;
contains that section's title, search and content;
does not repeat Databases | Dashboards or Queries/Library | History switcher buttons;
remains open after selecting a database, table, Dashboard, query or history item;
retains the section's expansion, search and scroll state;
uses the same application navigation commands as the wide sidebar;
never executes hidden Dashboards merely because the Dashboards section is visible.
Clicking the active rail icon closes the focused drawer and leaves the rail visible.
Clicking a different rail icon switches the drawer content in place without first closing the drawer.
Escape may close the focused drawer when focus is inside it, but must not also cancel a running query or trigger another global Escape action.
Section-specific behaviour
Databases
Show the existing schema search and database/table/column tree with existing click, double-click, Shift-click, drag and documentation actions unchanged.
Dashboards
Show the Dashboard hierarchy from #426 with its search, expansion, keyboard and navigation semantics unchanged.
Queries / Library
Before #427, show the existing Queries collection.
After #427, show only the zero-owner Library projection and update the rail label/tooltip to Library. The foldable shell must not introduce a separate data projection or duplicate ownership logic.
History
Show the existing history search/list and opening behaviour unchanged.
Drag-controlled state transitions
Use the vertical navigation frame border as a resize separator.
The transition must feel deliberate and must not flicker near a single threshold. Use named constants and hysteresis rather than deriving state directly from every pointer pixel.
Recommended starting values, adjustable only through real-browser layout verification:
mode, wideWidthPx and focusedDrawerWidthPx are browser preferences;
focusedSection is session UI state and need not reopen automatically after reload;
none of this state belongs in StoredWorkspaceV3, Dashboard documents or query specs;
selected Databases/Dashboards and Queries/Library/History roles continue to use their existing UI-state ownership.
The persisted preference decoder must clamp invalid or obsolete values safely.
Shared navigation state
Wide and focused presentations are two views over the same navigation state.
Preserve across transitions:
schema search text;
schema database/table expansion;
loaded-column cache;
schema scroll position;
Dashboard search and expansion;
Dashboard keyboard/current-row state;
Queries/Library search and editing state where safe;
History search;
upper/lower split percentage;
current application surface and editor/result state.
Do not create separate competing expansion/search stores for wide and focused presentations.
A transition may move DOM focus to the corresponding control in the new presentation, but it must not silently reset the user's state.
Interaction with drag-and-drop assignment
The implementation must remain compatible with #428.
When a Library-query drag is active in rail mode:
the Dashboards rail icon can be exposed as a valid hover launcher;
bounded hover may open the docked Dashboards focused drawer;
the user can then drop on Dashboard, Panels or Filters targets;
leaving/cancelling the drag clears temporary hover state;
this must never turn the drawer into an overlay.
This integration may be completed by #428 if #428 has not yet landed, but the left-navigation API must provide a deterministic openFocusedSection('dashboards') seam.
Main-surface resizing
Every width or mode change must notify/reflow the active centre surface correctly:
CodeMirror/editor geometry;
result table and virtualised rows;
Query editor/results splitter;
Dashboard layout engines and charts;
sticky Dashboard/filter/toolbars;
optional right inspector.
Use existing resize observers/layout hooks rather than arbitrary delayed resize events.
Left and right docked panels may be open simultaneously. Clamp widths so the centre retains a documented minimum usable width.
Keyboard and accessibility
The vertical frame border is a keyboard-operable separator:
announce semantic mode changes through an appropriate live/status mechanism without excessive chatter.
Rail buttons must expose aria-expanded and aria-controls for the focused drawer.
Closing a focused drawer returns focus to its rail icon. Converting to wide mode restores focus to the corresponding section tab/search/tree when possible.
Mobile
At the existing mobile breakpoint:
do not render the desktop rail or desktop focused drawer;
retain the established mobile segmented and bottom navigation;
ignore desktop folding preferences for effective mobile layout;
preserve those preferences for the next desktop session.
Suggested code boundaries
App shell layout controller
Owns:
explicit wide/rail mode;
widths and thresholds;
vertical resize separator;
focused drawer host;
preference persistence;
centre-width clamping and resize notifications.
Navigation section registry
Maps rail sections to existing views and labels without duplicating their domain state.
Existing navigation views
Continue to own their tree/list rendering, search and application actions. They must not manipulate shell widths directly.
Tests
State and preferences
fresh desktop session starts from the documented default;
valid mode/width preferences restore;
invalid widths clamp safely;
left state is never written to workspace JSON;
mobile ignores desktop effective state while preserving preferences.
Wide state
rail is absent;
upper and lower panes render together;
switchers and horizontal splitter remain;
existing navigation behaviour is unchanged;
dragging left below the fold threshold enters rail mode once.
Rail state
rail starts below the full-width header;
exactly four section icons remain visible;
icons remain visible while a drawer is open;
active icon is marked;
clicking active icon closes the drawer;
clicking another icon switches content;
rail never expands to drawer width.
Focused drawer
drawer is docked and reduces centre width;
no overlay/backdrop is created;
no redundant role switchers render inside it;
selected resources do not auto-close it;
search/expansion/scroll state survives section and mode changes;
Escape and focus restoration are correct.
Drag transitions
wide -> rail uses hysteresis without oscillation;
rail -> wide restores the prior width;
focused drawer can fold closed or expand to wide;
pointer cancellation and window blur terminate drag safely;
keyboard separator operations match pointer transitions.
Reflow and regressions
editor, results and Dashboard resize correctly;
a running query is not cancelled by folding navigation;
Query/Dashboard surface state is preserved;
right inspector can coexist;
database tree and Dashboard tree gestures are unchanged;
Depends on: #425, #426
Coordinate with: #427, which renames the lower
Queriesprojection toLibraryand filters out Dashboard-owned queries.Goal
Make the desktop left navigation foldable without adding collapse/expand buttons.
The user controls the navigation width by dragging its vertical frame border. A sufficiently narrow drag converts the current two-panel sidebar into a compact icon rail. Dragging the rail or its focused drawer wider converts it back into the normal two-panel sidebar.
The compact state must remain fully navigable: clicking a rail icon opens that section as a docked, full-height focused drawer beside the rail. The drawer consumes layout width and pushes the SQL/Dashboard work surface inward; it must not float over or obscure the work surface.
Mobile already uses a different navigation model and is explicitly out of scope.
Desktop shell geometry
The application header owns the complete top row across the viewport.
Below the header, the horizontal shell is:
The rail, sidebar, focused drawer, main surface and right inspector all begin below the header.
The left navigation must participate in normal layout. No left-navigation state uses an overlay or backdrop on desktop.
Two presentation states
Wide state
The compact rail is absent.
Show the established two stacked navigation panes:
After #427, the lower pane becomes:
Requirements:
>|<buttons for folding the left navigation.Rail state
Show a narrow vertical rail below the header.
Recommended visual width:
The rail contains four section launchers:
Open Databases navigationOpen Dashboards navigationOpen Queries navigationbefore #427,Open Library navigationafter #427Open query HistoryRequirements:
Focused drawer behaviour
Clicking a rail section opens that section as a docked drawer immediately to the right of the rail.
Examples:
The focused drawer:
Databases | DashboardsorQueries/Library | Historyswitcher buttons;Clicking the active rail icon closes the focused drawer and leaves the rail visible.
Clicking a different rail icon switches the drawer content in place without first closing the drawer.
Escape may close the focused drawer when focus is inside it, but must not also cancel a running query or trigger another global Escape action.
Section-specific behaviour
Databases
Show the existing schema search and database/table/column tree with existing click, double-click, Shift-click, drag and documentation actions unchanged.
Dashboards
Show the Dashboard hierarchy from #426 with its search, expansion, keyboard and navigation semantics unchanged.
Queries / Library
Before #427, show the existing Queries collection.
After #427, show only the zero-owner Library projection and update the rail label/tooltip to Library. The foldable shell must not introduce a separate data projection or duplicate ownership logic.
History
Show the existing history search/list and opening behaviour unchanged.
Drag-controlled state transitions
Use the vertical navigation frame border as a resize separator.
The transition must feel deliberate and must not flicker near a single threshold. Use named constants and hysteresis rather than deriving state directly from every pointer pixel.
Recommended starting values, adjustable only through real-browser layout verification:
Wide -> rail
While dragging the wide sidebar border left:
Rail -> wide
While dragging the rail's right frame border to the right:
Focused drawer resize
When a focused drawer is open, its right border is the active navigation resize separator.
Do not rely on CSS width alone to decide the semantic mode after every repaint. The mode is explicit application-shell state.
Layout state
Suggested shell state:
Persistence:
mode,wideWidthPxandfocusedDrawerWidthPxare browser preferences;focusedSectionis session UI state and need not reopen automatically after reload;StoredWorkspaceV3, Dashboard documents or query specs;The persisted preference decoder must clamp invalid or obsolete values safely.
Shared navigation state
Wide and focused presentations are two views over the same navigation state.
Preserve across transitions:
Do not create separate competing expansion/search stores for wide and focused presentations.
A transition may move DOM focus to the corresponding control in the new presentation, but it must not silently reset the user's state.
Interaction with drag-and-drop assignment
The implementation must remain compatible with #428.
When a Library-query drag is active in rail mode:
This integration may be completed by #428 if #428 has not yet landed, but the left-navigation API must provide a deterministic
openFocusedSection('dashboards')seam.Main-surface resizing
Every width or mode change must notify/reflow the active centre surface correctly:
Use existing resize observers/layout hooks rather than arbitrary delayed resize events.
Left and right docked panels may be open simultaneously. Clamp widths so the centre retains a documented minimum usable width.
Keyboard and accessibility
The vertical frame border is a keyboard-operable separator:
Keys:
Rail buttons must expose
aria-expandedandaria-controlsfor the focused drawer.Closing a focused drawer returns focus to its rail icon. Converting to wide mode restores focus to the corresponding section tab/search/tree when possible.
Mobile
At the existing mobile breakpoint:
Suggested code boundaries
App shell layout controller
Owns:
Navigation section registry
Maps rail sections to existing views and labels without duplicating their domain state.
Existing navigation views
Continue to own their tree/list rendering, search and application actions. They must not manipulate shell widths directly.
Tests
State and preferences
Wide state
Rail state
Focused drawer
Drag transitions
Reflow and regressions
Acceptance criteria
Non-goals