Skip to content

PDF viewer#5144

Open
bram-maegerman wants to merge 9 commits intoDSpace:mainfrom
atmire:pdf-viewer-10.0.0-next
Open

PDF viewer#5144
bram-maegerman wants to merge 9 commits intoDSpace:mainfrom
atmire:pdf-viewer-10.0.0-next

Conversation

@bram-maegerman
Copy link
Contributor

@bram-maegerman bram-maegerman commented Feb 20, 2026

References

Description

This PR adds a PDF viewer to DSpace

When enabled, users can view PDFs directly in the DSpace UI instead of downloading them. The viewer is based on ngx-extended-pdf-viewer.

Administrators can control PDF toggle the use of the viewer at community, collection, item, and bitstream levels. A new “PDF viewer” tab is added to the edit pages for communities, collections, and items, and a toggle is added to the edit bitstream page.

The file download link is updated so that when the PDF viewer is allowed, users see both a “View” (eye) and “Download” (file-download) icon instead of only a download link.

Instructions for Reviewers

To test the PDF viewer:

  1. Enable the PDF viewer for a bitstream by going to edit bitstream, and enabling the "Enable the PDF viewer for this bitstream" toggle
  2. Go to the item page, and click on the "eye" icon next to PDF bitstream on the simple item page.
  3. Verify the user get redirected to a separate page with a the PDF displayed.

List of changes in this PR:

  • Implemented a new PDF viewer based on ngx-extended-pdf-viewer.
  • Made the PDF viewer toggleable per DSO.

Checklist

This checklist provides a reminder of what we are going to look for when reviewing your PR. You do not need to complete this checklist prior creating your PR (draft PRs are always welcome).
However, reviewers may request that you complete any actions in this list if you have not done so. If you are unsure about an item in the checklist, don't hesitate to ask. We're here to help!

  • My PR is created against the main branch of code (unless it is a backport or is fixing an issue specific to an older branch).
  • My PR is small in size (e.g. less than 1,000 lines of code, not including comments & specs/tests), or I have provided reasons as to why that's not possible.
  • My PR passes ESLint validation using npm run lint
  • My PR doesn't introduce circular dependencies (verified via npm run check-circ-deps)
  • My PR includes TypeDoc comments for all new (or modified) public methods and classes. It also includes TypeDoc for large or complex private methods.
  • My PR passes all specs/tests and includes new/updated specs or tests based on the Code Testing Guide.
  • My PR aligns with Accessibility guidelines if it makes changes to the user interface.
  • My PR uses i18n (internationalization) keys instead of hardcoded English text, to allow for translations.
  • My PR includes details on how to test it. I've provided clear instructions to reviewers on how to successfully test this fix or feature.
  • If my PR includes new libraries/dependencies (in package.json), I've made sure their licenses align with the DSpace BSD License based on the Licensing of Contributions documentation.
  • If my PR includes new features or configurations, I've provided basic technical documentation in the PR itself.
  • If my PR fixes an issue ticket, I've linked them together.

@artlowel artlowel removed their request for review February 20, 2026 16:10
@tdonohue tdonohue moved this to 🙋 Needs Reviewers Assigned in DSpace 10.0 Release Feb 20, 2026
@pzlakowski pzlakowski self-requested a review February 23, 2026 11:20
@bram-maegerman bram-maegerman marked this pull request as ready for review February 23, 2026 13:45
Copy link

@pzlakowski pzlakowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have checked the code and integration part seems ok. I have narrowed a few cases in PR comments.

Checklist:

  • Check inherit of metadata
  • Check library health, license
  • Check if viewer works
    • including multi-page pdf to test route changes
  • Check logic when viewer should be visible
  • Accessibility
  • Lint check
  • Review design of feature
  • Tests

Feature feature logic:

In the config we have:

# Whether to enable the PDF viewer for Bitstreams (i.e. Bitstreams whose MIME type starts with 'application/pdf').
pdfViewer:
  enabled: true

I understand this feature requires to be enabled to be functional. When we follow this logic there are rough edges to handle:

  1. If document has dspace.pdfviewer.enabled set to true, it ignores feature flag
  2. When we do not set enabled to false it will fallback to true thus feature will be enabled

I have marked specific parts of code responsible for it. Please tell if I think wrongly here.

isFullscreen store:

My question is whether this state is tracked only for debugging purposes. This is ok for me to stay but I wonder whether there was any other rationale about it. I assume this is just to check a transition between DSO page <=> pdf viewer.

