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