Repository navigation
feat(admin): add a Configuration page to view and edit central-manager settings - #1988
Devin-Holland wants to merge 4 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.
| @@ -0,0 +1,211 @@ | |||
| import { Badge } from '@/components/ui/badge'; | |||
| import { Button } from '@/components/ui/button'; | |||
| import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogTitle } from '@/components/ui/dialog'; | |||
There was a problem hiding this comment.
Import DialogHeader from @/components/ui/dialog to wrap the dialog title and description, ensuring proper layout and padding according to shadcn/ui standards.
| import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogTitle } from '@/components/ui/dialog'; | |
| import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; |
| <DialogContent className="max-w-2xl"> | ||
| <DialogTitle className="font-mono">{entry?.name}</DialogTitle> | ||
| <DialogDescription>{entry?.description || 'No description.'}</DialogDescription> |
There was a problem hiding this comment.
Wrap DialogTitle and DialogDescription inside a DialogHeader component to maintain correct layout, alignment, and spacing as defined by shadcn/ui guidelines.
| <DialogContent className="max-w-2xl"> | |
| <DialogTitle className="font-mono">{entry?.name}</DialogTitle> | |
| <DialogDescription>{entry?.description || 'No description.'}</DialogDescription> | |
| <DialogContent className="max-w-2xl"> | |
| <DialogHeader> | |
| <DialogTitle className="font-mono">{entry?.name}</DialogTitle> | |
| <DialogDescription>{entry?.description || 'No description.'}</DialogDescription> | |
| </DialogHeader> |
| <Badge variant="secondary" className="text-[10px]"> | ||
| <LockIcon />Super user | ||
| </Badge> |
There was a problem hiding this comment.
The LockIcon inside the Badge is disproportionately large for a text-[10px] badge. Add size classes to the icon and a gap to the badge for proper visual alignment.
| <Badge variant="secondary" className="text-[10px]"> | |
| <LockIcon />Super user | |
| </Badge> | |
| <Badge variant="secondary" className="gap-1 text-[10px]"> | |
| <LockIcon className="h-3 w-3" />Super user | |
| </Badge> |
Coverage Report
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
⊙ 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 test5875 passing on this head. Page tests cover:Reverting any of this round's fixes fails a test. Shell visibility and route tests include Configuration.
Rendered the real page against stub data in the browser (light and dark): lock badges, the editor, and its warnings look as described.
Not run against a deployed central-manager. The endpoint side was smoke-tested on released Harper 5.3.1 in HarperFast/central-manager#982.
🤖 Generated by Claude Code (Claude Opus 5.5); posted via @Devin-Holland.
Related PRs: #1975 overlaps (AdminShell nav items, admin routes and the visibility test; whichever merges second keeps both pages), #1780 overlaps (both add types to api.patch.d.ts)
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; adjudicated=domain; blocked=cursor-composer(auth); declined=cursor-grok,cursor-kimi,cursor-muse,muse; rounds=3; full=1 @ 3832ab9
Review-Attention: read ~5m (decisions: global-error-reporting, client-side-precondition, gate-page-on-config-write, raw-value-display, client-side-superuser-gate, strict-integer-rejection, do-less-alternative) @ 3832ab9