Skip to content

feat: collapsible dynamic workarea - #3006

Draft
Volv-G wants to merge 2 commits into
masterfrom
feat/collapsible-dynamic-workarea
Draft

Volv-G wants to merge 2 commits into
masterfrom
feat/collapsible-dynamic-workarea

Conversation

@Volv-G

@Volv-G Volv-G commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

Intent

Give people a way to get the right-hand Dynamic Workarea out of the way when they want to focus on the chat, without losing anything they had open in it.

Current behavior

The workarea is always on screen. Even with nothing useful in it, it keeps its share of the row and the chat is capped at 760px. There is no way to hide it, and closing tabs to reclaim the space throws away the open views, their state and their live run connections.

What changes

A Hide/Show control in the project header, reachable by keyboard and labelled for screen readers, toggles the workarea.

  • Hidden means zero width. The chat fills the whole row, past the old 760px cap. Showing it again restores the previous split, clamped to the current viewport and dock widths.
  • Hidden does not mean unmounted. Tabs, the selected document, live pipeline-run providers, agent environments and tool bridges all stay registered. An agent target opened while hidden still becomes ready. Nothing disconnects, terminates or unregisters.
  • Hidden is inert. The pane is inert and visually hidden, focus moves out before it disappears, and host shortcuts go inactive. That now includes ReactFlow's own document-level Delete/Backspace, selection, multi-select, pan and zoom bindings, which are gated on the live keyboard-listening state instead of staying armed for an off-screen canvas. Selection, bindings and undo for the hidden canvas are untouched, and deletion works again as soon as the pane is shown. Programmatic agent mutations keep working while hidden.
  • Pipeline migration respects both visibility and consent. Workarea hosts now distinguish a selected tab from a selected and visible one. Collapsing clears only the latter, so an already-consented migration on the selected tab can finish while hidden instead of stalling on "Opening pipeline…". Background migration is opt-in and off by default, so unselected tabs keep upstream behaviour. A pipeline the user cancelled stays local even if consent is granted later from another tab — which also fixes an existing bug on master, where such a tab migrated as soon as you returned to it. A hidden, unconsented tab never portals a consent dialog and never uploads.
  • Reveal rules. Agent-initiated opens respect a manual collapse. Explicit human clicks on a resource, artifact, run or entity reveal the pane, and the reveal happens before the async open starts, so a collapse made after the click still wins.

Collapsed state is in-memory on the per-project store, so it resets on reload or re-navigation. Persisting it would mean a dock-persistence migration, which is deliberately out of scope here.

How to test

Assumes the normal frontend and backend are running.

  1. Open a Tangent project with the workarea showing. Click Hide workarea in the header (or reach it by keyboard and press Enter) — the workarea disappears and the chat expands to the full row width.
  2. Press Show workarea — the pane comes back at the width it had before, clamped to the current window.
  3. With a pipeline open in the workarea, select a node and hide the pane, then press Delete or Backspace — nothing is deleted and no canvas selection changes. Show the pane again and press Delete — the selected node is removed as usual.
  4. Ask an agent to open a pipeline or run while the workarea is hidden — the pane stays hidden, and the tab is live and ready the moment you show it.
  5. Click a resource, artifact or run in the chat or docks while hidden — the workarea reveals itself and opens that item.
  6. With at least two local (browser-stored) pipelines open as tabs and "Move pipelines I open… without asking" already ticked, confirm only the selected tab uploads; the other stays local until you select it.
  7. Click Cancel on the migration dialog for one pipeline, then grant consent from another pipeline's dialog — the cancelled pipeline stays local.

Checks actually run on this branch: tsc --noEmit passes, eslint on all changed/new files passes with 0 errors and 0 warnings, prettier --check is clean, and the full vitest suite passes (484/484 files, 5243 tests, 2 todo). Dependencies and the lockfile are unchanged.

The tests are deliberately a small behaviour-focused set rather than exhaustive: hide/show keeping your work, an agent's tab opening hidden without stealing focus, canvas Delete/Backspace ignored while hidden and working again once shown, programmatic deletion still available while hidden, only the selected tab finishing a consented migration, and a cancelled pipeline staying local when consent arrives elsewhere. Each of those was confirmed to fail when its fix is reverted.

