Skip to content

IONOS(viewer): NC33 IONOS delta — one commit per feature (HDNEXT-1585) - #46

Merged
printminion-co merged 6 commits into
ionos-dev-v33from
mk/dev/HDNEXT-1585-viewer-nc33-folded
Jul 29, 2026
Merged

IONOS(viewer): NC33 IONOS delta — one commit per feature (HDNEXT-1585)#46
printminion-co merged 6 commits into
ionos-dev-v33from
mk/dev/HDNEXT-1585-viewer-nc33-folded

Conversation

@printminion-co

@printminion-co printminion-co commented Jul 24, 2026

Copy link
Copy Markdown

Summary

This is the folded variant of #45 — essentially the same IONOS viewer delta on the NC33 base
ionos-dev-v33, with the history reshaped to one commit per feature so it reads cleanly and is
ready to be proposed upstream to nextcloud/viewer.

Compared to #45 it additionally carries a small follow-up header-layout fix (see feature 2
below) and, for now, omits the recompiled assets — see the note at the bottom.

Features (6 commits)

  1. feat(viewer): always-show-viewer with default fallback component — the always_show_viewer
    app config, the config module, the Default component (+ its text-color / Safari-width /
    title-color styling), default viewer registration, the fallback wiring in Viewer.vue, folder
    exclusion in the file action's enabled callback, and prev/next navigation.
  2. feat(viewer): hide file name in modal header for default/image view — hides the file name in
    the modal header for the Default component and for images. Also keeps the header actions
    (play/pause, actions menu, close) right-aligned when the name is empty: NcModal omits the
    .modal-header__name element behind v-if, and its .modal-header relies on that full-width
    name to push .icons-menu right via flex space-between (no margin-left: auto fallback), so
    without it the actions collapsed to the left. Fixed with a scoped
    :deep(.modal-header .icons-menu) { margin-inline-start: auto; } — a no-op when the name is
    shown, right-aligning when it is hidden.
  3. fix(viewer): exclude directories from the file list
  4. feat(viewer): exclude Collabora office documents and PDFs from preview
  5. fix(images): render default fallback and stop spinner on failed image load
  6. fix(viewer): fix live-photo peer match for numeric-name files

Authorship across the folded commits is preserved via Co-authored-by + Signed-off-by trailers.

Relationship to #45

