Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replaces angular ownership form with data-driven-form #5046

Merged
merged 7 commits into from Dec 7, 2018
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions .babelrc
Expand Up @@ -3,9 +3,9 @@
"env": {
"test": {
"presets": [
"react",
"react"
],
"plugins": ["transform-es2015-modules-commonjs"],
},
},
"plugins": ["transform-es2015-modules-commonjs", "babel-plugin-transform-class-properties"]
}
}
}

This file was deleted.

3 changes: 2 additions & 1 deletion app/javascript/.eslintrc.json
Expand Up @@ -34,6 +34,7 @@
}],
"no-use-before-define": ["error", { "functions": false, "classes": false }],
"react/jsx-filename-extension": "off",
"space-before-function-paren": [2, "never"]
"space-before-function-paren": [2, "never"],
"no-extra-boolean-cast": "off"
}
}
57 changes: 57 additions & 0 deletions app/javascript/components/set-service-ownership-form/index.jsx
@@ -0,0 +1,57 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Grid } from 'patternfly-react';
import MiqFormRenderer from '../../forms/data-driven-form';
import { http } from '../../http_api';
import { cleanVirtualDom } from '../../miq-component/helpers';
import createSchema from './schema';

class SetServiceOwnershipForm extends Component {
state = {
initialValues: {},
}

componentDidMount() {
cleanVirtualDom();
const { ownershipIds } = this.props;
this.loadInitialData(ownershipIds);
}

loadInitialData = objectIds =>
http.post('/service/ownership_form_fields', { object_ids: objectIds })
Copy link
Contributor

@himdel himdel Dec 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, all those /service/.. are wrong :(. (also goes for cancelUrl and submitUrl)

We need to be using the current controller, otherwise this fails for all the screens changing ownership for non-services.

Looks like the code is expecting the controller to be one of:

          when "orchestration_stack"
          when "service"
          when "vm_or_template", "vm_infra", "vm_cloud", "vm"
          when "miq_template"

(get_class_from_controller_param)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use /${ManageIQ.controller}/ownership_form_fields if it helps.

.then(data => this.setState({ initialValues: data }))


handleSubmit = (values, objectIds, url) => miqAjaxButton(url, {
objectIds,
...values,
})

render() {
const { groupOptions, ownerOptions, ownershipIds } = this.props;
const { initialValues } = this.state;
const cancelUrl = '/service/ownership_update/?button=cancel';
const submitUrl = '/service/ownership_update/?button=save';

return (
<Grid fluid id="set-ownership-form">
<MiqFormRenderer
initialValues={initialValues}
schema={createSchema(ownerOptions, groupOptions)}
onSubmit={values => this.handleSubmit(values, ownershipIds, submitUrl)}
onReset={() => add_flash(__('All changes have been reset'), 'warn')}
onCancel={() => miqAjaxButton(cancelUrl)}
canReset
/>
</Grid>
);
}
}

SetServiceOwnershipForm.propTypes = {
ownershipIds: PropTypes.arrayOf(PropTypes.string).isRequired,
groupOptions: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)).isRequired,
ownerOptions: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)).isRequired,
};

export default SetServiceOwnershipForm;
25 changes: 25 additions & 0 deletions app/javascript/components/set-service-ownership-form/schema.js
@@ -0,0 +1,25 @@
import { componentTypes } from '@data-driven-forms/react-form-renderer';

const createSchema = (ownerOptions, groupOptions) => ({
fields: [{
component: componentTypes.SELECT_COMPONENT,
name: 'user',
id: 'user_name',
label: __('Select an Owner:'),
options: ownerOptions.map(([label, value]) => ({
label,
value,
})),
}, {
component: componentTypes.SELECT_COMPONENT,
name: 'group',
id: 'group_name',
label: __('Select a Group:'),
options: groupOptions.map(([label, value]) => ({
label,
value,
})),
}],
});

export default createSchema;
7 changes: 7 additions & 0 deletions app/javascript/forms/data-driven-form.jsx
Expand Up @@ -2,6 +2,12 @@ import React from 'react';
import FormRender from '@data-driven-forms/react-form-renderer';
import { formFieldsMapper, layoutMapper } from '@data-driven-forms/pf3-component-mapper';

const buttonLabels = {
submitLabel: __('Save'),
resetLabel: __('Reset'),
cancelLabel: __('Cancel'),
};

