Skip to content

Commit

Permalink
Transforms haml forms to react for Automate class
Browse files Browse the repository at this point in the history
  • Loading branch information
elsamaryv committed Nov 13, 2024
1 parent 61578ea commit d359d80
Show file tree
Hide file tree
Showing 9 changed files with 476 additions and 35 deletions.
64 changes: 64 additions & 0 deletions app/controllers/miq_ae_class_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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}")
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
36 changes: 36 additions & 0 deletions app/javascript/components/miq-ae-class/class-form.schema.js
Original file line number Diff line number Diff line change
@@ -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;
174 changes: 174 additions & 0 deletions app/javascript/components/miq-ae-class/index.jsx
Original file line number Diff line number Diff line change
@@ -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
? (
<div className="dialog-provision-form">
<MiqFormRenderer
schema={createSchema(fqname)}
initialValues={data.initialValues}
onSubmit={onSubmit}
onCancel={onCancel}
canReset={!!classRecord.id}
validate={() => {}}
FormTemplate={(props) => <FormTemplate {...props} recId={classRecord.id} />}
/>
</div>
) : null
);
};

const FormTemplate = ({
formFields, recId,
}) => {
const {
handleSubmit, onReset, onCancel, getState,
} = useFormApi();
const { valid, pristine } = getState();
const submitLabel = !!recId ? __('Save') : __('Add');
return (
<form onSubmit={handleSubmit}>
{formFields}
<FormSpy>
{() => (
<div className="custom-button-wrapper">
{ !recId
? (
<Button
disabled={!valid}
kind="primary"
className="btnRight"
type="submit"
variant="contained"
>
{submitLabel}
</Button>
) : (
<Button
disabled={!valid || pristine}
kind="primary"
className="btnRight"
type="submit"
variant="contained"
>
{submitLabel}
</Button>
)}
{!!recId
? (
<Button
disabled={pristine}
kind="secondary"
className="btnRight"
variant="contained"
onClick={onReset}
type="button"
>
{ __('Reset')}
</Button>
) : null}

<Button variant="contained" type="button" onClick={onCancel} kind="secondary">
{ __('Cancel')}
</Button>
</div>
)}
</FormSpy>
</form>
);
};

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;
2 changes: 2 additions & 0 deletions app/javascript/packs/component-definitions-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Original file line number Diff line number Diff line change
@@ -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`] = `""`;
62 changes: 62 additions & 0 deletions app/javascript/spec/miq-ae-class-form/miq-ae-class-form.spec.js
Original file line number Diff line number Diff line change
@@ -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(<MiqAeClass
classRecord={undefined}
fqname={fqName}
/>);

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(<MiqAeClass
classRecord={MiqAeClassEditData}
fqname={fqName}
/>);

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();
});
});
});
});
Loading

0 comments on commit d359d80

Please sign in to comment.