14990: added 404 page with wildcard route
[arvados-workbench2.git] / src / store / collection-panel / collection-panel-files / collection-panel-files-reducer.ts
index 08b60308c42bb9d4f3dfdeb72eae23f4b45946de..08a717596f62df17779a590ebe4c7bb56d75327d 100644 (file)
@@ -2,29 +2,31 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import { CollectionPanelFilesState, CollectionPanelFile, CollectionPanelDirectory, mapCollectionFileToCollectionPanelFile, mergeCollectionPanelFilesStates } from "./collection-panel-files-state";
+import { CollectionPanelFilesState, CollectionPanelFile, CollectionPanelDirectory, mapCollectionFileToCollectionPanelFile, mergeCollectionPanelFilesStates } from './collection-panel-files-state';
 import { CollectionPanelFilesAction, collectionPanelFilesAction } from "./collection-panel-files-actions";
-import { createTree, mapTreeValues, getNode, setNode, getNodeAncestors, getNodeDescendants, setNodeValueWith, mapTree } from "~/models/tree";
+import { createTree, mapTreeValues, getNode, setNode, getNodeAncestorsIds, getNodeDescendantsIds, setNodeValueWith, mapTree } from "~/models/tree";
 import { CollectionFileType } from "~/models/collection-file";
 
 export const collectionPanelFilesReducer = (state: CollectionPanelFilesState = createTree(), action: CollectionPanelFilesAction) => {
+    // Low-level tree handling setNode() func does in-place data modifications
+    // for performance reasons, so we pass a copy of 'state' to avoid side effects.
     return collectionPanelFilesAction.match(action, {
         SET_COLLECTION_FILES: files =>
-            mergeCollectionPanelFilesStates(state, mapTree(mapCollectionFileToCollectionPanelFile)(files)),
+            mergeCollectionPanelFilesStates({...state}, mapTree(mapCollectionFileToCollectionPanelFile)(files)),
 
         TOGGLE_COLLECTION_FILE_COLLAPSE: data =>
-            toggleCollapse(data.id)(state),
+            toggleCollapse(data.id)({...state}),
 
-        TOGGLE_COLLECTION_FILE_SELECTION: data => [state]
+        TOGGLE_COLLECTION_FILE_SELECTION: data => [{...state}]
             .map(toggleSelected(data.id))
             .map(toggleAncestors(data.id))
             .map(toggleDescendants(data.id))[0],
 
         SELECT_ALL_COLLECTION_FILES: () =>
-            mapTreeValues(v => ({ ...v, selected: true }))(state),
+            mapTreeValues(v => ({ ...v, selected: true }))({...state}),
 
         UNSELECT_ALL_COLLECTION_FILES: () =>
-            mapTreeValues(v => ({ ...v, selected: false }))(state),
+            mapTreeValues(v => ({ ...v, selected: false }))({...state}),
 
         default: () => state
     }) as CollectionPanelFilesState;
@@ -44,7 +46,7 @@ const toggleSelected = (id: string) => (tree: CollectionPanelFilesState) =>
 const toggleDescendants = (id: string) => (tree: CollectionPanelFilesState) => {
     const node = getNode(id)(tree);
     if (node && node.value.type === CollectionFileType.DIRECTORY) {
-        return getNodeDescendants(id)(tree)
+        return getNodeDescendantsIds(id)(tree)
             .reduce((newTree, id) =>
                 setNodeValueWith(v => ({ ...v, selected: node.value.selected }))(id)(newTree), tree);
     }
@@ -52,7 +54,7 @@ const toggleDescendants = (id: string) => (tree: CollectionPanelFilesState) => {
 };
 
 const toggleAncestors = (id: string) => (tree: CollectionPanelFilesState) => {
-    const ancestors = getNodeAncestors(id)(tree).reverse();
+    const ancestors = getNodeAncestorsIds(id)(tree).reverse();
     return ancestors.reduce((newTree, parent) => parent ? toggleParentNode(parent)(newTree) : newTree, tree);
 };