Merge branch '22135-project-loading-indicator'
[arvados.git] / services / workbench2 / src / views-components / side-panel-tree / side-panel-tree.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React from "react";
6 import { Dispatch } from "redux";
7 import { connect } from "react-redux";
8 import { TreePicker, TreePickerProps } from "../tree-picker/tree-picker";
9 import { TreeItem } from "components/tree/tree";
10 import { ProjectResource } from "models/project";
11 import { ListItemTextIcon } from "components/list-item-text-icon/list-item-text-icon";
12 import { activateSidePanelTreeItem,
13          toggleSidePanelTreeItemCollapse,
14          SIDE_PANEL_TREE,
15          SidePanelTreeCategory,
16          getSidePanelIcon
17 } from 'store/side-panel-tree/side-panel-tree-actions';
18 import { openSidePanelContextMenu } from 'store/context-menu/context-menu-actions';
19 import { noop } from 'lodash';
20 import { ResourceKind } from "models/resource";
21 import { IllegalNamingWarning } from "components/warning/warning";
22 import { GroupClass } from "models/group";
23 import { setSelectedResourceUuid } from "store/selected-resource/selected-resource-actions";
24 import { FilterGroupIcon, ProjectsIcon } from 'components/icon/icon';
25
26 export interface SidePanelTreeProps {
27     onItemActivation: (id: string) => void;
28     sidePanelProgress?: boolean;
29     isCollapsed?: boolean;
30     currentSideWidth?: number;
31     currentRoute?: string;
32     isDetailsPanelTransitioning?: boolean;
33     setCurrentSideWidth: (width: number) => void
34 }
35
36 type SidePanelTreeActionProps = Pick<TreePickerProps<ProjectResource | string>, 'onContextMenu' | 'toggleItemActive' | 'toggleItemOpen' | 'toggleItemSelection'>;
37
38 const mapDispatchToProps = (dispatch: Dispatch, props: SidePanelTreeProps): SidePanelTreeActionProps => ({
39     onContextMenu: (event, { id }) => {
40         dispatch<any>(openSidePanelContextMenu(event, id));
41     },
42     toggleItemActive: (_, { id }) => {
43         dispatch<any>(activateSidePanelTreeItem(id));
44         const isSidePanelCat = Object.values(SidePanelTreeCategory).includes(id as SidePanelTreeCategory);
45         dispatch<any>(setSelectedResourceUuid(isSidePanelCat ? null : id));
46         props.onItemActivation(id);
47     },
48     toggleItemOpen: (_, { id }) => {
49         dispatch<any>(toggleSidePanelTreeItemCollapse(id));
50     },
51     toggleItemSelection: noop,
52 });
53
54 export const SidePanelTree = connect(undefined, mapDispatchToProps)(
55     (props: SidePanelTreeActionProps) =>
56         <div data-cy="side-panel-tree" style={{minWidth: 240}}>
57             <TreePicker {...props} render={renderSidePanelItem} pickerId={SIDE_PANEL_TREE} />
58         </div>);
59
60 const renderSidePanelItem = (item: TreeItem<ProjectResource>) => {
61     const name = typeof item.data === 'string' ? item.data : item.data.name;
62     const warn = typeof item.data !== 'string' && item.data.kind === ResourceKind.PROJECT
63         ? <IllegalNamingWarning name={name} />
64         : undefined;
65     return <ListItemTextIcon
66         icon={getProjectPickerIcon(item)}
67         name={name}
68         nameDecorator={warn}
69         isActive={item.active}
70         hasMargin={true}
71     />;
72 };
73
74 const getProjectPickerIcon = (item: TreeItem<ProjectResource | string>) =>
75     typeof item.data === 'string'
76         ? getSidePanelIcon(item.data)
77         : (item.data && item.data.groupClass === GroupClass.FILTER)
78             ? FilterGroupIcon
79             : ProjectsIcon;