feat(#68): lead new document form with file upload, all metadata optional
Some checks failed
CI / Unit & Component Tests (push) Failing after 1m17s
CI / Backend Unit Tests (push) Failing after 9h3m48s
CI / E2E Tests (push) Failing after 28m15s

Restructure the "New Document" page so users can save quickly:

- FileSectionNew becomes the first element, redesigned as a prominent
  upload zone with an icon and large click target
- Title field is rendered standalone below the upload zone; it
  auto-populates from the filename (via parseFilename + stripExtension
  fallback) unless the user has already typed something
- All remaining metadata (who/when, description, transcription) moves
  into a collapsible "Weitere Details" section that auto-expands when
  URL prefill data or a form error is present, or when filename parsing
  detects a date/person
- title is no longer required — the form can be saved with only a file
- DescriptionSection gains a `hideTitle` prop for use in this layout
- `form_label_title` translation key no longer carries a hardcoded `*`;
  the asterisk is rendered by the template only when `titleRequired` is
  set (currently only the edit form)
- E2E tests added for all three scenarios from the issue

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-03-26 22:52:12 +01:00
parent d6f4ea05d9
commit c5e28ac18e
7 changed files with 203 additions and 67 deletions

View File

@@ -77,12 +77,49 @@ test.describe('Document detail', () => {
});
test.describe('New document', () => {
test('renders the upload form', async ({ page }) => {
test('renders the upload form with file input first', async ({ page }) => {
await page.goto('/documents/new');
await page.waitForSelector('[data-hydrated]');
await expect(page.getByRole('heading', { name: /Neues Dokument/i })).toBeVisible();
await expect(page.getByLabel('Titel')).toBeVisible();
// File input comes before the title field in DOM order
const fileInput = page.locator('input[type="file"]');
const titleInput = page.getByLabel('Titel');
await expect(fileInput).toBeVisible();
await expect(titleInput).toBeVisible();
const fileBox = await fileInput.boundingBox();
const titleBox = await titleInput.boundingBox();
expect(fileBox!.y).toBeLessThan(titleBox!.y);
await page.screenshot({ path: 'test-results/e2e/document-new.png' });
});
test('title field is pre-filled from filename when a file is selected', async ({ page }) => {
await page.goto('/documents/new');
await page.waitForSelector('[data-hydrated]');
const PDF_FIXTURE = path.resolve(__dirname, 'fixtures/minimal.pdf');
const fileInput = page.locator('input[type="file"]');
await fileInput.setInputFiles({
name: 'Brief_1965.pdf',
mimeType: 'application/pdf',
buffer: fs.readFileSync(PDF_FIXTURE)
});
await expect(page.getByLabel('Titel')).toHaveValue('Brief_1965');
await page.screenshot({ path: 'test-results/e2e/document-new-filename-prefill.png' });
});
test('typed title is not overwritten when a file is selected', async ({ page }) => {
await page.goto('/documents/new');
await page.waitForSelector('[data-hydrated]');
await page.getByLabel('Titel').fill('Weihnachtsbrief 1965');
const PDF_FIXTURE = path.resolve(__dirname, 'fixtures/minimal.pdf');
const fileInput = page.locator('input[type="file"]');
await fileInput.setInputFiles({
name: 'Brief_1965.pdf',
mimeType: 'application/pdf',
buffer: fs.readFileSync(PDF_FIXTURE)
});
await expect(page.getByLabel('Titel')).toHaveValue('Weihnachtsbrief 1965');
await page.screenshot({ path: 'test-results/e2e/document-new-title-not-overwritten.png' });
});
});
test.describe('Document creation', () => {
@@ -97,6 +134,21 @@ test.describe('Document creation', () => {
await expect(page.getByRole('heading', { name: 'E2E Testbrief' })).toBeVisible();
await page.screenshot({ path: 'test-results/e2e/document-create.png' });
});
test('user saves a document with only a file — title comes from filename', async ({ page }) => {
await page.goto('/documents/new');
await page.waitForSelector('[data-hydrated]');
const PDF_FIXTURE = path.resolve(__dirname, 'fixtures/minimal.pdf');
await page.locator('input[type="file"]').setInputFiles({
name: 'Brief_1965.pdf',
mimeType: 'application/pdf',
buffer: fs.readFileSync(PDF_FIXTURE)
});
await page.getByRole('button', { name: 'Speichern', exact: true }).click();
await expect(page).toHaveURL(/\/documents\/[^/]+$/);
await expect(page.getByRole('heading', { name: 'Brief_1965' })).toBeVisible();
await page.screenshot({ path: 'test-results/e2e/document-create-file-only.png' });
});
});
test.describe('Document editing', () => {