fill common item details, clean code, change factory details panel
[arvados.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 import { resourceLabel } from '../../common/labels';
19
20 export const PROJECT_PANEL_ID = "projectPanel";
21
22 export interface ProjectPanelFilter extends DataTableFilterItem {
23     type: ResourceKind | ContainerRequestState;
24 }
25
26 type ProjectPanelProps = {
27     currentItemId: string,
28     onItemClick: (item: ProjectPanelItem) => void,
29     onContextMenu: (event: React.MouseEvent<HTMLElement>, item: ProjectPanelItem) => void;
30     onDialogOpen: (ownerUuid: string) => void;
31     onItemDoubleClick: (item: ProjectPanelItem) => void,
32     onItemRouteChange: (itemId: string) => void
33 }
34     & DispatchProp
35     & WithStyles<CssRules>
36     & RouteComponentProps<{ id: string }>;
37
38 class ProjectPanel extends React.Component<ProjectPanelProps> {    
39     render() {
40         return <div>
41             <div className={this.props.classes.toolbar}>
42                 <Button color="primary" variant="raised" className={this.props.classes.button}>
43                     Create a collection
44                 </Button>
45                 <Button color="primary" variant="raised" className={this.props.classes.button}>
46                     Run a process
47                 </Button>
48                 <Button color="primary" onClick={() => this.props.onDialogOpen(this.props.currentItemId)} variant="raised" className={this.props.classes.button}>
49                     New project
50                 </Button>
51             </div>
52             <DataExplorer
53                 id={PROJECT_PANEL_ID}
54                 onRowClick={this.props.onItemClick}
55                 onRowDoubleClick={this.props.onItemDoubleClick}
56                 onContextMenu={this.props.onContextMenu} />
57         </div>;
58     }
59
60     componentWillReceiveProps({ match, currentItemId }: ProjectPanelProps) {
61         if (match.params.id !== currentItemId) {
62             this.props.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 const renderType = (type: string) => {
125     return <Typography noWrap>
126         {resourceLabel(type)}
127     </Typography>;
128 };
129
130 const renderStatus = (item: ProjectPanelItem) =>
131     <Typography noWrap align="center">
132         {item.status || "-"}
133     </Typography>;
134
135 export enum ProjectPanelColumnNames {
136     Name = "Name",
137     Status = "Status",
138     Type = "Type",
139     Owner = "Owner",
140     FileSize = "File size",
141     LastModified = "Last modified"
142
143 }
144
145 export const columns: DataColumns<ProjectPanelItem, ProjectPanelFilter> = [{
146     name: ProjectPanelColumnNames.Name,
147     selected: true,
148     sortDirection: SortDirection.Asc,
149     render: renderName,
150     width: "450px"
151 }, {
152     name: "Status",
153     selected: true,
154     filters: [{
155         name: ContainerRequestState.Committed,
156         selected: true,
157         type: ContainerRequestState.Committed
158     }, {
159         name: ContainerRequestState.Final,
160         selected: true,
161         type: ContainerRequestState.Final
162     }, {
163         name: ContainerRequestState.Uncommitted,
164         selected: true,
165         type: ContainerRequestState.Uncommitted
166     }],
167     render: renderStatus,
168     width: "75px"
169 }, {
170     name: ProjectPanelColumnNames.Type,
171     selected: true,
172     filters: [{
173         name: resourceLabel(ResourceKind.Collection),
174         selected: true,
175         type: ResourceKind.Collection
176     }, {
177         name: resourceLabel(ResourceKind.Process),
178         selected: true,
179         type: ResourceKind.Process
180     }, {
181         name: resourceLabel(ResourceKind.Project),
182         selected: true,
183         type: ResourceKind.Project
184     }],
185     render: item => renderType(item.kind),
186     width: "125px"
187 }, {
188     name: ProjectPanelColumnNames.Owner,
189     selected: true,
190     render: item => renderOwner(item.owner),
191     width: "200px"
192 }, {
193     name: ProjectPanelColumnNames.FileSize,
194     selected: true,
195     render: item => renderFileSize(item.fileSize),
196     width: "50px"
197 }, {
198     name: ProjectPanelColumnNames.LastModified,
199     selected: true,
200     sortDirection: SortDirection.None,
201     render: item => renderDate(item.lastModified),
202     width: "150px"
203 }];
204
205
206 export default withStyles(styles)(
207     connect((state: RootState) => ({ currentItemId: state.projects.currentItemId }))(
208         ProjectPanel));