ec648e11b2e6d84922e57a54a6e57f973f381e1c
[arvados-workbench2.git] / src / components / side-panel / side-panel.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as React from 'react';
6 import { ReactElement } from 'react';
7 import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
8 import { ArvadosTheme } from '../../common/custom-theme';
9 import { List, ListItem, ListItemIcon, Collapse } from "@material-ui/core";
10 import { SidePanelRightArrowIcon, IconType } from '../icon/icon';
11 import * as classnames from "classnames";
12 import { ListItemTextIcon } from '../list-item-text-icon/list-item-text-icon';
13 import { Dispatch } from "redux";
14
15 type CssRules = 'active' | 'row' | 'root' | 'list' | 'iconClose' | 'iconOpen' | 'toggableIconContainer' | 'toggableIcon';
16
17 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
18     root: {
19         overflowY: 'auto',
20         minWidth: '240px',
21         whiteSpace: 'nowrap',
22         marginTop: '52px',
23         display: 'flex',
24         flexGrow: 1,
25     },
26     list: {
27         padding: '5px 0px 5px 14px',
28         minWidth: '240px',
29     },
30     row: {
31         display: 'flex',
32         alignItems: 'center',
33     },
34     toggableIconContainer: {
35         color: theme.palette.grey["700"],
36         height: '14px',
37         width: '14px'
38     },
39     toggableIcon: {
40         fontSize: '14px'
41     },
42     active: {
43         color: theme.palette.primary.main,
44     },
45     iconClose: {
46         transition: 'all 0.1s ease',
47     },
48     iconOpen: {
49         transition: 'all 0.1s ease',
50         transform: 'rotate(90deg)',
51     }
52 });
53
54 export interface SidePanelItem {
55     id: string;
56     name: string;
57     icon: IconType;
58     active?: boolean;
59     open?: boolean;
60     margin?: boolean;
61     openAble?: boolean;
62     activeAction?: (dispatch: Dispatch) => void;
63 }
64
65 interface SidePanelDataProps {
66     toggleOpen: (id: string) => void;
67     toggleActive: (id: string) => void;
68     sidePanelItems: SidePanelItem[];
69     onContextMenu: (event: React.MouseEvent<HTMLElement>, item: SidePanelItem) => void;
70 }
71
72 type SidePanelProps = SidePanelDataProps & WithStyles<CssRules>;
73
74 export const SidePanel = withStyles(styles)(
75     class extends React.Component<SidePanelProps> {
76         render(): ReactElement<any> {
77             const { classes, toggleOpen, toggleActive, sidePanelItems, children } = this.props;
78             const { root, row, list, toggableIconContainer } = classes;
79             return (
80                 <div className={root}>
81                     <List>
82                         {sidePanelItems.map(it => (
83                             <span key={it.name}>
84                                 <ListItem button className={list} onClick={() => toggleActive(it.id)}
85                                           onContextMenu={this.handleRowContextMenu(it)}>
86                                     <span className={row}>
87                                         {it.openAble ? (
88                                             <i onClick={() => toggleOpen(it.id)} className={toggableIconContainer}>
89                                                 <ListItemIcon
90                                                     className={this.getToggableIconClassNames(it.open, it.active)}>
91                                                     < SidePanelRightArrowIcon/>
92                                                 </ListItemIcon>
93                                             </i>
94                                         ) : null}
95                                         <ListItemTextIcon icon={it.icon} name={it.name} isActive={it.active}
96                                                           hasMargin={it.margin}/>
97                                     </span>
98                                 </ListItem>
99                                 {it.openAble ? (
100                                     <Collapse in={it.open} timeout="auto" unmountOnExit>
101                                         {children}
102                                     </Collapse>
103                                 ) : null}
104                             </span>
105                         ))}
106                     </List>
107                 </div>
108             );
109         }
110
111         getToggableIconClassNames = (isOpen?: boolean, isActive ?: boolean) => {
112             const { iconOpen, iconClose, active, toggableIcon } = this.props.classes;
113             return classnames(toggableIcon, {
114                 [iconOpen]: isOpen,
115                 [iconClose]: !isOpen,
116                 [active]: isActive
117             });
118         }
119
120         handleRowContextMenu = (item: SidePanelItem) =>
121             (event: React.MouseEvent<HTMLElement>) =>
122                 item.openAble ? this.props.onContextMenu(event, item) : null
123     }
124 );