18559: Update the new user dialog and fix groups functionality
authorStephen Smith <stephen@curii.com>
Mon, 14 Mar 2022 21:20:25 +0000 (17:20 -0400)
committerStephen Smith <stephen@curii.com>
Mon, 14 Mar 2022 21:20:25 +0000 (17:20 -0400)
Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen@curii.com>

src/store/users/users-actions.ts
src/views-components/dialog-create/dialog-user-create.tsx
src/views-components/dialog-forms/setup-shell-account-dialog.tsx
src/views-components/form-fields/user-form-fields.tsx

index fded11407b3b2df82805af5494ea2a401ac151b4..425a2d569d6e2b553e091134b3fa6f05af826d7b 100644 (file)
@@ -15,7 +15,7 @@ import { getResource } from 'store/resources/resources';
 import { navigateTo, navigateToUsers, navigateToRootProject } from "store/navigation/navigation-action";
 import { authActions } from 'store/auth/auth-action';
 import { getTokenV2 } from "models/api-client-authorization";
-import { AddLoginFormData, VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD, VIRTUAL_MACHINE_ADD_LOGIN_USER_FIELD } from "store/virtual-machines/virtual-machines-actions";
+import { AddLoginFormData, VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD, VIRTUAL_MACHINE_ADD_LOGIN_USER_FIELD, VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD } from "store/virtual-machines/virtual-machines-actions";
 import { PermissionLevel } from "models/permission";
 import { updateResources } from "store/resources/resources-actions";
 
@@ -27,8 +27,8 @@ export const SETUP_SHELL_ACCOUNT_DIALOG = 'setupShellAccountDialog';
 
 export interface UserCreateFormDialogData {
     email: string;
-    virtualMachineName: string;
-    groupVirtualMachine: string;
+    [VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD]: string;
+    [VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD]: string[];
 }
 
 export const userBindedActions = bindDataExplorerActions(USERS_PANEL_ID);
@@ -83,11 +83,28 @@ export const openUserProjects = (uuid: string) =>
         dispatch<any>(navigateTo(uuid));
     };
 
