## Summary Implements the bulk "Alle als fertig markieren" action for the transcription panel requested in #345. ### Backend - Added `PUT /api/documents/{documentId}/transcription-blocks/review-all` endpoint to `TranscriptionBlockController`, guarded with `@RequirePermission(Permission.WRITE_ALL)` - Added `markAllBlocksReviewed(UUID documentId, UUID userId)` to `TranscriptionService` — `@Transactional`, single DB round-trip via `blockRepository.saveAll()`, emits one `BLOCK_REVIEWED` audit event per previously-unreviewed block - Returns full updated block list (same shape as `listBlocks`) for a clean frontend update pass - 5 new `TranscriptionServiceTest` unit tests (idempotency, audit events, empty document) - 5 new `TranscriptionBlockControllerTest` `@WebMvcTest` tests (401, 403, 200 happy path, 200 empty, 401 user not found) - All 68 backend tests pass ### Frontend - Added `onMarkAllReviewed?: () => Promise<void>` prop to `TranscriptionEditView` (optional, consistent with `onTriggerOcr` pattern) - Button placed in sticky progress header, right-aligned next to `reviewedCount / totalCount geprüft` - Button is **disabled** (not hidden) when all blocks are already reviewed — `title="Alle Blöcke sind bereits als fertig markiert"` (Decision 1) - Loading spinner replaces checkmark icon during operation — always shown (Decision 4, no threshold) - Handler `markAllReviewed()` added to `documents/[id]/+page.svelte`, wired as `onMarkAllReviewed` - 5 new `TranscriptionEditView.svelte.spec.ts` Vitest Browser component tests; all 25 tests pass ### Decisions applied | # | Question | Choice | |---|---|---| | 1 | Button when all reviewed | **Disabled** with `title` tooltip | | 2 | Audit log | **N individual BLOCK_REVIEWED events** (one per unreviewed block) | | 3 | Atomicity | **All-or-nothing** via `@Transactional` | | 4 | Loading indicator | **Always show** during operation | Closes #345 Co-authored-by: Marcel <marcel@familienarchiv> Reviewed-on: http://heim-nas:3005/marcel/familienarchiv/pulls/352
This commit was merged in pull request #352.
This commit is contained in:
@@ -90,6 +90,15 @@ public class TranscriptionBlockController {
|
||||
return transcriptionService.reviewBlock(documentId, blockId, userId);
|
||||
}
|
||||
|
||||
@PutMapping("/review-all")
|
||||
@RequirePermission(Permission.WRITE_ALL)
|
||||
public List<TranscriptionBlock> markAllBlocksReviewed(
|
||||
@PathVariable UUID documentId,
|
||||
Authentication authentication) {
|
||||
UUID userId = requireUserId(authentication);
|
||||
return transcriptionService.markAllBlocksReviewed(documentId, userId);
|
||||
}
|
||||
|
||||
@GetMapping("/{blockId}/history")
|
||||
@RequirePermission(Permission.READ_ALL)
|
||||
public List<TranscriptionBlockVersion> getBlockHistory(
|
||||
|
||||
@@ -205,6 +205,18 @@ public class TranscriptionService {
|
||||
return saved;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<TranscriptionBlock> markAllBlocksReviewed(UUID documentId, UUID userId) {
|
||||
List<TranscriptionBlock> blocks = blockRepository.findByDocumentIdOrderBySortOrderAsc(documentId);
|
||||
for (TranscriptionBlock block : blocks) {
|
||||
if (!block.isReviewed()) {
|
||||
block.setReviewed(true);
|
||||
auditService.logAfterCommit(AuditKind.BLOCK_REVIEWED, userId, documentId, null);
|
||||
}
|
||||
}
|
||||
return blockRepository.saveAll(blocks);
|
||||
}
|
||||
|
||||
public List<TranscriptionBlockVersion> getBlockHistory(UUID documentId, UUID blockId) {
|
||||
getBlock(documentId, blockId);
|
||||
return versionRepository.findByBlockIdOrderByChangedAtDesc(blockId);
|
||||
|
||||
Reference in New Issue
Block a user