feat(maestro): multi-view web UI — splits, tabs, drag-dock, highlights
ci / rust (push) Successful in 5m46s

Render the content pane as tabs of nested split trees, each session leaf a live
attach mounted through the multi-mount pool:
- #30 arbitrarily-nested H/V splits with mouse-resizable dividers; per-pane
  ⏻/▥/▤/✕ tools; closing a pane collapses its parent split.
- #31 tabs, each holding its own tree; add / switch / close.
- #32 drag-to-dock: drag a pane title or a sidebar session onto a pane for a
  5-zone dock (edges split, centre swaps/replaces); a sidebar drag moves an
  already-open session.
- #33 focused pane at full strength, others dim; sidebar shows focused (loud)
  vs open-elsewhere (quiet) with a stable per-session colour mapping rows to
  panes.

Opening a session fills the focused pane (single-pane parity by default);
multi-pane is opt-in via split / drag / tabs. Panes auto-close when their
session ends (guarded against eviction and intentional close). The steady
"connected" label is hidden as noise.

Closes #30, #31, #32, #33. Part of epic #37.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 09:20:57 +00:00
co-authored by Claude Opus 4.8
parent 5a7e3c1b09
commit 159b7ecd6e
8 changed files with 1100 additions and 78 deletions
+7
View File
@@ -30,6 +30,10 @@ export interface AttachConnection {
export interface AttachOptions {
/** Invoked when the user clicks the view's explicit "disconnect" control. */
onRequestClose?: (sessionId: Uuid) => void;
/** Invoked when the socket closes on its own — the session ended or the link
* dropped — but NOT on an intentional `dispose()` (eviction / user close). The
* shell uses this to auto-close the pane rather than leave a dead one. */
onClosed?: (sessionId: Uuid) => void;
}
/** What the header shows about the session (name / command / host). Optional —
@@ -242,6 +246,9 @@ export function createAttachConnection(
ws.onclose = (ev) => {
setState(`closed (${ev.code})`, "closed");
// Only bubble up server/network closes — an intentional dispose has already
// set `disposed`, and eviction/user-close handle their own pane teardown.
if (!disposed) opts.onClosed?.(sessionId);
};
// PTY input: every keystroke goes out as a binary frame. A pending key-bar