aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2024-09-11 22:29:31 +0200
committerFerdinand Thiessen <opensource@fthiessen.de>2024-10-11 14:22:15 +0200
commitd58a333d5e35559401f8e2f49343eb739f8860fc (patch)
tree528ff77acba47b432032a488c1f92a3e72b70561 /apps/files
parent3980061111ea8ca5e5296d3828ac98409682c24d (diff)
downloadnextcloud-server-d58a333d5e35559401f8e2f49343eb739f8860fc.tar.gz
nextcloud-server-d58a333d5e35559401f8e2f49343eb739f8860fc.zip
fix(files): Add more visual move / copy notification
* Resolves: https://github.com/nextcloud/server/issues/46645 This adds loading toast notification while the move operation is running. Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps/files')
-rw-r--r--apps/files/src/actions/moveOrCopyAction.ts30
-rw-r--r--apps/files/src/components/FileEntryMixin.ts3
-rw-r--r--apps/files/src/views/FilesList.vue7
3 files changed, 36 insertions, 4 deletions
diff --git a/apps/files/src/actions/moveOrCopyAction.ts b/apps/files/src/actions/moveOrCopyAction.ts
index a47901d040a..b8907586276 100644
--- a/apps/files/src/actions/moveOrCopyAction.ts
+++ b/apps/files/src/actions/moveOrCopyAction.ts
@@ -28,8 +28,8 @@ import type { MoveCopyResult } from './moveOrCopyActionUtils'
// eslint-disable-next-line n/no-extraneous-import
import { AxiosError } from 'axios'
import { basename, join } from 'path'
+import { FilePickerClosed, getFilePickerBuilder, showError, showInfo, TOAST_PERMANENT_TIMEOUT } from '@nextcloud/dialogs'
import { emit } from '@nextcloud/event-bus'
-import { FilePickerClosed, getFilePickerBuilder, showError, showInfo } from '@nextcloud/dialogs'
import { FileAction, FileType, NodeStatus, davGetClient, davRootPath, davResultToNode, davGetDefaultPropfind, getUniqueName } from '@nextcloud/files'
import { translate as t } from '@nextcloud/l10n'
import { openConflictPicker, hasConflict } from '@nextcloud/upload'
@@ -60,6 +60,28 @@ const getActionForNodes = (nodes: Node[]): MoveCopyAction => {
}
/**
+ * Create a loading notification toast
+ * @param mode The move or copy mode
+ * @param source Name of the node that is copied / moved
+ * @param destination Destination path
+ * @return {() => void} Function to hide the notification
+ */
+function createLoadingNotification(mode: MoveCopyAction, source: string, destination: string): () => void {
+ const text = mode === MoveCopyAction.MOVE ? t('files', 'Moving "{source}" to "{destination}" …', { source, destination }) : t('files', 'Copying "{source}" to "{destination}" …', { source, destination })
+
+ let toast: ReturnType<typeof showInfo>|undefined
+ toast = showInfo(
+ `<span class="icon icon-loading-small toast-loading-icon"></span> ${text}`,
+ {
+ isHTML: true,
+ timeout: TOAST_PERMANENT_TIMEOUT,
+ onRemove: () => { toast?.hideToast(); toast = undefined },
+ },
+ )
+ return () => toast && toast.hideToast()
+}
+
+/**
* Handle the copy/move of a node to a destination
* This can be imported and used by other scripts/components on server
* @param {Node} node The node to copy/move
@@ -99,6 +121,7 @@ export const handleCopyMoveNodeTo = async (node: Node, destination: Folder, meth
// Set loading state
Vue.set(node, 'status', NodeStatus.LOADING)
+ const actionFinished = createLoadingNotification(method, node.basename, destination.path)
const queue = getQueue()
return await queue.add(async () => {
@@ -181,7 +204,8 @@ export const handleCopyMoveNodeTo = async (node: Node, destination: Folder, meth
logger.debug(error as Error)
throw new Error()
} finally {
- Vue.set(node, 'status', undefined)
+ Vue.set(node, 'status', '')
+ actionFinished()
}
})
}
@@ -327,7 +351,7 @@ export const action = new FileAction({
if (result === false) {
showInfo(nodes.length === 1
? t('files', 'Cancelled move or copy of "{filename}".', { filename: nodes[0].displayname })
- : t('files', 'Cancelled move or copy operation')
+ : t('files', 'Cancelled move or copy operation'),
)
return nodes.map(() => null)
}
diff --git a/apps/files/src/components/FileEntryMixin.ts b/apps/files/src/components/FileEntryMixin.ts
index 51e597c8fc5..7b0d875c880 100644
--- a/apps/files/src/components/FileEntryMixin.ts
+++ b/apps/files/src/components/FileEntryMixin.ts
@@ -87,8 +87,9 @@ export default defineComponent({
uniqueId() {
return hashCode(this.source.source)
},
+
isLoading() {
- return this.source.status === NodeStatus.LOADING
+ return this.source.status === NodeStatus.LOADING || this.loading !== ''
},
/**
diff --git a/apps/files/src/views/FilesList.vue b/apps/files/src/views/FilesList.vue
index da68f862e26..3dc2c1a3452 100644
--- a/apps/files/src/views/FilesList.vue
+++ b/apps/files/src/views/FilesList.vue
@@ -660,6 +660,13 @@ export default defineComponent({
</script>
<style scoped lang="scss">
+:global(.toast-loading-icon) {
+ // Reduce start margin (it was made for text but this is an icon)
+ margin-inline-start: -4px;
+ // 16px icon + 5px on both sides
+ min-width: 26px;
+}
+
.app-content {
// Virtual list needs to be full height and is scrollable
display: flex;