diff --git a/job-tracker-ui/src/App.tsx b/job-tracker-ui/src/App.tsx index e4a94d5a..ac441ee3 100644 --- a/job-tracker-ui/src/App.tsx +++ b/job-tracker-ui/src/App.tsx @@ -161,6 +161,10 @@ function titleFor(path: string, t: (k: any) => string): string { } function subtitleFor(path: string, t: (k: any) => string): string | undefined { + if (path.startsWith("/admin/audit")) return t("adminAuditSubtitle"); + if (path.startsWith("/admin/users")) return t("adminUsersSubtitle"); + if (path.startsWith("/admin/system")) return t("adminSystemSubtitle"); + if (path.startsWith("/admin/processing")) return t("processingSubtitle"); if (/^\/settings\/?$/.test(path)) return t("settingsPageDescription"); if (path === "/dashboard") return t("dashboardPageSubtitle"); if (path.startsWith("/analytics")) return t("analyticsPageSubtitle"); diff --git a/job-tracker-ui/src/admin-audit-page.test.tsx b/job-tracker-ui/src/admin-audit-page.test.tsx index 70279f2e..e0d7cd3a 100644 --- a/job-tracker-ui/src/admin-audit-page.test.tsx +++ b/job-tracker-ui/src/admin-audit-page.test.tsx @@ -37,8 +37,8 @@ test("[P7-10 audit] retains shared heading hierarchy and a named keyboard scroll mockedApi.get.mockResolvedValue({ data: [row] } as any); renderPage(); await screen.findByRole("button", { name: "Undo" }); - expect(screen.getByRole("heading", { name: "Audit log", level: 2 })).toBeInTheDocument(); - expect(screen.getByRole("heading", { name: translations.en.adminAuditEvents, level: 3 })).toBeInTheDocument(); + expect(screen.queryByRole("heading", { name: /^Audit log$/ })).not.toBeInTheDocument(); + expect(screen.getByRole("heading", { name: translations.en.adminAuditEvents, level: 2 })).toBeInTheDocument(); const region = screen.getByRole("region", { name: "Audit log" }); expect(region).toHaveAttribute("tabindex", "0"); expect(within(region).getByRole("table")).toHaveAccessibleName("Audit log"); @@ -104,7 +104,7 @@ test("distinguishes an unavailable audit log from an empty audit log and retries mockedApi.get.mockRejectedValueOnce(new Error("offline")); renderPage(); - expect(screen.getByRole("heading", { name: "Audit log", level: 2 })).toBeInTheDocument(); + expect(screen.getByRole("region", { name: /^Audit log$/ })).toBeInTheDocument(); expect(await screen.findByText("Unable to load audit events")).toBeInTheDocument(); expect(screen.queryByText("No events.")).not.toBeInTheDocument(); diff --git a/job-tracker-ui/src/admin-system-page.test.tsx b/job-tracker-ui/src/admin-system-page.test.tsx index 77eab3d3..1be9f864 100644 --- a/job-tracker-ui/src/admin-system-page.test.tsx +++ b/job-tracker-ui/src/admin-system-page.test.tsx @@ -176,7 +176,8 @@ describe('AdminSystemPage', () => { it('uses contextual system headings and keeps metric values out of heading navigation', async () => { render(); await screen.findByText('Production'); - expect(screen.getByRole('heading', { name: 'System status', level: 2 })).toBeInTheDocument(); + expect(screen.getByRole('region', { name: 'System status' })).toBeInTheDocument(); + expect(screen.queryByRole('heading', { name: 'System status' })).not.toBeInTheDocument(); expect(screen.queryByRole('heading', { name: 'Production' })).not.toBeInTheDocument(); const levels = screen.getAllByRole('heading').map(heading => Number(heading.tagName.slice(1))); let previous = 1; diff --git a/job-tracker-ui/src/admin-users-page.test.tsx b/job-tracker-ui/src/admin-users-page.test.tsx index c58cd982..13587088 100644 --- a/job-tracker-ui/src/admin-users-page.test.tsx +++ b/job-tracker-ui/src/admin-users-page.test.tsx @@ -96,7 +96,7 @@ test('disposed create acknowledgement cannot start a new private list read', asy test("requires explicit confirmation before removing your own admin role", async () => { renderPage([{ id: "me", email: "me@example.com", userName: "me", roles: ["Admin"], emailConfirmed: true, isCurrentUser: true, canRemoveAdmin: true }]); - expect(screen.getByRole("heading", { name: "Users", level: 2 })).toBeInTheDocument(); + expect(screen.getByRole("heading", { name: "Create user", level: 2 })).toBeInTheDocument(); fireEvent.click(await screen.findByRole("button", { name: "Remove admin" })); expect(await screen.findByText(/you will immediately lose access/i)).toBeInTheDocument(); diff --git a/job-tracker-ui/src/views/AdminAuditPage.tsx b/job-tracker-ui/src/views/AdminAuditPage.tsx index 860bb566..8540976f 100644 --- a/job-tracker-ui/src/views/AdminAuditPage.tsx +++ b/job-tracker-ui/src/views/AdminAuditPage.tsx @@ -18,7 +18,7 @@ import { useToast } from "../toast"; import { useI18n } from "../i18n/I18nProvider"; import { useViewResource } from "../hooks/useViewResource"; import ViewStateNotice from "../components/ViewStateNotice"; -import { PageHeader, PageSection } from "../layout/PageLayout"; +import { PageSection } from "../layout/PageLayout"; import { checkSessionCookie, getSessionContext, isSessionInvalidated } from "../sessionBoundary"; type AuditItem = { @@ -86,8 +86,7 @@ export default function AdminAuditPage() { return ( - - + { pausedRef.current = false; setPaused(false); setBefore(null); setRefresh(value => value + 1); }; const visibleListing = identity === getAuthUserKey() ? listing : null; return - diff --git a/job-tracker-ui/src/views/AdminSystemPage.tsx b/job-tracker-ui/src/views/AdminSystemPage.tsx index c3432229..24275e6b 100644 --- a/job-tracker-ui/src/views/AdminSystemPage.tsx +++ b/job-tracker-ui/src/views/AdminSystemPage.tsx @@ -17,7 +17,7 @@ import { import { api, getApiErrorMessage } from "../api"; import { useI18n } from "../i18n/I18nProvider"; -import { PageHeader, PageSection } from "../layout/PageLayout"; +import { PageSection } from "../layout/PageLayout"; import type { TranslationKey } from "../i18n/translations"; import { checkSessionCookie, getSessionContext, isSessionInvalidated } from "../sessionBoundary"; @@ -250,7 +250,6 @@ export default function AdminSystemPage() { const passwordRevision = useRef(0); const savedRevision = useRef(0); const bodyRef = useRef(null); - const headingRef = useRef(null); const restoreFocus = useRef(null); const navigationId = useId(); @@ -302,7 +301,6 @@ export default function AdminSystemPage() { restoreFocus.current = null; if (document.activeElement !== bodyRef.current) return; if (target.isConnected && !target.matches(":disabled")) target.focus(); - else headingRef.current?.focus(); }, [loading, action]); const rememberFocus = () => { @@ -422,21 +420,20 @@ export default function AdminSystemPage() { return ( - - - - } /> + + + + setTab(value)} variant="scrollable" scrollButtons="auto" allowScrollButtonsMobile> @@ -484,7 +481,7 @@ export default function AdminSystemPage() { - + @@ -501,7 +498,7 @@ export default function AdminSystemPage() { - + @@ -518,7 +515,7 @@ export default function AdminSystemPage() { - + @@ -529,7 +526,7 @@ export default function AdminSystemPage() { - + @@ -550,7 +547,7 @@ export default function AdminSystemPage() { - + {t("adminSystemRequests")}{status?.ai.requests ?? 0} {t("adminSystemCacheHits")}{status?.ai.cacheHits ?? 0} @@ -577,7 +574,7 @@ export default function AdminSystemPage() { - + @@ -619,7 +616,7 @@ export default function AdminSystemPage() { - {t("adminBenchmarkTopFindings")} + {t("adminBenchmarkTopFindings")} {benchmarkFindings.length > 0 ? benchmarkFindings.map((finding) => ( @@ -631,7 +628,7 @@ export default function AdminSystemPage() { - {t("adminBenchmarkWeakest")} + {t("adminBenchmarkWeakest")} {weakestEntries.map((entry) => ( @@ -649,7 +646,7 @@ export default function AdminSystemPage() { - {t("adminBenchmarkLatestSummary")} + {t("adminBenchmarkLatestSummary")} {benchmarkStatus?.reportMarkdown || "-"} @@ -668,7 +665,7 @@ export default function AdminSystemPage() {