diff --git a/webui/src/App.tsx b/webui/src/App.tsx index de6e308..6b9cbdc 100644 --- a/webui/src/App.tsx +++ b/webui/src/App.tsx @@ -78,6 +78,7 @@ import { countNodesBySection, type NodeSectionCounts, } from './sidebarCounts' +import { documentTitleFor, SECTION_TITLES } from './documentTitle' import { isResourceSectionId, navigateTo, @@ -112,18 +113,6 @@ const NAV_ITEMS: ReadonlyArray<{ id: SectionId; label: string }> = [ { id: 'vms', label: 'Virtual Machines' }, ] -const SECTION_TITLES: Record = { - overview: 'Overview', - vms: 'Virtual Machines', - docker: 'Docker', - containers: 'Containers', - logs: 'Logs', - profile: 'Profile', - configuration: 'Configuration', - setup: 'Setup', - login: 'Sign in', -} - const CONFIG_TABS: ReadonlyArray<{ id: ConfigTabId; label: string }> = [ { id: 'overview', label: 'Overview' }, { id: 'users', label: 'Users' }, @@ -3906,6 +3895,22 @@ function App() { } }, [bootState.kind]) + useEffect(() => { + if (bootState.kind === 'loading') { + document.title = documentTitleFor('loading') + return + } + if (bootState.kind === 'setup') { + document.title = documentTitleFor('setup') + return + } + if (bootState.kind === 'login') { + document.title = documentTitleFor('login') + return + } + document.title = documentTitleFor(activeSection) + }, [bootState.kind, activeSection]) + function goToSection(section: SectionId) { if (section === 'setup' || section === 'login') { return diff --git a/webui/src/documentTitle.test.ts b/webui/src/documentTitle.test.ts new file mode 100644 index 0000000..5b12624 --- /dev/null +++ b/webui/src/documentTitle.test.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from 'vitest' +import { documentTitleFor, SECTION_TITLES } from './documentTitle' + +describe('documentTitleFor', () => { + it('returns the app name alone while loading', () => { + expect(documentTitleFor('loading')).toBe('ClusterCanvas') + }) + + it('formats category titles for main sections', () => { + expect(documentTitleFor('overview')).toBe('ClusterCanvas - Overview') + expect(documentTitleFor('vms')).toBe('ClusterCanvas - Virtual Machines') + expect(documentTitleFor('docker')).toBe('ClusterCanvas - Docker') + expect(documentTitleFor('containers')).toBe('ClusterCanvas - Containers') + expect(documentTitleFor('logs')).toBe('ClusterCanvas - Logs') + expect(documentTitleFor('profile')).toBe('ClusterCanvas - Profile') + expect(documentTitleFor('configuration')).toBe( + 'ClusterCanvas - Configuration', + ) + }) + + it('formats titles for setup and sign-in', () => { + expect(documentTitleFor('setup')).toBe('ClusterCanvas - Setup') + expect(documentTitleFor('login')).toBe('ClusterCanvas - Sign in') + }) + + it('uses SECTION_TITLES for every section id', () => { + for (const section of Object.keys(SECTION_TITLES) as Array< + keyof typeof SECTION_TITLES + >) { + expect(documentTitleFor(section)).toBe( + `ClusterCanvas - ${SECTION_TITLES[section]}`, + ) + } + }) +}) diff --git a/webui/src/documentTitle.ts b/webui/src/documentTitle.ts new file mode 100644 index 0000000..96884f6 --- /dev/null +++ b/webui/src/documentTitle.ts @@ -0,0 +1,22 @@ +import type { SectionId } from './navigation' + +export const SECTION_TITLES: Record = { + overview: 'Overview', + vms: 'Virtual Machines', + docker: 'Docker', + containers: 'Containers', + logs: 'Logs', + profile: 'Profile', + configuration: 'Configuration', + setup: 'Setup', + login: 'Sign in', +} + +const APP_TITLE = 'ClusterCanvas' + +export function documentTitleFor(section: SectionId | 'loading'): string { + if (section === 'loading') { + return APP_TITLE + } + return `${APP_TITLE} - ${SECTION_TITLES[section]}` +}