Add configuration for which pages are shown in UI#13
Conversation
Greptile SummaryThis PR introduces per-page visibility configuration for the Hadrian UI. Operators can now mark any page as Key observations from the review:
Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Browser
participant ConfigProvider
participant Backend as Backend (GET /admin/v1/ui/config)
participant PageGuard
participant Router
Browser->>ConfigProvider: App mount (isLoading=true, defaultConfig)
ConfigProvider->>Backend: fetch /admin/v1/ui/config
Note over ConfigProvider: Renders with defaultPagesConfig (all enabled)
Browser->>Router: Navigate to route (e.g. /chat)
Router->>PageGuard: Render with defaultConfig
PageGuard-->>Browser: Render page content (flash)
Backend-->>ConfigProvider: UiConfigResponse { pages: PagesResponse }
ConfigProvider->>ConfigProvider: deep-merge with defaultPagesConfig
ConfigProvider->>PageGuard: Re-render with merged config
alt page.status == "disabled"
PageGuard->>Router: Navigate(getFirstEnabledRoute)
Router-->>Browser: Redirect to first enabled/notice page
else page.status == "notice"
PageGuard-->>Browser: Render PageNotice (title + message)
else page.status == "enabled"
PageGuard-->>Browser: Render children
end
|
| export function getFirstEnabledRoute(pages: PagesConfig): string { | ||
| for (const key of mainPageOrder) { | ||
| if (pages[key].status !== "disabled") { | ||
| return mainPageRoutes[key]; | ||
| } | ||
| } | ||
| return "/account"; | ||
| } |
There was a problem hiding this comment.
getFirstEnabledRoute redirects to "notice" pages
getFirstEnabledRoute skips pages whose status is "disabled", but it also returns the first page with status "notice". When a PageGuard redirects a user away from a disabled page (line 58), the redirect target could be a "notice" page, meaning the user is silently bounced to a notice screen rather than a functional page. The function name says "enabled" but its behaviour includes "notice".
If all main pages are either "disabled" or "notice", the user will keep landing on notices, never reaching a working page. Consider only returning routes whose status is strictly "enabled", and falling back to "notice" pages as a second tier, or at least document the intended behaviour:
| export function getFirstEnabledRoute(pages: PagesConfig): string { | |
| for (const key of mainPageOrder) { | |
| if (pages[key].status !== "disabled") { | |
| return mainPageRoutes[key]; | |
| } | |
| } | |
| return "/account"; | |
| } | |
| export function getFirstEnabledRoute(pages: PagesConfig): string { | |
| // First, prefer a fully enabled page | |
| for (const key of mainPageOrder) { | |
| if (pages[key].status === "enabled") { | |
| return mainPageRoutes[key]; | |
| } | |
| } | |
| // Fall back to a notice page if no enabled page exists | |
| for (const key of mainPageOrder) { | |
| if (pages[key].status !== "disabled") { | |
| return mainPageRoutes[key]; | |
| } | |
| } | |
| return "/account"; | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/components/PageGuard/PageGuard.tsx
Line: 38-45
Comment:
**`getFirstEnabledRoute` redirects to "notice" pages**
`getFirstEnabledRoute` skips pages whose status is `"disabled"`, but it also returns the first page with status `"notice"`. When a `PageGuard` redirects a user away from a disabled page (line 58), the redirect target could be a `"notice"` page, meaning the user is silently bounced to a notice screen rather than a functional page. The function name says "enabled" but its behaviour includes `"notice"`.
If all main pages are either `"disabled"` or `"notice"`, the user will keep landing on notices, never reaching a working page. Consider only returning routes whose status is strictly `"enabled"`, and falling back to `"notice"` pages as a second tier, or at least document the intended behaviour:
```suggestion
export function getFirstEnabledRoute(pages: PagesConfig): string {
// First, prefer a fully enabled page
for (const key of mainPageOrder) {
if (pages[key].status === "enabled") {
return mainPageRoutes[key];
}
}
// Fall back to a notice page if no enabled page exists
for (const key of mainPageOrder) {
if (pages[key].status !== "disabled") {
return mainPageRoutes[key];
}
}
return "/account";
}
```
How can I resolve this? If you propose a fix, please make it concise.| path="/session" | ||
| element={ | ||
| <Suspense fallback={<PageLoader />}> | ||
| <SessionInfoPage /> | ||
| <PageGuard pageKey="admin.session_info" pageTitle="Session Info"> | ||
| <SessionInfoPage /> | ||
| </PageGuard> | ||
| </Suspense> | ||
| } | ||
| /> |
There was a problem hiding this comment.
Session route gated by an admin config key
The /session route lives inside the AppLayout group (main user-facing app), but it is guarded with an AdminPagesConfig field key via the "admin.*" prefix. getPageConfig resolves this correctly at runtime, but the coupling is architecturally surprising: a main-app route is controlled by a field that belongs to admin page configuration.
AdminSidebar.tsx also lists a "Session Info" nav item pointing at /session (not an /admin/... path), using a key from AdminPagesConfig. Reading either file in isolation, the route appears admin-scoped while actually being served under the user layout.
Consider either moving the route under /admin/session so it lives consistently in the admin layout, or adding a top-level field in PagesConfig for it to keep the main-app and admin separation clear.
Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/routes/AppRoutes.tsx
Line: 236-244
Comment:
**Session route gated by an admin config key**
The `/session` route lives inside the `AppLayout` group (main user-facing app), but it is guarded with an `AdminPagesConfig` field key via the `"admin.*"` prefix. `getPageConfig` resolves this correctly at runtime, but the coupling is architecturally surprising: a main-app route is controlled by a field that belongs to admin page configuration.
`AdminSidebar.tsx` also lists a "Session Info" nav item pointing at `/session` (not an `/admin/...` path), using a key from `AdminPagesConfig`. Reading either file in isolation, the route appears admin-scoped while actually being served under the user layout.
Consider either moving the route under `/admin/session` so it lives consistently in the admin layout, or adding a top-level field in `PagesConfig` for it to keep the main-app and admin separation clear.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
No description provided.