import * as React from 'react';
import AccessTime from '@material-ui/icons/AccessTime';
+import Add from '@material-ui/icons/Add';
import ArrowBack from '@material-ui/icons/ArrowBack';
import ArrowDropDown from '@material-ui/icons/ArrowDropDown';
import BubbleChart from '@material-ui/icons/BubbleChart';
export type IconType = React.SFC<{ className?: string }>;
+export const AddIcon: IconType = (props) => <Add {...props} />;
export const AddFavoriteIcon: IconType = (props) => <StarBorder {...props} />;
export const AdvancedIcon: IconType = (props) => <SettingsApplications {...props} />;
export const BackIcon: IconType = (props) => <ArrowBack {...props} />;
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { connect, DispatchProp } from 'react-redux';
+import { RootState } from '~/store/store';
+import { getProperty } from '~/store/properties/properties';
+import { PROJECT_PANEL_CURRENT_UUID } from '~/store/project-panel/project-panel-action';
+import { ArvadosTheme } from '~/common/custom-theme';
+import { PopoverOrigin } from '@material-ui/core/Popover';
+import { StyleRulesCallback, WithStyles, withStyles, Toolbar, Grid, Button, MenuItem, Menu } from '@material-ui/core';
+import { AddIcon, CollectionIcon, ProcessIcon, ProjectIcon } from '~/components/icon/icon';
+import { openProjectCreateDialog } from '~/store/projects/project-create-actions';
+import { openCollectionCreateDialog } from '~/store/collections/collection-create-actions';
+
+type CssRules = 'button' | 'menuItem' | 'icon';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ button: {
+ boxShadow: 'none',
+ padding: '2px 10px 2px 5px',
+ fontSize: '0.75rem'
+ },
+ menuItem: {
+ fontSize: '0.875rem',
+ color: theme.palette.grey["700"]
+ },
+ icon: {
+ marginRight: theme.spacing.unit
+ }
+});
+
+interface SidePanelDataProps {
+ currentItemId: string;
+}
+
+interface SidePanelState {
+ anchorEl: any;
+}
+
+type SidePanelProps = SidePanelDataProps & DispatchProp & WithStyles<CssRules>;
+
+export const SidePanelButton = withStyles(styles)(
+ connect((state: RootState) => ({
+ currentItemId: getProperty(PROJECT_PANEL_CURRENT_UUID)(state.properties)
+ }))(
+ class extends React.Component<SidePanelProps> {
+
+ state: SidePanelState = {
+ anchorEl: undefined
+ };
+
+ transformOrigin: PopoverOrigin = {
+ vertical: -50,
+ horizontal: 25
+ };
+
+ render() {
+ const { classes } = this.props;
+ const { anchorEl } = this.state;
+ return <Toolbar>
+ <Grid container>
+ <Grid container item xs alignItems="center" justify="center">
+ <Button variant="contained" color="primary" size="small" className={classes.button}
+ aria-owns={anchorEl ? 'aside-menu-list' : undefined}
+ aria-haspopup="true"
+ onClick={this.handleOpen}>
+ <AddIcon />
+ New
+ </Button>
+ <Menu
+ id='aside-menu-list'
+ anchorEl={anchorEl}
+ open={Boolean(anchorEl)}
+ onClose={this.handleClose}
+ onClick={this.handleClose}
+ transformOrigin={this.transformOrigin}>
+ <MenuItem className={classes.menuItem} onClick={this.handleNewCollectionClick}>
+ <CollectionIcon className={classes.icon} /> New collection
+ </MenuItem>
+ <MenuItem className={classes.menuItem}>
+ <ProcessIcon className={classes.icon} /> Run a process
+ </MenuItem>
+ <MenuItem className={classes.menuItem} onClick={this.handleNewProjectClick}>
+ <ProjectIcon className={classes.icon} /> New project
+ </MenuItem>
+ </Menu>
+ </Grid>
+ </Grid>
+ </Toolbar>;
+ }
+
+ handleNewProjectClick = () => {
+ this.props.dispatch<any>(openProjectCreateDialog(this.props.currentItemId));
+ }
+
+ handleNewCollectionClick = () => {
+ this.props.dispatch<any>(openCollectionCreateDialog(this.props.currentItemId));
+ }
+
+ handleClose = () => {
+ this.setState({ anchorEl: undefined });
+ }
+
+ handleOpen = (event: React.MouseEvent<HTMLButtonElement>) => {
+ this.setState({ anchorEl: event.currentTarget });
+ }
+ }
+ )
+);
\ No newline at end of file
import * as React from 'react';
import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
-import Drawer from '@material-ui/core/Drawer';
import { ArvadosTheme } from '~/common/custom-theme';
import { SidePanelTree, SidePanelTreeProps } from '~/views-components/side-panel-tree/side-panel-tree';
import { compose, Dispatch } from 'redux';
import { connect } from 'react-redux';
import { navigateFromSidePanel } from '../../store/side-panel/side-panel-action';
+import { Grid } from '@material-ui/core';
+import { SidePanelButton } from '~/views-components/side-panel-button/side-panel-button';
const DRAWER_WITDH = 240;
withStyles(styles),
connect(undefined, mapDispatchToProps)
)(({ classes, ...props }: WithStyles<CssRules> & SidePanelTreeProps) =>
- <div className={classes.root}>
+ <Grid item xs>
+ <SidePanelButton />
<SidePanelTree {...props} />
- </div>);
+ </Grid>);
\ No newline at end of file
import { PanelDefaultView } from '~/components/panel-default-view/panel-default-view';
import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
-type CssRules = 'root' | "toolbar" | "button";
+type CssRules = 'root' | "button";
const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
root: {
width: '100%',
height: '100%'
},
- toolbar: {
- paddingBottom: theme.spacing.unit * 3,
- textAlign: "right"
- },
button: {
marginLeft: theme.spacing.unit
},
render() {
const { classes } = this.props;
return <div className={classes.root}>
- <div className={classes.toolbar}>
- <Button color="primary" onClick={this.handleNewCollectionClick} variant="raised" className={classes.button}>
- New collection
- </Button>
- <Button color="primary" variant="raised" className={classes.button}>
- Run a process
- </Button>
- <Button color="primary" onClick={this.handleNewProjectClick} variant="raised" className={classes.button}>
- New project
- </Button>
- </div>
{this.hasAnyItems()
? <DataExplorer
id={PROJECT_PANEL_ID}
return resource.ownerUuid === this.props.currentItemId;
}
- handleNewProjectClick = () => {
- this.props.dispatch<any>(openProjectCreateDialog(this.props.currentItemId));
- }
-
- handleNewCollectionClick = () => {
- this.props.dispatch<any>(openCollectionCreateDialog(this.props.currentItemId));
- }
-
handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
const menuKind = resourceKindToContextMenuKind(resourceUuid);
const resource = getResource<ProjectResource>(resourceUuid)(this.props.resources);
import { MainContentBar } from '../../views-components/main-content-bar/main-content-bar';
import { Grid } from '@material-ui/core';
-type CssRules = 'root' | 'contentWrapper' | 'content' | 'appBar';
+type CssRules = 'root' | 'asidePanel' | 'contentWrapper' | 'content' | 'appBar';
const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
root: {
width: '100vw',
height: '100vh'
},
+ asidePanel: {
+ maxWidth: '240px',
+ background: theme.palette.background.default
+ },
contentWrapper: {
background: theme.palette.background.default,
minWidth: 0,
state = {
searchText: "",
};
-
render() {
+ const { classes } = this.props;
return <>
- <Grid
- container
- direction="column"
- className={this.props.classes.root}>
- <Grid className={this.props.classes.appBar}>
+ <Grid container direction="column" className={classes.root}>
+ <Grid className={classes.appBar}>
<MainAppBar
searchText={this.state.searchText}
user={this.props.user}
buildInfo={this.props.buildInfo} />
</Grid>
{this.props.user &&
- <Grid
- container
- item
- xs
- alignItems="stretch"
- wrap="nowrap">
- <Grid item>
+ <Grid container item xs alignItems="stretch" wrap="nowrap">
+ <Grid container item xs component='aside' direction='column' className={classes.asidePanel}>
<SidePanel />
</Grid>
- <Grid
- container
- item
- xs
- component="main"
- direction="column"
- className={this.props.classes.contentWrapper}>
+ <Grid container item xs component="main" direction="column" className={classes.contentWrapper}>
<Grid item>
<MainContentBar />
</Grid>
- <Grid item xs className={this.props.classes.content}>
+ <Grid item xs className={classes.content}>
<Switch>
<Route path={Routes.PROJECTS} component={ProjectPanel} />
<Route path={Routes.COLLECTIONS} component={CollectionPanel} />