[ARVADOS-WORKBENCH2] updated: 2.3.0-149-gb178ea37

Git user git at public.arvados.org
Tue Feb 8 16:43:48 UTC 2022


Summary of changes:
 cypress/integration/virtual-machine-admin.spec.js  | 100 +++++++++++++++++++--
 .../virtual-machines/virtual-machines-actions.ts   |  53 ++++++++---
 .../virtual-machines-dialog/add-login-dialog.tsx   |  14 +--
 .../virtual-machine-admin-panel.tsx                |  10 ++-
 4 files changed, 148 insertions(+), 29 deletions(-)

       via  b178ea37c7a247a6399ecf1112d5f8c8aae12136 (commit)
      from  c2a580be1484629e557b967524473a75b2d02274 (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 b178ea37c7a247a6399ecf1112d5f8c8aae12136
Author: Stephen Smith <stephen at curii.com>
Date:   Tue Feb 8 11:43:05 2022 -0500

    18284: Add update vm login dialog, remove default group, update tests
    
    Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen at curii.com>

diff --git a/cypress/integration/virtual-machine-admin.spec.js b/cypress/integration/virtual-machine-admin.spec.js
index d057ce49..73804b20 100644
--- a/cypress/integration/virtual-machine-admin.spec.js
+++ b/cypress/integration/virtual-machine-admin.spec.js
@@ -41,10 +41,10 @@ describe('Virtual machine login manage tests', function() {
                 cy.get('button[title="Add Login Permission"]').click();
             });
         cy.get('[data-cy=form-dialog]')
-            .should('contain', 'Add login permissions')
+            .should('contain', 'Add login permission')
             .within(() => {
                 cy.get('label')
-                  .contains('Search for users')
+                  .contains('Search for user')
                   .parent()
                   .within(() => {
                     cy.get('input').type('VMAdmin');
@@ -52,13 +52,13 @@ describe('Virtual machine login manage tests', function() {
             });
         cy.get('[role=tooltip]').click();
         cy.get('[data-cy=form-dialog]')
-            .should('contain', 'Add login permissions')
+            .should('contain', 'Add login permission')
             .within(() => {
                 cy.get('label')
                   .contains('Add groups')
                   .parent()
                   .within(() => {
-                    cy.get('input').type('sudo{enter}');
+                    cy.get('input').type('docker sudo{enter}');
                   })
             });
         cy.get('[data-cy=form-dialog]').within(() => {
@@ -79,10 +79,10 @@ describe('Virtual machine login manage tests', function() {
                 cy.get('button[title="Add Login Permission"]').click();
             });
         cy.get('[data-cy=form-dialog]')
-            .should('contain', 'Add login permissions')
+            .should('contain', 'Add login permission')
             .within(() => {
                 cy.get('label')
-                  .contains('Search for users')
+                  .contains('Search for user')
                   .parent()
                   .within(() => {
                     cy.get('input').type('VMActive user');
@@ -118,12 +118,100 @@ describe('Virtual machine login manage tests', function() {
         cy.get('header button[title="Account Management"]').click();
         cy.get('#account-menu').contains('Virtual Machines').click();
 
+        cy.get('[data-cy=vm-user-table]')
+            .contains(vmHost)
+            .parents('tr')
+            .within(() => {
+                cy.get('td').contains('user');
+                cy.get('td').should('not.contain', 'docker');
+                cy.get('td').should('not.contain', 'sudo');
+                cy.get('td').contains('ssh user@' + vmHost);
+        });
+
+        // Edit login permissions
+        cy.loginAs(adminUser);
+        cy.get('header button[title="Admin Panel"]').click();
+        cy.get('#admin-menu').contains('Virtual Machines').click();
+
+        cy.get('[data-cy=vm-admin-table]')
+            .contains('admin'); // Wait for page to finish
+
+        cy.get('[data-cy=vm-admin-table]')
+            .contains(vmHost)
+            .parents('tr')
+            .contains('admin')
+            .click();
+
+        cy.get('[data-cy=form-dialog]')
+            .should('contain', 'Update login permission')
+            .within(() => {
+                cy.get('label')
+                    .contains('Add groups')
+                    .parent()
+                    .as('groupInput');
+            });
+
+        cy.get('@groupInput').within(() => {
+            cy.get('div[role=button]').contains('sudo').parent().find('svg').click();
+            cy.get('div[role=button]').contains('docker').parent().find('svg').click();
+        });
+
+        cy.get('[data-cy=form-dialog]').within(() => {
+            cy.get('[data-cy=form-submit-btn]').click();
+        });
+
+        cy.get('[data-cy=vm-admin-table]')
+            .contains('user'); // Wait for page to finish
+
+        cy.get('[data-cy=vm-admin-table]')
+            .contains(vmHost)
+            .parents('tr')
+            .contains('user')
+            .click();
+
+        cy.get('[data-cy=form-dialog]')
+            .should('contain', 'Update login permission')
+            .within(() => {
+                cy.get('label')
+                    .contains('Add groups')
+                    .parent()
+                    .within(() => {
+                        cy.get('input').type('docker{enter}');
+                    })
+            });
+
+        cy.get('[data-cy=form-dialog]').within(() => {
+            cy.get('[data-cy=form-submit-btn]').click();
+        });
+
+        // Verify new login permissions
+        // Check admin's vm page for login
+        cy.get('header button[title="Account Management"]').click();
+        cy.get('#account-menu').contains('Virtual Machines').click();
+
+        cy.get('[data-cy=vm-user-table]')
+            .contains(vmHost)
+            .parents('tr')
+            .within(() => {
+                cy.get('td').contains('admin');
+                cy.get('td').should('not.contain', 'docker');
+                cy.get('td').should('not.contain', 'sudo');
+                cy.get('td').contains('ssh admin@' + vmHost);
+        });
+
+        // Verify new login permissions
+        // Check activeUser's vm page for login
+        cy.loginAs(activeUser);
+        cy.get('header button[title="Account Management"]').click();
+        cy.get('#account-menu').contains('Virtual Machines').click();
+
         cy.get('[data-cy=vm-user-table]')
             .contains(vmHost)
             .parents('tr')
             .within(() => {
                 cy.get('td').contains('user');
                 cy.get('td').contains('docker');
+                cy.get('td').should('not.contain', 'sudo');
                 cy.get('td').contains('ssh user@' + vmHost);
         });
 
diff --git a/src/store/virtual-machines/virtual-machines-actions.ts b/src/store/virtual-machines/virtual-machines-actions.ts
index 08654a44..e2cf6fd4 100644
--- a/src/store/virtual-machines/virtual-machines-actions.ts
+++ b/src/store/virtual-machines/virtual-machines-actions.ts
@@ -18,6 +18,7 @@ import { PermissionLevel } from "models/permission";
 import { deleteResources, updateResources } from 'store/resources/resources-actions';
 import { Participant } from "views-components/sharing-dialog/participant-select";
 import { initialize, reset } from "redux-form";
+import { getUserDisplayName } from "models/user";
 
 export const virtualMachinesActions = unionize({
     SET_REQUESTED_DATE: ofType<string>(),
@@ -35,6 +36,7 @@ export const VIRTUAL_MACHINE_ADD_LOGIN_DIALOG = 'virtualMachineAddLoginDialog';
 export const VIRTUAL_MACHINE_ADD_LOGIN_FORM = 'virtualMachineAddLoginForm';
 export const VIRTUAL_MACHINE_REMOVE_LOGIN_DIALOG = 'virtualMachineRemoveLoginDialog';
 
+export const VIRTUAL_MACHINE_UPDATE_LOGIN_UUID_FIELD = 'uuid';
 export const VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD = 'vmUuid';
 export const VIRTUAL_MACHINE_ADD_LOGIN_USER_FIELD = 'user';
 export const VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD = 'groups';
@@ -111,42 +113,67 @@ export const loadVirtualMachinesUserData = () =>
         dispatch(virtualMachinesActions.SET_LINKS(links));
     };
 
-export const openAddVirtualMachineLoginDialog = (uuid: string) =>
+export const openAddVirtualMachineLoginDialog = (vmUuid: string) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
-        dispatch(initialize(VIRTUAL_MACHINE_ADD_LOGIN_FORM, {[VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD]: uuid, [VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD]: ['docker']}));
+        dispatch(initialize(VIRTUAL_MACHINE_ADD_LOGIN_FORM, {[VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD]: vmUuid, [VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD]: []}));
         dispatch(dialogActions.OPEN_DIALOG( {id: VIRTUAL_MACHINE_ADD_LOGIN_DIALOG, data: {}} ));
     }
 
+export const openEditVirtualMachineLoginDialog = (permissionUuid: string) =>
+    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        const login = await services.permissionService.get(permissionUuid);
+        const user = await services.userService.get(login.tailUuid);
+        dispatch(initialize(VIRTUAL_MACHINE_ADD_LOGIN_FORM, {
+                [VIRTUAL_MACHINE_UPDATE_LOGIN_UUID_FIELD]: permissionUuid,
+                [VIRTUAL_MACHINE_ADD_LOGIN_USER_FIELD]: {name: getUserDisplayName(user, true), uuid: login.tailUuid},
+                [VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD]: login.properties.groups,
+            }));
+        dispatch(dialogActions.OPEN_DIALOG( {id: VIRTUAL_MACHINE_ADD_LOGIN_DIALOG, data: {updating: true}} ));
+    }
+
 export interface AddLoginFormData {
+    [VIRTUAL_MACHINE_UPDATE_LOGIN_UUID_FIELD]: string;
     [VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD]: string;
     [VIRTUAL_MACHINE_ADD_LOGIN_USER_FIELD]: Participant;
     [VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD]: string[];
 }
 
 
-export const addVirtualMachineLogin = ({vmUuid, user, groups}: AddLoginFormData) =>
+export const addUpdateVirtualMachineLogin = ({uuid, vmUuid, user, groups}: AddLoginFormData) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         try {
             // Get user
             const userResource = await services.userService.get(user.uuid);
 
-            const permission = await services.permissionService.create({
+            if (uuid) {
+                const permission = await services.permissionService.update(uuid, {
+                    tailUuid: userResource.uuid,
+                    name: PermissionLevel.CAN_LOGIN,
+                    properties: {
+                        username: userResource.username,
+                        groups,
+                    }
+                });
+                dispatch(updateResources([permission]));
+            } else {
+                const permission = await services.permissionService.create({
                 headUuid: vmUuid,
-                tailUuid: userResource.uuid,
-                name: PermissionLevel.CAN_LOGIN,
-                properties: {
-                    username: userResource.username,
-                    groups,
-                }
-            });
-            dispatch(updateResources([permission]));
+                    tailUuid: userResource.uuid,
+                    name: PermissionLevel.CAN_LOGIN,
+                    properties: {
+                        username: userResource.username,
+                        groups,
+                    }
+                });
+                dispatch(updateResources([permission]));
+            }
 
             dispatch(reset(VIRTUAL_MACHINE_ADD_LOGIN_FORM));
             dispatch(dialogActions.CLOSE_DIALOG({ id: VIRTUAL_MACHINE_ADD_LOGIN_DIALOG }));
             dispatch<any>(loadVirtualMachinesAdminData());
 
             dispatch(snackbarActions.OPEN_SNACKBAR({
-                message: `Permissions updated`,
+                message: `Permission updated`,
                 kind: SnackbarKind.SUCCESS
             }));
         } catch (e) {
diff --git a/src/views-components/virtual-machines-dialog/add-login-dialog.tsx b/src/views-components/virtual-machines-dialog/add-login-dialog.tsx
index 8d543406..bfc04716 100644
--- a/src/views-components/virtual-machines-dialog/add-login-dialog.tsx
+++ b/src/views-components/virtual-machines-dialog/add-login-dialog.tsx
@@ -7,7 +7,7 @@ import { compose } from "redux";
 import { reduxForm, InjectedFormProps, WrappedFieldProps, Field } from 'redux-form';
 import { withDialog, WithDialogProps } from "store/dialog/with-dialog";
 import { FormDialog } from 'components/form-dialog/form-dialog';
-import { VIRTUAL_MACHINE_ADD_LOGIN_DIALOG, VIRTUAL_MACHINE_ADD_LOGIN_FORM, addVirtualMachineLogin, AddLoginFormData, VIRTUAL_MACHINE_ADD_LOGIN_USER_FIELD, VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD } from 'store/virtual-machines/virtual-machines-actions';
+import { VIRTUAL_MACHINE_ADD_LOGIN_DIALOG, VIRTUAL_MACHINE_ADD_LOGIN_FORM, addUpdateVirtualMachineLogin, AddLoginFormData, VIRTUAL_MACHINE_ADD_LOGIN_USER_FIELD, VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD } from 'store/virtual-machines/virtual-machines-actions';
 import { ParticipantSelect } from 'views-components/sharing-dialog/participant-select';
 import { GroupArrayInput } from 'views-components/virtual-machines-dialog/group-array-input';
 
@@ -16,27 +16,27 @@ export const VirtualMachineAddLoginDialog = compose(
     reduxForm<AddLoginFormData>({
         form: VIRTUAL_MACHINE_ADD_LOGIN_FORM,
         onSubmit: (data, dispatch) => {
-            dispatch(addVirtualMachineLogin(data));
+            dispatch(addUpdateVirtualMachineLogin(data));
         }
     })
 )(
     (props: CreateGroupDialogComponentProps) =>
         <FormDialog
-            dialogTitle='Add login permissions'
+            dialogTitle={props.data.updating ? "Update login permission" : "Add login permission"}
             formFields={AddLoginFormFields}
-            submitLabel='Add'
+            submitLabel={props.data.updating ? "Update" : "Add"}
             {...props}
         />
 );
 
-type CreateGroupDialogComponentProps = WithDialogProps<{}> & InjectedFormProps<AddLoginFormData>;
+type CreateGroupDialogComponentProps = WithDialogProps<{updating: boolean}> & InjectedFormProps<AddLoginFormData>;
 
 const AddLoginFormFields = () =>
     <>
         <UserField />
         <GroupArrayInput
             name={VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD}
-            input={{id:"Add groups to VM login", disabled:false}}
+            input={{id:"Add groups to VM login (eg: docker, sudo)", disabled:false}}
             required={false}
         />
     </>;
@@ -50,7 +50,7 @@ const UserField = () =>
 const UserSelect = ({ input, meta }: WrappedFieldProps) =>
     <ParticipantSelect
         onlyPeople
-        label='Search for users to grant login permission'
+        label='Search for user to grant login permission'
         items={input.value ? [input.value] : []}
         onSelect={input.onChange}
         onDelete={() => (input.onChange(''))} />;
diff --git a/src/views/virtual-machine-panel/virtual-machine-admin-panel.tsx b/src/views/virtual-machine-panel/virtual-machine-admin-panel.tsx
index bfa6be26..468ef35a 100644
--- a/src/views/virtual-machine-panel/virtual-machine-admin-panel.tsx
+++ b/src/views/virtual-machine-panel/virtual-machine-admin-panel.tsx
@@ -8,7 +8,7 @@ import { Grid, Card, Chip, CardContent, TableBody, TableCell, TableHead, TableRo
 import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
 import { ArvadosTheme } from 'common/custom-theme';
 import { compose, Dispatch } from 'redux';
-import { loadVirtualMachinesAdminData, openAddVirtualMachineLoginDialog, openRemoveVirtualMachineLoginDialog } from 'store/virtual-machines/virtual-machines-actions';
+import { loadVirtualMachinesAdminData, openAddVirtualMachineLoginDialog, openRemoveVirtualMachineLoginDialog, openEditVirtualMachineLoginDialog } from 'store/virtual-machines/virtual-machines-actions';
 import { RootState } from 'store/store';
 import { ListResults } from 'services/common-service/common-service';
 import { MoreOptionsIcon, AddUserIcon } from 'components/icon/icon';
@@ -40,7 +40,7 @@ const mapStateToProps = (state: RootState) => {
     };
 };
 
-const mapDispatchToProps = (dispatch: Dispatch): Pick<VirtualMachinesPanelActionProps, 'loadVirtualMachinesData' | 'onOptionsMenuOpen' | 'onAddLogin' | 'onDeleteLogin'> => ({
+const mapDispatchToProps = (dispatch: Dispatch): Pick<VirtualMachinesPanelActionProps, 'loadVirtualMachinesData' | 'onOptionsMenuOpen' | 'onAddLogin' | 'onDeleteLogin' | 'onLoginEdit'> => ({
     loadVirtualMachinesData: () => dispatch<any>(loadVirtualMachinesAdminData()),
     onOptionsMenuOpen: (event, virtualMachine) => {
         dispatch<any>(openVirtualMachinesContextMenu(event, virtualMachine));
@@ -51,6 +51,9 @@ const mapDispatchToProps = (dispatch: Dispatch): Pick<VirtualMachinesPanelAction
     onDeleteLogin: (uuid: string) => {
         dispatch<any>(openRemoveVirtualMachineLoginDialog(uuid));
     },
+    onLoginEdit: (uuid: string) => {
+        dispatch<any>(openEditVirtualMachineLoginDialog(uuid));
+    },
 });
 
 interface VirtualMachinesPanelDataProps {
@@ -65,6 +68,7 @@ interface VirtualMachinesPanelActionProps {
     onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>, virtualMachine: VirtualMachinesResource) => void;
     onAddLogin: (uuid: string) => void;
     onDeleteLogin: (uuid: string) => void;
+    onLoginEdit: (uuid: string) => void;
 }
 
 type VirtualMachineProps = VirtualMachinesPanelActionProps & VirtualMachinesPanelDataProps & WithStyles<CssRules>;
@@ -117,7 +121,7 @@ const virtualMachinesTable = (props: VirtualMachineProps) =>
                         <Grid container spacing={8} className={props.classes.chipsRoot}>
                             {props.links.items.filter((link) => (link.headUuid === machine.uuid)).map((permission, i) => (
                                 <Grid item key={i}>
-                                    <Chip label={<VirtualMachineLogin linkUuid={permission.uuid} />} onDelete={event => props.onDeleteLogin(permission.uuid)} />
+                                    <Chip label={<VirtualMachineLogin linkUuid={permission.uuid} />} onDelete={event => props.onDeleteLogin(permission.uuid)} onClick={event => props.onLoginEdit(permission.uuid)} />
                                 </Grid>
                             ))}
                         </Grid>

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list