mirror of
https://github.com/nextcloud/server.git
synced 2026-06-08 16:26:59 -04:00
fix(files): protect filelist actions with try...catch
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
This commit is contained in:
parent
9c08d3b0b8
commit
34299e6a5d
2 changed files with 50 additions and 10 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue