Skip to content

Commit dd9c62a

Browse files
committed
Converts Catalogs > Catalog > Add/Edit to react forms
1 parent 727b91b commit dd9c62a

File tree

8 files changed

+663
-152
lines changed

8 files changed

+663
-152
lines changed

app/controllers/catalog_controller.rb

Lines changed: 8 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -578,54 +578,19 @@ def st_catalog_edit
578578
@in_a_form = false
579579
replace_right_cell
580580
when "save", "add"
581-
assert_privileges("st_catalog_#{params[:id] ? "edit" : "new"}")
582-
return unless load_edit("st_catalog_edit__#{params[:id] || "new"}", "replace_cell__explorer")
583-
584-
@stc = @edit[:rec_id] ? ServiceTemplateCatalog.find(@edit[:rec_id]) : ServiceTemplateCatalog.new
585-
st_catalog_set_record_vars(@stc)
586-
begin
587-
@stc.save
588-
rescue => bang
589-
add_flash(_("Error during 'Catalog Edit': %{error_message}") % {:error_message => bang.message}, :error)
590-
else
591-
if @stc.errors.empty?
592-
add_flash(_("Catalog \"%{name}\" was saved") % {:name => @edit[:new][:name]})
593-
else
594-
@stc.errors.each do |field, msg|
595-
add_flash("#{field.to_s.capitalize} #{msg}", :error)
596-
end
597-
javascript_flash
598-
return
599-
end
600-
end
581+
add_flash(_("Catalog was saved"))
601582
@changed = session[:changed] = false
602583
@in_a_form = false
603584
@edit = session[:edit] = nil
604585
replace_right_cell(:replace_trees => trees_to_replace(%i(sandt svccat stcat)))
605-
when "reset", nil # Reset or first time in
586+
when nil # First time in
606587
st_catalog_set_form_vars
607-
if params[:button] == "reset"
608-
add_flash(_("All changes have been reset"), :warning)
609-
end
610588
@changed = session[:changed] = false
611589
replace_right_cell(:action => "st_catalog_edit")
612590
return
613591
end
614592
end
615593

616-
def st_catalog_form_field_changed
617-
id = session[:edit][:rec_id] || "new"
618-
return unless load_edit("st_catalog_edit__#{id}", "replace_cell__explorer")
619-
st_catalog_get_form_vars
620-
changed = (@edit[:new] != @edit[:current])
621-
render :update do |page|
622-
page << javascript_prologue
623-
page.replace(@refresh_div, :partial => @refresh_partial) if @refresh_div
624-
page << javascript_for_miq_button_visibility(changed)
625-
page << "miqSparkle(false);"
626-
end
627-
end
628-
629594
def process_sts(sts, task, _display_name = nil)
630595
ServiceTemplate.where(:id => sts).order("lower(name)").each do |st|
631596
id = st.id
@@ -1201,14 +1166,6 @@ def service_dialog_from_ot_submit_save
12011166
end
12021167
end
12031168

1204-
def st_catalog_get_form_vars
1205-
case params[:button]
1206-
when 'right' then move_cols_left_right('right')
1207-
when 'left' then move_cols_left_right('left')
1208-
else copy_params_if_set(@edit[:new], params, %i(name description))
1209-
end
1210-
end
1211-
12121169
def st_catalog_set_form_vars
12131170
checked = find_checked_items
12141171
checked[0] = params[:id] if checked.blank? && params[:id]
@@ -1220,28 +1177,13 @@ def st_catalog_set_form_vars
12201177
_("Adding a new Catalog")
12211178
end
12221179
@edit = {}
1223-
@edit[:key] = "st_catalog_edit__#{@record.id || "new"}"
12241180
@edit[:new] = {}
1225-
@edit[:current] = {}
12261181
@edit[:rec_id] = @record.id
12271182
@edit[:new][:name] = @record.name
1228-
@edit[:new][:description] = @record.description
1229-
@edit[:new][:fields] = @record.service_templates.collect { |st| [st.name, st.id] }.sort
1230-
1231-
@edit[:new][:available_fields] = Rbac.filtered(ServiceTemplate, :named_scope => %i(displayed public_service_templates without_service_template_catalog_id))
1232-
.collect { |st| [st.name, st.id] }
1233-
.sort
1234-
1235-
@edit[:current] = copy_hash(@edit[:new])
1183+
@edit[:current] = {} # because of locking tree in replace_right_cell method
12361184
@in_a_form = true
12371185
end
12381186

