removed description column Arvados-DCO-1.1-Signed-off-by: Lisa Knox <lisa.knox@curii...
[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 React from 'react';
6 import withStyles from "@material-ui/core/styles/withStyles";
7 import { DispatchProp, connect } from 'react-redux';
8 import { RouteComponentProps } from 'react-router';
9 import { StyleRulesCallback, WithStyles } from "@material-ui/core";
10
11 import { DataExplorer } from "views-components/data-explorer/data-explorer";
12 import { DataColumns } from 'components/data-table/data-table';
13 import { RootState } from 'store/store';
14 import { DataTableFilterItem } from 'components/data-table-filters/data-table-filters';
15 import { ContainerRequestState } from 'models/container-request';
16 import { SortDirection } from 'components/data-table/data-column';
17 import { ResourceKind, Resource } from 'models/resource';
18 import {
19     ResourceName,
20     ProcessStatus as ResourceStatus,
21     ResourceType,
22     ResourceOwnerWithName,
23     ResourceVersion,
24     ResourceFileSize,
25     ResourceFileCount,
26     ResourceUUID,
27     ResourceContainerUuid,
28     ResourceOutputUuid,
29     ResourceLogUuid,
30     ResourceParentProcess,
31     ResourceModifiedByUserUuid,
32     ResourcePortableDataHash,
33     ResourceCreatedAtDate,
34     ResourceLastModifiedDate,
35     ResourceTrashDate,
36     ResourceDeleteDate,
37 } from 'views-components/data-explorer/renderers';
38 import { ProjectIcon } from 'components/icon/icon';
39 import {
40     ResourcesState,
41     getResource
42 } from 'store/resources/resources';
43 import { loadDetailsPanel } from 'store/details-panel/details-panel-action';
44 import {
45     openContextMenu,
46     resourceUuidToContextMenuKind
47 } from 'store/context-menu/context-menu-actions';
48 import { navigateTo } from 'store/navigation/navigation-action';
49 import { getProperty } from 'store/properties/properties';
50 import { PROJECT_PANEL_CURRENT_UUID } from 'store/project-panel/project-panel-action';
51 import { ArvadosTheme } from "common/custom-theme";
52 import { createTree } from 'models/tree';
53 import {
54     getInitialResourceTypeFilters,
55     getInitialProcessStatusFilters
56 } from 'store/resource-type-filters/resource-type-filters';
57 import { GroupContentsResource } from 'services/groups-service/groups-service';
58 import { GroupClass, GroupResource } from 'models/group';
59 import { CollectionResource } from 'models/collection';
60 import { resourceIsFrozen } from 'common/frozen-resources';
61
62 type CssRules = 'root' | "button";
63
64 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
65     root: {
66         width: '100%',
67     },
68     button: {
69         marginLeft: theme.spacing.unit
70     },
71 });
72
73 export enum ProjectPanelColumnNames {
74     NAME = "Name",
75     STATUS = "Status",
76     TYPE = "Type",
77     OWNER = "Owner",
78     VERSION = "Version",
79     FILE_SIZE = "File size",
80     FILE_COUNT = "File count",
81     UUID = "UUID",
82     CONTAINER_UUID = "Container UUID",
83     OUTPUT_UUID = "Output UUID",
84     LOG_UUID = "Log UUID",
85     PARENT_PROCESS = 'Parent process UUID',
86     MODIFIED_BY_USER_UUID = 'Modified by User UUID',
87     PORTABLE_DATA_HASH = "Portable data hash",
88     CREATED_AT = "Date created",
89     LAST_MODIFIED = "Last modified",
90     TRASH_AT = "Trash at",
91     DELETE_AT = "Delete at",
92 }
93
94 export interface ProjectPanelFilter extends DataTableFilterItem {
95     type: ResourceKind | ContainerRequestState;
96 }
97
98 export const projectPanelColumns: DataColumns<string> = [
99     {
100         name: ProjectPanelColumnNames.NAME,
101         selected: true,
102         configurable: true,
103         sortDirection: SortDirection.NONE,
104         filters: createTree(),
105         render: uuid => <ResourceName uuid={uuid} />
106     },
107     {
108         name: ProjectPanelColumnNames.STATUS,
109         selected: true,
110         configurable: true,
111         mutuallyExclusiveFilters: true,
112         filters: getInitialProcessStatusFilters(),
113         render: uuid => <ResourceStatus uuid={uuid} />,
114     },
115     {
116         name: ProjectPanelColumnNames.TYPE,
117         selected: true,
118         configurable: true,
119         filters: getInitialResourceTypeFilters(),
120         render: uuid => <ResourceType uuid={uuid} />
121     },
122     {
123         name: ProjectPanelColumnNames.OWNER,
124         selected: false,
125         configurable: true,
126         filters: createTree(),
127         render: uuid => <ResourceOwnerWithName uuid={uuid} />
128     },
129     {
130         name: ProjectPanelColumnNames.VERSION,
131         selected: false,
132         configurable: true,
133         filters: createTree(),
134         render: uuid =><ResourceVersion uuid={uuid}/>
135     },
136     {
137         name: ProjectPanelColumnNames.FILE_SIZE,
138         selected: true,
139         configurable: true,
140         filters: createTree(),
141         render: uuid => <ResourceFileSize uuid={uuid} />
142     },
143     {
144         name: ProjectPanelColumnNames.FILE_COUNT,
145         selected: false,
146         configurable: true,
147         filters: createTree(),
148         render: uuid =><ResourceFileCount uuid={uuid}/>
149     },
150     {
151         name: ProjectPanelColumnNames.UUID,
152         selected: false,
153         configurable: true,
154         filters: createTree(),
155         render: uuid => <ResourceUUID uuid={uuid}/>
156     },
157     {
158         name: ProjectPanelColumnNames.CONTAINER_UUID,
159         selected: true,
160         configurable: true,
161         filters: createTree(),
162         render: uuid => <ResourceContainerUuid uuid={uuid}/>
163     },
164     {
165         name: ProjectPanelColumnNames.OUTPUT_UUID,
166         selected: false,
167         configurable: true,
168         filters: createTree(),
169         render: uuid => <ResourceOutputUuid uuid={uuid}/>
170     },
171     {
172         name: ProjectPanelColumnNames.LOG_UUID,
173         selected: false,
174         configurable: true,
175         filters: createTree(),
176         render: uuid => <ResourceLogUuid uuid={uuid}/>
177     },
178     {
179         name: ProjectPanelColumnNames.PARENT_PROCESS,
180         selected: false,
181         configurable: true,
182         filters: createTree(),
183         render: uuid => <ResourceParentProcess uuid={uuid}/>
184     },
185     {
186         name: ProjectPanelColumnNames.MODIFIED_BY_USER_UUID,
187         selected: false,
188         configurable: true,
189         filters: createTree(),
190         render: uuid => <ResourceModifiedByUserUuid uuid={uuid}/>
191     },
192     {
193         name: ProjectPanelColumnNames.PORTABLE_DATA_HASH,
194         selected: false,
195         configurable: true,
196         filters: createTree(),
197         render: uuid => <ResourcePortableDataHash uuid={uuid}/>
198     },
199     {
200         name: ProjectPanelColumnNames.CREATED_AT,
201         selected: false,
202         configurable: true,
203         sortDirection: SortDirection.DESC,
204         filters: createTree(),
205         render: uuid =><ResourceCreatedAtDate uuid={uuid}/>
206     },
207     {
208         name: ProjectPanelColumnNames.LAST_MODIFIED,
209         selected: true,
210         configurable: true,
211         sortDirection: SortDirection.DESC,
212         filters: createTree(),
213         render: uuid => <ResourceLastModifiedDate uuid={uuid} />
214     },
215     {
216         name: ProjectPanelColumnNames.TRASH_AT,
217         selected: false,
218         configurable: true,
219         sortDirection: SortDirection.DESC,
220         filters: createTree(),
221         render: uuid => <ResourceTrashDate uuid={uuid} />
222     },
223     {
224         name: ProjectPanelColumnNames.DELETE_AT,
225         selected: false,
226         configurable: true,
227         sortDirection: SortDirection.DESC,
228         filters: createTree(),
229         render: uuid => <ResourceDeleteDate uuid={uuid} />
230     },
231     
232 ];
233
234 export const PROJECT_PANEL_ID = "projectPanel";
235
236 const DEFAULT_VIEW_MESSAGES = [
237     'Your project is empty.',
238     'Please create a project or create a collection and upload a data.',
239 ];
240
241 interface ProjectPanelDataProps {
242     currentItemId: string;
243     resources: ResourcesState;
244     isAdmin: boolean;
245     userUuid: string;
246     dataExplorerItems: any;
247 }
248
249 type ProjectPanelProps = ProjectPanelDataProps & DispatchProp
250     & WithStyles<CssRules> & RouteComponentProps<{ id: string }>;
251
252
253 export const ProjectPanel = withStyles(styles)(
254     connect((state: RootState) => ({
255         currentItemId: getProperty(PROJECT_PANEL_CURRENT_UUID)(state.properties),
256         resources: state.resources,
257         userUuid: state.auth.user!.uuid
258     }))(
259         class extends React.Component<ProjectPanelProps> {
260             render() {
261                 const { classes } = this.props;
262
263                 return <div data-cy='project-panel' className={classes.root}>
264                     <DataExplorer
265                         id={PROJECT_PANEL_ID}
266                         onRowClick={this.handleRowClick}
267                         onRowDoubleClick={this.handleRowDoubleClick}
268                         onContextMenu={this.handleContextMenu}
269                         contextMenuColumn={true}
270                         defaultViewIcon={ProjectIcon}
271                         defaultViewMessages={DEFAULT_VIEW_MESSAGES}
272                     />
273                 </div>;
274             }
275
276             isCurrentItemChild = (resource: Resource) => {
277                 return resource.ownerUuid === this.props.currentItemId;
278             }
279
280             handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
281                 const { resources, isAdmin } = this.props;
282                 const resource = getResource<GroupContentsResource>(resourceUuid)(resources);
283                 // When viewing the contents of a filter group, all contents should be treated as read only.
284                 let readonly = false;
285                 const project = getResource<GroupResource>(this.props.currentItemId)(resources);
286                 if (project && project.groupClass === GroupClass.FILTER) {
287                     readonly = true;
288                 }
289
290                 const menuKind = this.props.dispatch<any>(resourceUuidToContextMenuKind(resourceUuid, readonly));
291                 if (menuKind && resource) {
292                     this.props.dispatch<any>(openContextMenu(event, {
293                         name: resource.name,
294                         uuid: resource.uuid,
295                         ownerUuid: resource.ownerUuid,
296                         isTrashed: ('isTrashed' in resource) ? resource.isTrashed : false,
297                         kind: resource.kind,
298                         menuKind,
299                         isAdmin,
300                         isFrozen: resourceIsFrozen(resource, resources),
301                         description: resource.description,
302                         storageClassesDesired: (resource as CollectionResource).storageClassesDesired,
303                         properties: ('properties' in resource) ? resource.properties : {},
304                     }));
305                 }
306                 this.props.dispatch<any>(loadDetailsPanel(resourceUuid));
307             }
308
309             handleRowDoubleClick = (uuid: string) => {
310                 this.props.dispatch<any>(navigateTo(uuid));
311             }
312
313             handleRowClick = (uuid: string) => {
314                 this.props.dispatch<any>(loadDetailsPanel(uuid));
315             }
316
317         }
318     )
319 );