aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files/src/actions/convertAction.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files/src/actions/convertAction.ts')
-rw-r--r--apps/files/src/actions/convertAction.ts81
1 files changed, 81 insertions, 0 deletions
diff --git a/apps/files/src/actions/convertAction.ts b/apps/files/src/actions/convertAction.ts
new file mode 100644
index 00000000000..a8b4d537eb2
--- /dev/null
+++ b/apps/files/src/actions/convertAction.ts
@@ -0,0 +1,81 @@
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+import type { Node, View } from '@nextcloud/files'
+
+import { FileAction, registerFileAction } from '@nextcloud/files'
+import { generateUrl } from '@nextcloud/router'
+import { getCapabilities } from '@nextcloud/capabilities'
+import { t } from '@nextcloud/l10n'
+
+import AutoRenewSvg from '@mdi/svg/svg/autorenew.svg?raw'
+
+import { convertFile, convertFiles, getParentFolder } from './convertUtils'
+
+type ConversionsProvider = {
+ from: string,
+ to: string,
+ displayName: string,
+}
+
+export const ACTION_CONVERT = 'convert'
+export const registerConvertActions = () => {
+ // Generate sub actions
+ const convertProviders = getCapabilities()?.files?.file_conversions as ConversionsProvider[] ?? []
+ const actions = convertProviders.map(({ to, from, displayName }) => {
+ return new FileAction({
+ id: `convert-${from}-${to}`,
+ displayName: () => t('files', 'Save as {displayName}', { displayName }),
+ iconSvgInline: () => generateIconSvg(to),
+ enabled: (nodes: Node[]) => {
+ // Check that all nodes have the same mime type
+ return nodes.every(node => from === node.mime)
+ },
+
+ async exec(node: Node, view: View, dir: string) {
+ // If we're here, we know that the node has a fileid
+ convertFile(node.fileid as number, to, getParentFolder(view, dir))
+
+ // Silently terminate, we'll handle the UI in the background
+ return null
+ },
+
+ async execBatch(nodes: Node[], view: View, dir: string) {
+ const fileIds = nodes.map(node => node.fileid).filter(Boolean) as number[]
+ convertFiles(fileIds, to, getParentFolder(view, dir))
+
+ // Silently terminate, we'll handle the UI in the background
+ return Array(nodes.length).fill(null)
+ },
+
+ parent: ACTION_CONVERT,
+ })
+ })
+
+ // Register main action
+ registerFileAction(new FileAction({
+ id: ACTION_CONVERT,
+ displayName: () => t('files', 'Save as …'),
+ iconSvgInline: () => AutoRenewSvg,
+ enabled: (nodes: Node[], view: View) => {
+ return actions.some(action => action.enabled!(nodes, view))
+ },
+ async exec() {
+ return null
+ },
+ order: 25,
+ }))
+
+ // Register sub actions
+ actions.forEach(registerFileAction)
+}
+
+export const generateIconSvg = (mime: string) => {
+ // Generate icon based on mime type
+ const url = generateUrl('/core/mimeicon?mime=' + encodeURIComponent(mime))
+ return `<svg width="32" height="32" viewBox="0 0 32 32"
+ xmlns="http://www.w3.org/2000/svg">
+ <image href="${url}" height="32" width="32" />
+ </svg>`
+}