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