].reduce((tree, node) => Tree.setNode(node)(tree), tree);
expect(Tree.getNodeDescendants('Node 1')(newTree)).toEqual(['Node 2', 'Node 3', 'Node 2.1', 'Node 3.1']);
});
-
+
it('gets root descendants', () => {
const newTree = [
{ children: [], id: 'Node 1', parent: '', value: 'Value 1' },
{ children: [], id: 'Node 3', parent: 'Node 1', value: 'Value 1' },
{ children: [], id: 'Node 3.1', parent: 'Node 3', value: 'Value 1' }
].reduce((tree, node) => Tree.setNode(node)(tree), tree);
- expect(Tree.getNodeDescendants('')(newTree)).toEqual(['Node 1','Node 2', 'Node 3', 'Node 2.1', 'Node 3.1']);
+ expect(Tree.getNodeDescendants('')(newTree)).toEqual(['Node 1', 'Node 2', 'Node 3', 'Node 2.1', 'Node 3.1']);
});
-
+
it('gets node children', () => {
const newTree = [
{ children: [], id: 'Node 1', parent: '', value: 'Value 1' },
].reduce((tree, node) => Tree.setNode(node)(tree), tree);
expect(Tree.getNodeChildren('Node 1')(newTree)).toEqual(['Node 2', 'Node 3']);
});
-
+
it('gets root children', () => {
const newTree = [
{ children: [], id: 'Node 1', parent: '', value: 'Value 1' },
].reduce((tree, node) => Tree.setNode(node)(tree), tree);
expect(Tree.getNodeChildren('')(newTree)).toEqual(['Node 1', 'Node 3']);
});
-
- it('maps nodes', () => {
- const newTree = [
- { children: [], id: 'Node 1', parent: '', value: 'Value 1' },
- { children: [], id: 'Node 2', parent: 'Node 1', value: 'Value 1' },
- { children: [], id: 'Node 2.1', parent: 'Node 2', value: 'Value 1' },
- { children: [], id: 'Node 3', parent: 'Node 1', value: 'Value 1' },
- { children: [], id: 'Node 3.1', parent: 'Node 3', value: 'Value 1' }
- ].reduce((tree, node) => Tree.setNode(node)(tree), tree);
- const updatedTree = Tree.mapNodes(['Node 2.1', 'Node 3.1'])(node => ({...node, value: `Updated ${node.value}`}))(newTree);
- expect(Tree.getNode('Node 2.1')(updatedTree)).toEqual({ children: [], id: 'Node 2.1', parent: 'Node 2', value: 'Updated Value 1' },);
- });
-
+
it('maps tree', () => {
const newTree = [
{ children: [], id: 'Node 1', parent: '', value: 'Value 1' },
{ children: [], id: 'Node 2', parent: 'Node 1', value: 'Value 2' },
].reduce((tree, node) => Tree.setNode(node)(tree), tree);
- const mappedTree = Tree.mapTree<string, number>(node => ({...node, value: parseInt(node.value.split(' ')[1], 10)}))(newTree);
- expect(Tree.getNode('Node 2')(mappedTree)).toEqual({ children: [], id: 'Node 2', parent: 'Node 1', value: 2 },);
+ const mappedTree = Tree.mapTreeValues<string, number>(value => parseInt(value.split(' ')[1], 10))(newTree);
+ expect(Tree.getNode('Node 2')(mappedTree)).toEqual({ children: [], id: 'Node 2', parent: 'Node 1', value: 2 }, );
});
});
\ No newline at end of file
return newTree;
};
-export const addChild = (parentId: string, childId: string) => <T>(tree: Tree<T>): Tree<T> => {
- const node = getNode(parentId)(tree);
- if (node) {
- const children = node.children.some(id => id === childId)
- ? node.children
- : [...node.children, childId];
+export const getNodeValue = (id: string) => <T>(tree: Tree<T>) => {
+ const node = getNode(id)(tree);
+ return node ? node.value : undefined;
+};
- const newNode = children === node.children
- ? node
- : { ...node, children };
+export const setNodeValue = (id: string) => <T>(value: T) => (tree: Tree<T>) => {
+ const node = getNode(id)(tree);
+ return node
+ ? setNode(mapNodeValue(() => value)(node))(tree)
+ : tree;
+};
- return setNode(newNode)(tree);
- }
- return tree;
+export const setNodeValueWith = <T>(mapFn: (value: T) => T) => (id: string) => (tree: Tree<T>) => {
+ const node = getNode(id)(tree);
+ return node
+ ? setNode(mapNodeValue(mapFn)(node))(tree)
+ : tree;
};
+export const mapTreeValues = <T, R>(mapFn: (value: T) => R) => (tree: Tree<T>): Tree<R> =>
+ getNodeDescendants('')(tree)
+ .map(id => getNode(id)(tree))
+ .map(mapNodeValue(mapFn))
+ .reduce((newTree, node) => setNode(node)(newTree), createTree<R>());
+
+export const mapTree = <T, R>(mapFn: (node: TreeNode<T>) => TreeNode<R>) => (tree: Tree<T>): Tree<R> =>
+ getNodeDescendants('')(tree)
+ .map(id => getNode(id)(tree))
+ .map(mapFn)
+ .reduce((newTree, node) => setNode(node)(newTree), createTree<R>());
export const getNodeAncestors = (id: string) => <T>(tree: Tree<T>): string[] => {
const node = getNode(id)(tree);
export const getNodeChildren = (id: string) => <T>(tree: Tree<T>): string[] =>
getNodeDescendants(id, 0)(tree);
-export const mapNodes = (ids: string[]) => <T>(mapFn: (node: TreeNode<T>) => TreeNode<T>) => (tree: Tree<T>): Tree<T> =>
- ids
- .map(id => getNode(id)(tree))
- .map(mapFn)
- .map(setNode)
- .reduce((tree, update) => update(tree), tree);
-
-export const mapTree = <T, R>(mapFn: (node: TreeNode<T>) => TreeNode<R>) => (tree: Tree<T>): Tree<R> =>
- getNodeDescendants('')(tree)
- .map(id => getNode(id)(tree))
- .map(mapFn)
- .reduce((newTree, node) => setNode(node)(newTree), createTree<R>());
-
-export const mapNodeValue = <T>(mapFn: (value: T) => T) => (node: TreeNode<T>) =>
+const mapNodeValue = <T, R>(mapFn: (value: T) => R) => (node: TreeNode<T>): TreeNode<R> =>
({ ...node, value: mapFn(node.value) });
const getRootNodeChildren = <T>(tree: Tree<T>) =>
.keys(tree)
.filter(id => getNode(id)(tree)!.parent === TREE_ROOT_ID);
+const addChild = (parentId: string, childId: string) => <T>(tree: Tree<T>): Tree<T> => {
+ const node = getNode(parentId)(tree);
+ if (node) {
+ const children = node.children.some(id => id === childId)
+ ? node.children
+ : [...node.children, childId];
+ const newNode = children === node.children
+ ? node
+ : { ...node, children };
+ return setNode(newNode)(tree);
+ }
+ return tree;
+};
import { CollectionPanelFilesState, CollectionPanelFile, CollectionPanelDirectory, mapCollectionFileToCollectionPanelFile } from "./collection-panel-files-state";
import { CollectionPanelFilesAction, collectionPanelFilesAction } from "./collection-panel-files-actions";
-import { createTree, mapTree, TreeNode, mapNodes, getNode, setNode, getNodeAncestors, getNodeDescendants, mapNodeValue } from "../../../models/tree";
+import { createTree, mapTreeValues, getNode, setNode, getNodeAncestors, getNodeDescendants, setNodeValueWith, mapTree } from "../../../models/tree";
import { CollectionFileType } from "../../../models/collection-file";
export const collectionPanelFilesReducer = (state: CollectionPanelFilesState = createTree(), action: CollectionPanelFilesAction) => {
.map(toggleDescendants(data.id))[0],
SELECT_ALL_COLLECTION_FILES: () =>
- mapTree(mapNodeValue(v => ({ ...v, selected: true })))(state),
+ mapTreeValues(v => ({ ...v, selected: true }))(state),
UNSELECT_ALL_COLLECTION_FILES: () =>
- mapTree(mapNodeValue(v => ({ ...v, selected: false })))(state),
-
+ mapTreeValues(v => ({ ...v, selected: false }))(state),
+
default: () => state
});
};
const toggleCollapse = (id: string) => (tree: CollectionPanelFilesState) =>
- mapNodes
- ([id])
- (mapNodeValue((v: CollectionPanelDirectory | CollectionPanelFile) =>
- v.type === CollectionFileType.DIRECTORY
- ? { ...v, collapsed: !v.collapsed }
- : v))
- (tree);
+ setNodeValueWith((v: CollectionPanelDirectory | CollectionPanelFile) =>
+ v.type === CollectionFileType.DIRECTORY
+ ? { ...v, collapsed: !v.collapsed }
+ : v)(id)(tree);
+
const toggleSelected = (id: string) => (tree: CollectionPanelFilesState) =>
- mapNodes
- ([id])
- (mapNodeValue((v: CollectionPanelDirectory | CollectionPanelFile) => ({ ...v, selected: !v.selected })))
- (tree);
+ setNodeValueWith((v: CollectionPanelDirectory | CollectionPanelFile) => ({ ...v, selected: !v.selected }))(id)(tree);
const toggleDescendants = (id: string) => (tree: CollectionPanelFilesState) => {
const node = getNode(id)(tree);
if (node && node.value.type === CollectionFileType.DIRECTORY) {
- return mapNodes(getNodeDescendants(id)(tree))(mapNodeValue(v => ({ ...v, selected: node.value.selected })))(tree);
+ return getNodeDescendants(id)(tree)
+ .reduce((newTree, id) =>
+ setNodeValueWith(v => ({ ...v, selected: node.value.selected }))(id)(newTree), tree);
}
return tree;
};
const toggleAncestors = (id: string) => (tree: CollectionPanelFilesState) => {
- const ancestors = getNodeAncestors(id)(tree)
- .map(id => getNode(id)(tree))
- .reverse();
- return ancestors.reduce((newTree, parent) => parent !== undefined ? toggleParentNode(parent)(newTree) : newTree, tree);
+ const ancestors = getNodeAncestors(id)(tree).reverse();
+ return ancestors.reduce((newTree, parent) => parent ? toggleParentNode(parent)(newTree) : newTree, tree);
};
-const toggleParentNode = (node: TreeNode<CollectionPanelDirectory | CollectionPanelFile>) => (tree: CollectionPanelFilesState) => {
- const parentNode = getNode(node.id)(tree);
- if (parentNode) {
- const selected = parentNode.children
- .map(id => getNode(id)(tree))
- .every(node => node !== undefined && node.value.selected);
- return setNode(mapNodeValue(v => ({ ...v, selected }))(parentNode))(tree);
+const toggleParentNode = (id: string) => (tree: CollectionPanelFilesState) => {
+ const node = getNode(id)(tree);
+ if (node) {
+ const parentNode = getNode(node.id)(tree);
+ if (parentNode) {
+ const selected = parentNode.children
+ .map(id => getNode(id)(tree))
+ .every(node => node !== undefined && node.value.selected);
+ return setNodeValueWith(v => ({ ...v, selected }))(parentNode.id)(tree);
+ }
+ return setNode(node)(tree);
}
- return setNode(node)(tree);
+ return tree;
};