Priority hierarchy:

This is just for documentation purposes.

Given structure Community > Collection > Item > Bitstream

  1. Children will inherit metadata from parent
  2. The last hierarchical element tells whenever PDF Viewer will be enabled or not
    • From parent to grandchildren the value is passed as default value but in the end bitstream is aggregate responsible to tell whenever to display it

This behaviour in my opinion is ok.

Accessibility:

Collection page:

Image

Community page:

Image

There is lack of margin between back nad save button. There is global class space-children-mr to handle it.

I have checked item, bitstream page and there is everything ok.

Tests:

I think I would research places where we can add tests. The good start would be:

  • PdfViewerService
  • PdfViewerEnableComponent
  • EditBitstreamPageComponent

matomo?: MatomoConfig;
geospatialMapViewer: GeospatialMapConfig;
accessibility: AccessibilitySettingsConfig;
pdfViewer?: { enabled: boolean };

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move it to the interface like any other feature does it since it is common pattern in the application.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look at default-app-config.ts and specify default enabled value like you did for environment.test.ts. This will make code more ergonomic since you do not need to chain ?. everywhere.

}),
filter((dso: DSpaceObject) => hasValue(dso)),
toArray(),
map((dsos: DSpaceObject[]) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the logic should be conjunctive:

isNotEmpty(dsosWithViewerInfo) && !!environment.pdfViewer?.enabled

Otherwise we allow to run PDF Viewer even when feature is disabled by configuration. Please tell me if I think wrongly here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current logic tells that if key is not present then it should fallback as enabled. This connects to former comment whenever it should not be set to false as default.

environment.pdfViewer?.enabled ?? true;

/**
* Service to check permissions for PDF viewer
*/
export class PdfViewerService {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use naming conventions for observables e.g. isViewerEnabled$. The dollar suffix sign tells it is observable.

}
<ng-container *ngTemplateOutlet="content"></ng-container>
<span>
<a [routerLink]="pdfViewerPath" [ngClass]="cssClasses"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there should be set role to link for a11y improvements for anchor tag.

title="{{'pdf-viewer.link.view' | translate}}">
<i class="fa fa-eye ms-2" ngbTooltip="{{'pdf-viewer.link.view' | translate}}"
container="body"></i></a>
<a [routerLink]="(bitstreamPath$| async)?.routerLink" [queryParams]="(bitstreamPath$| async)?.queryParams"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there should be set role to link for a11y improvements for anchor tag.

@tdonohue tdonohue requested a review from atarix83 February 26, 2026 15:39
@tdonohue tdonohue moved this from 🙋 Needs Reviewers Assigned to 👀 Under Review in DSpace 10.0 Release Feb 26, 2026
@saschaszott
Copy link
Contributor

saschaszott commented Feb 26, 2026

We should assess the stability of the ngx-extended-pdf-viewer project. The project appears to be maintained by a single main developer and contains almost 20,000 lines of TypeScript code under projects/ngx-extended-pdf-viewer/src. We should evaluate alternative libraries before deciding whether to rely on ngx-extended-pdf-viewer.
A key question is whether the project is backed by a company or if it is primarily a personal/hobby project.

$ cloc ngx-extended-pdf-viewer/projects/ngx-extended-pdf-viewer/src
     339 text files.
     324 unique files.
      15 files ignored.

github.com/AlDanial/cloc v 2.08  T=0.23 s (1390.2 files/s, 151349.6 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
TypeScript                     204           3761           2207          19033
SCSS                            15           1231            400           6051
HTML                            72             31             16           1795
CSS                             33            114             26            609
-------------------------------------------------------------------------------
SUM:                           324           5137           2649          27488
-------------------------------------------------------------------------------

@bram-maegerman
Copy link
Contributor Author

Thanks for the feedback on this @pzlakowski!

I Confirmed that pdf-viewer-service.ts#isViewerEnabled$ was indeed enabling the pdf-viewer even when the configured pdfViewer.enabled value was false -> made the suggested change
All other suggested changes seemed very reasonable -> should all be implemented

I added tests for:

  • pdf-viewer-service
  • pdf-viewer-enable
  • pdf-viewer-page
  • pdf-viewer-fullscreen-service

Please let me know if there is any other feedback!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: 👀 Under Review

Development

Successfully merging this pull request may close these issues.

Integrated PDF viewer

4 participants