Untested reveal paths: clicking a chat artifact (ProjectChatArea onOpenArtifact) and opening an asset (AssetsWindowContent) also reveal the pane, and neither has a test. The entity-click path in chat does (revealEntity).

Verification gap: the on-screen geometry (zero-width hidden pane, chat filling the row, restored split) has not been checked in a real browser. The repo's canvas e2e suite is disabled upstream (#2925) and the Tangent workspace route needs a live backend, so there was no safe way to drive it here. The layout tests assert classes and styles in jsdom, which does not compute real geometry. Worth a manual pass before this leaves draft.

Deferred review finding: useNarrowLayoutDock still budgets MIN_WORKAREA_WIDTH through NARROW_LAYOUT_WIDTH while the workarea is collapsed, so the left dock auto-collapses a bit earlier than it needs to. It is a dock-sizing heuristic outside the collapse contract and changing it would also shift behaviour for the normal expanded layout, so it is left as a follow-up.

Related Issue and Pull requests

Touches the ReactFlow keyboard area referenced by #2925 (disabled canvas e2e suite). Unrelated to #2387103.

Type of Change

  • New feature
  • Bug fix

Line Breakdown

Category Added Removed
Production code 118 20
Comments 12 0
Tests 421 8
Total 551 28

Checklist

  • I have tested this does not break current pipelines / runs functionality
  • I have tested the changes on staging

Additional Comments

AI-assisted: written and validated by an agent, then reviewed by a second independent agent, with the results above. The first review round found that background pipeline migration had been extended to every mounted-but-unselected tab, which would have uploaded a pipeline the user had explicitly cancelled once consent was given elsewhere; that is fixed here and covered by regression tests (confirmed to fail without the fix). A later pass cut the tests from ~1160 to ~420 lines, dropping assertions on classes, styles and store internals in favour of user-visible behaviour; that pass also found and fixed a FlowCanvas test that batched keyDown/keyUp in one act(), which had made its hidden-canvas assertions pass regardless of the keyboard gating. Browser geometry and staging remain unverified, so this stays a draft.

Add an always-reachable Hide/Show control for the right-hand Dynamic
Workarea. A hidden workarea takes zero width so the chat fills the row,
and showing it restores the previous split clamped to the viewport.

Hiding keeps the workarea mounted: tabs, selected documents, live
pipeline-run providers, agent environments and tool bridges all stay
registered, and new hidden agent targets still become ready. Hidden
tabs are inert and their host shortcuts are inactive, including
ReactFlow's own document-level Delete/Backspace, selection,
multi-select, pan and zoom bindings, which are now gated on the live
keyboard listening state instead of staying armed off-screen.

Workarea hosts now distinguish a selected tab from a selected and
visible one. Collapsing clears only the latter, so an already-consented
pipeline migration on the selected tab can finish while hidden, while
unselected tabs keep upstream behaviour. Background migration is opt-in
and off by default, and a migration the user cancelled stays local even
if consent arrives later from another tab.

Agent-initiated opens respect a manual collapse; explicit human clicks
on a resource, artifact, run or entity reveal the pane, and the reveal
happens before the async open starts so a newer manual collapse wins.
@github-actions

github-actions Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

🎩 Preview

A preview build has been created at: feat/collapsible-dynamic-workarea/d57a902

Cut the test diff from ~1160 to ~420 lines. Drop assertions on classes,
inline styles, inert/display attributes, store internals and prop
plumbing, along with the heavy editor mock scaffolding they needed, and
keep tests that describe what a person does: hide and show the pane,
canvas keys while hidden, migration of the selected tab only, and a
cancelled pipeline staying local.

Migration coverage moves into the existing LocalPipelineMigration and
pipelineKind harnesses instead of standing up the whole embedded editor.

Fix a FlowCanvas test that batched keyDown and keyUp in one act(), which
collapsed React Flow's key state in a single render and stopped the
delete effect from ever running; the hidden-canvas assertions were
passing regardless of the keyboard gating. Split the events so the test
fails when the gating is removed.

No production code changes.

act(() => {
localStorage.setItem(consentKey, "true");
window.dispatchEvent(new StorageEvent("storage", { key: consentKey }));

This branch has not been deployed

No deployments
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