merge master
[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 { Button, StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
8 import { DataExplorer } from "../../views-components/data-explorer/data-explorer";
9 import { DispatchProp, connect } from 'react-redux';
10 import { DataColumns } from '../../components/data-table/data-table';
11 import { RouteComponentProps } from 'react-router';
12 import { RootState } from '../../store/store';
13 import { DataTableFilterItem } from '../../components/data-table-filters/data-table-filters';
14 import { ContainerRequestState } from '../../models/container-request';
15 import { SortDirection } from '../../components/data-table/data-column';
16 import { ResourceKind } from '../../models/resource';
17 import { resourceLabel } from '../../common/labels';
18 import { ArvadosTheme } from '../../common/custom-theme';
19 import { renderName, renderStatus, renderType, renderOwner, renderFileSize, renderDate } from '../../views-components/data-explorer/renderers';
20
21 type CssRules = "toolbar" | "button";
22
23 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
24     toolbar: {
25         paddingBottom: theme.spacing.unit * 3,
26         textAlign: "right"
27     },
28     button: {
29         marginLeft: theme.spacing.unit
30     },
31 });
32
33 export enum ProjectPanelColumnNames {
34     NAME = "Name",
35     STATUS = "Status",
36     TYPE = "Type",
37     OWNER = "Owner",
38     FILE_SIZE = "File size",
39     LAST_MODIFIED = "Last modified"
40 }
41
42 export interface ProjectPanelFilter extends DataTableFilterItem {
43     type: ResourceKind | ContainerRequestState;
44 }
45
46 export const columns: DataColumns<ProjectPanelItem, ProjectPanelFilter> = [
47     {
48         name: ProjectPanelColumnNames.NAME,
49         selected: true,
50         configurable: true,
51         sortDirection: SortDirection.ASC,
52         render: renderName,
53         width: "450px"
54     },
55     {
56         name: "Status",
57         selected: true,
58         configurable: true,
59         filters: [
60             {
61                 name: ContainerRequestState.COMMITTED,
62                 selected: true,
63                 type: ContainerRequestState.COMMITTED
64             },
65             {
66                 name: ContainerRequestState.FINAL,
67                 selected: true,
68                 type: ContainerRequestState.FINAL
69             },
70             {
71                 name: ContainerRequestState.UNCOMMITTED,
72                 selected: true,
73                 type: ContainerRequestState.UNCOMMITTED
74             }
75         ],
76         render: renderStatus,
77         width: "75px"
78     },
79     {
80         name: ProjectPanelColumnNames.TYPE,
81         selected: true,
82         configurable: true,
83         filters: [
84             {
85                 name: resourceLabel(ResourceKind.COLLECTION),
86                 selected: true,
87                 type: ResourceKind.COLLECTION
88             },
89             {
90                 name: resourceLabel(ResourceKind.PROCESS),
91                 selected: true,
92                 type: ResourceKind.PROCESS
93             },
94             {
95                 name: resourceLabel(ResourceKind.PROJECT),
96                 selected: true,
97                 type: ResourceKind.PROJECT
98             }
99         ],
100         render: item => renderType(item.kind),
101         width: "125px"
102     },
103     {
104         name: ProjectPanelColumnNames.OWNER,
105         selected: true,
106         configurable: true,
107         render: item => renderOwner(item.owner),
108         width: "200px"
109     },
110     {
111         name: ProjectPanelColumnNames.FILE_SIZE,
112         selected: true,
113         configurable: true,
114         render: item => renderFileSize(item.fileSize),
115         width: "50px"
116     },
117     {
118         name: ProjectPanelColumnNames.LAST_MODIFIED,
119         selected: true,
120         configurable: true,
121         sortDirection: SortDirection.NONE,
122         render: item => renderDate(item.lastModified),
123         width: "150px"
124     }
125 ];
126
127 export const PROJECT_PANEL_ID = "projectPanel";
128
129 interface ProjectPanelDataProps {
130     currentItemId: string;
131 }
132
133 interface ProjectPanelActionProps {
134     onItemClick: (item: ProjectPanelItem) => void;
135     onContextMenu: (event: React.MouseEvent<HTMLElement>, item: ProjectPanelItem) => void;
136     onProjectCreationDialogOpen: (ownerUuid: string) => void;
137     onCollectionCreationDialogOpen: (ownerUuid: string) => void;
138     onItemDoubleClick: (item: ProjectPanelItem) => void;
139     onItemRouteChange: (itemId: string) => void;
140 }
141
142 type ProjectPanelProps = ProjectPanelDataProps & ProjectPanelActionProps & DispatchProp
143     & WithStyles<CssRules> & RouteComponentProps<{ id: string }>;
144
145 export const ProjectPanel = withStyles(styles)(
146     connect((state: RootState) => ({ currentItemId: state.projects.currentItemId }))(
147         class extends React.Component<ProjectPanelProps> {
148             render() {
149                 const { classes } = this.props;
150                 return <div>
151                     <div className={classes.toolbar}>
152                         <Button color="primary" onClick={this.handleNewCollectionClick} variant="raised" className={classes.button}>
153                             Create a collection
154                         </Button>
155                         <Button color="primary" variant="raised" className={classes.button}>
156                             Run a process
157                         </Button>
158                         <Button color="primary" onClick={this.handleNewProjectClick} variant="raised" className={classes.button}>
159                             New project
160                         </Button>
161                     </div>
162                     <DataExplorer
163                         id={PROJECT_PANEL_ID}
164                         columns={columns}
165                         onRowClick={this.props.onItemClick}
166                         onRowDoubleClick={this.props.onItemDoubleClick}
167                         onContextMenu={this.props.onContextMenu}
168                         extractKey={(item: ProjectPanelItem) => item.uuid} />
169                 </div>;
170             }
171
172             handleNewProjectClick = () => {
173                 this.props.onProjectCreationDialogOpen(this.props.currentItemId);
174             }
175
176             handleNewCollectionClick = () => {
177                 this.props.onCollectionCreationDialogOpen(this.props.currentItemId);
178             }
179             componentWillReceiveProps({ match, currentItemId, onItemRouteChange }: ProjectPanelProps) {
180                 if (match.params.id !== currentItemId) {
181                     onItemRouteChange(match.params.id);
182                 }
183             }
184         }
185     )
186 );