feat(admin): observability — job history, live now-analyzing, durations & metrics (0.84.0) (#6)
Some checks failed
deploy / test-backend (push) Failing after 19m59s
deploy / test-frontend (push) Successful in 9m54s
deploy / build-and-push (push) Has been skipped
deploy / deploy (push) Has been skipped

This commit was merged in pull request #6.
This commit is contained in:
2026-06-16 12:21:13 +00:00
parent 790549636f
commit d51ab2a049
41 changed files with 3655 additions and 21 deletions

View File

@@ -6,6 +6,9 @@
import ActiveJobsTable from '$lib/components/crawler/ActiveJobsTable.svelte';
import MissingCoversTable from '$lib/components/crawler/MissingCoversTable.svelte';
import DeadJobsTable from '$lib/components/crawler/DeadJobsTable.svelte';
import CrawlerHistoryTable from '$lib/components/crawler/CrawlerHistoryTable.svelte';
import CrawlerMetricsPanel from '$lib/components/crawler/CrawlerMetricsPanel.svelte';
import SegmentedControl from '$lib/components/SegmentedControl.svelte';
import SessionModal from '$lib/components/crawler/SessionModal.svelte';
import RestartConfirmModal from '$lib/components/crawler/RestartConfirmModal.svelte';
import RequeueAllConfirmModal from '$lib/components/crawler/RequeueAllConfirmModal.svelte';
@@ -27,6 +30,10 @@
type RequeueScope
} from '$lib/api/admin';
// Segmented Live/History/Metrics view. Live keeps the SSE-driven
// dashboard; History is a searchable job log; Metrics shows durations.
let view = $state<'live' | 'history' | 'metrics'>('live');
let status: CrawlerStatus | null = $state(null);
let error: string | null = $state(null);
let notice: string | null = $state(null);
@@ -387,6 +394,20 @@
</span>
</div>
<div class="viewtabs">
<SegmentedControl
options={[
{ label: 'Live', value: 'live' },
{ label: 'History', value: 'history' },
{ label: 'Metrics', value: 'metrics' }
]}
value={view}
onchange={(v) => (view = v)}
ariaLabel="Crawler view"
testid="crawler-tab"
/>
</div>
{#if error}
<p class="error" role="alert">{error}</p>
{/if}
@@ -394,6 +415,11 @@
<p class="notice" role="status">{notice}</p>
{/if}
{#if view === 'history'}
<CrawlerHistoryTable onRequeue={requeue} {busy} />
{:else if view === 'metrics'}
<CrawlerMetricsPanel />
{:else}
{#if status}
<CrawlerHero {status} />
@@ -446,6 +472,7 @@
onRequeue={requeue}
onRequeueAll={() => (requeueAllModalOpen = true)}
/>
{/if}
<RestartConfirmModal
open={restartModalOpen}
@@ -488,6 +515,9 @@
.livedot.on {
color: var(--success, #0a7d2c);
}
.viewtabs {
margin-bottom: var(--space-4);
}
.notice {
color: var(--success, #0a7d2c);
padding: var(--space-2) var(--space-3);