Supersedes-in-spirit #45, but both are intentionally left open so reviewers can compare the
granular history (#45) against this folded, upstream-ready shape.

Assets

The chore(assets): recompile viewer assets for NC33 delta commit has been dropped from this
branch. The compiled js//css/ assets still need to be rebuilt and re-committed to reflect
the source changes (notably the header-layout fix in feature 2) before this is merged.

CI note

static-psalm-analysis fails on a pre-existing base issue unrelated to this delta: the psalm job
pulls nextcloud/ocp dev-master, which now requires PHP ~8.3, while the vanilla composer.json
config.platform.php is 8.2. This affects any viewer fork PR until the base bumps the platform pin.

Jira: HDNEXT-1585

@printminion-co
printminion-co force-pushed the mk/dev/HDNEXT-1585-viewer-nc33-folded branch 2 times, most recently from 0d13802 to b5991e1 Compare July 24, 2026 15:40
@printminion-co

Copy link
Copy Markdown
Author

Update: header layout fix for empty modal title

Folded a follow-up fix into IONOS: feat(viewer): hide file name in modal header for default/image view (4bcf5a69).

Problem: when the modal name is empty (Default handler / always_show_viewer fallback), NcModal omits the .modal-header__name element entirely (it's rendered behind v-if="modalName"). Since NcModal's .modal-header right-aligns .icons-menu via flex + justify-content: space-between relying on that full-width name element — and has no margin-left: auto fallback — the header actions (play/pause, actions menu, close) collapsed to the left instead of the top-right.

Fix: add a scoped override in Viewer.vue that keeps the menu pinned right regardless of whether the name is present:

:deep(.modal-header .icons-menu) {
	margin-inline-start: auto;
}

It's a no-op when the name is shown (the full-width name leaves no free space for the auto margin) and right-aligns the menu when the name is hidden. The image--fullscreen case is unaffected (there the name element still exists, only opacity: 0).

ℹ️ Note: the IONOS: chore(assets): recompile viewer assets for NC33 delta commit was dropped from this branch — compiled js//css/ assets still need to be rebuilt and re-committed to reflect this source change.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR ports and reshapes the NC33 IONOS Viewer delta to support an “always show viewer” mode with a Default fallback handler, along with related modal header behavior and file list filtering/fallback behavior across the viewer and file action integration.

Changes:

  • Add always_show_viewer initial-state/config plumbing and register a Default viewer handler used as a fallback when no specialized handler exists.
  • Adjust viewer modal title/header behavior to hide the filename for Default/image views while keeping header actions right-aligned.
  • Refine viewer navigation/list building to support default-group fallback and broadened file inclusion/exclusion rules when always-show-viewer is enabled.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/views/Viewer.vue Adds modal title logic, default-handler/group fallback, and updated folder-list filtering when always-show-viewer is enabled.
src/utils/livePhotoUtils.ts Adjusts live-photo peer matching to tolerate non-string basenames.
src/services/Viewer.js Registers the new Default handler alongside existing built-in handlers.
src/models/default.ts Introduces the Default handler model keyed to the configured default mime type.
src/models/config.ts Adds initial-state backed config module for always-show-viewer + default mime type.
src/files_actions/viewerAction.ts Updates viewer file-action enablement behavior for always-show-viewer and folder exclusion.
src/components/Images.vue Renders Default fallback when original image load fails and ensures loading state is ended.
src/components/Default.vue Adds the Default fallback UI component for unsupported file types.
lib/Listener/LoadViewerScript.php Provides initial state for always_show_viewer to the frontend based on app config.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/Listener/LoadViewerScript.php
Comment thread src/components/Default.vue
Comment thread src/views/Viewer.vue
Comment on lines +793 to +799
filteredFiles = fileList.filter(file => {
const mime = file?.mime
const isOfficeDocument = mime && OC.MimeTypeList.aliases[mime]?.startsWith('x-office')
const isPdf = mime && mime === 'application/pdf'

return mime && !isOfficeDocument && !isPdf
})
Comment thread src/models/config.ts
printminion-co and others added 6 commits July 29, 2026 08:50
Add an `always_show_viewer` app config value that, when enabled, makes
the viewer open a generic Default component for any file whose mimetype
has no dedicated handler, instead of refusing to open it.

Includes:
- the `always_show_viewer` app config value and a config module that
  exposes `alwaysShowViewer` / `defaultMimeType` to the frontend
- the Default component (mimetype icon + basename), with proper text
  color, a Safari icon-width fix and a consistent title-color variable
- registration of a default (`*/*`) viewer handler and the fallback
  wiring in Viewer.vue
- folder exclusion in the viewer file action's `enabled` callback
- previous/next navigation support for the default component

enable via:
./occ config:app:set --value yes --type string viewer always_show_viewer

Signed-off-by: Misha M.-Kupriyanov <kupriyanov@strato.de>
Signed-off-by: Franziska Bath <franziska.bath@strato.de>
Signed-off-by: Thomas Lehmann <t.lehmann@strato.de>
Co-authored-by: Franziska Bath <franziska.bath@strato.de>
Co-authored-by: Thomas Lehmann <t.lehmann@strato.de>
… view

Extract the modal title into its own computed property and, when the
always-show-viewer fallback is active, hide the file name in the modal
header for the Default component and for images (where the name is
already shown elsewhere).

Signed-off-by: Misha M.-Kupriyanov <kupriyanov@strato.de>
Signed-off-by: Franziska Bath <franziska.bath@strato.de>
Co-authored-by: Franziska Bath <franziska.bath@strato.de>
Don't include directories as they can not be displayed.

Note: including directories could also cause a follow-up error with
certain directory structures which happen to include a directory
named like a number (i.e. 123) because of sloppy, too broad type
casting in fileUtils.ts's genFileInfo() accidentally converting
such a folder name to a Number, which then can not be used in string
comparisons.

Filter the folder file list down to entries that actually carry a mime
type, which excludes directories.

Signed-off-by: Thomas Lehmann <t.lehmann@strato.de>
Signed-off-by: Franziska Bath <franziska.bath@strato.de>
Co-authored-by: Franziska Bath <franziska.bath@strato.de>
… preview

When the always-show-viewer fallback is active, exclude office documents
and PDFs from the folder file list so Collabora-handled files are not
shown by the viewer.

Signed-off-by: Franziska Bath <franziska.bath@strato.de>
…d image load

== The cause

Previously the code attempted to load a preview of an image.

If loading this preview image failed it was attempted to load the
original image.

Load errors of images were only handled _once_. This meant that a
load error for the original image was never handled, thus the
viewer was still in loading state and showed a browser-dependant
"broken image" replacement icon.

== The fix

Now further image load errors are handled too. In case the original
fails too, the loading state is ended and a placeholder text is shown.

The default preview component, which was introduced to show something
for any mimetype if configured, is now also used as a fallback.

Signed-off-by: Thomas Lehmann <t.lehmann@strato.de>
Coerce the compared basename to a string before calling startsWith(),
so live-photo peer detection does not throw for files whose name is
parsed as a number.

Signed-off-by: Franziska Bath <franziska.bath@strato.de>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

lib/Listener/LoadViewerScript.php:45

  • IAppConfig::getAppValue requires (appId, key, default). Calling it with only (key, default) will not read the app config correctly and can fail at runtime. Use the viewer app id explicitly.
		$alwaysShowViewer = $this->appConfig->getAppValue('always_show_viewer', 'no') === 'yes';

src/views/Viewer.vue:798

  • This filter does not actually exclude directories: DAV directory entries typically have a non-empty mime (e.g. httpd/unix-directory), so mime && … will still include them. Use file.type !== 'directory' (as used elsewhere in src/utils/fileUtils.ts) to reliably exclude folders from the slideshow list.
						return mime && !isOfficeDocument && !isPdf

src/files_actions/viewerAction.ts:114

  • When alwaysShowViewer is enabled, the action becomes available without checking READ permission. This can expose a "View" action for items the user cannot read (or trigger avoidable errors). Keep the READ-permission requirement while still allowing any readable file type.
			// Always enabled if configured so
			if (configModule.alwaysShowViewer) {
				// disable for folders
				return !nodes.some(node => node.type === 'folder')
			}

@printminion-co
printminion-co merged commit d49b1db into ionos-dev-v33 Jul 29, 2026
3 of 8 checks passed
@printminion-co
printminion-co deleted the mk/dev/HDNEXT-1585-viewer-nc33-folded branch July 29, 2026 12:05
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.

6 participants