Commit Graph

11 Commits

Author SHA1 Message Date
Marcel
0f4c844002 fix(admin/system): address second-round review concerns
All checks were successful
CI / Unit & Component Tests (pull_request) Successful in 3m9s
CI / OCR Service Tests (pull_request) Successful in 16s
CI / Backend Unit Tests (pull_request) Successful in 4m29s
CI / fail2ban Regex (pull_request) Successful in 38s
CI / Compose Bucket Idempotency (pull_request) Successful in 55s
CI / Unit & Component Tests (push) Successful in 3m8s
CI / OCR Service Tests (push) Successful in 16s
CI / Backend Unit Tests (push) Successful in 4m25s
CI / fail2ban Regex (push) Successful in 38s
CI / Compose Bucket Idempotency (push) Successful in 55s
- Extract ImportStatus type to types.ts — removes duplication across
  +page.svelte, ImportStatusCard.svelte, and test file (Felix blocker)
- Fix H2 to match CLAUDE.md card pattern: text-xs uppercase tracking-widest
  text-ink-3 mb-5 (Leonie blocker 1)
- Add font-sans to RUNNING and DONE status labels (Leonie blocker 2)
- Add data-testid="processed-count" to count elements in both states
- Replace document.querySelector with locator API in spinner tests
- Tighten getByText('7') to getByTestId('processed-count') (Felix/Sara)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 16:27:33 +02:00
Marcel
b7744667f2 fix(admin/system): address review concerns in ImportStatusCard
- Remove dead `message` field from both frontend ImportStatus types
  (field is now @JsonIgnore'd on the backend)
- Extract failure message ternary into `$derived` — business logic off
  the template (Felix)
- Add motion-reduce:animate-none to spinner — WCAG 2.1 SC 2.3.3 (Leonie)
- Replace text-green-600 with text-green-800 — WCAG AA contrast 6.1:1
  on bg-green-50 (Leonie)
- Add min-h-[44px] to all three buttons — WCAG 2.2 44px touch target (Leonie)
- Add 6 missing tests: IMPORT_FAILED_INTERNAL path, IDLE state text,
  null importStatus, ontrigger called on DONE/FAILED/IDLE buttons (Sara)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 14:37:04 +02:00
Marcel
375fd3893c feat(admin/system): extract ImportStatusCard — spinner, text-base count, statusCode i18n
Extracts the mass-import block from +page.svelte into ImportStatusCard.svelte.

Changes per the three UX fixes from issue #533:
- RUNNING: animated spinner (animate-spin) + processed count at text-base;
  auto-poll at 2 s was already in place
- DONE: processed count at text-base, label at text-xs uppercase tracking-widest
- FAILED: maps statusCode (IMPORT_FAILED_NO_SPREADSHEET / IMPORT_FAILED_INTERNAL)
  to Paraglide messages — no raw German backend string rendered

Adds vitest-browser tests covering spinner visibility, count display,
and per-statusCode FAILED message selection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 14:37:04 +02:00
Marcel
7bb3800490 feat(frontend): add admin card to generate thumbnails with polling
Fourth card on /admin/system mirrors the mass-import pattern:
- POST /api/admin/generate-thumbnails to trigger
- 2000 ms polling on /api/admin/thumbnail-status while RUNNING
- processed / skipped / failed counters in the DONE message
- standalone pollInterval so import and thumbnail polling don't
  interfere with each other

Paraglide keys added in de/en/es, mirroring admin_system_import_*.

Refs #307

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 22:39:47 +02:00
Marcel
cea1234400 feat(ocr): move training cards from system page to OCR overview page
OcrTrainingCard and SegmentationTrainingCard now live on the dedicated
OCR overview page. System page no longer fetches training info.
SegmentationTrainingCard updated to use shared TrainingRun type.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 10:52:23 +02:00
Marcel
1fd5c31fd1 fix(training): pass trainingInfo directly to SegmentationTrainingCard
The parent was manually remapping availableSegBlocks → availableBlocks
before passing props, which broke after the card was updated to read
availableSegBlocks directly. Pass the full trainingInfo object instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 17:55:16 +02:00
Marcel
86e9c05aaf feat(training): add Paraglide i18n to training UI components and wire SegmentationTrainingCard
- Convert TrainingHistory, OcrTrainingCard, SegmentationTrainingCard, and
  TranscriptionBlock "Nur Segmentierung" badge to use Paraglide message keys
- Add availableSegBlocks to TrainingInfoResponse to expose segmentation
  block count in the training info endpoint
- Wire SegmentationTrainingCard into admin/system page below OCR training card
- Update api.ts with availableSegBlocks field

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 15:14:27 +02:00
Marcel
4e08d31e01 feat(admin): add OCR training card to admin/system page
- TrainingHistory.svelte: responsive table with status badges
  (green/red/animated pulse), keyed iteration, empty-state row
- OcrTrainingCard.svelte: shows available blocks/docs, disabled states
  (< 5 blocks, service down), in-flight "…" state, 5s success message,
  embeds TrainingHistory
- Wired into admin/system/+page.svelte via fetchTrainingInfo() in $effect
- Regenerated api.ts with OcrTrainingRun + TrainingInfoResponse types
- TRAINING_ALREADY_RUNNING error code in errors.ts + de/en/es translations
- 7 OcrTrainingCard Vitest tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 14:58:13 +02:00
Marcel
393cb52178 fix(admin): address PR review feedback from all personas
Blockers resolved:
- localStorage key collision: UsersListPanel/GroupsListPanel/TagsListPanel
  now each use their own key (admin_*_list_collapsed)
- $effect autocollapse replaced with $derived(autocollapse || manualCollapse)
  across all three list panels (Felix — Svelte 5 rule violation)
- groups/new: add READ_ALL and ANNOTATE_ALL to available standard permissions
- Mobile back-to-list links added to all five detail panel headers (md:hidden)
  so users landing directly on a detail URL on mobile can navigate back
- onDestroy(() => stopPolling()) added to system/+page.svelte (Tobias)

High priority resolved:
- Permission labels in groups/[id] and groups/new now use Paraglide i18n keys
  (admin_perm_read_all, admin_perm_annotate_all, etc.) across de/en/es
- $derived used for permission arrays (reactive i18n) — Felix Svelte 5 rule
- UserGroup type in +layout.server.ts now uses generated API type (Markus/Felix)
- discardTarget annotation changed to variable-level type annotation

Accessibility (Leonie):
- EntityNav tablet icon strip buttons: min-h-[44px] for WCAG 2.5.8 compliance
- Flyout focus management: openFlyout() focuses first link, closeFlyout()
  returns focus to the trigger button that opened it
- Flyout animation replaced: broken inline style -> transition:fly={{ x: -160 }}

Tests (Sara/Felix):
- localStorage key assertion tests added per panel
- localStorage.removeItem calls updated to use the panel-specific keys
- page.server.spec.ts added for groups/[id] and tags/[id] delete actions
- Polling lifecycle tests added to system/page.svelte.spec.ts

Note: Paraglide types for new admin_perm_* keys regenerate automatically on
next npm run dev (Vite plugin). No manual compilation step needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 11:23:27 +02:00
Marcel
9996055cac feat(admin): mass import card on system tab with live status polling
Adds a new card on the System tab that triggers the existing
POST /api/admin/trigger-import endpoint. Status is polled every 2 s
while RUNNING and stops automatically on DONE or FAILED.
IDLE/RUNNING/DONE/FAILED states each render distinct UI feedback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 09:42:44 +02:00
Marcel
cee16c1657 feat(admin/system): add system maintenance page under /admin/system
Moves the system maintenance panel out of the old tab-based admin page
and into a dedicated route. Renders maintenance cards with spinner state
and success message on completion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 01:39:09 +02:00