Add sidebar navigation and global command search

This commit is contained in:
2026-10-07 18:59:39 -04:00
parent 9999e80226
commit e4f37f6964
33 changed files with 660 additions and 151 deletions
+17 -11
View File
@@ -6,30 +6,36 @@ describe('application navigation', () => {
['/servers/t5_zombie_theater_1', 'fleet', '/'],
['/collections/launches/42', 'fleet', '/collections'],
['/hosts/42', 'fleet', '/hosts'],
['/hosts/operations', 'operations', '/hosts/operations'],
['/provisioning', 'operations', '/provisioning'],
['/betas/new', 'operations', '/betas'],
['/campaigns/42', 'operations', '/campaigns'],
['/configs/42', 'library', '/configs'],
['/leaderboard/players/42', 'analytics', '/leaderboard'],
['/settings/users', 'administration', '/settings/users'],
['/server-keys', 'administration', '/server-keys']
['/hosts/operations', 'activity', '/hosts/operations'],
['/provisioning', 'activity', '/provisioning'],
['/betas/new', 'releases', '/betas'],
['/campaigns/42', 'releases', '/campaigns'],
['/configs/42', 'releases', '/configs'],
['/leaderboard/players/42', 'players', '/leaderboard'],
['/settings/users', 'admin', '/settings/users'],
['/server-keys', 'admin', '/server-keys']
])('gives %s exactly one canonical home', (path, group, href) => {
expect(navigationLocation(path, 'admin')?.group.id).toBe(group);
expect(navigationGroups.flatMap(group => group.items).filter(item => navigationItemActive(item, path)).map(item => item.href)).toEqual([href]);
});
it('opens Operations at Provisioning and redirects legacy overview links', async () => {
expect(navigationGroups.find(group => group.id === 'operations')?.items[0].href).toBe('/provisioning');
it('keeps Operations reachable from Activity and redirects legacy overview links', async () => {
expect(navigationGroups.find(group => group.id === 'activity')?.items[0].href).toBe('/provisioning');
const { load } = await import('../../src/routes/operations/+page.server.js');
expect(load).toThrow(expect.objectContaining({ status: 308, location: '/provisioning' }));
});
it('keeps administration and its shortcuts out of operator and viewer navigation', () => {
for (const role of ['operator', 'viewer'] as const) {
expect(visibleNavigation(role).map(group => group.id)).not.toContain('administration');
expect(visibleNavigation(role).map(group => group.id)).not.toContain('admin');
expect(navigationLocation('/server-keys', role)).toBeNull();
expect(visibleNavigation(role).flatMap(group => group.items).filter(item => ['h', 'k'].includes(item.shortcut ?? ''))).toEqual([]);
}
});
it('groups file releases together and retains Campaigns as its own destination', () => {
expect(navigationGroups.map(group => group.label)).toEqual(['Fleet', 'Releases', 'Activity', 'Players', 'Admin']);
expect(navigationGroups.find(group => group.id === 'releases')?.items.map(item => item.label)).toEqual(['Scripts', 'Configs', 'Plugins', 'Game files', 'Betas', 'Campaigns']);
expect(navigationGroups.flatMap(group => group.items).some(item => /rollout/i.test(item.label))).toBe(false);
});
});