Merge branch 'master' into 14565-admin-managing-user
authorPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Tue, 18 Dec 2018 09:09:50 +0000 (10:09 +0100)
committerPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Tue, 18 Dec 2018 09:09:50 +0000 (10:09 +0100)
refs #14565

Arvados-DCO-1.1-Signed-off-by: Pawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>

src/store/users/users-actions.ts
src/views-components/context-menu/action-sets/user-action-set.ts
src/views-components/dialog-create/dialog-user-create.tsx
src/views-components/dialog-forms/setup-shell-account-dialog.tsx [new file with mode: 0644]
src/views-components/form-fields/user-form-fields.tsx
src/views-components/user-dialog/manage-dialog.tsx [new file with mode: 0644]
src/views/workbench/workbench.tsx

index 585a3663bcdf5fabf7b34fe295f0d30981f08fd0..9e76396d0e7f3adafdf934da2fc83ee25534188c 100644 (file)
@@ -16,10 +16,11 @@ import { navigateToProject, navigateToUsers, navigateToRootProject } from "~/sto
 export const USERS_PANEL_ID = 'usersPanel';
 export const USER_ATTRIBUTES_DIALOG = 'userAttributesDialog';
 export const USER_CREATE_FORM_NAME = 'userCreateFormName';
+export const USER_MANAGE_DIALOG = 'userManageDialog';
+export const SETUP_SHELL_ACCOUNT_DIALOG = 'setupShellAccountDialog';
 
 export interface UserCreateFormDialogData {
     email: string;
-    identityUrl: string;
     virtualMachineName: string;
     groupVirtualMachine: string;
 }
@@ -31,6 +32,21 @@ export const openUserAttributes = (uuid: string) =>
         dispatch(dialogActions.OPEN_DIALOG({ id: USER_ATTRIBUTES_DIALOG, data }));
     };
 
+export const openUserManage = (uuid: string) =>
+    (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        const { resources } = getState();
+        const data = getResource<UserResource>(uuid)(resources);
+        dispatch(dialogActions.OPEN_DIALOG({ id: USER_MANAGE_DIALOG, data }));
+    };
+
+export const openSetupShellAccount = (uuid: string) =>
+    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        const { resources } = getState();
+        const user = getResource<UserResource>(uuid)(resources);
+        const virtualMachines = await services.virtualMachineService.list();
+        dispatch(dialogActions.OPEN_DIALOG({ id: SETUP_SHELL_ACCOUNT_DIALOG, data: { user, ...virtualMachines } }));
+    };
+
 export const openUserCreateDialog = () =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         const userUuid = await services.authService.getUuid();
index 7b0884e668b02ef9f3c5f30bf4c2b2eab3607873..c1b559fe50b5e9241169260791423fb1dd500a75 100644 (file)
@@ -5,7 +5,7 @@
 import { ContextMenuActionSet } from "~/views-components/context-menu/context-menu-action-set";
 import { AdvancedIcon, ProjectIcon, AttributesIcon, UserPanelIcon } from "~/components/icon/icon";
 import { openAdvancedTabDialog } from '~/store/advanced-tab/advanced-tab';
