94ae438986eeb3145ba02a1dfc872966de18c91f
[arvados-workbench2.git] / src / views-components / project-explorer / project-explorer.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 { ProjectExplorerItem } from './project-explorer-item';
7 import { Grid, Typography } from '@material-ui/core';
8 import { formatDate, formatFileSize } from '../../common/formatters';
9 import DataExplorer from '../../components/data-explorer/data-explorer';
10 import { DataColumn, toggleSortDirection, resetSortDirection } from '../../components/data-table/data-column';
11 import { DataTableFilterItem } from '../../components/data-table-filters/data-table-filters';
12 import { ContextMenuAction } from '../../components/context-menu/context-menu';
13 import { ResourceKind } from "../../models/resource";
14
15 export interface ProjectExplorerContextActions {
16     onAddToFavourite: (item: ProjectExplorerItem) => void;
17     onCopy: (item: ProjectExplorerItem) => void;
18     onDownload: (item: ProjectExplorerItem) => void;
19     onMoveTo: (item: ProjectExplorerItem) => void;
20     onRemove: (item: ProjectExplorerItem) => void;
21     onRename: (item: ProjectExplorerItem) => void;
22     onShare: (item: ProjectExplorerItem) => void;
23 }
24
25 interface ProjectExplorerProps {
26     items: ProjectExplorerItem[];
27     onRowClick: (item: ProjectExplorerItem) => void;
28 }
29
30 interface ProjectExplorerState {
31     columns: Array<DataColumn<ProjectExplorerItem>>;
32     searchValue: string;
33     page: number;
34     rowsPerPage: number;
35 }
36
37 class ProjectExplorer extends React.Component<ProjectExplorerProps, ProjectExplorerState> {
38     state: ProjectExplorerState = {
39         searchValue: "",
40         page: 0,
41         rowsPerPage: 10,
42         columns: [{
43             name: "Name",
44             selected: true,
45             sortDirection: "asc",
46             render: renderName,
47             width: "450px"
48         }, {
49             name: "Status",
50             selected: true,
51             filters: [{
52                 name: "In progress",
53                 selected: true
54             }, {
55                 name: "Complete",
56                 selected: true
57             }],
58             render: renderStatus,
59             width: "75px"
60         }, {
61             name: "Type",
62             selected: true,
63             filters: [{
64                 name: "Collection",
65                 selected: true
66             }, {
67                 name: "Group",
68                 selected: true
69             }],
70             render: item => renderType(item.kind),
71             width: "125px"
72         }, {
73             name: "Owner",
74             selected: true,
75             render: item => renderOwner(item.owner),
76             width: "200px"
77         }, {
78             name: "File size",
79             selected: true,
80             sortDirection: "none",
81             render: item => renderFileSize(item.fileSize),
82             width: "50px"
83         }, {
84             name: "Last modified",
85             selected: true,
86             render: item => renderDate(item.lastModified),
87             width: "150px"
88         }]
89     };
90
91     contextMenuActions = [[{
92         icon: "fas fa-users fa-fw",
93         name: "Share"
94     }, {
95         icon: "fas fa-sign-out-alt fa-fw",
96         name: "Move to"
97     }, {
98         icon: "fas fa-star fa-fw",
99         name: "Add to favourite"
100     }, {
101         icon: "fas fa-edit fa-fw",
102         name: "Rename"
103     }, {
104         icon: "fas fa-copy fa-fw",
105         name: "Make a copy"
106     }, {
107         icon: "fas fa-download fa-fw",
108         name: "Download"
109     }], [{
110         icon: "fas fa-trash-alt fa-fw",
111         name: "Remove"
112     }
113     ]];
114
115     render() {
116         return <DataExplorer
117             items={this.props.items}
118             columns={this.state.columns}
119             contextActions={this.contextMenuActions}
120             searchValue={this.state.searchValue}
121             page={this.state.page}
122             rowsPerPage={this.state.rowsPerPage}
123             onColumnToggle={this.toggleColumn}
124             onFiltersChange={this.changeFilters}
125             onRowClick={this.props.onRowClick}
126             onSortToggle={this.toggleSort}
127             onSearch={this.search}
128             onContextAction={this.executeAction}
129             onChangePage={this.changePage}
130             onChangeRowsPerPage={this.changeRowsPerPage} />;
131     }
132
133     toggleColumn = (toggledColumn: DataColumn<ProjectExplorerItem>) => {
134         this.setState({
135             columns: this.state.columns.map(column =>
136                 column.name === toggledColumn.name
137                     ? { ...column, selected: !column.selected }
138                     : column
139             )
140         });
141     }
142
143     toggleSort = (toggledColumn: DataColumn<ProjectExplorerItem>) => {
144         this.setState({
145             columns: this.state.columns.map(column =>
146                 column.name === toggledColumn.name
147                     ? toggleSortDirection(column)
148                     : resetSortDirection(column)
149             )
150         });
151     }
152
153     changeFilters = (filters: DataTableFilterItem[], updatedColumn: DataColumn<ProjectExplorerItem>) => {
154         this.setState({
155             columns: this.state.columns.map(column =>
156                 column.name === updatedColumn.name
157                     ? { ...column, filters }
158                     : column
159             )
160         });
161     }
162
163     executeAction = (action: ContextMenuAction, item: ProjectExplorerItem) => {
164         alert(`Executing ${action.name} on ${item.name}`);
165     }
166
167     search = (searchValue: string) => {
168         this.setState({ searchValue });
169     }
170
171     changePage = (page: number) => {
172         this.setState({ page });
173     }
174
175     changeRowsPerPage = (rowsPerPage: number) => {
176         this.setState({ rowsPerPage });
177     }
178 }
179
180 const renderName = (item: ProjectExplorerItem) =>
181     <Grid
182         container
183         alignItems="center"
184         wrap="nowrap"
185         spacing={16}>
186         <Grid item>
187             {renderIcon(item)}
188         </Grid>
189         <Grid item>
190             <Typography color="primary">
191                 {item.name}
192             </Typography>
193         </Grid>
194     </Grid>;
195
196
197 const renderIcon = (item: ProjectExplorerItem) => {
198     switch (item.kind) {
199         case ResourceKind.LEVEL_UP:
200             return <i className="icon-level-up" style={{fontSize: "1rem"}}/>;
201         case ResourceKind.PROJECT:
202             return <i className="fas fa-folder fa-lg"/>;
203         case ResourceKind.COLLECTION:
204             return <i className="fas fa-th fa-lg"/>;
205         default:
206             return <i />;
207     }
208 };
209
210 const renderDate = (date: string) =>
211     <Typography noWrap>
212         {formatDate(date)}
213     </Typography>;
214
215 const renderFileSize = (fileSize?: number) =>
216     <Typography noWrap>
217         {formatFileSize(fileSize)}
218     </Typography>;
219
220 const renderOwner = (owner: string) =>
221     <Typography noWrap color="primary">
222         {owner}
223     </Typography>;
224
225 const renderType = (type: string) =>
226     <Typography noWrap>
227         {type}
228     </Typography>;
229
230 const renderStatus = (item: ProjectExplorerItem) =>
231     <Typography noWrap align="center">
232         {item.status || "-"}
233     </Typography>;
234
235 export default ProjectExplorer;