1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import * as _ from "lodash";
7 import { projectActions, ProjectAction } from "./project-action";
8 import { TreeItem, TreeItemStatus } from "~/components/tree/tree";
9 import { ProjectResource } from "~/models/project";
11 export type ProjectState = {
12 items: Array<TreeItem<ProjectResource>>,
13 currentItemId: string,
14 creator: ProjectCreator,
15 updater: ProjectUpdater
18 interface ProjectCreator {
24 interface ProjectUpdater {
29 export function findTreeItem<T>(tree: Array<TreeItem<T>>, itemId: string): TreeItem<T> | undefined {
31 for (const t of tree) {
32 item = t.id === itemId
34 : findTreeItem(t.items ? t.items : [], itemId);
42 export function getActiveTreeItem<T>(tree: Array<TreeItem<T>>): TreeItem<T> | undefined {
44 for (const t of tree) {
47 : getActiveTreeItem(t.items ? t.items : []);
55 export function getTreePath<T>(tree: Array<TreeItem<T>>, itemId: string): Array<TreeItem<T>> {
56 for (const item of tree) {
57 if (item.id === itemId) {
60 const branch = getTreePath(item.items || [], itemId);
61 if (branch.length > 0) {
62 return [item, ...branch];
69 function resetTreeActivity<T>(tree: Array<TreeItem<T>>) {
70 for (const t of tree) {
72 resetTreeActivity(t.items ? t.items : []);
76 function updateProjectTree(tree: Array<TreeItem<ProjectResource>>, projects: ProjectResource[], parentItemId?: string): Array<TreeItem<ProjectResource>> {
79 treeItem = findTreeItem(tree, parentItemId);
81 treeItem.status = TreeItemStatus.LOADED;
84 const items = projects.map(p => ({
88 status: TreeItemStatus.INITIAL,
91 } as TreeItem<ProjectResource>));
94 treeItem.items = items;
101 const updateCreator = (state: ProjectState, creator: Partial<ProjectCreator>) => ({
109 const updateProject = (state: ProjectState, updater?: Partial<ProjectUpdater>) => ({
117 const initialState: ProjectState = {
131 export const projectsReducer = (state: ProjectState = initialState, action: ProjectAction) => {
132 return projectActions.match(action, {
133 OPEN_PROJECT_CREATOR: ({ ownerUuid }) => updateCreator(state, { ownerUuid, opened: true }),
134 CLOSE_PROJECT_CREATOR: () => updateCreator(state, { opened: false }),
135 CREATE_PROJECT: () => updateCreator(state, { error: undefined }),
136 CREATE_PROJECT_SUCCESS: () => updateCreator(state, { opened: false, ownerUuid: "" }),
137 OPEN_PROJECT_UPDATER: ({ uuid }) => updateProject(state, { uuid, opened: true }),
138 CLOSE_PROJECT_UPDATER: () => updateProject(state, { opened: false, uuid: "" }),
139 UPDATE_PROJECT_SUCCESS: () => updateProject(state, { opened: false, uuid: "" }),
140 REMOVE_PROJECT: () => state,
141 PROJECTS_REQUEST: itemId => {
142 const items = _.cloneDeep(state.items);
143 const item = findTreeItem(items, itemId);
145 item.status = TreeItemStatus.PENDING;
148 return { ...state, items };
150 PROJECTS_SUCCESS: ({ projects, parentItemId }) => {
151 const items = _.cloneDeep(state.items);
154 items: updateProjectTree(items, projects, parentItemId)
157 TOGGLE_PROJECT_TREE_ITEM_OPEN: itemId => {
158 const items = _.cloneDeep(state.items);
159 const item = findTreeItem(items, itemId);
161 item.open = !item.open;
166 currentItemId: itemId
169 TOGGLE_PROJECT_TREE_ITEM_ACTIVE: itemId => {
170 const items = _.cloneDeep(state.items);
171 resetTreeActivity(items);
172 const item = findTreeItem(items, itemId);
179 currentItemId: itemId
182 RESET_PROJECT_TREE_ACTIVITY: () => {
183 const items = _.cloneDeep(state.items);
184 resetTreeActivity(items);