[ARVADOS-WORKBENCH2] created: 1.3.0-88-g4afdbe4

Git user git at public.curoverse.com
Tue Dec 11 05:18:25 EST 2018


        at  4afdbe4d6f060423725d77fa7500d76d8e7e5f04 (commit)


commit 4afdbe4d6f060423725d77fa7500d76d8e7e5f04
Author: Pawel Kowalczyk <pawel.kowalczyk at contractors.roche.com>
Date:   Tue Dec 11 11:18:01 2018 +0100

    context menu for groups panel
    
    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 8f702af..13598da 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -56,6 +56,7 @@ import { virtualMachineActionSet } from '~/views-components/context-menu/action-
 import { userActionSet } from '~/views-components/context-menu/action-sets/user-action-set';
 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';
 
 console.log(`Starting arvados [${getBuildInfo()}]`);
 
@@ -79,6 +80,7 @@ addMenuActionSet(ContextMenuKind.KEEP_SERVICE, keepServiceActionSet);
 addMenuActionSet(ContextMenuKind.USER, userActionSet);
 addMenuActionSet(ContextMenuKind.NODE, computeNodeActionSet);
 addMenuActionSet(ContextMenuKind.API_CLIENT_AUTHORIZATION, apiClientAuthorizationActionSet);
+addMenuActionSet(ContextMenuKind.GROUPS, groupActionSet);
 
 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 b5465d0..e46ebd1 100644
--- a/src/store/groups-panel/groups-panel-actions.ts
+++ b/src/store/groups-panel/groups-panel-actions.ts
@@ -7,12 +7,19 @@ import { reset } from 'redux-form';
 import { bindDataExplorerActions } from "~/store/data-explorer/data-explorer-action";
 import { dialogActions } from '~/store/dialog/dialog-actions';
 import { Person } from '~/views-components/sharing-dialog/people-select';
+import { RootState } from '~/store/store';
+import { ServiceRepository } from '~/services/services';
+import { getResource } from '~/store/resources/resources';
+import { GroupResource } from '~/models/group';
+import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
 
 export const GROUPS_PANEL_ID = "groupsPanel";
 export const CREATE_GROUP_DIALOG = "createGroupDialog";
 export const CREATE_GROUP_FORM = "createGroupForm";
 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 GroupsPanelActions = bindDataExplorerActions(GROUPS_PANEL_ID);
 
@@ -24,6 +31,34 @@ export const openCreateGroupDialog = () =>
         dispatch(reset(CREATE_GROUP_FORM));
     };
 
