From d359d80abc6917c49f7a0e2033e9c8f237366498 Mon Sep 17 00:00:00 2001 From: Elsa Mary Date: Wed, 30 Oct 2024 16:45:36 +0530 Subject: [PATCH 1/8] Transforms haml forms to react for Automate class --- app/controllers/miq_ae_class_controller.rb | 64 +++++++ .../miq-ae-class/class-form.schema.js | 36 ++++ .../components/miq-ae-class/index.jsx | 174 ++++++++++++++++++ .../packs/component-definitions-common.js | 2 + .../miq-ae-class-form.spec.js.snap | 5 + .../miq-ae-class-form.spec.js | 62 +++++++ app/views/miq_ae_class/_class_form.html.haml | 41 +---- config/routes.rb | 2 + .../Embedded-Automate/Explorer/class.cy.js | 125 +++++++++++++ 9 files changed, 476 insertions(+), 35 deletions(-) create mode 100644 app/javascript/components/miq-ae-class/class-form.schema.js create mode 100644 app/javascript/components/miq-ae-class/index.jsx create mode 100644 app/javascript/spec/miq-ae-class-form/__snapshots__/miq-ae-class-form.spec.js.snap create mode 100644 app/javascript/spec/miq-ae-class-form/miq-ae-class-form.spec.js create mode 100644 cypress/e2e/ui/Automation/Embedded-Automate/Explorer/class.cy.js diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index bb7da5ba57c..21bb1e9c02c 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -341,6 +341,9 @@ def replace_right_cell(options = {}) :serialize => @sb[:active_tab] == 'methods', } ]) + if @hide_bottom_bar + presenter.hide(:paging_div, :form_buttons_div) + end else # incase it was hidden for summary screen, and incase there were no records on show_list presenter.hide(:paging_div, :form_buttons_div) @@ -459,6 +462,7 @@ def edit_class @ae_class = find_record_with_rbac(MiqAeClass, params[:id]) end set_form_vars + @hide_bottom_bar = true # have to get name and set node info, to load multiple tabs correctly # rec_name = get_rec_name(@ae_class) # get_node_info("aec-#{@ae_class.id}") @@ -468,6 +472,24 @@ def edit_class replace_right_cell end + def edit_class_record + assert_privileges("miq_ae_class_edit") + unless params[:id] + obj = find_checked_items + @_params[:id] = obj[0] + end + @hide_bottom_bar = true + + class_rec = MiqAeClass.find(params[:id]) + + render :json => { + :fqname => class_rec.fqname, + :name => class_rec.name, + :display_name => class_rec.display_name, + :description => class_rec.description + } + end + def edit_fields assert_privileges("miq_ae_field_edit") if params[:pressed] == "miq_ae_item_edit" # came from Namespace details screen @@ -1291,6 +1313,7 @@ def new assert_privileges("miq_ae_class_new") @ae_class = MiqAeClass.new set_form_vars + @hide_bottom_bar = true @in_a_form = true replace_right_cell end @@ -1841,8 +1864,49 @@ def ae_method_operations end end + def class_update + assert_privileges(params[:id].present? ? 'miq_ae_class_edit' : 'miq_ae_class_new') + @hide_bottom_bar = true + class_update_create + end + private + def class_update_create + case params[:button] + when "add", "save" + class_rec = params[:id].blank? ? MiqAeClass.new : MiqAeClass.find(params[:id]) # Get new or existing record + add_flash(_("Name is required"), :error) if params[:name].blank? + class_rec.name = params[:name] + class_rec.display_name = params[:display_name] + class_rec.description = params[:description] + class_rec.namespace_id = x_node.split('-')[1] if params[:id].blank? + begin + class_rec.save! + rescue StandardError + class_rec.errors.each do |error| + add_flash("#{error.attribute.to_s.capitalize} #{error.message}", :error) + end + @changed = true + javascript_flash + else + edit_hash = {} + edit_hash[:new] = {:name => params[:name], + :display_name => params[:display_name], :description => params[:description]} + edit_hash[:current] = if params[:old_data] + {:name => params[:old_data][:name], + :display_name => params[:old_data][:display_name], + :description => params[:old_data][:description]} + else + {:name => nil, :display_name => nil, :description => nil} + end + AuditEvent.success(build_saved_audit(class_rec, edit_hash)) + @edit = session[:edit] = nil # clean out the saved info + replace_right_cell(:nodetype => x_node, :replace_trees => [:ae]) + end + end + end + def get_template_class(location) if location == "ansible_workflow_template" ManageIQ::Providers::ExternalAutomationManager::ConfigurationWorkflow diff --git a/app/javascript/components/miq-ae-class/class-form.schema.js b/app/javascript/components/miq-ae-class/class-form.schema.js new file mode 100644 index 00000000000..49133416e82 --- /dev/null +++ b/app/javascript/components/miq-ae-class/class-form.schema.js @@ -0,0 +1,36 @@ +import { componentTypes, validatorTypes } from '@@ddf'; + +const createSchema = (fqname) => ({ + fields: [ + { + component: componentTypes.PLAIN_TEXT, + name: 'fqname', + label: `${__('Fully Qualified Name')}:\t ${fqname}`, + }, + { + component: componentTypes.TEXT_FIELD, + id: 'name', + name: 'name', + label: __('Name'), + maxLength: 128, + validate: [{ type: validatorTypes.REQUIRED }], + isRequired: true, + }, + { + component: componentTypes.TEXT_FIELD, + id: 'display_name', + name: 'display_name', + label: __('Display Name'), + maxLength: 128, + }, + { + component: componentTypes.TEXT_FIELD, + id: 'description', + name: 'description', + label: __('Description'), + maxLength: 255, + }, + ], +}); + +export default createSchema; diff --git a/app/javascript/components/miq-ae-class/index.jsx b/app/javascript/components/miq-ae-class/index.jsx new file mode 100644 index 00000000000..c5138cdbcbd --- /dev/null +++ b/app/javascript/components/miq-ae-class/index.jsx @@ -0,0 +1,174 @@ +import React, { useState, useEffect } from 'react'; +import { FormSpy } from '@data-driven-forms/react-form-renderer'; +import { Button } from 'carbon-components-react'; +import MiqFormRenderer, { useFormApi } from '@@ddf'; +import PropTypes from 'prop-types'; +import createSchema from './class-form.schema'; +import miqRedirectBack from '../../helpers/miq-redirect-back'; + +const MiqAeClass = ({ classRecord, fqname }) => { + const [data, setData] = useState({ + isLoading: true, + initialValues: undefined, + }); + + const isEdit = !!(classRecord && classRecord.id); + + useEffect(() => { + if (isEdit) { + http.get(`/miq_ae_class/edit_class_record/${classRecord.id}/`).then((recordValues) => { + if (recordValues) { + setData({ ...data, isLoading: false, initialValues: recordValues }); + } + }); + } else { + const initialValues = { + fqname, + name: classRecord && classRecord.name, + display_name: classRecord && classRecord.display_name, + description: classRecord && classRecord.description, + }; + setData({ ...data, isLoading: false, initialValues }); + } + }, [classRecord]); + + const onSubmit = (values) => { + miqSparkleOn(); + + const params = { + action: isEdit ? 'edit' : 'create', + name: values.name, + display_name: values.display_name, + description: values.description, + old_data: data.initialValues, + button: classRecord.id ? 'save' : 'add', + }; + + const request = isEdit + ? http.post(`/miq_ae_class/class_update/${classRecord.id}`, params) + : http.post(`/miq_ae_class/class_update/`, params); + + request + .then(() => { + const confirmation = isEdit ? __(`Class "${values.name}" was saved`) : __(`Class "${values.name}" was added`); + miqRedirectBack(sprintf(confirmation, values.name), 'success', '/miq_ae_class/explorer'); + }) + .catch(miqSparkleOff); + }; + + const onCancel = () => { + const confirmation = classRecord.id ? __(`Edit of Class "${classRecord.name}" cancelled by the user`) + : __(`Add of new Class was cancelled by the user`); + const message = sprintf( + confirmation + ); + miqRedirectBack(message, 'warning', '/miq_ae_class/explorer'); + }; + + return (!data.isLoading + ? ( +
+ {}} + FormTemplate={(props) => } + /> +
+ ) : null + ); +}; + +const FormTemplate = ({ + formFields, recId, +}) => { + const { + handleSubmit, onReset, onCancel, getState, + } = useFormApi(); + const { valid, pristine } = getState(); + const submitLabel = !!recId ? __('Save') : __('Add'); + return ( +
+ {formFields} + + {() => ( +
+ { !recId + ? ( + + ) : ( + + )} + {!!recId + ? ( + + ) : null} + + +
+ )} +
+
+ ); +}; + +MiqAeClass.propTypes = { + classRecord: PropTypes.shape({ + id: PropTypes.number, + name: PropTypes.string, + display_name: PropTypes.string, + description: PropTypes.string, + }), + fqname: PropTypes.string.isRequired, +}; + +MiqAeClass.defaultProps = { + classRecord: undefined, +}; + +FormTemplate.propTypes = { + formFields: PropTypes.arrayOf( + PropTypes.shape({ id: PropTypes.number }), + PropTypes.shape({ name: PropTypes.string }), + PropTypes.shape({ display_name: PropTypes.string }), + PropTypes.shape({ description: PropTypes.string }), + ), + recId: PropTypes.number, +}; + +FormTemplate.defaultProps = { + formFields: undefined, + recId: undefined, +}; + +export default MiqAeClass; diff --git a/app/javascript/packs/component-definitions-common.js b/app/javascript/packs/component-definitions-common.js index f56709a0b77..b5e3b5de67f 100644 --- a/app/javascript/packs/component-definitions-common.js +++ b/app/javascript/packs/component-definitions-common.js @@ -177,6 +177,7 @@ import WorkflowPayload from '../components/workflows/workflow_payload'; import WorkflowRepositoryForm from '../components/workflow-repository-form'; import XmlHolder from '../components/XmlHolder'; import ZoneForm from '../components/zone-form'; +import MiqAeClass from '../components/miq-ae-class'; /** * Add component definitions to this file. @@ -363,3 +364,4 @@ ManageIQ.component.addReact('WorkflowPayload', WorkflowPayload); ManageIQ.component.addReact('WorkflowRepositoryForm', WorkflowRepositoryForm); ManageIQ.component.addReact('XmlHolder', XmlHolder); ManageIQ.component.addReact('ZoneForm', ZoneForm); +ManageIQ.component.addReact('MiqAeClass', MiqAeClass); diff --git a/app/javascript/spec/miq-ae-class-form/__snapshots__/miq-ae-class-form.spec.js.snap b/app/javascript/spec/miq-ae-class-form/__snapshots__/miq-ae-class-form.spec.js.snap new file mode 100644 index 00000000000..412578bfe67 --- /dev/null +++ b/app/javascript/spec/miq-ae-class-form/__snapshots__/miq-ae-class-form.spec.js.snap @@ -0,0 +1,5 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MiqAeClass Form Component should render add class form correctly 1`] = `""`; + +exports[`MiqAeClass Form Component should render edit class form correctly 1`] = `""`; diff --git a/app/javascript/spec/miq-ae-class-form/miq-ae-class-form.spec.js b/app/javascript/spec/miq-ae-class-form/miq-ae-class-form.spec.js new file mode 100644 index 00000000000..8e369f9327b --- /dev/null +++ b/app/javascript/spec/miq-ae-class-form/miq-ae-class-form.spec.js @@ -0,0 +1,62 @@ +import React from 'react'; +import fetchMock from 'fetch-mock'; +import { shallow } from 'enzyme'; +import toJson from 'enzyme-to-json'; +import MiqAeClass from '../../components/miq-ae-class'; + +describe('MiqAeClass Form Component', () => { + const classMockData = [ + { + href: `/miq_ae_class/edit_class/2/`, + id: 2, + description: 'Configured System Provision', + }, + ]; + + const MiqAeClassEditData = { + id: 40, + name: 'test', + display_name: 'test display name', + description: 'test description', + }; + + const fqName = 'Sample FQ Name'; + + afterEach(() => { + fetchMock.reset(); + fetchMock.restore(); + }); + + it('should render add class form correctly', async() => { + const wrapper = shallow(); + + fetchMock.get(`/miq_ae_class/new?&expand=resources/`, classMockData); + + await new Promise((resolve) => { + setImmediate(() => { + wrapper.update(); + expect(toJson(wrapper)).toMatchSnapshot(); + resolve(); + }); + }); + }); + + it('should render edit class form correctly', async() => { + const wrapper = shallow(); + + fetchMock.get(`/miq_ae_class/edit_class_react/${MiqAeClassEditData.id}?&expand=resources/`, classMockData); + await new Promise((resolve) => { + setImmediate(() => { + wrapper.update(); + expect(toJson(wrapper)).toMatchSnapshot(); + resolve(); + }); + }); + }); +}); diff --git a/app/views/miq_ae_class/_class_form.html.haml b/app/views/miq_ae_class/_class_form.html.haml index 5d3d9bc3808..a3e5041d203 100644 --- a/app/views/miq_ae_class/_class_form.html.haml +++ b/app/views/miq_ae_class/_class_form.html.haml @@ -1,35 +1,6 @@ -- url = url_for_only_path(:action => 'form_field_changed', :id => (@ae_class.id || 'new')) -- obs = {:interval => '.5', :url => url}.to_json -%h3 - = _('Properties') -.form-horizontal - .form-group - %label.col-md-2.control-label - = _('Fully Qualified Name') - .col-md-8 - = @sb[:namespace_path] - .form-group - %label.col-md-2.control-label - = _('Name') - .col-md-8 - = text_field_tag("name", @edit[:new][:name], - :maxlength => ViewHelper::MAX_NAME_LEN, - :class => "form-control", - "data-miq_observe" => obs) - = javascript_tag(javascript_focus('name')) - .form-group - %label.col-md-2.control-label - = _('Display Name') - .col-md-8 - = text_field_tag("display_name", @edit[:new][:display_name], - :maxlength => ViewHelper::MAX_NAME_LEN, - :class => "form-control", - "data-miq_observe" => obs) - .form-group - %label.col-md-2.control-label - = _('Description') - .col-md-8 - = text_field_tag("description", @edit[:new][:description], - :maxlength => ViewHelper::MAX_NAME_LEN, - :class => "form-control", - "data-miq_observe" => obs) +- if @ae_class + - if @in_a_form + = react('MiqAeClass', + :classRecord => @ae_class, + :fqname => @sb[:namespace_path]) + diff --git a/config/routes.rb b/config/routes.rb index 2056e137c7d..a796ad5f217 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1911,6 +1911,7 @@ ae_methods ae_method_operations show + edit_class_record ], :post => %w[ add_update_method @@ -1955,6 +1956,7 @@ x_button x_history x_show + class_update ] + adv_search_post + exp_post }, diff --git a/cypress/e2e/ui/Automation/Embedded-Automate/Explorer/class.cy.js b/cypress/e2e/ui/Automation/Embedded-Automate/Explorer/class.cy.js new file mode 100644 index 00000000000..d728adf6824 --- /dev/null +++ b/cypress/e2e/ui/Automation/Embedded-Automate/Explorer/class.cy.js @@ -0,0 +1,125 @@ +/* eslint-disable no-undef */ + +describe('Automation > Embedded Automate > Explorer', () => { + beforeEach(() => { + cy.login(); + cy.intercept('POST', '/ops/accordion_select?id=rbac_accord').as('accordion'); + cy.menu('Automation', 'Embedded Automate', 'Explorer'); + cy.get('#explorer_title_text'); + }); + + afterEach(() => { + // Remove Domain after each tests + cy.get('[title="Datastore"]').click({force: true}); + cy.get('[title="Automate Domain: TestDomain"]').click({force: true}); + cy.get('[title="Configuration"]').click({force: true}); + cy.get('[title="Remove this Domain"]').click({force: true}); + + cy.get('.bx--data-table-content tbody tr').should('not.contain', 'Automate Domain: TestDomain'); + }); + + describe('Class Form', () => { + it('Creates and edits an automate class', () => { + // Creates a Domain + cy.get('[title="Datastore"]').click({force: true}); + cy.get('[title="Configuration"]').click({force: true}); + cy.get('[title="Add a New Domain"]').click({force: true}); + cy.get('[name="name"]').type('TestDomain'); + cy.get('[name="description"]').type('This is a test domain'); + cy.get('#enabled').check(); + cy.get('[class="bx--btn bx--btn--primary"]').contains('Add').click(); // submits Domain + // checks for the success message + cy.get('div.alert.alert-success.alert-dismissable') + .should('exist') + .and('contain', 'Automate Domain "TestDomain" was added') + .find('button.close').should('exist'); + + // Creates a Namespace + cy.get('[title="Datastore"]').click({force: true}); + cy.get('[title="Automate Domain: TestDomain"]').click({force: true}); // clicks on Domain + cy.get('[title="Configuration"]').click({force: true}); + cy.get('[title="Add a New Namespace"]').click({force: true}); + cy.get('[name="name"]').type('TestNS'); + cy.get('[name="description"]').type('This is a test NS'); + cy.get('.bx--btn--primary').contains('Add').click(); // submits Namespace + + // Creates a Class + cy.get('[title="Datastore"]').click({force: true}); + cy.get('[title="Automate Domain: TestDomain"]').click({force: true}); // clicks on Domain + cy.get('[title="Automate Namespace: TestNS"]').click({force: true}); // clicks on Namespace + cy.get('[title="Configuration"]').click({force: true}); + cy.get('[title="Add a New Class"]').click({force: true}); + cy.get('[name="name"]').type('TestClass'); + cy.get('[name="display_name"]').type('TC'); + cy.get('[name="description"').type('This is a test class desc'); + cy.get('.bx--btn--primary').contains('Add').click(); // submits class + // checks for the success message + cy.get('#flash_msg_div .alert.alert-success').should('exist') + .and('be.visible').and('contain', 'Class "TestClass" was added'); + + // Edits a class + cy.get('[title="Automate Class: TC (TestClass)"]').click({force: true}); // clicks on the class + cy.get('[title="Configuration"]').click({force: true}); + cy.get('[title="Edit this Class"]').click({force: true}); + cy.get('[name="display_name"]').clear({force: true}); + cy.get('[name="display_name"]').type('Edited TC', {force: true}); + cy.get('[name="description"').clear({force: true}); + cy.get('[name="description"').type('Edited Test Class Description'); + cy.get('[class="btnRight bx--btn bx--btn--primary"]').contains('Save').click({force: true}); + // Checks if class data was updated + cy.get('#props_tab a').click(); // Navigate to the Properties tab + cy.get('div.label_header:contains("Name")').siblings('.content_value') + .should('contain', 'TestClass'); + cy.get('div.label_header:contains("Display Name")').siblings('.content_value') + .should('contain', 'Edited TC'); + cy.get('div.label_header:contains("Description")').siblings('.content_value') + .should('contain', 'Edited Test Class Description'); + + // Clicks the Cancel button during class creation + cy.get('[title="Datastore"]').click({force: true}); + cy.get('[title="Automate Domain: TestDomain"]').click({force: true}); + cy.get('[title="Automate Namespace: TestNS"]').click({force: true}); + cy.get('[title="Configuration"]').click({force: true}); + cy.get('[title="Add a New Class"]').click({force: true}); + cy.get('[class="bx--btn bx--btn--secondary"]') + .contains('Cancel').click({force: true}); // clicks Cancel button + cy.get('[id="explorer_title_text"]').contains('Automate Namespace "TestNS"'); + + // Clicks the Cancel button during class update + cy.get('[title="Automate Class: Edited TC (TestClass)"]').click({force: true}); // clicks on the class + cy.get('[title="Configuration"]').click({force: true}); + cy.get('[title="Edit this Class"]').click({force: true}); + cy.get('[name="description"]').clear({force: true}); + cy.get('[name="description"]').type('New description for class', {force: true}); + cy.get('[class="bx--btn bx--btn--secondary"]').contains('Cancel').click({force: true}); + // Checks if class data was updated + cy.get('#props_tab a').click(); // Navigate to the Properties tab + cy.get('div.label_header:contains("Description")').siblings('.content_value') + .should('not.contain', 'New description for class') + .should('contain', 'Edited Test Class Description'); + + // Clicks the Reset button during class update + cy.get('[title="Automate Class: Edited TC (TestClass)"]').click({force: true}); // clicks on the class + cy.get('[title="Configuration"]').click({force: true}); + cy.get('[title="Edit this Class"]').click({force: true}); + cy.get('[name="description"]').clear({force: true}); + cy.get('[name="description"]').type('New description for class', {force: true}); + cy.get('[class="btnRight bx--btn bx--btn--secondary"]').contains('Reset').click({force: true}); + // Check for the flash message div + cy.get('#flash_msg_div .alert.alert-warning').should('exist') + .and('be.visible').and('contain', 'All changes have been reset'); + // Checks if class data was updated + cy.get('[name="description"]').should('have.value', 'Edited Test Class Description'); + cy.get('[class="bx--btn bx--btn--secondary"]').contains('Cancel').click({force: true}); + + // Removes class + cy.get('[title="Automate Class: Edited TC (TestClass)"]').click({force: true}); // clicks on the class + cy.get('[title="Configuration"]').click({force: true}); + cy.get('[title="Remove this Class"]').click({force: true}); + // checks for the success message + cy.get('div.alert.alert-success.alert-dismissable') + .should('exist') + .and('contain', 'Automate Class "TestClass": Delete successful'); + }); + }); +}); From 6029c956a0b8cb98b7c059968fe7e5df623998bf Mon Sep 17 00:00:00 2001 From: Gilbert Cherrie Date: Thu, 28 Nov 2024 11:59:37 -0500 Subject: [PATCH 2/8] Minor fixes --- app/controllers/miq_ae_class_controller.rb | 7 +- .../miq-ae-class/class-form.schema.js | 4 +- .../components/miq-ae-class/index.jsx | 25 +- cypress.config.js | 2 +- .../Embedded-Automate/Explorer/class.cy.js | 342 +++++++++++++----- 5 files changed, 278 insertions(+), 102 deletions(-) diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index 21bb1e9c02c..dac870c46db 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -1884,11 +1884,12 @@ def class_update_create begin class_rec.save! rescue StandardError + errors = [] class_rec.errors.each do |error| - add_flash("#{error.attribute.to_s.capitalize} #{error.message}", :error) + errors.push("#{error.attribute.to_s.capitalize} #{error.message}") end @changed = true - javascript_flash + render :json => {:error => errors, :status => 500} else edit_hash = {} edit_hash[:new] = {:name => params[:name], @@ -1902,7 +1903,7 @@ def class_update_create end AuditEvent.success(build_saved_audit(class_rec, edit_hash)) @edit = session[:edit] = nil # clean out the saved info - replace_right_cell(:nodetype => x_node, :replace_trees => [:ae]) + render :json => {:status => 200} end end end diff --git a/app/javascript/components/miq-ae-class/class-form.schema.js b/app/javascript/components/miq-ae-class/class-form.schema.js index 49133416e82..86132e5141e 100644 --- a/app/javascript/components/miq-ae-class/class-form.schema.js +++ b/app/javascript/components/miq-ae-class/class-form.schema.js @@ -1,4 +1,4 @@ -import { componentTypes, validatorTypes } from '@@ddf'; +import { componentTypes } from '@@ddf'; const createSchema = (fqname) => ({ fields: [ @@ -13,7 +13,7 @@ const createSchema = (fqname) => ({ name: 'name', label: __('Name'), maxLength: 128, - validate: [{ type: validatorTypes.REQUIRED }], + validate: [{ type: 'customValidatorForNameField' }], isRequired: true, }, { diff --git a/app/javascript/components/miq-ae-class/index.jsx b/app/javascript/components/miq-ae-class/index.jsx index c5138cdbcbd..e8086299079 100644 --- a/app/javascript/components/miq-ae-class/index.jsx +++ b/app/javascript/components/miq-ae-class/index.jsx @@ -5,6 +5,7 @@ import MiqFormRenderer, { useFormApi } from '@@ddf'; import PropTypes from 'prop-types'; import createSchema from './class-form.schema'; import miqRedirectBack from '../../helpers/miq-redirect-back'; +import miqFlash from '../../helpers/miq-flash'; const MiqAeClass = ({ classRecord, fqname }) => { const [data, setData] = useState({ @@ -49,9 +50,14 @@ const MiqAeClass = ({ classRecord, fqname }) => { : http.post(`/miq_ae_class/class_update/`, params); request - .then(() => { - const confirmation = isEdit ? __(`Class "${values.name}" was saved`) : __(`Class "${values.name}" was added`); - miqRedirectBack(sprintf(confirmation, values.name), 'success', '/miq_ae_class/explorer'); + .then((response) => { + if (response.status === 200) { + const confirmation = isEdit ? __(`Class "${values.name}" was saved`) : __(`Class "${values.name}" was added`); + miqRedirectBack(sprintf(confirmation, values.name), 'success', '/miq_ae_class/explorer'); + } else { + miqSparkleOff(); + miqFlash('error', response.error); + } }) .catch(miqSparkleOff); }; @@ -65,12 +71,25 @@ const MiqAeClass = ({ classRecord, fqname }) => { miqRedirectBack(message, 'warning', '/miq_ae_class/explorer'); }; + const customValidatorMapper = { + customValidatorForNameField: () => (value) => { + if (!value) { + return __('Required'); + } + if (!value.match('^[a-zA-Z0-9_.-]*$')) { + return __('Name may contain only alphanumeric and _ . - characters'); + } + return false; + }, + }; + return (!data.isLoading ? (
Embedded Automate > Explorer', () => { - beforeEach(() => { + before(() => { + // Create a Domain and Namespace before all the tests cy.login(); cy.intercept('POST', '/ops/accordion_select?id=rbac_accord').as('accordion'); cy.menu('Automation', 'Embedded Automate', 'Explorer'); cy.get('#explorer_title_text'); - }); - afterEach(() => { - // Remove Domain after each tests - cy.get('[title="Datastore"]').click({force: true}); - cy.get('[title="Automate Domain: TestDomain"]').click({force: true}); - cy.get('[title="Configuration"]').click({force: true}); - cy.get('[title="Remove this Domain"]').click({force: true}); + // Creates a Domain + cy.get('[title="Datastore"]').click(); + cy.get('[title="Configuration"]').click(); + cy.get('[title="Add a New Domain"]').click(); + cy.get('[name="name"]').type('TestDomain', {force: true}); + cy.get('[name="description"]').type('This is a test domain'); + cy.get('#enabled').check(); + cy.get('[class="bx--btn bx--btn--primary"]').contains('Add').click(); - cy.get('.bx--data-table-content tbody tr').should('not.contain', 'Automate Domain: TestDomain'); + // Check for the success message + cy.get('div.alert.alert-success.alert-dismissable').should('exist').and('contain', 'Automate Domain "TestDomain" was added').find('button.close').should('exist'); + + // Creates a Namespace + cy.get('[title="Datastore"]').click(); + cy.get('[title="Automate Domain: TestDomain"]').click(); // Click on Domain + cy.get('[title="Configuration"]').click(); + cy.get('[title="Add a New Namespace"]').click(); + cy.get('[name="name"]').type('TestNameSpace', {force: true}); + cy.get('[name="description"]').type('This is a test NameSpace'); + cy.get('.bx--btn--primary').contains('Add').click(); + + cy.wait(1000); // Need this wait or else namespace doesn't get added properly + }); + + beforeEach(() => { + cy.login(); + cy.intercept('POST', '/ops/accordion_select?id=rbac_accord').as('accordion'); + cy.menu('Automation', 'Embedded Automate', 'Explorer'); + cy.get('#explorer_title_text'); }); describe('Class Form', () => { - it('Creates and edits an automate class', () => { - // Creates a Domain - cy.get('[title="Datastore"]').click({force: true}); - cy.get('[title="Configuration"]').click({force: true}); - cy.get('[title="Add a New Domain"]').click({force: true}); - cy.get('[name="name"]').type('TestDomain'); - cy.get('[name="description"]').type('This is a test domain'); - cy.get('#enabled').check(); - cy.get('[class="bx--btn bx--btn--primary"]').contains('Add').click(); // submits Domain - // checks for the success message - cy.get('div.alert.alert-success.alert-dismissable') - .should('exist') - .and('contain', 'Automate Domain "TestDomain" was added') - .find('button.close').should('exist'); + it('Cancel button works on the form', () => { + // Clicks the Cancel button on the create class form + cy.get('[title="Datastore"]').click(); + cy.get('[title="Automate Domain: TestDomain"]').click(); + cy.get('[title="Automate Namespace: TestNameSpace"]').click(); + cy.get('[title="Configuration"]').click(); + cy.get('[title="Add a New Class"]').click(); + cy.get('[class="bx--btn bx--btn--secondary"]').contains('Cancel').click(); // clicks Cancel button - // Creates a Namespace - cy.get('[title="Datastore"]').click({force: true}); - cy.get('[title="Automate Domain: TestDomain"]').click({force: true}); // clicks on Domain - cy.get('[title="Configuration"]').click({force: true}); - cy.get('[title="Add a New Namespace"]').click({force: true}); - cy.get('[name="name"]').type('TestNS'); - cy.get('[name="description"]').type('This is a test NS'); - cy.get('.bx--btn--primary').contains('Add').click(); // submits Namespace + // Make sure that the cancel button redirects back to the namespace page + cy.get('[id="explorer_title_text"]').contains('Automate Namespace "TestNameSpace"'); + cy.get('.flash_text_div > .alert').contains('Add of new Class was cancelled by the user'); + cy.get('#ns_details_div > .alert').contains('The selected Namespace is empty'); + }); + + it('Reset button works on the form', () => { + // Creates a Class + cy.get('[title="Datastore"]').click(); + cy.get('[title="Automate Domain: TestDomain"]').click(); // clicks on Domain + cy.get('[title="Automate Namespace: TestNameSpace"]').click(); // clicks on Namespace + cy.get('[title="Configuration"]').click(); + cy.get('[title="Add a New Class"]').click(); + cy.get('[name="name"]').type('TestClass', {force: true}); + cy.get('[name="display_name"]').type('Test Class 0'); + cy.get('[name="description"').type('This is a test class description'); + cy.get('.bx--btn--primary').contains('Add').click(); + + // Check for the success message + cy.get('#flash_msg_div .alert.alert-success').should('exist').and('be.visible').and('contain', 'Class "TestClass" was added'); + + // Navigate to the Properties tab of the class just created + cy.get('.clickable-row').contains('Test Class 0').click(); + cy.get('#props_tab > a').click(); + + // Edits the class + cy.get('[title="Configuration"]').click(); + cy.get('[title="Edit this Class"]').click(); + cy.get('[name="name"]').type('Edit', {force: true}); + cy.get('[name="display_name"]').clear().type('Edited Test Class'); + cy.get('[name="description"').clear().type('Edited test class description'); + + // Click Reset Button + cy.get('.btnRight.bx--btn--secondary').contains('Reset').click(); + + // Verify that the form was reset + cy.get('.flash_text_div > .alert').contains('All changes have been reset'); + cy.get('[name="name"]').should('have.value', 'TestClass'); + cy.get('[name="display_name"]').should('have.value', 'Test Class 0'); + cy.get('[name="description"]').should('have.value', 'This is a test class description'); + + // Click Cancel button + cy.get('[class="bx--btn bx--btn--secondary"]').contains('Cancel').click(); + + // Removes class + cy.get('[title="Configuration"]').click(); + cy.get('[title="Remove this Class"]').click(); + + // Verify that the class was removed + cy.get('div.alert.alert-success.alert-dismissable').should('exist').and('contain', 'Automate Class "TestClass": Delete successful'); + cy.get('#ns_details_div > .alert').contains('The selected Namespace is empty'); + }); + + it('Form validation works', () => { + // Try to create a Class with an invalid name + cy.get('[title="Datastore"]').click(); + cy.get('[title="Automate Domain: TestDomain"]').click(); // clicks on Domain + cy.get('[title="Automate Namespace: TestNameSpace"]').click(); // clicks on Namespace + + cy.get('[title="Configuration"]').click(); + cy.get('[title="Add a New Class"]').click(); + cy.get('[name="name"]').type('Test Class', {force: true}); + cy.get('[name="display_name"]').type('Test Class 0'); + cy.get('[name="description"').type('This is a test class description'); + + // Verify that error message appears + cy.get('#name-error-msg').contains('Name may contain only alphanumeric and _ . - characters'); + cy.get('.btnRight').should('be.disabled'); + + // Enter a valid name + cy.get('[name="name"]').clear({force: true}).type('TestClass'); + cy.get('.btnRight').click(); + cy.get('#flash_msg_div .alert.alert-success').should('exist').and('be.visible').and('contain', 'Class "TestClass" was added'); + + // Navigate to the Properties tab of the class just created + cy.get('.clickable-row').contains('Test Class 0').click(); + cy.get('#props_tab > a').click(); + + // Verify that the class created correctly + cy.get(':nth-child(1) > .label_header').contains('Fully Qualified Name'); + cy.get(':nth-child(1) > .content_value').contains('/ TestDomain / TestNameSpace / TestClass'); + cy.get(':nth-child(2) > .label_header').contains('Name'); + cy.get(':nth-child(2) > .content_value').contains('TestClass'); + cy.get(':nth-child(3) > .label_header').contains('Display Name'); + cy.get(':nth-child(3) > .content_value').contains('Test Class 0'); + cy.get(':nth-child(4) > .label_header').contains('Description'); + cy.get(':nth-child(4) > .content_value').contains('This is a test class description'); + cy.get(':nth-child(5) > .label_header').contains('Instances'); + cy.get(':nth-child(5) > .content_value').contains('0'); + + cy.get('.list-group-item').then((listItems) => { + const nums = [...Array(listItems.length).keys()]; + nums.forEach((index) => { + if (listItems[index].innerText === 'TestNameSpace') { + cy.get(listItems[index]).click(); + } + }); + }); + + // Try to create a Class with the same name + cy.get('[title="Configuration"]').click(); + cy.get('[title="Add a New Class"]').click(); + cy.get('[name="name"]').type('TestClass', {force: true}); + cy.get('[name="display_name"]').type('Test Class 1'); + cy.get('[name="description"').type('This is a test class description'); + cy.get('.btnRight').click(); + + // Verify that error message appears + cy.get('.alert').contains('Name has already been taken'); + + // Enter a new name + cy.get('[name="name"]').clear({force: true}).type('NewTestClass', {force: true}); + cy.get('.btnRight').click(); + + // Check for the success message + cy.get('#flash_msg_div .alert.alert-success').should('exist').and('be.visible').and('contain', 'Class "NewTestClass" was added'); + + // Navigate to the Properties tab of the class just created + cy.get('.clickable-row').contains('Test Class 1').click(); + cy.get('#props_tab > a').click(); + + // Verify that the class created correctly + cy.get(':nth-child(1) > .label_header').contains('Fully Qualified Name'); + cy.get(':nth-child(1) > .content_value').contains('/ TestDomain / TestNameSpace / NewTestClass'); + cy.get(':nth-child(2) > .label_header').contains('Name'); + cy.get(':nth-child(2) > .content_value').contains('NewTestClass'); + cy.get(':nth-child(3) > .label_header').contains('Display Name'); + cy.get(':nth-child(3) > .content_value').contains('Test Class 1'); + cy.get(':nth-child(4) > .label_header').contains('Description'); + cy.get(':nth-child(4) > .content_value').contains('This is a test class description'); + cy.get(':nth-child(5) > .label_header').contains('Instances'); + cy.get(':nth-child(5) > .content_value').contains('0'); + + // Removes class + cy.get('[title="Configuration"]').click(); + cy.get('[title="Remove this Class"]').click(); + + // Verify that the class was removed + cy.get('div.alert.alert-success.alert-dismissable').should('exist').and('contain', 'Automate Class "NewTestClass": Delete successful'); + + // Navigate to the Properties tab of the first class just created + cy.get('.clickable-row').contains('Test Class 0').click(); + + // Removes class + cy.get('[title="Configuration"]').click(); + cy.get('[title="Remove this Class"]').click(); + + // Verify that the class was removed + cy.get('div.alert.alert-success.alert-dismissable').should('exist').and('contain', 'Automate Class "TestClass": Delete successful'); + cy.get('#ns_details_div > .alert').contains('The selected Namespace is empty'); + }); + + it('Creates and edits an automate class', () => { // Creates a Class cy.get('[title="Datastore"]').click({force: true}); cy.get('[title="Automate Domain: TestDomain"]').click({force: true}); // clicks on Domain - cy.get('[title="Automate Namespace: TestNS"]').click({force: true}); // clicks on Namespace + cy.get('[title="Automate Namespace: TestNameSpace"]').click({force: true}); // clicks on Namespace cy.get('[title="Configuration"]').click({force: true}); cy.get('[title="Add a New Class"]').click({force: true}); - cy.get('[name="name"]').type('TestClass'); - cy.get('[name="display_name"]').type('TC'); - cy.get('[name="description"').type('This is a test class desc'); - cy.get('.bx--btn--primary').contains('Add').click(); // submits class - // checks for the success message - cy.get('#flash_msg_div .alert.alert-success').should('exist') - .and('be.visible').and('contain', 'Class "TestClass" was added'); - - // Edits a class - cy.get('[title="Automate Class: TC (TestClass)"]').click({force: true}); // clicks on the class + cy.get('[name="name"]').type('TestClass', {force: true}); + cy.get('[name="display_name"]').type('Test Class 0'); + cy.get('[name="description"').type('This is a test class description'); + cy.get('.bx--btn--primary').contains('Add').click(); + + // Check for the success message + cy.get('#flash_msg_div .alert.alert-success').should('exist').and('be.visible').and('contain', 'Class "TestClass" was added'); + + // Navigate to the Properties tab of the class just created + cy.get('.clickable-row').contains('Test Class 0').click(); + cy.get('#props_tab > a').click(); + + // Verify that the class created correctly + cy.get(':nth-child(1) > .label_header').contains('Fully Qualified Name'); + cy.get(':nth-child(1) > .content_value').contains('/ TestDomain / TestNameSpace / TestClass'); + cy.get(':nth-child(2) > .label_header').contains('Name'); + cy.get(':nth-child(2) > .content_value').contains('TestClass'); + cy.get(':nth-child(3) > .label_header').contains('Display Name'); + cy.get(':nth-child(3) > .content_value').contains('Test Class 0'); + cy.get(':nth-child(4) > .label_header').contains('Description'); + cy.get(':nth-child(4) > .content_value').contains('This is a test class description'); + cy.get(':nth-child(5) > .label_header').contains('Instances'); + cy.get(':nth-child(5) > .content_value').contains('0'); + + // Edits the class cy.get('[title="Configuration"]').click({force: true}); cy.get('[title="Edit this Class"]').click({force: true}); - cy.get('[name="display_name"]').clear({force: true}); - cy.get('[name="display_name"]').type('Edited TC', {force: true}); - cy.get('[name="description"').clear({force: true}); - cy.get('[name="description"').type('Edited Test Class Description'); + cy.get('[name="name"]').type('Edit', {force: true}); + cy.get('[name="display_name"]').clear().type('Edited Test Class', {force: true}); + cy.get('[name="description"').clear().type('Edited test class description'); cy.get('[class="btnRight bx--btn bx--btn--primary"]').contains('Save').click({force: true}); - // Checks if class data was updated - cy.get('#props_tab a').click(); // Navigate to the Properties tab - cy.get('div.label_header:contains("Name")').siblings('.content_value') - .should('contain', 'TestClass'); - cy.get('div.label_header:contains("Display Name")').siblings('.content_value') - .should('contain', 'Edited TC'); - cy.get('div.label_header:contains("Description")').siblings('.content_value') - .should('contain', 'Edited Test Class Description'); - - // Clicks the Cancel button during class creation - cy.get('[title="Datastore"]').click({force: true}); - cy.get('[title="Automate Domain: TestDomain"]').click({force: true}); - cy.get('[title="Automate Namespace: TestNS"]').click({force: true}); - cy.get('[title="Configuration"]').click({force: true}); - cy.get('[title="Add a New Class"]').click({force: true}); - cy.get('[class="bx--btn bx--btn--secondary"]') - .contains('Cancel').click({force: true}); // clicks Cancel button - cy.get('[id="explorer_title_text"]').contains('Automate Namespace "TestNS"'); - // Clicks the Cancel button during class update - cy.get('[title="Automate Class: Edited TC (TestClass)"]').click({force: true}); // clicks on the class - cy.get('[title="Configuration"]').click({force: true}); - cy.get('[title="Edit this Class"]').click({force: true}); - cy.get('[name="description"]').clear({force: true}); - cy.get('[name="description"]').type('New description for class', {force: true}); - cy.get('[class="bx--btn bx--btn--secondary"]').contains('Cancel').click({force: true}); - // Checks if class data was updated - cy.get('#props_tab a').click(); // Navigate to the Properties tab - cy.get('div.label_header:contains("Description")').siblings('.content_value') - .should('not.contain', 'New description for class') - .should('contain', 'Edited Test Class Description'); - - // Clicks the Reset button during class update - cy.get('[title="Automate Class: Edited TC (TestClass)"]').click({force: true}); // clicks on the class - cy.get('[title="Configuration"]').click({force: true}); - cy.get('[title="Edit this Class"]').click({force: true}); - cy.get('[name="description"]').clear({force: true}); - cy.get('[name="description"]').type('New description for class', {force: true}); - cy.get('[class="btnRight bx--btn bx--btn--secondary"]').contains('Reset').click({force: true}); - // Check for the flash message div - cy.get('#flash_msg_div .alert.alert-warning').should('exist') - .and('be.visible').and('contain', 'All changes have been reset'); - // Checks if class data was updated - cy.get('[name="description"]').should('have.value', 'Edited Test Class Description'); - cy.get('[class="bx--btn bx--btn--secondary"]').contains('Cancel').click({force: true}); + // Navigate to the Properties tab of the class just edited + cy.get('#props_tab a').click(); + + // Verify that the class edited correctly + cy.get(':nth-child(1) > .label_header').contains('Fully Qualified Name'); + cy.get(':nth-child(1) > .content_value').contains('/ TestDomain / TestNameSpace / TestClassEdit'); + cy.get(':nth-child(2) > .label_header').contains('Name'); + cy.get(':nth-child(2) > .content_value').contains('TestClassEdit'); + cy.get(':nth-child(3) > .label_header').contains('Display Name'); + cy.get(':nth-child(3) > .content_value').contains('Edited Test Class'); + cy.get(':nth-child(4) > .label_header').contains('Description'); + cy.get(':nth-child(4) > .content_value').contains('Edited test class description'); + cy.get(':nth-child(5) > .label_header').contains('Instances'); + cy.get(':nth-child(5) > .content_value').contains('0'); // Removes class - cy.get('[title="Automate Class: Edited TC (TestClass)"]').click({force: true}); // clicks on the class cy.get('[title="Configuration"]').click({force: true}); cy.get('[title="Remove this Class"]').click({force: true}); - // checks for the success message + + // Verify that the class was removed cy.get('div.alert.alert-success.alert-dismissable') .should('exist') - .and('contain', 'Automate Class "TestClass": Delete successful'); + .and('contain', 'Automate Class "TestClassEdit": Delete successful'); + cy.get('#ns_details_div > .alert').contains('The selected Namespace is empty'); }); }); + + after(() => { + // Remove the Domain after all the tests + cy.menu('Automation', 'Embedded Automate', 'Explorer'); + cy.get('[title="Datastore"]').click({force: true}); + cy.get('[title="Automate Domain: TestDomain"]').click({force: true}); + cy.get('[title="Configuration"]').click({force: true}); + cy.get('[title="Remove this Domain"]').click({force: true}); + + cy.get('.bx--data-table-content tbody tr').should('not.contain', 'Automate Domain: TestDomain'); + }); }); From b90b9349a103c7d91657f010623d541c6c986b3e Mon Sep 17 00:00:00 2001 From: Elsa Mary Date: Tue, 3 Dec 2024 18:43:55 +0530 Subject: [PATCH 3/8] Uses placeholder for translations in the UI code --- app/javascript/components/miq-ae-class/index.jsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/javascript/components/miq-ae-class/index.jsx b/app/javascript/components/miq-ae-class/index.jsx index e8086299079..150869db4e9 100644 --- a/app/javascript/components/miq-ae-class/index.jsx +++ b/app/javascript/components/miq-ae-class/index.jsx @@ -52,8 +52,9 @@ const MiqAeClass = ({ classRecord, fqname }) => { request .then((response) => { if (response.status === 200) { - const confirmation = isEdit ? __(`Class "${values.name}" was saved`) : __(`Class "${values.name}" was added`); - miqRedirectBack(sprintf(confirmation, values.name), 'success', '/miq_ae_class/explorer'); + const confirmation = isEdit ? __(`Class "%s" was saved`) : __(`Class "%s" was added`); + const message = sprintf(confirmation, values.name); + miqRedirectBack(message, 'success', '/miq_ae_class/explorer'); } else { miqSparkleOff(); miqFlash('error', response.error); @@ -63,11 +64,9 @@ const MiqAeClass = ({ classRecord, fqname }) => { }; const onCancel = () => { - const confirmation = classRecord.id ? __(`Edit of Class "${classRecord.name}" cancelled by the user`) + const confirmation = classRecord.id ? __(`Edit of Class "%s" cancelled by the user`) : __(`Add of new Class was cancelled by the user`); - const message = sprintf( - confirmation - ); + const message = sprintf(confirmation, classRecord.name); miqRedirectBack(message, 'warning', '/miq_ae_class/explorer'); }; From e7802ea5cdd8712bf701e080d32a58c5a8ddd810 Mon Sep 17 00:00:00 2001 From: Elsa Mary Date: Wed, 4 Dec 2024 16:59:01 +0530 Subject: [PATCH 4/8] Formats Fully Qualified Name field --- app/javascript/components/miq-ae-class/class-form.schema.js | 6 ++++-- app/javascript/components/miq-ae-class/index.jsx | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/javascript/components/miq-ae-class/class-form.schema.js b/app/javascript/components/miq-ae-class/class-form.schema.js index 86132e5141e..dda2cd26785 100644 --- a/app/javascript/components/miq-ae-class/class-form.schema.js +++ b/app/javascript/components/miq-ae-class/class-form.schema.js @@ -3,9 +3,11 @@ import { componentTypes } from '@@ddf'; const createSchema = (fqname) => ({ fields: [ { - component: componentTypes.PLAIN_TEXT, + component: componentTypes.TEXT_FIELD, name: 'fqname', - label: `${__('Fully Qualified Name')}:\t ${fqname}`, + label: 'Fully Qualified Name', + value: `${fqname}`, + disabled: true, }, { component: componentTypes.TEXT_FIELD, diff --git a/app/javascript/components/miq-ae-class/index.jsx b/app/javascript/components/miq-ae-class/index.jsx index 150869db4e9..7630e4aba08 100644 --- a/app/javascript/components/miq-ae-class/index.jsx +++ b/app/javascript/components/miq-ae-class/index.jsx @@ -8,6 +8,7 @@ import miqRedirectBack from '../../helpers/miq-redirect-back'; import miqFlash from '../../helpers/miq-flash'; const MiqAeClass = ({ classRecord, fqname }) => { + const formattedFqname = fqname.replace(/\s+/g, ''); const [data, setData] = useState({ isLoading: true, initialValues: undefined, @@ -24,7 +25,7 @@ const MiqAeClass = ({ classRecord, fqname }) => { }); } else { const initialValues = { - fqname, + formattedFqname, name: classRecord && classRecord.name, display_name: classRecord && classRecord.display_name, description: classRecord && classRecord.description, @@ -86,7 +87,7 @@ const MiqAeClass = ({ classRecord, fqname }) => { ? (
Date: Thu, 5 Dec 2024 12:08:51 +0530 Subject: [PATCH 5/8] Cypress config 'numTestsKeptInMemory' put back to 0 --- cypress.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress.config.js b/cypress.config.js index 0577d4b77ae..c2afc4851f9 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -7,7 +7,7 @@ module.exports = defineConfig({ baseUrl: 'http://localhost:3000', viewportHeight: 800, viewportWidth: 1800, - numTestsKeptInMemory: 5, + numTestsKeptInMemory: 0, videoCompression: false, // eslint-disable-next-line no-unused-vars setupNodeEvents(on, config) { From 1e6098c9199505a6cf2d881739709bfdcbaab923 Mon Sep 17 00:00:00 2001 From: Elsa Mary Date: Tue, 17 Dec 2024 12:02:22 +0530 Subject: [PATCH 6/8] Removes spaces in the fqname --- app/controllers/miq_ae_class_controller.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb index dac870c46db..0dcf61e33a9 100644 --- a/app/controllers/miq_ae_class_controller.rb +++ b/app/controllers/miq_ae_class_controller.rb @@ -131,7 +131,6 @@ def set_right_cell_text(id, rec = nil) txt = rec.domain? ? _('Automate Domain') : _('Automate Namespace') @sb[:namespace_path] = rec.fqname end - @sb[:namespace_path]&.gsub!(%r{\/}, " / ") @right_cell_text = "#{txt} #{_("\"%s\"") % get_rec_name(rec)}" unless %w[root aei aem].include?(nodes[0]) end From de370e0edd31e5d0fd65d3e576c91a789c62becf Mon Sep 17 00:00:00 2001 From: Elsa Mary Date: Tue, 17 Dec 2024 14:57:50 +0530 Subject: [PATCH 7/8] rspec updated --- spec/controllers/miq_ae_class_controller_spec.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/controllers/miq_ae_class_controller_spec.rb b/spec/controllers/miq_ae_class_controller_spec.rb index 954d325cbee..0e72fd9e5f8 100644 --- a/spec/controllers/miq_ae_class_controller_spec.rb +++ b/spec/controllers/miq_ae_class_controller_spec.rb @@ -24,7 +24,8 @@ id = "aec-#{cls.id}" fq_name = cls.fqname controller.send(:set_right_cell_text, id, cls) - expect(assigns(:sb)[:namespace_path]).to eq(fq_name.gsub!(%r{\/}, " / ")) + # expect(assigns(:sb)[:namespace_path]).to eq(fq_name.gsub!(%r{\/}, " / ")) + expect(assigns(:sb)[:namespace_path]).to eq(fq_name) id = "root" fq_name = "" @@ -291,7 +292,8 @@ :active_tree => :ae_tree, :trees => {:ae_tree => {:active_node => node}}) controller.send(:get_node_info, node) - expect(assigns(:sb)[:namespace_path]).to eq(ns1.fqname.gsub!(%r{\/}, " / ")) + # expect(assigns(:sb)[:namespace_path]).to eq(ns1.fqname.gsub!(%r{\/}, " / ")) + expect(assigns(:sb)[:namespace_path]).to eq(ns1.fqname) end end From a82a6153932dd4abab196523a17a1a13bdffd520 Mon Sep 17 00:00:00 2001 From: Elsa Mary Date: Tue, 17 Dec 2024 15:19:02 +0530 Subject: [PATCH 8/8] Removes commented lines --- spec/controllers/miq_ae_class_controller_spec.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/controllers/miq_ae_class_controller_spec.rb b/spec/controllers/miq_ae_class_controller_spec.rb index 0e72fd9e5f8..27964a84ac4 100644 --- a/spec/controllers/miq_ae_class_controller_spec.rb +++ b/spec/controllers/miq_ae_class_controller_spec.rb @@ -24,7 +24,6 @@ id = "aec-#{cls.id}" fq_name = cls.fqname controller.send(:set_right_cell_text, id, cls) - # expect(assigns(:sb)[:namespace_path]).to eq(fq_name.gsub!(%r{\/}, " / ")) expect(assigns(:sb)[:namespace_path]).to eq(fq_name) id = "root" @@ -292,7 +291,6 @@ :active_tree => :ae_tree, :trees => {:ae_tree => {:active_node => node}}) controller.send(:get_node_info, node) - # expect(assigns(:sb)[:namespace_path]).to eq(ns1.fqname.gsub!(%r{\/}, " / ")) expect(assigns(:sb)[:namespace_path]).to eq(ns1.fqname) end end