refactor
[arvados-workbench2.git] / src / views / project-panel / project-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 { ProjectPanelItem } from './project-panel-item';
7 import { Grid, Typography, Button, StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
8 import { formatDate, formatFileSize } from '../../common/formatters';
9 import DataExplorer from "../../views-components/data-explorer/data-explorer";
10 import { DispatchProp, connect } from 'react-redux';
11 import { DataColumns } from '../../components/data-table/data-table';
12 import { RouteComponentProps } from 'react-router';
13 import { RootState } from '../../store/store';
14 import { ResourceKind } from '../../models/kinds';
15 import { DataTableFilterItem } from '../../components/data-table-filters/data-table-filters';
16 import { ContainerRequestState } from '../../models/container-request';
17 import { SortDirection } from '../../components/data-table/data-column';
18
19 export const PROJECT_PANEL_ID = "projectPanel";
20
21 export interface ProjectPanelFilter extends DataTableFilterItem {
22     type: ResourceKind | ContainerRequestState;
23 }
24
25 type ProjectPanelProps = {
26     currentItemId: string,
27     onItemClick: (item: ProjectPanelItem) => void,
28     onContextMenu: (event: React.MouseEvent<HTMLElement>, item: ProjectPanelItem) => void;
29     onDialogOpen: (ownerUuid: string) => void;
30     onItemDoubleClick: (item: ProjectPanelItem) => void,
31     onItemRouteChange: (itemId: string) => void
32 }
33     & DispatchProp
34     & WithStyles<CssRules>
35     & RouteComponentProps<{ id: string }>;
36
37 class ProjectPanel extends React.Component<ProjectPanelProps> {
38     render() {
39         const { classes, currentItemId, onItemClick, onItemDoubleClick, onContextMenu, onDialogOpen } = this.props;
40         return <div>
41             <div className={classes.toolbar}>
42                 <Button color="primary" variant="raised" className={classes.button}>
43                     Create a collection
44                 </Button>
45                 <Button color="primary" variant="raised" className={classes.button}>
46                     Run a process
47                 </Button>
48                 <Button color="primary" onClick={() => onDialogOpen(currentItemId)} variant="raised" className={classes.button}>
49                     New project
50                 </Button>
51             </div>
52             <DataExplorer
53                 id={PROJECT_PANEL_ID}
54                 onRowClick={onItemClick}
55                 onRowDoubleClick={onItemDoubleClick}
56                 onContextMenu={onContextMenu} />
57         </div>;
58     }
59
60     componentWillReceiveProps({ match, currentItemId, onItemRouteChange }: ProjectPanelProps) {
61         if (match.params.id !== currentItemId) {
62             onItemRouteChange(match.params.id);
63         }
64     }
65 }
66
67 type CssRules = "toolbar" | "button";
68
69 const styles: StyleRulesCallback<CssRules> = theme => ({
70     toolbar: {
71         paddingBottom: theme.spacing.unit * 3,
72         textAlign: "right"
73     },
74     button: {
75         marginLeft: theme.spacing.unit
76     },
77 });
78
79 const renderName = (item: ProjectPanelItem) =>
80     <Grid
81         container
82         alignItems="center"
83         wrap="nowrap"
84         spacing={16}>
85         <Grid item>
86             {renderIcon(item)}
87         </Grid>
88         <Grid item>
89             <Typography color="primary">
90                 {item.name}
91             </Typography>
92         </Grid>
93     </Grid>;
94
95
96 const renderIcon = (item: ProjectPanelItem) => {
97     switch (item.kind) {
98         case ResourceKind.Project:
99             return <i className="fas fa-folder fa-lg" />;
100         case ResourceKind.Collection:
101             return <i className="fas fa-archive fa-lg" />;
102         case ResourceKind.Process:
103             return <i className="fas fa-cogs fa-lg" />;
104         default:
105             return <i />;
106     }
107 };
108
109 const renderDate = (date: string) =>
110     <Typography noWrap>
111         {formatDate(date)}
112     </Typography>;
113
114 const renderFileSize = (fileSize?: number) =>
115     <Typography noWrap>
116         {formatFileSize(fileSize)}
117     </Typography>;
118
119 const renderOwner = (owner: string) =>
120     <Typography noWrap color="primary">
121         {owner}
122     </Typography>;
123
124
125
126 const typeToLabel = (type: string) => {
127     switch (type) {
128         case ResourceKind.Collection:
129             return "Data collection";
130         case ResourceKind.Project:
131             return "Project";
132         case ResourceKind.Process:
133             return "Process";
134         default:
135             return "Unknown";
136     }
137 };
138
139 const renderType = (type: string) => {
140     return <Typography noWrap>
141         {typeToLabel(type)}
142     </Typography>;
143 };
144
145 const renderStatus = (item: ProjectPanelItem) =>
146     <Typography noWrap align="center">
147         {item.status || "-"}
148     </Typography>;
149
150 export enum ProjectPanelColumnNames {
151     Name = "Name",
152     Status = "Status",
153     Type = "Type",
154     Owner = "Owner",
155     FileSize = "File size",
156     LastModified = "Last modified"
157
158 }
159
160 export const columns: DataColumns<ProjectPanelItem, ProjectPanelFilter> = [{
161     name: ProjectPanelColumnNames.Name,
162     selected: true,
163     sortDirection: SortDirection.Asc,
164     render: renderName,
165     width: "450px"
166 }, {
167     name: "Status",
168     selected: true,
169     filters: [{
170         name: ContainerRequestState.Committed,
171         selected: true,
172         type: ContainerRequestState.Committed
173     }, {
174         name: ContainerRequestState.Final,
175         selected: true,
176         type: ContainerRequestState.Final
177     }, {
178         name: ContainerRequestState.Uncommitted,
179         selected: true,
180         type: ContainerRequestState.Uncommitted
181     }],
182     render: renderStatus,
183     width: "75px"
184 }, {
185     name: ProjectPanelColumnNames.Type,
186     selected: true,
187     filters: [{
188         name: typeToLabel(ResourceKind.Collection),
189         selected: true,
190         type: ResourceKind.Collection
191     }, {
192         name: typeToLabel(ResourceKind.Process),
193         selected: true,
194         type: ResourceKind.Process
195     }, {
196         name: typeToLabel(ResourceKind.Project),
197         selected: true,
198         type: ResourceKind.Project
199     }],
200     render: item => renderType(item.kind),
201     width: "125px"
202 }, {
203     name: ProjectPanelColumnNames.Owner,
204     selected: true,
205     render: item => renderOwner(item.owner),
206     width: "200px"
207 }, {
208     name: ProjectPanelColumnNames.FileSize,
209     selected: true,
210     render: item => renderFileSize(item.fileSize),
211     width: "50px"
212 }, {
213     name: ProjectPanelColumnNames.LastModified,
214     selected: true,
215     sortDirection: SortDirection.None,
216     render: item => renderDate(item.lastModified),
217     width: "150px"
218 }];
219
220
221 export default withStyles(styles)(
222     connect((state: RootState) => ({ currentItemId: state.projects.currentItemId }))(
223         ProjectPanel));