context menu for groups panel
[arvados.git] / src / store / tree-picker / tree-picker-reducer.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { createTree, TreeNode, setNode, Tree, TreeNodeStatus, setNodeStatus, expandNode, deactivateNode, deselectNode, selectNode, selectNodes, deselectNodes } from '~/models/tree';
6 import { TreePicker } from "./tree-picker";
7 import { treePickerActions, TreePickerAction } from "./tree-picker-actions";
8 import { compose } from "redux";
9 import { activateNode, getNode, toggleNodeCollapse, toggleNodeSelection } from '~/models/tree';
10 import { pipe } from 'lodash/fp';
11 import { appendSubtree } from '~/models/tree';
12
13 export const treePickerReducer = (state: TreePicker = {}, action: TreePickerAction) =>
14     treePickerActions.match(action, {
15         LOAD_TREE_PICKER_NODE: ({ id, pickerId }) =>
16             updateOrCreatePicker(state, pickerId, setNodeStatus(id)(TreeNodeStatus.PENDING)),
17
18         LOAD_TREE_PICKER_NODE_SUCCESS: ({ id, nodes, pickerId }) =>
19             updateOrCreatePicker(state, pickerId, compose(receiveNodes(nodes)(id), setNodeStatus(id)(TreeNodeStatus.LOADED))),
20
21         APPEND_TREE_PICKER_NODE_SUBTREE: ({ id, subtree, pickerId}) =>
22             updateOrCreatePicker(state, pickerId, compose(appendSubtree(id, subtree), setNodeStatus(id)(TreeNodeStatus.LOADED))),
23
24         TOGGLE_TREE_PICKER_NODE_COLLAPSE: ({ id, pickerId }) =>
25             updateOrCreatePicker(state, pickerId, toggleNodeCollapse(id)),
26
27         ACTIVATE_TREE_PICKER_NODE: ({ id, pickerId, relatedTreePickers = [] }) =>
28             pipe(
29                 () => relatedTreePickers.reduce(
30                     (state, relatedPickerId) => updateOrCreatePicker(state, relatedPickerId, deactivateNode),
31                     state
32                 ),
33                 state => updateOrCreatePicker(state, pickerId, activateNode(id))
34             )(),
35
36         DEACTIVATE_TREE_PICKER_NODE: ({ pickerId }) =>
37             updateOrCreatePicker(state, pickerId, deactivateNode),
38
39         TOGGLE_TREE_PICKER_NODE_SELECTION: ({ id, pickerId }) =>
40             updateOrCreatePicker(state, pickerId, toggleNodeSelection(id)),
41
42         SELECT_TREE_PICKER_NODE: ({ id, pickerId }) =>
43             updateOrCreatePicker(state, pickerId, selectNodes(id)),
44
45         DESELECT_TREE_PICKER_NODE: ({ id, pickerId }) =>
46             updateOrCreatePicker(state, pickerId, deselectNodes(id)),
47
48         RESET_TREE_PICKER: ({ pickerId }) =>
49             updateOrCreatePicker(state, pickerId, createTree),
50
51         EXPAND_TREE_PICKER_NODES: ({ pickerId, ids }) =>
52             updateOrCreatePicker(state, pickerId, expandNode(...ids)),
53
54         default: () => state
55     });
56
57 const updateOrCreatePicker = <V>(state: TreePicker, pickerId: string, func: (value: Tree<V>) => Tree<V>) => {
58     const picker = state[pickerId] || createTree();
59     const updatedPicker = func(picker);
60     return { ...state, [pickerId]: updatedPicker };
61 };
62
63 const receiveNodes = <V>(nodes: Array<TreeNode<V>>) => (parent: string) => (state: Tree<V>) => {
64     const parentNode = getNode(parent)(state);
65     let newState = state;
66     if (parentNode) {
67         newState = setNode({ ...parentNode, children: [] })(state);
68     }
69     return nodes.reduce((tree, node) => {
70         return setNode({ ...node, parent })(tree);
71     }, newState);
72 };