Skip to content

Split FrameSettings.tsx, and make its surface gating a reviewable table - #473

Open
mariusandra wants to merge 1 commit into
mainfrom
split-frame-settings
Open

Split FrameSettings.tsx, and make its surface gating a reviewable table#473
mariusandra wants to merge 1 commit into
mainfrom
split-frame-settings

Conversation

@mariusandra

Copy link
Copy Markdown
Collaborator

frontend/src/scenes/frame/panels/FrameSettings/FrameSettings.tsx was one
4,297-line component. Its surface gating was forty nested ternaries over
cloudProfile, esp32CloudProfile, inFrameAdminMode and hideForCloud,
spread over two thousand lines between where a flag was derived and where it
was used. docs/review-todo.md listed the split as a larger task because that
gating "cannot be reviewed by hand, which is how a cloud-only finding survived
the first pass".

The drift it was hiding

Commit 97c8c750 wrapped a long stretch of the JSX in {!cloudProfile ? … }
and swept the cloud's SSH keys section inside it. cloudProfile === hideForCloud, so {hideForCloud && !esp32CloudProfile ? …} nested in that
branch is dead code: for a release, a cloud-managed Linux frame rendered no SSH
keys section at all, while allowedFrameSettingsSections.cloud kept offering a
nav link to its anchor. This PR restores it and adds tests for both directions.

The gate is now a table

frameSettingsSurface.ts lists every section the panel can render, with:

  • surfaces — which of the four surfaces render it,
  • nav — which surfaces link it from the settings sub-navigation (defaults to
    surfaces; [] requires a written navNote saying why not),
  • conditions — prose for the per-frame and per-firmware conditions that stay
    in the component (which panel is attached, what version the device reported).

The panel resolves to one of four surfaces rather than three planes:
backend, frameAdmin, cloudLinux, cloudEsp32 — because a cloud ESP32
accepts a strictly narrower set_settings set than a cloud Pi, and
set_settings refuses the whole push on the first key the device does not
know.

<FrameSettingsSection sectionKey="…"> is the only gate: it renders nothing
when the table does not list the current surface, and throws on an unknown key.
No section tests the mode for itself.

Tests

cloud/apps/auth-web/src/test/shared-spa/frame-settings-surface.test.ts (new,
20 cases) pins the table against allowedFrameSettingsSections in
workspaceSurfaces.ts in both directions — every nav link points at a section
that mode renders, and every linkable section a mode renders has a nav link —
plus the table's own well-formedness and the surface rules the SSH-keys and
Power sections turn on. The existing panel test gains the two SSH-keys cases.

The split

file lines what
FrameSettings.tsx 200 the list of sections and their keys
frameSettingsSurface.ts 393 the gating table
frameSettingsContext.tsx 588 every derived value, computed once
esp32Hardware.ts 674 board tables and normalisers (pure)
fields/sharedFields.tsx 509 the field blocks cloud and self-hosted share
sections/*.tsx 83–687 account, cloud, device, connectivity, system
FrameActionsMenu.tsx 168 the "…" dropdown

Two small cleanups came with it: the panel no longer mounts settingsLogic for
a value it never read, and CloudSettingsSection now goes through the table
rather than a bare inFrameAdminMode test.

Verification

Beyond the suites: the panel was rendered for thirteen frame/surface
combinations (rpios, buildroot, embedded ESP32, virtual, TLS on, admin auth on,
mounts, QR + reboot, silent-retry errors, a store scene, frameAdmin, cloud
Linux, cloud ESP32) on main and on this branch, and the HTML diffed. The only
difference across all thirteen is the restored SSH-keys section — everything
else is byte-identical.

tsc --noEmit clean, prettier clean, node build.mjs builds, and all 712
shared-SPA tests pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Qunf3ap3xUWL5iYZA4ZopM

The per-frame Settings panel was one 4,297-line component whose surface
gating was forty nested ternaries over `cloudProfile`, `esp32CloudProfile`,
`inFrameAdminMode` and `hideForCloud`. It could not be reviewed by hand,
and it had drifted: commit 97c8c75 wrapped a long stretch of JSX in
`{!cloudProfile ? …}` and swept the cloud's "SSH keys" section inside it,
so the settings nav offered a link to an anchor no cloud frame rendered,
and a cloud Linux frame's SD-card keys could not be edited at all.

`frameSettingsSurface.ts` is now the panel's only surface gate: a table of
every section with the surfaces that render it, the surfaces whose nav
links it (with a written reason wherever a section opts out), and the
per-frame conditions each section still decides for itself.
`<FrameSettingsSection>` refuses to render a section the table does not
list for the current surface, so nothing can appear on a plane by
accident. The panel resolves to one of four surfaces — backend,
frameAdmin, cloudLinux, cloudEsp32 — because a cloud ESP32 accepts a
strictly narrower `set_settings` set than a cloud Pi.

frame-settings-surface.test.ts pins that table against
`allowedFrameSettingsSections` in workspaceSurfaces.ts in both directions,
so a nav link can no longer point at a heading the panel does not draw.
The panel test gains the two SSH-keys cases.

The file splits into: the ESP32 board tables (esp32Hardware.ts, pure data),
the derived-values context (frameSettingsContext.tsx), the field blocks the
cloud and self-hosted surfaces share (fields/sharedFields.tsx), the actions
dropdown, and six section modules. FrameSettings.tsx is now the list of
sections and their keys.

Verified by rendering all thirteen frame/surface combinations before and
after and diffing the HTML: byte-identical everywhere except the restored
SSH-keys section.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qunf3ap3xUWL5iYZA4ZopM
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