merge master
authorPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Tue, 28 Aug 2018 11:08:29 +0000 (13:08 +0200)
committerPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Tue, 28 Aug 2018 11:08:29 +0000 (13:08 +0200)
Feature #13858

Arvados-DCO-1.1-Signed-off-by: Pawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>

1  2 
src/index.tsx
src/routes/routes.ts
src/views/process-panel/process-panel.tsx
src/views/workbench/workbench.tsx

diff --combined src/index.tsx
index c6a5da24a372f2f3adbb822435e69008de18a3bc,c7f76c68f8c2e971a7558122f50ba0602512fea9..d3115a6754bf70feb6731e8910e71b04859534f4
@@@ -7,14 -7,14 +7,14 @@@ import * as ReactDOM from 'react-dom'
  import { Provider } from "react-redux";
  import { Workbench } from './views/workbench/workbench';
  import './index.css';
- import { Route } from "react-router";
+ import { Route } from 'react-router';
  import createBrowserHistory from "history/createBrowserHistory";
- import { configureStore } from "./store/store";
+ import { History } from "history";
+ import { configureStore, RootStore } from './store/store';
  import { ConnectedRouter } from "react-router-redux";
  import { ApiToken } from "./views-components/api-token/api-token";
  import { initAuth } from "./store/auth/auth-action";
  import { createServices } from "./services/services";
- import { getProjectList } from "./store/project/project-action";
  import { MuiThemeProvider } from '@material-ui/core/styles';
  import { CustomTheme } from './common/custom-theme';
  import { fetchConfig } from './common/config';
@@@ -27,7 -27,9 +27,10 @@@ import { collectionFilesActionSet } fro
  import { collectionFilesItemActionSet } from './views-components/context-menu/action-sets/collection-files-item-action-set';
  import { collectionActionSet } from './views-components/context-menu/action-sets/collection-action-set';
  import { collectionResourceActionSet } from './views-components/context-menu/action-sets/collection-resource-action-set';
 +import { processActionSet } from './views-components/context-menu/action-sets/process-action-set';
+ import { addRouteChangeHandlers } from './routes/routes';
+ import { loadWorkbench } from './store/workbench/workbench-actions';
+ import { Routes } from '~/routes/routes';
  
  const getBuildNumber = () => "BN-" + (process.env.REACT_APP_BUILD_NUMBER || "dev");
  const getGitCommit = () => "GIT-" + (process.env.REACT_APP_GIT_COMMIT || "latest").substr(0, 7);
@@@ -45,27 -47,27 +48,28 @@@ addMenuActionSet(ContextMenuKind.COLLEC
  addMenuActionSet(ContextMenuKind.COLLECTION_FILES_ITEM, collectionFilesItemActionSet);
  addMenuActionSet(ContextMenuKind.COLLECTION, collectionActionSet);
  addMenuActionSet(ContextMenuKind.COLLECTION_RESOURCE, collectionResourceActionSet);
 +addMenuActionSet(ContextMenuKind.PROCESS, processActionSet);
  
  fetchConfig()
-     .then(config => {
+     .then((config) => {
          const history = createBrowserHistory();
          const services = createServices(config);
          const store = configureStore(history, services);
  
+         store.subscribe(initListener(history, store));
          store.dispatch(initAuth());
-         store.dispatch(getProjectList(services.authService.getUuid()));  
  
-         const TokenComponent = (props: any) => <ApiToken authService={services.authService} {...props}/>;
-         const WorkbenchComponent = (props: any) => <Workbench authService={services.authService} buildInfo={buildInfo} {...props}/>;
+         const TokenComponent = (props: any) => <ApiToken authService={services.authService} {...props} />;
+         const WorkbenchComponent = (props: any) => <Workbench authService={services.authService} buildInfo={buildInfo} {...props} />;
  
          const App = () =>
              <MuiThemeProvider theme={CustomTheme}>
                  <Provider store={store}>
                      <ConnectedRouter history={history}>
                          <div>
-                             <Route path="/" component={WorkbenchComponent} />
-                             <Route path="/token" component={TokenComponent} />
+                             <Route path={Routes.TOKEN} component={TokenComponent} />
+                             <Route path={Routes.ROOT} component={WorkbenchComponent} />
                          </div>
                      </ConnectedRouter>
                  </Provider>
              <App />,
              document.getElementById('root') as HTMLElement
          );
      });
  
+ const initListener = (history: History, store: RootStore) => {
+     let initialized = false;
+     return async () => {
+         const { router, auth } = store.getState();
+         if (router.location && auth.user && !initialized) {
+             initialized = true;
+             await store.dispatch(loadWorkbench());
+             addRouteChangeHandlers(history, store);
+         }
+     };
+ };
  
diff --combined src/routes/routes.ts
index 0000000000000000000000000000000000000000,0279bb06f25f0a2372a848f7cc7cbb9585fcd36c..0bf7110126df7849f4571cfbe6e2c21dffa49fdd
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,71 +1,72 @@@
+ // Copyright (C) The Arvados Authors. All rights reserved.
+ //
+ // SPDX-License-Identifier: AGPL-3.0
+ import { History, Location } from 'history';
+ import { RootStore } from '../store/store';
+ import { matchPath } from 'react-router';
+ import { ResourceKind, RESOURCE_UUID_PATTERN, extractUuidKind } from '~/models/resource';
+ import { getProjectUrl } from '../models/project';
+ import { getCollectionUrl } from '~/models/collection';
+ import { loadProject, loadFavorites, loadCollection } from '../store/workbench/workbench-actions';
+ export const Routes = {
+     ROOT: '/',
+     TOKEN: '/token',
+     PROJECTS: `/projects/:id(${RESOURCE_UUID_PATTERN})`,
+     COLLECTIONS: `/collections/:id(${RESOURCE_UUID_PATTERN})`,
++    PROCESS: `/processes/:id(${RESOURCE_UUID_PATTERN})`,
+     FAVORITES: '/favorites',
+ };
+ export const getResourceUrl = (uuid: string) => {
+     const kind = extractUuidKind(uuid);
+     switch (kind) {
+         case ResourceKind.PROJECT:
+             return getProjectUrl(uuid);
+         case ResourceKind.COLLECTION:
+             return getCollectionUrl(uuid);
+         default:
+             return undefined;
+     }
+ };
+ export const addRouteChangeHandlers = (history: History, store: RootStore) => {
+     const handler = handleLocationChange(store);
+     handler(history.location);
+     history.listen(handler);
+ };
+ export const matchRootRoute = (route: string) =>
+     matchPath(route, { path: Routes.ROOT, exact: true });
+ export const matchFavoritesRoute = (route: string) =>
+     matchPath(route, { path: Routes.FAVORITES });
+ export interface ProjectRouteParams {
+     id: string;
+ }
+ export const matchProjectRoute = (route: string) =>
+     matchPath<ProjectRouteParams>(route, { path: Routes.PROJECTS });
+ export interface CollectionRouteParams {
+     id: string;
+ }
+ export const matchCollectionRoute = (route: string) =>
+     matchPath<CollectionRouteParams>(route, { path: Routes.COLLECTIONS });
+ const handleLocationChange = (store: RootStore) => ({ pathname }: Location) => {
+     const projectMatch = matchProjectRoute(pathname);
+     const collectionMatch = matchCollectionRoute(pathname);
+     const favoriteMatch = matchFavoritesRoute(pathname);
+     if (projectMatch) {
+         store.dispatch(loadProject(projectMatch.params.id));
+     } else if (collectionMatch) {
+         store.dispatch(loadCollection(collectionMatch.params.id));
+     } else if (favoriteMatch) {
+         store.dispatch(loadFavorites());
+     }
+ };
index 08bd37015d228837d3834952bacb4ed8041a40a2,0000000000000000000000000000000000000000..70a7a405ac8e83ee6c66ee18689bad107c46683c
mode 100644,000000..100644
--- /dev/null
@@@ -1,129 -1,0 +1,141 @@@
-                 const { classes, onContextMenu, item } = this.props;
 +// Copyright (C) The Arvados Authors. All rights reserved.
 +//
 +// SPDX-License-Identifier: AGPL-3.0
 +
 +import * as React from 'react';
 +import {
 +    StyleRulesCallback, WithStyles, withStyles, Card,
 +    CardHeader, IconButton, CardContent, Grid, Chip
 +} from '@material-ui/core';
 +import { ArvadosTheme } from '~/common/custom-theme';
 +import { ProcessResource } from '~/models/process';
 +import { DispatchProp, connect } from 'react-redux';
 +import { RouteComponentProps } from 'react-router';
 +import { MoreOptionsIcon, ProcessIcon } from '~/components/icon/icon';
 +import { DetailsAttribute } from '~/components/details-attribute/details-attribute';
 +import { RootState } from '~/store/store';
++import { ContextMenuKind } from '~/views-components/context-menu/context-menu';
++import { openContextMenu } from '~/store/context-menu/context-menu-actions';
 +
 +type CssRules = 'card' | 'iconHeader' | 'label' | 'value' | 'content' | 'chip' | 'headerText' | 'link';
 +
 +const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
 +    card: {
 +        marginBottom: theme.spacing.unit * 2,
 +        width: '60%'
 +    },
 +    iconHeader: {
 +        fontSize: '1.875rem',
 +        color: theme.customs.colors.green700
 +    },
 +    label: {
 +        fontSize: '0.875rem',
 +    },
 +    value: {
 +        textTransform: 'none',
 +        fontSize: '0.875rem'
 +    },
 +    content: {
 +        display: 'flex',
 +        paddingBottom: '0px ',
 +        paddingTop: '0px',
 +        '&:last-child': {
 +            paddingBottom: '0px ',
 +        }
 +    },
 +    link: {
 +        fontSize: '0.875rem',
 +        '&:hover': {
 +            color: theme.palette.primary.main,
 +            cursor: 'pointer'
 +        }
 +    },
 +    chip: {
 +        height: theme.spacing.unit * 2.5,
 +        width: theme.spacing.unit * 12,
 +        backgroundColor: theme.customs.colors.green700,
 +        color: theme.palette.common.white,
 +        fontSize: '0.875rem',
 +        borderRadius: theme.spacing.unit * 0.625
 +    },
 +    headerText: {
 +        fontSize: '0.875rem',
 +        display: 'flex',
 +        position: 'relative',
 +        justifyContent: 'flex-start',
 +        top: -theme.spacing.unit * 4.5,
 +        left: theme.spacing.unit * 3,
 +    }
 +});
 +
 +interface ProcessPanelDataProps {
 +    item: ProcessResource;
 +}
 +
 +interface ProcessPanelActionProps {
 +    onContextMenu: (event: React.MouseEvent<HTMLElement>, item: ProcessResource) => void;
 +}
 +
 +type ProcessPanelProps = ProcessPanelDataProps & ProcessPanelActionProps & DispatchProp & WithStyles<CssRules> & RouteComponentProps<{ id: string }>;
 +
 +export const ProcessPanel = withStyles(styles)(
 +    connect((state: RootState) => ({
 +        item: state.collectionPanel.item,
 +        tags: state.collectionPanel.tags
 +    }))(
 +        class extends React.Component<ProcessPanelProps> {
 +            render() {
-                                     onClick={event => onContextMenu(event, item)}>
++                const { classes } = this.props;
 +
 +                return <div>
 +                    <Card className={classes.card}>
 +                        <CardHeader
 +                            avatar={<ProcessIcon className={classes.iconHeader} />}
 +                            action={
 +                                <IconButton
 +                                    aria-label="More options"
-                             title="Pipeline template that generates a config file from a template"
-                              />
++                                    onClick={this.handleContextMenu}>
 +                                    <MoreOptionsIcon />
 +                                </IconButton>
 +                            }
++                            title="Pipeline template that generates a config file from a template" />
 +                        <CardContent className={classes.content}>
 +                            <Grid container direction="column">
 +                                <Grid item xs={8}>
 +                                    <DetailsAttribute classLabel={classes.label} classValue={classes.value}
 +                                        label='Status' value={<Chip label="Complete" className={classes.chip} />} />
 +                                    <DetailsAttribute classLabel={classes.label} classValue={classes.value}
 +                                        label='Started at' value="1:25 PM 3/23/2018" />
 +                                    <DetailsAttribute classLabel={classes.label} classValue={classes.value}
 +                                        label='Finished at' value='1:25 PM 3/23/2018' />
 +                                </Grid>
 +                            </Grid>
 +                            <Grid container direction="column">
 +                                <Grid item xs={8}>
 +                                    <DetailsAttribute classLabel={classes.link} classValue={classes.value}
 +                                        label='Container output' />
 +                                    <DetailsAttribute classLabel={classes.link} classValue={classes.value}
 +                                        label='Show inputs' />
 +                                    <DetailsAttribute classLabel={classes.link} classValue={classes.value}
 +                                        label='Show command' />
 +                                </Grid>
 +                            </Grid>
 +                        </CardContent>
 +                        <span className={classes.headerText}>This container request was created from the workflow FastQC MultiQC</span>
 +                    </Card>
 +                </div>;
 +            }
++
++            handleContextMenu = (event: React.MouseEvent<any>) => {
++                // const { uuid, name, description } = this.props.item;
++                const resource = {
++                    uuid: '',
++                    name: '',
++                    description: '',
++                    kind: ContextMenuKind.PROCESS
++                };
++                this.props.dispatch<any>(openContextMenu(event, resource));
++            }
 +        }
 +    )
 +);