+export const openGroupAttributes = (uuid: string) =>
+    (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        const { resources } = getState();
+        const data = getResource<GroupResource>(uuid)(resources);
+        dispatch(dialogActions.OPEN_DIALOG({ id: GROUP_ATTRIBUTES_DIALOG, data }));
+    };
+
+export const removeGroup = (uuid: string) =>
+    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...' }));
+        await services.groupsService.delete(uuid);
+        dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removed.', hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
+        dispatch<any>(loadGroupsPanel());
+    };
+
+export const openRemoveGroupDialog = (uuid: string) =>
+    (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        dispatch(dialogActions.OPEN_DIALOG({
+            id: GROUP_REMOVE_DIALOG,
+            data: {
+                title: 'Remove group',
+                text: 'Are you sure you want to remove this group?',
+                confirmButtonLabel: 'Remove',
+                uuid
+            }
+        }));
+    };
+
 export interface CreateGroupFormData {
     [CREATE_GROUP_NAME_FIELD_NAME]: string;
     [CREATE_GROUP_USERS_FIELD_NAME]: Person[];
diff --git a/src/store/users/users-actions.ts b/src/store/users/users-actions.ts
index 64c3646..f431fc7 100644
--- a/src/store/users/users-actions.ts
+++ b/src/store/users/users-actions.ts
@@ -7,8 +7,7 @@ import { bindDataExplorerActions } from '~/store/data-explorer/data-explorer-act
 import { RootState } from '~/store/store';
 import { ServiceRepository } from "~/services/services";
 import { dialogActions } from '~/store/dialog/dialog-actions';
-import { startSubmit, reset, stopSubmit } from "redux-form";
-import { getCommonResourceServiceError, CommonResourceServiceError } from "~/services/common-service/common-resource-service";
+import { startSubmit, reset } from "redux-form";
 import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
 import { UserResource } from "~/models/user";
 import { getResource } from '~/store/resources/resources';
diff --git a/src/views-components/context-menu/action-sets/group-action-set.ts b/src/views-components/context-menu/action-sets/group-action-set.ts
new file mode 100644
index 0000000..8d718a3
--- /dev/null
+++ b/src/views-components/context-menu/action-sets/group-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 { openGroupAttributes, openRemoveGroupDialog } from "~/store/groups-panel/groups-panel-actions";
+
+export const groupActionSet: ContextMenuActionSet = [[{
+    name: "Attributes",
+    icon: AttributesIcon,
+    execute: (dispatch, { uuid }) => {
+        dispatch<any>(openGroupAttributes(uuid));
+    }
+}, {
+    name: "Advanced",
+    icon: AdvancedIcon,
+    execute: (dispatch, resource) => {
+        dispatch<any>(openAdvancedTabDialog(resource.uuid));
+    }
+}, {
+    name: "Remove",
+    icon: RemoveIcon,
+    execute: (dispatch, { uuid }) => {
+        dispatch<any>(openRemoveGroupDialog(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 95a4a83..99a595e 100644
--- a/src/views-components/context-menu/context-menu.tsx
+++ b/src/views-components/context-menu/context-menu.tsx
@@ -75,5 +75,6 @@ export enum ContextMenuKind {
     VIRTUAL_MACHINE = "VirtualMachine",
     KEEP_SERVICE = "KeepService",
     USER = "User",
-    NODE = "Node"
+    NODE = "Node",
+    GROUPS = "Group"
 }
diff --git a/src/views-components/groups-dialog/attributes-dialog.tsx b/src/views-components/groups-dialog/attributes-dialog.tsx
new file mode 100644
index 0000000..f6ab8c1
--- /dev/null
+++ b/src/views-components/groups-dialog/attributes-dialog.tsx
@@ -0,0 +1,101 @@
+// 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 { GroupResource } from "~/models/group";
+import { GROUP_ATTRIBUTES_DIALOG } from "~/store/groups-panel/groups-panel-actions";
+
+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: GroupResource;
+}
+
+type GroupAttributesProps = GroupAttributesDataProps & WithStyles<CssRules>;
+
+export const GroupAttributesDialog = compose(
+    withDialog(GROUP_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 = (group: GroupResource, classes: any) => {
+    const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, name, deleteAt, description, etag, href, isTrashed, trashAt} = group;
+    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>}
+                    {deleteAt && <Grid item>Delete at</Grid>}
+                    {description && <Grid item>Description</Grid>}
+                    {etag && <Grid item>Etag</Grid>}
+                    {href && <Grid item>Href</Grid>}
+                    {isTrashed && <Grid item>Is trashed</Grid>}
+                    {trashAt && <Grid item>Trashed at</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>{deleteAt}</Grid>
+                    <Grid item>{description}</Grid>
+                    <Grid item>{etag}</Grid>
+                    <Grid item>{href}</Grid>
+                    <Grid item>{isTrashed}</Grid>
+                    <Grid item>{trashAt}</Grid>
+                </Grid>
+            </Grid>
+        </span>
+    );
+};
diff --git a/src/views-components/groups-dialog/remove-dialog.ts b/src/views-components/groups-dialog/remove-dialog.ts
new file mode 100644
index 0000000..8220198
--- /dev/null
+++ b/src/views-components/groups-dialog/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 { removeGroup, GROUP_REMOVE_DIALOG } from '~/store/groups-panel/groups-panel-actions';
+
+const mapDispatchToProps = (dispatch: Dispatch, props: WithDialogProps<any>) => ({
+    onConfirm: () => {
+        props.closeDialog();
+        dispatch<any>(removeGroup(props.data.uuid));
+    }
+});
+
+export const RemoveGroupDialog = compose(
+    withDialog(GROUP_REMOVE_DIALOG),
+    connect(null, mapDispatchToProps)
+)(ConfirmationDialog);
\ No newline at end of file
diff --git a/src/views/groups-panel/groups-panel.tsx b/src/views/groups-panel/groups-panel.tsx
index 39028ec..f3f3701 100644
--- a/src/views/groups-panel/groups-panel.tsx
+++ b/src/views/groups-panel/groups-panel.tsx
@@ -15,6 +15,12 @@ import { ResourceName } from '~/views-components/data-explorer/renderers';
 import { createTree } from '~/models/tree';
 import { GROUPS_PANEL_ID, openCreateGroupDialog } from '~/store/groups-panel/groups-panel-actions';
 import { noop } from 'lodash/fp';
+import { ContextMenuKind } from '~/views-components/context-menu/context-menu';
+import { getResource, ResourcesState } from '~/store/resources/resources';
+import { GroupResource } from '~/models/group';
+import { RootState } from '~/store/store';
+import { Dispatch } from 'redux';
+import { openContextMenu } from '~/store/context-menu/context-menu-actions';
 
 export enum GroupsPanelColumnNames {
     GROUP = "Name",
@@ -47,15 +53,25 @@ export const groupsPanelColumns: DataColumns<string> = [
     },
 ];
 
+const mapStateToProps = (state: RootState) => {
+    return {
+        resources: state.resources
+    };
+};
+
+const mapDispatchToProps = (dispatch: Dispatch) => ({
+    onContextMenu: (event: React.MouseEvent<HTMLElement>, item: any) => dispatch<any>(openContextMenu(event, item)),
+    onNewGroup: openCreateGroupDialog
+});
+
 export interface GroupsPanelProps {
     onNewGroup: () => void;
+    onContextMenu: (event: React.MouseEvent<HTMLElement>, item: any) => void;
+    resources: ResourcesState;
 }
 
 export const GroupsPanel = connect(
-    null,
-    {
-        onNewGroup: openCreateGroupDialog
-    }
+    mapStateToProps, mapDispatchToProps
 )(
     class GroupsPanel extends React.Component<GroupsPanelProps> {
 
@@ -65,7 +81,7 @@ export const GroupsPanel = connect(
                     id={GROUPS_PANEL_ID}
                     onRowClick={noop}
                     onRowDoubleClick={noop}
-                    onContextMenu={noop}
+                    onContextMenu={this.handleContextMenu}
                     contextMenuColumn={true}
                     hideColumnSelector
                     actions={
@@ -80,4 +96,17 @@ export const GroupsPanel = connect(
                     } />
             );
         }
+        
+        handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
+            const resource = getResource<GroupResource>(resourceUuid)(this.props.resources);
+            if (resource) {
+                this.props.onContextMenu(event, {
+                    name: '',
+                    uuid: resource.uuid,
+                    ownerUuid: resource.ownerUuid,
+                    kind: resource.kind,
+                    menuKind: ContextMenuKind.GROUPS
+                });
+            }
+        }
     });
diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx
index 2a77318..62c10f2 100644
--- a/src/views/workbench/workbench.tsx
+++ b/src/views/workbench/workbench.tsx
@@ -77,6 +77,8 @@ import { CreateUserDialog } from '~/views-components/dialog-forms/create-user-di
 import { HelpApiClientAuthorizationDialog } from '~/views-components/api-client-authorizations-dialog/help-dialog';
 import { GroupsPanel } from '~/views/groups-panel/groups-panel';
 import { CreateGroupDialog } from '~/views-components/dialog-forms/create-group-dialog';
+import { RemoveGroupDialog } from '~/views-components/groups-dialog/remove-dialog';
+import { GroupAttributesDialog } from '~/views-components/groups-dialog/attributes-dialog';
 
 type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content';
 
@@ -181,6 +183,7 @@ export const WorkbenchPanel =
             <CurrentTokenDialog />
             <FileRemoveDialog />
             <FilesUploadCollectionDialog />
+            <GroupAttributesDialog />
             <HelpApiClientAuthorizationDialog />
             <MoveCollectionDialog />
             <MoveProcessDialog />
@@ -193,6 +196,7 @@ export const WorkbenchPanel =
             <ProjectPropertiesDialog />
             <RemoveApiClientAuthorizationDialog />
             <RemoveComputeNodeDialog />
+            <RemoveGroupDialog />
             <RemoveKeepServiceDialog />
             <RemoveProcessDialog />
             <RemoveRepositoryDialog />

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list