Skip to content

DN-3497 Implement react-pdf-highlighter-extended and create POC#43

Open
danielleklaasen wants to merge 3 commits intomainfrom
DN-3497-POC
Open

DN-3497 Implement react-pdf-highlighter-extended and create POC#43
danielleklaasen wants to merge 3 commits intomainfrom
DN-3497-POC

Conversation

@danielleklaasen
Copy link
Copy Markdown
Contributor

@danielleklaasen danielleklaasen commented Mar 10, 2026

Uses: UvA-FNWI/workflow-api#96


PDF Review & Annotation — POC

What is this?

This POC adds inline PDF reviewing and annotation directly inside the workflow UI. Reviewers can open a submitted PDF, highlight text or areas, leave comments, and have those annotations persisted to the backend.


How does it work?

User flow

  1. When a submission contains a PDF file, a "Review" button appears next to the file link in the question/answer list.
  2. Clicking "Review" opens a full-screen modal with the PDF rendered inside it.
  3. The reviewer can:
    • Highlight text by selecting it with the mouse → a tooltip appears to add a comment.
    • Highlight an area by holding Alt and dragging a rectangle → same comment tooltip.
  4. Confirmed highlights are saved to the backend immediately and are visible to all subsequent reviewers who open the same file.

Components added

File Purpose
src/components/instance/PdfReviewModal.tsx Full-screen modal wrapping the react-pdf-highlighter viewer
src/store/api/annotationsApi.ts RTK Query endpoints: GET and POST annotations
src/store/api/types/annotations.ts TypeScript types for annotation data (position, bounding rect, comment)

API contract

Annotations are stored and retrieved via two REST endpoints:

GET  /Annotations/{instanceId}/{submissionId}/{questionName}/{artifactId}
POST /Annotations/{instanceId}/{submissionId}/{questionName}/{artifactId}

Each annotation payload:

{
  "id": "...",
  "highlightedText": "The selected text",
  "comment": "Reviewer comment",
  "position": {
    "boundingRect": { "x1": 0, "y1": 0, "x2": 100, "y2": 20, "width": 595, "height": 842 },
    "rects": [...],
    "pageNumber": 2
  }
}

The position format is defined by react-pdf-highlighter-extended and stored in this format (no transformation is done on the backend).

Key dependency

react-pdf-highlighter-extended — a React library built on top of pdf.js that handles PDF rendering, text layer extraction, coordinate mapping, and highlight rendering out of the box.

Limitations of the current POC

  • No update or delete — annotations can only be added, not edited or removed.
  • No annotation list — there is no sidebar listing all highlights; you can only see them rendered on the PDF.
  • Area highlight "change" re-creates — dragging an existing area highlight calls createAnnotation rather than a dedicated update endpoint; this creates duplicates.
  • No i18n — the "Review" button label is hardcoded in English.
  • No loading/error states — the modal shows a plain "Loading PDF…" text and has no error handling if the PDF fails to load.
  • Inline styles — the modal height is set with an inline style={{height: "70vh"}} instead of Tailwind.
  • No access control — any user who can view the submission can annotate.

Next steps

1. Backend completeness

Endpoint needed Priority
DELETE /Annotations/.../{annotationId} High
PUT /Annotations/.../{annotationId} Medium
Pagination or filtering for large numbers of annotations Low

2. Replace area highlight re-creation with a proper update

The AreaHighlight.onChange callback currently calls createAnnotation. Wire it to a updateAnnotation mutation instead, and pass the annotation id to avoid duplicates.

3. Add a highlights sidebar

react-pdf-highlighter is designed to work alongside a sidebar that lists all highlights. Clicking a highlight in the list should call scrollViewerTo (already wired up via useRef) to scroll the PDF to that position. This makes reviewing manageable for long documents.

4. Internationalise

Add translation keys for "Review", "Loading PDF…", and any future annotation UI strings, then run pnpm translations:generate.

5. Polish the modal UI

  • Replace style={{height: "70vh"}} with a Tailwind class (e.g. h-[70vh]).
  • Add a proper skeleton/spinner while the PDF loads.
  • Add an error boundary or fallback if PdfLoader fails (e.g. expired URL, network error).

6. Permissions

Decide who may annotate (e.g. only reviewers, not submitters). Gate the "Review" button and the API calls behind the appropriate role check, consistent with how the rest of the app handles impersonation and roles.

7. Performance

Large PDFs can be slow. Consider:

  • Lazy-loading only the pages visible in the viewport (already handled by pdf.js internally, but verify).
  • Caching the annotation fetch result aggressively — annotations don't change often mid-session.

Summary

The POC proves that end-to-end PDF annotation — render, select, highlight, persist, reload — is achievable with a small amount of code. The core technical risk is resolved. The remaining work is primarily UX polish, backend completion, and productionising the edge cases listed above.

@danielleklaasen danielleklaasen self-assigned this Mar 10, 2026
@danielleklaasen danielleklaasen changed the title DN-3497-POC Implement react-pdf-highlighter-extended and create POC DN-3497 Implement react-pdf-highlighter-extended and create POC Mar 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant