feat(viewer): drop the bundled viewer app for @nextcloud/viewer - #63954
Open
skjnldsv wants to merge 10 commits into
Open
feat(viewer): drop the bundled viewer app for @nextcloud/viewer#63954skjnldsv wants to merge 10 commits into
skjnldsv wants to merge 10 commits into
Conversation
skjnldsv
force-pushed
the
feat/merge-viewer
branch
from
September 2, 2026 12:26
92e753a to
c0f841d
Compare
skjnldsv
force-pushed
the
feat/merge-viewer
branch
2 times, most recently
from
September 2, 2026 12:50
8018718 to
7a2fb77
Compare
skjnldsv
marked this pull request as ready for review
September 8, 2026 06:58
skjnldsv
requested review from
CarlSchwan,
kristian-zendato,
leftybournes,
salmart-dev,
sorbaugh and
susnux
and removed request for
a team
September 8, 2026 06:58
skjnldsv
force-pushed
the
feat/merge-viewer
branch
3 times, most recently
from
September 9, 2026 00:31
88fcb71 to
59fecf7
Compare
skjnldsv
force-pushed
the
feat/merge-viewer
branch
from
September 9, 2026 08:16
93ec687 to
bc519a9
Compare
This comment was marked as resolved.
This comment was marked as resolved.
22 tasks
Member
Author
|
Tracking issue for all of this, including the apps outside the organisation: nextcloud-libraries/nextcloud-viewer#17 |
This was referenced Sep 9, 2026
The viewer's own end-to-end suite lived in its repository and ran against a server it provisioned itself. It belongs here: what it covers is the viewer opening files out of the Files list, out of a public share, and out of a folder, none of which the library can exercise on its own. The specs run on the server's Playwright harness, with a ViewerPage section and a fixture for it, and the harness gained a port override so several checkouts can run at once. Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
Which mimes the server can render a preview for decides what a client offers to open: heic, heif and tiff are viewable through a preview and not otherwise. That list was an initial state the viewer app provided on every page, so anything wanting it had to be on a page that app had touched. As a capability it is where clients already look, public share pages included, and no app has to provide it. Reading it costs nothing: the preview manager registers closures and instantiates no provider, and it reports nothing at all when previews are turned off. Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
The viewer arrives as @nextcloud/viewer now rather than as an app of its own, and something has to put it on the page. The files app is the one that owns file actions, which is what a viewer handler registers, so it takes the job over from the viewer app's own listener, on the same event and with the same reach: every page a file can be opened from, not only the Files list. The script does nothing but import the package, which registers the handlers for images, video and audio. The viewer itself is fetched when a file is opened. Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
Viewer 7.0.0 dropped the OCA.Viewer global. Three callers were still on it: the versions sidebar, the "Open online" button of the open locally dialog, and the pdf link in the admin settings. The new API takes nodes, so the versions sidebar builds one for the version it shows, pointing at the version's own dav endpoint rather than at the 250px thumbnail meant for the list; the open-locally action passes the node and the folder listing it already has; and the settings link looks its file up over dav. Whether to offer the "View" button is canView() from the package, the same test the click-to-open action uses. Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
Nothing needs it any more: the handlers come from @nextcloud/viewer, the files app puts the init script on every page, and the enabled preview providers are a core capability. With it goes the LoadViewer event, which three places dispatched behind a class_exists() guard to ask the app to load itself. An app that wants a file view imports the package and registers a handler; it no longer matters whether the viewer app is enabled, or which app got there first. The app config rows left behind on an upgrade are cleaned up by the repair step that already does this for the other apps we dropped. Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
The viewer is loaded from core rather than from the files app: it affects every page a file can be opened from, not only the Files list, so the listener and the init script belong there. The init script calls registerDefaultHandlers() rather than relying on the side effect of importing the package. @nextcloud/image-editor and @skjnldsv/vue-plyr were left behind by the move to the package, which brings both itself. Nothing in the server imports either. The media fixtures join the other test data in tests/data/media, with their license annotations, and the playwright server timeout drops to the five minutes CI uses rather than fifteen. Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
The init script was in the legacy webpack build, which is where the
files app lives, but that build is vue 2.7 and the viewer library is
vue 3. It only worked because the library sits in the root node_modules
and resolution walked up to vue 3 there rather than to the 2.7 in
build/frontend-legacy. Aliasing vue in that build would have broken it.
It builds with the vite frontend now, where the viewer app's own entry
used to be, referenced by relative path: a `core` symlink next to the
`apps` ones makes eslint resolve a different config for the whole run
and reports 122 errors in files nothing here touches.
camelcase, dompurify and vue-material-design-icons came in with the
vendored viewer and are already declared, at the same versions, in
build/frontend-legacy where the code using them is built. Master has
none of the three at the root, so this drops them and the only
dependency this adds is @nextcloud/viewer.
The event listener registration in the files app went with the class
that moved to core, which psalm caught:
UndefinedClass: Class, interface or enum named
OCA\Files\Listener\LoadViewerListener does not exist
Assisted-by: ClaudeCode:claude-opus-5
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
php-cs, rector-summary and strict all fail on the same one line diff: the OC\Template\LoadViewerListener import went next to the other listeners rather than into its own namespace group. Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
skjnldsv
force-pushed
the
feat/merge-viewer
branch
from
September 9, 2026 17:47
38affdd to
8fbe560
Compare
Member
Author
|
object storage failures unrelated |
Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
viewerapp into server repository #60480Summary
The viewer used to be a bundled app that every other app had to check for before
it could register a handler. It is a library now —
@nextcloud/viewer, innextcloud-libraries/nextcloud-viewer —
and this drops the app.
An app that wants to add a file view imports the package and registers its
handler. It no longer matters whether the viewer app is enabled, or which app
loaded it first: several copies on a page elect the newest between them, and only
that copy fetches the viewer, only when a file is opened.
What is left in the server
apps/filesputs a thirteen line init script on every page a file can be openedfrom, on the same event the viewer app's own listener used. The script does
nothing but import the package; the handlers for images, video and audio come
with it.
dist/files-viewer-init.jsis 24 kB, 8.3 kB gzipped.LoadViewergoes with the app. Three places dispatched it behind aclass_exists()guard to ask the app to load itself; none of them need to now.enabled_preview_providers becomes a core capability
Which mimes have a preview provider decides what the viewer offers to open — heic,
heif and tiff are viewable through a preview and not otherwise. That was an
initial state the viewer app provided, so anything wanting it had to be on a page
that app had touched. It is
core.previews.enabled_providersnow, next to thecapabilities clients already read, public share pages included.
PreviewManager::getProviders()registers closures and instantiates no provider,so this costs nothing per request, and it reports nothing when previews are off.
OCA.Viewer is gone, and three callers were still on it
Viewer 7.0.0 dropped the global. These do nothing on current master:
They take nodes now. The versions sidebar builds one for the version it shows,
pointing at the version's own dav endpoint rather than at the 250px thumbnail
meant for the list;
canView()from the package decides whether to offer thebutton, which is the same test the click-to-open action uses.
Third-party apps calling
OCA.Viewer.open()— Photos, Talk, Deck, Mail,Collectives — need to move to the package. There is no shim.
Testing
tests/playwright/e2e/viewer/, which comes over from the viewer's ownrepository in the first commit: 46 passed, 1 skipped
versionToNodeand the capabilitytests/lib/OCS/CoreCapabilitiesTest.php,tests/lib/AppTest.php,tests/lib/App/AppManagerTest.phpUpgrades:
viewerjoins the abandoned appsCleanUpAbandonedAppsalreadycleans the config rows for.
TODO
OCA.ViewerAPI and theLoadViewereventChecklist
3. to review, feature component)stable32)AI (if applicable)