-export const createUser = (user: UserCreateFormDialogData) =>
+export const createUser = (data: UserCreateFormDialogData) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         dispatch(startSubmit(USER_CREATE_FORM_NAME));
         try {
-            const newUser = await services.userService.create({ ...user });
+            const newUser = await services.userService.create({
+                email: data.email,
+            });
+            dispatch(updateResources([newUser]));
+
+            if (data[VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD]) {
+                const permission = await services.permissionService.create({
+                    headUuid: data[VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD],
+                    tailUuid: newUser.uuid,
+                    name: PermissionLevel.CAN_LOGIN,
+                    properties: {
+                        username: newUser.username,
+                        groups: data.groups,
+                    }
+                });
+                dispatch(updateResources([permission]));
+            }
+
             dispatch(dialogActions.CLOSE_DIALOG({ id: USER_CREATE_FORM_NAME }));
             dispatch(reset(USER_CREATE_FORM_NAME));
             dispatch(snackbarActions.OPEN_SNACKBAR({ message: "User has been successfully created.", hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
@@ -96,6 +113,8 @@ export const createUser = (user: UserCreateFormDialogData) =>
             return newUser;
         } catch (e) {
             return;
+        } finally {
+            dispatch(stopSubmit(USER_CREATE_FORM_NAME));
         }
     };
 
index d8d25da494c57ff587557039c62d1a828afb7822..6be7b28f0ebea3f5d370d7397cfdbd2e8ec228c6 100644 (file)
@@ -7,8 +7,16 @@ import { InjectedFormProps } from 'redux-form';
 import { WithDialogProps } from 'store/dialog/with-dialog';
 import { FormDialog } from 'components/form-dialog/form-dialog';
 import { UserEmailField, UserVirtualMachineField, UserGroupsVirtualMachineField } from 'views-components/form-fields/user-form-fields';
+import { UserCreateFormDialogData } from 'store/users/users-actions';
+import { UserResource } from 'models/user';
+import { VirtualMachinesResource } from 'models/virtual-machines';
 
-export type DialogUserProps = WithDialogProps<{}> & InjectedFormProps<any>;
+export type DialogUserProps = WithDialogProps<{}> & InjectedFormProps<UserCreateFormDialogData>;
+
+interface DataProps {
+    user: UserResource;
+    items: VirtualMachinesResource[];
+}
 
 export const UserRepositoryCreate = (props: DialogUserProps) =>
     <FormDialog
@@ -20,6 +28,6 @@ export const UserRepositoryCreate = (props: DialogUserProps) =>
 
 const UserAddFields = (props: DialogUserProps) => <span>
     <UserEmailField />
-    <UserVirtualMachineField data={props.data}/>
+    <UserVirtualMachineField data={props.data as DataProps}/>
     <UserGroupsVirtualMachineField />
 </span>;
index 666ea38e4da3b6122af77c561c08314afce16e4e..04eae1267ca483af99f312ae26d575a9a3cc7185 100644 (file)
@@ -8,13 +8,11 @@ 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 { CHOOSE_VM_VALIDATION } from 'validators/validators';
 import { InputLabel } from '@material-ui/core';
-import { NativeSelectField } from 'components/select-field/select-field';
 import { SETUP_SHELL_ACCOUNT_DIALOG, setupUserVM } from 'store/users/users-actions';
 import { UserResource } from 'models/user';
-import { VIRTUAL_MACHINE_ADD_LOGIN_USER_FIELD, VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD, VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD, AddLoginFormData } from 'store/virtual-machines/virtual-machines-actions';
-import { GroupArrayInput } from 'views-components/virtual-machines-dialog/group-array-input';
+import { VIRTUAL_MACHINE_ADD_LOGIN_USER_FIELD, AddLoginFormData } from 'store/virtual-machines/virtual-machines-actions';
+import { UserGroupsVirtualMachineField, RequiredUserVirtualMachineField } from 'views-components/form-fields/user-form-fields';
 
 export const SetupShellAccountDialog = compose(
     withDialog(SETUP_SHELL_ACCOUNT_DIALOG),
@@ -34,11 +32,6 @@ export const SetupShellAccountDialog = compose(
         />
 );
 
-interface VirtualMachinesProps {
-    data: {
-        items: VirtualMachinesResource[];
-    };
-}
 interface DataProps {
     user: UserResource;
     items: VirtualMachinesResource[];
@@ -50,33 +43,14 @@ const UserNameField = () =>
         <Field
             name={`${VIRTUAL_MACHINE_ADD_LOGIN_USER_FIELD}.username`}
             component={TextField as any}
-            disabled /></span>;
-
-const UserVirtualMachineField = ({ data }: VirtualMachinesProps) =>
-    <div style={{ marginBottom: '21px' }}>
-        <InputLabel>Virtual Machine</InputLabel>
-        <Field
-            name={VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD}
-            component={NativeSelectField as any}
-            validate={CHOOSE_VM_VALIDATION}
-            items={getVirtualMachinesList(data.items)} />
-    </div>;
-
-const UserGroupsVirtualMachineField = () =>
-    <GroupArrayInput
-        name={VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD}
-        input={{id:"Add groups to VM login (eg: docker, sudo)", disabled:false}}
-        required={false}
-    />
-
-const getVirtualMachinesList = (virtualMachines: VirtualMachinesResource[]) =>
-    [{ key: "", value: "" }].concat(virtualMachines.map(it => ({ key: it.uuid, value: it.hostname })));
+            disabled />
+    </span>;
 
 type SetupShellAccountDialogComponentProps = WithDialogProps<{}> & InjectedFormProps<AddLoginFormData>;
 
 const SetupShellAccountFormFields = (props: SetupShellAccountDialogComponentProps) =>
     <>
         <UserNameField />
-        <UserVirtualMachineField data={props.data as DataProps} />
+        <RequiredUserVirtualMachineField data={props.data as DataProps} />
         <UserGroupsVirtualMachineField />
     </>;
index 393f29d325a6f28321b8f8effa90ca06d2d66c47..12fc91e2423553b62ceb71bc474c120d6aca04c0 100644 (file)
@@ -5,10 +5,18 @@
 import React from "react";
 import { Field } from "redux-form";
 import { TextField } from "components/text-field/text-field";
-import { USER_EMAIL_VALIDATION, USER_LENGTH_VALIDATION } from "validators/validators";
+import { USER_EMAIL_VALIDATION, CHOOSE_VM_VALIDATION } from "validators/validators";
 import { NativeSelectField } from "components/select-field/select-field";
 import { InputLabel } from "@material-ui/core";
 import { VirtualMachinesResource } from "models/virtual-machines";
+import { VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD, VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD } from "store/virtual-machines/virtual-machines-actions";
+import { GroupArrayInput } from "views-components/virtual-machines-dialog/group-array-input";
+
+interface VirtualMachinesProps {
+    data: {
+        items: VirtualMachinesResource[];
+    };
+}
 
 export const UserEmailField = () =>
     <Field
@@ -18,24 +26,31 @@ export const UserEmailField = () =>
         autoFocus={true}
         label="Email" />;
 
-export const UserVirtualMachineField = ({ data }: any) =>
+export const RequiredUserVirtualMachineField = ({ data }: VirtualMachinesProps) =>
+    <div style={{ marginBottom: '21px' }}>
+        <InputLabel>Virtual Machine</InputLabel>
+        <Field
+            name={VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD}
+            component={NativeSelectField as any}
+            validate={CHOOSE_VM_VALIDATION}
+            items={getVirtualMachinesList(data.items)} />
+    </div>;
+
+export const UserVirtualMachineField = ({ data }: VirtualMachinesProps) =>
     <div style={{ marginBottom: '21px' }}>
         <InputLabel>Virtual Machine</InputLabel>
         <Field
-            name='virtualMachine'
+            name={VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD}
             component={NativeSelectField as any}
-            validate={USER_LENGTH_VALIDATION}
             items={getVirtualMachinesList(data.items)} />
     </div>;
 
 export const UserGroupsVirtualMachineField = () =>
-    <Field
-        name='groups'
-        component={TextField as any}
-        validate={USER_LENGTH_VALIDATION}
-        label="Groups for virtual machine (comma separated list)" />;
+    <GroupArrayInput
+        name={VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD}
+        input={{id:"Add groups to VM login (eg: docker, sudo)", disabled:false}}
+        required={false}
+    />
 
-const getVirtualMachinesList = (virtualMachines: VirtualMachinesResource[]) => {
-    const mappedVirtualMachines = virtualMachines.map(it => ({ key: it.hostname, value: it.hostname }));
-    return mappedVirtualMachines;
-};
+const getVirtualMachinesList = (virtualMachines: VirtualMachinesResource[]) =>
+    [{ key: "", value: "" }].concat(virtualMachines.map(it => ({ key: it.uuid, value: it.hostname })));