1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
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";
10 export const collectionPanelFilesReducer = (state: CollectionPanelFilesState = createTree(), action: CollectionPanelFilesAction) => {
11 return collectionPanelFilesAction.match(action, {
12 SET_COLLECTION_FILES: files =>
13 mergeCollectionPanelFilesStates(state, mapTree(mapCollectionFileToCollectionPanelFile)(files)),
15 TOGGLE_COLLECTION_FILE_COLLAPSE: data =>
16 toggleCollapse(data.id)(state),
18 TOGGLE_COLLECTION_FILE_SELECTION: data => [state]
19 .map(toggleSelected(data.id))
20 .map(toggleAncestors(data.id))
21 .map(toggleDescendants(data.id))[0],
23 SELECT_ALL_COLLECTION_FILES: () =>
24 mapTreeValues(v => ({ ...v, selected: true }))(state),
26 UNSELECT_ALL_COLLECTION_FILES: () =>
27 mapTreeValues(v => ({ ...v, selected: false }))(state),
30 }) as CollectionPanelFilesState;
33 const toggleCollapse = (id: string) => (tree: CollectionPanelFilesState) =>
34 setNodeValueWith((v: CollectionPanelDirectory | CollectionPanelFile) =>
35 v.type === CollectionFileType.DIRECTORY
36 ? { ...v, collapsed: !v.collapsed }
40 const toggleSelected = (id: string) => (tree: CollectionPanelFilesState) =>
41 setNodeValueWith((v: CollectionPanelDirectory | CollectionPanelFile) => ({ ...v, selected: !v.selected }))(id)(tree);
44 const toggleDescendants = (id: string) => (tree: CollectionPanelFilesState) => {
45 const node = getNode(id)(tree);
46 if (node && node.value.type === CollectionFileType.DIRECTORY) {
47 return getNodeDescendantsIds(id)(tree)
48 .reduce((newTree, id) =>
49 setNodeValueWith(v => ({ ...v, selected: node.value.selected }))(id)(newTree), tree);
54 const toggleAncestors = (id: string) => (tree: CollectionPanelFilesState) => {
55 const ancestors = getNodeAncestorsIds(id)(tree).reverse();
56 return ancestors.reduce((newTree, parent) => parent ? toggleParentNode(parent)(newTree) : newTree, tree);
59 const toggleParentNode = (id: string) => (tree: CollectionPanelFilesState) => {
60 const node = getNode(id)(tree);
62 const parentNode = getNode(node.id)(tree);
64 const selected = parentNode.children
65 .map(id => getNode(id)(tree))
66 .every(node => node !== undefined && node.value.selected);
67 return setNodeValueWith(v => ({ ...v, selected }))(parentNode.id)(tree);
69 return setNode(node)(tree);