Skip to content

Commit a9296ab

Browse files
authored
Merge pull request #46971 from nextcloud/backport/46963/stable28
[stable28] fix(files): cancel move-copy action should not be handled as an error
2 parents 2c1883f + ba14e7b commit a9296ab

5 files changed

Lines changed: 42 additions & 23 deletions

File tree

apps/files/src/actions/moveOrCopyAction.ts

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ import type { IFilePickerButton } from '@nextcloud/dialogs'
2525
import type { FileStat, ResponseDataDetailed } from 'webdav'
2626
import type { MoveCopyResult } from './moveOrCopyActionUtils'
2727

28-
// eslint-disable-next-line n/no-extraneous-import
29-
import { AxiosError } from 'axios'
30-
import { basename, join } from 'path'
28+
import { FilePickerClosed, getFilePickerBuilder, showError, showInfo } from '@nextcloud/dialogs'
3129
import { emit } from '@nextcloud/event-bus'
32-
import { FilePickerClosed, getFilePickerBuilder, showError } from '@nextcloud/dialogs'
3330
import { FileAction, FileType, NodeStatus, davGetClient, davRootPath, davResultToNode, davGetDefaultPropfind, getUniqueName } from '@nextcloud/files'
3431
import { translate as t } from '@nextcloud/l10n'
3532
import { openConflictPicker, hasConflict } from '@nextcloud/upload'
33+
// eslint-disable-next-line n/no-extraneous-import
34+
import { AxiosError } from 'axios'
35+
import { basename, join } from 'path'
3636
import Vue from 'vue'
3737

3838
import CopyIconSvg from '@mdi/svg/svg/folder-multiple.svg?raw'
@@ -106,7 +106,7 @@ export const handleCopyMoveNodeTo = async (node: Node, destination: Folder, meth
106106
if (index === 1) {
107107
return t('files', '(copy)') // TRANSLATORS: Mark a file as a copy of another file
108108
}
109-
return t('files', '(copy %n)', undefined, index) // TRANSLATORS: Meaning it is the n'th copy of a file
109+
return t('files', '(copy %n)', undefined, index) // TRANSLATORS: Meaning it is the nth copy of a file
110110
}
111111

112112
try {
@@ -186,12 +186,17 @@ export const handleCopyMoveNodeTo = async (node: Node, destination: Folder, meth
186186

187187
/**
188188
* Open a file picker for the given action
189-
* @param {MoveCopyAction} action The action to open the file picker for
190-
* @param {string} dir The directory to start the file picker in
191-
* @param {Node[]} nodes The nodes to move/copy
192-
* @return {Promise<MoveCopyResult>} The picked destination
189+
* @param action The action to open the file picker for
190+
* @param dir The directory to start the file picker in
191+
* @param nodes The nodes to move/copy
192+
* @return The picked destination or false if cancelled by user
193193
*/
194-
const openFilePickerForAction = async (action: MoveCopyAction, dir = '/', nodes: Node[]): Promise<MoveCopyResult> => {
194+
async function openFilePickerForAction(
195+
action: MoveCopyAction,
196+
dir = '/',
197+
nodes: Node[],
198+
): Promise<MoveCopyResult | false> {
199+
const { resolve, reject, promise } = Promise.withResolvers<MoveCopyResult | false>()
195200
const fileIDs = nodes.map(node => node.fileid).filter(Boolean)
196201
const filePicker = getFilePickerBuilder(t('files', 'Choose destination'))
197202
.allowDirectories(true)
@@ -202,9 +207,7 @@ const openFilePickerForAction = async (action: MoveCopyAction, dir = '/', nodes:
202207
.setMimeTypeFilter([])
203208
.setMultiSelect(false)
204209
.startAt(dir)
205-
206-
return new Promise((resolve, reject) => {
207-
filePicker.setButtonFactory((selection: Node[], path: string) => {
210+
.setButtonFactory((selection: Node[], path: string) => {
208211
const buttons: IFilePickerButton[] = []
209212
const target = basename(path)
210213

@@ -252,17 +255,19 @@ const openFilePickerForAction = async (action: MoveCopyAction, dir = '/', nodes:
252255

253256
return buttons
254257
})
258+
.build()
255259

256-
const picker = filePicker.build()
257-
picker.pick().catch((error) => {
260+
filePicker.pick()
261+
.catch((error: Error) => {
258262
logger.debug(error as Error)
259263
if (error instanceof FilePickerClosed) {
260-
reject(new Error(t('files', 'Cancelled move or copy operation')))
264+
resolve(false)
261265
} else {
262266
reject(new Error(t('files', 'Move or copy operation failed')))
263267
}
264268
})
265-
})
269+
270+
return promise
266271
}
267272

268273
export const action = new FileAction({
@@ -295,6 +300,11 @@ export const action = new FileAction({
295300
logger.error(e as Error)
296301
return false
297302
}
303+
if (result === false) {
304+
showInfo(t('files', 'Cancelled move or copy of "{filename}".', { filename: node.displayname }))
305+
return null
306+
}
307+
298308
try {
299309
await handleCopyMoveNodeTo(node, result.destination, result.action)
300310
return true
@@ -311,6 +321,15 @@ export const action = new FileAction({
311321
async execBatch(nodes: Node[], view: View, dir: string) {
312322
const action = getActionForNodes(nodes)
313323
const result = await openFilePickerForAction(action, dir, nodes)
324+
// Handle cancellation silently
325+
if (result === false) {
326+
showInfo(nodes.length === 1
327+
? t('files', 'Cancelled move or copy of "{filename}".', { filename: nodes[0].displayname })
328+
: t('files', 'Cancelled move or copy operation'),
329+
)
330+
return nodes.map(() => null)
331+
}
332+
314333
const promises = nodes.map(async node => {
315334
try {
316335
await handleCopyMoveNodeTo(node, result.destination, result.action)

dist/files-init.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/files-init.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/files-main.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/files-main.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)