//
// SPDX-License-Identifier: AGPL-3.0
-import * as React from 'react';
+import 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 { RootState } from 'store/store';
+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';
-import { matchProjectRoute } from '~/routes/routes';
-import { navigateToRunProcess } from '~/store/navigation/navigation-action';
-import { runProcessPanelActions } from '~/store/run-process-panel/run-process-panel-actions';
+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';
+import { navigateToRunProcess } from 'store/navigation/navigation-action';
+import { runProcessPanelActions } from 'store/run-process-panel/run-process-panel-actions';
+import { getUserUuid } from 'common/getuser';
+import { matchProjectRoute } from 'routes/routes';
+import { GroupClass, GroupResource } from 'models/group';
+import { ResourcesState, getResource } from 'store/resources/resources';
+import { extractUuidKind, ResourceKind } from 'models/resource';
+import { pluginConfig } from 'plugins';
+import { ElementListReducer } from 'common/plugintypes';
+import { Location } from 'history';
type CssRules = 'button' | 'menuItem' | 'icon';
});
interface SidePanelDataProps {
+ location: Location;
currentItemId: string;
- buttonVisible: boolean;
+ resources: ResourcesState;
+ currentUserUUID: string | undefined;
}
interface SidePanelState {
horizontal: 0
};
-const isButtonVisible = ({ router }: RootState) => {
- const pathname = router.location ? router.location.pathname : '';
- const match = matchProjectRoute(pathname);
- return !!match;
+export const isProjectTrashed = (proj: GroupResource | undefined, resources: ResourcesState): boolean => {
+ if (proj === undefined) { return false; }
+ if (proj.isTrashed) { return true; }
+ if (extractUuidKind(proj.ownerUuid) === ResourceKind.USER) { return false; }
+ const parentProj = getResource<GroupResource>(proj.ownerUuid)(resources);
+ return isProjectTrashed(parentProj, resources);
};
export const SidePanelButton = withStyles(styles)(
connect((state: RootState) => ({
- currentItemId: getProperty(PROJECT_PANEL_CURRENT_UUID)(state.properties),
- buttonVisible: isButtonVisible(state)
+ currentItemId: state.router.location
+ ? state.router.location.pathname.split('/').slice(-1)[0]
+ : null,
+ location: state.router.location,
+ resources: state.resources,
+ currentUserUUID: getUserUuid(state),
}))(
class extends React.Component<SidePanelProps> {
};
render() {
- const { classes, buttonVisible } = this.props;
+ const { classes, location, resources, currentUserUUID, currentItemId } = this.props;
const { anchorEl } = this.state;
+ let enabled = false;
+ if (currentItemId === currentUserUUID) {
+ enabled = true;
+ } else if (matchProjectRoute(location ? location.pathname : '')) {
+ const currentProject = getResource<GroupResource>(currentItemId)(resources);
+ if (currentProject &&
+ currentProject.writableBy.indexOf(currentUserUUID || '') >= 0 &&
+ !isProjectTrashed(currentProject, resources) &&
+ currentProject.groupClass !== GroupClass.FILTER) {
+ enabled = true;
+ }
+ }
+
+ for (const enableFn of pluginConfig.enableNewButtonMatchers) {
+ if (enableFn(location, currentItemId, currentUserUUID, resources)) {
+ enabled = true;
+ }
+ }
+
+ let menuItems = <>
+ <MenuItem data-cy='side-panel-new-collection' className={classes.menuItem} onClick={this.handleNewCollectionClick}>
+ <CollectionIcon className={classes.icon} /> New collection
+ </MenuItem>
+ <MenuItem data-cy='side-panel-run-process' className={classes.menuItem} onClick={this.handleRunProcessClick}>
+ <ProcessIcon className={classes.icon} /> Run a workflow
+ </MenuItem>
+ <MenuItem data-cy='side-panel-new-project' className={classes.menuItem} onClick={this.handleNewProjectClick}>
+ <ProjectIcon className={classes.icon} /> New project
+ </MenuItem>
+ </>;
+
+ const reduceItemsFn: (a: React.ReactElement[], b: ElementListReducer) => React.ReactElement[] =
+ (a, b) => b(a, classes.menuItem);
+
+ menuItems = React.createElement(React.Fragment, null,
+ pluginConfig.newButtonMenuList.reduce(reduceItemsFn, React.Children.toArray(menuItems.props.children)));
+
return <Toolbar>
- {buttonVisible && <Grid container>
+ <Grid container>
<Grid container item xs alignItems="center" justify="flex-start">
- <Button variant="contained" color="primary" size="small" className={classes.button}
+ <Button data-cy="side-panel-button" variant="contained" disabled={!enabled}
+ color="primary" size="small" className={classes.button}
aria-owns={anchorEl ? 'aside-menu-list' : undefined}
aria-haspopup="true"
onClick={this.handleOpen}>
onClose={this.handleClose}
onClick={this.handleClose}
transformOrigin={transformOrigin}>
- <MenuItem className={classes.menuItem} onClick={this.handleNewCollectionClick}>
- <CollectionIcon className={classes.icon} /> New collection
- </MenuItem>
- <MenuItem className={classes.menuItem} onClick={this.handleRunProcessClick}>
- <ProcessIcon className={classes.icon} /> Run a process
- </MenuItem>
- <MenuItem className={classes.menuItem} onClick={this.handleNewProjectClick}>
- <ProjectIcon className={classes.icon} /> New project
- </MenuItem>
+ {menuItems}
</Menu>
</Grid>
- </Grid>}
+ </Grid>
</Toolbar>;
}
}
handleRunProcessClick = () => {
+ const location = this.props.location;
+ this.props.dispatch(runProcessPanelActions.RESET_RUN_PROCESS_PANEL());
+ this.props.dispatch(runProcessPanelActions.SET_PROCESS_PATHNAME(location.pathname));
this.props.dispatch(runProcessPanelActions.SET_PROCESS_OWNER_UUID(this.props.currentItemId));
+
this.props.dispatch<any>(navigateToRunProcess);
}
}
}
)
-);
\ No newline at end of file
+);