Repository navigation
feat(admin): add a Configuration page to view and edit central-manager settings - #1988
Devin-Holland wants to merge 7 commits into
Conversation
…r settings A staff-only /admin/configuration page listing every Configuration key with its description and current value. Accounts holding config:write (fabric_admin, and the core super user) can edit a value as JSON: the editor rejects JSON that doesn't parse, warns when an edit changes the value's type, and shows a refused save inline. Keys central-manager marks superUserOnly (security controls such as the SSO session cap and host SSH keys) show a lock and can only be edited by the core super user. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…SON can't round-trip The editor no longer closes while a save is in flight, so a dismissed dialog can't drop the result; the list refresh and success toast now live on the mutation itself. Values containing a non-finite number (1e400) or an integer past 2^53 are refused instead of being saved as null or rounded, and a refused-save message clears once the value is edited. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… overwrite a newer value A save now re-reads the key and stops if it changed since the editor opened, since PATCH replaces the whole value. Failures go through the global toast, so a refused or unanswered save is still reported after navigating away. The editor locks while saving, deep nesting no longer throws during render, and a row with no value edits as null. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lue as null Drops the stack-dependent depth case to 1,000 (100,000 still catches both regressions), shows a row with no value as null in the table as the editor does, and trims comments that restated the code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request introduces a new Configuration section to the admin panel, allowing authorized staff and super users to view and edit central-manager settings with JSON validation and concurrency checks. It adds the /admin/configuration route, updates navigation visibility, and introduces new config:read and config:write permissions. The review feedback suggests improving the layout of the edit dialog by wrapping the title and description in a DialogHeader component, and adjusting the size and spacing of the LockIcon inside the "Super user" badge for better visual alignment.
Coverage Report
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
…page Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…page Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…logs Wrap the title and description in DialogHeader, as most Studio dialogs do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| const path = `/Admin/Configuration/${encodeURIComponent(name)}` as '/Admin/Configuration/{name}'; | ||
| // PATCH replaces the whole value with no precondition. Re-reading first catches an edit made while the | ||
| // editor was open; one landing between these two requests is still overwritten. | ||
| const { data } = await apiClient.get(path); |
There was a problem hiding this comment.
[major] A second admin's write between GET and PATCH is silently overwritten; enforce an atomic expected-value precondition in central-manager
There was a problem hiding this comment.
Thanks, agreed that only the server can close this fully. This PR leaves it open on purpose, though. It is the "client-side-precondition" decision under ⚖️ Alternatives: PATCH /Admin/Configuration/{name} takes no expected value, so Studio can only re-read before it writes. That catches any edit made while the dialog was open. The only gap left is the round trip between the GET and the PATCH.
Why it's not a blocker here:
- A handful of staff edit this table, and the gap is one request long.
- central-manager#1025 audits each edit with its before and after values (
Configuration.jspatch), so a lost write can be found and restored.
The real fix is a central-manager change: accept an optional expected value on PATCH and compare it in the same transaction as the write. Harper's transactions and record locks can support that, so the PR body's "no compare-and-set" means there is no built-in primitive, not that it can't be built. Once that lands, Studio only needs to pass expected through. I've noted this as a follow-up for central-manager instead of growing this PR.
— devain (Claude Opus 5.5)
⊙ Problem
Staff cannot see or change central-manager's Configuration table from Studio; it takes the core super user and a direct API call.
🤔 Is a JSON editor safe enough for staff?
Yes, because central-manager decides: HarperFast/central-manager#982 lets fabric_admin edit an allowlist of operational keys and refuses the rest. This page only hides the edits that would fail.
💡 Solution
⚖️ Alternatives
🤔 Should read-only staff get the page too?
Not in this PR. Every staff role holds
config:read, but the page exists to edit, so it is gated onconfig:write. Gating onconfig:readinstead is a one-line change if read-only staff should see values.🔧 Changes
src/features/admin/configuration/index.tsx— the page and edit dialog. JSON checks reject1e400, integers past 2^53 and nesting too deep to send. Locks use central-manager's computedsuperUserOnly.src/features/admin/configuration/queries/getConfiguration.ts,src/features/admin/configuration/mutations/useUpdateConfiguration.ts— load the list and save changes: re-read, PATCH, then refresh the list.src/features/admin/routes.ts,src/features/admin/components/AdminShell.tsx— the route, and a nav item requiringconfig:write; AdminShell's existing check redirects a deep link from anyone without it.src/integrations/api/api.patch.d.ts— theconfig:readandconfig:writepermissions and the row type until the generated OpenAPI types includesuperUserOnly.✅ Verification
pnpm test6302 passing after mergingstage(the Hosts, Monitoring and API Tokens pages sit beside this one, and the custom-region types beside the row type). Page tests cover:Shell visibility and route tests include Configuration.
Screenshots below: this branch (ede76d2) in Chrome with stubbed API responses and placeholder values.
Not run against a deployed central-manager. The endpoint side was smoke-tested on released Harper 5.3.1 in HarperFast/central-manager#982.
Light theme, as fabric_admin: Super user keys have no Edit button.
Dark theme.
Changing a number to a string warns; Save stays enabled for valid JSON.
🤖 Generated by Claude Code (Claude Opus 5.5); posted via @Devin-Holland.
Related PRs: #1975 overlaps (merged into stage, included here), #1780 overlaps (merged into stage, included here)
Complexity: medium
Deferred findings
e3cf9431bf9907fcnit maintainability —src/features/admin/configuration/index.tsx— local imports omit file extensions — NOT FILED9662b6ba91556850nit data-integrity —src/features/admin/configuration/mutations/useUpdateConfiguration.ts— whole-value PATCH from stale snapshot loses concurrent edits — NOT FILEDc061a4cfe6c1e8e6nit performance —src/features/admin/configuration/index.tsx— per-keystroke stringify/lowercase/closed-dialog parse over all rows — NOT FILED64d604298c694ca2nit maintainability —src/features/admin/configuration/queries/getConfiguration.ts— double cast instead of patched endpoint types — NOT FILED7244681086f2b812nit maintainability —src/features/admin/configuration/index.tsx— exports with no consumer outside their own file — NOT FILEDReview-Coverage: authored=claude; ran=gemini,codex,cursor-composer; pending=cursor-grok; late=cursor-grok:pending; adjudicated=domain; declined=cursor-kimi,cursor-muse,muse; rounds=4; full=1 @ ede76d2
Review-Attention: read ~8m (decisions: gate-page-on-config-write, global-error-reporting, client-side-precondition, raw-value-display, strict-integer-rejection, do-less-alternative; raised: degraded review) @ ede76d2