[ARVADOS-WORKBENCH2] created: 1.3.0-102-g7d5095d
Git user
git at public.curoverse.com
Thu Dec 13 10:51:30 EST 2018
at 7d5095d5324b5d5ee91254f1cfa83f0ef88806cc (commit)
commit 7d5095d5324b5d5ee91254f1cfa83f0ef88806cc
Author: Pawel Kowalczyk <pawel.kowalczyk at contractors.roche.com>
Date: Thu Dec 13 16:51:14 2018 +0100
context-menu-for-group-member
Feature #14505
Arvados-DCO-1.1-Signed-off-by: Pawel Kowalczyk <pawel.kowalczyk at contractors.roche.com>
diff --git a/src/index.tsx b/src/index.tsx
index 13598da..f64e076 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -57,6 +57,7 @@ import { userActionSet } from '~/views-components/context-menu/action-sets/user-
import { computeNodeActionSet } from '~/views-components/context-menu/action-sets/compute-node-action-set';
import { apiClientAuthorizationActionSet } from '~/views-components/context-menu/action-sets/api-client-authorization-action-set';
import { groupActionSet } from '~/views-components/context-menu/action-sets/group-action-set';
+import { groupMemberActionSet } from '~/views-components/context-menu/action-sets/group-member-action-set';
console.log(`Starting arvados [${getBuildInfo()}]`);
@@ -81,6 +82,7 @@ addMenuActionSet(ContextMenuKind.USER, userActionSet);
addMenuActionSet(ContextMenuKind.NODE, computeNodeActionSet);
addMenuActionSet(ContextMenuKind.API_CLIENT_AUTHORIZATION, apiClientAuthorizationActionSet);
addMenuActionSet(ContextMenuKind.GROUPS, groupActionSet);
+addMenuActionSet(ContextMenuKind.GROUP_MEMBER, groupMemberActionSet);
fetchConfig()
.then(({ config, apiHost }) => {
diff --git a/src/store/groups-panel/groups-panel-actions.ts b/src/store/groups-panel/groups-panel-actions.ts
index 1af7a2e..2787fc3 100644
--- a/src/store/groups-panel/groups-panel-actions.ts
+++ b/src/store/groups-panel/groups-panel-actions.ts
@@ -13,7 +13,7 @@ import { getResource } from '~/store/resources/resources';
import { GroupResource } from '~/models/group';
import { getCommonResourceServiceError, CommonResourceServiceError } from '~/services/common-service/common-resource-service';
import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
-import { PermissionLevel } from '~/models/permission';
+import { PermissionLevel, PermissionResource } from '~/models/permission';
import { PermissionService } from '~/services/permission-service/permission-service';
export const GROUPS_PANEL_ID = "groupsPanel";
@@ -23,6 +23,8 @@ export const CREATE_GROUP_NAME_FIELD_NAME = 'name';
export const CREATE_GROUP_USERS_FIELD_NAME = 'users';
export const GROUP_ATTRIBUTES_DIALOG = 'groupAttributesDialog';
export const GROUP_REMOVE_DIALOG = 'groupRemoveDialog';
+export const MEMBER_ATTRIBUTES_DIALOG = 'memberAttributesDialog';
+export const MEMBER_REMOVE_DIALOG = 'memberRemoveDialog';
export const GroupsPanelActions = bindDataExplorerActions(GROUPS_PANEL_ID);
@@ -41,6 +43,13 @@ export const openGroupAttributes = (uuid: string) =>
dispatch(dialogActions.OPEN_DIALOG({ id: GROUP_ATTRIBUTES_DIALOG, data }));
};
+export const openGroupMemberAttributes = (uuid: string) =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const { resources } = getState();
+ const data = getResource<PermissionResource>(uuid)(resources);
+ dispatch(dialogActions.OPEN_DIALOG({ id: MEMBER_ATTRIBUTES_DIALOG, data }));
+ };
+
export const removeGroup = (uuid: string) =>
async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...' }));
@@ -62,6 +71,27 @@ export const openRemoveGroupDialog = (uuid: string) =>
}));
};
+export const removeGroupMember = (uuid: string) =>
+ async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...' }));
+ await services.permissionService.delete(uuid);
+ dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removed.', hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
+ dispatch<any>(loadGroupsPanel());
+ };
+
+export const openRemoveGroupMemberDialog = (uuid: string) =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ dispatch(dialogActions.OPEN_DIALOG({
+ id: MEMBER_REMOVE_DIALOG,
+ data: {
+ title: 'Remove member',
+ text: 'Are you sure you want to remove this member from this group?',
+ confirmButtonLabel: 'Remove',
+ uuid
+ }
+ }));
+ };
+
export interface CreateGroupFormData {
[CREATE_GROUP_NAME_FIELD_NAME]: string;
[CREATE_GROUP_USERS_FIELD_NAME]?: Person[];
diff --git a/src/views-components/context-menu/action-sets/group-member-action-set.ts b/src/views-components/context-menu/action-sets/group-member-action-set.ts
new file mode 100644
index 0000000..73a9a77
--- /dev/null
+++ b/src/views-components/context-menu/action-sets/group-member-action-set.ts
@@ -0,0 +1,28 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { ContextMenuActionSet } from "~/views-components/context-menu/context-menu-action-set";
+import { AdvancedIcon, RemoveIcon, AttributesIcon } from "~/components/icon/icon";
+import { openAdvancedTabDialog } from "~/store/advanced-tab/advanced-tab";
+import { openGroupMemberAttributes, openRemoveGroupMemberDialog } from "~/store/groups-panel/groups-panel-actions";
+
+export const groupMemberActionSet: ContextMenuActionSet = [[{
+ name: "Attributes",
+ icon: AttributesIcon,
+ execute: (dispatch, { uuid }) => {
+ dispatch<any>(openGroupMemberAttributes(uuid));
+ }
+}, {
+ name: "Advanced",
+ icon: AdvancedIcon,
+ execute: (dispatch, resource) => {
+ dispatch<any>(openAdvancedTabDialog(resource.uuid));
+ }
+}, {
+ name: "Remove",
+ icon: RemoveIcon,
+ execute: (dispatch, { uuid }) => {
+ dispatch<any>(openRemoveGroupMemberDialog(uuid));
+ }
+}]];
\ No newline at end of file
diff --git a/src/views-components/context-menu/context-menu.tsx b/src/views-components/context-menu/context-menu.tsx
index 99a595e..e148a78 100644
--- a/src/views-components/context-menu/context-menu.tsx
+++ b/src/views-components/context-menu/context-menu.tsx
@@ -76,5 +76,6 @@ export enum ContextMenuKind {
KEEP_SERVICE = "KeepService",
USER = "User",
NODE = "Node",
- GROUPS = "Group"
+ GROUPS = "Group",
+ GROUP_MEMBER = "GroupMember"
}
diff --git a/src/views-components/groups-dialog/member-attributes-dialog.tsx b/src/views-components/groups-dialog/member-attributes-dialog.tsx
new file mode 100644
index 0000000..6124cc3
--- /dev/null
+++ b/src/views-components/groups-dialog/member-attributes-dialog.tsx
@@ -0,0 +1,96 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from "react";
+import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Typography, Grid } from "@material-ui/core";
+import { WithDialogProps } from "~/store/dialog/with-dialog";
+import { withDialog } from '~/store/dialog/with-dialog';
+import { WithStyles, withStyles } from '@material-ui/core/styles';
+import { ArvadosTheme } from '~/common/custom-theme';
+import { compose } from "redux";
+import { PermissionResource } from "~/models/permission";
+import { MEMBER_ATTRIBUTES_DIALOG } from "~/store/groups-panel/groups-panel-actions";
+import { UserResource } from "~/models/user";
+
+type CssRules = 'rightContainer' | 'leftContainer' | 'spacing';
+
+const styles = withStyles<CssRules>((theme: ArvadosTheme) => ({
+ rightContainer: {
+ textAlign: 'right',
+ paddingRight: theme.spacing.unit * 2,
+ color: theme.palette.grey["500"]
+ },
+ leftContainer: {
+ textAlign: 'left',
+ paddingLeft: theme.spacing.unit * 2
+ },
+ spacing: {
+ paddingTop: theme.spacing.unit * 2
+ },
+}));
+
+interface GroupAttributesDataProps {
+ data: PermissionResource;
+}
+
+type GroupAttributesProps = GroupAttributesDataProps & WithStyles<CssRules>;
+
+export const GroupMemberAttributesDialog = compose(
+ withDialog(MEMBER_ATTRIBUTES_DIALOG),
+ styles)(
+ (props: WithDialogProps<GroupAttributesProps> & GroupAttributesProps) =>
+ <Dialog open={props.open}
+ onClose={props.closeDialog}
+ fullWidth
+ maxWidth="sm">
+ <DialogTitle>Attributes</DialogTitle>
+ <DialogContent>
+ <Typography variant="body2" className={props.classes.spacing}>
+ {props.data && attributes(props.data, props.classes)}
+ </Typography>
+ </DialogContent>
+ <DialogActions>
+ <Button
+ variant='flat'
+ color='primary'
+ onClick={props.closeDialog}>
+ Close
+ </Button>
+ </DialogActions>
+ </Dialog>
+ );
+
+const attributes = (memberGroup: PermissionResource, classes: any) => {
+ const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, name, etag, href, linkClass } = memberGroup;
+ return (
+ <span>
+ <Grid container direction="row">
+ <Grid item xs={5} className={classes.rightContainer}>
+ {name && <Grid item>Name</Grid>}
+ {ownerUuid && <Grid item>Owner uuid</Grid>}
+ {createdAt && <Grid item>Created at</Grid>}
+ {modifiedAt && <Grid item>Modified at</Grid>}
+ {modifiedByUserUuid && <Grid item>Modified by user uuid</Grid>}
+ {modifiedByClientUuid && <Grid item>Modified by client uuid</Grid>}
+ {uuid && <Grid item>uuid</Grid>}
+ {linkClass && <Grid item>Link Class</Grid>}
+ {etag && <Grid item>Etag</Grid>}
+ {href && <Grid item>Href</Grid>}
+ </Grid>
+ <Grid item xs={7} className={classes.leftContainer}>
+ <Grid item>{name}</Grid>
+ <Grid item>{ownerUuid}</Grid>
+ <Grid item>{createdAt}</Grid>
+ <Grid item>{modifiedAt}</Grid>
+ <Grid item>{modifiedByUserUuid}</Grid>
+ <Grid item>{modifiedByClientUuid}</Grid>
+ <Grid item>{uuid}</Grid>
+ <Grid item>{linkClass}</Grid>
+ <Grid item>{etag}</Grid>
+ <Grid item>{href}</Grid>
+ </Grid>
+ </Grid>
+ </span>
+ );
+};
diff --git a/src/views-components/groups-dialog/member-remove-dialog.ts b/src/views-components/groups-dialog/member-remove-dialog.ts
new file mode 100644
index 0000000..04d144f
--- /dev/null
+++ b/src/views-components/groups-dialog/member-remove-dialog.ts
@@ -0,0 +1,21 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { Dispatch, compose } from 'redux';
+import { connect } from "react-redux";
+import { ConfirmationDialog } from "~/components/confirmation-dialog/confirmation-dialog";
+import { withDialog, WithDialogProps } from "~/store/dialog/with-dialog";
+import { removeGroupMember, MEMBER_REMOVE_DIALOG } from '~/store/groups-panel/groups-panel-actions';
+
+const mapDispatchToProps = (dispatch: Dispatch, props: WithDialogProps<any>) => ({
+ onConfirm: () => {
+ props.closeDialog();
+ dispatch<any>(removeGroupMember(props.data.uuid));
+ }
+});
+
+export const RemoveGroupMemberDialog = compose(
+ withDialog(MEMBER_REMOVE_DIALOG),
+ connect(null, mapDispatchToProps)
+)(ConfirmationDialog);
\ No newline at end of file
diff --git a/src/views/group-details-panel/group-details-panel.tsx b/src/views/group-details-panel/group-details-panel.tsx
index fb4825d..940f9d0 100644
--- a/src/views/group-details-panel/group-details-panel.tsx
+++ b/src/views/group-details-panel/group-details-panel.tsx
@@ -12,6 +12,10 @@ import { createTree } from '~/models/tree';
import { noop } from 'lodash/fp';
import { RootState } from '~/store/store';
import { GROUP_DETAILS_PANEL_ID } from '~/store/group-details-panel/group-details-panel-actions';
+import { openContextMenu } from '~/store/context-menu/context-menu-actions';
+import { ResourcesState, getResource } from '~/store/resources/resources';
+import { ContextMenuKind } from '~/views-components/context-menu/context-menu';
+import { PermissionResource } from '~/models/permission';
export enum GroupDetailsPanelColumnNames {
FIRST_NAME = "First name",
@@ -65,9 +69,14 @@ const mapStateToProps = (state: RootState) => {
};
};
-const mapDispatchToProps = {};
+const mapDispatchToProps = {
+ onContextMenu: openContextMenu,
+};
-export interface GroupDetailsPanelProps { }
+export interface GroupDetailsPanelProps {
+ onContextMenu: (event: React.MouseEvent<HTMLElement>, item: any) => void;
+ resources: ResourcesState;
+}
export const GroupDetailsPanel = connect(
mapStateToProps, mapDispatchToProps
@@ -80,10 +89,23 @@ export const GroupDetailsPanel = connect(
id={GROUP_DETAILS_PANEL_ID}
onRowClick={noop}
onRowDoubleClick={noop}
- onContextMenu={noop}
+ onContextMenu={this.handleContextMenu}
contextMenuColumn={true}
hideColumnSelector />
);
}
+
+ handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
+ const resource = getResource<PermissionResource>(resourceUuid)(this.props.resources);
+ if (resource) {
+ this.props.onContextMenu(event, {
+ name: '',
+ uuid: resource.uuid,
+ ownerUuid: resource.ownerUuid,
+ kind: resource.kind,
+ menuKind: ContextMenuKind.GROUP_MEMBER
+ });
+ }
+ }
});
diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx
index 9c8726a..76c7d25 100644
--- a/src/views/workbench/workbench.tsx
+++ b/src/views/workbench/workbench.tsx
@@ -80,6 +80,8 @@ import { CreateGroupDialog } from '~/views-components/dialog-forms/create-group-
import { RemoveGroupDialog } from '~/views-components/groups-dialog/remove-dialog';
import { GroupAttributesDialog } from '~/views-components/groups-dialog/attributes-dialog';
import { GroupDetailsPanel } from '~/views/group-details-panel/group-details-panel';
+import { RemoveGroupMemberDialog } from '~/views-components/groups-dialog/member-remove-dialog';
+import { GroupMemberAttributesDialog } from '~/views-components/groups-dialog/member-attributes-dialog';
type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content';
@@ -186,6 +188,7 @@ export const WorkbenchPanel =
<FileRemoveDialog />
<FilesUploadCollectionDialog />
<GroupAttributesDialog />
+ <GroupMemberAttributesDialog />
<HelpApiClientAuthorizationDialog />
<MoveCollectionDialog />
<MoveProcessDialog />
@@ -199,6 +202,7 @@ export const WorkbenchPanel =
<RemoveApiClientAuthorizationDialog />
<RemoveComputeNodeDialog />
<RemoveGroupDialog />
+ <RemoveGroupMemberDialog />
<RemoveKeepServiceDialog />
<RemoveProcessDialog />
<RemoveRepositoryDialog />
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list