left-side-panel-small-refactor
[arvados-workbench2.git] / src / views / workbench / workbench.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, Theme, WithStyles, withStyles } from '@material-ui/core/styles';
7 import Drawer from '@material-ui/core/Drawer';
8 import { connect, DispatchProp } from "react-redux";
9
10 import ProjectList from "../../components/project-list/project-list";
11 import { Route, Switch } from "react-router";
12 import authActions from "../../store/auth/auth-action";
13 import { User } from "../../models/user";
14 import { RootState } from "../../store/store";
15 import MainAppBar, { MainAppBarActionProps, MainAppBarMenuItem } from '../../components/main-app-bar/main-app-bar';
16 import { Breadcrumb } from '../../components/breadcrumbs/breadcrumbs';
17 import { push } from 'react-router-redux';
18 import projectActions from "../../store/project/project-action";
19 import sidePanelActions from '../../store/side-panel/side-panel-action';
20 import ProjectTree from '../../components/project-tree/project-tree';
21 import { TreeItem, TreeItemStatus } from "../../components/tree/tree";
22 import { Project } from "../../models/project";
23 import { projectService } from '../../services/services';
24 import SidePanel, { SidePanelItem } from '../../components/side-panel/side-panel';
25
26 const drawerWidth = 240;
27
28 type CssRules = 'root' | 'appBar' | 'drawerPaper' | 'content' | 'toolbar';
29
30 const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
31     root: {
32         flexGrow: 1,
33         zIndex: 1,
34         overflow: 'hidden',
35         position: 'relative',
36         display: 'flex',
37         width: '100vw',
38         height: '100vh'
39     },
40     appBar: {
41         zIndex: theme.zIndex.drawer + 1,
42         backgroundColor: '#692498',
43         position: "absolute",
44         width: "100%"
45     },
46     drawerPaper: {
47         position: 'relative',
48         width: drawerWidth,
49         display: 'flex',
50         flexDirection: 'column',
51     },
52     content: {
53         flexGrow: 1,
54         backgroundColor: theme.palette.background.default,
55         padding: theme.spacing.unit * 3,
56         height: '100%',
57         minWidth: 0,
58     },
59     toolbar: theme.mixins.toolbar
60 });
61
62 interface WorkbenchDataProps {
63     projects: Array<TreeItem<Project>>;
64     user?: User;
65     sidePanelItems: SidePanelItem[];
66 }
67
68 interface WorkbenchActionProps {
69 }
70
71 type WorkbenchProps = WorkbenchDataProps & WorkbenchActionProps & DispatchProp & WithStyles<CssRules>;
72
73 interface NavBreadcrumb extends Breadcrumb {
74     path: string;
75 }
76
77 interface NavMenuItem extends MainAppBarMenuItem {
78     action: () => void;
79 }
80
81 interface WorkbenchState {
82     anchorEl: any;
83     breadcrumbs: NavBreadcrumb[];
84     searchText: string;
85     menuItems: {
86         accountMenu: NavMenuItem[],
87         helpMenu: NavMenuItem[],
88         anonymousMenu: NavMenuItem[]
89     };
90 }
91
92 class Workbench extends React.Component<WorkbenchProps, WorkbenchState> {
93     state = {
94         anchorEl: null,
95         searchText: "",
96         breadcrumbs: [
97             {
98                 label: "Projects",
99                 path: "/projects"
100             }, {
101                 label: "Project 1",
102                 path: "/projects/project-1"
103             }
104         ],
105         menuItems: {
106             accountMenu: [
107                 {
108                     label: "Logout",
109                     action: () => this.props.dispatch(authActions.LOGOUT())
110                 },
111                 {
112                     label: "My account",
113                     action: () => this.props.dispatch(push("/my-account"))
114                 }
115             ],
116             helpMenu: [
117                 {
118                     label: "Help",
119                     action: () => this.props.dispatch(push("/help"))
120                 }
121             ],
122             anonymousMenu: [
123                 {
124                     label: "Sign in",
125                     action: () => this.props.dispatch(authActions.LOGIN())
126                 }
127             ]
128         }
129     };
130
131
132     mainAppBarActions: MainAppBarActionProps = {
133         onBreadcrumbClick: (breadcrumb: NavBreadcrumb) => this.props.dispatch(push(breadcrumb.path)),
134         onSearch: searchText => {
135             this.setState({ searchText });
136             this.props.dispatch(push(`/search?q=${searchText}`));
137         },
138         onMenuItemClick: (menuItem: NavMenuItem) => menuItem.action()
139     };
140
141     toggleProjectTreeItemOpen = (itemId: string, status: TreeItemStatus) => {
142         if (status === TreeItemStatus.Loaded) {
143             this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(itemId));
144             this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
145         } else {
146             this.props.dispatch<any>(projectService.getProjectList(itemId)).then(() => {
147                 this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(itemId));
148                 this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
149             });
150         }
151     }
152
153     toggleProjectTreeItemActive = (itemId: string) => {
154         this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
155         this.props.dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(itemId));
156     }
157
158     toggleSidePanelOpen = (itemId: string) => {
159         this.props.dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_OPEN(itemId));
160     }
161
162     toggleSidePanelActive = (itemId: string) => {
163         this.props.dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_ACTIVE(itemId));
164         this.props.dispatch(projectActions.RESET_PROJECT_TREE_ACTIVITY(itemId));
165     }
166
167     render() {
168         const { classes, user, projects, sidePanelItems } = this.props;
169         return (
170             <div className={classes.root}>
171                 <div className={classes.appBar}>
172                     <MainAppBar
173                         breadcrumbs={this.state.breadcrumbs}
174                         searchText={this.state.searchText}
175                         user={this.props.user}
176                         menuItems={this.state.menuItems}
177                         {...this.mainAppBarActions}
178                     />
179                 </div>
180                 {user &&
181                     <Drawer
182                         variant="permanent"
183                         classes={{
184                             paper: classes.drawerPaper,
185                         }}>
186                         <div className={classes.toolbar} />
187                             <SidePanel
188                                 toggleOpen={this.toggleSidePanelOpen}
189                                 toggleActive={this.toggleSidePanelActive}
190                                 sidePanelItems={sidePanelItems}>
191                                 <ProjectTree
192                                     projects={projects}
193                                     toggleOpen={this.toggleProjectTreeItemOpen}
194                                     toggleActive={this.toggleProjectTreeItemActive} />
195                             </SidePanel>
196                     </Drawer>}
197                 <main className={classes.content}>
198                     <div className={classes.toolbar} />
199                     <Switch>
200                         <Route path="/project/:name" component={ProjectList} />
201                     </Switch>
202                 </main>
203             </div>
204         );
205     }
206 }
207
208 export default connect<WorkbenchDataProps>(
209     (state: RootState) => ({
210         projects: state.projects,
211         user: state.auth.user,
212         sidePanelItems: state.sidePanel,
213     })
214 )(
215     withStyles(styles)(Workbench)
216 );