diff --git a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.jsx b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.jsx index b3b4d12f92..c8f1a6894d 100644 --- a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.jsx +++ b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.jsx @@ -17,23 +17,30 @@ function JobTemplateAdd({ history, i18n }) { const [formSubmitError, setFormSubmitError] = useState(null); async function handleSubmit(values) { - const { newLabels, removedLabels } = values; - delete values.newLabels; - delete values.removedLabels; + const { + newLabels, + removedLabels, + addedInstanceGroups, + removedInstanceGroups, + ...remainingValues + } = values; setFormSubmitError(null); try { const { data: { id, type }, - } = await JobTemplatesAPI.create(values); - await Promise.all([submitLabels(id, newLabels, removedLabels)]); + } = await JobTemplatesAPI.create(remainingValues); + await Promise.all([ + submitLabels(id, newLabels, removedLabels), + submitInstanceGroups(id, addedInstanceGroups, removedInstanceGroups), + ]); history.push(`/templates/${type}/${id}/details`); } catch (error) { setFormSubmitError(error); } } - async function submitLabels(id, newLabels = [], removedLabels = []) { + function submitLabels(id, newLabels = [], removedLabels = []) { const disassociationPromises = removedLabels.map(label => JobTemplatesAPI.disassociateLabel(id, label) ); @@ -44,12 +51,18 @@ function JobTemplateAdd({ history, i18n }) { .filter(label => label.organization) .map(label => JobTemplatesAPI.generateLabel(id, label)); - const results = await Promise.all([ + return Promise.all([ ...disassociationPromises, ...associationPromises, ...creationPromises, ]); - return results; + } + + function submitInstanceGroups(templateId, addedGroups) { + const associatePromises = addedGroups.map(group => + JobTemplatesAPI.associateInstanceGroup(templateId, group.id) + ); + return Promise.all(associatePromises); } function handleCancel() { diff --git a/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.jsx b/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.jsx index 51e5a3ff65..8771b7c3bf 100644 --- a/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.jsx +++ b/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.jsx @@ -102,18 +102,22 @@ class JobTemplateEdit extends Component { } async handleSubmit(values) { + const { template, history } = this.props; const { - template: { id }, - history, - } = this.props; - const { newLabels, removedLabels } = values; - delete values.newLabels; - delete values.removedLabels; + newLabels, + removedLabels, + addedInstanceGroups, + removedInstanceGroups, + ...remainingValues + } = values; this.setState({ formSubmitError: null }); try { - await JobTemplatesAPI.update(id, values); - await Promise.all([this.submitLabels(newLabels, removedLabels)]); + await JobTemplatesAPI.update(template.id, remainingValues); + await Promise.all([ + this.submitLabels(newLabels, removedLabels), + this.submitInstanceGroups(addedInstanceGroups, removedInstanceGroups), + ]); history.push(this.detailsUrl); } catch (formSubmitError) { this.setState({ formSubmitError }); @@ -121,18 +125,16 @@ class JobTemplateEdit extends Component { } async submitLabels(newLabels = [], removedLabels = []) { - const { - template: { id }, - } = this.props; + const { template } = this.props; const disassociationPromises = removedLabels.map(label => - JobTemplatesAPI.disassociateLabel(id, label) + JobTemplatesAPI.disassociateLabel(template.id, label) ); const associationPromises = newLabels .filter(label => !label.organization) - .map(label => JobTemplatesAPI.associateLabel(id, label)); + .map(label => JobTemplatesAPI.associateLabel(template.id, label)); const creationPromises = newLabels .filter(label => label.organization) - .map(label => JobTemplatesAPI.generateLabel(id, label)); + .map(label => JobTemplatesAPI.generateLabel(template.id, label)); const results = await Promise.all([ ...disassociationPromises, @@ -142,6 +144,17 @@ class JobTemplateEdit extends Component { return results; } + async submitInstanceGroups(addedGroups, removedGroups) { + const { template } = this.props; + const associatePromises = addedGroups.map(group => + JobTemplatesAPI.associateInstanceGroup(template.id, group.id) + ); + const disassociatePromises = removedGroups.map(group => + JobTemplatesAPI.disassociateInstanceGroup(template.id, group.id) + ); + return Promise.all([...associatePromises, ...disassociatePromises]); + } + handleCancel() { const { history } = this.props; history.push(this.detailsUrl); diff --git a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx index 10c6d83257..ff377380a2 100644 --- a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx +++ b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx @@ -142,7 +142,8 @@ class JobTemplateForm extends Component { try { const { data } = await JobTemplatesAPI.readInstanceGroups(template.id); this.setState({ - relatedInstanceGroups: data.results, + initialInstanceGroups: data.results, + relatedInstanceGroups: [...data.results], }); } catch (err) { this.setState({ contentError: err }); @@ -232,6 +233,26 @@ class JobTemplateForm extends Component { } handleInstanceGroupsChange(relatedInstanceGroups) { + const { setFieldValue } = this.props; + const { initialInstanceGroups } = this.state; + let added = []; + const removed = []; + if (initialInstanceGroups) { + initialInstanceGroups.forEach(group => { + if (!relatedInstanceGroups.find(g => g.id === group.id)) { + removed.push(group); + } + }); + relatedInstanceGroups.forEach(group => { + if (!initialInstanceGroups.find(g => g.id === group.id)) { + added.push(group); + } + }); + } else { + added = relatedInstanceGroups; + } + setFieldValue('addedInstanceGroups', added); + setFieldValue('removedInstanceGroups', removed); this.setState({ relatedInstanceGroups }); }