From f548128940328e084578ef4bd0235ccc7d59e594 Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 20 Apr 2026 22:08:09 +0200 Subject: [PATCH] feat(dashboard): wire EnrichmentBlock between Resume strip and Mission Control Dashboard loader fetches /api/documents/incomplete?size=5 plus the existing /incomplete-count and surfaces both via data; +page.svelte renders EnrichmentBlock with the top 5 docs, the total count, and the bannerCount state bound to DropZone's onUploadComplete callback (issue #296). The block returns null when there is nothing to show, so dashboards without pending uploads stay uncluttered. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/src/routes/+page.server.ts | 21 +++++++++++++++++++-- frontend/src/routes/+page.svelte | 12 +++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/frontend/src/routes/+page.server.ts b/frontend/src/routes/+page.server.ts index c89e3ec2..e12e0d89 100644 --- a/frontend/src/routes/+page.server.ts +++ b/frontend/src/routes/+page.server.ts @@ -8,6 +8,7 @@ type TranscriptionWeeklyStatsDTO = components['schemas']['TranscriptionWeeklySta type DashboardResumeDTO = components['schemas']['DashboardResumeDTO']; type DashboardPulseDTO = components['schemas']['DashboardPulseDTO']; type ActivityFeedItemDTO = components['schemas']['ActivityFeedItemDTO']; +type IncompleteDocumentDTO = components['schemas']['IncompleteDocumentDTO']; export async function load({ fetch }) { const api = createApiClient(fetch); @@ -27,7 +28,9 @@ export async function load({ fetch }) { segmentationResult, transcriptionResult, readyResult, - weeklyStatsResult + weeklyStatsResult, + incompleteResult, + incompleteCountResult ] = await Promise.allSettled([ api.GET('/api/stats'), api.GET('/api/dashboard/resume'), @@ -36,7 +39,9 @@ export async function load({ fetch }) { api.GET('/api/transcription/segmentation-queue'), api.GET('/api/transcription/transcription-queue'), api.GET('/api/transcription/ready-to-read'), - api.GET('/api/transcription/weekly-stats') + api.GET('/api/transcription/weekly-stats'), + api.GET('/api/documents/incomplete', { params: { query: { size: 5 } } }), + api.GET('/api/documents/incomplete-count') ]); let stats: StatsDTO | null = null; @@ -47,6 +52,8 @@ export async function load({ fetch }) { let transcriptionDocs: TranscriptionQueueItemDTO[] = []; let readyDocs: TranscriptionQueueItemDTO[] = []; let weeklyStats: TranscriptionWeeklyStatsDTO | null = null; + let incompleteDocs: IncompleteDocumentDTO[] = []; + let incompleteTotal = 0; if (statsResult.status === 'fulfilled' && statsResult.value.response.ok) { stats = statsResult.value.data ?? null; @@ -72,6 +79,12 @@ export async function load({ fetch }) { if (weeklyStatsResult.status === 'fulfilled' && weeklyStatsResult.value.response.ok) { weeklyStats = weeklyStatsResult.value.data ?? null; } + if (incompleteResult.status === 'fulfilled' && incompleteResult.value.response.ok) { + incompleteDocs = (incompleteResult.value.data ?? []) as IncompleteDocumentDTO[]; + } + if (incompleteCountResult.status === 'fulfilled' && incompleteCountResult.value.response.ok) { + incompleteTotal = (incompleteCountResult.value.data?.count as number | undefined) ?? 0; + } return { stats, @@ -82,6 +95,8 @@ export async function load({ fetch }) { transcriptionDocs, readyDocs, weeklyStats, + incompleteDocs, + incompleteTotal, error: null as string | null }; } catch (e) { @@ -96,6 +111,8 @@ export async function load({ fetch }) { transcriptionDocs: [], readyDocs: [], weeklyStats: null, + incompleteDocs: [] as IncompleteDocumentDTO[], + incompleteTotal: 0, error: 'Daten konnten nicht geladen werden.' as string | null }; } diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index 300313ce..2f1f6f5f 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -4,10 +4,13 @@ import DashboardResumeStrip from '$lib/components/DashboardResumeStrip.svelte'; import MissionControlStrip from '$lib/components/MissionControlStrip.svelte'; import DashboardFamilyPulse from '$lib/components/DashboardFamilyPulse.svelte'; import DashboardActivityFeed from '$lib/components/DashboardActivityFeed.svelte'; +import EnrichmentBlock from '$lib/components/EnrichmentBlock.svelte'; import { m } from '$lib/paraglide/messages.js'; let { data } = $props(); +let bannerCount = $state(0); + const greetingText = $derived.by(() => { const name = data?.user?.firstName ?? ''; const h = new Date().getHours(); @@ -32,6 +35,13 @@ const greetingText = $derived.by(() => {
+ (bannerCount = 0)} + /> +

{m.dashboard_mission_caption()} @@ -49,7 +59,7 @@ const greetingText = $derived.by(() => { {#if data.canWrite} - + (bannerCount = count)} /> {/if}