test-web / test (push) Failing after 32s
Renders GET /api/admin/library/missing under Admin -> Missing files. Folder-grouped, because that is the unit an operator decides about: the case behind #2523 was three reorganised albums, and forty individual rows hides that it is really three decisions. Each row leads with the fact that settles whether a missing file is worth chasing -- "last played 2d ago" against "never played". The group header carries how many tracks and how long they have been gone. Read-only. No remove button anywhere: the row, its play history and its likes survive a file going missing, and the scanner clears the mark by itself when the file returns (or adopts the row if it returns renamed, #2528). The page says so in its own copy rather than leaving the operator to infer it. Empty state explains the feature instead of the emptiness -- what puts a row here (moved outside Minstrel, deleted, a drive that didn't mount) and that rows leave on their own. Someone who has never seen this page should not have to guess. Paging follows the house pattern -- plain offset into the factory, wrapped in $derived so a page change re-creates the query with a new key. Passing a getter instead would capture the key once and paging would silently not refetch. The pager only renders when it can do something.
41 lines
1.4 KiB
Svelte
41 lines
1.4 KiB
Svelte
<script lang="ts">
|
|
import { page } from '$app/state';
|
|
|
|
type Item = { href: string; label: string };
|
|
|
|
const items: Item[] = [
|
|
{ href: '/admin', label: 'Overview' },
|
|
{ href: '/admin/integrations', label: 'Integrations' },
|
|
{ href: '/admin/requests', label: 'Requests' },
|
|
{ href: '/admin/quarantine', label: 'Quarantine' },
|
|
{ href: '/admin/missing-files', label: 'Missing files' },
|
|
{ href: '/admin/playback-errors', label: 'Playback errors' },
|
|
{ href: '/admin/diagnostics', label: 'Diagnostics' },
|
|
{ href: '/admin/tuning', label: 'Tuning' },
|
|
{ href: '/admin/users', label: 'Users' }
|
|
];
|
|
|
|
function isActive(href: string): boolean {
|
|
if (href === '/admin') return page.url.pathname === '/admin';
|
|
return page.url.pathname.startsWith(href);
|
|
}
|
|
</script>
|
|
|
|
<nav aria-label="Admin sections" class="sticky top-0 z-10 border-b border-border bg-background">
|
|
<ul class="flex gap-2">
|
|
{#each items as item (item.href)}
|
|
<li>
|
|
<a
|
|
href={item.href}
|
|
aria-current={isActive(item.href) ? 'page' : undefined}
|
|
class="block border-b-2 px-3 py-2 text-sm transition-colors {isActive(item.href)
|
|
? 'border-accent text-text-primary'
|
|
: 'border-transparent text-text-secondary hover:text-text-primary'}"
|
|
>
|
|
{item.label}
|
|
</a>
|
|
</li>
|
|
{/each}
|
|
</ul>
|
|
</nav>
|