Skip to content

feat: collapsible dynamic workarea - #3006

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

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

Conversation

@Volv-G

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

Copy link
Copy Markdown
Collaborator

Intent

Let people fold the right-hand Dynamic Workarea away when they want to focus on the chat, using the same gestures as the left dock, and 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 stays capped at 760px. The left dock can be collapsed by dragging or double-clicking its edge, but the workarea can't be collapsed at all.

What changes

The workarea collapses and expands the way the left dock does.

  • Collapse: drag the chat/workarea divider toward the right edge. About 20px past the point where the divider stops, the same snap preview the dock uses appears, and releasing collapses the workarea. Double-clicking the divider collapses it straight away. The snap point is measured from wherever the divider actually stops (the chat's 760px maximum or the workarea's minimum, whichever binds first), so wide screens have no stretch of drag where nothing happens. The 20px give is a constant shared with the dock.
  • Collapsed: the workarea becomes a 36px rail with the same width and styling as the collapsed dock. It holds a "Show workarea" button and one icon per open tab, and each icon reopens the workarea on that tab. The chat fills the rest of the row, past the old 760px cap.
  • Expand: double-click the rail's edge or drag it outward, as with the dock. Reopening restores the previous split, clamped to the current window.
  • Collapsed does not mean unmounted. This is the one deliberate difference from the dock, which unmounts its windows. Tabs, the selected document, live pipeline-run providers, agent environments and tool bridges all stay registered, and an agent target opened while collapsed still becomes ready. The hidden content is inert and visually hidden. When collapsing strands focus inside it, focus moves to the rail.
  • Canvas shortcuts are off while collapsed. That includes React Flow'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 for an off-screen canvas. Programmatic agent edits keep working while collapsed.
  • Pipeline migration respects visibility and consent. Workarea hosts now tell a selected tab apart from a selected and visible one. Collapsing clears only the second, so an already-consented migration on the selected tab can finish while collapsed instead of stalling on "Opening pipeline…". Background migration is opt-in and off by default, so unselected tabs keep the behaviour on master. A pipeline the user cancelled stays local even if consent is granted later from another tab. This also fixes an existing bug on master, where such a tab migrated as soon as you returned to it. A collapsed, unconsented tab never shows 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 reopen the workarea, and the reveal happens before the async open starts, so a collapse made after the click still wins.
  • Narrow windows: while the workarea is collapsed, the heuristic that auto-collapses the left dock on narrow windows only budgets for the 36px rail, not the workarea's full minimum width.

Collapsed state lives in memory on the per-project store, so it resets on reload. The dock remembers its state, but persisting the workarea's would need a dock-persistence change, which is out of scope here.

How to test

Tophat: https://oasis-staging.shopify.io/tangent?tophat_location=feat%2Fcollapsible-dynamic-workarea%2Fed3df33 (build of ed3df33)

Assumes the normal frontend and backend are running.

  1. Open a Tangent project with something in the workarea. Drag the divider between chat and workarea all the way right. Expected: the snap preview appears just after the divider stops, and on release the workarea collapses to a 36px rail with the chat filling the row. Try it on a wide monitor as well as a laptop screen.
  2. Double-click the rail's edge. Expected: the workarea reopens at its previous width.
  3. Double-click the divider. Expected: the workarea collapses immediately.
  4. With two tabs open, collapse, then click the rail icon for the tab that wasn't selected. Expected: the workarea reopens on that tab, with the work you left there intact.
  5. With a pipeline open, select a node, collapse the workarea, then press Delete or Backspace. Expected: nothing is deleted. Reopen, press Delete again. Expected: the node is removed.
  6. Ask an agent to open a pipeline or run while collapsed. Expected: the workarea stays collapsed and a new icon appears on the rail. The tab is live when you reopen.
  7. Click a resource, artifact or run in the chat or the docks while collapsed. Expected: the workarea reopens on that item.
  8. On a window narrower than about 1020px, collapse the workarea. Expected: the left dock may spring open, because there's now room for it. Reopening the workarea collapses the dock again. Please judge whether two panels moving at once feels right.

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 (486/486 files, 5250 tests, 2 todo). Dependencies and the lockfile are unchanged.

The tests are a small behaviour-focused set: the divider's double-click and drag-past-the-stop collapse, and a shorter drag only resizes; the snap point on 1512/1920/2560px rows; the rail's double-click reopening; collapse keeping your work and a rail icon reopening on its tab; an agent tab opening while collapsed without reopening the workarea or taking focus; canvas Delete/Backspace ignored while collapsed and working again once reopened; programmatic deletion still available while collapsed; only the selected tab finishing a consented migration; a cancelled pipeline staying local; and the narrow-window dock budget. Each was confirmed to fail when its fix is reverted.

