-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fixup! fixup! fixup! feat(files): add conversion action
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
- Loading branch information
Showing
4 changed files
with
159 additions
and
15 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/** | ||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors | ||
* SPDX-License-Identifier: AGPL-3.0-or-later | ||
*/ | ||
import type { AxiosResponse } from '@nextcloud/axios' | ||
import type { Folder, View } from '@nextcloud/files' | ||
|
||
import { emit } from '@nextcloud/event-bus' | ||
import { generateOcsUrl } from '@nextcloud/router' | ||
import { showError, showLoading, showSuccess } from '@nextcloud/dialogs' | ||
import { t } from '@nextcloud/l10n' | ||
import axios from '@nextcloud/axios' | ||
import PQueue from 'p-queue' | ||
|
||
import logger from '../logger' | ||
import { useFilesStore } from '../store/files' | ||
import { getPinia } from '../store' | ||
import { usePathsStore } from '../store/paths' | ||
|
||
const queue = new PQueue({ concurrency: 5 }) | ||
|
||
const requestConversion = function(fileId: number, targetMimeType: string): Promise<AxiosResponse> { | ||
return axios.post(generateOcsUrl('/apps/files/api/v1/convert'), { | ||
fileId, | ||
targetMimeType, | ||
}) | ||
} | ||
|
||
export const convertFiles = async function(fileIds: number[], targetMimeType: string, parentFolder: Folder | null) { | ||
const conversions = fileIds.map(fileId => queue.add(() => requestConversion(fileId, targetMimeType))) | ||
|
||
// Start conversion | ||
const toast = showLoading(t('files', 'Converting files…')) | ||
|
||
// Handle results | ||
try { | ||
const results = await Promise.allSettled(conversions) | ||
const failed = results.filter(result => result.status === 'rejected') | ||
if (failed.length) { | ||
const messages = failed.map(result => result.reason?.response?.data?.ocs?.meta?.message) as string[] | ||
|
||
// If all failed files have the same error message, show it | ||
if (new Set(messages).size === 1) { | ||
showError(t('files', 'Failed to convert files: {message}', { message: messages[0] })) | ||
return | ||
} | ||
|
||
if (failed.length === fileIds.length) { | ||
showError(t('files', 'Failed to convert files')) | ||
return | ||
} | ||
showError(t('files', 'Some files could not be converted')) | ||
return | ||
} | ||
|
||
// All files converted | ||
showSuccess(t('files', 'Files successfully converted')) | ||
|
||
// Trigger a reload of the file list | ||
if (parentFolder) { | ||
emit('files:node:updated', parentFolder) | ||
} | ||
|
||
// Switch to the new files | ||
const firstSuccess = results[0] as PromiseFulfilledResult<AxiosResponse> | ||
const newFileId = firstSuccess.value.data.ocs.data.fileId | ||
window.OCP.Files.Router.goToRoute(null, { ...window.OCP.Files.Router.params, fileid: newFileId }, window.OCP.Files.Router.query) | ||
} catch (error) { | ||
// Should not happen as we use allSettled and handle errors above | ||
showError(t('files', 'Failed to convert files')) | ||
logger.error('Failed to convert files', { fileIds, targetMimeType, error }) | ||
} finally { | ||
// Hide loading toast | ||
toast.hideToast() | ||
} | ||
} | ||
|
||
export const convertFile = async function(fileId: number, targetMimeType: string, parentFolder: Folder | null) { | ||
const toast = showLoading(t('files', 'Converting file…')) | ||
|
||
try { | ||
const result = await queue.add(() => requestConversion(fileId, targetMimeType)) as AxiosResponse | ||
showSuccess(t('files', 'File successfully converted')) | ||
|
||
// Trigger a reload of the file list | ||
if (parentFolder) { | ||
emit('files:node:updated', parentFolder) | ||
} | ||
|
||
// Switch to the new file | ||
const newFileId = result.data.ocs.data.fileId | ||
window.OCP.Files.Router.goToRoute(null, { ...window.OCP.Files.Router.params, fileid: newFileId }, window.OCP.Files.Router.query) | ||
} catch (error) { | ||
// If the server returned an error message, show it | ||
if (error.response?.data?.ocs?.meta?.message) { | ||
showError(t('files', 'Failed to convert file: {message}', { message: error.response.data.ocs.meta.message })) | ||
return | ||
} | ||
|
||
logger.error('Failed to convert file', { fileId, targetMimeType, error }) | ||
showError(t('files', 'Failed to convert file')) | ||
} finally { | ||
// Hide loading toast | ||
toast.hideToast() | ||
} | ||
} | ||
|
||
/** | ||
* Get the parent folder of a path | ||
* | ||
* TODO: replace by the parent node straight away when we | ||
* update the Files actions api accordingly. | ||
* | ||
* @param view The current view | ||
* @param path The path to the file | ||
* @returns The parent folder | ||
*/ | ||
export const getParentFolder = function(view: View, path: string): Folder | null { | ||
const filesStore = useFilesStore(getPinia()) | ||
const pathsStore = usePathsStore(getPinia()) | ||
|
||
const parentSource = pathsStore.getPath(view.id, path) | ||
if (!parentSource) { | ||
return null | ||
} | ||
|
||
const parentFolder = filesStore.getNode(parentSource) as Folder | undefined | ||
return parentFolder ?? null | ||
} |
This file contains 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