-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Expand file tree
/
Copy pathconvertUtils.ts
More file actions
147 lines (124 loc) · 5 KB
/
convertUtils.ts
File metadata and controls
147 lines (124 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/**
* 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 > 0) {
const messages = failed.map(result => result.reason?.response?.data?.ocs?.meta?.message) as string[]
logger.error('Failed to convert files', { fileIds, targetMimeType, messages })
// 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', 'All files failed to be converted'))
return
}
// A single file failed
if (failed.length === 1) {
// If we have a message for the failed file, show it
if (messages[0]) {
showError(t('files', 'One file could not be converted: {message}', { message: messages[0] }))
return
}
// Otherwise, show a generic error
showError(t('files', 'One file could not be converted'))
return
}
// We already check above when all files failed
// if we're here, we have a mix of failed and successful files
showError(t('files', '{count} files could not be converted', { count: failed.length }))
showSuccess(t('files', '{count} files successfully converted', { count: fileIds.length - failed.length }))
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
}