fix test
[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, ListItemText, ListItemIcon, Collapse, Typography } from "@material-ui/core";
10 import IconBase, { IconTypes } from '../icon/icon';
11 import * as classnames from "classnames";
12
13 export interface SidePanelItem {
14     id: string;
15     name: string;
16     icon: IconTypes;
17     active?: boolean;
18     open?: boolean;
19     margin?: boolean;
20     openAble?: boolean;
21 }
22
23 interface SidePanelProps {
24     toggleOpen: (id: string) => void;
25     toggleActive: (id: string) => void;
26     sidePanelItems: SidePanelItem[];
27     onContextMenu: (event: React.MouseEvent<HTMLElement>, item: SidePanelItem) => void;
28 }
29
30 class SidePanel extends React.Component<SidePanelProps & WithStyles<CssRules>> {
31     render(): ReactElement<any> {
32         const { classes, toggleOpen, toggleActive, sidePanelItems, children } = this.props;
33         const { listItemText, leftSidePanelContainer, row, list, icon, projectIconMargin, active, iconArrowContainer } = classes;
34         return (
35             <div className={leftSidePanelContainer}>
36                 <List>
37                     {sidePanelItems.map(it => (
38                         <span key={it.name}>
39                             <ListItem button className={list} onClick={() => toggleActive(it.id)} onContextMenu={this.handleRowContextMenu(it)}>
40                                 <span className={row}>
41                                     {it.openAble ? (
42                                         <i onClick={() => toggleOpen(it.id)} className={iconArrowContainer}>
43                                             <IconBase icon={IconTypes.PLAY_ARROW} 
44                                                 className={this.getIconClassNames(it.open, it.active)}/>
45                                         </i>
46                                     ) : null}
47                                     <ListItemIcon className={it.active ? active : ''}>
48                                         <IconBase icon={it.icon} 
49                                             className={ `${icon} ${it.margin ? projectIconMargin : ''}` } />
50                                     </ListItemIcon>
51                                     <ListItemText className={listItemText} 
52                                         primary={renderListItemText(it.name, active, it.active)} />
53                                 </span>
54                             </ListItem>
55                             {it.openAble ? (
56                                 <Collapse in={it.open} timeout="auto" unmountOnExit>
57                                     {children}
58                                 </Collapse>
59                             ) : null}
60                         </span>
61                     ))}
62                 </List>
63             </div>
64         );
65     }
66
67     getIconClassNames = (itemOpen ?: boolean, itemActive ?: boolean) => {
68         const { classes } = this.props;
69         return classnames(classes.iconArrow, {
70             [classes.iconOpen]: itemOpen,
71             [classes.iconClose]: !itemOpen,
72             [classes.active]: itemActive
73         });
74     }
75
76     handleRowContextMenu = (item: SidePanelItem) =>
77         (event: React.MouseEvent<HTMLElement>) =>
78             item.openAble ? this.props.onContextMenu(event, item) : null
79
80 }
81
82 const renderListItemText = (itemName: string, active: string, itemActive?: boolean) =>
83     <Typography className={itemActive ? active : ''}>{itemName}</Typography>;
84
85 type CssRules = 'active' | 'listItemText' | 'row' | 'leftSidePanelContainer' | 'list' | 'icon' | 
86     'projectIconMargin' | 'iconClose' | 'iconOpen' | 'iconArrowContainer' | 'iconArrow';
87
88 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
89     active: {
90         color: theme.palette.primary.main,
91     },
92     listItemText: {
93         padding: '0px',
94     },
95     row: {
96         display: 'flex',
97         alignItems: 'center',
98     },
99     iconArrowContainer: {
100         color: theme.palette.grey["700"],
101         height: '14px',
102         position: 'absolute'
103     },
104     iconArrow: {
105         fontSize: '14px'
106     },
107     iconClose: {
108         transition: 'all 0.1s ease',
109     },
110     iconOpen: {
111         transition: 'all 0.1s ease',
112         transform: 'rotate(90deg)',
113     },
114     leftSidePanelContainer: {
115         overflowY: 'auto',
116         minWidth: '240px',
117         whiteSpace: 'nowrap',
118         marginTop: '52px',
119         display: 'flex',
120         flexGrow: 1,
121     },
122     list: {
123         padding: '5px 0px 5px 14px',
124         minWidth: '240px',
125     },
126     icon: {
127         fontSize: '20px'
128     },
129     projectIconMargin: {
130         marginLeft: '17px',
131     }
132 });
133
134 export default withStyles(styles)(SidePanel);