[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