Merge branch '21225-project-panel-tabs' into main. Closes #21225
[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 { ProcessIcon, ProjectIcon, FilterGroupIcon, FavoriteIcon, ProjectsIcon, ShareMeIcon, TrashIcon, PublicFavoriteIcon, GroupsIcon, TerminalIcon, ResourceIcon } from 'components/icon/icon';
13 import { activateSidePanelTreeItem, toggleSidePanelTreeItemCollapse, SIDE_PANEL_TREE, SidePanelTreeCategory } from 'store/side-panel-tree/side-panel-tree-actions';
14 import { openSidePanelContextMenu } from 'store/context-menu/context-menu-actions';
15 import { noop } from 'lodash';
16 import { ResourceKind } from "models/resource";
17 import { IllegalNamingWarning } from "components/warning/warning";
18 import { GroupClass } from "models/group";
19 import { setSelectedResourceUuid } from "store/selected-resource/selected-resource-actions";
20
21 export interface SidePanelTreeProps {
22     onItemActivation: (id: string) => void;
23     sidePanelProgress?: boolean;
24     isCollapsed?: boolean;
25     currentSideWidth?: number;
26     currentRoute?: string;
27     isDetailsPanelTransitioning?: boolean;
28     setCurrentSideWidth: (width: number) => void
29 }
30
31 type SidePanelTreeActionProps = Pick<TreePickerProps<ProjectResource | string>, 'onContextMenu' | 'toggleItemActive' | 'toggleItemOpen' | 'toggleItemSelection'>;
32
33 const mapDispatchToProps = (dispatch: Dispatch, props: SidePanelTreeProps): SidePanelTreeActionProps => ({
34     onContextMenu: (event, { id }) => {
35         dispatch<any>(openSidePanelContextMenu(event, id));
36     },
37     toggleItemActive: (_, { id }) => {
38         dispatch<any>(activateSidePanelTreeItem(id));
39         const isSidePanelCat = Object.values(SidePanelTreeCategory).includes(id as SidePanelTreeCategory);
40         dispatch<any>(setSelectedResourceUuid(isSidePanelCat ? null : id));
41         props.onItemActivation(id);
42     },
43     toggleItemOpen: (_, { id }) => {
44         dispatch<any>(toggleSidePanelTreeItemCollapse(id));
45     },
46     toggleItemSelection: noop,
47 });
48
49 export const SidePanelTree = connect(undefined, mapDispatchToProps)(
50     (props: SidePanelTreeActionProps) =>
51         <div data-cy="side-panel-tree">
52             <TreePicker {...props} render={renderSidePanelItem} pickerId={SIDE_PANEL_TREE} />
53         </div>);
54
55 const renderSidePanelItem = (item: TreeItem<ProjectResource>) => {
56     const name = typeof item.data === 'string' ? item.data : item.data.name;
57     const warn = typeof item.data !== 'string' && item.data.kind === ResourceKind.PROJECT
58         ? <IllegalNamingWarning name={name} />
59         : undefined;
60     return <ListItemTextIcon
61         icon={getProjectPickerIcon(item)}
62         name={name}
63         nameDecorator={warn}
64         isActive={item.active}
65         hasMargin={true}
66     />;
67 };
68
69 const getProjectPickerIcon = (item: TreeItem<ProjectResource | string>) =>
70     typeof item.data === 'string'
71         ? getSidePanelIcon(item.data)
72         : (item.data && item.data.groupClass === GroupClass.FILTER)
73             ? FilterGroupIcon
74             : ProjectsIcon;
75
76 export const getSidePanelIcon = (category: string) => {
77     switch (category) {
78         case SidePanelTreeCategory.FAVORITES:
79             return FavoriteIcon;
80         case SidePanelTreeCategory.PROJECTS:
81             return ProjectsIcon;
82         case SidePanelTreeCategory.SHARED_WITH_ME:
83             return ShareMeIcon;
84         case SidePanelTreeCategory.TRASH:
85             return TrashIcon;
86         case SidePanelTreeCategory.PUBLIC_FAVORITES:
87             return PublicFavoriteIcon;
88         case SidePanelTreeCategory.ALL_PROCESSES:
89             return ProcessIcon;
90         case SidePanelTreeCategory.INSTANCE_TYPES:
91             return ResourceIcon;
92         case SidePanelTreeCategory.GROUPS:
93             return GroupsIcon;
94         case SidePanelTreeCategory.SHELL_ACCESS:
95             return TerminalIcon
96         default:
97             return ProjectIcon;
98     }
99 };