Verification gaps:

  • The on-screen geometry and the drag feel have not been checked in a real browser. jsdom has no layout, so the tests drive the gestures with synthetic mouse events and assert the outcome, not the pixels. The tophat is the real check.
  • There's no keyboard way to collapse the workarea. The left dock has none either. Reopening is keyboard-reachable through the rail's buttons.
  • Clicking a chat artifact (ProjectChatArea onOpenArtifact) and opening an asset (AssetsWindowContent) also reopen the workarea, and neither has a test.

Follow-ups:

  • The rail and the snap previews mirror the dock's markup. Moving both into a shared preview component would stop them drifting apart, but it touches DockArea, which the pipeline editor also uses, so it's left out of this PR.

Related Issue and Pull requests

Touches the React Flow keyboard area covered by #2925 (disabled canvas e2e suite).

Type of Change

  • New feature
  • Bug fix

Line Breakdown

Category Added Removed
Production code 268 33
Comments 30 0
Tests 500 6
Total 798 39

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 independent agents over several rounds, with the results above. The reviews caught and fixed:

  • background migration extended to every mounted unselected tab, which could have uploaded a pipeline the user had explicitly cancelled;
  • a FlowCanvas test that batched keyDown/keyUp in one act(), which made its collapsed-canvas assertions pass regardless of the keyboard gating;
  • a drag dead zone on wide screens, where the divider stopped but the workarea didn't snap shut until the pointer was within 400px of the edge.

An earlier version used a header toggle. It worked, but collapsing should match the left dock, so the toggle was replaced and the header is unchanged from master. Browser geometry and staging remain unverified, so this stays a draft.

@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/ed3df33

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.
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.
Replace the header toggle with the left dock's own gestures. Dragging
the chat/workarea divider 20px past where it stops snaps the workarea
shut, with the same snap preview, and double-clicking the divider
collapses it. Collapsed, the workarea becomes a 36px rail of its open
tabs, the counterpart of the dock's collapsed rail. Double-clicking or
dragging the rail's edge reopens the workarea, and each tab icon reopens
it on that tab.

The snap point is measured from wherever the divider actually stops (the
chat's maximum or the workarea's minimum), so wide screens no longer have
a stretch of drag where nothing happens. The 20px give is shared with the
dock.

Unlike the dock, the workarea keeps its content mounted while collapsed,
so live runs, migrations and agent targets keep working.

The narrow-window dock heuristic now budgets the 36px rail rather than
the workarea's minimum while the workarea is collapsed.

The project header returns to its state on master.
@Volv-G
Volv-G force-pushed the feat/collapsible-dynamic-workarea branch from 6a63c11 to d032e5e Compare November 6, 2026 18:11
@Volv-G
Volv-G marked this pull request as ready for review November 6, 2026 18:11
@Volv-G
Volv-G requested a review from a team as a code owner November 6, 2026 18:11

@camielvs camielvs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 This is an AI-generated code review comment.

9 findings, inline below (2 Medium, 7 Low). The two Medium ones are a narrow-window dock regression and a missing test for the no-consent background migration path.

Two notes that don't belong on a single line:

  • Rail markup copies DockArea. You already list merging them as a follow-up, and I agree. That's why the markup duplication in the rail and snap previews isn't flagged inline.
  • Snap feel on wide screens, for the tophat. On a 2560px row, dragging 20px past the 760px chat limit collapses a workarea about 1,400px wide. The preview warns first, and removing the dead zone was a deliberate choice, so this is a question, not a finding: does it trigger too easily when the workarea is far from its minimum width?

- Narrow-window dock: forget our own collapse as soon as the dock opens
  for any reason, so a dock the user reopened and then closed is never
  reopened by a workarea toggle or a resize.
- Test that a collapsed tab without consent never prompts, checks write
  access or uploads.
- Hide the collapsed workarea with the `hidden` attribute instead of an
  inline style, which also makes `inert` unnecessary.
- Test React Flow's key gating on FlowCanvas alone through
  `keyboard.listening`, and cover the collapse → inactive link in the
  workarea test.
- Share the rail's button and the tab-icon lookup, return `rowMeasured`
  from the chat width hook, rename the snap constant to
  DOCK_AREA_SNAP_OVERSHOOT, and drop comments that restated the code.

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.

2 participants