Optimize side panel tree
[arvados-workbench2.git] / src / views-components / tree-picker / tree-picker.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { connect } from "react-redux";
6 import { Tree, TreeProps, TreeItem, TreeItemStatus } from "~/components/tree/tree";
7 import { RootState } from "~/store/store";
8 import { createTreePickerNode, TreePickerNode } from "~/store/tree-picker/tree-picker";
9 import { getNodeValue, getNodeChildrenIds, Tree as Ttree, createTree } from "~/models/tree";
10 import { Dispatch } from "redux";
11
12 export interface TreePickerProps {
13     pickerId: string;
14     onContextMenu: (event: React.MouseEvent<HTMLElement>, nodeId: string, pickerId: string) => void;
15     toggleItemOpen: (nodeId: string, status: TreeItemStatus, pickerId: string) => void;
16     toggleItemActive: (nodeId: string, status: TreeItemStatus, pickerId: string) => void;
17 }
18
19 const memoizedMapStateToProps = () => {
20     let prevTree: Ttree<TreePickerNode>;
21     let mappedProps: Pick<TreeProps<any>, 'items'>;
22     return (state: RootState, props: TreePickerProps): Pick<TreeProps<any>, 'items'> => {
23         const tree = state.treePicker[props.pickerId] || createTree();
24         if(tree !== prevTree){
25             prevTree = tree;
26             mappedProps = {
27                 items: getNodeChildrenIds('')(tree)
28                     .map(treePickerToTreeItems(tree))
29             };
30         }
31         return mappedProps;
32     };
33 };
34
35 const mapDispatchToProps = (dispatch: Dispatch, props: TreePickerProps): Pick<TreeProps<any>, 'onContextMenu' | 'toggleItemOpen' | 'toggleItemActive'> => ({
36     onContextMenu: (event, item) => props.onContextMenu(event, item.id, props.pickerId),
37     toggleItemActive: (id, status) => props.toggleItemActive(id, status, props.pickerId),
38     toggleItemOpen: (id, status) => props.toggleItemOpen(id, status, props.pickerId)
39 });
40
41 export const TreePicker = connect(memoizedMapStateToProps(), mapDispatchToProps)(Tree);
42
43 const treePickerToTreeItems = (tree: Ttree<TreePickerNode>) =>
44     (id: string): TreeItem<any> => {
45         const node: TreePickerNode = getNodeValue(id)(tree) || createTreePickerNode({ nodeId: '', value: 'InvalidNode' });
46         const items = getNodeChildrenIds(node.nodeId)(tree)
47             .map(treePickerToTreeItems(tree));
48         return {
49             active: node.selected,
50             data: node.value,
51             id: node.nodeId,
52             items: items.length > 0 ? items : undefined,
53             open: !node.collapsed,
54             status: node.status
55         };
56     };
57