feat(search): show result count and term-aware empty state in DocumentList
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -131,6 +131,12 @@ const showRightColumn = $derived(data.canWrite || (data.incompleteDocs?.length ?
|
|||||||
<DashboardRecentDocuments recentDocs={data.recentDocs ?? []} stats={data.stats} />
|
<DashboardRecentDocuments recentDocs={data.recentDocs ?? []} stats={data.stats} />
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<DocumentList documents={data.documents ?? []} canWrite={data.canWrite} error={data.error} />
|
<DocumentList
|
||||||
|
documents={data.documents ?? []}
|
||||||
|
canWrite={data.canWrite}
|
||||||
|
error={data.error}
|
||||||
|
total={data.total ?? 0}
|
||||||
|
q={q}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import { formatDate } from '$lib/utils/date';
|
|||||||
let {
|
let {
|
||||||
documents,
|
documents,
|
||||||
canWrite,
|
canWrite,
|
||||||
error
|
error,
|
||||||
|
total = 0,
|
||||||
|
q = ''
|
||||||
}: {
|
}: {
|
||||||
documents: {
|
documents: {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -20,6 +22,8 @@ let {
|
|||||||
}[];
|
}[];
|
||||||
canWrite: boolean;
|
canWrite: boolean;
|
||||||
error?: string | null;
|
error?: string | null;
|
||||||
|
total?: number;
|
||||||
|
q?: string;
|
||||||
} = $props();
|
} = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -41,6 +45,11 @@ let {
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- RESULT COUNT -->
|
||||||
|
{#if total > 0}
|
||||||
|
<p class="mb-3 font-sans text-sm text-ink-2">{m.docs_result_count({ count: total })}</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<!-- DOCUMENT LIST -->
|
<!-- DOCUMENT LIST -->
|
||||||
<div class="border border-line bg-surface shadow-sm">
|
<div class="border border-line bg-surface shadow-sm">
|
||||||
{#if error}
|
{#if error}
|
||||||
@@ -162,7 +171,7 @@ let {
|
|||||||
</div>
|
</div>
|
||||||
<h3 class="font-serif text-lg font-medium text-ink">{m.docs_empty_heading()}</h3>
|
<h3 class="font-serif text-lg font-medium text-ink">{m.docs_empty_heading()}</h3>
|
||||||
<p class="mt-1 font-sans text-sm text-ink-2">
|
<p class="mt-1 font-sans text-sm text-ink-2">
|
||||||
{m.docs_empty_text()}
|
{q ? m.docs_empty_for_term({ term: q }) : m.docs_empty_text()}
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
onclick={() => goto('/')}
|
onclick={() => goto('/')}
|
||||||
|
|||||||
51
frontend/src/routes/DocumentList.svelte.spec.ts
Normal file
51
frontend/src/routes/DocumentList.svelte.spec.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { describe, expect, it, vi } from 'vitest';
|
||||||
|
import { render } from 'vitest-browser-svelte';
|
||||||
|
import { page } from 'vitest/browser';
|
||||||
|
import DocumentList from './DocumentList.svelte';
|
||||||
|
|
||||||
|
vi.mock('$app/navigation', () => ({ goto: vi.fn() }));
|
||||||
|
|
||||||
|
const baseProps = {
|
||||||
|
documents: [],
|
||||||
|
canWrite: false,
|
||||||
|
error: null,
|
||||||
|
total: 0,
|
||||||
|
q: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
const makeDoc = () => ({
|
||||||
|
id: '1',
|
||||||
|
title: 'Testbrief',
|
||||||
|
originalFilename: 'testbrief.pdf',
|
||||||
|
status: 'UPLOADED' as const,
|
||||||
|
documentDate: '2024-03-15',
|
||||||
|
location: null,
|
||||||
|
sender: null,
|
||||||
|
receivers: [],
|
||||||
|
tags: []
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('DocumentList – result count', () => {
|
||||||
|
it('shows result count when total > 0', async () => {
|
||||||
|
render(DocumentList, { ...baseProps, documents: [makeDoc()], total: 1, q: 'test' });
|
||||||
|
await expect.element(page.getByText('1 Dokumente')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not show result count when total is 0 and there is no error', async () => {
|
||||||
|
render(DocumentList, { ...baseProps, total: 0, q: '' });
|
||||||
|
const count = page.getByText(/\d+ Dokumente/);
|
||||||
|
await expect.element(count).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('DocumentList – empty state with search term', () => {
|
||||||
|
it('shows generic empty heading when q is empty', async () => {
|
||||||
|
render(DocumentList, { ...baseProps });
|
||||||
|
await expect.element(page.getByText(/Keine Dokumente/)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows search term in empty state when q is set', async () => {
|
||||||
|
render(DocumentList, { ...baseProps, q: 'Urlaub' });
|
||||||
|
await expect.element(page.getByText(/"Urlaub"/)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user