Skip to content

feat(viewer): migrate to @nextcloud/viewer package API - #9235

Open
skjnldsv wants to merge 1 commit into
mainfrom
feature/migrate-new-viewer-api
Open

skjnldsv wants to merge 1 commit into
mainfrom
feature/migrate-new-viewer-api

Conversation

@skjnldsv

@skjnldsv skjnldsv commented Sep 22, 2026 •

Copy link
Copy Markdown
Member

📝 Summary

Migrates the text viewer handler registration from the legacy OCA.Viewer.registerHandler() global to registerHandler() from @nextcloud/viewer, following the removal of the bundled viewer app in favour of the @nextcloud/viewer package.

What changed:

  • src/viewer.js: registers oca-text-viewer as a custom element (via Vue's defineCustomElement with shadowRoot: false) and calls registerHandler() from @nextcloud/viewer instead of OCA.Viewer.registerHandler()
  • src/views/TextViewerWrapper.vue: new thin wrapper that maps the new IFile-based ViewerProps (file, files, editing, …) to the existing ViewerComponent props (filename, fileid, mime)
  • lib/Listeners/LoadViewerListener.php: rewritten to listen on OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent (fires on every non-error page) instead of the now-gone OCA\Viewer\Event\LoadViewer; loads text-viewer as an init script
  • lib/AppInfo/Application.php: updated event listener registration accordingly; drops the dead OCA\Viewer import
  • Adds @nextcloud/viewer ^2.0.0-beta.11 dependency

canCompare and downloadCallback are not part of the new IHandler API and have been dropped.

🖼️ Screenshots

No UI change: the viewer behaviour is unchanged.

🏁 Checklist

  • Code is properly formatted (npm run lint / npm run stylelint / composer run cs:check)
  • Sign-off message is added to all commits
  • Tests (unit, integration and/or end-to-end) passing and the changes are covered with tests
  • Documentation (README or documentation) has been updated or is not required

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI tools
  • The AI-generated content was reviewed, comprehended and tested by a human

@skjnldsv skjnldsv added the enhancement New feature or request label Sep 22, 2026
@skjnldsv
skjnldsv force-pushed the feature/migrate-new-viewer-api branch 2 times, most recently from 8f4b8b4 to a6ddb27 Compare September 23, 2026 07:50
@skjnldsv skjnldsv self-assigned this Sep 23, 2026
Replace the legacy OCA.Viewer.registerHandler() global with
registerHandler() from @nextcloud/viewer, following the removal of the
bundled viewer app in favour of the package (nextcloud/server#63954).

Key changes:
- viewer.js: register a custom element (oca-text-viewer) via
  defineCustomElement and call registerHandler() from @nextcloud/viewer
- TextViewerWrapper.vue: thin wrapper mapping new IFile-based ViewerProps
  to the existing ViewerComponent props
- LoadViewerListener: switch from OCA\Viewer\Event\LoadViewer (gone with
  the viewer app) to OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent,
  loading text-viewer as an init script on every non-error page
- Application.php: update event listener registration accordingly
- Add @nextcloud/viewer ^2.0.0-beta.11 dependency

canCompare and downloadCallback are not part of the new API and have
been dropped.

Assisted-by: ClaudeCode:claude-sonnet-4-6
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>

@max-nextcloud max-nextcloud left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks a lot for looking into this! Appreciate it a lot! ❤️

Just a few initial comments. Did not test nor look into test failures yet.

Comment on lines +9 to +10
import { computed } from 'vue'
import ViewerComponent from '../components/ViewerComponent.vue'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could we maybe make this an async component so it only loads when a text file is actually opened?

If I understand the code correctly TextViewerWrapper will be loaded asynchronously - but it will always be loaded, right?

Something like this maybe:

Suggested change
import { computed } from 'vue'
import ViewerComponent from '../components/ViewerComponent.vue'
import { computed, defineAsyncComponent } from 'vue'
const ViewerComponent = defineAsyncComponent(() =>
import('../components/ViewerComponent.vue')
)


public function handle(Event $event): void {
if (!$event instanceof LoadViewer) {
if (!($event instanceof BeforeTemplateRenderedEvent)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

So we will load this for basically all templates now, right - even if no viewer is loaded at all. So we need to make sure this is small.

$this->eventDispatcher->dispatchTyped(new RenderReferenceEvent());

$this->initialStateProvider->provideState();
if ($event->getResponse()->getRenderAs() === TemplateResponse::RENDER_AS_ERROR) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe exclude blank templates as well?

This branch has not been deployed

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

Labels

3. to review enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate off the OCA.Viewer global before Nextcloud 36

2 participants