Merge branch 'master' into 13765-information-inside-details-panel
[arvados-workbench2.git] / src / views-components / details-panel / details-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 Drawer from '@material-ui/core/Drawer';
7 import IconButton from "@material-ui/core/IconButton";
8 import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
9 import { ArvadosTheme } from '../../common/custom-theme';
10 import Attribute from '../../components/attribute/attribute';
11 import Tabs from '@material-ui/core/Tabs';
12 import Tab from '@material-ui/core/Tab';
13 import Typography from '@material-ui/core/Typography';
14 import Grid from '@material-ui/core/Grid';
15 import * as classnames from "classnames";
16 import { connect, Dispatch } from 'react-redux';
17 import EmptyState from '../../components/empty-state/empty-state';
18 import { RootState } from '../../store/store';
19 import actions from "../../store/details-panel/details-panel-action";
20 import { Resource } from '../../common/api/common-resource-service';
21 import { ResourceKind } from '../../models/kinds';
22 import { ProjectResource } from '../../models/project';
23 import { CollectionResource } from '../../models/collection';
24 import IconBase, { IconTypes } from '../../components/icon/icon';
25 import { ProcessResource } from '../../models/process';
26
27 export interface DetailsPanelDataProps {
28     onCloseDrawer: () => void;
29     isOpened: boolean;
30     icon: IconTypes;
31     title: string;
32     details: React.ReactElement<any>;
33 }
34
35 type DetailsPanelProps = DetailsPanelDataProps & WithStyles<CssRules>;
36
37 class DetailsPanel extends React.Component<DetailsPanelProps, {}> {
38     state = {
39         tabsValue: 0
40     };
41
42     handleChange = (event: any, value: boolean) => {
43         this.setState({ tabsValue: value });
44     }
45
46     renderTabContainer = (children: React.ReactElement<any>) =>
47         <Typography className={this.props.classes.tabContainer} component="div">
48             {children}
49         </Typography>
50
51     render() {
52         const { classes, onCloseDrawer, isOpened, icon, title, details } = this.props;
53         const { tabsValue } = this.state;
54         return (
55             <Typography component="div" className={classnames([classes.container, { [classes.opened]: isOpened }])}>
56                 <Drawer variant="permanent" anchor="right" classes={{ paper: classes.drawerPaper }}>
57                     <Typography component="div" className={classes.headerContainer}>
58                         <Grid container alignItems='center' justify='space-around'>
59                             <IconBase className={classes.headerIcon} icon={icon} />
60                             <Typography variant="title">
61                                 {title}
62                             </Typography>
63                             <IconButton color="inherit" onClick={onCloseDrawer}>
64                                 <IconBase icon={IconTypes.CLOSE} />
65                             </IconButton>
66                         </Grid>
67                     </Typography>
68                     <Tabs value={tabsValue} onChange={this.handleChange}>
69                         <Tab disableRipple label="Details" />
70                         <Tab disableRipple label="Activity" />
71                     </Tabs>
72                     {tabsValue === 0 && this.renderTabContainer(
73                         <Grid container direction="column">
74                             {details}
75                         </Grid>
76                     )}
77                     {tabsValue === 1 && this.renderTabContainer(
78                         <Grid container direction="column" />
79                     )}
80                 </Drawer>
81             </Typography>
82         );
83     }
84
85 }
86
87 type CssRules = 'drawerPaper' | 'container' | 'opened' | 'headerContainer' | 'headerIcon' | 'tabContainer';
88
89 const drawerWidth = 320;
90 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
91     container: {
92         width: 0,
93         position: 'relative',
94         height: 'auto',
95         transition: 'width 0.5s ease',
96         '&$opened': {
97             width: drawerWidth
98         }
99     },
100     opened: {},
101     drawerPaper: {
102         position: 'relative',
103         width: drawerWidth
104     },
105     headerContainer: {
106         color: theme.palette.grey["600"],
107         margin: `${theme.spacing.unit}px 0`
108     },
109     headerIcon: {
110         fontSize: "34px"
111     },
112     tabContainer: {
113         padding: theme.spacing.unit * 3
114     }
115 });
116
117 type DetailsPanelResource = ProjectResource | CollectionResource | ProcessResource;
118
119 const getIcon = (res: DetailsPanelResource) => {
120     switch (res.kind) {
121         case ResourceKind.Project:
122             return IconTypes.FOLDER;
123         case ResourceKind.Collection:
124             return IconTypes.COLLECTION;
125         case ResourceKind.Process:
126             return IconTypes.PROCESS;
127         default:
128             return IconTypes.FOLDER;
129     }
130 };
131
132 const getDetails = (res: DetailsPanelResource) => {
133     switch (res.kind) {
134         case ResourceKind.Project:
135             return <div>
136                 <Attribute label='Type' value='Project' />
137                 <Attribute label='Size' value='---' />
138                 <Attribute label="Location">
139                     <IconBase icon={IconTypes.FOLDER} />
140                     Projects
141                 </Attribute>
142                 <Attribute label='Owner' value='me' />
143                 <Attribute label='Last modified' value='5:25 PM 5/23/2018' />
144                 <Attribute label='Created at' value='1:25 PM 5/23/2018' />
145                 <Attribute label='File size' value='1.4 GB' />
146             </div>;
147         case ResourceKind.Collection:
148             return <div>
149                 <Attribute label='Type' value='Data Collection' />
150                 <Attribute label='Size' value='---' />
151                 <Attribute label="Location">
152                     <IconBase icon={IconTypes.FOLDER} />
153                     Projects
154                 </Attribute>
155                 <Attribute label='Owner' value='me' />
156                 <Attribute label='Last modified' value='5:25 PM 5/23/2018' />
157                 <Attribute label='Created at' value='1:25 PM 5/23/2018' />
158                 <Attribute label='Number of files' value='20' />
159                 <Attribute label='Content size' value='54 MB' />
160                 <Attribute label='Collection UUID' link='http://www.google.pl' value='nfnz05wp63ibf8w' />
161                 <Attribute label='Content address' link='http://www.google.pl' value='nfnz05wp63ibf8w' />
162                 <Attribute label='Creator' value='Chrystian' />
163                 <Attribute label='Used by' value='---' />
164             </div>;
165         case ResourceKind.Process:
166             return <div>
167                 <Attribute label='Type' value='Process' />
168                 <Attribute label='Size' value='---' />
169                 <Attribute label="Location">
170                     <IconBase icon={IconTypes.FOLDER} />
171                     Projects
172                 </Attribute>
173                 <Attribute label='Owner' value='me' />
174                 <Attribute label='Last modified' value='5:25 PM 5/23/2018' />
175                 <Attribute label='Created at' value='1:25 PM 5/23/2018' />
176                 <Attribute label='Finished at' value='1:25 PM 5/23/2018' />
177                 <Attribute label='Outputs' link='http://www.google.pl' value='Container Output' />
178                 <Attribute label='UUID' link='http://www.google.pl' value='nfnz05wp63ibf8w' />
179                 <Attribute label='Container UUID' link='http://www.google.pl' value='nfnz05wp63ibf8w' />
180                 <Attribute label='Priority' value='1' />
181                 <Attribute label='Runtime constrains' value='1' />
182                 <Attribute label='Docker image locator' link='http://www.google.pl' value='3838388226321' />
183             </div>;
184         default:
185             return getEmptyState();
186     }
187 };
188
189 const getEmptyState = () => {
190     return <EmptyState icon={ IconTypes.ANNOUNCEMENT } 
191         message='Select a file or folder to view its details.' />;
192 };
193
194 const mapStateToProps = ({ detailsPanel }: RootState) => {
195     const { isOpened, item } = detailsPanel;
196     return {
197         isOpened,
198         title: item ? (item as DetailsPanelResource).name : 'Projects',
199         icon: item ? getIcon(item as DetailsPanelResource) : IconTypes.FOLDER,
200         details: item ? getDetails(item as DetailsPanelResource) : getEmptyState()
201     };
202 };
203
204 const mapDispatchToProps = (dispatch: Dispatch) => ({
205     onCloseDrawer: () => {
206         dispatch(actions.TOGGLE_DETAILS_PANEL());
207     }
208 });
209
210 const DetailsPanelContainer = connect(mapStateToProps, mapDispatchToProps)(DetailsPanel);
211
212 export default withStyles(styles)(DetailsPanelContainer);