Merge branch 'master' into 14093-data-explorer-table-cell-width
[arvados.git] / src / views / trash-panel / trash-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 { IconButton, 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 { RootState } from '~/store/store';
11 import { DataTableFilterItem } from '~/components/data-table-filters/data-table-filters';
12 import { SortDirection } from '~/components/data-table/data-column';
13 import { ResourceKind, TrashableResource } from '~/models/resource';
14 import { resourceLabel } from '~/common/labels';
15 import { ArvadosTheme } from '~/common/custom-theme';
16 import { RestoreFromTrashIcon, TrashIcon } from '~/components/icon/icon';
17 import { TRASH_PANEL_ID } from "~/store/trash-panel/trash-panel-action";
18 import { getProperty } from "~/store/properties/properties";
19 import { PROJECT_PANEL_CURRENT_UUID } from "~/store/project-panel/project-panel-action";
20 import { openContextMenu } from "~/store/context-menu/context-menu-actions";
21 import { getResource, ResourcesState } from "~/store/resources/resources";
22 import {
23     ResourceDeleteDate,
24     ResourceFileSize,
25     ResourceName,
26     ResourceTrashDate,
27     ResourceType
28 } from "~/views-components/data-explorer/renderers";
29 import { navigateTo } from "~/store/navigation/navigation-action";
30 import { loadDetailsPanel } from "~/store/details-panel/details-panel-action";
31 import { toggleCollectionTrashed, toggleProjectTrashed, toggleTrashed } from "~/store/trash/trash-actions";
32 import { ContextMenuKind } from "~/views-components/context-menu/context-menu";
33 import { Dispatch } from "redux";
34
35 type CssRules = "toolbar" | "button";
36
37 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
38     toolbar: {
39         paddingBottom: theme.spacing.unit * 3,
40         textAlign: "right"
41     },
42     button: {
43         marginLeft: theme.spacing.unit
44     },
45 });
46
47 export enum TrashPanelColumnNames {
48     NAME = "Name",
49     TYPE = "Type",
50     FILE_SIZE = "File size",
51     TRASHED_DATE = "Trashed date",
52     TO_BE_DELETED = "To be deleted"
53 }
54
55 export interface TrashPanelFilter extends DataTableFilterItem {
56     type: ResourceKind;
57 }
58
59 export const ResourceRestore =
60     connect((state: RootState, props: { uuid: string, dispatch?: Dispatch<any> }) => {
61         const resource = getResource<TrashableResource>(props.uuid)(state.resources);
62         return { resource, dispatch: props.dispatch };
63     })((props: { resource?: TrashableResource, dispatch?: Dispatch<any> }) =>
64         <IconButton onClick={() => {
65             if (props.resource && props.dispatch) {
66                 props.dispatch(toggleTrashed(
67                     props.resource.kind,
68                     props.resource.uuid,
69                     props.resource.ownerUuid,
70                     props.resource.isTrashed
71                 ));
72             }
73         }}>
74             <RestoreFromTrashIcon/>
75         </IconButton>
76     );
77
78 export const trashPanelColumns: DataColumns<string, TrashPanelFilter> = [
79     {
80         name: TrashPanelColumnNames.NAME,
81         selected: true,
82         configurable: true,
83         sortDirection: SortDirection.ASC,
84         filters: [],
85         render: uuid => <ResourceName uuid={uuid}/>
86     },
87     {
88         name: TrashPanelColumnNames.TYPE,
89         selected: true,
90         configurable: true,
91         sortDirection: SortDirection.NONE,
92         filters: [
93             {
94                 name: resourceLabel(ResourceKind.COLLECTION),
95                 selected: true,
96                 type: ResourceKind.COLLECTION
97             },
98             {
99                 name: resourceLabel(ResourceKind.PROCESS),
100                 selected: true,
101                 type: ResourceKind.PROCESS
102             },
103             {
104                 name: resourceLabel(ResourceKind.PROJECT),
105                 selected: true,
106                 type: ResourceKind.PROJECT
107             }
108         ],
109         render: uuid => <ResourceType uuid={uuid}/>,
110     },
111     {
112         name: TrashPanelColumnNames.FILE_SIZE,
113         selected: true,
114         configurable: true,
115         sortDirection: SortDirection.NONE,
116         filters: [],
117         render: uuid => <ResourceFileSize uuid={uuid} />
118     },
119     {
120         name: TrashPanelColumnNames.TRASHED_DATE,
121         selected: true,
122         configurable: true,
123         sortDirection: SortDirection.NONE,
124         filters: [],
125         render: uuid => <ResourceTrashDate uuid={uuid} />
126     },
127     {
128         name: TrashPanelColumnNames.TO_BE_DELETED,
129         selected: true,
130         configurable: true,
131         sortDirection: SortDirection.NONE,
132         filters: [],
133         render: uuid => <ResourceDeleteDate uuid={uuid} />
134     },
135     {
136         name: '',
137         selected: true,
138         configurable: false,
139         sortDirection: SortDirection.NONE,
140         filters: [],
141         render: uuid => <ResourceRestore uuid={uuid}/>
142     }
143 ];
144
145 interface TrashPanelDataProps {
146     currentItemId: string;
147     resources: ResourcesState;
148 }
149
150 type TrashPanelProps = TrashPanelDataProps & DispatchProp & WithStyles<CssRules>;
151
152 export const TrashPanel = withStyles(styles)(
153     connect((state: RootState) => ({
154         currentItemId: getProperty(PROJECT_PANEL_CURRENT_UUID)(state.properties),
155         resources: state.resources
156     }))(
157         class extends React.Component<TrashPanelProps> {
158             render() {
159                 return <DataExplorer
160                     id={TRASH_PANEL_ID}
161                     onRowClick={this.handleRowClick}
162                     onRowDoubleClick={this.handleRowDoubleClick}
163                     onContextMenu={this.handleContextMenu}
164                     defaultIcon={TrashIcon}
165                     defaultMessages={['Your trash list is empty.']}
166                     contextMenuColumn={false}/>
167                 ;
168             }
169
170             handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
171                 const resource = getResource<TrashableResource>(resourceUuid)(this.props.resources);
172                 if (resource) {
173                     this.props.dispatch<any>(openContextMenu(event, {
174                         name: '',
175                         uuid: resource.uuid,
176                         ownerUuid: resource.ownerUuid,
177                         isTrashed: resource.isTrashed,
178                         kind: resource.kind,
179                         menuKind: ContextMenuKind.TRASH
180                     }));
181                 }
182             }
183
184             handleRowDoubleClick = (uuid: string) => {
185                 this.props.dispatch<any>(navigateTo(uuid));
186             }
187
188             handleRowClick = (uuid: string) => {
189                 this.props.dispatch(loadDetailsPanel(uuid));
190             }
191         }
192     )
193 );