index d8daed58b6ce1a421dc724bf47e0fe097b1c08bc,12010acc0eb04733877c3ac2245a39ed35b227e0..27470fa43086c2ebdd78630eec1db39b01ecdefc
@@@ -4,62 -4,43 +4,43 @@@
  
  import * as React from 'react';
  import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
- import Drawer from '@material-ui/core/Drawer';
  import { connect, DispatchProp } from "react-redux";
- import { Route, RouteComponentProps, Switch, Redirect } from "react-router";
+ import { Route, Switch } from "react-router";
  import { login, logout } from "~/store/auth/auth-action";
  import { User } from "~/models/user";
  import { RootState } from "~/store/store";
  import { MainAppBar, MainAppBarActionProps, MainAppBarMenuItem } from '~/views-components/main-app-bar/main-app-bar';
- import { Breadcrumb } from '~/components/breadcrumbs/breadcrumbs';
  import { push } from 'react-router-redux';
- import { reset } from 'redux-form';
- import { ProjectTree } from '~/views-components/project-tree/project-tree';
- import { TreeItem } from "~/components/tree/tree";
- import { getTreePath } from '~/store/project/project-reducer';
- import { sidePanelActions } from '~/store/side-panel/side-panel-action';
- import { SidePanel, SidePanelItem } from '~/components/side-panel/side-panel';
- import { ItemMode, setProjectItem } from "~/store/navigation/navigation-action";
- import { projectActions } from "~/store/project/project-action";
+ import { ProjectPanel } from "~/views/project-panel/project-panel";
  import { DetailsPanel } from '~/views-components/details-panel/details-panel';
  import { ArvadosTheme } from '~/common/custom-theme';
