X-Git-Url: https://git.arvados.org/arvados-workbench2.git/blobdiff_plain/8fb1b7d964d128c28ddf0208e1a488f46136d501..fa03027f1954dfdd98c3d3d4f74ea3a016cf57c0:/src/views-components/side-panel-button/side-panel-button.tsx

diff --git a/src/views-components/side-panel-button/side-panel-button.tsx b/src/views-components/side-panel-button/side-panel-button.tsx
index e39b3782..151cfb68 100644
--- a/src/views-components/side-panel-button/side-panel-button.tsx
+++ b/src/views-components/side-panel-button/side-panel-button.tsx
@@ -5,15 +5,22 @@
 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';
+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 { 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';
 
@@ -33,8 +40,10 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
 });
 
 interface SidePanelDataProps {
+    location: Location;
     currentItemId: string;
-    buttonVisible: boolean;
+    resources: ResourcesState;
+    currentUserUUID: string | undefined;
 }
 
 interface SidePanelState {
@@ -45,19 +54,25 @@ type SidePanelProps = SidePanelDataProps & DispatchProp & WithStyles<CssRules>;
 
 const transformOrigin: PopoverOrigin = {
     vertical: -50,
-    horizontal: 45
+    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> {
 
@@ -66,12 +81,49 @@ export const SidePanelButton = withStyles(styles)(
             };
 
             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)) {
+                        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 process
+                    </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 item xs alignItems="center" justify="center">
-                            <Button variant="contained" color="primary" size="small" className={classes.button}
+                    <Grid container>
+                        <Grid container item xs alignItems="center" justify="flex-start">
+                            <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}>
@@ -85,18 +137,10 @@ export const SidePanelButton = withStyles(styles)(
                                 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}>
-                                    <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>;
             }
 
@@ -104,6 +148,15 @@ export const SidePanelButton = withStyles(styles)(
                 this.props.dispatch<any>(openProjectCreateDialog(this.props.currentItemId));
             }
 
+            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);
+            }
+
             handleNewCollectionClick = () => {
                 this.props.dispatch<any>(openCollectionCreateDialog(this.props.currentItemId));
             }
@@ -117,4 +170,4 @@ export const SidePanelButton = withStyles(styles)(
             }
         }
     )
-);
\ No newline at end of file
+);
