2c74eb239d1774d20937c6b44745cf526a74f6c6
[arvados-workbench2.git] / src / store / project / project-reducer.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { Project } from "../../models/project";
6 import actions, { ProjectAction } from "./project-action";
7 import { TreeItem, TreeItemStatus } from "../../components/tree/tree";
8 import * as _ from "lodash";
9
10 export type ProjectState = Array<TreeItem<Project>>;
11
12 export function findTreeItem<T>(tree: Array<TreeItem<T>>, itemId: string): TreeItem<T> | undefined {
13     let item;
14     for (const t of tree) {
15         item = t.id === itemId
16             ? t
17             : findTreeItem(t.items ? t.items : [], itemId);
18         if (item) {
19             break;
20         }
21     }
22     return item;
23 }
24
25 export function getActiveTreeItem<T>(tree: Array<TreeItem<T>>): TreeItem<T> | undefined {
26     let item;
27     for (const t of tree) {
28         item = t.active
29             ? t
30             : getActiveTreeItem(t.items ? t.items : []);
31         if (item) {
32             break;
33         }
34     }
35     return item;
36 }
37
38 export function getTreePath<T>(tree: Array<TreeItem<T>>, itemId: string): Array<TreeItem<T>> {
39     for (const item of tree){
40         if(item.id === itemId){
41             return [item];
42         } else {
43             const branch = getTreePath(item.items || [], itemId);
44             if(branch.length > 0){
45                 return [item, ...branch];
46             }
47         }
48     }
49     return [];
50 }
51
52 function resetTreeActivity<T>(tree: Array<TreeItem<T>>) {
53     for (const t of tree) {
54         t.active = false;
55         resetTreeActivity(t.items ? t.items : []);
56     }
57 }
58
59 function updateProjectTree(tree: Array<TreeItem<Project>>, projects: Project[], parentItemId?: string): Array<TreeItem<Project>> {
60     let treeItem;
61     if (parentItemId) {
62         treeItem = findTreeItem(tree, parentItemId);
63         if (treeItem) {
64             treeItem.status = TreeItemStatus.Loaded;
65         }
66     }
67     const items = projects.map((p, idx) => ({
68         id: p.uuid,
69         open: false,
70         active: false,
71         status: TreeItemStatus.Initial,
72         data: p,
73         items: []
74     } as TreeItem<Project>));
75
76     if (treeItem) {
77         treeItem.items = items;
78         return tree;
79     }
80
81     return items;
82 }
83
84 const projectsReducer = (state: ProjectState = [], action: ProjectAction) => {
85     return actions.match(action, {
86         CREATE_PROJECT: project => [...state, project],
87         REMOVE_PROJECT: () => state,
88         PROJECTS_REQUEST: itemId => {
89             const tree = _.cloneDeep(state);
90             const item = findTreeItem(tree, itemId);
91             if (item) {
92                 item.status = TreeItemStatus.Pending;
93             }
94             return tree;
95         },
96         PROJECTS_SUCCESS: ({ projects, parentItemId }) => {
97             return updateProjectTree(state, projects, parentItemId);
98         },
99         TOGGLE_PROJECT_TREE_ITEM: itemId => {
100             const tree = _.cloneDeep(state);
101             resetTreeActivity(tree);
102             const item = findTreeItem(tree, itemId);
103             if (item) {
104                 item.open = !item.open;
105                 item.active = true;
106                 item.toggled = true;
107             }
108             return tree;
109         },
110         default: () => state
111     });
112 };
113
114 export default projectsReducer;