- import { detailsPanelActions, loadDetails } from "~/store/details-panel/details-panel-action";
- import { contextMenuActions } from "~/store/context-menu/context-menu-actions";
- import { ProjectResource } from '~/models/project';
- import { ResourceKind } from '~/models/resource';
- import { ProcessPanel } from '~/views/process-panel/process-panel';
- import { ContextMenu, ContextMenuKind } from "~/views-components/context-menu/context-menu";
+ import { detailsPanelActions } from "~/store/details-panel/details-panel-action";
+ import { ContextMenu } from "~/views-components/context-menu/context-menu";
  import { FavoritePanel } from "../favorite-panel/favorite-panel";
  import { CurrentTokenDialog } from '~/views-components/current-token-dialog/current-token-dialog';
  import { Snackbar } from '~/views-components/snackbar/snackbar';
- import { favoritePanelActions } from '~/store/favorite-panel/favorite-panel-action';
  import { CollectionPanel } from '../collection-panel/collection-panel';
- import { loadCollection, loadCollectionTags } from '~/store/collection-panel/collection-panel-action';
- import { getCollectionUrl } from '~/models/collection';
- import { PROJECT_CREATE_FORM_NAME, openProjectCreateDialog } from '~/store/projects/project-create-actions';
- import { COLLECTION_CREATE_FORM_NAME, openCollectionCreateDialog } from '~/store/collections/collection-create-actions';
- import { CreateCollectionDialog } from '~/views-components/dialog-forms/create-collection-dialog';
- import { UpdateCollectionDialog } from '~/views-components/dialog-forms/update-collection-dialog';
- import { CreateProjectDialog } from '~/views-components/dialog-forms/create-project-dialog';
- import { UpdateProjectDialog } from '~/views-components/dialog-forms/update-project-dialog';
- import { ProjectPanel } from "~/views/project-panel/project-panel";
  import { AuthService } from "~/services/auth-service/auth-service";
  import { RenameFileDialog } from '~/views-components/rename-file-dialog/rename-file-dialog';
  import { FileRemoveDialog } from '~/views-components/file-remove-dialog/file-remove-dialog';
  import { MultipleFilesRemoveDialog } from '~/views-components/file-remove-dialog/multiple-files-remove-dialog';
  import { UploadCollectionFilesDialog } from '~/views-components/upload-collection-files-dialog/upload-collection-files-dialog';
  import { CollectionPartialCopyDialog } from '~/views-components/collection-partial-copy-dialog/collection-partial-copy-dialog';
+ import { SidePanel } from '~/views-components/side-panel/side-panel';
+ import { Routes } from '~/routes/routes';
+ import { Breadcrumbs } from '~/views-components/breadcrumbs/breadcrumbs';
+ import { CreateProjectDialog } from '~/views-components/dialog-forms/create-project-dialog';
+ import { CreateCollectionDialog } from '~/views-components/dialog-forms/create-collection-dialog';
+ import { CopyCollectionDialog } from '~/views-components/dialog-forms/copy-collection-dialog';
+ import { UpdateCollectionDialog } from '~/views-components/dialog-forms/update-collection-dialog';
+ import { UpdateProjectDialog } from '~/views-components/dialog-forms/update-project-dialog';
  import { MoveProjectDialog } from '~/views-components/dialog-forms/move-project-dialog';
  import { MoveCollectionDialog } from '~/views-components/dialog-forms/move-collection-dialog';
- import { CopyCollectionDialog } from '~/views-components/dialog-forms/copy-collection-dialog';
 -
++import { ProcessPanel } from '~/views/process-panel/process-panel';
  
- const DRAWER_WITDH = 240;
  const APP_BAR_HEIGHT = 100;
  
- type CssRules = 'root' | 'appBar' | 'drawerPaper' | 'content' | 'contentWrapper' | 'toolbar';
+ type CssRules = 'root' | 'appBar' | 'content' | 'contentWrapper';
  
  const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
      root: {
          position: "absolute",
          width: "100%"
      },
-     drawerPaper: {
-         position: 'relative',
-         width: DRAWER_WITDH,
-         display: 'flex',
-         flexDirection: 'column',
-     },
      contentWrapper: {
          backgroundColor: theme.palette.background.default,
          display: "flex",
          flexGrow: 1,
          position: 'relative'
      },
