1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
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 import { Route, Switch } from "react-router";
10 import authActions from "../../store/auth/auth-action";
11 import { User } from "../../models/user";
12 import { RootState } from "../../store/store";
13 import MainAppBar, { MainAppBarActionProps, MainAppBarMenuItem } from '../../views-components/main-app-bar/main-app-bar';
14 import { Breadcrumb } from '../../components/breadcrumbs/breadcrumbs';
15 import { push } from 'react-router-redux';
16 import projectActions, { getProjectList } from "../../store/project/project-action";
17 import ProjectTree from '../../views-components/project-tree/project-tree';
18 import { TreeItem, TreeItemStatus } from "../../components/tree/tree";
19 import { Project } from "../../models/project";
20 import { getTreePath } from '../../store/project/project-reducer';
21 import ProjectPanel from '../project-panel/project-panel';
22 import sidePanelActions from '../../store/side-panel/side-panel-action';
23 import { projectService } from '../../services/services';
24 import SidePanel, { SidePanelItem } from '../../components/side-panel/side-panel';
26 const drawerWidth = 240;
27 const appBarHeight = 102;
29 type CssRules = 'root' | 'appBar' | 'drawerPaper' | 'content' | 'contentWrapper' | 'toolbar';
31 const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
42 zIndex: theme.zIndex.drawer + 1,
43 backgroundColor: '#692498',
51 flexDirection: 'column',
54 backgroundColor: theme.palette.background.default,
58 paddingTop: appBarHeight
61 padding: theme.spacing.unit * 3,
65 toolbar: theme.mixins.toolbar
68 interface WorkbenchDataProps {
69 projects: Array<TreeItem<Project>>;
71 sidePanelItems: SidePanelItem[];
74 interface WorkbenchActionProps {
77 type WorkbenchProps = WorkbenchDataProps & WorkbenchActionProps & DispatchProp & WithStyles<CssRules>;
79 interface NavBreadcrumb extends Breadcrumb {
81 status: TreeItemStatus;
84 interface NavMenuItem extends MainAppBarMenuItem {
88 interface WorkbenchState {
90 breadcrumbs: NavBreadcrumb[];
93 accountMenu: NavMenuItem[],
94 helpMenu: NavMenuItem[],
95 anonymousMenu: NavMenuItem[]
99 class Workbench extends React.Component<WorkbenchProps, WorkbenchState> {
108 action: () => this.props.dispatch(authActions.LOGOUT())
112 action: () => this.props.dispatch(push("/my-account"))
118 action: () => this.props.dispatch(push("/help"))
124 action: () => this.props.dispatch(authActions.LOGIN())
131 mainAppBarActions: MainAppBarActionProps = {
132 onBreadcrumbClick: ({ itemId, status }: NavBreadcrumb) => {
133 this.toggleProjectTreeItemOpen(itemId, status);
135 onSearch: searchText => {
136 this.setState({ searchText });
137 this.props.dispatch(push(`/search?q=${searchText}`));
139 onMenuItemClick: (menuItem: NavMenuItem) => menuItem.action()
142 toggleProjectTreeItemOpen = (itemId: string, status: TreeItemStatus) => {
143 if (status === TreeItemStatus.Loaded) {
144 this.openProjectItem(itemId);
145 this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(itemId));
146 this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
148 this.props.dispatch<any>(getProjectList(itemId))
150 this.openProjectItem(itemId);
151 this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(itemId));
152 this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
157 toggleProjectTreeItemActive = (itemId: string, status: TreeItemStatus) => {
158 if (status === TreeItemStatus.Loaded) {
159 this.openProjectItem(itemId);
160 this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
161 this.props.dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(itemId));
163 this.props.dispatch<any>(getProjectList(itemId))
165 this.openProjectItem(itemId);
166 this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
167 this.props.dispatch(sidePanelActions.RESET_SIDE_PANEL_ACTIVITY(itemId));
172 toggleSidePanelOpen = (itemId: string) => {
173 this.props.dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_OPEN(itemId));
176 toggleSidePanelActive = (itemId: string) => {
177 this.props.dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_ACTIVE(itemId));
178 this.props.dispatch(projectActions.RESET_PROJECT_TREE_ACTIVITY(itemId));
181 openProjectItem = (itemId: string) => {
182 const branch = getTreePath(this.props.projects, itemId);
184 breadcrumbs: branch.map(item => ({
185 label: item.data.name,
186 itemId: item.data.uuid,
190 this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(itemId));
191 this.props.dispatch(push(`/project/${itemId}`));
195 const { classes, user, projects, sidePanelItems } = this.props;
197 <div className={classes.root}>
198 <div className={classes.appBar}>
200 breadcrumbs={this.state.breadcrumbs}
201 searchText={this.state.searchText}
202 user={this.props.user}
203 menuItems={this.state.menuItems}
204 {...this.mainAppBarActions}
211 paper: classes.drawerPaper,
213 <div className={classes.toolbar} />
215 toggleOpen={this.toggleSidePanelOpen}
216 toggleActive={this.toggleSidePanelActive}
217 sidePanelItems={sidePanelItems}>
220 toggleOpen={this.toggleProjectTreeItemOpen}
221 toggleActive={this.toggleProjectTreeItemActive} />
224 <main className={classes.contentWrapper}>
225 <div className={classes.content}>
227 <Route path="/project/:name" component={ProjectPanel} />
236 export default connect<WorkbenchDataProps>(
237 (state: RootState) => ({
238 projects: state.projects,
239 user: state.auth.user,
240 sidePanelItems: state.sidePanel,
243 withStyles(styles)(Workbench)