Skip to content

Say which device a settings section changes, and switch it right there - #1063

Merged
sak0a merged 2 commits into
mainfrom
port/settings-scope-sentence
Oct 31, 2026
Merged

sak0a merged 2 commits into
mainfrom
port/settings-scope-sentence

Conversation

@sak0a

@sak0a sak0a commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

What Changed

Built on #1062 ("Apply to all nodes", merged).

  • Node sections now start with Changes apply to [Studio ▾] instead of the small device label above the title.
  • The device in the sentence is a menu. It is the nav header's own device menu: one SettingsNodeMenu with one list (useSettingsNodeMenu). Both places show the same devices, apply the same rule for which ones a hosted browser may open, and switch through the same handler. The page no longer builds its own list.
  • In hosted mode, picking a device moves the selection cursor, as the nav header always did. It never opens a second write target.
  • A device that is not reachable shows Offline or Connecting, in the menu and in the sentence. It uses the facts the "isn't connected" empty state uses: directory or Hub machine presence, a connection underway, and whether the machine record allows connecting.
  • More than six devices get a search field (T3 Code's threshold). That list is its own chunk and loads only when needed; until it has loaded, and if it never does, the plain menu works.
  • With two or more nodes known, sections that have "Apply to all nodes" rows add a muted "· rows marked Mixed differ on other nodes".
  • This app's sections, and sections whose scope is browser or device, keep their one-line label. The frozen web phone tier (PhoneSettingsSurface) is untouched.
  • docs/settings-ownership.md describes the sentence.

Why

The device a section changes was a small grey label, and switching it meant finding the icon button at the bottom of the nav. With "Apply to all nodes" and "Mixed" on the same page, it matters to see which device you are editing, and to switch it where you read it. The page keeps one device list and one switch, so the two menus can never disagree.

Security note for review: the sentence is display plus the existing switch. Its menu takes its choices, its disabled rule and its handler from the same hook as the nav header, and the handler also refuses a device that is not in that list or that the list marks unavailable. So the scope menu can never pick a node the nav would not offer.

Validation

  • bun run check and bun run check:changed on 91125b136: everything passed except the same 5 server tests that fail on origin/main (ProjectionPipeline.followUpQueue.test.ts, 026_CanonicalizeModelSelectionOptions.test.ts; no server code here), and one markdown fuzz test that timed out under load and passes alone. The searchable list uses preloadableLazy, as webBundleSplitting.test.ts requires.
  • Tests that fail without the change:
    • SettingsPage.test.ts: the sentence is chosen by destination and section scope (node sections yes; client, browser and device sections no); the Mixed clause only on sections with fan-out rows; the Offline / Connecting rule.
    • SettingsPageHosted.browser.tsx: a node section shows "Changes apply to" with a menu named after the device; picking Travel laptop moves the selection cursor, the sentence and the section description follow, and the section mounts again for the new node; the menu disables a node while the browser is not current, exactly as the nav does, and labels an offline node "Offline"; above six devices the list is searchable and picks through the cursor; Appearance shows no sentence. Checked against the S3 SettingsPage.tsx: the three positive cases fail.
  • Existing tests still pass: the four earlier hosted cases (nav header "Settings device" menu), SettingsPageSearchReveal, PhoneSettingsSurface.
  • Web bundle against an origin/main build (95e814c): boot 523.5 KiB gzip both (unchanged), RootAppShell 398.0 → 397.5 KiB, settings route 186.9 → 192.7 KiB (S3 alone: 190.9). The searchable list (combobox and its vendor code, about 15 KiB) is its own chunk, loaded only above six devices.
  • Rebased after Switch a saved machine off without removing it, and keep it off #1036: the device list leaves switched-off machines out, as the page's own list did.
  • Not verified: a desktop build with Hub machines in several states, and hosted mode against a real Hub.

Review

An independent review checked that the sentence's menu and the nav header share one hook (same choices, same hosted gate). It also checked that hosted mode only moves the selection cursor and never adopts or reconnects a session itself, that offline or connecting devices cannot be written, the lazy search list, and the frozen phone tier (no diff). Fixed after it:

  • With more than six devices, the switch-device button did nothing until the search list's chunk arrived. A failed load threw to the root error view, taking Settings down with its only way to switch device. Now the plain menu works until the search field has loaded and stays if it never does. SettingsNodeMenu.browser.tsx makes the load fail and still switches device; it fails without the fix.

Left as they are (low):

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Oct 31, 2026
@sak0a
sak0a force-pushed the port/settings-scope-sentence branch from 0eae471 to 33d12d7 Compare October 31, 2026 09:51
@sak0a
sak0a force-pushed the port/settings-apply-to-all-nodes branch from 31b9854 to 05dc55d Compare October 31, 2026 12:45
@sak0a
sak0a force-pushed the port/settings-scope-sentence branch from 33d12d7 to 4143cd0 Compare October 31, 2026 12:56
@sak0a
sak0a changed the base branch from port/settings-apply-to-all-nodes to main October 31, 2026 12:56
@github-actions github-actions Bot added size:XXL and removed size:XL labels Oct 31, 2026
sak0a and others added 2 commits October 31, 2026 15:11
- Node sections now start with "Changes apply to [Studio]". The device is a
  menu: the nav header's own device menu, with the same devices, the same rule
  for which ones a hosted browser may open, and the same switch. In hosted mode
  it moves the selection cursor, as before; it never opens a second target.
- A device that is not reachable shows "Offline" or "Connecting", in the menu
  and in the sentence.
- More than six devices get a search field. That list loads only when needed.
- With two or more nodes known, sections with "Apply to all nodes" rows add
  "rows marked Mixed differ on other nodes".
- This app's sections, and browser or device sections, keep their one-line
  label. The web phone tier is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n it never does

Review fix: with more than six devices, the switch-device button opened nothing
until the search list's chunk arrived, and a failed load threw to the root error
view, taking Settings down with its only way to switch device.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sak0a
sak0a force-pushed the port/settings-scope-sentence branch from 4143cd0 to efa02dd Compare October 31, 2026 14:11
@github-actions github-actions Bot added size:XL and removed size:XXL labels Oct 31, 2026
@sak0a
sak0a merged commit c600d44 into main Oct 31, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant