Add cross-reference map, admin health page, passkeys and device list, settings tabs
Build and Push Docker Image / build-and-push (push) Successful in 10m22s

- Reader: chapter cross-reference map (M) from IQ Bible's reference graph
- Admin: Health tab with disk use, snapshots (back up, download, restore), failure logs
- Passkey sign-in (WebAuthn), signed-in device list, sign out others, optional sign-in alerts
- Settings split into Account, Preferences, Notifications, Security, Your data tabs
- ntfy server field: catch a topic typed into the server box

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-06 12:52:49 -04:00
1 parent 207bfcb919
commit bdb04cdedc
35 files changed
+1860 -22

No files matched your search

+17
View File
@@ -82,6 +82,23 @@ describe('Authentication', () => {
await u.click(await screen.findByRole('menuitem', { name: /settings/i }));
expect(await screen.findByDisplayValue('My Show')).toBeInTheDocument();
});
test('Settings is split into tabs, one group at a time', async () => {
stubApi({ session: user });
const u = userEvent.setup();
render(<App />);
await openAccountMenu(u);
await u.click(await screen.findByRole('menuitem', { name: /settings/i }));
const tabs = await screen.findAllByRole('tab');
expect(tabs.map((t) => t.textContent)).toEqual(['Account', 'Preferences', 'Notifications', 'Security', 'Your data']);
expect(screen.queryByRole('heading', { name: 'Two-factor authentication' })).not.toBeInTheDocument();
await u.click(screen.getByRole('tab', { name: 'Security' }));
expect(screen.getByRole('tab', { name: 'Security' })).toHaveAttribute('aria-selected', 'true');
expect(await screen.findByRole('heading', { name: 'Two-factor authentication' })).toBeInTheDocument();
expect(screen.getByRole('heading', { name: 'Passkeys' })).toBeInTheDocument();
expect(screen.getByRole('heading', { name: 'Where you’re signed in' })).toBeInTheDocument();
expect(screen.queryByDisplayValue('My Show')).not.toBeInTheDocument();
});
});
// ---------------------------------------------------------------------------