feat(bulk-edit): extend BulkDocumentEditLayout with mode="edit"

- New FieldLabelBadge component (additive / replace variants, WCAG AA contrast)
- WhoWhenSection: hideDate prop, editMode prop renders badges next to sender
  and receivers, hides the meta_location field
- DescriptionSection: editMode prop renders badges next to tags and archive
  fields; new bindable archiveBox / archiveFolder inputs only in editMode
- PersonTypeahead: optional badge prop forwards to FieldLabelBadge
- FileSwitcherStrip FileEntry: file is now optional, documentId added so
  edit-mode entries reference an existing document by UUID
- BulkDocumentEditLayout: mode prop branches drop zone / read-only title /
  callout / save handler. Edit save chunks 500 IDs per PATCH, stops on chunk
  failure with retry, marks per-document errors as chips, clears the bulk
  selection store on full success.

Refs #225

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-25 15:16:06 +02:00
parent d4f32ed5d4
commit fa5dc43864
8 changed files with 610 additions and 110 deletions

View File

@@ -0,0 +1,30 @@
import { afterEach, describe, expect, it } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import FieldLabelBadge from './FieldLabelBadge.svelte';
afterEach(() => cleanup());
describe('FieldLabelBadge', () => {
it('renders the additive variant text', async () => {
render(FieldLabelBadge, { variant: 'additive' });
await expect.element(page.getByTestId('field-label-badge-additive')).toBeInTheDocument();
await expect
.element(page.getByTestId('field-label-badge-additive'))
.toHaveTextContent('+ wird hinzugefügt');
});
it('renders the replace variant text', async () => {
render(FieldLabelBadge, { variant: 'replace' });
await expect
.element(page.getByTestId('field-label-badge-replace'))
.toHaveTextContent('wird ersetzt');
});
it('uses text-gray-600 for WCAG-AA contrast on muted backgrounds', async () => {
render(FieldLabelBadge, { variant: 'replace' });
await expect
.element(page.getByTestId('field-label-badge-replace'))
.toHaveClass(/text-gray-600/);
});
});