diff --git a/app/controllers/ops_controller.rb b/app/controllers/ops_controller.rb index 447d2feca4d..0318d595bd2 100644 --- a/app/controllers/ops_controller.rb +++ b/app/controllers/ops_controller.rb @@ -583,7 +583,9 @@ def replace_right_cell(options = {}) replace_explorer_trees(replace_trees, presenter) rebuild_toolbars(presenter) - handle_bottom_cell(nodetype, presenter, locals) + unless @hide_bottom_bar + handle_bottom_cell(nodetype, presenter, locals) + end x_active_tree_replace_cell(nodetype, presenter) extra_js_commands(presenter) diff --git a/app/controllers/ops_controller/ops_rbac.rb b/app/controllers/ops_controller/ops_rbac.rb index fb1a370aaff..096fb75d190 100644 --- a/app/controllers/ops_controller/ops_rbac.rb +++ b/app/controllers/ops_controller/ops_rbac.rb @@ -51,13 +51,15 @@ def rbac_tags_edit def rbac_user_add assert_privileges("rbac_user_add") + @hide_bottom_bar = true rbac_edit_reset('new', 'user', User) end def rbac_user_copy # get users id either from gtl check or detail id user_id = params[:miq_grid_checks].presence || params[:id] - user = User.find(user_id) + user = User.find(user_id) + # check if it is allowed to copy the user if rbac_user_copy_restriction?(user) rbac_restricted_user_copy_flash(user) @@ -66,17 +68,17 @@ def rbac_user_copy javascript_flash return end + + @copy_user_id = user_id assert_privileges("rbac_user_copy") + @hide_bottom_bar = true rbac_edit_reset('copy', 'user', User) end def rbac_user_edit assert_privileges("rbac_user_edit") - case params[:button] - when 'cancel' then rbac_edit_cancel('user') - when 'save', 'add' then rbac_edit_save_or_add('user') - when 'reset', nil then rbac_edit_reset(params[:typ], 'user', User) # Reset or first time in - end + @hide_bottom_bar = true + rbac_edit_reset(params[:typ], 'user', User) end def rbac_group_add @@ -185,13 +187,6 @@ def rbac_tenant_tags_edit end end - # AJAX driven routines to check for changes in ANY field on the form - def rbac_user_field_changed - assert_privileges(params[:id] == "new" ? "rbac_user_add" : "rbac_user_edit") - - rbac_field_changed("user") - end - def rbac_group_field_changed assert_privileges(params[:id] == "new" ? "rbac_group_add" : "rbac_group_edit") @@ -660,10 +655,6 @@ def rbac_edit_save_or_add(what, rbac_suffix = what) return unless load_edit("rbac_#{what}_edit__#{id}", "replace_cell__explorer") case key - when :user - record = @edit[:user_id] ? User.find_by(:id => @edit[:user_id]) : User.new - validated = rbac_user_validate? - rbac_user_set_record_vars(record) when :group then record = @edit[:group_id] ? MiqGroup.find_by(:id => @edit[:group_id]) : MiqGroup.new validated = rbac_group_validate? @@ -676,7 +667,6 @@ def rbac_edit_save_or_add(what, rbac_suffix = what) end if record.valid? && validated && record.save! - record.update!(:miq_groups => Rbac.filtered(MiqGroup.where(:id => rbac_user_get_group_ids))) if key == :user # only set miq_groups if everything is valid populate_role_features(record) if what == "role" self.current_user = record if what == 'user' && @edit[:current][:userid] == current_userid AuditEvent.success(build_saved_audit(record, @edit)) @@ -746,13 +736,10 @@ def rbac_field_changed(rec_type) return unless load_edit("rbac_#{rec_type}_edit__#{id}", "replace_cell__explorer") case rec_type - when "user" then rbac_user_get_form_vars when "group" then rbac_group_get_form_vars when "role" then rbac_role_get_form_vars end - @edit[:new][:group] = rbac_user_get_group_ids if rec_type == "user" - session[:changed] = changed = @edit[:new] != @edit[:current] render :update do |page| @@ -764,11 +751,6 @@ def rbac_field_changed(rec_type) page.replace(@refresh_div, :partial => @refresh_partial) end else - # only do following for user (adding/editing a user) - if x_node.split("-").first == "u" || x_node == "xx-u" - page.replace("group_selected", - :partial => "ops/rbac_group_selected") - end # only do following for groups if @refresh_div page.replace(@refresh_div, @@ -966,25 +948,9 @@ def build_rbac_feature_tree # Set form variables for user edit def rbac_user_set_form_vars copy = @sb[:typ] == "copy" - # save a shadow copy of the record if record is being copied - @user = copy ? @record.dup : @record - @user.miq_groups = @record.miq_groups if copy @edit = {:new => {}, :current => {}} @edit[:user_id] = @record.id unless copy - @edit[:key] = "rbac_user_edit__#{@edit[:user_id] || "new"}" - # prefill form fields for edit and copy action - @edit[:new].merge!(:name => @user.name, - :email => @user.email, - :group => @user.miq_groups ? @user.miq_groups.map(&:id).sort : nil) - unless copy - @edit[:new].merge!(:userid => @user.userid, - :password => @user.password, - :verify => @user.password) - end - # load all user groups, filter available for tenant - @edit[:groups] = Rbac.filtered(MiqGroup.non_tenant_groups_in_my_region).sort_by { |g| g.description.downcase }.collect { |g| [g.description, g.id] } - # store current state of the new users information - @edit[:current] = copy_hash(@edit[:new]) + @edit[:new][:userid] = @record.userid @right_cell_text = if @edit[:user_id] _("Editing User \"%{name}\"") % {:name => @record.name} else @@ -992,56 +958,6 @@ def rbac_user_set_form_vars end end - # Get variables from user edit form - def rbac_user_get_form_vars - copy_params_if_present(@edit[:new], params, %i[name password verify]) - - @edit[:new][:userid] = params[:userid].strip.presence if params[:userid] - @edit[:new][:email] = params[:email].strip.presence if params[:email] - @edit[:new][:group] = params[:chosen_group] if params[:chosen_group] - end - - # Set user record variables to new values - def rbac_user_set_record_vars(user) - user.name = @edit[:new][:name] - user.userid = @edit[:new][:userid] - user.email = @edit[:new][:email] - user.password = @edit[:new][:password] if @edit[:new][:password] - end - - # Get array of group ids - def rbac_user_get_group_ids - case @edit[:new][:group] - when 'null', nil - [] - when String - @edit[:new][:group].split(',').delete_if(&:blank?).map(&:to_i).sort - when Array - @edit[:new][:group].map(&:to_i).sort - end - end - - # Validate some of the user fields - def rbac_user_validate? - valid = true - if @edit[:new][:password] != @edit[:new][:verify] - add_flash(_("Password/Verify Password do not match"), :error) - valid = false - end - - new_group_ids = rbac_user_get_group_ids - new_groups = new_group_ids.present? && MiqGroup.find(new_group_ids).present? ? MiqGroup.find(new_group_ids) : [] - - if new_group_ids.blank? - add_flash(_("A User must be assigned to a Group"), :error) - valid = false - elsif Rbac.filtered(new_groups).count != new_group_ids.count - add_flash(_("A User must be assigned to an allowed Group"), :error) - valid = false - end - valid - end - def valid_tenant?(tenant_id) Rbac.filtered(Tenant.in_my_region.where(:id => tenant_id)).present? end diff --git a/app/javascript/components/async-credentials/edit-password-field.jsx b/app/javascript/components/async-credentials/edit-password-field.jsx index 355f63521dc..18720794fd7 100644 --- a/app/javascript/components/async-credentials/edit-password-field.jsx +++ b/app/javascript/components/async-credentials/edit-password-field.jsx @@ -10,7 +10,7 @@ import { useFieldApi, componentTypes } from '@@ddf'; const EditPasswordField = ({ componentClass, ...props }) => { const { - labelText, validateOnMount, isDisabled, editMode, setEditMode, buttonLabel, input, meta, ...rest + labelText, validateOnMount, isDisabled, editMode, setEditMode, buttonLabel, input, meta, icon, kind, ...rest } = useFieldApi(prepareProps(props)); const invalid = (meta.touched || validateOnMount) && meta.error; @@ -58,7 +58,14 @@ const EditPasswordField = ({ componentClass, ...props }) => { { field }
-
diff --git a/app/javascript/components/selected-groups-list/index.jsx b/app/javascript/components/selected-groups-list/index.jsx new file mode 100644 index 00000000000..458ffdec3c0 --- /dev/null +++ b/app/javascript/components/selected-groups-list/index.jsx @@ -0,0 +1,43 @@ +/* eslint-disable jsx-a11y/label-has-associated-control */ +import React from 'react'; +import PropTypes from 'prop-types'; + +const SelectedGroupsList = ({ groups }) => { + const selectedGroups = []; + // console.log(groups); + groups.sort(); + if (groups) { + groups.forEach((group) => { + selectedGroups.push( +
+ +

+ {group} +

+
+
+ ); + }); + } + + return ( +
+ +
+ {selectedGroups} +
+
+ ); +}; + +SelectedGroupsList.propTypes = { + groups: PropTypes.arrayOf(PropTypes.string), +}; + +SelectedGroupsList.defaultProps = { + groups: [], +}; + +export default SelectedGroupsList; diff --git a/app/javascript/components/user-form/helper.js b/app/javascript/components/user-form/helper.js new file mode 100644 index 00000000000..4c494d77b9a --- /dev/null +++ b/app/javascript/components/user-form/helper.js @@ -0,0 +1,54 @@ +const areGroupsEqual = (initialValues, selectedGroups = []) => { + selectedGroups.sort(); + initialValues.groups.sort(); + if (selectedGroups.length !== initialValues.groups.length) { + return false; + } + return selectedGroups.every((group, index) => group === initialValues.groups[index]); +}; + +export const passwordValidation = (initialValues, id, editMode, values, setState, selectedGroups) => { + if (values.groups === undefined) { + if (selectedGroups.length > 0) { + setState((state) => ({ + ...state, + selectedGroups: [], + })); + } + } + const errors = {}; + const groupIds = []; + if (values.groups) { + values.groups.forEach((group) => { + if (group.value) { + groupIds.push(group.value); + } else { + groupIds.push(group); + } + }); + } + if (!editMode && !!id) { + values.password = undefined; + values.confirmPassword = undefined; + if (values.name === initialValues.name + && values.userid === initialValues.userid + && values.email === initialValues.email + && areGroupsEqual(initialValues, groupIds)) { + errors.confirmPassword = ''; + } + } + + if (values.password === undefined) { + if (!!id && editMode) { + errors.password = 'Required'; + } + } + + if (editMode && values.password !== values.confirmPassword) { + errors.confirmPassword = 'Password/Verify Password do not match'; + } + if (!!id === false && values.password !== values.confirmPassword) { + errors.confirmPassword = 'Password/Verify Password do not match'; + } + return errors; +}; diff --git a/app/javascript/components/user-form/index.jsx b/app/javascript/components/user-form/index.jsx new file mode 100644 index 00000000000..86d345cf8f7 --- /dev/null +++ b/app/javascript/components/user-form/index.jsx @@ -0,0 +1,200 @@ +import React, { useState, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import MiqFormRenderer from '@@ddf'; +import { Loading } from 'carbon-components-react'; +import createSchema from './user-form.schema'; +import miqRedirectBack from '../../helpers/miq-redirect-back'; +import { API } from '../../http_api'; +import { passwordValidation } from './helper'; + +const UserForm = ({ + id, copyUserId, disabled, dbMode, +}) => { + const [{ + initialValues, isLoading, editMode, groups, selectedGroups, // Use to populate the custom component + }, setState] = useState({ isLoading: true }); + + useEffect(() => { + if (id) { + Promise.all([API.get('/api/groups?&expand=resources'), API.get(`/api/users/${id}?&attributes=miq_groups`)]) + .then(([{ resources }, userData]) => { + const availableGroups = []; + resources.forEach((group) => { + availableGroups.push({ label: group.description, value: group.id }); + }); + + const selectedGroups = []; + const selectedGroupIds = []; + userData.miq_groups.forEach((group) => { + selectedGroups.push(group.description); + selectedGroupIds.push(group.id); + }); + userData.groups = selectedGroupIds; + userData.selectedGroups = selectedGroups; + setState({ + initialValues: userData, + isLoading: false, + editMode: false, + groups: availableGroups, + selectedGroups, + }); + }); + } else { + const promises = [API.get('/api/groups?&expand=resources')]; + if (copyUserId) { + promises.push(API.get(`/api/users/${copyUserId}?&attributes=miq_groups`)); + } + Promise.all(promises).then(([{ resources }, userData]) => { + const availableGroups = []; + resources.forEach((group) => { + availableGroups.push({ label: group.description, value: group.id }); + }); + + const values = {}; + const selectedGroups = []; + const selectedGroupIds = []; + if (userData) { + if (userData.name) { + values.name = userData.name; + } + if (userData.email) { + values.email = userData.email; + } + if (userData.miq_groups) { + userData.miq_groups.forEach((group) => { + selectedGroups.push(group.description); + selectedGroupIds.push(group.id); + }); + values.groups = selectedGroupIds; + values.selectedGroups = selectedGroups; + } + } + + setState({ + initialValues: values, + isLoading: false, + editMode: false, + groups: availableGroups, + selectedGroups: [], + }); + }); + } + }, []); + + const onSubmit = (values) => { + miqSparkleOn(); + if (values.email === undefined) { + values.email = ''; + } + const groupIds = new Set(); + const sortedGroupIds = []; + const groupIdObjects = []; + values.groups.forEach((group) => { + if (group.value) { + groupIds.add(group.value); + } else { + groupIds.add(group); + } + }); + groupIds.forEach((group) => { + sortedGroupIds.push(group); + }); + sortedGroupIds.sort(); + sortedGroupIds.forEach((group) => { + groupIdObjects.push({ id: group }); + }); + if (id) { + if (values.confirmPassword && values.confirmPassword === values.password) { + API.post(`/api/users/${id}`, + { + action: 'edit', + resource: { + name: values.name, + userid: values.userid, + password: values.password, + email: values.email, + miq_groups: groupIdObjects, + }, + }).then(() => { + miqRedirectBack(`User ${values.name} was saved`, 'success', '/ops/'); + }); + } else { + API.post(`/api/users/${id}`, + { + action: 'edit', + resource: { + name: values.name, + userid: values.userid, + email: values.email, + miq_groups: groupIdObjects, + }, + }).then(() => { + miqRedirectBack(`User ${values.name} was saved`, 'success', '/ops/'); + }); + } + miqSparkleOff(); + } else { + API.post('/api/users', { + name: values.name, + userid: values.userid, + password: values.password, + email: values.email, + miq_groups: groupIdObjects, + }).then(() => { + miqRedirectBack(`User ${values.name} was saved`, 'success', '/ops/'); + }); + miqSparkleOff(); + } + }; + + const onCancel = () => { + const url = '/ops/'; + let message = ''; + message = __('Add of new User was cancelled by the user'); + miqRedirectBack(message, 'success', url); + }; + + const onFormReset = () => { + const temp = initialValues; + temp.selectedGroups = selectedGroups; + setState((state) => ({ + ...state, + initialValues: temp, + editMode: false, + })); + add_flash(__('All changes have been reset'), 'warn'); + }; + + if (isLoading) return ; + return !isLoading && ( +
+ passwordValidation(initialValues, id, editMode, values, setState, selectedGroups)} + onSubmit={onSubmit} + onCancel={onCancel} + canReset={!!id} + onReset={onFormReset} + buttonsLabels={{ + submitLabel: id ? __('Submit') : __('Add'), + }} + /> +
+ ); +}; + +UserForm.propTypes = { + id: PropTypes.number, + copyUserId: PropTypes.number, + disabled: PropTypes.bool, + dbMode: PropTypes.string.isRequired, +}; + +UserForm.defaultProps = { + id: undefined, + copyUserId: undefined, + disabled: false, +}; + +export default UserForm; diff --git a/app/javascript/components/user-form/user-form.schema.js b/app/javascript/components/user-form/user-form.schema.js new file mode 100644 index 00000000000..2545a90af67 --- /dev/null +++ b/app/javascript/components/user-form/user-form.schema.js @@ -0,0 +1,167 @@ +import { componentTypes, validatorTypes } from '@@ddf'; +import { Edit16 } from '@carbon/icons-react'; + +function createSchema(id, editMode, setState, disabled, dbMode, availableGroups, selectedGroups) { + const fields = [ + { + component: componentTypes.TEXT_FIELD, + label: __('Full Name'), + maxLength: 50, + id: 'name', + name: 'name', + isDisabled: disabled, + isRequired: true, + validate: [{ + type: validatorTypes.REQUIRED, + message: __('Required'), + }], + }, + { + component: componentTypes.TEXT_FIELD, + label: __('Username'), + maxLength: 255, + id: 'userid', + name: 'userid', + isDisabled: disabled, + isRequired: true, + validate: [{ + type: validatorTypes.REQUIRED, + message: __('Required'), + }], + }, + ...(dbMode === 'database' || (dbMode !== 'database' && disabled) ? [ + ...(id ? [ + ...(editMode ? [ + { + component: 'edit-password-field', + label: __('Password'), + id: 'password', + name: 'password', + maxLength: 50, + editMode, + disabled: !editMode, + setEditMode: () => { + setState((state) => ({ + ...state, + editMode: !editMode, + })); + }, + placeholder: '●●●●●●●●', + buttonLabel: editMode ? __('Cancel') : __('Change'), + }, + { + component: componentTypes.TEXT_FIELD, + label: __('Confirm Password'), + maxLength: 50, + type: 'password', + id: 'confirmPassword', + name: 'confirmPassword', + initialValue: '', + isRequired: true, + }, + ] : [ + { + component: 'edit-password-field', + label: __('Password'), + maxLength: 50, + id: 'passwordPlaceholder', + name: 'passwordPlaceholder', + icon: Edit16, + kind: 'primary', + editMode, + disabled: true, + setEditMode: () => { + setState((state) => ({ + ...state, + editMode: !editMode, + })); + }, + placeholder: '●●●●●●●●', + buttonLabel: editMode ? __('Cancel') : __('Change'), + }, + ]), + ] : [ + { + component: componentTypes.TEXT_FIELD, + label: __('Password'), + maxLength: 50, + type: 'password', + id: 'password', + name: 'password', + isRequired: true, + validate: [{ + type: validatorTypes.REQUIRED, + message: __('Required'), + }], + }, + { + component: componentTypes.TEXT_FIELD, + label: __('Confirm Password'), + maxLength: 50, + type: 'password', + id: 'confirmPassword', + name: 'confirmPassword', + initialValue: '', + isRequired: true, + validate: [{ + type: validatorTypes.REQUIRED, + message: __('Required'), + }], + }, + ])] : []), + { + component: componentTypes.TEXT_FIELD, + label: __('E-mail Address'), + maxLength: 255, + id: 'email', + name: 'email', + validate: [{ + type: validatorTypes.PATTERN, + pattern: '[a-z0-9._%+-]+@[a-z0-9.-]+.[a-z]{2,}$', + message: __('Email must be a valid email address'), + }], + }, + { + component: componentTypes.SELECT, + label: __('Available Groups'), + id: 'groups', + name: 'groups', + isDisabled: disabled, + isMulti: true, + isRequired: true, + placeholder: __(''), + options: availableGroups, + validate: [{ + type: validatorTypes.REQUIRED, + message: __('Required'), + }], + onChange: (values) => { + const groups = []; + values.forEach((group) => { + if (group.label) { + groups.push(group.label); + } else { + availableGroups.forEach((availableGroup) => { + if (availableGroup.value === group) { + groups.push(availableGroup.label); + } + }); + } + }); + setState((state) => ({ + ...state, + selectedGroups: groups, + })); + }, + }, + { + component: 'selected-groups-list', + label: __('Selected Groups'), + name: 'selected-groups', + groups: selectedGroups, + }, + ]; + return { fields }; +} + +export default createSchema; diff --git a/app/javascript/forms/mappers/componentMapper.jsx b/app/javascript/forms/mappers/componentMapper.jsx index 70cce28946c..f1c84a665a7 100644 --- a/app/javascript/forms/mappers/componentMapper.jsx +++ b/app/javascript/forms/mappers/componentMapper.jsx @@ -13,6 +13,7 @@ import FontIconPickerDdf from '../../components/fonticon-picker/font-icon-picker import KeyValueListComponent from '../../components/key-value-list'; import EmbeddedAutomateEntryPoint from '../../components/embedded-automate-entry-point'; import EmbeddedWorkflowEntryPoint from '../../components/embedded-workflow-entry-point'; +import SelectedGroupsList from '../../components/selected-groups-list'; const mapper = { ...componentMapper, @@ -24,6 +25,7 @@ const mapper = { 'key-value-list': KeyValueListComponent, 'password-field': PasswordField, 'validate-credentials': AsyncCredentials, + 'selected-groups-list': SelectedGroupsList, 'tree-view': TreeViewField, 'tree-selector': TreeViewSelector, [componentTypes.SELECT]: Select, diff --git a/app/javascript/packs/component-definitions-common.js b/app/javascript/packs/component-definitions-common.js index 1b3406d55f9..29c1798510d 100644 --- a/app/javascript/packs/component-definitions-common.js +++ b/app/javascript/packs/component-definitions-common.js @@ -154,6 +154,7 @@ import TimeProfileReportsTable from '../components/data-tables/time-profile-repo import TimeProfileTable from '../components/data-tables/time-profile-table'; import ToastList from '../components/toast-list/toast-list'; import UsageTrendChart from '../components/provider-dashboard-charts/usage-network-image-charts'; +import UserForm from '../components/user-form'; import UtilizationChartGraph from '../components/provider-dashboard-charts/provider-dashboard-utilization-chart'; import VisualSettingsForm from '../components/visual-settings-form'; import VmCommonRenameForm from '../components/vm-common-rename-form'; @@ -342,6 +343,7 @@ ManageIQ.component.addReact('ToastList', ToastList); ManageIQ.component.addReact('Toolbar', Toolbar); ManageIQ.component.addReact('TreeViewRedux', TreeViewRedux); ManageIQ.component.addReact('UsageTrendChart', UsageTrendChart); +ManageIQ.component.addReact('UserForm', UserForm); ManageIQ.component.addReact('UtilizationChartGraph', UtilizationChartGraph); ManageIQ.component.addReact('VisualSettingsForm', VisualSettingsForm); ManageIQ.component.addReact('VmCommonRenameForm', VmCommonRenameForm); diff --git a/app/javascript/spec/action-form/__snapshots__/action-form.spec.js.snap b/app/javascript/spec/action-form/__snapshots__/action-form.spec.js.snap index 9d123c24579..89ace785460 100644 --- a/app/javascript/spec/action-form/__snapshots__/action-form.spec.js.snap +++ b/app/javascript/spec/action-form/__snapshots__/action-form.spec.js.snap @@ -832,6 +832,7 @@ exports[`Action Form Component should render adding a new action 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -1546,6 +1547,7 @@ exports[`Action Form Component should render adding a new action 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/add-remove-security-groups-form/__snapshots__/add-remove-security-groups-form.spec.js.snap b/app/javascript/spec/add-remove-security-groups-form/__snapshots__/add-remove-security-groups-form.spec.js.snap index 72d8afdddbf..e6304bd9e04 100644 --- a/app/javascript/spec/add-remove-security-groups-form/__snapshots__/add-remove-security-groups-form.spec.js.snap +++ b/app/javascript/spec/add-remove-security-groups-form/__snapshots__/add-remove-security-groups-form.spec.js.snap @@ -146,6 +146,7 @@ exports[`Add/remove security groups form component should remove security group "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -212,6 +213,7 @@ exports[`Add/remove security groups form component should remove security group "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/ansible-credentials-form/__snapshots__/ansible-credentials-form.spec.js.snap b/app/javascript/spec/ansible-credentials-form/__snapshots__/ansible-credentials-form.spec.js.snap index bf8f651ffc5..a95ae56da72 100644 --- a/app/javascript/spec/ansible-credentials-form/__snapshots__/ansible-credentials-form.spec.js.snap +++ b/app/javascript/spec/ansible-credentials-form/__snapshots__/ansible-credentials-form.spec.js.snap @@ -106,6 +106,7 @@ exports[`Ansible Credential Form Component should render adding a new credential "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -202,6 +203,7 @@ exports[`Ansible Credential Form Component should render adding a new credential "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -1595,6 +1597,7 @@ exports[`Ansible Credential Form Component should render editing a credential 1` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -1698,6 +1701,7 @@ exports[`Ansible Credential Form Component should render editing a credential 1` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/ansible-edit-catalog-form/__snapshots__/ansible-edit-catalog-form.spec.js.snap b/app/javascript/spec/ansible-edit-catalog-form/__snapshots__/ansible-edit-catalog-form.spec.js.snap index d046f049e1a..982247af4bb 100644 --- a/app/javascript/spec/ansible-edit-catalog-form/__snapshots__/ansible-edit-catalog-form.spec.js.snap +++ b/app/javascript/spec/ansible-edit-catalog-form/__snapshots__/ansible-edit-catalog-form.spec.js.snap @@ -1323,6 +1323,7 @@ exports[`Ansible playbook edit catalog Form Component should not render some fie "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -3535,6 +3536,7 @@ exports[`Ansible playbook edit catalog Form Component should not render some fie "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -5754,6 +5756,7 @@ exports[`Ansible playbook edit catalog Form Component should not render some fie "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -59566,6 +59569,7 @@ exports[`Ansible playbook edit catalog Form Component should render correct form "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -61787,6 +61791,7 @@ exports[`Ansible playbook edit catalog Form Component should render correct form "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -64015,6 +64020,7 @@ exports[`Ansible playbook edit catalog Form Component should render correct form "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -120752,6 +120758,7 @@ exports[`Ansible playbook edit catalog Form Component should render retirement p "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -122964,6 +122971,7 @@ exports[`Ansible playbook edit catalog Form Component should render retirement p "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -125183,6 +125191,7 @@ exports[`Ansible playbook edit catalog Form Component should render retirement p "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/c-and-u-collections-form/__snapshots__/c-and-u-collections-form.spec.js.snap b/app/javascript/spec/c-and-u-collections-form/__snapshots__/c-and-u-collections-form.spec.js.snap index bd5a0a74490..7b027908866 100644 --- a/app/javascript/spec/c-and-u-collections-form/__snapshots__/c-and-u-collections-form.spec.js.snap +++ b/app/javascript/spec/c-and-u-collections-form/__snapshots__/c-and-u-collections-form.spec.js.snap @@ -112,6 +112,7 @@ exports[`DiagnosticsCURepairForm Component Should add a record from DiagnosticsC "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -224,6 +225,7 @@ exports[`DiagnosticsCURepairForm Component Should add a record from DiagnosticsC "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/cloud-database-form/__snapshots__/cloud-database-form.spec.js.snap b/app/javascript/spec/cloud-database-form/__snapshots__/cloud-database-form.spec.js.snap index 565a9d709b6..54afbbbbc2b 100644 --- a/app/javascript/spec/cloud-database-form/__snapshots__/cloud-database-form.spec.js.snap +++ b/app/javascript/spec/cloud-database-form/__snapshots__/cloud-database-form.spec.js.snap @@ -144,6 +144,7 @@ exports[`Cloud Database form component should render "Edit" form 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -229,6 +230,7 @@ exports[`Cloud Database form component should render "Edit" form 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/cloud-object-store-container-form/__snapshots__/cloud-object-store-container-form.spec.js.snap b/app/javascript/spec/cloud-object-store-container-form/__snapshots__/cloud-object-store-container-form.spec.js.snap index cda9a34a03e..17458b29449 100644 --- a/app/javascript/spec/cloud-object-store-container-form/__snapshots__/cloud-object-store-container-form.spec.js.snap +++ b/app/javascript/spec/cloud-object-store-container-form/__snapshots__/cloud-object-store-container-form.spec.js.snap @@ -76,6 +76,7 @@ exports[`Cloud Object Store Container form component should add Amazon cloud obj "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -143,6 +144,7 @@ exports[`Cloud Object Store Container form component should add Amazon cloud obj "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -998,6 +1000,7 @@ exports[`Cloud Object Store Container form component should add Openstack cloud "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -1065,6 +1068,7 @@ exports[`Cloud Object Store Container form component should add Openstack cloud "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -1896,6 +1900,7 @@ exports[`Cloud Object Store Container form component should render add cloud obj "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -1963,6 +1968,7 @@ exports[`Cloud Object Store Container form component should render add cloud obj "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/cloud-volume-actions-form/__snapshots__/cloud-volume-actions-form.spec.js.snap b/app/javascript/spec/cloud-volume-actions-form/__snapshots__/cloud-volume-actions-form.spec.js.snap index aaa7be01fdd..fdcae04c002 100644 --- a/app/javascript/spec/cloud-volume-actions-form/__snapshots__/cloud-volume-actions-form.spec.js.snap +++ b/app/javascript/spec/cloud-volume-actions-form/__snapshots__/cloud-volume-actions-form.spec.js.snap @@ -108,6 +108,7 @@ exports[`Cloud Volume Backup Create form component should render the cloud volum "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -203,6 +204,7 @@ exports[`Cloud Volume Backup Create form component should render the cloud volum "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -1652,6 +1654,7 @@ exports[`Cloud Volume Backup Create form component when adding a new backup of c "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -1747,6 +1750,7 @@ exports[`Cloud Volume Backup Create form component when adding a new backup of c "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -3176,6 +3180,7 @@ exports[`Cloud Volume Restore from backup form component should render the cloud "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -3251,6 +3256,7 @@ exports[`Cloud Volume Restore from backup form component should render the cloud "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -4273,6 +4279,7 @@ exports[`Cloud Volume Restore from backup form component when restoring cloud vo "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -4348,6 +4355,7 @@ exports[`Cloud Volume Restore from backup form component when restoring cloud vo "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -5362,6 +5370,7 @@ exports[`Cloud Volume Snapshot Create form component should render the cloud vol "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -5429,6 +5438,7 @@ exports[`Cloud Volume Snapshot Create form component should render the cloud vol "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -6217,6 +6227,7 @@ exports[`Cloud Volume Snapshot Create form component when adding a new snapshot "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -6284,6 +6295,7 @@ exports[`Cloud Volume Snapshot Create form component when adding a new snapshot "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/cloud-volume-form/__snapshots__/attach-detach-cloud-volume-form.spec.js.snap b/app/javascript/spec/cloud-volume-form/__snapshots__/attach-detach-cloud-volume-form.spec.js.snap index bc59b82ebdd..884d1cc772a 100644 --- a/app/javascript/spec/cloud-volume-form/__snapshots__/attach-detach-cloud-volume-form.spec.js.snap +++ b/app/javascript/spec/cloud-volume-form/__snapshots__/attach-detach-cloud-volume-form.spec.js.snap @@ -139,6 +139,7 @@ exports[`Attach / Detach form component should render Attach Cloud Volume to the "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -235,6 +236,7 @@ exports[`Attach / Detach form component should render Attach Cloud Volume to the "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -1406,6 +1408,7 @@ exports[`Attach / Detach form component should render Attach Selected Cloud Volu "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -1502,6 +1505,7 @@ exports[`Attach / Detach form component should render Attach Selected Cloud Volu "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -2660,6 +2664,7 @@ exports[`Attach / Detach form component should render Detach Cloud Volume from t "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -2743,6 +2748,7 @@ exports[`Attach / Detach form component should render Detach Cloud Volume from t "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -3707,6 +3713,7 @@ exports[`Attach / Detach form component should render Detach Selected Cloud Volu "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -3790,6 +3797,7 @@ exports[`Attach / Detach form component should render Detach Selected Cloud Volu "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -4769,6 +4777,7 @@ exports[`Attach / Detach form component should submit Attach API call 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -4865,6 +4874,7 @@ exports[`Attach / Detach form component should submit Attach API call 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -6023,6 +6033,7 @@ exports[`Attach / Detach form component should submit Detach API call 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -6106,6 +6117,7 @@ exports[`Attach / Detach form component should submit Detach API call 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/data-store-fore/__snapshots__/datastore-form.spec.js.snap b/app/javascript/spec/data-store-fore/__snapshots__/datastore-form.spec.js.snap index caeb23bc7c3..048385dd71a 100644 --- a/app/javascript/spec/data-store-fore/__snapshots__/datastore-form.spec.js.snap +++ b/app/javascript/spec/data-store-fore/__snapshots__/datastore-form.spec.js.snap @@ -181,6 +181,7 @@ exports[`Datastore form component Datastore domain form component should render "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -280,6 +281,7 @@ exports[`Datastore form component Datastore domain form component should render "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -1773,6 +1775,7 @@ exports[`Datastore form component Datastore namespace form component should rend "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -1875,6 +1878,7 @@ exports[`Datastore form component Datastore namespace form component should rend "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/embedded-terraform-credentials-form/__snapshots__/embedded-terraform-credentials-form.spec.js.snap b/app/javascript/spec/embedded-terraform-credentials-form/__snapshots__/embedded-terraform-credentials-form.spec.js.snap index cde9915dbab..dd42a6a44f5 100644 --- a/app/javascript/spec/embedded-terraform-credentials-form/__snapshots__/embedded-terraform-credentials-form.spec.js.snap +++ b/app/javascript/spec/embedded-terraform-credentials-form/__snapshots__/embedded-terraform-credentials-form.spec.js.snap @@ -107,6 +107,7 @@ exports[`Embedded Terraform Credential Form Component should render adding a new "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -204,6 +205,7 @@ exports[`Embedded Terraform Credential Form Component should render adding a new "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -1618,6 +1620,7 @@ exports[`Embedded Terraform Credential Form Component should render editing a cr "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -1722,6 +1725,7 @@ exports[`Embedded Terraform Credential Form Component should render editing a cr "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/evacuate-form/__snapshots__/evacuate-form.spec.js.snap b/app/javascript/spec/evacuate-form/__snapshots__/evacuate-form.spec.js.snap index 8fd83cfdd8f..6815c989546 100644 --- a/app/javascript/spec/evacuate-form/__snapshots__/evacuate-form.spec.js.snap +++ b/app/javascript/spec/evacuate-form/__snapshots__/evacuate-form.spec.js.snap @@ -133,6 +133,7 @@ exports[`evacuate form component should render evacuate form when hosts empty 1` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -247,6 +248,7 @@ exports[`evacuate form component should render evacuate form when hosts empty 1` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -2070,6 +2072,7 @@ exports[`evacuate form component should render evacuate form with host options 1 "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -2205,6 +2208,7 @@ exports[`evacuate form component should render evacuate form with host options 1 "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -4387,6 +4391,7 @@ exports[`evacuate form component should render evacuate form with multiple insta "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -4501,6 +4506,7 @@ exports[`evacuate form component should render evacuate form with multiple insta "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/generic-objects-form/__snapshots__/generic-objects-form.spec.js.snap b/app/javascript/spec/generic-objects-form/__snapshots__/generic-objects-form.spec.js.snap index 3bfdf125352..f1dbb624af6 100644 --- a/app/javascript/spec/generic-objects-form/__snapshots__/generic-objects-form.spec.js.snap +++ b/app/javascript/spec/generic-objects-form/__snapshots__/generic-objects-form.spec.js.snap @@ -46,6 +46,7 @@ exports[`Generic Object Form Component should render adding a new generic object "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -307,6 +308,7 @@ exports[`Generic Object Form Component should render adding a new generic object "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -571,6 +573,7 @@ exports[`Generic Object Form Component should render adding a new generic object "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -4652,6 +4655,7 @@ exports[`Generic Object Form Component should render editing a generic object wi "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -4971,6 +4975,7 @@ exports[`Generic Object Form Component should render editing a generic object wi "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -5293,6 +5298,7 @@ exports[`Generic Object Form Component should render editing a generic object wi "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -12282,6 +12288,7 @@ exports[`Generic Object Form Component should render editing a generic object wi "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -12598,6 +12605,7 @@ exports[`Generic Object Form Component should render editing a generic object wi "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -12917,6 +12925,7 @@ exports[`Generic Object Form Component should render editing a generic object wi "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/host-aggregate-form/__snapshots__/host-aggregate-form.spec.js.snap b/app/javascript/spec/host-aggregate-form/__snapshots__/host-aggregate-form.spec.js.snap index abe7e1d952e..ba3beb48f72 100644 --- a/app/javascript/spec/host-aggregate-form/__snapshots__/host-aggregate-form.spec.js.snap +++ b/app/javascript/spec/host-aggregate-form/__snapshots__/host-aggregate-form.spec.js.snap @@ -102,6 +102,7 @@ exports[`Host aggregate form component should render add host form variant (remv "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -163,6 +164,7 @@ exports[`Host aggregate form component should render add host form variant (remv "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/host-edit-form/__snapshots__/host-edit-form.spec.js.snap b/app/javascript/spec/host-edit-form/__snapshots__/host-edit-form.spec.js.snap index 9e7faa30795..1057ebef1db 100644 --- a/app/javascript/spec/host-edit-form/__snapshots__/host-edit-form.spec.js.snap +++ b/app/javascript/spec/host-edit-form/__snapshots__/host-edit-form.spec.js.snap @@ -47,6 +47,7 @@ exports[`Show Edit Host Form Component should render form for *one* host 1`] = ` "protocol-selector": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -270,6 +271,7 @@ exports[`Show Edit Host Form Component should render form for *one* host 1`] = ` "protocol-selector": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -500,6 +502,7 @@ exports[`Show Edit Host Form Component should render form for *one* host 1`] = ` "protocol-selector": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -5541,6 +5544,7 @@ exports[`Show Edit Host Form Component should render form for multiple hosts 1`] "protocol-selector": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -5603,6 +5607,7 @@ exports[`Show Edit Host Form Component should render form for multiple hosts 1`] "protocol-selector": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -5672,6 +5677,7 @@ exports[`Show Edit Host Form Component should render form for multiple hosts 1`] "protocol-selector": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/host-initiator-group-form/__snapshots__/host-initiator-group.spec.js.snap b/app/javascript/spec/host-initiator-group-form/__snapshots__/host-initiator-group.spec.js.snap index 165568fa6d0..b8d86f17718 100644 --- a/app/javascript/spec/host-initiator-group-form/__snapshots__/host-initiator-group.spec.js.snap +++ b/app/javascript/spec/host-initiator-group-form/__snapshots__/host-initiator-group.spec.js.snap @@ -115,6 +115,7 @@ exports[`Host Initiator Group Form Loads data and renders 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -219,6 +220,7 @@ exports[`Host Initiator Group Form Loads data and renders 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/live-migrate-form/__snapshots__/live-migrate-form.spec.js.snap b/app/javascript/spec/live-migrate-form/__snapshots__/live-migrate-form.spec.js.snap index 424de5b17c7..53837b0b900 100644 --- a/app/javascript/spec/live-migrate-form/__snapshots__/live-migrate-form.spec.js.snap +++ b/app/javascript/spec/live-migrate-form/__snapshots__/live-migrate-form.spec.js.snap @@ -125,6 +125,7 @@ exports[`Live Migrate form component should render live migrate form when hosts "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -237,6 +238,7 @@ exports[`Live Migrate form component should render live migrate form when hosts "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -2006,6 +2008,7 @@ exports[`Live Migrate form component should render live migrate form with host o "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -2139,6 +2142,7 @@ exports[`Live Migrate form component should render live migrate form with host o "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -4267,6 +4271,7 @@ exports[`Live Migrate form component should render live migrate form with multip "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -4379,6 +4384,7 @@ exports[`Live Migrate form component should render live migrate form with multip "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/physical-storage-form/__snapshots__/physical-storage-form.spec.js.snap b/app/javascript/spec/physical-storage-form/__snapshots__/physical-storage-form.spec.js.snap index 183b6212b45..8bd08cbcbd5 100644 --- a/app/javascript/spec/physical-storage-form/__snapshots__/physical-storage-form.spec.js.snap +++ b/app/javascript/spec/physical-storage-form/__snapshots__/physical-storage-form.spec.js.snap @@ -36,6 +36,7 @@ exports[`Physical storage form component should render adding form variant 1`] = "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -312,6 +313,7 @@ exports[`Physical storage form component should render editing form variant 1`] "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -563,6 +565,7 @@ exports[`Physical storage form component should render editing form variant 1`] "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -817,6 +820,7 @@ exports[`Physical storage form component should render editing form variant 1`] "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/pxe-customization-template-form/__snapshots__/pxe-customization-template-form.spec.js.snap b/app/javascript/spec/pxe-customization-template-form/__snapshots__/pxe-customization-template-form.spec.js.snap index 791bd8563af..f317184633c 100644 --- a/app/javascript/spec/pxe-customization-template-form/__snapshots__/pxe-customization-template-form.spec.js.snap +++ b/app/javascript/spec/pxe-customization-template-form/__snapshots__/pxe-customization-template-form.spec.js.snap @@ -145,6 +145,7 @@ exports[`Pxe Customization Template Form Component should render adding a new px "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -274,6 +275,7 @@ exports[`Pxe Customization Template Form Component should render adding a new px "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -2777,6 +2779,7 @@ exports[`Pxe Customization Template Form Component should render copying a pxe c "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -2915,6 +2918,7 @@ exports[`Pxe Customization Template Form Component should render copying a pxe c "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -5445,6 +5449,7 @@ exports[`Pxe Customization Template Form Component should render editing a pxe c "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -5583,6 +5588,7 @@ exports[`Pxe Customization Template Form Component should render editing a pxe c "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/pxe-image-type-form/__snapshots__/pxe-image-type-form.spec.js.snap b/app/javascript/spec/pxe-image-type-form/__snapshots__/pxe-image-type-form.spec.js.snap index 9157994f317..fcb00cbfef0 100644 --- a/app/javascript/spec/pxe-image-type-form/__snapshots__/pxe-image-type-form.spec.js.snap +++ b/app/javascript/spec/pxe-image-type-form/__snapshots__/pxe-image-type-form.spec.js.snap @@ -100,6 +100,7 @@ exports[`Pxe Image Type Form Component should render adding a new pxe image type "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -190,6 +191,7 @@ exports[`Pxe Image Type Form Component should render adding a new pxe image type "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -1604,6 +1606,7 @@ exports[`Pxe Image Type Form Component should render editing a pxe image type 1` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -1700,6 +1703,7 @@ exports[`Pxe Image Type Form Component should render editing a pxe image type 1` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/pxe-iso-datastore-form/__snapshots__/pxe-iso-datastore-form.spec.js.snap b/app/javascript/spec/pxe-iso-datastore-form/__snapshots__/pxe-iso-datastore-form.spec.js.snap index 885c991ac0a..9ec85abcba1 100644 --- a/app/javascript/spec/pxe-iso-datastore-form/__snapshots__/pxe-iso-datastore-form.spec.js.snap +++ b/app/javascript/spec/pxe-iso-datastore-form/__snapshots__/pxe-iso-datastore-form.spec.js.snap @@ -105,6 +105,7 @@ exports[`Pxe Iso Datastore Form Component should render adding a new iso datasto "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -188,6 +189,7 @@ exports[`Pxe Iso Datastore Form Component should render adding a new iso datasto "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/pxe-iso-image-form/__snapshots__/pxe-iso-image-form.spec.js.snap b/app/javascript/spec/pxe-iso-image-form/__snapshots__/pxe-iso-image-form.spec.js.snap index 1de51401fe7..378f352cd21 100644 --- a/app/javascript/spec/pxe-iso-image-form/__snapshots__/pxe-iso-image-form.spec.js.snap +++ b/app/javascript/spec/pxe-iso-image-form/__snapshots__/pxe-iso-image-form.spec.js.snap @@ -86,6 +86,7 @@ exports[`Pxe Edit Iso Image Form Component should render editing a iso image 1`] "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -160,6 +161,7 @@ exports[`Pxe Edit Iso Image Form Component should render editing a iso image 1`] "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/reconfigure-vm-form/__snapshots__/reconfigure-vm-form.spec.js.snap b/app/javascript/spec/reconfigure-vm-form/__snapshots__/reconfigure-vm-form.spec.js.snap index fb6094539ac..9204b9a5210 100644 --- a/app/javascript/spec/reconfigure-vm-form/__snapshots__/reconfigure-vm-form.spec.js.snap +++ b/app/javascript/spec/reconfigure-vm-form/__snapshots__/reconfigure-vm-form.spec.js.snap @@ -109,6 +109,7 @@ exports[`Reconfigure VM form component should render form with only fields it ha "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -418,6 +419,7 @@ exports[`Reconfigure VM form component should render form with only fields it ha "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -732,6 +734,7 @@ exports[`Reconfigure VM form component should render form with only fields it ha "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -4602,6 +4605,7 @@ exports[`Reconfigure VM form component should render reconfigure form and click "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -5015,6 +5019,7 @@ exports[`Reconfigure VM form component should render reconfigure form and click "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -5433,6 +5438,7 @@ exports[`Reconfigure VM form component should render reconfigure form and click "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -15957,6 +15963,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show c "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -16072,6 +16079,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show c "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -16192,6 +16200,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show c "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -17435,6 +17444,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show d "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -17655,6 +17665,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show d "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -17880,6 +17891,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show d "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -21239,6 +21251,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show d "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -21459,6 +21472,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show d "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -21684,6 +21698,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show d "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -25022,6 +25037,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show h "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -25248,6 +25264,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show h "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -25479,6 +25496,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show h "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -30082,6 +30100,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show n "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -30227,6 +30246,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show n "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -30377,6 +30397,7 @@ exports[`Reconfigure VM form component should render reconfigure form and show n "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -32194,6 +32215,7 @@ exports[`Reconfigure VM form component should render reconfigure form with datat "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -32608,6 +32630,7 @@ exports[`Reconfigure VM form component should render reconfigure form with datat "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -33027,6 +33050,7 @@ exports[`Reconfigure VM form component should render reconfigure form with datat "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -43724,6 +43748,7 @@ exports[`Reconfigure VM form component should render reconfigure form without da "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -43950,6 +43975,7 @@ exports[`Reconfigure VM form component should render reconfigure form without da "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -44181,6 +44207,7 @@ exports[`Reconfigure VM form component should render reconfigure form without da "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -48784,6 +48811,7 @@ exports[`Reconfigure VM form component should render reconfigure sub form and cl "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -49196,6 +49224,7 @@ exports[`Reconfigure VM form component should render reconfigure sub form and cl "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -49613,6 +49642,7 @@ exports[`Reconfigure VM form component should render reconfigure sub form and cl "radio": [Function], "reconfigure-table": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/schedule-form/__snapshots__/schedule-form.spec.js.snap b/app/javascript/spec/schedule-form/__snapshots__/schedule-form.spec.js.snap index 4b0ba541a76..84a38796e66 100644 --- a/app/javascript/spec/schedule-form/__snapshots__/schedule-form.spec.js.snap +++ b/app/javascript/spec/schedule-form/__snapshots__/schedule-form.spec.js.snap @@ -737,6 +737,7 @@ exports[`Schedule form component should render edit form when filter_type is not "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -1380,6 +1381,7 @@ exports[`Schedule form component should render edit form when filter_type is not "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -15556,6 +15558,7 @@ exports[`Schedule form component should render edit form when filter_type is nul "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -16341,6 +16344,7 @@ exports[`Schedule form component should render edit form when filter_type is nul "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -33750,6 +33754,7 @@ exports[`Schedule form component should render schedule add form 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -34316,6 +34321,7 @@ exports[`Schedule form component should render schedule add form 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/service-request-default-form/__snapshots__/service-request-default-form.spec.js.snap b/app/javascript/spec/service-request-default-form/__snapshots__/service-request-default-form.spec.js.snap index 9974503a718..3a2ee28417a 100644 --- a/app/javascript/spec/service-request-default-form/__snapshots__/service-request-default-form.spec.js.snap +++ b/app/javascript/spec/service-request-default-form/__snapshots__/service-request-default-form.spec.js.snap @@ -336,6 +336,7 @@ exports[`Show Service Request Page should render 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -540,6 +541,7 @@ exports[`Show Service Request Page should render 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/settings-category-form/__snapshots__/settings-category-form.spec.js.snap b/app/javascript/spec/settings-category-form/__snapshots__/settings-category-form.spec.js.snap index 911a57d8572..ba891ac282f 100644 --- a/app/javascript/spec/settings-category-form/__snapshots__/settings-category-form.spec.js.snap +++ b/app/javascript/spec/settings-category-form/__snapshots__/settings-category-form.spec.js.snap @@ -147,6 +147,7 @@ exports[`SettingsCategoryForm Component should render a new SettingsCategoryForm "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -282,6 +283,7 @@ exports[`SettingsCategoryForm Component should render a new SettingsCategoryForm "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/settings-time-profile-form/__snapshots__/settings-time-profile-form.spec.js.snap b/app/javascript/spec/settings-time-profile-form/__snapshots__/settings-time-profile-form.spec.js.snap index f55f28a80b2..fbce04573fa 100644 --- a/app/javascript/spec/settings-time-profile-form/__snapshots__/settings-time-profile-form.spec.js.snap +++ b/app/javascript/spec/settings-time-profile-form/__snapshots__/settings-time-profile-form.spec.js.snap @@ -507,6 +507,7 @@ exports[`VM common form component should render adding form variant add new time "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -1008,6 +1009,7 @@ exports[`VM common form component should render adding form variant add new time "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/user-form/__snapshots__/user-form.spec.js.snap b/app/javascript/spec/user-form/__snapshots__/user-form.spec.js.snap new file mode 100644 index 00000000000..132cf306658 --- /dev/null +++ b/app/javascript/spec/user-form/__snapshots__/user-form.spec.js.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`User Form Component should render add User form correctly 1`] = ` + +`; + +exports[`User Form Component should render copy User form correclty 1`] = ` + +`; + +exports[`User Form Component should render edit Admin User form correclty 1`] = ` + +`; + +exports[`User Form Component should render edit User form correclty 1`] = ` + +`; diff --git a/app/javascript/spec/user-form/user-form.spec.js b/app/javascript/spec/user-form/user-form.spec.js new file mode 100644 index 00000000000..6cf54a6c61c --- /dev/null +++ b/app/javascript/spec/user-form/user-form.spec.js @@ -0,0 +1,99 @@ +import React from 'react'; +import fetchMock from 'fetch-mock'; +import { shallow } from 'enzyme'; +import toJson from 'enzyme-to-json'; +import UserForm from '../../components/user-form/index'; + +describe('User Form Component', () => { + const groupsMockData = [ + { + href: 'http://localhost:3000/api/groups/2', + id: '2', + description: 'EvmGroup-super_adminstrator', + }, + { + href: 'http://localhost:3000/api/groups/3', + id: '3', + description: 'EvmGroup-operator', + }, + { + href: 'http://localhost:3000/api/groups/4', + id: '4', + description: 'EvmGroup-user', + }, + ]; + + const userMockData = { + current_group_id: '40', + email: 'test@email.com', + id: '41', + name: 'test name', + userid: 'testuser', + }; + + const adminMockData = { + current_group_id: '40', + email: 'test@email.com', + id: '1', + name: 'Administrator', + userid: 'admin', + }; + + const userData = { + current_group_id: '2', + email: 'test@email.com', + name: 'test name', + userid: 'testuser', + }; + + afterEach(() => { + fetchMock.reset(); + fetchMock.restore(); + }); + + it('should render add User form correctly', async(done) => { + const wrapper = shallow(); + fetchMock.get('/api/groups?&expand=resources', groupsMockData); + + setImmediate(() => { + wrapper.update(); + expect(toJson(wrapper)).toMatchSnapshot(); + done(); + }); + }); + + it('should render edit User form correclty', async(done) => { + const wrapper = shallow(); + fetchMock.get('/api/groups?&expand=resources', groupsMockData); + fetchMock.get('/api/users/41', userMockData); + + setImmediate(() => { + wrapper.update(); + expect(toJson(wrapper)).toMatchSnapshot(); + done(); + }); + }); + + it('should render edit Admin User form correclty', async(done) => { + const wrapper = shallow(); + fetchMock.get('/api/groups?&expand=resources', groupsMockData); + fetchMock.get('/api/users/1', adminMockData); + + setImmediate(() => { + wrapper.update(); + expect(toJson(wrapper)).toMatchSnapshot(); + done(); + }); + }); + + it('should render copy User form correclty', async(done) => { + const wrapper = shallow(); + fetchMock.get('/api/groups?&expand=resources', groupsMockData); + + setImmediate(() => { + wrapper.update(); + expect(toJson(wrapper)).toMatchSnapshot(); + done(); + }); + }); +}); diff --git a/app/javascript/spec/vm-floating-ips-form/__snapshots__/vm-floating-ips-form.spec.js.snap b/app/javascript/spec/vm-floating-ips-form/__snapshots__/vm-floating-ips-form.spec.js.snap index e0249f182c7..83ce08873d7 100644 --- a/app/javascript/spec/vm-floating-ips-form/__snapshots__/vm-floating-ips-form.spec.js.snap +++ b/app/javascript/spec/vm-floating-ips-form/__snapshots__/vm-floating-ips-form.spec.js.snap @@ -69,6 +69,7 @@ exports[`Associate / Disassociate form component should render associate form va "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -135,6 +136,7 @@ exports[`Associate / Disassociate form component should render associate form va "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -1101,6 +1103,7 @@ exports[`Associate / Disassociate form component should render disassociate form "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -1167,6 +1170,7 @@ exports[`Associate / Disassociate form component should render disassociate form "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -2160,6 +2164,7 @@ exports[`Associate / Disassociate form component should submit Associate API cal "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -2226,6 +2231,7 @@ exports[`Associate / Disassociate form component should submit Associate API cal "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -3072,6 +3078,7 @@ exports[`Associate / Disassociate form component should submit Disassociate API "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -3138,6 +3145,7 @@ exports[`Associate / Disassociate form component should submit Disassociate API "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/vm-resize-form/__snapshots__/vm-resize-form.spec.js.snap b/app/javascript/spec/vm-resize-form/__snapshots__/vm-resize-form.spec.js.snap index 15a030ad2b2..470650cc69d 100644 --- a/app/javascript/spec/vm-resize-form/__snapshots__/vm-resize-form.spec.js.snap +++ b/app/javascript/spec/vm-resize-form/__snapshots__/vm-resize-form.spec.js.snap @@ -79,6 +79,7 @@ exports[`vm resize form component should render a resize form 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -146,6 +147,7 @@ exports[`vm resize form component should render a resize form 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/workflow-credential-mapping-form/__snapshots__/workflow-credential-mapping-form.spec.js.snap b/app/javascript/spec/workflow-credential-mapping-form/__snapshots__/workflow-credential-mapping-form.spec.js.snap index 46dbe52751e..3d9dd8266e3 100644 --- a/app/javascript/spec/workflow-credential-mapping-form/__snapshots__/workflow-credential-mapping-form.spec.js.snap +++ b/app/javascript/spec/workflow-credential-mapping-form/__snapshots__/workflow-credential-mapping-form.spec.js.snap @@ -72,6 +72,7 @@ exports[`Workflow Credential Form Component should render mapping credentials to "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -261,6 +262,7 @@ exports[`Workflow Credential Form Component should render mapping credentials to "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -453,6 +455,7 @@ exports[`Workflow Credential Form Component should render mapping credentials to "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/workflow-credentials-form/__snapshots__/workflow-credentials-form.spec.js.snap b/app/javascript/spec/workflow-credentials-form/__snapshots__/workflow-credentials-form.spec.js.snap index 3c8754b5f07..fa355b7ffbf 100644 --- a/app/javascript/spec/workflow-credentials-form/__snapshots__/workflow-credentials-form.spec.js.snap +++ b/app/javascript/spec/workflow-credentials-form/__snapshots__/workflow-credentials-form.spec.js.snap @@ -107,6 +107,7 @@ exports[`Workflow Credential Form Component should render adding a new credentia "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -204,6 +205,7 @@ exports[`Workflow Credential Form Component should render adding a new credentia "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], @@ -1618,6 +1620,7 @@ exports[`Workflow Credential Form Component should render editing a credential 1 "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -1722,6 +1725,7 @@ exports[`Workflow Credential Form Component should render editing a credential 1 "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/javascript/spec/zone-form/__snapshots__/zone-form.spec.js.snap b/app/javascript/spec/zone-form/__snapshots__/zone-form.spec.js.snap index 7f7416f31a0..8302a222d06 100644 --- a/app/javascript/spec/zone-form/__snapshots__/zone-form.spec.js.snap +++ b/app/javascript/spec/zone-form/__snapshots__/zone-form.spec.js.snap @@ -321,6 +321,7 @@ exports[`zone Form Component should render editing a zone form 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "sub-form": [Function], "switch": [Function], @@ -494,6 +495,7 @@ exports[`zone Form Component should render editing a zone form 1`] = ` "plain-text": [Function], "radio": [Function], "select": [Function], + "selected-groups-list": [Function], "slider": [Function], "spy-field": [Function], "sub-form": [Function], diff --git a/app/stylesheet/application-webpack.scss b/app/stylesheet/application-webpack.scss index 51aaf564eb8..9c5a81f6fa0 100644 --- a/app/stylesheet/application-webpack.scss +++ b/app/stylesheet/application-webpack.scss @@ -32,3 +32,4 @@ @import './widget.scss'; @import './workflows.scss'; @import './cloud-container-projects-dashboard.scss'; +@import './selected-groups-list.scss'; diff --git a/app/stylesheet/ddf_override.scss b/app/stylesheet/ddf_override.scss index fa6e599fbe5..e2ca8632184 100644 --- a/app/stylesheet/ddf_override.scss +++ b/app/stylesheet/ddf_override.scss @@ -526,3 +526,18 @@ margin-right: 5%; } } + +.user-form { + #passwordWarning { + color: #da1e28; + font-size: 14px; + } + + .custom-button-wrapper { + margin-top: 10px; + + .submit-button { + margin-right: 8px; + } + } +} diff --git a/app/stylesheet/selected-groups-list.scss b/app/stylesheet/selected-groups-list.scss new file mode 100644 index 00000000000..62d01fea524 --- /dev/null +++ b/app/stylesheet/selected-groups-list.scss @@ -0,0 +1,24 @@ +#selected-groups-label { + display: inline-flex; + font-family: inherit; + font-size: 0.75rem; + letter-spacing: 0.32px; + color: #525252; + font-weight: 400; + line-height: 1rem; +} + +#selected-groups { + padding-left: 3rem; + display: inline-table; +} + +.group-name { + display: inline-flex; + font-family: "Open Sans", Helvetica, Arial, sans-serif; + font-size: 12px; + line-height: 1.67; + color: #363636; + padding-left: 2px; + margin-bottom: 0px; +} diff --git a/app/views/ops/_rbac_user_details.html.haml b/app/views/ops/_rbac_user_details.html.haml index e65c4aa23b3..5cf877cdf5a 100644 --- a/app/views/ops/_rbac_user_details.html.haml +++ b/app/views/ops/_rbac_user_details.html.haml @@ -1,114 +1,11 @@ - if @edit - - change_stored_password ||= _("Change") - - cancel_password_change ||= _("Cancel") - - stored_password_placeholder = "●●●●●●●●" - - pfx ||= "" - - url = url_for_only_path(:action => 'rbac_user_field_changed', :id => (@edit[:user_id] || "new")) - - observe_url_json = {:interval => '.5', :url => url}.to_json - - disabled = @edit && @edit[:new][:userid] == "admin" = render :partial => "layouts/flash_msg" + - disabled = @edit && @edit[:new][:userid] == "admin" + - db_mode = ::Settings.authentication.mode #user_info %h3 = _("User Information") - .form-horizontal - .form-group - %label.col-md-2.control-label - = _("Full Name") - .col-md-8 - = text_field_tag("name", - @edit[:new][:name], - :autocomplete => 'off', - :maxlength => 50, - :disabled => disabled, - :class => "form-control", - "data-miq_observe" => observe_url_json) - - unless @edit[:new][:userid] == "admin" - = javascript_tag(javascript_focus('name')) - .form-group - %label.col-md-2.control-label - = _("Username") - .col-md-8 - = text_field_tag("userid", - @edit[:new][:userid], - :autocomplete => 'off', - :maxlength => 255, - :disabled => disabled, - :class => "form-control", - "data-miq_observe" => observe_url_json) - - db_mode = ::Settings.authentication.mode - - if db_mode == "database" || (db_mode != "database" && disabled) - .form-group - %label.col-md-2.control-label - = _("Password") - .col-md-8 - %span.input-group{:style => "width: 100%"} - = password_field_tag("password", - "", - :autocomplete => "new-password", - :maxlength => 50, - :disabled => @edit[:new][:userid].blank? ? false : true, - :placeholder => @edit[:new][:userid].blank? ? "" : stored_password_placeholder, - :class => "form-control", - "data-miq_observe" => observe_url_json) - - if @edit[:new][:userid] == "admin" - = javascript_tag(javascript_focus('password')) - - unless @edit[:new][:userid].blank? - %span.input-group-btn - %button.btn.btn-default{:id => "change_stored_password", - "style" => "display:block;cursor: pointer; cursor: hand;", "onclick" => "changeStoredPassword('#{pfx}', '#{url}')"} - = change_stored_password - %button.btn.btn-default{:id => "cancel_password_change", - "style" => "display:none;cursor: pointer; cursor: hand;", - "onclick" => "cancelPasswordChange('#{pfx}', '#{url}')"} - = cancel_password_change - .form-group{:id => "verify_group", - :style => @edit[:new][:userid].blank? ? "display:block" : "display:none"} - %label.col-md-2.control-label - = _("Confirm Password") - .col-md-8 - = password_field_tag("verify", - "", - :autocomplete => "new-password", - :maxlength => 50, - :class => "form-control", - "data-miq_observe" => observe_url_json) - .form-group - %label.col-md-2.control-label - = _("E-mail Address") - .col-md-8 - = text_field_tag("email", - @edit[:new][:email], - :autocomplete => 'off', - :maxlength => 253, - :class => "form-control", - "data-miq_observe" => observe_url_json) - .form-group - %label.col-md-2.control-label - = _("Available Groups") - .col-md-2 - - groups = @record.present? && @record.miq_groups.present? ? @record.miq_groups.order(:description) : [] - - if disabled - %p.form-control-static - - groups.each do |group| - = h(group.description) - %br - - else - - select_groups = @edit[:new][:userid].blank? ? @edit[:new][:group] : groups.map(&:id) - = select_tag('chosen_group', - options_for_select(@edit[:groups], select_groups), - :class => "selectpicker", - :multiple => true, - :title => "<#{_('Choose one or more Groups')}>", - :style => "overflow-x: scroll;") - :javascript - miqInitSelectPicker(); - miqSelectPickerEvent('chosen_group', "#{url}") - .form-group - %label.col-md-2.control-label - = _("Selected Groups") - .col-md-4 - = render :partial => "ops/rbac_group_selected" - %hr + = react('UserForm', {:id => (@edit[:user_id]), :copyUserId => @copy_user_id, :disabled => disabled, :dbMode => db_mode}) - else = settings_users_summary(@record) = render :partial => "rbac_tag_box" diff --git a/config/routes.rb b/config/routes.rb index 6be2977c352..ba55c82139e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2472,7 +2472,6 @@ rbac_tenants_list rbac_tenant_manage_quotas rbac_user_edit - rbac_user_field_changed rbac_users_list region_edit restart_server diff --git a/cypress/e2e/ui/Settings/application-settings.cy.js b/cypress/e2e/ui/Settings/application-settings.cy.js new file mode 100644 index 00000000000..22fba8dcc23 --- /dev/null +++ b/cypress/e2e/ui/Settings/application-settings.cy.js @@ -0,0 +1,744 @@ +/* eslint-disable no-undef */ + +describe('Settings > Application Settings Tests', () => { + beforeEach(() => { + cy.login(); + cy.intercept('POST', '/ops/accordion_select?id=rbac_accord').as('accordion'); + cy.menu('Settings', 'Application Settings'); + cy.get('#settings_server > :nth-child(5)'); // Waits for form to load or else explorer breaks + }); + + describe('Access Control', () => { + beforeEach(() => { + cy.get('#control_rbac_accord > .panel-title > .collapsed').click(); + cy.wait('@accordion'); // Wait for explorer screen to load + }); + + describe('Users', () => { + it('Correctly loads admin user', () => { + // Navigate to user list and click on Administrator user in table + cy.get('[title="View Users"] > .content_value').click({force: true}); + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + if (rows[index].children[1].textContent === 'Administrator') { + cy.get(rows[index].children[1]).click({ force: true }); + } + }); + }); + + // Check Administrator user values on summary page + cy.get('#accordion-item-15 > .bx--structured-list > .bx--structured-list-tbody > :nth-child(1) > .label_header').contains('ID'); + cy.get(':nth-child(1) > .content_value > .content').contains('1'); + cy.get(':nth-child(2) > .label_header').contains('Full Name'); + cy.get(':nth-child(2) > .content_value').contains('Administrator'); + cy.get(':nth-child(3) > .label_header').contains('Username'); + cy.get(':nth-child(3) > .content_value').contains('admin'); + cy.get(':nth-child(4) > .label_header').contains('E-mail Address'); + cy.get(':nth-child(4) > .content_value').then((val) => { + expect(val[0].innerText).to.eq(''); + }); + cy.get(':nth-child(5) > .label_header').contains('Current Group'); + cy.get(':nth-child(5) > .content_value').contains('EvmGroup-super_administrator'); + cy.get(':nth-child(6) > .label_header').contains('Role'); + cy.get(':nth-child(6) > .content_value').contains('EvmRole-super_administrator'); + cy.get('.label_header > .bx--link > .content > .expand').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + expect(rows[index].innerText).to.eq('EvmGroup-super_administrator'); + }); + }); + + // Click edit button + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(1) > .bx--overflow-menu-options__btn > div').click(); + + // Check that fields are correctly disabled and contain the correct values + cy.get('#name').then((val) => { + expect(val[0].disabled).to.eq(true); + expect(val[0].defaultValue).to.eq('Administrator'); + }); + cy.get('#userid').then((val) => { + expect(val[0].disabled).to.eq(true); + expect(val[0].defaultValue).to.eq('admin'); + }); + cy.get('#passwordPlaceholder').then((val) => { + expect(val[0].disabled).to.eq(true); + }); + cy.get('#email').then((val) => { + expect(val[0].disabled).to.eq(false); + expect(val[0].defaultValue).to.eq(''); + }); + cy.get('#downshift-0-toggle-button').then((val) => { + expect(val[0].disabled).to.eq(true); + }); + cy.get('#EvmGroup-super_administrator').contains('EvmGroup-super_administrator'); + }); + + it('Edit admin user', () => { + // Navigate to user list and click on Administrator user in table + cy.get('[title="View Users"] > .content_value').click({force: true}); + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + if (rows[index].children[1].textContent === 'Administrator') { + cy.get(rows[index].children[1]).click({ force: true }); + } + }); + }); + + // Click edit button + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(1) > .bx--overflow-menu-options__btn > div').click(); + + // Edit the email field since that is the only field that the Adminisistrator user can change not including the password field + cy.get('#email').type('test@email.com'); + cy.get('.bx--btn-set > .bx--btn--primary').click(); + cy.get(':nth-child(4) > .label_header').contains('E-mail Address'); + cy.get(':nth-child(4) > .content_value').contains('test@email.com'); // Check that email was correctly saved on the summary page + + // Click edit button + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(1) > .bx--overflow-menu-options__btn > div').click(); + + // Reset email back to default value of empty + cy.get('#email').clear(); + cy.get('.bx--btn-set > .bx--btn--primary').click(); + }); + + it('Create, edit and delete a user', () => { + let groups = []; + + // Navigate to user list and click Add a new User button + cy.get('[title="View Users"] > .content_value').click({force: true}); + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(1) > .bx--overflow-menu-options__btn').click(); + + // Input values on the user form + cy.get('#name').type('Cypress Test Add', {force: true}); + cy.get('#userid').type('cypressUserAdd', {force: true}); + cy.get('#password').type('cypressPass'); + cy.get('#confirmPassword').type('cypressPass'); + cy.get('#email').type('test@email.com'); + cy.get('#downshift-0-toggle-button').click(); + cy.get('#downshift-0-menu').then((val) => { + // Select the first group + cy.get(val[0].children[0]).click(); + groups.push(val[0].children[0].innerText); + }); + cy.get('#downshift-0-toggle-button').click(); + cy.get('#selected-groups > div > p').then((selectedGroups) => { + const nums = [...Array(selectedGroups.length).keys()]; + nums.forEach((index) => { + expect(groups.includes(selectedGroups[index].textContent)).to.eq(true); // Check that multi select and selected groups list component work together correctly + }); + }); + cy.get('.bx--btn-set > .bx--btn--primary').click(); // Click the add button + + // Find the new user in the table and click it + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + if (rows[index].children[1].textContent === 'Cypress Test Add') { + cy.get(rows[index].children[1]).click({ force: true }); + } + }); + }); + + // Verify that the new user was created with the correct values on the summary page + cy.get(':nth-child(1) > .label_header').contains('ID'); + cy.get(':nth-child(2) > .label_header').contains('Full Name'); + cy.get(':nth-child(2) > .content_value').contains('Cypress Test Add'); + cy.get(':nth-child(3) > .label_header').contains('Username'); + cy.get(':nth-child(3) > .content_value').contains('cypressUserAdd'); + cy.get(':nth-child(4) > .label_header').contains('E-mail Address'); + cy.get(':nth-child(4) > .content_value').contains('test@email.com'); + cy.get(':nth-child(5) > .label_header').contains('Current Group'); + cy.get(':nth-child(5) > .content_value').contains('EvmGroup-administrator'); + cy.get(':nth-child(6) > .label_header').contains('Role'); + cy.get(':nth-child(6) > .content_value').contains('EvmRole-administrator'); + cy.get('.label_header > .bx--link > .content > .expand').then((rows) => { // Check groups list to verify user was correctly added to all selected groups + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + expect(groups.includes(rows[index].innerText)).to.eq(true); + }); + }); + + // Logout of admin user and login to the new user account and logout again + cy.get('#menu_item_logout').click(); + cy.get('#user_name').type('cypressUserAdd'); + cy.get('#user_password').type('cypressPass'); + cy.get('#login').click(); + cy.get('#menu_item_logout').click(); + + // Login to admin user again and navigate to user table + cy.login(); + cy.intercept('POST', '/ops/accordion_select?id=rbac_accord').as('accordion'); + cy.menu('Settings', 'Application Settings'); + cy.get('#settings_server > :nth-child(5)'); + cy.get('#control_rbac_accord > .panel-title > .collapsed').click(); + cy.wait('@accordion'); // Wait for explorer screen to load + cy.get('[title="View Users"] > .content_value').click({force: true}); + + // Find the new user in the table and click on that row + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + if (rows[index].children[1].textContent === 'Cypress Test Add') { + cy.get(rows[index].children[1]).click({ force: true }); + } + }); + }); + + // Click the edit user button + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(1) > .bx--overflow-menu-options__btn').click(); + + // Edit the values on the user form + cy.get('#name').clear({force: true}).type('Cypress Test Edit', {force: true}); + cy.get('#userid').clear({force: true}).type('cypressUserEdit', {force: true}); + cy.get('.bx--col-sm-1 > .bx--btn').click(); + cy.get('#password').type('newPassword'); + cy.get('#confirmPassword').type('newPassword'); + cy.get('#email').clear().type('test_edit@email.com'); + cy.get('#downshift-0-toggle-button').click({force: true}); + groups = []; + cy.get('#downshift-0-menu').then((val) => { + // Unselect first group and select next two groups + cy.get(val[0].children[0]).click(); + cy.get(val[0].children[1]).click(); + cy.get(val[0].children[2]).click(); + + groups.push(val[0].children[1].innerText); + groups.push(val[0].children[2].innerText); + }); + cy.get('#downshift-0-toggle-button').click({force: true}); + cy.get('#selected-groups > div > p').then((selectedGroups) => { + const nums = [...Array(selectedGroups.length).keys()]; + nums.forEach((index) => { + expect(groups.includes(selectedGroups[index].textContent)).to.eq(true); + }); + }); + cy.get('.bx--btn-set > .bx--btn--primary').click(); // Click save button + + // Verify that the new user was edited with the correct values on the summary page + cy.get(':nth-child(1) > .label_header').contains('ID'); + cy.get(':nth-child(2) > .label_header').contains('Full Name'); + cy.get(':nth-child(2) > .content_value').contains('Cypress Test Edit'); + cy.get(':nth-child(3) > .label_header').contains('Username'); + cy.get(':nth-child(3) > .content_value').contains('cypressUserEdit'); + cy.get(':nth-child(4) > .label_header').contains('E-mail Address'); + cy.get(':nth-child(4) > .content_value').contains('test_edit@email.com'); + cy.get(':nth-child(5) > .label_header').contains('Current Group'); + cy.get(':nth-child(5) > .content_value').contains('EvmGroup-approver'); + cy.get(':nth-child(6) > .label_header').contains('Role'); + cy.get(':nth-child(6) > .content_value').contains('EvmRole-approver'); + cy.get('.label_header > .bx--link > .content > .expand').then((rows) => { // Check groups list to verify user was correctly added to all selected groups + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + expect(groups.includes(rows[index].innerText)).to.eq(true); + }); + }); + + // Logout of admin user and login to the edited account and logout again + cy.get('#menu_item_logout').click(); + cy.get('#user_name').type('cypressUserEdit'); + cy.get('#user_password').type('newPassword'); + cy.get('#login').click(); + cy.get('#menu_item_logout').click(); + + // Login to admin user again and navigate to user table + cy.login(); + cy.intercept('POST', '/ops/accordion_select?id=rbac_accord').as('accordion'); + cy.menu('Settings', 'Application Settings'); + cy.get('#settings_server > :nth-child(5)'); + cy.get('#control_rbac_accord > .panel-title > .collapsed').click(); + cy.wait('@accordion'); // Wait for explorer screen to load + cy.get('[title="View Users"] > .content_value').click({force: true}); + + // Find the editted user in the table and click it + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + if (rows[index].children[1].textContent === 'Cypress Test Edit') { + cy.get(rows[index].children[1]).click({ force: true }); + } + }); + }); + + // Click the delete user button + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(3) > .bx--overflow-menu-options__btn').click(); + + // Verify that the user was deleted from the table + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + expect(rows[index].children[1].textContent).to.not.eq('Cypress Test Add'); + expect(rows[index].children[1].textContent).to.not.eq('Cypress Test Edit'); + }); + }); + }); + + it('Create, copy and delete a user', () => { + let groups = []; + + // Navigate to user list and click Add a new User button + cy.get('[title="View Users"] > .content_value').click({force: true}); + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(1) > .bx--overflow-menu-options__btn').click(); + + // Input values on the user form + cy.get('#name').type('Cypress Test Add 2', {force: true}); + cy.get('#userid').type('cypressUserAdd2', {force: true}); + cy.get('#password').type('cypressPass'); + cy.get('#confirmPassword').type('cypressPass'); + cy.get('#email').type('test@email.com'); + cy.get('#downshift-0-toggle-button').click(); + cy.get('#downshift-0-menu').then((val) => { + // Click first two + cy.get(val[0].children[0]).click(); + cy.get(val[0].children[1]).click(); + + groups.push(val[0].children[0].innerText); + groups.push(val[0].children[1].innerText); + }); + cy.get('#downshift-0-toggle-button').click(); + cy.get('#selected-groups > div > p').then((selectedGroups) => { + const nums = [...Array(selectedGroups.length).keys()]; + nums.forEach((index) => { + expect(groups.includes(selectedGroups[index].textContent)).to.eq(true); // Check that multi select and selected groups list component work together correctly + }); + }); + cy.get('.bx--btn-set > .bx--btn--primary').click(); // Click the add button + + // Find the new user in the table and click it + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + if (rows[index].children[1].textContent === 'Cypress Test Add 2') { + cy.get(rows[index].children[1]).click({ force: true }); + } + }); + }); + + // Click copy user button + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(2) > .bx--overflow-menu-options__btn').click(); + + // Verify copy form was loaded with the correct values + cy.get('#name').then((val) => { + expect(val[0].defaultValue).to.eq('Cypress Test Add 2'); + }); + cy.get('#userid').then((val) => { + expect(val[0].defaultValue).to.eq(''); + }); + cy.get('#password').then((val) => { + expect(val[0].defaultValue).to.eq(''); + }); + cy.get('#confirmPassword').then((val) => { + expect(val[0].defaultValue).to.eq(''); + }); + cy.get('#email').then((val) => { + expect(val[0].defaultValue).to.eq('test@email.com'); + }); + + // Check the multi-select and selected groups list initial selected values + cy.get('#downshift-0-toggle-button').click(); + cy.get('#downshift-0-menu').then((val) => { + val[0].children.forEach((group) => { + if (groups.includes(group.textContent)) { + expect(group.children[0].children[0].children[0].getAttribute('data-contained-checkbox-state')).to.eq('true'); + } else { + expect(group.children[0].children[0].children[0].getAttribute('data-contained-checkbox-state')).to.eq('false'); + } + }); + }); + cy.get('#downshift-0-toggle-button').click(); + cy.get('#selected-groups > div > p').then((selectedGroups) => { + const nums = [...Array(selectedGroups.length).keys()]; + nums.forEach((index) => { + expect(groups.includes(selectedGroups[index].textContent)).to.eq(true); + }); + }); + + // Input the new values on the copy user form + cy.get('#name').clear().type('Cypress Test Copy'); + cy.get('#userid').type('cypressUserCopy'); + cy.get('#password').type('newPassword'); + cy.get('#confirmPassword').type('newPassword'); + cy.get('#email').clear().type('test_copy@email.com'); + cy.get('#downshift-0-toggle-button').click({force: true}); + groups = []; + cy.get('#downshift-0-menu').then((val) => { + // Unselect first group and leave second group selected + cy.get(val[0].children[0]).click(); + + groups.push(val[0].children[1].innerText); + }); + cy.get('#downshift-0-toggle-button').click({force: true}); + cy.get('#selected-groups > div > p').then((selectedGroups) => { + const nums = [...Array(selectedGroups.length).keys()]; + nums.forEach((index) => { + expect(groups.includes(selectedGroups[index].textContent)).to.eq(true); + }); + }); + cy.get('.bx--btn-set > .bx--btn--primary').click(); // Click the add button + + // Wait for summary page to load + cy.get(':nth-child(1) > .label_header').contains('ID'); + + // Logout of admin user and login to the new user account and logout again + cy.get('#menu_item_logout').click(); + cy.get('#user_name').type('cypressUserAdd2'); + cy.get('#user_password').type('cypressPass'); + cy.get('#login').click(); + cy.get('#menu_item_logout').click(); + + // Login to copied user then logout + cy.get('#user_name').type('cypressUserCopy'); + cy.get('#user_password').type('newPassword'); + cy.get('#login').click(); + cy.get('#menu_item_logout').click(); + + // Login to admin user again and navigate to user table + cy.login(); + cy.intercept('POST', '/ops/accordion_select?id=rbac_accord').as('accordion'); + cy.menu('Settings', 'Application Settings'); + cy.get('#settings_server > :nth-child(5)'); + cy.get('#control_rbac_accord > .panel-title > .collapsed').click(); + cy.wait('@accordion'); // Wait for explorer screen to load + cy.get('[title="View Users"] > .content_value').click({force: true}); + + // Find the copied user in the table and click it + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + if (rows[index].children[1].textContent === 'Cypress Test Copy') { + cy.get(rows[index].children[1]).click({ force: true }); + } + }); + }); + + // Verify that the copied user was created with the correct values on the summary page + cy.get(':nth-child(1) > .label_header').contains('ID'); + cy.get(':nth-child(2) > .label_header').contains('Full Name'); + cy.get(':nth-child(2) > .content_value').contains('Cypress Test Copy'); + cy.get(':nth-child(3) > .label_header').contains('Username'); + cy.get(':nth-child(3) > .content_value').contains('cypressUserCopy'); + cy.get(':nth-child(4) > .label_header').contains('E-mail Address'); + cy.get(':nth-child(4) > .content_value').contains('test_copy@email.com'); + cy.get(':nth-child(5) > .label_header').contains('Current Group'); + cy.get(':nth-child(5) > .content_value').contains('EvmGroup-approver'); + cy.get(':nth-child(6) > .label_header').contains('Role'); + cy.get(':nth-child(6) > .content_value').contains('EvmRole-approver'); + cy.get('.label_header > .bx--link > .content > .expand').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + expect(groups.includes(rows[index].innerText)).to.eq(true); + }); + }); + + // Click the delete user button for the copied user + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(3) > .bx--overflow-menu-options__btn').click(); + + // Find the new user in the table and click it + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + if (rows[index].children[1].textContent === 'Cypress Test Add 2') { + cy.get(rows[index].children[1]).click({ force: true }); + } + }); + }); + + // Verify that the new user was created with the correct values on the summary page + cy.get(':nth-child(1) > .label_header').contains('ID'); + cy.get(':nth-child(2) > .label_header').contains('Full Name'); + cy.get(':nth-child(2) > .content_value').contains('Cypress Test Add 2'); + cy.get(':nth-child(3) > .label_header').contains('Username'); + cy.get(':nth-child(3) > .content_value').contains('cypressUserAdd2'); + cy.get(':nth-child(4) > .label_header').contains('E-mail Address'); + cy.get(':nth-child(4) > .content_value').contains('test@email.com'); + cy.get(':nth-child(5) > .label_header').contains('Current Group'); + cy.get(':nth-child(5) > .content_value').contains('EvmGroup-administrator'); + cy.get(':nth-child(6) > .label_header').contains('Role'); + cy.get(':nth-child(6) > .content_value').contains('EvmRole-administrator'); + cy.get('.label_header > .bx--link > .content > .expand').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + expect(groups.includes(rows[index].innerText)).to.eq(true); + }); + }); + + // Click the delete user button for the new user + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(3) > .bx--overflow-menu-options__btn').click(); + + // Verify that the user was deleted from the table + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + expect(rows[index].children[1].textContent).to.not.eq('Cypress Test Add 2'); + expect(rows[index].children[1].textContent).to.not.eq('Cypress Test Edit 2'); + }); + }); + }); + + it('Test Form Validation', () => { + let groups = []; + + // Navigate to user list and click Add a new User button + cy.get('[title="View Users"] > .content_value').click({force: true}); + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(1) > .bx--overflow-menu-options__btn').click(); + + // Input values on the user form + cy.get('#downshift-0-toggle-button').click(); + cy.get('#downshift-0-menu').then((val) => { + cy.get(val[0].children[0]).click(); + groups.push(val[0].children[0].innerText); + }); + cy.get('#selected-groups > div > p').then((selectedGroups) => { + const nums = [...Array(selectedGroups.length).keys()]; + nums.forEach((index) => { + expect(groups.includes(selectedGroups[index].textContent)).to.eq(true); + }); + }); + cy.get('#downshift-0-toggle-button').click(); + cy.get('#userid').type('cypressUserValidation', {force: true}); + cy.get('#password').type('cypressPass'); // Test password validation with non-matching passwords + cy.get('#confirmPassword').type('incorrectPassword'); + cy.get('#email').type('emailError'); // Test email validation with bad email + cy.get('#name').type('Cypress Test Validation', {force: true}); + cy.get('#confirmPassword-error-msg'); + cy.get('#email-error-msg'); + cy.get('.bx--btn-set > .bx--btn--primary').should('be.disabled'); // Verify that the add button is disabled + + cy.get('#email').clear().type('test@email.com'); // Input correct email + cy.get('#confirmPassword-error-msg'); // Verify that the confirm password error message is present + cy.get('.bx--btn-set > .bx--btn--primary').should('be.disabled'); // Verify that the add button is disabled + + cy.get('#confirmPassword').clear().type('newPassword'); // Enter new matching password and confirm password + cy.get('#password').clear().type('newPassword'); + + cy.get('#email').clear(); + + // Verify that add button is enabled and click it + cy.get('.bx--btn-set > .bx--btn--primary').should('be.enabled'); + cy.get('.bx--btn-set > .bx--btn--primary').click(); + + // Find the new user in the table and click it + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + if (rows[index].children[1].textContent === 'Cypress Test Validation') { + cy.get(rows[index].children[1]).click({ force: true }); + } + }); + }); + + // Verify that the new user was created with the correct values on the summary page + cy.get(':nth-child(1) > .label_header').contains('ID'); + cy.get(':nth-child(2) > .label_header').contains('Full Name'); + cy.get(':nth-child(2) > .content_value').contains('Cypress Test Validation'); + cy.get(':nth-child(3) > .label_header').contains('Username'); + cy.get(':nth-child(3) > .content_value').contains('cypressUserValidation'); + cy.get(':nth-child(4) > .label_header').contains('E-mail Address'); + cy.get(':nth-child(4) > .content_value').then((val) => { + expect(val[0].innerText).to.eq(''); + }); + cy.get(':nth-child(5) > .label_header').contains('Current Group'); + cy.get(':nth-child(5) > .content_value').contains('EvmGroup-administrator'); + cy.get(':nth-child(6) > .label_header').contains('Role'); + cy.get(':nth-child(6) > .content_value').contains('EvmRole-administrator'); + cy.get('.label_header > .bx--link > .content > .expand').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + expect(groups.includes(rows[index].innerText)).to.eq(true); + }); + }); + + // Logout of admin user and login to the new user account and logout again + cy.get('#menu_item_logout').click(); + cy.get('#user_name').type('cypressUserValidation'); + cy.get('#user_password').type('newPassword'); + cy.get('#login').click(); + cy.get('#menu_item_logout').click(); + + // Login to admin user again and navigate to user table + cy.login(); + cy.intercept('POST', '/ops/accordion_select?id=rbac_accord').as('accordion'); + cy.menu('Settings', 'Application Settings'); + cy.get('#settings_server > :nth-child(5)'); + cy.get('#control_rbac_accord > .panel-title > .collapsed').click(); + cy.wait('@accordion'); // Wait for explorer screen to load + cy.get('[title="View Users"] > .content_value').click({force: true}); + + // Find the new user in the table and click on that row + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + if (rows[index].children[1].textContent === 'Cypress Test Validation') { + cy.get(rows[index].children[1]).click({ force: true }); + } + }); + }); + + // Click the edit user button + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(1) > .bx--overflow-menu-options__btn').click(); + + // Edit the name field and confirm save button is enabled + cy.get('#name').type(' Edit', { force: true }); + cy.get('.bx--btn-set > .bx--btn--primary').should('be.enabled'); + + // Verify that the password field is disabled and then after clicking the edit password button is enabled + cy.get('#passwordPlaceholder').should('be.disabled'); + cy.get('.bx--col-sm-1 > .bx--btn').click(); + cy.get('.bx--btn-set > .bx--btn--primary').should('be.disabled'); + + // Type in matching passwords and verify save button is enabled + cy.get('#password').type('test'); + cy.get('#confirmPassword').type('test'); + cy.get('.bx--btn-set > .bx--btn--primary').should('be.enabled'); + + // Clear confirm password field and verify save button is disabled + cy.get('#confirmPassword').clear(); + cy.get('.bx--btn-set > .bx--btn--primary').should('be.disabled'); + + // Type incorrect value for confirm password field and verify error message is present and save button is still disabled + cy.get('#confirmPassword').type('fail'); + cy.get('#email').type('test@email.com').clear(); + cy.get('#confirmPassword-error-msg'); + cy.get('.bx--btn-set > .bx--btn--primary').should('be.disabled'); + + // Click the cancel edit password button and verify that the save button is enabled and click it + cy.get('.bx--col-sm-1 > .bx--btn').click(); + cy.get('.bx--btn-set > .bx--btn--primary').should('be.enabled'); + cy.get('.bx--btn-set > .bx--btn--primary').click(); + + // Verify that the user values were edited with the correct values on the summary page + cy.get(':nth-child(1) > .label_header').contains('ID'); + cy.get(':nth-child(2) > .label_header').contains('Full Name'); + cy.get(':nth-child(2) > .content_value').contains('Cypress Test Validation Edit'); + cy.get(':nth-child(3) > .label_header').contains('Username'); + cy.get(':nth-child(3) > .content_value').contains('cypressUserValidation'); + cy.get(':nth-child(4) > .label_header').contains('E-mail Address'); + cy.get(':nth-child(4) > .content_value').then((val) => { + expect(val[0].innerText).to.eq(''); + }); + cy.get(':nth-child(5) > .label_header').contains('Current Group'); + cy.get(':nth-child(5) > .content_value').contains('EvmGroup-administrator'); + cy.get(':nth-child(6) > .label_header').contains('Role'); + cy.get(':nth-child(6) > .content_value').contains('EvmRole-administrator'); + cy.get('.label_header > .bx--link > .content > .expand').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + expect(groups.includes(rows[index].innerText)).to.eq(true); + }); + }); + + // Logout of admin user and login to the edited account and logout again + cy.get('#menu_item_logout').click(); + cy.get('#user_name').type('cypressUserValidation'); + cy.get('#user_password').type('newPassword'); + cy.get('#login').click(); + cy.get('#menu_item_logout').click(); + + // Login to admin user again and navigate to user table + cy.login(); + cy.intercept('POST', '/ops/accordion_select?id=rbac_accord').as('accordion'); + cy.menu('Settings', 'Application Settings'); + cy.get('#settings_server > :nth-child(5)'); + cy.get('#control_rbac_accord > .panel-title > .collapsed').click(); + cy.wait('@accordion'); // Wait for explorer screen to load + cy.get('[title="View Users"] > .content_value').click({force: true}); + + // Find the editted user in the table and click it + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + if (rows[index].children[1].textContent === 'Cypress Test Validation Edit') { + cy.get(rows[index].children[1]).click({ force: true }); + } + }); + }); + + // Click the edit user button + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(1) > .bx--overflow-menu-options__btn').click(); + + // Enter new matching passwords and click the save button + cy.get('#passwordPlaceholder').should('be.disabled'); + cy.get('.bx--col-sm-1 > .bx--btn').click(); + cy.get('.bx--btn-set > .bx--btn--primary').should('be.disabled'); + cy.get('#password').type('test'); + cy.get('#confirmPassword').type('test'); + cy.get('.bx--btn-set > .bx--btn--primary').should('be.enabled'); + cy.get('.bx--btn-set > .bx--btn--primary').click(); + + // Verify that the user values remain the same on the summary page + cy.get(':nth-child(1) > .label_header').contains('ID'); + cy.get(':nth-child(2) > .label_header').contains('Full Name'); + cy.get(':nth-child(2) > .content_value').contains('Cypress Test Validation Edit'); + cy.get(':nth-child(3) > .label_header').contains('Username'); + cy.get(':nth-child(3) > .content_value').contains('cypressUserValidation'); + cy.get(':nth-child(4) > .label_header').contains('E-mail Address'); + cy.get(':nth-child(4) > .content_value').then((val) => { + expect(val[0].innerText).to.eq(''); + }); + cy.get(':nth-child(5) > .label_header').contains('Current Group'); + cy.get(':nth-child(5) > .content_value').contains('EvmGroup-administrator'); + cy.get(':nth-child(6) > .label_header').contains('Role'); + cy.get(':nth-child(6) > .content_value').contains('EvmRole-administrator'); + cy.get('.label_header > .bx--link > .content > .expand').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + expect(groups.includes(rows[index].innerText)).to.eq(true); + }); + }); + + // Logout of admin user and login to the edited account with a new password and logout again + cy.get('#menu_item_logout').click(); + cy.get('#user_name').type('cypressUserValidation'); + cy.get('#user_password').type('test'); + cy.get('#login').click(); + cy.get('#menu_item_logout').click(); + + // Login to admin user again and navigate to user table + cy.login(); + cy.intercept('POST', '/ops/accordion_select?id=rbac_accord').as('accordion'); + cy.menu('Settings', 'Application Settings'); + cy.get('#settings_server > :nth-child(5)'); + cy.get('#control_rbac_accord > .panel-title > .collapsed').click(); + cy.wait('@accordion'); // Wait for explorer screen to load + cy.get('[title="View Users"] > .content_value').click({force: true}); + + // Find the editted user in the table and click it + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + if (rows[index].children[1].textContent === 'Cypress Test Validation Edit') { + cy.get(rows[index].children[1]).click({ force: true }); + } + }); + }); + + // Click the delete user button + cy.get('#user_vmdb_choice').click(); + cy.get(':nth-child(3) > .bx--overflow-menu-options__btn').click(); + + // Verify that the user was deleted from the table + cy.get('.clickable-row').then((rows) => { + const nums = [...Array(rows.length).keys()]; + nums.forEach((index) => { + expect(rows[index].children[1].textContent).to.not.eq('Cypress Test Validation'); + expect(rows[index].children[1].textContent).to.not.eq('Cypress Test Validation Edit'); + }); + }); + }); + }); + }); +}); diff --git a/spec/controllers/ops_controller/ops_rbac_spec.rb b/spec/controllers/ops_controller/ops_rbac_spec.rb index ca06f4bd54c..66381224ac5 100644 --- a/spec/controllers/ops_controller/ops_rbac_spec.rb +++ b/spec/controllers/ops_controller/ops_rbac_spec.rb @@ -646,33 +646,6 @@ subject { controller.instance_variable_get(:@edit)[:new][:group] } - context 'adding a new user' do - let(:rec_type) { "user" } - let(:params) { {:id => "new", :chosen_group => "17,7"} } - - it 'sets list of selected groups properly' do - controller.send(:rbac_field_changed, rec_type) - expect(subject).to eq([7, 17]) - end - - it 'sets session[:changed] to true' do - controller.send(:rbac_field_changed, rec_type) - expect(session[:changed]).to be(true) - end - - context 'deleting name and/or password from the form while adding user' do - let(:params) { {:name => '', :id => 'new', :password => '', :verify => ''} } - let(:edit) { {:new => {:name => 'new_user', :password => 'passw', :verify => 'passw'}, :current => edit_curr } } - let(:edit_curr) { {:name => nil, :group => [], :password => nil, :verify => nil} } - - it 'sets @edit[:new] and session[:changed] properly' do - controller.send(:rbac_field_changed, rec_type) - expect(controller.instance_variable_get(:@edit)[:new]).to eq(edit_curr) - expect(session[:changed]).to be(false) - end - end - end - context 'adding a new group' do let(:rec_type) { "group" } @@ -784,21 +757,4 @@ end end end - - describe '#rbac_user_set_form_vars' do - let(:user) { FactoryBot.create(:user, :miq_groups => [group2, group1]) } - let!(:group1) { FactoryBot.create(:miq_group) } - let!(:group2) { FactoryBot.create(:miq_group) } - - before do - allow(Rbac).to receive(:filtered).and_return([]) - controller.instance_variable_set(:@record, user) - controller.instance_variable_set(:@sb, {}) - end - - it 'sorts the ids of available groups of a user' do - controller.send(:rbac_user_set_form_vars) - expect(controller.instance_variable_get(:@edit)[:current][:group]).to eq([group1.id, group2.id]) - end - end end diff --git a/spec/controllers/ops_controller/ops_rbac_user_spec.rb b/spec/controllers/ops_controller/ops_rbac_user_spec.rb deleted file mode 100644 index 702073ae0f4..00000000000 --- a/spec/controllers/ops_controller/ops_rbac_user_spec.rb +++ /dev/null @@ -1,170 +0,0 @@ -describe OpsController do - include Spec::Support::OpsUserHelper - - before do - EvmSpecHelper.local_miq_server - MiqRegion.seed - stub_admin - - controller.instance_variable_set(:@sb, {}) - allow(controller).to receive(:replace_right_cell) - allow(controller).to receive(:load_edit).and_return(true) - allow(controller).to receive(:render_flash) - allow(controller).to receive(:get_node_info) - end - - context 'set record data before calling record.valid?' do - let(:group) { FactoryBot.create(:miq_group) } - - it "calls both record.valid? and rbac_user_set_record_vars or neither" do - new_user_edit( - :name => 'Full name', - :userid => 'username', - :group => group.id.to_s, - :password => "foo", - :verify => "bar", - ) - - user = FactoryBot.build(:user) - allow(User).to receive(:new).and_return(user) - - done_valid = false - allow(user).to receive(:valid?) { - done_valid = true - } - - done_set = false - allow(controller).to receive(:rbac_user_set_record_vars) { - done_set = true - } - - controller.send(:rbac_edit_save_or_add, 'user') - - expect(done_valid).to eq(done_set) - end - - it "displays both validation failures from rails and from rbac_user_validate? at the same time" do - new_user_edit( - :name => '', # fails user.valid? - :userid => 'username', - :group => group.id.to_s, - :password => "foo", # fails rbac_user_validate - :verify => "bar", - ) - - controller.send(:rbac_edit_save_or_add, 'user') - - messages = controller.instance_variable_get(:@flash_array).pluck(:message) - expect(messages).to include(match(/password/i)) - expect(messages).to include(match(/name/i)) - end - end - - context 'don\'t change groups on cancel' do - let(:user) { FactoryBot.create(:user_with_group) } - let(:group) { FactoryBot.create(:miq_group) } - - it "should not unset groups on cancel" do - old_groups = user.miq_groups.pluck(:id).sort - existing_user_edit(user, :group => "") - - controller.params = {:typ => nil, - :button => 'save', # attempt to save - :id => user.id} - controller.send(:rbac_edit_save_or_add, 'user') - - # make sure it complains about the unset group in the first place - messages = controller.instance_variable_get(:@flash_array).pluck(:message) - expect(messages).to include(match(/group/i)) - - # make sure the group didn't get changed - user.reload - expect(user.miq_groups.pluck(:id).sort).to eq(old_groups) - end - - it "should not change groups when rails validation fails" do - old_groups = user.miq_groups.pluck(:id).sort - existing_user_edit(user, :group => group.id.to_s, - :name => "") # fails record.valid? - - controller.params = {:typ => nil, - :button => 'save', - :id => user.id} - controller.send(:rbac_edit_save_or_add, 'user') - - # make sure it complains about the name - messages = controller.instance_variable_get(:@flash_array).pluck(:message) - expect(messages).to include(match(/name/i)) - - # make sure the group didn't get changed - user.reload - expect(user.miq_groups.pluck(:id).sort).to eq(old_groups) - end - end - - context 'update record fields when editing' do - let(:user) { FactoryBot.create(:user_with_group) } - - it "updates record even for existing users" do - existing_user_edit(user, :name => "changed") - - controller.params = {:typ => nil, - :button => 'save', - :id => user.id} - - controller.send(:rbac_edit_save_or_add, 'user') - - # make sure it returned success - messages = controller.instance_variable_get(:@flash_array).pluck(:message) - expect(messages).to include(match(/was saved/i)) - - # make sure the name did get changed - user.reload - expect(user.name).to eq('changed') - end - end - - context 'set current_group' do - let(:user) { FactoryBot.create(:user_with_group) } - let(:group) { FactoryBot.create(:miq_group) } - - it "should set current_group for new item" do - new_user_edit( - :name => 'Full name', - :userid => 'username', - :group => group.id.to_s, - :password => "foo", - :verify => "foo", - ) - - controller.params = {:typ => nil, - :button => 'add'} - controller.send(:rbac_edit_save_or_add, 'user') - - # make sure it returned success - messages = controller.instance_variable_get(:@flash_array).pluck(:message) - expect(messages).to include(match(/was saved/i)) - - # make sure current_group is set and saved - new_user = User.where(:userid => 'username').first - expect(new_user.current_group.id).to eq(group.id) - end - - it "should set current_group when editing" do - existing_user_edit(user, :group => group.id.to_s) - - controller.params = {:typ => nil, - :button => 'save', - :id => user.id} - controller.send(:rbac_edit_save_or_add, 'user') - - # make sure it returned success - messages = controller.instance_variable_get(:@flash_array).pluck(:message) - expect(messages).to include(match(/was saved/i)) - - # make sure current_group is set and saved - user.reload - expect(user.current_group.id).to eq(group.id) - end - end -end diff --git a/spec/controllers/ops_controller_spec.rb b/spec/controllers/ops_controller_spec.rb index e2e709e1501..6968ed6a484 100644 --- a/spec/controllers/ops_controller_spec.rb +++ b/spec/controllers/ops_controller_spec.rb @@ -56,89 +56,6 @@ end end - describe 'rbac_user_edit' do - let(:group) { user.miq_groups.first } - before do - ApplicationController.handle_exceptions = true - end - - it 'can add a user w/ group' do - session[:edit] = { - :key => 'rbac_user_edit__new', - :current => {}, - :new => { - :name => 'test7', - :userid => 'test7', - :email => 'test7@foo.bar', - :group => group.id.to_s, - :password => 'test7', - :verify => 'test7', - } - } - expect(controller).to receive(:replace_right_cell) - get :rbac_user_edit, :params => {:button => 'add'} - end - - it 'cannot add a user w/o matching passwords' do - session[:edit] = { - :key => 'rbac_user_edit__new', - :new => { - :name => 'test7', - :userid => 'test7', - :email => 'test7@foo.bar', - :group => group.id.to_s, - :password => 'test7', - :verify => 'test8', - } - } - - expect(controller).to receive(:render_flash) - get :rbac_user_edit, :params => {:button => 'add'} - flash_messages = assigns(:flash_array) - expect(flash_messages.first[:message]).to eq("Password/Verify Password do not match") - expect(flash_messages.first[:level]).to eq(:error) - end - - it 'cannot add a user w/o group' do - session[:edit] = { - :key => 'rbac_user_edit__new', - :new => { - :name => 'test7', - :userid => 'test7', - :email => 'test7@foo.bar', - :group => nil, - :password => 'test7', - :verify => 'test7', - } - } - - expect(controller).to receive(:render_flash) - get :rbac_user_edit, :params => {:button => 'add'} - flash_messages = assigns(:flash_array) - expect(flash_messages.first[:message]).to eq("A User must be assigned to a Group") - expect(flash_messages.first[:level]).to eq(:error) - end - - it 'does not update the user without validation' do - user1 = FactoryBot.create(:user, :name => "User1", :userid => "User1", :miq_groups => [group], :email => "user1@test.com") - - session[:edit] = {:key => "rbac_user_edit__#{user1.id}", - :new => {:name => 'test8', - :userid => 'test8', - :email => 'test8@foo.bar', - :group => nil, - :password => 'test8', - :verify => 'test8'}} - expect(controller).to receive(:render_flash) - post :rbac_user_edit, :params => {:button => 'save', :id => user1.id} - flash_messages = assigns(:flash_array) - expect(flash_messages.first[:message]).to eq("A User must be assigned to a Group") - expect(flash_messages.first[:level]).to eq(:error) - expect(user1.miq_groups).to eq([group]) - expect(user1.name).to eq('User1') - end - end - describe "#edit_changed?" do it "should set session[:changed] as false" do edit = { diff --git a/spec/routing/ops_routing_spec.rb b/spec/routing/ops_routing_spec.rb index 00ef106fc24..263a8523041 100644 --- a/spec/routing/ops_routing_spec.rb +++ b/spec/routing/ops_routing_spec.rb @@ -61,7 +61,6 @@ rbac_tags_edit rbac_tenants_list rbac_user_edit - rbac_user_field_changed rbac_users_list region_edit restart_server diff --git a/spec/views/ops/_rbac_user_details.html.haml_spec.rb b/spec/views/ops/_rbac_user_details.html.haml_spec.rb deleted file mode 100644 index b7667f36edc..00000000000 --- a/spec/views/ops/_rbac_user_details.html.haml_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -describe 'ops/_rbac_user_details.html.haml' do - context "edit user" do - before do - user = FactoryBot.build(:user_with_group, :name => "Joe Test", :userid => "tester") - allow(view).to receive(:current_tenant).and_return(Tenant.seed) - allow(view).to receive(:session).and_return(:assigned_filters => []) - edit = {:new => {:name => user.name, - :email => user.email, - :userid => user.userid}, - :groups => []} - view.instance_variable_set(:@edit, edit) - end - - it "displays full name" do - render :template => "ops/_rbac_user_details" - expect(rendered).to have_field("name", :with => "Joe Test") - end - end -end