diff --git a/web/src/routes/admin/discovery/+page.svelte b/web/src/routes/admin/discovery/+page.svelte index 1654c38..ed703bc 100644 --- a/web/src/routes/admin/discovery/+page.svelte +++ b/web/src/routes/admin/discovery/+page.svelte @@ -111,9 +111,7 @@ // Scroll into view so the highlighted row stays visible during // keyboard-driven scanning through a long list. requestAnimationFrame(() => { - document - .querySelector(`[data-row-id="${selectedId}"]`) - ?.scrollIntoView({ block: 'nearest' }); + document.querySelector(`[data-row-id="${selectedId}"]`)?.scrollIntoView({ block: 'nearest' }); }); } @@ -269,11 +267,6 @@ const showingFrom = $derived(data.offset + 1); const showingTo = $derived(Math.min(data.offset + data.limit, data.total ?? 0)); - // 'YYYY-MM-DDTHH:mm:ssZ' → 'YYYY-MM-DD' for - function dateInputValue(iso: string | null): string { - return iso ? iso.slice(0, 10) : ''; - } - // 'YYYY-MM-DDTHH:mm:ssZ' → 'DD.MM.YYYY' (German) for display. function fmtDate(iso: string | null): string { if (!iso) return ''; @@ -289,6 +282,13 @@ return s || e || ''; } + // Backend emits UTC; render in the browser's local timezone. + function fmtLocalStamp(iso: string): string { + const d = new Date(iso); + const pad = (n: number) => String(n).padStart(2, '0'); + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`; + } + function konfidenzClass(k: string): string { switch (k) { case 'hoch': @@ -578,9 +578,7 @@
- Rang 1 = höchste Priorität · Gewinnende Quelle: - {contributions[0].source_name} - · Amber = abweichende Werte zwischen Quellen -
+| Feld | {#each contributions as c, i}- {c.source_name} + {c.source_name} {#if i === 0} Rang 1Rang 1 {/if} | @@ -93,18 +103,18 @@ {#each fields as field} {@const conflict = hasConflict(field)}
|---|---|
| {field.label} {#if conflict} - ⚠ + {/if} | {#each contributions as c} diff --git a/web/src/routes/admin/discovery/DetailDrawer.svelte b/web/src/routes/admin/discovery/DetailDrawer.svelte index 4e01731..e7c5a32 100644 --- a/web/src/routes/admin/discovery/DetailDrawer.svelte +++ b/web/src/routes/admin/discovery/DetailDrawer.svelte @@ -177,6 +177,12 @@ const [y, m, day] = d.split('-'); return y && m && day ? `${day}.${m}.${y}` : d; } + // Backend emits UTC; render in the browser's local timezone. + function fmtLocalStamp(iso: string): string { + const d = new Date(iso); + const pad = (n: number) => String(n).padStart(2, '0'); + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`; + } function konfidenzClass(k: string): string { switch (k) { case 'hoch': @@ -189,8 +195,58 @@ return 'bg-stone-100 text-stone-600 dark:bg-stone-800 dark:text-stone-400'; } } + function provenanceClass(src: string | undefined): string { + if (src === 'llm') { + return 'bg-purple-100 text-purple-700 dark:bg-purple-900/50 dark:text-purple-300'; + } + if (src === 'crawl') { + return 'bg-sky-100 text-sky-700 dark:bg-sky-900/50 dark:text-sky-300'; + } + return 'bg-stone-100 text-stone-500 dark:bg-stone-800 dark:text-stone-400'; + } + function hostnameOf(url: string): string { + try { + return new URL(url).hostname.replace(/^www\./, ''); + } catch { + return url; + } + } + function enrichmentStatusClass(s: string): string { + if (s === 'done') + return 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/50 dark:text-emerald-300'; + if (s === 'failed') return 'bg-red-100 text-red-700 dark:bg-red-900/50 dark:text-red-300'; + return 'bg-stone-100 text-stone-600 dark:bg-stone-800 dark:text-stone-300'; + } + + // Truthy iff the row has at least one enrichment value worth rendering. + const hasEnrichment = $derived.by(() => { + const en = row?.enrichment; + if (!en) return false; + return !!( + en.plz || + en.venue || + en.organizer || + en.category || + en.opening_hours || + en.description || + (en.lat != null && en.lng != null) + ); + }); +{#snippet sourceBadge(src: string | undefined)} + {#if src} + + {src} + + {/if} +{/snippet} + {#if row} @@ -203,7 +259,7 @@ >