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