const MiqFormRenderer = props => (
<FormRender
formFieldsMapper={formFieldsMapper}
Expand All @@ -10,6 +16,7 @@ const MiqFormRenderer = props => (
'pristine',
'invalid',
]}
{...buttonLabels}
{...props}
/>
);
Expand Down
6 changes: 5 additions & 1 deletion app/javascript/http_api/http.js
Expand Up @@ -16,9 +16,13 @@ function get(url, options = {}) {
});
}

function post(url, data, options = {}) {
function post(url, data, { headers, ...options } = {}) {
return miqFetch({
...options,
headers: {
'Content-Type': 'application/json',
...headers,
},
url,
method: 'POST',
csrf: true,
Expand Down
2 changes: 2 additions & 0 deletions app/javascript/packs/component-definitions-common.js
Expand Up @@ -8,6 +8,7 @@ import FormButtonsRedux from '../forms/form-buttons-redux';
import MiqAboutModal from '../components/miq-about-modal';
import CloudTenantForm from '../components/cloud-tenant-form/cloud-tenant-form';
import ServiceForm from '../components/service-form';
import SetServiceOwnershipForm from '../components/set-service-ownership-form';

/**
* Add component definitions to this file.
Expand All @@ -26,3 +27,4 @@ ManageIQ.component.addReact('FormButtonsRedux', FormButtonsRedux);
ManageIQ.component.addReact('MiqAboutModal', MiqAboutModal);
ManageIQ.component.addReact('CloudTenantForm', CloudTenantForm);
ManageIQ.component.addReact('ServiceForm', ServiceForm);
ManageIQ.component.addReact('SetServiceOwnershipForm', SetServiceOwnershipForm);
@@ -0,0 +1,81 @@
import React from 'react';
import { mount } from 'enzyme';
import FormRenderer from '@data-driven-forms/react-form-renderer';
import SetServiceOwnershipForm from '../../components/set-service-ownership-form';
import createSchema from '../../components/set-service-ownership-form/schema';
import { http } from '../../http_api';

describe('Set service ownership form component', () => {
let initialProps;
const httpSpy = jest.spyOn(http, 'post');
const submitSpy = jest.spyOn(window, 'miqAjaxButton');
const flashSpy = jest.spyOn(window, 'add_flash');

beforeEach(() => {
initialProps = {
ownershipIds: ['123456'],
groupOptions: [['Foo', '1'], ['Bar', '2']],
ownerOptions: [['Baz', '3'], ['Quxx', '4']],
};
});

afterEach(() => {
submitSpy.mockReset();
flashSpy.mockReset();
});

it('should correctly map group and owner options ', () => {
const expectedResult = [
expect.objectContaining({
options: [{
value: '3',
label: 'Baz',
}, {
value: '4',
label: 'Quxx',
}],
}),
expect.objectContaining({
options: [{
value: '1',
label: 'Foo',
}, {
value: '2',
label: 'Bar',
}],
}),
];
const { fields } = createSchema(initialProps.ownerOptions, initialProps.groupOptions);
expect(fields).toEqual(expectedResult);
});

// TO DO replace with actual request mock
it('should request initialForm values after mount', () => {
mount(<SetServiceOwnershipForm {...initialProps} />);
expect(httpSpy).toHaveBeenCalledWith('/service/ownership_form_fields', { object_ids: ['123456'] });
});

it('should send correct data on save', () => {
const wrapper = mount(<SetServiceOwnershipForm {...initialProps} />);
const Form = wrapper.find(FormRenderer).childAt(0);
Form.instance().form.change('user', 'foo');
wrapper.find('button').at(0).simulate('click');
expect(submitSpy).toHaveBeenCalledWith('/service/ownership_update/?button=save', { objectIds: ['123456'], user: 'foo' });
});

it('should send correct data on cancel', () => {
const wrapper = mount(<SetServiceOwnershipForm {...initialProps} />);
wrapper.find('button').last().simulate('click');
expect(submitSpy).toHaveBeenCalledWith('/service/ownership_update/?button=cancel');
});

it('should reset formValues and add flash messages on reset click', () => {
const wrapper = mount(<SetServiceOwnershipForm {...initialProps} />);
const Form = wrapper.find(FormRenderer).childAt(0);
Form.instance().form.change('user', 'foo');
expect(Form.instance().form.getState().values).toEqual({ user: 'foo' });
wrapper.find('button').at(1).simulate('click');
expect(Form.instance().form.getState().values).toEqual({});
expect(flashSpy).toHaveBeenCalledWith(expect.any(String), 'warn');
});
});