]> source.dussan.org Git - nextcloud-server.git/commitdiff
fix(files): Ensure children are removed from folder and not duplicated
authorFerdinand Thiessen <opensource@fthiessen.de>
Wed, 11 Sep 2024 18:15:04 +0000 (20:15 +0200)
committerFerdinand Thiessen <opensource@fthiessen.de>
Tue, 15 Oct 2024 14:54:39 +0000 (16:54 +0200)
* Resolves https://github.com/nextcloud/server/issues/47904

We need to make sure that we only add one source (unique!) once as a child,
this is ensured by simply use a native `Set`.
Also we need to remove children on from folders when the `files:node:deleted`
event is emitted.

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
apps/files/src/store/paths.ts
apps/files/src/views/FilesList.vue

index 816014feb56e1733c0255cf88ad5f9770240d36a..e4e520aebba100b3ccb3743716b207d76bfcbf16 100644 (file)
@@ -19,7 +19,7 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  *
  */
-import type { FileSource, PathsStore, PathOptions, ServicesState } from '../types'
+import type { FileSource, PathsStore, PathOptions, ServicesState, Service } from '../types'
 import { defineStore } from 'pinia'
 import { FileType, Folder, Node, getNavigation } from '@nextcloud/files'
 import { subscribe } from '@nextcloud/event-bus'
@@ -58,6 +58,57 @@ export const usePathsStore = function(...args) {
                                Vue.set(this.paths[payload.service], payload.path, payload.source)
                        },
 
+                       deletePath(service: Service, path: string) {
+                               // skip if service does not exist
+                               if (!this.paths[service]) {
+                                       return
+                               }
+
+                               Vue.delete(this.paths[service], path)
+                       },
+
+                       onDeletedNode(node: Node) {
+                               const service = getNavigation()?.active?.id || 'files'
+
+                               if (node.type === FileType.Folder) {
+                                       // Delete the path
+                                       this.deletePath(
+                                               service,
+                                               node.path,
+                                       )
+                               }
+
+                               // Remove node from children
+                               if (node.dirname === '/') {
+                                       const root = files.getRoot(service) as Folder & { _children?: string[] }
+                                       // ensure sources are unique
+                                       const children = new Set(root._children ?? [])
+                                       children.delete(node.source)
+                                       Vue.set(root, '_children', [...children.values()])
+                                       return
+                               }
+
+                               if (this.paths[service][node.dirname]) {
+                                       const parentSource = this.paths[service][node.dirname]
+                                       const parentFolder = files.getNode(parentSource) as Folder & { _children?: string[] }
+
+                                       if (!parentFolder) {
+                                               logger.error('Parent folder not found', { parentSource })
+                                               return
+                                       }
+
+                                       logger.debug('Path exists, removing from children', { parentFolder, node })
+
+                                       // ensure sources are unique
+                                       const children = new Set(parentFolder._children ?? [])
+                                       children.delete(node.source)
+                                       Vue.set(parentFolder, '_children', [...children.values()])
+                                       return
+                               }
+
+                               logger.debug('Parent path does not exists, skipping children update', { node })
+                       },
+
                        onCreatedNode(node: Node) {
                                const service = getNavigation()?.active?.id || 'files'
                                if (!node.fileid) {
@@ -77,11 +128,11 @@ export const usePathsStore = function(...args) {
                                // Update parent folder children if exists
                                // If the folder is the root, get it and update it
                                if (node.dirname === '/') {
-                                       const root = files.getRoot(service)
-                                       if (!root._children) {
-                                               Vue.set(root, '_children', [])
-                                       }
-                                       root._children.push(node.source)
+                                       const root = files.getRoot(service) as Folder & { _children?: string[] }
+                                       // ensure sources are unique
+                                       const children = new Set(root._children ?? [])
+                                       children.add(node.source)
+                                       Vue.set(root, '_children', [...children.values()])
                                        return
                                }
 
@@ -89,7 +140,7 @@ export const usePathsStore = function(...args) {
                                // fetched later and its children updated anyway.
                                if (this.paths[service][node.dirname]) {
                                        const parentSource = this.paths[service][node.dirname]
-                                       const parentFolder = files.getNode(parentSource) as Folder
+                                       const parentFolder = files.getNode(parentSource) as Folder & { _children?: string[] }
                                        logger.debug('Path already exists, updating children', { parentFolder, node })
 
                                        if (!parentFolder) {
@@ -97,10 +148,10 @@ export const usePathsStore = function(...args) {
                                                return
                                        }
 
-                                       if (!parentFolder._children) {
-                                               Vue.set(parentFolder, '_children', [])
-                                       }
-                                       parentFolder._children.push(node.source)
+                                       // ensure sources are unique
+                                       const children = new Set(parentFolder._children ?? [])
+                                       children.add(node.source)
+                                       Vue.set(parentFolder, '_children', [...children.values()])
                                        return
                                }
 
@@ -114,7 +165,7 @@ export const usePathsStore = function(...args) {
        if (!pathsStore._initialized) {
                // TODO: watch folders to update paths?
                subscribe('files:node:created', pathsStore.onCreatedNode)
-               // subscribe('files:node:deleted', pathsStore.onDeletedNode)
+               subscribe('files:node:deleted', pathsStore.onDeletedNode)
                // subscribe('files:node:moved', pathsStore.onMovedNode)
 
                pathsStore._initialized = true
index 3dc2c1a34521a4fa89fd6eae00aa0f0ea1ea968b..5f74af85d3485e39eeceeb22defe94518d2a1100 100644 (file)
@@ -652,6 +652,7 @@ export default defineComponent({
                        }
                        sidebarAction.exec(this.currentFolder, this.currentView!, this.currentFolder.path)
                },
+
                toggleGridView() {
                        this.userConfigStore.update('grid_view', !this.userConfig.grid_view)
                },