16437: Removes context items when projects are not editable by user
[arvados-workbench2.git] / src / views / favorite-panel / favorite-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 { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
7 import { DataExplorer } from "~/views-components/data-explorer/data-explorer";
8 import { connect, DispatchProp } from 'react-redux';
9 import { DataColumns } from '~/components/data-table/data-table';
10 import { RouteComponentProps } from 'react-router';
11 import { DataTableFilterItem } from '~/components/data-table-filters/data-table-filters';
12 import { SortDirection } from '~/components/data-table/data-column';
13 import { ResourceKind, EditableResource } from '~/models/resource';
14 import { ArvadosTheme } from '~/common/custom-theme';
15 import { FAVORITE_PANEL_ID } from "~/store/favorite-panel/favorite-panel-action";
16 import {
17     ProcessStatus,
18     ResourceFileSize,
19     ResourceLastModifiedDate,
20     ResourceName,
21     ResourceOwner,
22     ResourceType
23 } from '~/views-components/data-explorer/renderers';
24 import { FavoriteIcon } from '~/components/icon/icon';
25 import { openContextMenu, resourceKindToContextMenuKind } from '~/store/context-menu/context-menu-actions';
26 import { loadDetailsPanel } from '~/store/details-panel/details-panel-action';
27 import { navigateTo } from '~/store/navigation/navigation-action';
28 import { ContainerRequestState } from "~/models/container-request";
29 import { FavoritesState } from '~/store/favorites/favorites-reducer';
30 import { RootState } from '~/store/store';
31 import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
32 import { createTree } from '~/models/tree';
33 import { getSimpleObjectTypeFilters } from '~/store/resource-type-filters/resource-type-filters';
34 import { getResourceWithEditableStatus, ResourcesState } from '~/store/resources/resources';
35 import { ProjectResource } from '~/models/project';
36
37 type CssRules = "toolbar" | "button";
38
39 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
40     toolbar: {
41         paddingBottom: theme.spacing.unit * 3,
42         textAlign: "right"
43     },
44     button: {
45         marginLeft: theme.spacing.unit
46     },
47 });
48
49 export enum FavoritePanelColumnNames {
50     NAME = "Name",
51     STATUS = "Status",
52     TYPE = "Type",
53     OWNER = "Owner",
54     FILE_SIZE = "File size",
55     LAST_MODIFIED = "Last modified"
56 }
57
58 export interface FavoritePanelFilter extends DataTableFilterItem {
59     type: ResourceKind | ContainerRequestState;
60 }
61
62 export const favoritePanelColumns: DataColumns<string> = [
63     {
64         name: FavoritePanelColumnNames.NAME,
65         selected: true,
66         configurable: true,
67         sortDirection: SortDirection.NONE,
68         filters: createTree(),
69         render: uuid => <ResourceName uuid={uuid} />
70     },
71     {
72         name: "Status",
73         selected: true,
74         configurable: true,
75         filters: createTree(),
76         render: uuid => <ProcessStatus uuid={uuid} />
77     },
78     {
79         name: FavoritePanelColumnNames.TYPE,
80         selected: true,
81         configurable: true,
82         filters: getSimpleObjectTypeFilters(),
83         render: uuid => <ResourceType uuid={uuid} />
84     },
85     {
86         name: FavoritePanelColumnNames.OWNER,
87         selected: true,
88         configurable: true,
89         filters: createTree(),
90         render: uuid => <ResourceOwner uuid={uuid} />
91     },
92     {
93         name: FavoritePanelColumnNames.FILE_SIZE,
94         selected: true,
95         configurable: true,
96         filters: createTree(),
97         render: uuid => <ResourceFileSize uuid={uuid} />
98     },
99     {
100         name: FavoritePanelColumnNames.LAST_MODIFIED,
101         selected: true,
102         configurable: true,
103         sortDirection: SortDirection.DESC,
104         filters: createTree(),
105         render: uuid => <ResourceLastModifiedDate uuid={uuid} />
106     }
107 ];
108
109 interface FavoritePanelDataProps {
110     favorites: FavoritesState;
111     resources: ResourcesState;
112     isAdmin: boolean;
113     userUuid: string;
114 }
115
116 interface FavoritePanelActionProps {
117     onItemClick: (item: string) => void;
118     onDialogOpen: (ownerUuid: string) => void;
119     onItemDoubleClick: (item: string) => void;
120 }
121 const mapStateToProps = (state : RootState): FavoritePanelDataProps => ({
122     favorites: state.favorites,
123     resources: state.resources,
124     isAdmin: state.auth.user!.isAdmin,
125     userUuid: state.auth.user!.uuid,
126 });
127
128 type FavoritePanelProps = FavoritePanelDataProps & FavoritePanelActionProps & DispatchProp
129     & WithStyles<CssRules> & RouteComponentProps<{ id: string }>;
130
131 export const FavoritePanel = withStyles(styles)(
132     connect(mapStateToProps)(
133         class extends React.Component<FavoritePanelProps> {
134
135             handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
136                 const { isAdmin, userUuid, resources } = this.props;
137                 const resource = getResourceWithEditableStatus<ProjectResource & EditableResource>(resourceUuid, userUuid)(resources);
138                 const menuKind = resourceKindToContextMenuKind(resourceUuid, isAdmin, (resource || {} as EditableResource).isEditable);
139                 if (menuKind) {
140                     this.props.dispatch<any>(openContextMenu(event, {
141                         name: '',
142                         uuid: resourceUuid,
143                         ownerUuid: '',
144                         kind: ResourceKind.NONE,
145                         menuKind
146                     }));
147                 }
148                 this.props.dispatch<any>(loadDetailsPanel(resourceUuid));
149             }
150
151             handleRowDoubleClick = (uuid: string) => {
152                 this.props.dispatch<any>(navigateTo(uuid));
153             }
154
155             handleRowClick = (uuid: string) => {
156                 this.props.dispatch(loadDetailsPanel(uuid));
157             }
158
159             render() {
160                 return <DataExplorer
161                     id={FAVORITE_PANEL_ID}
162                     onRowClick={this.handleRowClick}
163                     onRowDoubleClick={this.handleRowDoubleClick}
164                     onContextMenu={this.handleContextMenu}
165                     contextMenuColumn={true}
166                     dataTableDefaultView={
167                         <DataTableDefaultView
168                             icon={FavoriteIcon}
169                             messages={['Your favorites list is empty.']}
170                             />
171                     } />;
172             }
173         }
174     )
175 );