Skip to content

Commit d97e17b

Browse files
susnuxkesselb
authored andcommitted
fix(files): Add more visual move / copy notification
* Resolves: #46645 This adds loading toast notification while the move operation is running. Signed-off-by: Ferdinand Thiessen <[email protected]>
1 parent be87dec commit d97e17b

File tree

9 files changed

+45
-13
lines changed

9 files changed

+45
-13
lines changed

apps/files/src/actions/moveOrCopyAction.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { FileStat, ResponseDataDetailed } from 'webdav'
88
import type { MoveCopyResult } from './moveOrCopyActionUtils'
99

1010
import { isAxiosError } from '@nextcloud/axios'
11-
import { FilePickerClosed, getFilePickerBuilder, showError, showInfo } from '@nextcloud/dialogs'
11+
import { FilePickerClosed, getFilePickerBuilder, showError, showInfo, TOAST_PERMANENT_TIMEOUT } from '@nextcloud/dialogs'
1212
import { emit } from '@nextcloud/event-bus'
1313
import { FileAction, FileType, NodeStatus, davGetClient, davRootPath, davResultToNode, davGetDefaultPropfind, getUniqueName, Permission } from '@nextcloud/files'
1414
import { translate as t } from '@nextcloud/l10n'
@@ -40,6 +40,28 @@ const getActionForNodes = (nodes: Node[]): MoveCopyAction => {
4040
return MoveCopyAction.COPY
4141
}
4242

43+
/**
44+
* Create a loading notification toast
45+
* @param mode The move or copy mode
46+
* @param source Name of the node that is copied / moved
47+
* @param destination Destination path
48+
* @return {() => void} Function to hide the notification
49+
*/
50+
function createLoadingNotification(mode: MoveCopyAction, source: string, destination: string): () => void {
51+
const text = mode === MoveCopyAction.MOVE ? t('files', 'Moving "{source}" to "{destination}" …', { source, destination }) : t('files', 'Copying "{source}" to "{destination}" …', { source, destination })
52+
53+
let toast: ReturnType<typeof showInfo>|undefined
54+
toast = showInfo(
55+
`<span class="icon icon-loading-small toast-loading-icon"></span> ${text}`,
56+
{
57+
isHTML: true,
58+
timeout: TOAST_PERMANENT_TIMEOUT,
59+
onRemove: () => { toast?.hideToast(); toast = undefined },
60+
},
61+
)
62+
return () => toast && toast.hideToast()
63+
}
64+
4365
/**
4466
* Handle the copy/move of a node to a destination
4567
* This can be imported and used by other scripts/components on server
@@ -80,6 +102,7 @@ export const handleCopyMoveNodeTo = async (node: Node, destination: Folder, meth
80102

81103
// Set loading state
82104
Vue.set(node, 'status', NodeStatus.LOADING)
105+
const actionFinished = createLoadingNotification(method, node.basename, destination.path)
83106

84107
const queue = getQueue()
85108
return await queue.add(async () => {
@@ -162,7 +185,8 @@ export const handleCopyMoveNodeTo = async (node: Node, destination: Folder, meth
162185
logger.debug(error as Error)
163186
throw new Error()
164187
} finally {
165-
Vue.set(node, 'status', undefined)
188+
Vue.set(node, 'status', '')
189+
actionFinished()
166190
}
167191
})
168192
}
@@ -313,7 +337,7 @@ export const action = new FileAction({
313337
if (result === false) {
314338
showInfo(nodes.length === 1
315339
? t('files', 'Cancelled move or copy of "{filename}".', { filename: nodes[0].displayname })
316-
: t('files', 'Cancelled move or copy operation')
340+
: t('files', 'Cancelled move or copy operation'),
317341
)
318342
return nodes.map(() => null)
319343
}

apps/files/src/components/FileEntryMixin.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ export default defineComponent({
7373
uniqueId() {
7474
return hashCode(this.source.source)
7575
},
76+
7677
isLoading() {
77-
return this.source.status === NodeStatus.LOADING
78+
return this.source.status === NodeStatus.LOADING || this.loading !== ''
7879
},
7980

8081
/**

apps/files/src/views/FilesList.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,13 @@ export default defineComponent({
669669
</script>
670670

671671
<style scoped lang="scss">
672+
:global(.toast-loading-icon) {
673+
// Reduce start margin (it was made for text but this is an icon)
674+
margin-inline-start: -4px;
675+
// 16px icon + 5px on both sides
676+
min-width: 26px;
677+
}
678+
672679
.app-content {
673680
// Virtual list needs to be full height and is scrollable
674681
display: flex;

dist/core-common.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/core-common.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-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)