-import { openUserAttributes, openUserProjects } from "~/store/users/users-actions";
+import { openUserAttributes, openUserProjects, openUserManage } from "~/store/users/users-actions";
 
 export const userActionSet: ContextMenuActionSet = [[{
     name: "Attributes",
@@ -25,11 +25,10 @@ export const userActionSet: ContextMenuActionSet = [[{
     execute: (dispatch, { uuid }) => {
         dispatch<any>(openAdvancedTabDialog(uuid));
     }
-},
-{
+}, {
     name: "Manage",
     icon: UserPanelIcon,
     execute: (dispatch, { uuid }) => {
-        dispatch<any>(openAdvancedTabDialog(uuid));
+        dispatch<any>(openUserManage(uuid));
     }
 }]];
index 14365af7d6c69f1d8dddc91fc486b6d807969326..06db587307a3119e06ae38d8cdb7c6211b18dd69 100644 (file)
@@ -6,7 +6,7 @@ import * as React from 'react';
 import { InjectedFormProps } from 'redux-form';
 import { WithDialogProps } from '~/store/dialog/with-dialog';
 import { FormDialog } from '~/components/form-dialog/form-dialog';
-import { UserEmailField, UserIdentityUrlField, UserVirtualMachineField, UserGroupsVirtualMachineField } from '~/views-components/form-fields/user-form-fields';
+import { UserEmailField, UserVirtualMachineField, UserGroupsVirtualMachineField } from '~/views-components/form-fields/user-form-fields';
 
 export type DialogUserProps = WithDialogProps<{}> & InjectedFormProps<any>;
 
@@ -20,7 +20,6 @@ export const UserRepositoryCreate = (props: DialogUserProps) =>
 
 const UserAddFields = (props: DialogUserProps) => <span>
     <UserEmailField />
-    <UserIdentityUrlField />
     <UserVirtualMachineField data={props.data}/>
     <UserGroupsVirtualMachineField />
 </span>;
diff --git a/src/views-components/dialog-forms/setup-shell-account-dialog.tsx b/src/views-components/dialog-forms/setup-shell-account-dialog.tsx
new file mode 100644 (file)
index 0000000..8b9a6b6
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+import * as React from 'react';
+import { compose } from "redux";
+import { reduxForm, InjectedFormProps, Field } from 'redux-form';
+import { withDialog, WithDialogProps } from "~/store/dialog/with-dialog";
+import { FormDialog } from '~/components/form-dialog/form-dialog';
+import { TextField } from '~/components/text-field/text-field';
+import { VirtualMachinesResource } from '~/models/virtual-machines';
+import { USER_LENGTH_VALIDATION } from '~/validators/validators';
+import { InputLabel } from '@material-ui/core';
+import { NativeSelectField } from '~/components/select-field/select-field';
+import { SETUP_SHELL_ACCOUNT_DIALOG, createUser } from '~/store/users/users-actions';
+
+interface SetupShellAccountFormDialogData {
+    email: string;
+    virtualMachineName: string;
+    groupVirtualMachine: string;
+}
+
+export const SetupShellAccountDialog = compose(
+    withDialog(SETUP_SHELL_ACCOUNT_DIALOG),
+    reduxForm<SetupShellAccountFormDialogData>({
+        form: SETUP_SHELL_ACCOUNT_DIALOG,
+        onSubmit: (data, dispatch) => {
+            dispatch(createUser(data));
+        }
+    })
+)(
+    (props: SetupShellAccountDialogComponentProps) =>
+        <FormDialog
+            dialogTitle='Setup shell account'
+            formFields={SetupShellAccountFormFields}
+            submitLabel='Submit'
+            {...props}
+        />
+);
+
+const UserEmailField = ({ data }: any) =>
+    <Field
+        name='email'
+        component={TextField}
+        disabled
+        label={data.user.email} />;
+
+const UserVirtualMachineField = ({ data }: any) =>
+    <div style={{ marginBottom: '21px' }}>
+        <InputLabel>Virtual Machine</InputLabel>
+        <Field
+            name='virtualMachine'
+            component={NativeSelectField}
+            validate={USER_LENGTH_VALIDATION}
+            items={getVirtualMachinesList(data.items)} />
+    </div>;
+
+const UserGroupsVirtualMachineField = () =>
+    <Field
+        name='groups'
+        component={TextField}
+        validate={USER_LENGTH_VALIDATION}
+        label="Groups for virtual machine (comma separated list)" />;
+
+const getVirtualMachinesList = (virtualMachines: VirtualMachinesResource[]) => {
+    const mappedVirtualMachines = virtualMachines.map(it => ({ key: it.hostname, value: it.hostname }));
+    return mappedVirtualMachines;
+};
+
+type SetupShellAccountDialogComponentProps = WithDialogProps<{}> & InjectedFormProps<SetupShellAccountFormDialogData>;
+
+const SetupShellAccountFormFields = (props: SetupShellAccountDialogComponentProps) =>
+    <>
+        <UserEmailField data={props.data}/>
+        <UserVirtualMachineField data={props.data} />
+        <UserGroupsVirtualMachineField />
+    </>;
+
+
+
index 856344492f72f6fe361a2e0c6858f9f0c347a29b..11d7d80280c699d5bd55c88781db65459d905ab6 100644 (file)
@@ -18,13 +18,6 @@ export const UserEmailField = () =>
         autoFocus={true}
         label="Email" />;
 
-export const UserIdentityUrlField = () =>
-    <Field
-        name='identityUrl'
-        component={TextField}
-        validate={USER_LENGTH_VALIDATION}
-        label="Identity URL Prefix" />;
-
 export const UserVirtualMachineField = ({ data }: any) =>
     <div style={{ marginBottom: '21px' }}>
         <InputLabel>Virtual Machine</InputLabel>
diff --git a/src/views-components/user-dialog/manage-dialog.tsx b/src/views-components/user-dialog/manage-dialog.tsx
new file mode 100644 (file)
index 0000000..ddf73fb
--- /dev/null
@@ -0,0 +1,72 @@
+// 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 } 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, Dispatch } from "redux";
+import { USER_MANAGE_DIALOG, openSetupShellAccount } from "~/store/users/users-actions";
+import { UserResource } from "~/models/user";
+import { connect } from "react-redux";
+
+type CssRules = 'spacing';
+
+const styles = withStyles<CssRules>((theme: ArvadosTheme) => ({
+    spacing: {
+        paddingBottom: theme.spacing.unit * 2,
+        paddingTop: theme.spacing.unit * 2,
+    }
+}));
+
+interface UserManageDataProps {
+    data: UserResource;
+}
+
+interface UserManageActionProps {
+    openSetupShellAccount: (uuid: string) => void;
+}
+
+const mapDispatchToProps = (dispatch: Dispatch) => ({
+    openSetupShellAccount: (uuid: string) => dispatch<any>(openSetupShellAccount(uuid))
+});
+
+type UserManageProps = UserManageDataProps & UserManageActionProps & WithStyles<CssRules>;
+
+export const UserManageDialog = compose(
+    connect(null, mapDispatchToProps),
+    withDialog(USER_MANAGE_DIALOG),
+    styles)(
+        (props: WithDialogProps<UserManageProps> & UserManageProps) =>
+            <Dialog open={props.open}
+                onClose={props.closeDialog}
+                fullWidth
+                maxWidth="md">
+                <DialogTitle>{`Manage - ${props.data.firstName} ${props.data.lastName}`}</DialogTitle>
+                <DialogContent>
+                    <Typography variant="body2" className={props.classes.spacing}>
+                        As an admin, you can log in as this user. When you’ve finished, you will need to log out and log in again with your own account.
+                    </Typography>
+                    <Button variant="contained" color="primary">
+                        {`LOG IN AS ${props.data.firstName} ${props.data.lastName}`}
+                    </Button>
+                    <Typography variant="body2" className={props.classes.spacing}>
+                        As an admin, you can setup a shell account for this user. The login name is automatically generated from the user's e-mail address.
+                    </Typography>
+                    <Button variant="contained" color="primary" onClick={() => props.openSetupShellAccount(props.data.uuid)}>
+                        {`SETUP SHELL ACCOUNT FOR ${props.data.firstName} ${props.data.lastName}`}
+                    </Button>
+                </DialogContent>
+                <DialogActions>
+                    <Button
+                        variant='flat'
+                        color='primary'
+                        onClick={props.closeDialog}>
+                        Close
+                </Button>
+                </DialogActions>
+            </Dialog>
+    );
index bff328e8c8c6ff448bc271d36068925a8b0cc81d..6c7c24386205310611b65b3df22029911c8602c0 100644 (file)
@@ -79,6 +79,8 @@ import { UserPanel } from '~/views/user-panel/user-panel';
 import { UserAttributesDialog } from '~/views-components/user-dialog/attributes-dialog';
 import { CreateUserDialog } from '~/views-components/dialog-forms/create-user-dialog';
 import { HelpApiClientAuthorizationDialog } from '~/views-components/api-client-authorizations-dialog/help-dialog';
+import { UserManageDialog } from '~/views-components/user-dialog/manage-dialog';
+import { SetupShellAccountDialog } from '~/views-components/dialog-forms/setup-shell-account-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';
@@ -223,12 +225,14 @@ export const WorkbenchPanel =
             <RepositoryAttributesDialog />
             <RepositoriesSampleGitDialog />
             <RichTextEditorDialog />
+            <SetupShellAccountDialog />
             <SharingDialog />
             <Snackbar />
             <UpdateCollectionDialog />
             <UpdateProcessDialog />
             <UpdateProjectDialog />
             <UserAttributesDialog />
+            <UserManageDialog />
             <VirtualMachineAttributesDialog />
         </Grid>
     );
\ No newline at end of file