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