- 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>
- OcrTrigger component rendered in the transcription empty state when
the document has a file and user has write permission
- Review checkmark toggle on each TranscriptionBlock (turquoise when
reviewed, muted outline when not). Calls PUT .../review to toggle.
- TranscriptionBlockData type: added source + reviewed fields
- +page.svelte: triggerOcr() and reviewToggle() functions wired up
- Paraglide translations (de/en/es) for review toggle + reviewed count
All 687 frontend tests pass.
Refs #226, #230
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CommentThread: add missing empty-state paragraph using comment_empty_hint
i18n key (key existed but was never rendered in the template)
- TranscriptionBlock: add selectedQuote hint using transcription_block_quote_hint
i18n key (key existed but was never rendered); fix test to use native DOM
el.focus()/setSelectionRange()/dispatchEvent instead of locator.selectText()
which is not available in this vitest-browser version
- TranscriptionEditView: fix test to use native el.dispatchEvent(FocusEvent)
instead of locator.blur() which is not available
- Conversations: fix test expected text from stale "Korrespondenz durchsuchen"
to match current conv_empty_heading() = "Wessen Briefe möchten Sie lesen?"
All 687 tests now pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Own comments:
- Click the text to open inline edit (textarea replaces text)
- Enter saves, Escape cancels
- Small trash icon always visible in bottom-right corner
- Hover on text shows cursor-text + subtle bg highlight
Other people's comments: read-only, no edit/delete affordances.
Re-add currentUserId prop chain for ownership check.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Quote captured automatically on mouseup in textarea (no button needed)
Selection is held in state and pre-fills the comment input
- "Kommentieren" button only shown when zero comments exist
When comments are present, the input is already visible — button is noise
- Chat bubble icon added to Kommentieren button for visual consistency
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- MentionEditor: Enter sends (Shift+Enter for newline), remove @ button
- CommentThread: remove send button, full-width input, always show
input when comments exist (no need to click Kommentieren first)
- TranscriptionBlock: remove border-t above comment section (orange
background provides enough visual separation)
- Update placeholder in all languages to hint @mention and Enter to send
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comments were only visible after clicking "Kommentieren". Now:
- Comment list always renders (CommentThread with loadOnMount=true)
- Compose box hidden by default (showCompose prop on CommentThread)
- Clicking "Kommentieren" sets commentOpen=true → shows compose box
- Closing hides compose box but comments remain visible
This separates "viewing comments" (always) from "writing a comment"
(on demand via Kommentieren button).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comments were only shown after clicking "Kommentieren". Now:
- Load comment counts per block when blocks are loaded
- Pass commentCount prop to TranscriptionBlock
- If commentCount > 0, the comment thread is expanded by default
- If commentCount is 0, thread stays collapsed behind the button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The textarea value was bound directly to the text prop from the parent.
When auto-save completed and updated the blocks array, Svelte re-rendered
the textarea with the prop value, causing the text to disappear briefly.
Fix: use localText state initialized from prop, synced only when blockId
changes (not on save responses). Typing updates localText immediately,
parent re-renders from save don't overwrite the local value.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TranscriptionBlock.svelte:
- "Kommentieren" button opens expandable comment thread per block
- Text selection in textarea captured as quoted text (> "...") prefix
- Quote hint "Text markieren für Zitat" shown when block is active/focused
- Comment thread uses existing CommentThread with blockId prop
CommentThread.svelte:
- Add blockId prop for block-level comments URL routing
- Add quotedText prop — pre-fills comment input with markdown blockquote
- commentsBase now supports 3 URL patterns: document, annotation, block
TranscriptionEditView.svelte:
- Pass canComment + currentUserId through to block components
3 new frontend tests:
- Kommentieren button present
- Quote hint shown when active
- Quote hint hidden when inactive
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add turquoise/turquoise-fg semantic color tokens to layout.css
(light + dark mode), replacing all hardcoded #00C7B1 in components
- Bump Details toggle from text-xs to text-sm for visual hierarchy
- Block badge: navy → turquoise, overlapping top-left card border
with absolute positioning to visually link PDF annotation badges
- Saved indicator: smooth 300ms opacity fade before removal
(new 'fading' state in SaveState type)
- Transcribe buttons: use border-turquoise/bg-turquoise/text-turquoise-fg
Fixes @Leonie concerns: toggle visual weight, semantic tokens,
badge styling, saved fade animation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixes from PR #178 review:
Migration fixes:
- V18/V19: fix FK references from app_users to users (correct table name)
- V18: change annotation_id FK from ON DELETE CASCADE to ON DELETE RESTRICT
(block is aggregate root, cascade flows from block, not annotation)
Backend fixes:
- TranscriptionService.deleteBlock(): remove userId param, delete block first
then annotation directly via repository (no ownership check — block owns annotation)
- TranscriptionService.sanitizeText(): remove flawed regex HTML stripping,
textarea content is plain text by design — just enforce max length
- TranscriptionBlockController.requireUserId(): throw DomainException.unauthorized()
instead of silently returning null on auth failure
- CreateTranscriptionBlockDTO: add @Min/@Positive validation on coordinates
- Add @Slf4j logging to TranscriptionService for create/delete operations
Frontend fixes:
- Delete DocumentBottomPanel.svelte entirely (issue #175 requirement)
- Remove redundant mode exclusivity $effect (handled at toggle call sites)
- Remove dead handleCommentClick + onCommentClick prop (comments are future work)
- Remove quote hint UI (depends on comment feature)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>