[ARVADOS-WORKBENCH2] updated: 1.3.0-90-g8b6f5c6
Git user
git at public.curoverse.com
Tue Dec 11 05:36:34 EST 2018
Summary of changes:
src/index.tsx | 2 ++
src/store/groups-panel/groups-panel-actions.ts | 33 ++++++++++++++++++
src/store/users/users-actions.ts | 3 +-
.../{ssh-key-action-set.ts => group-action-set.ts} | 16 ++++-----
src/views-components/context-menu/context-menu.tsx | 3 +-
.../attributes-dialog.tsx | 40 ++++++++++++----------
.../remove-dialog.ts} | 9 ++---
src/views/groups-panel/groups-panel.tsx | 39 ++++++++++++++++++---
src/views/workbench/workbench.tsx | 4 +++
9 files changed, 111 insertions(+), 38 deletions(-)
copy src/views-components/context-menu/action-sets/{ssh-key-action-set.ts => group-action-set.ts} (54%)
copy src/views-components/{user-dialog => groups-dialog}/attributes-dialog.tsx (70%)
copy src/views-components/{ssh-keys-dialog/remove-dialog.tsx => groups-dialog/remove-dialog.ts} (68%)
via 8b6f5c68fa40ad59092e1290dfd4261f0dfe643f (commit)
via 4afdbe4d6f060423725d77fa7500d76d8e7e5f04 (commit)
from fc1f170015c5ffd5f4ee5b990d530f3c9782f549 (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 8b6f5c68fa40ad59092e1290dfd4261f0dfe643f
Merge: 4afdbe4 fc1f170
Author: Pawel Kowalczyk <pawel.kowalczyk at contractors.roche.com>
Date: Tue Dec 11 11:23:58 2018 +0100
merge-14505-admin-group-panel
Feature #14505
Arvados-DCO-1.1-Signed-off-by: Pawel Kowalczyk <pawel.kowalczyk at contractors.roche.com>
diff --cc src/store/groups-panel/groups-panel-actions.ts
index e46ebd1,65ca66b..e5cb2d9
--- a/src/store/groups-panel/groups-panel-actions.ts
+++ b/src/store/groups-panel/groups-panel-actions.ts
@@@ -7,10 -7,8 +7,11 @@@ import { reset, startSubmit, stopSubmit
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 { getCommonResourceServiceError, CommonResourceServiceError } from '~/services/common-service/common-resource-service';
import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
export const GROUPS_PANEL_ID = "groupsPanel";
@@@ -31,40 -27,38 +32,66 @@@ 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[];
+ [CREATE_GROUP_USERS_FIELD_NAME]?: Person[];
}
- export const createGroup = (data: CreateGroupFormData) =>
- (dispatch: Dispatch) => {
- console.log(data);
+ export const createGroup = ({ name }: CreateGroupFormData) =>
+ async (dispatch: Dispatch, _: {}, { groupsService }: ServiceRepository) => {
+
+ dispatch(startSubmit(CREATE_GROUP_FORM));
+
+ try {
+
+ const newGroup = await groupsService.create({ name });
+
+ dispatch(dialogActions.CLOSE_DIALOG({ id: CREATE_GROUP_DIALOG }));
+ dispatch(reset(CREATE_GROUP_FORM));
+ dispatch(loadGroupsPanel());
+ dispatch(snackbarActions.OPEN_SNACKBAR({
+ message: `${newGroup.name} group has been created`,
+ kind: SnackbarKind.SUCCESS
+ }));
+
+ return newGroup;
+
+ } catch (e) {
+
+ const error = getCommonResourceServiceError(e);
+ if (error === CommonResourceServiceError.UNIQUE_VIOLATION) {
+ dispatch(stopSubmit(CREATE_GROUP_FORM, { name: 'Group with the same name already exists.' } as FormErrors));
+ }
+
+ return;
+
+ }
};
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