From 6e0618711e0da1cf138e8f7320eb3818c8f5facd Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Wed, 9 Sep 2026 11:26:16 +0200 Subject: [PATCH] feat(previews)!: read the enabled preview providers from the capability Whether the viewer offers heic, heif, tiff and friends depends on which preview providers the server has enabled. That arrived as an initial state the viewer app provided on every page, which is the last thing tying the library to an app of its own. It is a core capability now, so the library reads it wherever capabilities are, public share pages included, and @nextcloud/initial-state stops being a peer dependency. BREAKING CHANGE: needs a server exposing core.previews.enabled_providers. On an older one no preview-only mime is offered, which is what a server with the providers disabled reports anyway. Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: skjnldsv --- __tests__/models.spec.ts | 2 +- __tests__/previewProviders.spec.ts | 48 ++++++++++++++++++++++++++++++ lib/models/images.ts | 12 ++++++-- package-lock.json | 4 +-- package.json | 4 +-- 5 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 __tests__/previewProviders.spec.ts diff --git a/__tests__/models.spec.ts b/__tests__/models.spec.ts index 3a6c41e..f439b9e 100644 --- a/__tests__/models.spec.ts +++ b/__tests__/models.spec.ts @@ -164,7 +164,7 @@ describe('images model', () => { }) it('rejects a preview-only mime when no preview provider is enabled', async () => { - // enabled_preview_providers is empty (no initial-state), so image/heic is filtered out. + // No preview capability in this suite, so image/heic is filtered out. const { registerImageHandler } = await import('../lib/models/images.ts') registerImageHandler() const handler = handlerById('images') diff --git a/__tests__/previewProviders.spec.ts b/__tests__/previewProviders.spec.ts new file mode 100644 index 0000000..05520b7 --- /dev/null +++ b/__tests__/previewProviders.spec.ts @@ -0,0 +1,48 @@ +/*! + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +import { beforeEach, describe, expect, it, vi } from 'vitest' +import { getHandlers } from '../lib/index.ts' +import { makeFile } from './factories.ts' + +const { capabilities } = vi.hoisted(() => ({ capabilities: { value: {} as object } })) +vi.mock('@nextcloud/capabilities', () => ({ getCapabilities: () => capabilities.value })) + +/** + * Register the image handler against the given set of enabled preview providers. + * + * @param providers - The provider mime patterns the server would report + */ +async function registerWithProviders(providers?: string[]) { + capabilities.value = providers === undefined ? {} : { core: { previews: { enabled_providers: providers } } } + vi.resetModules() + const { registerImageHandler } = await import('../lib/models/images.ts') + registerImageHandler() + return getHandlers().get('images')! +} + +describe('preview providers', () => { + beforeEach(() => { + capabilities.value = {} + }) + + it('enables a preview-only mime the server has a provider for', async () => { + const handler = await registerWithProviders(['/image\\/hei(f|c)/']) + + expect(handler.enabled([makeFile({ mime: 'image/heic' })])).toBe(true) + }) + + it('leaves a preview-only mime alone when its provider is disabled', async () => { + const handler = await registerWithProviders(['/image\\/jpeg/']) + + expect(handler.enabled([makeFile({ mime: 'image/heic' })])).toBe(false) + }) + + it('falls back to the browser mimes when the capability is missing', async () => { + const handler = await registerWithProviders(undefined) + + expect(handler.enabled([makeFile({ mime: 'image/heic' })])).toBe(false) + expect(handler.enabled([makeFile({ mime: 'image/png' })])).toBe(true) + }) +}) diff --git a/lib/models/images.ts b/lib/models/images.ts index 7a04c8f..57be0b5 100644 --- a/lib/models/images.ts +++ b/lib/models/images.ts @@ -3,13 +3,21 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { loadState } from '@nextcloud/initial-state' +import { getCapabilities } from '@nextcloud/capabilities' import { defineCustomElement } from 'vue' import { registerHandler } from '../index.ts' import { logger } from '../services/logger.ts' import { t } from '../utils/l10n.ts' -const enabledPreviewProviders = loadState('viewer', 'enabled_preview_providers', []) +interface PreviewCapabilities { + core?: { + previews?: { + enabled_providers?: string[] + } + } +} + +const enabledPreviewProviders = (getCapabilities() as PreviewCapabilities).core?.previews?.enabled_providers ?? [] /** * Those mimes needs a proper preview to be displayed diff --git a/package-lock.json b/package-lock.json index 73d80f6..db393a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,11 +20,11 @@ }, "devDependencies": { "@nextcloud/axios": "^2.5.2", + "@nextcloud/capabilities": "^1.2.1", "@nextcloud/dialogs": "^7.5.0", "@nextcloud/eslint-config": "^9.0.1", "@nextcloud/event-bus": "^3.3.3", "@nextcloud/files": "^4.0.0", - "@nextcloud/initial-state": "^3.0.0", "@nextcloud/l10n": "^3.4.1", "@nextcloud/paths": "^3.1.0", "@nextcloud/router": "^3.1.0", @@ -54,10 +54,10 @@ }, "peerDependencies": { "@nextcloud/axios": "^2.5.2", + "@nextcloud/capabilities": "^1.2.1", "@nextcloud/dialogs": "^7.5.0", "@nextcloud/event-bus": "^3.3.3", "@nextcloud/files": "^4.0.0", - "@nextcloud/initial-state": "^3.0.0", "@nextcloud/l10n": "^3.4.1", "@nextcloud/paths": "^3.1.0", "@nextcloud/router": "^3.1.0", diff --git a/package.json b/package.json index c8a737b..b81e95b 100644 --- a/package.json +++ b/package.json @@ -62,10 +62,10 @@ }, "peerDependencies": { "@nextcloud/axios": "^2.5.2", + "@nextcloud/capabilities": "^1.2.1", "@nextcloud/dialogs": "^7.5.0", "@nextcloud/event-bus": "^3.3.3", "@nextcloud/files": "^4.0.0", - "@nextcloud/initial-state": "^3.0.0", "@nextcloud/l10n": "^3.4.1", "@nextcloud/paths": "^3.1.0", "@nextcloud/router": "^3.1.0", @@ -75,11 +75,11 @@ }, "devDependencies": { "@nextcloud/axios": "^2.5.2", + "@nextcloud/capabilities": "^1.2.1", "@nextcloud/dialogs": "^7.5.0", "@nextcloud/eslint-config": "^9.0.1", "@nextcloud/event-bus": "^3.3.3", "@nextcloud/files": "^4.0.0", - "@nextcloud/initial-state": "^3.0.0", "@nextcloud/l10n": "^3.4.1", "@nextcloud/paths": "^3.1.0", "@nextcloud/router": "^3.1.0",