feat(transcription): add bulk "Alle als fertig markieren" action to transcription panel
Some checks failed
CI / Unit & Component Tests (push) Failing after 3m31s
CI / OCR Service Tests (push) Successful in 37s
CI / Backend Unit Tests (push) Failing after 3m1s
CI / Unit & Component Tests (pull_request) Failing after 3m13s
CI / OCR Service Tests (pull_request) Successful in 30s
CI / Backend Unit Tests (pull_request) Failing after 2m57s
Some checks failed
CI / Unit & Component Tests (push) Failing after 3m31s
CI / OCR Service Tests (push) Successful in 37s
CI / Backend Unit Tests (push) Failing after 3m1s
CI / Unit & Component Tests (pull_request) Failing after 3m13s
CI / OCR Service Tests (pull_request) Successful in 30s
CI / Backend Unit Tests (pull_request) Failing after 2m57s
Adds a single-transaction backend endpoint PUT /api/documents/{id}/transcription-blocks/review-all
that marks all blocks as reviewed atomically. Emits N individual BLOCK_REVIEWED audit events (one
per previously-unreviewed block). The frontend button is disabled (not hidden) when all blocks are
already reviewed, and shows a spinner during the operation.
Closes #345
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,9 +13,12 @@ import { getErrorMessage } from '$lib/errors';
|
||||
import { translateOcrProgress } from '$lib/ocr/translateOcrProgress';
|
||||
import { createFileLoader } from '$lib/hooks/useFileLoader.svelte';
|
||||
import { scrollToCommentFromQuery } from '$lib/utils/deepLinkScroll';
|
||||
import { getConfirmService } from '$lib/services/confirm.svelte.js';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
const { confirm } = getConfirmService();
|
||||
|
||||
const doc = $derived(data.document);
|
||||
const canWrite = $derived(data.canWrite ?? false);
|
||||
const currentUserId = $derived((data.user?.id as string | undefined) ?? null);
|
||||
@@ -105,6 +108,23 @@ async function deleteBlock(blockId: string) {
|
||||
annotationReloadKey++;
|
||||
}
|
||||
|
||||
async function handleAnnotationDeleteRequest(annotationId: string) {
|
||||
const confirmed = await confirm({
|
||||
title: m.transcription_block_delete_confirm(),
|
||||
destructive: true
|
||||
});
|
||||
if (!confirmed) return;
|
||||
|
||||
const block = transcriptionBlocks.find((b) => b.annotationId === annotationId);
|
||||
if (block) {
|
||||
await deleteBlock(block.id);
|
||||
} else {
|
||||
// Annotation has no linked block — delete the annotation directly
|
||||
await fetch(`/api/documents/${doc.id}/annotations/${annotationId}`, { method: 'DELETE' });
|
||||
annotationReloadKey++;
|
||||
}
|
||||
}
|
||||
|
||||
async function reviewToggle(blockId: string) {
|
||||
const res = await fetch(`/api/documents/${doc.id}/transcription-blocks/${blockId}/review`, {
|
||||
method: 'PUT'
|
||||
@@ -114,6 +134,18 @@ async function reviewToggle(blockId: string) {
|
||||
transcriptionBlocks = transcriptionBlocks.map((b) => (b.id === blockId ? updated : b));
|
||||
}
|
||||
|
||||
async function markAllReviewed() {
|
||||
const res = await fetch(`/api/documents/${doc.id}/transcription-blocks/review-all`, {
|
||||
method: 'PUT'
|
||||
});
|
||||
if (!res.ok) return;
|
||||
const updated = await res.json();
|
||||
for (const b of updated) {
|
||||
const existing = transcriptionBlocks.find((x) => x.id === b.id);
|
||||
if (existing) existing.reviewed = b.reviewed;
|
||||
}
|
||||
}
|
||||
|
||||
async function toggleTrainingLabel(label: string, enrolled: boolean) {
|
||||
const res = await fetch(`/api/documents/${doc.id}/training-labels`, {
|
||||
method: 'PATCH',
|
||||
@@ -381,6 +413,7 @@ onMount(() => {
|
||||
bind:activeAnnotationId={activeAnnotationId}
|
||||
onAnnotationClick={handleAnnotationClick}
|
||||
onTranscriptionDraw={createBlockFromDraw}
|
||||
onDeleteAnnotationRequest={handleAnnotationDeleteRequest}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -477,6 +510,7 @@ onMount(() => {
|
||||
onSaveBlock={saveBlock}
|
||||
onDeleteBlock={deleteBlock}
|
||||
onReviewToggle={reviewToggle}
|
||||
onMarkAllReviewed={markAllReviewed}
|
||||
onTriggerOcr={triggerOcr}
|
||||
onToggleTrainingLabel={toggleTrainingLabel}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user