From a021355072036f28adcba145d71f33a8a1b5d40a Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 27 Apr 2026 21:43:20 +0200 Subject: [PATCH] feat(documents): inline relationship pills next to person names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the standalone "Beziehung" badge at the bottom of the metadata drawer's Personen column with small inline pills attached to each personCard — sender gets labelFromA, the single receiver gets labelFromB. Matches docs/specs/stammbaum-doc-badge-spec.html. Drops the now-unused RelationshipBadge component. Co-Authored-By: Claude Opus 4.7 --- .../components/DocumentMetadataDrawer.svelte | 24 ++++++++--------- .../DocumentMetadataDrawer.svelte.spec.ts | 19 ++++++++++++++ .../lib/components/RelationshipBadge.svelte | 26 ------------------- .../lib/components/RelationshipPill.svelte | 10 +++++++ 4 files changed, 41 insertions(+), 38 deletions(-) delete mode 100644 frontend/src/lib/components/RelationshipBadge.svelte create mode 100644 frontend/src/lib/components/RelationshipPill.svelte diff --git a/frontend/src/lib/components/DocumentMetadataDrawer.svelte b/frontend/src/lib/components/DocumentMetadataDrawer.svelte index fd896f1c..4441fd53 100644 --- a/frontend/src/lib/components/DocumentMetadataDrawer.svelte +++ b/frontend/src/lib/components/DocumentMetadataDrawer.svelte @@ -3,7 +3,7 @@ import { m } from '$lib/paraglide/messages.js'; import { formatDate } from '$lib/utils/date'; import { formatDocumentStatus } from '$lib/utils/documentStatusLabel'; import { getInitials, personAvatarColor } from '$lib/utils/personFormat'; -import RelationshipBadge from '$lib/components/RelationshipBadge.svelte'; +import RelationshipPill from '$lib/components/RelationshipPill.svelte'; type Person = { id: string; firstName?: string | null; lastName: string; displayName: string }; type Tag = { id: string; name: string }; @@ -47,7 +47,7 @@ function getFullName(person: Person): string { } -{#snippet personCard(person: Person)} +{#snippet personCard(person: Person, relationLabel: string | null = null)} {getInitials(person.displayName)} - {getFullName(person)} + {getFullName(person)} + {#if relationLabel} + + {/if} {/snippet} @@ -98,7 +101,7 @@ function getFullName(person: Person): string {

{m.doc_details_field_sender()}

- {@render personCard(sender)} + {@render personCard(sender, inferredRelationship?.labelFromA ?? null)} {/if} {#if receivers.length > 0} @@ -107,8 +110,11 @@ function getFullName(person: Person): string { {m.doc_details_field_receivers()}

- {#each displayedReceivers as receiver (receiver.id)} - {@render personCard(receiver)} + {#each displayedReceivers as receiver, i (receiver.id)} + {@render personCard( + receiver, + i === 0 ? (inferredRelationship?.labelFromB ?? null) : null + )} {/each}
{#if hiddenReceiverCount > 0 && !showAllReceivers} @@ -122,12 +128,6 @@ function getFullName(person: Person): string { {/if} {/if} - {#if inferredRelationship} - - {/if} {:else}

{m.doc_details_no_persons()}

diff --git a/frontend/src/lib/components/DocumentMetadataDrawer.svelte.spec.ts b/frontend/src/lib/components/DocumentMetadataDrawer.svelte.spec.ts index aeda6bbe..07f3d4c5 100644 --- a/frontend/src/lib/components/DocumentMetadataDrawer.svelte.spec.ts +++ b/frontend/src/lib/components/DocumentMetadataDrawer.svelte.spec.ts @@ -81,6 +81,25 @@ describe('DocumentMetadataDrawer — persons column', () => { renderDrawer({ sender: null, receivers: [] }); await expect.element(page.getByText('Keine Personen zugeordnet')).toBeInTheDocument(); }); + + it('renders inferred relationship pills inline next to sender and receiver', async () => { + renderDrawer({ + receivers: [receivers[0]], + inferredRelationship: { labelFromA: 'Elternteil', labelFromB: 'Kind' } + }); + + // Sender link contains its pill, receiver link contains its pill. + const senderLink = page.getByRole('link', { name: /Karl Müller.*Elternteil/i }); + await expect.element(senderLink).toBeInTheDocument(); + const receiverLink = page.getByRole('link', { name: /Anna Schmidt.*Kind/i }); + await expect.element(receiverLink).toBeInTheDocument(); + }); + + it('omits the pills when no inferred relationship is provided', async () => { + renderDrawer(); + const elternteil = page.getByText('Elternteil'); + expect(await elternteil.elements()).toHaveLength(0); + }); }); // ─── Tags column ───────────────────────────────────────────────────────────── diff --git a/frontend/src/lib/components/RelationshipBadge.svelte b/frontend/src/lib/components/RelationshipBadge.svelte deleted file mode 100644 index 8de6473f..00000000 --- a/frontend/src/lib/components/RelationshipBadge.svelte +++ /dev/null @@ -1,26 +0,0 @@ - - -
-

- {m.doc_details_field_relationship()} -

-
- {labelFromA} - - {labelFromB} -
-
diff --git a/frontend/src/lib/components/RelationshipPill.svelte b/frontend/src/lib/components/RelationshipPill.svelte new file mode 100644 index 00000000..d447b326 --- /dev/null +++ b/frontend/src/lib/components/RelationshipPill.svelte @@ -0,0 +1,10 @@ + + + + {label} +