aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorskjnldsv <skjnldsv@protonmail.com>2024-12-12 10:50:39 +0100
committerChristopher Ng <chrng8@gmail.com>2024-12-12 10:08:38 -0800
commit34299e6a5d9bcbdb6af0d49da26e85f236701349 (patch)
tree3a949144acd49e42a2632e3e162bf3282372829e /apps
parent9c08d3b0b8cd0f2443d81e82eb5b50731fd92f9f (diff)
downloadnextcloud-server-34299e6a5d9bcbdb6af0d49da26e85f236701349.tar.gz
nextcloud-server-34299e6a5d9bcbdb6af0d49da26e85f236701349.zip
fix(files): protect filelist actions with try...catch
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
Diffstat (limited to 'apps')
-rw-r--r--apps/files/src/views/FilesList.vue53
-rw-r--r--apps/files_trashbin/src/fileListActions/emptyTrashAction.ts7
2 files changed, 50 insertions, 10 deletions
diff --git a/apps/files/src/views/FilesList.vue b/apps/files/src/views/FilesList.vue
index 4f7945881d9..d4f58b53a65 100644
--- a/apps/files/src/views/FilesList.vue
+++ b/apps/files/src/views/FilesList.vue
@@ -44,13 +44,15 @@
force-name>
<NcActionButton v-for="action in enabledFileListActions"
:key="action.id"
+ :disabled="!!loadingAction"
close-after-click
- @click="action.exec(currentView, dirContents, currentFolder)">
+ @click="execFileListAction(action)">
<template #icon>
- <NcIconSvgWrapper v-if="action.iconSvgInline !== undefined"
+ <NcLoadingIcon v-if="loadingAction === action.id" :size="18" />
+ <NcIconSvgWrapper v-else-if="action.iconSvgInline !== undefined && currentView"
:svg="action.iconSvgInline(currentView)" />
</template>
- {{ action.displayName(currentView) }}
+ {{ actionDisplayName(action) }}
</NcActionButton>
</NcActions>
@@ -132,7 +134,7 @@
</template>
<script lang="ts">
-import type { ContentsWithRoot, Folder, INode } from '@nextcloud/files'
+import type { ContentsWithRoot, FileListAction, Folder, INode } from '@nextcloud/files'
import type { Upload } from '@nextcloud/upload'
import type { CancelablePromise } from 'cancelable-promise'
import type { ComponentPublicInstance } from 'vue'
@@ -144,7 +146,7 @@ import { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'
import { Node, Permission, sortNodes, getFileListActions } from '@nextcloud/files'
import { translate as t } from '@nextcloud/l10n'
import { join, dirname, normalize } from 'path'
-import { showError, showWarning } from '@nextcloud/dialogs'
+import { showError, showSuccess, showWarning } from '@nextcloud/dialogs'
import { ShareType } from '@nextcloud/sharing'
import { UploadPicker, UploadStatus } from '@nextcloud/upload'
import { loadState } from '@nextcloud/initial-state'
@@ -258,6 +260,7 @@ export default defineComponent({
data() {
return {
loading: true,
+ loadingAction: null as string | null,
error: null as string | null,
promise: null as CancelablePromise<ContentsWithRoot> | Promise<ContentsWithRoot> | null,
@@ -437,6 +440,10 @@ export default defineComponent({
},
enabledFileListActions() {
+ if (!this.currentView || !this.currentFolder) {
+ return []
+ }
+
const actions = getFileListActions()
const enabledActions = actions
.filter(action => {
@@ -446,7 +453,7 @@ export default defineComponent({
return action.enabled(
this.currentView!,
this.dirContents,
- { folder: this.currentFolder! },
+ this.currentFolder as Folder,
)
})
.toSorted((a, b) => a.order - b.order)
@@ -714,6 +721,40 @@ export default defineComponent({
}
this.dirContentsFiltered = nodes
},
+
+ actionDisplayName(action: FileListAction): string {
+ let displayName = action.id
+ try {
+ displayName = action.displayName(this.currentView!)
+ } catch (error) {
+ logger.error('Error while getting action display name', { action, error })
+ }
+ return displayName
+ },
+
+ async execFileListAction(action: FileListAction) {
+ this.loadingAction = action.id
+
+ const displayName = this.actionDisplayName(action)
+ try {
+ const success = await action.exec(this.source, this.dirContents, this.currentDir)
+ // If the action returns null, we stay silent
+ if (success === null || success === undefined) {
+ return
+ }
+
+ if (success) {
+ showSuccess(t('files', '"{displayName}" action executed successfully', { displayName }))
+ return
+ }
+ showError(t('files', '"{displayName}" action failed', { displayName }))
+ } catch (error) {
+ logger.error('Error while executing action', { action, error })
+ showError(t('files', '"{displayName}" action failed', { displayName }))
+ } finally {
+ this.loadingAction = null
+ }
+ },
},
})
</script>
diff --git a/apps/files_trashbin/src/fileListActions/emptyTrashAction.ts b/apps/files_trashbin/src/fileListActions/emptyTrashAction.ts
index b0a2fbdd2c2..9c45d6a8565 100644
--- a/apps/files_trashbin/src/fileListActions/emptyTrashAction.ts
+++ b/apps/files_trashbin/src/fileListActions/emptyTrashAction.ts
@@ -2,8 +2,7 @@
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
-import type { Node } from '@nextcloud/files'
+import type { Node, View, Folder } from '@nextcloud/files'
import PQueue from 'p-queue'
import { FileListAction } from '@nextcloud/files'
@@ -73,14 +72,14 @@ export const emptyTrashAction = new FileListAction({
displayName: () => t('files_trashbin', 'Empty deleted files'),
order: 0,
- enabled: (view, nodes, folder) => {
+ enabled(view: View, nodes: Node[], folder: Folder) {
if (view.id !== 'trashbin') {
return false
}
return nodes.length > 0 && folder.path === '/'
},
- exec: async (view, nodes) => {
+ async exec(view: View, nodes: Node[]) {
const dialog = getDialogBuilder(t('files_trashbin', 'Confirm permanent deletion'))
.setSeverity(DialogSeverity.Warning)
// TODO Add note for groupfolders