1239-
def st_catalog_set_record_vars(stc)
1240-
stc.name = @edit[:new][:name]
1241-
stc.description = @edit[:new][:description]
1242-
stc.service_templates = @edit[:new][:fields].collect { |sf| ServiceTemplate.find(sf[1]) }
1243-
end
1244-
12451187
def st_catalog_delete
12461188
assert_privileges("st_catalog_delete")
12471189
elements = []
@@ -2099,7 +2041,11 @@ def replace_right_cell(options = {})
20992041
presenter.hide(:toolbar).show(:paging_div)
21002042
# incase it was hidden for summary screen, and incase there were no records on show_list
21012043
presenter.remove_paging
2102-
action == 'at_st_new' && ansible_playbook? ? presenter.hide(:form_buttons_div) : presenter.show(:form_buttons_div)
2044+
if (action == 'at_st_new' && ansible_playbook?) || (action == 'st_catalog_new' || action == 'st_catalog_edit')
2045+
presenter.hide(:form_buttons_div)
2046+
else
2047+
presenter.show(:form_buttons_div)
2048+
end
21032049
locals = {:record_id => @edit[:rec_id]}
21042050
case action
21052051
when 'group_edit'
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import React, { Component } from 'react';
2+
import PropTypes from 'prop-types';
3+
import { Grid } from 'patternfly-react';
4+
import MiqFormRenderer from '../../forms/data-driven-form';
5+
import createSchema from './catalog-form.schema';
6+
import { filterOptions, filterValues } from '../dual-list-select/helpers';
7+
import { API } from '../../http_api';
8+
import { cleanVirtualDom } from '../../miq-component/helpers';
9+
10+
class CatalogForm extends Component {
11+
constructor(props) {
12+
super(props);
13+
this.state = {
14+
isLoaded: false,
15+
};
16+
cleanVirtualDom();
17+
}
18+
19+
componentDidMount() {
20+
miqSparkleOn();
21+
const { catalogId } = this.props;
22+
if (catalogId) {
23+
Promise.all([
24+
API.get('/api/service_templates?expand=resources&filter[]=service_template_catalog_id=null'),
25+
API.get(`/api/service_catalogs/${catalogId}?expand=service_templates`)])
26+
.then(([{ resources }, { name, description, service_templates }]) => {
27+
const rightValues = service_templates.resources.map(({ href, name }) => ({ key: href, label: name }));
28+
const options = resources.map(({ href, name }) => ({ key: href, label: name })).concat(rightValues);
29+
this.setState(() => ({
30+
schema: createSchema(options),
31+
initialValues: {
32+
name,
33+
description: description === null ? undefined : description,
34+
service_templates: rightValues.map(({ key }) => key),
35+
},
36+
originalRightValues: rightValues,
37+
isLoaded: true,
38+
}), miqSparkleOff);
39+
});
40+
} else {
41+
API.get('/api/service_templates?expand=resources&filter[]=service_template_catalog_id=null').then(
42+
({ resources }) => this.setState({
43+
schema: createSchema(resources.map(({ href, name }) => ({ key: href, label: name }))),
44+
isLoaded: true,
45+
}, miqSparkleOff),
46+
);
47+
}
48+
}
49+
50+
handleError = (error) => {
51+
const { data: { error: { message } } } = error;
52+
return message.includes('Name has already been taken') ? __('Name has already been taken') : message;
53+
}
54+
55+
submitValues = (values) => {
56+
const { catalogId } = this.props;
57+
const { originalRightValues } = this.state;
58+
const { service_templates = [] } = values;
59+
const apiBase = `/api/service_catalogs${catalogId ? `/${catalogId}` : ''}`;
60+
61+
if (!catalogId) {
62+
return API.post(apiBase, {
63+
action: 'create',
64+
resource: {
65+
...values,
66+
service_templates: service_templates.map(key => ({ href: `${key}` })),
67+
},
68+
})
69+
.then(() => miqAjaxButton('/catalog/st_catalog_edit?button=add'));
70+
}
71+
72+
const unassignedRightValues = filterValues(values.service_templates, originalRightValues.map(({ key }) => key));
73+
const unassignedLeftValues = filterOptions(originalRightValues, values.service_templates);
74+
const promises = [
75+
API.post(apiBase, {
76+
action: 'edit',
77+
resource: {
78+
name: values.name,
79+
description: values.description,
80+
},
81+
}, {
82+
skipErrors: [500],
83+
}),
84+
];
85+
86+
if (unassignedRightValues.length > 0) {
87+
promises.push(
88+
API.post(`${apiBase}/service_templates`, {
89+
action: 'assign',
90+
resources: unassignedRightValues.map(key => ({ href: key })),
91+
}, {
92+
skipErrors: [500],
93+
}),
94+
);
95+
}
96+
if (unassignedLeftValues.length > 0) {
97+
promises.push(
98+
API.post(`${apiBase}/service_templates`, {
99+
action: 'unassign',
100+
resources: unassignedLeftValues.map(({ key }) => ({ href: key })),
101+
}, {
102+
skipErrors: [500],
103+
}),
104+
);
105+
}
106+
107+
return Promise.all(promises)
108+
.then(([{ id }]) => miqAjaxButton(`/catalog/st_catalog_edit/${id}?button=save`))
109+
.catch(error => add_flash(this.handleError(error), 'error'));
110+
};
111+
112+
render() {
113+
const { catalogId } = this.props;
114+
const { isLoaded, initialValues, schema } = this.state;
115+
const cancelUrl = `/catalog/st_catalog_edit/${catalogId}?button=cancel`;
116+
if (!isLoaded) return null;
117+
118+
return (
119+
<Grid fluid>
120+
<MiqFormRenderer
121+
initialValues={initialValues}
122+
schema={schema}
123+
onSubmit={this.submitValues}
124+
onCancel={() => miqAjaxButton(cancelUrl)}
125+
onReset={() => add_flash(__('All changes have been reset'), 'warn')}
126+
canReset={!!catalogId}
127+
buttonsLabels={{
128+
submitLabel: catalogId ? __('Save') : __('Add'),
129+
}}
130+
/>
131+
</Grid>
132+
);
133+
}
134+
}
135+
136+
CatalogForm.propTypes = {
137+
catalogId: PropTypes.number,
138+
};
139+
140+
CatalogForm.defaultProps = {
141+
catalogId: undefined,
142+
};
143+
144+
export default CatalogForm;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { componentTypes, validatorTypes } from '@data-driven-forms/react-form-renderer';
2+
3+
function createSchema(options) {
4+
const fields = [{
5+
component: componentTypes.SUB_FORM,
6+
title: __('Basic Info'),
7+
fields: [{
8+
component: componentTypes.TEXT_FIELD,
9+
name: 'name',
10+
validate: [{
11+
type: validatorTypes.REQUIRED,
12+
message: __("Name can't be blank"),
13+
}],
14+
label: __('Name'),
15+
maxLength: 40,
16+
autoFocus: true,
17+
validateOnMount: true,
18+
}, {
19+
component: componentTypes.TEXT_FIELD,
20+
name: 'description',
21+
label: __('Description'),
22+
maxLength: 60,
23+
}],
24+
}, {
25+
component: 'hr',
26+
name: 'hr',
27+
}, {
28+
component: componentTypes.SUB_FORM,
29+
title: __('Assign Catalog Items'),
30+
fields: [
31+
{
32+
component: 'dual-list-select',
33+
leftTitle: __('Unassigned:'),
34+
rightTitle: __('Selected:'),
35+
leftId: 'available_fields',
36+
rightId: 'selected_fields',
37+
allToRight: false,
38+
moveLeftTitle: __('Move Selected buttons left'),
39+
moveRightTitle: __('Move Selected buttons right'),
40+
size: 8,
41+
assignFieldProvider: true,
42+
options,
43+
name: 'service_templates',
44+
},
45+
],
46+
}];
47+
return { fields };
48+
}
49+
50+
export default createSchema;

app/javascript/packs/component-definitions-common.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import SetServiceOwnershipForm from '../components/set-service-ownership-form';
1212
import FlavorForm from '../components/flavor-form/flavor-form';
1313
import ImportDatastoreViaGit from '../components/automate-import-export-form/import-datastore-via-git';
1414
import VmServerRelationshipForm from '../components/vm-server-relationship-form';
15+
import CatalogForm from '../components/catalog-form/catalog-form';
1516

1617
/**
1718
* Add component definitions to this file.
@@ -34,3 +35,4 @@ ManageIQ.component.addReact('SetServiceOwnershipForm', SetServiceOwnershipForm);
3435
ManageIQ.component.addReact('FlavorForm', FlavorForm);
3536
ManageIQ.component.addReact('ImportDatastoreViaGit', ImportDatastoreViaGit);
3637
ManageIQ.component.addReact('VmServerRelationshipForm', VmServerRelationshipForm);
38+
ManageIQ.component.addReact('CatalogForm', CatalogForm);

0 commit comments

Comments
 (0)