-     toolbar: theme.mixins.toolbar
  });
  
  interface WorkbenchDataProps {
-     projects: Array<TreeItem<ProjectResource>>;
-     currentProjectId: string;
      user?: User;
      currentToken?: string;
-     sidePanelItems: SidePanelItem[];
  }
  
  interface WorkbenchGeneralProps {
@@@ -116,10 -87,6 +87,6 @@@ interface WorkbenchActionProps 
  
  type WorkbenchProps = WorkbenchDataProps & WorkbenchGeneralProps & WorkbenchActionProps & DispatchProp<any> & WithStyles<CssRules>;
  
- interface NavBreadcrumb extends Breadcrumb {
-     itemId: string;
- }
  interface NavMenuItem extends MainAppBarMenuItem {
      action: () => void;
  }
@@@ -138,16 -105,12 +105,12 @@@ interface WorkbenchState 
  export const Workbench = withStyles(styles)(
      connect<WorkbenchDataProps>(
          (state: RootState) => ({
-             projects: state.projects.items,
-             currentProjectId: state.projects.currentItemId,
              user: state.auth.user,
              currentToken: state.auth.apiToken,
-             sidePanelItems: state.sidePanel
          })
      )(
          class extends React.Component<WorkbenchProps, WorkbenchState> {
              state = {
-                 isCreationDialogOpen: false,
                  isCurrentTokenDialogOpen: false,
                  anchorEl: null,
                  searchText: "",
              };
  
              render() {
-                 const path = getTreePath(this.props.projects, this.props.currentProjectId);
-                 const breadcrumbs = path.map(item => ({
-                     label: item.data.name,
-                     itemId: item.data.uuid,
-                     status: item.status
-                 }));
                  const { classes, user } = this.props;
                  return (
                      <div className={classes.root}>
                          <div className={classes.appBar}>
                              <MainAppBar
-                                 breadcrumbs={breadcrumbs}
+                                 breadcrumbs={Breadcrumbs}
                                  searchText={this.state.searchText}
                                  user={this.props.user}
                                  menuItems={this.state.menuItems}
                                  buildInfo={this.props.buildInfo}
                                  {...this.mainAppBarActions} />
                          </div>
-                         {user &&
-                             <Drawer
-                                 variant="permanent"
-                                 classes={{
-                                     paper: classes.drawerPaper,
-                                 }}>
-                                 <div className={classes.toolbar} />
-                                 <SidePanel
-                                     toggleOpen={this.toggleSidePanelOpen}
-                                     toggleActive={this.toggleSidePanelActive}
-                                     sidePanelItems={this.props.sidePanelItems}
-                                     onContextMenu={(event) => this.openContextMenu(event, {
-                                         uuid: this.props.authService.getUuid() || "",
-                                         name: "",
-                                         kind: ContextMenuKind.ROOT_PROJECT
-                                     })}>
-                                     <ProjectTree
-                                         projects={this.props.projects}
-                                         toggleOpen={itemId => this.props.dispatch(setProjectItem(itemId, ItemMode.OPEN))}
-                                         onContextMenu={(event, item) => this.openContextMenu(event, {
-                                             uuid: item.data.uuid,
-                                             name: item.data.name,
-                                             kind: ContextMenuKind.PROJECT
-                                         })}
-                                         toggleActive={itemId => {
-                                             this.props.dispatch(setProjectItem(itemId, ItemMode.ACTIVE));
-                                             this.props.dispatch(loadDetails(itemId, ResourceKind.PROJECT));
-                                         }} />
-                                 </SidePanel>
-                             </Drawer>}
+                         {user && <SidePanel />}
                          <main className={classes.contentWrapper}>
                              <div className={classes.content}>
                                  <Switch>
-                                     <Route path='/' exact render={() => <Redirect to={`/projects/${this.props.authService.getUuid()}`} />} />
-                                     <Route path="/projects/:id" render={this.renderProjectPanel} />
-                                     <Route path="/favorites" render={this.renderFavoritePanel} />
-                                     <Route path="/collections/:id" render={this.renderCollectionPanel} />
-                                     <Route path="/process/:id" render={this.renderProcessPanel} />
+                                     <Route path={Routes.PROJECTS} component={ProjectPanel} />
+                                     <Route path={Routes.COLLECTIONS} component={CollectionPanel} />
+                                     <Route path={Routes.FAVORITES} component={FavoritePanel} />
++                                    <Route path={Routes.PROCESS} component={ProcessPanel} />
                                  </Switch>
                              </div>
                              {user && <DetailsPanel />}
                  );
              }
  
-             renderProcessPanel = (props: RouteComponentProps<{ id: string }>) => <ProcessPanel
-                 onContextMenu={(event, item) => {
-                     this.openContextMenu(event, {
-                         uuid: 'item.uuid',
-                         name: 'item.name',
-                         description: 'item.description',
-                         kind: ContextMenuKind.PROCESS
-                     });
-                 }}
-                 {...props} />
-             renderCollectionPanel = (props: RouteComponentProps<{ id: string }>) => <CollectionPanel
-                 onItemRouteChange={(collectionId) => {
-                     this.props.dispatch<any>(loadCollection(collectionId));
-                     this.props.dispatch<any>(loadCollectionTags(collectionId));
-                 }}
-                 onContextMenu={(event, item) => {
-                     this.openContextMenu(event, {
-                         uuid: item.uuid,
-                         name: item.name,
-                         description: item.description,
-                         kind: ContextMenuKind.COLLECTION
-                     });
-                 }}
-                 {...props} />
-             renderProjectPanel = (props: RouteComponentProps<{ id: string }>) => <ProjectPanel
-                 onItemRouteChange={itemId => this.props.dispatch(setProjectItem(itemId, ItemMode.ACTIVE))}
-                 onContextMenu={(event, item) => {
-                     let kind: ContextMenuKind;
-                     if (item.kind === ResourceKind.PROJECT) {
-                         kind = ContextMenuKind.PROJECT;
-                     } else if (item.kind === ResourceKind.COLLECTION) {
-                         kind = ContextMenuKind.COLLECTION_RESOURCE;
-                     } else {
-                         kind = ContextMenuKind.RESOURCE;
-                     }
-                     this.openContextMenu(event, {
-                         uuid: item.uuid,
-                         name: item.name,
-                         description: item.description,
-                         kind
-                     });
-                 }}
-                 onProjectCreationDialogOpen={this.handleProjectCreationDialogOpen}
-                 onCollectionCreationDialogOpen={this.handleCollectionCreationDialogOpen}
-                 onItemClick={item => {
-                     this.props.dispatch(loadDetails(item.uuid, item.kind as ResourceKind));
-                 }}
-                 onItemDoubleClick={item => {
-                     switch (item.kind) {
-                         case ResourceKind.COLLECTION:
-                             this.props.dispatch(loadCollection(item.uuid));
-                             this.props.dispatch(push(getCollectionUrl(item.uuid)));
-                         default:
-                             this.props.dispatch(setProjectItem(item.uuid, ItemMode.ACTIVE));
-                             this.props.dispatch(loadDetails(item.uuid, item.kind as ResourceKind));
-                     }
-                 }}
-                 {...props} />
-             renderFavoritePanel = (props: RouteComponentProps<{ id: string }>) => <FavoritePanel
-                 onItemRouteChange={() => this.props.dispatch(favoritePanelActions.REQUEST_ITEMS())}
-                 onContextMenu={(event, item) => {
-                     const kind = item.kind === ResourceKind.PROJECT ? ContextMenuKind.PROJECT : ContextMenuKind.RESOURCE;
-                     this.openContextMenu(event, {
-                         uuid: item.uuid,
-                         name: item.name,
-                         kind,
-                     });
-                 }}
-                 onDialogOpen={this.handleProjectCreationDialogOpen}
-                 onItemClick={item => {
-                     this.props.dispatch(loadDetails(item.uuid, item.kind as ResourceKind));
-                 }}
-                 onItemDoubleClick={item => {
-                     switch (item.kind) {
-                         case ResourceKind.COLLECTION:
-                             this.props.dispatch(loadCollection(item.uuid));
-                             this.props.dispatch(push(getCollectionUrl(item.uuid)));
-                         default:
-                             this.props.dispatch(loadDetails(item.uuid, ResourceKind.PROJECT));
-                             this.props.dispatch(setProjectItem(item.uuid, ItemMode.ACTIVE));
-                     }
-                 }}
-                 {...props} />
              mainAppBarActions: MainAppBarActionProps = {
-                 onBreadcrumbClick: ({ itemId }: NavBreadcrumb) => {
-                     this.props.dispatch(setProjectItem(itemId, ItemMode.BOTH));
-                     this.props.dispatch(loadDetails(itemId, ResourceKind.PROJECT));
-                 },
                  onSearch: searchText => {
                      this.setState({ searchText });
                      this.props.dispatch(push(`/search?q=${searchText}`));
                  onDetailsPanelToggle: () => {
                      this.props.dispatch(detailsPanelActions.TOGGLE_DETAILS_PANEL());
                  },
-                 onContextMenu: (event: React.MouseEvent<HTMLElement>, breadcrumb: NavBreadcrumb) => {
-                     this.openContextMenu(event, {
-                         uuid: breadcrumb.itemId,
-                         name: breadcrumb.label,
-                         kind: ContextMenuKind.PROJECT
-                     });
-                 }
              };
  
-             toggleSidePanelOpen = (itemId: string) => {
-                 this.props.dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_OPEN(itemId));
-             }
-             toggleSidePanelActive = (itemId: string) => {
-                 this.props.dispatch(projectActions.RESET_PROJECT_TREE_ACTIVITY(itemId));
-                 const panelItem = this.props.sidePanelItems.find(it => it.id === itemId);
-                 if (panelItem && panelItem.activeAction) {
-                     panelItem.activeAction(this.props.dispatch, this.props.authService.getUuid());
-                 }
-             }
-             handleProjectCreationDialogOpen = (itemUuid: string) => {
-                 this.props.dispatch(reset(PROJECT_CREATE_FORM_NAME));
-                 this.props.dispatch<any>(openProjectCreateDialog(itemUuid));
-             }
-             handleCollectionCreationDialogOpen = (itemUuid: string) => {
-                 this.props.dispatch(reset(COLLECTION_CREATE_FORM_NAME));
-                 this.props.dispatch<any>(openCollectionCreateDialog(itemUuid));
-             }
-             openContextMenu = (event: React.MouseEvent<HTMLElement>, resource: { name: string; uuid: string; description?: string; kind: ContextMenuKind; }) => {
-                 event.preventDefault();
-                 this.props.dispatch(
-                     contextMenuActions.OPEN_CONTEXT_MENU({
-                         position: { x: event.clientX, y: event.clientY },
-                         resource
-                     })
-                 );
-             }
              toggleCurrentTokenModal = () => {
                  this.setState({ isCurrentTokenDialogOpen: !this.state.isCurrentTokenDialogOpen });
              }