01f41f0e7816673f14bd8a5f75f227e0d4a83b31
[arvados-workbench2.git] / src / store / collection-panel / collection-panel-files / collection-panel-files-reducer.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { CollectionPanelFilesState, CollectionPanelFile, CollectionPanelDirectory, mapCollectionFileToCollectionPanelFile, mergeCollectionPanelFilesStates } from './collection-panel-files-state';
6 import { CollectionPanelFilesAction, collectionPanelFilesAction } from "./collection-panel-files-actions";
7 import { createTree, mapTreeValues, getNode, setNode, getNodeAncestorsIds, getNodeDescendantsIds, setNodeValueWith, mapTree } from "~/models/tree";
8 import { CollectionFileType } from "~/models/collection-file";
9
10 export const collectionPanelFilesReducer = (state: CollectionPanelFilesState = createTree(), action: CollectionPanelFilesAction) => {
11     // Low-level tree handling setNode() func does in-place data modifications
12     // for performance reasons, so we pass a copy of 'state' to avoid side effects.
13     return collectionPanelFilesAction.match(action, {
14         SET_COLLECTION_FILES: files =>
15             mergeCollectionPanelFilesStates({ ...state }, mapTree(mapCollectionFileToCollectionPanelFile)(files)),
16
17         TOGGLE_COLLECTION_FILE_COLLAPSE: data =>
18             toggleCollapse(data.id)({ ...state }),
19
20         TOGGLE_COLLECTION_FILE_SELECTION: data => [{ ...state }]
21             .map(toggleSelected(data.id))
22             .map(toggleAncestors(data.id))
23             .map(toggleDescendants(data.id))[0],
24
25         ON_SEARCH_CHANGE: (data) =>
26             mapTreeValues((v: CollectionPanelDirectory | CollectionPanelFile) => {
27                 if (v.type === CollectionFileType.DIRECTORY) {
28                     return ({ ...v, collapsed: data.length === 0 });
29                 }
30
31                 return ({ ...v });
32             })({ ...state }),
33
34         SELECT_ALL_COLLECTION_FILES: () =>
35             mapTreeValues(v => ({ ...v, selected: true }))({ ...state }),
36
37         UNSELECT_ALL_COLLECTION_FILES: () =>
38             mapTreeValues(v => ({ ...v, selected: false }))({ ...state }),
39
40         default: () => state
41     }) as CollectionPanelFilesState;
42 };
43
44 const toggleCollapse = (id: string) => (tree: CollectionPanelFilesState) =>
45     setNodeValueWith((v: CollectionPanelDirectory | CollectionPanelFile) =>
46         v.type === CollectionFileType.DIRECTORY
47             ? { ...v, collapsed: !v.collapsed }
48             : v)(id)(tree);
49
50
51 const toggleSelected = (id: string) => (tree: CollectionPanelFilesState) =>
52     setNodeValueWith((v: CollectionPanelDirectory | CollectionPanelFile) => ({ ...v, selected: !v.selected }))(id)(tree);
53
54
55 const toggleDescendants = (id: string) => (tree: CollectionPanelFilesState) => {
56     const node = getNode(id)(tree);
57     if (node && node.value.type === CollectionFileType.DIRECTORY) {
58         return getNodeDescendantsIds(id)(tree)
59             .reduce((newTree, id) =>
60                 setNodeValueWith(v => ({ ...v, selected: node.value.selected }))(id)(newTree), tree);
61     }
62     return tree;
63 };
64
65 const toggleAncestors = (id: string) => (tree: CollectionPanelFilesState) => {
66     const ancestors = getNodeAncestorsIds(id)(tree).reverse();
67     return ancestors.reduce((newTree, parent) => parent ? toggleParentNode(parent)(newTree) : newTree, tree);
68 };
69
70 const toggleParentNode = (id: string) => (tree: CollectionPanelFilesState) => {
71     const node = getNode(id)(tree);
72     if (node) {
73         const parentNode = getNode(node.id)(tree);
74         if (parentNode) {
75             const selected = parentNode.children
76                 .map(id => getNode(id)(tree))
77                 .every(node => node !== undefined && node.value.selected);
78             return setNodeValueWith(v => ({ ...v, selected }))(parentNode.id)(tree);
79         }
80         return setNode(node)(tree);
81     }
82     return tree;
83 };
84
85