merge changes
[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
26 export interface DetailsPanelDataProps {
27     onCloseDrawer: () => void;
28     isOpened: boolean;
29     header: React.ReactElement<any>;
30     renderDetails?: React.ComponentType<{}>;
31     renderActivity?: React.ComponentType<{}>;
32 }
33
34 type DetailsPanelProps = DetailsPanelDataProps & WithStyles<CssRules>;
35
36 class DetailsPanel extends React.Component<DetailsPanelProps, {}> {
37     state = {
38         tabsValue: 0
39     };
40
41     handleChange = (event: any, value: boolean) => {
42         this.setState({ tabsValue: value });
43     }
44
45     renderTabContainer = (children: React.ReactElement<any>) =>
46         <Typography className={this.props.classes.tabContainer} component="div">
47             {children}
48         </Typography>
49
50     render() {
51         const { classes, onCloseDrawer, isOpened, header, renderDetails, renderActivity } = this.props;
52         const { tabsValue } = this.state;
53         return (
54             <Typography component="div" className={classnames([classes.container, { [classes.opened]: isOpened }])}>
55                 <Drawer variant="permanent" anchor="right" classes={{ paper: classes.drawerPaper }}>
56                     <Typography component="div" className={classes.headerContainer}>
57                         <Grid container alignItems='center' justify='space-around'>
58                             {header}
59                             <IconButton color="inherit" onClick={onCloseDrawer}>
60                                 <IconBase icon={IconTypes.CLOSE} />
61                             </IconButton>
62                         </Grid>
63                     </Typography>
64                     <Tabs value={tabsValue} onChange={this.handleChange}>
65                         <Tab disableRipple label="Details" />
66                         <Tab disableRipple label="Activity" />
67                     </Tabs>
68                     {tabsValue === 0 && this.renderTabContainer(
69                         <Grid container direction="column">
70                             {renderDetails}
71                             <EmptyState icon={IconTypes.ANNOUNCEMENT}
72                                 message='Select a file or folder to view its details.' />
73                             <Attribute label='Type' value='Process' />
74                             <Attribute label='Size' value='---' />
75                             <Attribute label="Location">
76                                 <IconBase icon={IconTypes.FOLDER} />
77                                 Projects
78                             </Attribute>
79                             <Attribute label='Outputs' link='http://www.google.pl' value='New output as link' />
80                             <Attribute label='Owner' value='me' />
81                         </Grid>
82                     )}
83                     {tabsValue === 1 && this.renderTabContainer(
84                         <Grid container direction="column">
85                             {renderActivity}
86                             <EmptyState icon={IconTypes.ANNOUNCEMENT} message='Select a file or folder to view its details.' />
87                         </Grid>
88                     )}
89                 </Drawer>
90             </Typography>
91         );
92     }
93
94 }
95
96 type CssRules = 'drawerPaper' | 'container' | 'opened' | 'headerContainer' | 'tabContainer';
97
98 const drawerWidth = 320;
99 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
100     container: {
101         width: 0,
102         position: 'relative',
103         height: 'auto',
104         transition: 'width 0.5s ease',
105         '&$opened': {
106             width: drawerWidth
107         }
108     },
109     opened: {},
110     drawerPaper: {
111         position: 'relative',
112         width: drawerWidth
113     },
114     headerContainer: {
115         color: theme.palette.grey["600"],
116         margin: `${theme.spacing.unit}px 0`,
117         '& .fa-cogs': {
118             fontSize: "24px",
119             color: theme.customs.colors.green700
120         }
121     },
122     tabContainer: {
123         padding: theme.spacing.unit * 3
124     }
125 });
126
127 const renderCollectionHeader = (collection: CollectionResource) =>
128     <>
129         <IconBase icon={IconTypes.COLLECTION} />
130         <Typography variant="title">
131             {collection.name}
132         </Typography>
133     </>;
134
135 const renderProjectHeader = (project: ProjectResource) =>
136     <>
137         <IconBase icon={IconTypes.FOLDER} />
138         <Typography variant="title">
139             {project.name}
140         </Typography>
141     </>;
142
143 const renderHeader = (resource: Resource) => {
144     switch(resource.kind) {
145         case ResourceKind.Project:
146             return renderProjectHeader(resource as ProjectResource);
147         case ResourceKind.Collection:
148             return renderCollectionHeader(resource as CollectionResource);
149         default: 
150             return null;
151     }
152 };
153
154 const mapStateToProps = ({detailsPanel}: RootState) => ({
155     isOpened: detailsPanel.isOpened,
156     header: detailsPanel.item ? renderHeader(detailsPanel.item) : null
157 });
158
159 const mapDispatchToProps = (dispatch: Dispatch) => ({
160     onCloseDrawer: () => {
161         dispatch(actions.TOGGLE_DETAILS_PANEL());
162     }
163 });
164
165 const DetailsPanelContainer = connect(mapStateToProps, mapDispatchToProps)(DetailsPanel);
166
167 export default withStyles(styles)(DetailsPanelContainer);