Skip to content

Commit

Permalink
Fixes name validation when editing
Browse files Browse the repository at this point in the history
* name async validation checks if the name already exists but it did not check if the name exists on the same catalog -> now it checks id of the catalog with the same name and compares to its id
  • Loading branch information
rvsia committed Apr 9, 2019
1 parent a881678 commit 18cf9a7
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 30 deletions.
4 changes: 2 additions & 2 deletions app/javascript/components/catalog-form/catalog-form.jsx
Expand Up @@ -25,7 +25,7 @@ class CatalogForm extends Component {
const rightValues = service_templates.resources.map(({ href, name }) => ({ key: href, label: name }));
const options = resources.map(({ href, name }) => ({ key: href, label: name })).concat(rightValues);
this.setState(() => ({
schema: createSchema(options),
schema: createSchema(options, catalogId),
initialValues: {
name,
description: description === null ? undefined : description,
Expand Down Expand Up @@ -133,7 +133,7 @@ class CatalogForm extends Component {
}

CatalogForm.propTypes = {
catalogId: PropTypes.number,
catalogId: PropTypes.string,
};

CatalogForm.defaultProps = {
Expand Down
25 changes: 13 additions & 12 deletions app/javascript/components/catalog-form/catalog-form.schema.js
Expand Up @@ -2,28 +2,29 @@ import { componentTypes } from '@data-driven-forms/react-form-renderer';
import debouncePromise from '../../helpers/promise-debounce';
import { API } from '../../http_api';

export const asyncValidator = value => API.get(`/api/service_catalogs?expand=resources&filter[]=name=${value}`)
.then((json) => {
if (json.resources.length > 0) {
return __('Name has already been taken');
}
if (value === '' || value === undefined) {
return __("Name can't be blank");
}
return undefined;
});
export const asyncValidator = (value, catalogId) =>
API.get(`/api/service_catalogs?expand=resources&filter[]=name='${value ? value.replace('%', '%25') : ''}'`)
.then((json) => {
if (json.resources.find(({ id, name }) => name === value && id !== catalogId)) {
return __('Name has already been taken');
}
if (value === '' || value === undefined) {
return __("Name can't be blank");
}
return undefined;
});

const asyncValidatorDebounced = debouncePromise(asyncValidator);

function createSchema(options) {
function createSchema(options, catalogId) {
const fields = [{
component: componentTypes.SUB_FORM,
title: __('Basic Info'),
fields: [{
component: componentTypes.TEXT_FIELD,
name: 'name',
validate: [
asyncValidatorDebounced,
value => asyncValidatorDebounced(value, catalogId),
],
label: __('Name'),
maxLength: 40,
Expand Down
16 changes: 8 additions & 8 deletions app/javascript/spec/catalog-form/catalog-form.spec.js
Expand Up @@ -70,7 +70,7 @@ describe('Catalog form component', () => {
it('should render edit variant form', (done) => {
fetchMock.getOnce(urlFreeTemplates, { resources })
.getOnce(urlTemplates, assignedResources);
const wrapper = shallow(<CatalogForm catalogId={1001} />);
const wrapper = shallow(<CatalogForm catalogId="1001" />);

setImmediate(() => {
wrapper.update();
Expand All @@ -82,7 +82,7 @@ describe('Catalog form component', () => {
it('should call cancel callback ', (done) => {
fetchMock.getOnce(urlFreeTemplates, { resources })
.getOnce(urlTemplates, assignedResources);
const wrapper = mount(<CatalogForm catalogId={1001} />);
const wrapper = mount(<CatalogForm catalogId="1001" />);
const url = '/catalog/st_catalog_edit/1001?button=cancel';

setImmediate(() => {
Expand Down Expand Up @@ -113,7 +113,7 @@ describe('Catalog form component', () => {
fetchMock
.getOnce(urlFreeTemplates, { resources })
.getOnce(urlTemplates, assignedResources);
const wrapper = mount(<CatalogForm catalogId={1001} />);
const wrapper = mount(<CatalogForm catalogId="1001" />);

expect(submitSpyMiqSparkleOn).toHaveBeenCalled();
expect(fetchMock.called(urlFreeTemplates)).toBe(true);
Expand Down Expand Up @@ -209,7 +209,7 @@ describe('Catalog form component', () => {
fetchMock.getOnce('/api/service_catalogs/1001?expand=service_templates', {});
fetchMock.postOnce(apiBase, returnObject);

const wrapper = mount(<CatalogForm catalogId={1001} />);
const wrapper = mount(<CatalogForm catalogId="1001" />);
const spyHandleError = jest.spyOn(wrapper.instance(), 'handleError');

wrapper.instance().setState({ originalRightValues: [] });
Expand All @@ -235,7 +235,7 @@ describe('Catalog form component', () => {
fetchMock.post(`${apiBase}/service_templates`, {});
fetchMock.get(urlTemplates, assignedResources);

const wrapper = mount(<CatalogForm catalogId={1001} />);
const wrapper = mount(<CatalogForm catalogId="1001" />);

const values = {
name: 'Some name',
Expand All @@ -262,7 +262,7 @@ describe('Catalog form component', () => {
fetchMock.post(`${apiBase}/service_templates`, {});
fetchMock.get(urlTemplates, assignedResources);

const wrapper = mount(<CatalogForm catalogId={1001} />);
const wrapper = mount(<CatalogForm catalogId="1001" />);

const values = {
name: 'Some name',
Expand All @@ -285,7 +285,7 @@ describe('Catalog form component', () => {
const error = {
data: { error: { message: 'This is some nice error' } },
};
const wrapper = mount(<CatalogForm catalogId={1001} />);
const wrapper = mount(<CatalogForm catalogId="1001" />);

expect(wrapper.instance().handleError(error)).toEqual(error.data.error.message);
});
Expand All @@ -294,7 +294,7 @@ describe('Catalog form component', () => {
const error = {
data: { error: { message: 'Service catalog: Name has already been taken' } },
};
const wrapper = mount(<CatalogForm catalogId={1001} />);
const wrapper = mount(<CatalogForm catalogId="1001" />);

expect(wrapper.instance().handleError(error)).toEqual(__('Name has already been taken'));
});
Expand Down
24 changes: 17 additions & 7 deletions app/javascript/spec/catalog-form/validator.spec.js
Expand Up @@ -8,28 +8,38 @@ describe('catalog form - promise validator', () => {
});

it('returns error message when name is taken', () => {
fetchMock.getOnce('/api/service_catalogs?expand=resources&filter[]=name=a1', {
fetchMock.getOnce('/api/service_catalogs?expand=resources&filter[]=name=%27a1%27', {
resources: [
{ name: 'a1' },
{ name: 'a1', id: '1' },
],
});

return asyncValidator('a1').then(data => expect(data).toEqual(__('Name has already been taken')));
return asyncValidator('a1', '2').then(data => expect(data).toEqual(__('Name has already been taken')));
});

it('returns nothing when name is taken but by the same catalog', () => {
fetchMock.getOnce('/api/service_catalogs?expand=resources&filter[]=name=%27a1%27', {
resources: [
{ name: 'a1', id: '1'},
],
});

return asyncValidator('a1', '1').then(data => expect(data).toEqual(undefined));
});

it('returns error message when name is undefined', () => {
fetchMock.getOnce('/api/service_catalogs?expand=resources&filter[]=name=undefined', {
fetchMock.getOnce('/api/service_catalogs?expand=resources&filter[]=name=%27%27', {
resources: [],
});

return asyncValidator(undefined).then(data => expect(data).toEqual(__("Name can't be blank")));
return asyncValidator(undefined, '1').then(data => expect(data).toEqual(__("Name can't be blank")));
});

it('returns nothing when passes', () => {
fetchMock.getOnce('/api/service_catalogs?expand=resources&filter[]=name=a1', {
fetchMock.getOnce('/api/service_catalogs?expand=resources&filter[]=name=%27a1%27', {
resources: [],
});

return asyncValidator('a1').then(data => expect(data).toEqual(undefined));
return asyncValidator('a1', '1').then(data => expect(data).toEqual(undefined));
});
});
2 changes: 1 addition & 1 deletion app/views/catalog/_stcat_form.html.haml
@@ -1,3 +1,3 @@
= render :partial => "layouts/flash_msg"
.col-md-12
= react('CatalogForm', { :catalogId => @edit[:rec_id] || nil })
= react('CatalogForm', { :catalogId => @edit[:rec_id].to_s || nil })

0 comments on commit 18cf9a7

Please sign in to comment.