[ARVADOS-WORKBENCH2] updated: 2.1.0-218-gddaff5cb
Git user
git at public.arvados.org
Sat Feb 27 22:05:44 UTC 2021
Summary of changes:
src/common/plugintypes.ts | 14 ++++-
src/plugins.tsx | 3 +
src/plugins/blank/index.tsx | 3 +
src/plugins/example/index.tsx | 40 +++++++++++--
src/views-components/main-app-bar/account-menu.tsx | 65 +++++++++++++---------
src/views-components/main-app-bar/main-app-bar.tsx | 21 ++++---
.../side-panel-button/side-panel-button.tsx | 42 ++++++++++----
src/views/workbench/workbench.tsx | 4 +-
8 files changed, 137 insertions(+), 55 deletions(-)
via ddaff5cb9937340eed1c8f3b59053146dcefa3b8 (commit)
from 9cc4f706feecd621f9d0121942bb0faa881ec926 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit ddaff5cb9937340eed1c8f3b59053146dcefa3b8
Author: Peter Amstutz <peter.amstutz at curii.com>
Date: Sat Feb 27 17:05:15 2021 -0500
17426: Add plugin ability to modify +New and account menu
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>
diff --git a/src/common/plugintypes.ts b/src/common/plugintypes.ts
index dfbe7c45..bda92b67 100644
--- a/src/common/plugintypes.ts
+++ b/src/common/plugintypes.ts
@@ -5,15 +5,18 @@
import * as React from 'react';
import { Dispatch } from 'redux';
import { RootStore, RootState } from '~/store/store';
+import { ResourcesState } from '~/store/resources/resources';
+import { Location } from 'history';
-export type RouteListReducer = (startingList: React.ReactElement[]) => React.ReactElement[];
+export type ElementListReducer = (startingList: React.ReactElement[]) => React.ReactElement[];
export type CategoriesListReducer = (startingList: string[]) => string[];
export type NavigateMatcher = (dispatch: Dispatch, getState: () => RootState, uuid: string) => boolean;
export type LocationChangeMatcher = (store: RootStore, pathname: string) => boolean;
+export type EnableNew = (location: Location, currentItemId: string, currentUserUUID: string | undefined, resources: ResourcesState) => boolean;
export interface PluginConfig {
// Customize the list of possible center panels by adding or removing Route components.
- centerPanelList: RouteListReducer[];
+ centerPanelList: ElementListReducer[];
// Customize the list of side panel categories
sidePanelCategories: CategoriesListReducer[];
@@ -32,4 +35,11 @@ export interface PluginConfig {
appBarMiddle?: React.ReactElement;
appBarRight?: React.ReactElement;
+
+ // Customize the list menu items in the account menu
+ accountMenuList: ElementListReducer[];
+
+ enableNewButtonMatchers: EnableNew[];
+
+ newButtonMenuList: ElementListReducer[];
}
diff --git a/src/plugins.tsx b/src/plugins.tsx
index 83593f23..3a58a8c2 100644
--- a/src/plugins.tsx
+++ b/src/plugins.tsx
@@ -13,6 +13,9 @@ export const pluginConfig: PluginConfig = {
appBarLeft: undefined,
appBarMiddle: undefined,
appBarRight: undefined,
+ accountMenuList: [],
+ enableNewButtonMatchers: [],
+ newButtonMenuList: []
};
// Starting here, import and register your Workbench 2 plugins. //
diff --git a/src/plugins/blank/index.tsx b/src/plugins/blank/index.tsx
index 9471372d..0074c02a 100644
--- a/src/plugins/blank/index.tsx
+++ b/src/plugins/blank/index.tsx
@@ -13,6 +13,9 @@ export const register = (pluginConfig: PluginConfig) => {
pluginConfig.sidePanelCategories.push((cats: string[]): string[] => []);
+ pluginConfig.accountMenuList.push((elms) => []);
+ pluginConfig.newButtonMenuList.push((elms) => []);
+
pluginConfig.appBarLeft = <span />;
pluginConfig.appBarMiddle = <span />;
pluginConfig.appBarRight = <span />;
diff --git a/src/plugins/example/index.tsx b/src/plugins/example/index.tsx
index 4fa98966..b8bfcb0f 100644
--- a/src/plugins/example/index.tsx
+++ b/src/plugins/example/index.tsx
@@ -14,16 +14,36 @@ import { Route, matchPath } from "react-router";
import { RootStore } from '~/store/store';
import { activateSidePanelTreeItem } from '~/store/side-panel-tree/side-panel-tree-actions';
import { setSidePanelBreadcrumbs } from '~/store/breadcrumbs/breadcrumbs-actions';
+import { DispatchProp, connect } from 'react-redux';
+import { MenuItem } from "@material-ui/core";
+import { propertiesActions } from '~/store/properties/properties-actions';
+import { Location } from 'history';
const categoryName = "Plugin Example";
export const routePath = "/examplePlugin";
+const propertyKey = "Example_menu_item_pressed_count";
-const ExamplePluginMainPanel = (props: {}) => {
- return <Typography>
- This is a example main panel plugin.
- </Typography>;
+interface ExampleProps {
+ pressedCount: number;
+}
+
+const exampleMapStateToProps = (state: RootState) => ({ pressedCount: state.properties[propertyKey] || 0 });
+
+const incrementPressedCount = (dispatch: Dispatch, pressedCount: number) => {
+ dispatch(propertiesActions.SET_PROPERTY({ key: propertyKey, value: pressedCount + 1 }));
};
+const ExampleMenuComponent = connect(exampleMapStateToProps)(
+ ({ pressedCount, dispatch }: ExampleProps & DispatchProp<any>) =>
+ <MenuItem onClick={() => incrementPressedCount(dispatch, pressedCount)}>Example menu item</MenuItem >
+);
+
+const ExamplePluginMainPanel = connect(exampleMapStateToProps)(
+ ({ pressedCount }: ExampleProps) =>
+ <Typography>
+ This is a example main panel plugin. The example menu item has been pressed {pressedCount} times.
+ </Typography>);
+
export const register = (pluginConfig: PluginConfig) => {
pluginConfig.centerPanelList.push((elms) => {
@@ -31,6 +51,16 @@ export const register = (pluginConfig: PluginConfig) => {
return elms;
});
+ pluginConfig.accountMenuList.push((elms) => {
+ elms.push(<ExampleMenuComponent />);
+ return elms;
+ });
+
+ pluginConfig.newButtonMenuList.push((elms) => {
+ elms.push(<ExampleMenuComponent />);
+ return elms;
+ });
+
pluginConfig.navigateToHandlers.push((dispatch: Dispatch, getState: () => RootState, uuid: string) => {
if (uuid === categoryName) {
dispatch(push(routePath));
@@ -49,4 +79,6 @@ export const register = (pluginConfig: PluginConfig) => {
}
return false;
});
+
+ pluginConfig.enableNewButtonMatchers.push((location: Location) => (!!matchPath(location.pathname, { path: routePath, exact: true })));
};
diff --git a/src/views-components/main-app-bar/account-menu.tsx b/src/views-components/main-app-bar/account-menu.tsx
index 6e844cc8..2d262b3f 100644
--- a/src/views-components/main-app-bar/account-menu.tsx
+++ b/src/views-components/main-app-bar/account-menu.tsx
@@ -20,6 +20,8 @@ import {
navigateToLinkAccount
} from '~/store/navigation/navigation-action';
import { openUserVirtualMachines } from "~/store/virtual-machines/virtual-machines-actions";
+import { pluginConfig } from '~/plugins';
+import { ElementListReducer } from '~/common/plugintypes';
interface AccountMenuProps {
user?: User;
@@ -57,35 +59,44 @@ const styles: StyleRulesCallback<CssRules> = () => ({
});
export const AccountMenuComponent =
- ({ user, dispatch, currentRoute, workbenchURL, apiToken, localCluster, classes }: AccountMenuProps & DispatchProp<any> & WithStyles<CssRules>) =>
- user
- ? <DropdownMenu
- icon={<UserPanelIcon />}
- id="account-menu"
- title="Account Management"
- key={currentRoute}>
- <MenuItem disabled>
- {getUserDisplayName(user)} {user.uuid.substr(0, 5) !== localCluster && `(${user.uuid.substr(0, 5)})`}
- </MenuItem>
- {user.isActive ? <>
- <MenuItem onClick={() => dispatch(openUserVirtualMachines())}>Virtual Machines</MenuItem>
- {!user.isAdmin && <MenuItem onClick={() => dispatch(openRepositoriesPanel())}>Repositories</MenuItem>}
- <MenuItem onClick={() => dispatch(openCurrentTokenDialog)}>Current token</MenuItem>
- <MenuItem onClick={() => dispatch(navigateToSshKeysUser)}>Ssh Keys</MenuItem>
- <MenuItem onClick={() => dispatch(navigateToSiteManager)}>Site Manager</MenuItem>
- <MenuItem onClick={() => dispatch(navigateToMyAccount)}>My account</MenuItem>
- <MenuItem onClick={() => dispatch(navigateToLinkAccount)}>Link account</MenuItem>
- </> : null}
+ ({ user, dispatch, currentRoute, workbenchURL, apiToken, localCluster, classes }: AccountMenuProps & DispatchProp<any> & WithStyles<CssRules>) => {
+ let accountMenuItems = <>
+ <MenuItem onClick={() => dispatch(openUserVirtualMachines())}>Virtual Machines</MenuItem>
+ <MenuItem onClick={() => dispatch(openRepositoriesPanel())}>Repositories</MenuItem>
+ <MenuItem onClick={() => dispatch(openCurrentTokenDialog)}>Current token</MenuItem>
+ <MenuItem onClick={() => dispatch(navigateToSshKeysUser)}>Ssh Keys</MenuItem>
+ <MenuItem onClick={() => dispatch(navigateToSiteManager)}>Site Manager</MenuItem>
+ <MenuItem onClick={() => dispatch(navigateToMyAccount)}>My account</MenuItem>
+ <MenuItem onClick={() => dispatch(navigateToLinkAccount)}>Link account</MenuItem>
<MenuItem>
<a href={`${workbenchURL.replace(/\/$/, "")}/${wb1URL(currentRoute)}?api_token=${apiToken}`}
className={classes.link}>
Switch to Workbench v1</a></MenuItem>
- <Divider />
- <MenuItem data-cy="logout-menuitem"
- onClick={() => dispatch(authActions.LOGOUT({deleteLinkData: true}))}>
- Logout
- </MenuItem>
- </DropdownMenu>
- : null;
+ </>;
-export const AccountMenu = withStyles(styles)( connect(mapStateToProps)(AccountMenuComponent) );
+ const reduceItemsFn: (a: React.ReactElement[],
+ b: ElementListReducer) => React.ReactElement[] = (a, b) => b(a);
+
+ accountMenuItems = React.createElement(React.Fragment, null,
+ pluginConfig.accountMenuList.reduce(reduceItemsFn, React.Children.toArray(accountMenuItems.props.children)));
+
+ return user
+ ? <DropdownMenu
+ icon={<UserPanelIcon />}
+ id="account-menu"
+ title="Account Management"
+ key={currentRoute}>
+ <MenuItem disabled>
+ {getUserDisplayName(user)} {user.uuid.substr(0, 5) !== localCluster && `(${user.uuid.substr(0, 5)})`}
+ </MenuItem>
+ {user.isActive && accountMenuItems}
+ <Divider />
+ <MenuItem data-cy="logout-menuitem"
+ onClick={() => dispatch(authActions.LOGOUT({ deleteLinkData: true }))}>
+ Logout
+ </MenuItem>
+ </DropdownMenu>
+ : null;
+ };
+
+export const AccountMenu = withStyles(styles)(connect(mapStateToProps)(AccountMenuComponent));
diff --git a/src/views-components/main-app-bar/main-app-bar.tsx b/src/views-components/main-app-bar/main-app-bar.tsx
index 7bec7b24..44cbe20d 100644
--- a/src/views-components/main-app-bar/main-app-bar.tsx
+++ b/src/views-components/main-app-bar/main-app-bar.tsx
@@ -47,7 +47,7 @@ export const MainAppBar = withStyles(styles)(
<Typography variant='h6' color="inherit" noWrap>
<Link to={Routes.ROOT} className={props.classes.link}>
<span dangerouslySetInnerHTML={{ __html: props.siteBanner }} /> ({props.uuidPrefix})
- </Link>
+ </Link>
</Typography>
<Typography variant="caption" color="inherit">{props.buildInfo}</Typography>
</Grid>}
@@ -65,14 +65,17 @@ export const MainAppBar = withStyles(styles)(
alignItems="center"
justify="flex-end"
wrap="nowrap">
- {pluginConfig.appBarRight ||
- (props.user ? <>
- <NotificationsMenu />
- <AccountMenu />
- {props.user.isAdmin && <AdminMenu />}
- <HelpMenu />
- </> :
- <HelpMenu />)}
+ {props.user ? <>
+ <NotificationsMenu />
+ <AccountMenu />
+ {pluginConfig.appBarRight ||
+ <>
+ {props.user.isAdmin && <AdminMenu />}
+ <HelpMenu />
+ </>}
+ </> :
+ pluginConfig.appBarRight || <HelpMenu />
+ }
</Grid>
</Grid>
</Toolbar>
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 3ca2f0d6..4c25bcfe 100644
--- a/src/views-components/side-panel-button/side-panel-button.tsx
+++ b/src/views-components/side-panel-button/side-panel-button.tsx
@@ -18,6 +18,9 @@ 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';
@@ -37,7 +40,7 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
});
interface SidePanelDataProps {
- location: any;
+ location: Location;
currentItemId: string;
resources: ResourcesState;
currentUserUUID: string | undefined;
@@ -91,6 +94,31 @@ export const SidePanelButton = withStyles(styles)(
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);
+
+ menuItems = React.createElement(React.Fragment, null,
+ pluginConfig.newButtonMenuList.reduce(reduceItemsFn, React.Children.toArray(menuItems.props.children)));
+
return <Toolbar>
<Grid container>
<Grid container item xs alignItems="center" justify="flex-start">
@@ -109,15 +137,7 @@ export const SidePanelButton = withStyles(styles)(
onClose={this.handleClose}
onClick={this.handleClose}
transformOrigin={transformOrigin}>
- <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>
+ {menuItems}
</Menu>
</Grid>
</Grid>
@@ -150,4 +170,4 @@ export const SidePanelButton = withStyles(styles)(
}
}
)
-);
\ No newline at end of file
+);
diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx
index f3872615..cd3eaf0b 100644
--- a/src/views/workbench/workbench.tsx
+++ b/src/views/workbench/workbench.tsx
@@ -102,7 +102,7 @@ import { AutoLogout } from '~/views-components/auto-logout/auto-logout';
import { RestoreCollectionVersionDialog } from '~/views-components/collections-dialog/restore-version-dialog';
import { WebDavS3InfoDialog } from '~/views-components/webdav-s3-dialog/webdav-s3-dialog';
import { pluginConfig } from '~/plugins';
-import { RouteListReducer } from '~/common/plugintypes';
+import { ElementListReducer } from '~/common/plugintypes';
type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content';
@@ -183,7 +183,7 @@ let routes = <>
</>;
const reduceRoutesFn: (a: React.ReactElement[],
- b: RouteListReducer) => React.ReactElement[] = (a, b) => b(a);
+ b: ElementListReducer) => React.ReactElement[] = (a, b) => b(a);
routes = React.createElement(React.Fragment, null, pluginConfig.centerPanelList.reduce(reduceRoutesFn, React.Children.toArray(routes.props.children)));
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list