fix: member-machines UI round one — eleven annotated fixes - #107
Merged
Conversation
The strip's Files / teenyapps / Connections buttons duplicated the right icon strip (WorkspaceRailStrip), which owns those panels. The slot now holds a single Drive icon that navigates to the Drive page — the route the account menu's Drive entry used. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The rail's pinned action drew its own popover that looked like the tab strip's "+" menu but listed less: no live ports, no preview links. The menu now lives in one component, src/NewTabMenu.tsx, and both call sites render it with their own anchor. SessionTypeIcon moves to src/SessionTypeIcon.tsx so the shared menu needs no import back into WebAppHeader; WebAppHeader re-exports both, so its importers are unchanged. The pinned action reads "New tab". The "+" button behaves as before. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…igned PR #95 put Refresh in the filter row. It now sits in a footer row under the list, on the right edge, beside the selection count. Behaviour is unchanged: the same click still bumps the refresh version. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The strip's tiles were flat, so a two-letter code was the only thing telling them apart. src/shell/workspace-tile.ts hashes the workspace id to a hue, paints a 135° gradient to hue + 40°, and picks a near-white or near-black ink from the gradient's average luminance. Ids whose average lands in the band where neither ink clears 4.5:1 are darkened out of it; measured worst case over all 360 hues is 4.83:1. The active ring and the dashed create tile are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The strip's avatar drew a four-item popover. Drive is a strip icon since A2, Settings was one click away, and the name was a label. Clicking the avatar now navigates to settings. "Ask us on Discord" moves to the bottom of the settings side navigation, under the section tabs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dialog #106 built kept the three tabs the plan asks for and lost the look the pre-#106 one had. This puts the look back without touching what any control does: - the header says `Workspace details “name”` again; - every panel opens with the micro-caps section heading the old `workspace-details-grid` sections wore; - the member rows take the old access-list geometry (a 28px avatar, a 48px row) instead of the taller #106 one; - Clone and Delete leave the bottom of the Settings tab for the restored `workspace-details-footer`, which is where the old dialog kept Delete. Members, Credentials and Settings are the same three tabs, and every write behind them is untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every member machine has taken its own volume since #106, and there was no way to say a machine does not need one. The member row now carries the answer. Wire: `members[].persistentVolume` on the create request and the same optional boolean on `AddWorkspaceMemberRequest` and `ProvisionMemberMachineRequest`, in `wire.ts` and `packages/schema` together. Absent means true, so only a refusal travels. Control plane: the flag reaches `ProvisionMachineInput` and, at the ONE existing call site in `provisionMachine`, skips `provisionWorkspaceVolume` exactly as an explicit `volumeId` already does. No new volume path was written. Webapp: the toggle sits next to the machine-type select in every member row, in the create dialog's draft rows and in the live members editor. A row whose machine exists reports the disk it has, disabled — the disk is created with the machine and this is not the route that moves one. The workspace-level Volume section leaves the create dialog; `volumeId` stays on the wire, where a recreate still reads it. The test fake grew an optional `volumeLocation`, so a suite can turn on the volume placement the fake otherwise declines to do. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Inside the workspace-details dialog the role listbox, the machine-type listbox and the lifecycle menu all came out under their neighbours. The popover was `position: absolute`, so `.workspace-details-body` — which scrolls — was both the thing that clipped it and the thing it could not paint over. One rule in the shared stylesheet fixes all three: the popover is `position: fixed` with the top stacking position, so no scroll container between it and the page can clip it. `WebAppSelectMenu` writes `left` and one of `top`/`bottom` from the trigger's viewport rect, clamped to the viewport, flipping to whichever side has more room; it follows a scroll in any container above it. The one per-instance override of the popover's geometry (the mobile settings picker) is gone with it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The strip's tiles answered a left click and nothing else. A right click now opens the same context menu the tab strip serves: the chrome is `.webapp-session-menu`, positioned at the pointer and clamped to the viewport, closed by Escape or by a click outside. Three items, graded by §3: - Rename, which edits the name in a field the popover holds — the tile is two letters wide — and writes it with the PATCH the settings tab already uses; - Settings, which opens the details dialog on its Settings tab; - Invite, which opens it on Members with the add-member picker focused. There is no email invite here: adding somebody means adding an existing member of the organization. A member sees Settings alone. The left click is untouched, and a right click never selects the tile it opened on. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The rail header said what the workspace is and never what the member's own machine is. A third button opens that panel, wearing the box glyph `files/DriveIcons.tsx` has drawn since before #106. The dialog is the workspace-details chrome with no tab row: one view, because there is one machine to read. It names the state, the type and what the type is (vCPU, RAM, disk, price, all off the existing catalog helpers), whether a persistent volume is attached, and the machine's own error where it has one. The lifecycle controls carry the §3 matrix in the first person. Stop and start are a member's own business; recreate, destroy and the machine-type change are workspace-admin work, and provisioning where there is no machine row at all is the member-add route in disguise. A verb this member may not run is shown DISABLED and names who to ask — "Ask a workspace admin: Ada Owner" — because there is no request to file and pretending one was filed would be worse than saying who can act. A viewer holds no machine (§2.2) and is told so. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The rail drew its own three-node share glyph while the Drive page drew a person-with-a-plus for the same verb. The rail now imports the Drive page's `ShareGlyph`, so one shape means "share" across the app, and the strip's copy is deleted rather than left to drift — the rail was its only caller. The button still opens Members and nothing else changed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #106, from the user's DOM annotations on the live canary. Eleven fixes, one commit each.
Shell
Rail
Dialogs
Create
Gates: typecheck 0; lint at baseline (102/0, 7 max-lines); CP 633, actor 119, webapp 358, all pass.
🤖 Generated with Claude Code