Implement sorting in projet-panel
[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 * as React from 'react';
6 import { RouteComponentProps } from 'react-router';
7 import { ProjectState } from '../../store/project/project-reducer';
8 import { RootState } from '../../store/store';
9 import { connect, DispatchProp } from 'react-redux';
10 import { CollectionState } from "../../store/collection/collection-reducer";
11 import { ItemMode, setProjectItem } from "../../store/navigation/navigation-action";
12 import ProjectExplorer from "../../views-components/project-explorer/project-explorer";
13 import { projectExplorerItems } from "./project-panel-selectors";
14 import { ProjectExplorerItem } from "../../views-components/project-explorer/project-explorer-item";
15 import { Button, StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
16 import { DataColumn, SortDirection } from '../../components/data-table/data-column';
17
18 interface ProjectPanelDataProps {
19     projects: ProjectState;
20     collections: CollectionState;
21 }
22
23 type ProjectPanelProps = ProjectPanelDataProps & RouteComponentProps<{ name: string }> & DispatchProp;
24
25 interface ProjectPanelState {
26     sort: {
27         columnName: string;
28         direction: SortDirection;
29     };
30 }
31
32 class ProjectPanel extends React.Component<ProjectPanelProps & WithStyles<CssRules>, ProjectPanelState> {
33     state: ProjectPanelState = {
34         sort: {
35             columnName: "Name",
36             direction: "desc"
37         }
38     };
39
40     render() {
41         const items = projectExplorerItems(
42             this.props.projects.items,
43             this.props.projects.currentItemId,
44             this.props.collections
45         );
46         const [goBackItem, ...otherItems] = items;
47         const sortedItems = sortItems(this.state.sort, otherItems);
48         return (
49             <div>
50                 <div className={this.props.classes.toolbar}>
51                     <Button color="primary" variant="raised" className={this.props.classes.button}>
52                         Create a collection
53                     </Button>
54                     <Button color="primary" variant="raised" className={this.props.classes.button}>
55                         Run a process
56                     </Button>
57                     <Button color="primary" variant="raised" className={this.props.classes.button}>
58                         Create a project
59                     </Button>
60                 </div>
61                 <ProjectExplorer
62                     items={goBackItem ? [goBackItem, ...sortedItems] : sortedItems }
63                     onRowClick={this.goToItem}
64                     onToggleSort={this.toggleSort}
65                 />
66             </div>
67         );
68     }
69
70     goToItem = (item: ProjectExplorerItem) => {
71         this.props.dispatch<any>(setProjectItem(this.props.projects.items, item.uuid, item.kind, ItemMode.BOTH));
72     }
73
74     toggleSort = (column: DataColumn<ProjectExplorerItem>) => {
75         this.setState({sort: {
76             columnName: column.name,
77             direction: column.sortDirection || "none"
78         }});
79     }
80 }
81
82 const sortItems = (sort: {columnName: string, direction: SortDirection}, items: ProjectExplorerItem[]) => {
83     const sortedItems = items.slice(0);
84     const direction = sort.direction === "asc" ? -1 : 1;
85     sortedItems.sort((a, b) => {
86         if(sort.columnName === "Last modified") {
87             return ((new Date(a.lastModified)).getTime() - (new Date(b.lastModified)).getTime()) * direction;
88         } else {
89             return a.name.localeCompare(b.name) * direction;
90         }
91     });
92     return sortedItems;
93 };
94
95 type CssRules = "toolbar" | "button";
96
97 const styles: StyleRulesCallback<CssRules> = theme => ({
98     toolbar: {
99         marginBottom: theme.spacing.unit * 3,
100         display: "flex",
101         justifyContent: "flex-end"
102     },
103     button: {
104         marginLeft: theme.spacing.unit
105     }
106 });
107
108 export default withStyles(styles)(
109     connect(
110         (state: RootState) => ({
111             projects: state.projects,
112             collections: state.collections
113         })
114     )(ProjectPanel));