From 2579e30ca183ad48982b49c2db9ab0c77e0e5a84 Mon Sep 17 00:00:00 2001 From: mabashian Date: Tue, 29 Jan 2019 13:23:52 -0500 Subject: [PATCH 1/4] Pulls in latest pf-react. Adds selected list component to org instance groups lookup --- __tests__/components/Lookup.test.jsx | 5 + __tests__/components/SelectedList.test.jsx | 123 ++++++++++++++++++ .../screens/OrganizationAdd.test.jsx | 81 ++++++++++++ package-lock.json | 33 +++-- package.json | 2 +- src/components/Lookup/Lookup.jsx | 24 +++- src/components/SelectedList/SelectedList.jsx | 61 +++++++++ src/components/SelectedList/index.js | 3 + src/components/SelectedList/styles.scss | 34 +++++ src/index.jsx | 1 + .../Organizations/screens/OrganizationAdd.jsx | 61 ++++++--- 11 files changed, 393 insertions(+), 35 deletions(-) create mode 100644 __tests__/components/SelectedList.test.jsx create mode 100644 src/components/SelectedList/SelectedList.jsx create mode 100644 src/components/SelectedList/index.js create mode 100644 src/components/SelectedList/styles.scss diff --git a/__tests__/components/Lookup.test.jsx b/__tests__/components/Lookup.test.jsx index 9081fd0dfd..c7d08242f5 100644 --- a/__tests__/components/Lookup.test.jsx +++ b/__tests__/components/Lookup.test.jsx @@ -11,6 +11,7 @@ describe('', () => { lookup_header="Foo Bar" lookupChange={() => { }} data={mockData} + selected={[]} /> ); }); @@ -22,6 +23,7 @@ describe('', () => { lookup_header="Foo Bar" lookupChange={() => { }} data={mockData} + selected={[]} /> ); @@ -38,6 +40,7 @@ describe('', () => { lookup_header="Foo Bar" lookupChange={() => { }} data={mockData} + selected={[]} /> ); @@ -55,6 +58,7 @@ describe('', () => { lookup_header="Foo Bar" lookupChange={() => { }} data={mockData} + selected={[]} /> ); @@ -71,6 +75,7 @@ describe('', () => { lookup_header="Foo Bar" lookupChange={() => { }} data={mockData} + selected={[]} /> ); diff --git a/__tests__/components/SelectedList.test.jsx b/__tests__/components/SelectedList.test.jsx new file mode 100644 index 0000000000..4eaa52bf61 --- /dev/null +++ b/__tests__/components/SelectedList.test.jsx @@ -0,0 +1,123 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import SelectedList from '../../src/components/SelectedList'; + +describe('', () => { + test('initially renders succesfully', () => { + const mockSelected = [ + { + id: 1, + name: 'foo' + }, { + id: 2, + name: 'bar' + } + ]; + mount( + {}} + /> + ); + }); + test('showOverflow should set showOverflow state to true', () => { + const wrapper = mount( + {}} + /> + ); + expect(wrapper.state('showOverflow')).toBe(false); + wrapper.instance().showOverflow(); + expect(wrapper.state('showOverflow')).toBe(true); + }); + test('Overflow chip should be shown when more selected.length exceeds showOverflowAfter', () => { + const mockSelected = [ + { + id: 1, + name: 'foo' + }, { + id: 2, + name: 'bar' + }, { + id: 3, + name: 'foobar' + }, { + id: 4, + name: 'baz' + }, { + id: 5, + name: 'foobaz' + } + ]; + const wrapper = mount( + {}} + /> + ); + expect(wrapper.find('Chip').length).toBe(4); + expect(wrapper.find('[isOverflowChip=true]').length).toBe(1); + }); + test('Clicking overflow chip should show all chips', () => { + const mockSelected = [ + { + id: 1, + name: 'foo' + }, { + id: 2, + name: 'bar' + }, { + id: 3, + name: 'foobar' + }, { + id: 4, + name: 'baz' + }, { + id: 5, + name: 'foobaz' + } + ]; + const wrapper = mount( + {}} + /> + ); + expect(wrapper.find('Chip').length).toBe(4); + expect(wrapper.find('[isOverflowChip=true]').length).toBe(1); + wrapper.find('[isOverflowChip=true] button').simulate('click'); + expect(wrapper.find('Chip').length).toBe(5); + expect(wrapper.find('[isOverflowChip=true]').length).toBe(0); + }); + test('Clicking remove on chip calls onRemove callback prop with correct params', () => { + const onRemove = jest.fn(); + const mockSelected = [ + { + id: 1, + name: 'foo' + } + ]; + const wrapper = mount( + + ); + wrapper.find('.pf-c-chip button').first().simulate('click'); + expect(onRemove).toBeCalledWith({ + id: 1, + name: 'foo' + }); + }); +}); diff --git a/__tests__/pages/Organizations/screens/OrganizationAdd.test.jsx b/__tests__/pages/Organizations/screens/OrganizationAdd.test.jsx index ad0ef6fc8f..b035c21a60 100644 --- a/__tests__/pages/Organizations/screens/OrganizationAdd.test.jsx +++ b/__tests__/pages/Organizations/screens/OrganizationAdd.test.jsx @@ -92,4 +92,85 @@ describe('', () => { done(); }); }); + + test('onSelectChange successfully sets custom_virtualenv state', () => { + const wrapper = mount( + + + + ).find('OrganizationAdd'); + wrapper.instance().onSelectChange('foobar'); + expect(wrapper.state('custom_virtualenv')).toBe('foobar'); + }); + + test('onLookupChange successfully adds/removes row from selectedInstanceGroups state', () => { + const wrapper = mount( + + + + ).find('OrganizationAdd'); + wrapper.setState({ results: [{ + id: 1, + name: 'foo' + }] }); + wrapper.instance().onLookupChange({ + id: 1, + name: 'foo' + }); + expect(wrapper.state('results')).toEqual([{ + id: 1, + name: 'foo', + isChecked: true + }]); + expect(wrapper.state('selectedInstanceGroups')).toEqual([{ + id: 1, + name: 'foo' + }]); + wrapper.instance().onLookupChange({ + id: 1, + name: 'foo' + }); + expect(wrapper.state('results')).toEqual([{ + id: 1, + name: 'foo', + isChecked: false + }]); + expect(wrapper.state('selectedInstanceGroups')).toEqual([]); + }); + + test('onSubmit posts instance groups from selectedInstanceGroups', async () => { + const createOrganizationFn = jest.fn().mockResolvedValue({ + data: { + id: 1, + name: 'mock org', + related: { + instance_groups: '/api/v2/organizations/1/instance_groups' + } + } + }); + const createInstanceGroupsFn = jest.fn().mockResolvedValue('done'); + const api = { + createOrganization: createOrganizationFn, + createInstanceGroups: createInstanceGroupsFn + }; + const wrapper = mount( + + + + ).find('OrganizationAdd'); + wrapper.setState({ + name: 'mock org', + selectedInstanceGroups: [{ + id: 1, + name: 'foo' + }] + }); + await wrapper.instance().onSubmit(); + expect(createOrganizationFn).toHaveBeenCalledWith({ + custom_virtualenv: '', + description: '', + name: 'mock org' + }); + expect(createInstanceGroupsFn).toHaveBeenCalledWith('/api/v2/organizations/1/instance_groups', 1); + }); }); diff --git a/package-lock.json b/package-lock.json index 90242670df..517dacec0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1311,22 +1311,27 @@ "integrity": "sha512-sIRfo/tk4NSnaRwHIHLUf4XoqzNNa4MMa8ZWivzzSfdZ5pCbgvZtyEUqKnQAEH6zuaCM9S8HyhxcNXnm/xaYaQ==" }, "@patternfly/react-core": { - "version": "1.43.5", - "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-1.43.5.tgz", - "integrity": "sha512-xO37/q5BJEdGvAoPllm/gbcwCtW7t0Ae7mKm5UU7d4i5bycEjd0UwJacYxCA6GFTwxN5kzn61XEpAUPY49U3pA==", + "version": "1.49.5", + "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-1.49.5.tgz", + "integrity": "sha512-bb62fkL8nB6F1cUd/szfpLOIAjaa5HBzAoOa4Vc1AjdagwZ6w4MsU7xBPtC0Sp937CpGckRGiVOf0XHWEiSL2g==", "requires": { - "@patternfly/react-icons": "^2.9.5", + "@patternfly/react-icons": "^2.10.1", "@patternfly/react-styles": "^2.3.0", - "@patternfly/react-tokens": "^1.0.0", + "@patternfly/react-tokens": "^1.10.0", "@tippy.js/react": "^1.1.1", "exenv": "^1.2.2", "focus-trap-react": "^4.0.1" }, "dependencies": { "@patternfly/react-icons": { - "version": "2.9.5", - "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-2.9.5.tgz", - "integrity": "sha512-5e/BD2ER5jifUjUgbIilApOfhVldlAjhQdh7EwH/M3M+qzIb+2qKxV/xQ6hWD3AA71lcYIxvPMMHgdWIAl5oPQ==" + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-2.10.1.tgz", + "integrity": "sha512-d3uWfQQeCgCLel2DVlF1SSlyOI0Z12tT1YjSLDE091E2uCB582DUQQ4HfmuV51nH5aTXg+en35QG7JP5jzYlvA==" + }, + "@patternfly/react-tokens": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-1.10.0.tgz", + "integrity": "sha512-jslQPSRgwbSXAGszA22prGSVye6ri3sRFkaF3BUdWBa8fO6Z2MDFB59x4d6BGK9iW7S+3U/Qkden6myP1CgXdA==" } } }, @@ -13808,9 +13813,9 @@ "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=" }, "tabbable": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-3.1.1.tgz", - "integrity": "sha512-583MHIOwictf7+zbxqO/L5fBqMN6Li4SJ1XTKQA9WzHRA7c2BB+D+Ny7Y6kGqU2u+rHK59+oRzrBvMU53aZz+A==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-3.1.2.tgz", + "integrity": "sha512-wjB6puVXTYO0BSFtCmWQubA/KIn7Xvajw0x0l6eJUudMG/EAiJvIUnyNX6xO4NpGrJ16lbD0eUseB9WxW0vlpQ==" }, "table": { "version": "5.1.0", @@ -13927,9 +13932,9 @@ } }, "tippy.js": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-3.3.0.tgz", - "integrity": "sha512-2gIQg57EFSCBqE97NZbakSkGBJF0GzdOhx/lneGQGMzJiJyvbpyKgNy4l4qofq0nEbXACl7C/jW/ErsdQa21aQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-3.4.1.tgz", + "integrity": "sha512-ZiyGP9WZyCCcjxKM4G88cm4U1r1ytjeMDGa5FSKPaPzwc/3yZJVZsb1ffcmqUMCpryRp5LNxRNGKLzbs11sb/Q==", "requires": { "popper.js": "^1.14.6" } diff --git a/package.json b/package.json index 31eb8bd2da..a95bcb1f79 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "dependencies": { "@lingui/react": "^2.7.2", "@patternfly/patternfly-next": "^1.0.84", - "@patternfly/react-core": "^1.43.5", + "@patternfly/react-core": "^1.49.5", "@patternfly/react-icons": "^2.9.1", "@patternfly/react-styles": "^2.3.0", "@patternfly/react-tokens": "^1.9.0", diff --git a/src/components/Lookup/Lookup.jsx b/src/components/Lookup/Lookup.jsx index 691c798350..313f428fee 100644 --- a/src/components/Lookup/Lookup.jsx +++ b/src/components/Lookup/Lookup.jsx @@ -8,9 +8,13 @@ import { Toolbar, ToolbarGroup, } from '@patternfly/react-core'; +import { I18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import CheckboxListItem from '../ListItem'; +import SelectedList from '../SelectedList'; + class Lookup extends React.Component { constructor (props) { super(props); @@ -28,9 +32,9 @@ class Lookup extends React.Component { this.handleModalToggle(); } - onChecked (_, evt) { + onChecked (row) { const { lookupChange } = this.props; - lookupChange(evt.target.value); + lookupChange(row); } onRemove (evt) { @@ -57,7 +61,7 @@ class Lookup extends React.Component { render () { const { isModalOpen } = this.state; - const { data, lookupHeader } = this.props; + const { data, lookupHeader, selected } = this.props; return (
@@ -81,7 +75,7 @@ class Lookup extends React.Component { itemId={i.id} name={i.name} isSelected={i.isChecked} - onSelect={() => this.onChecked(i)} + onSelect={() => this.toggleSelected(i)} /> ))} @@ -92,7 +86,7 @@ class Lookup extends React.Component { label={i18n._(t`Selected`)} selected={selected} showOverflowAfter={5} - onRemove={this.onChecked} + onRemove={this.toggleSelected} /> )} From 0e9e17f957f1b09b56cfbdb283cdf740e336b57b Mon Sep 17 00:00:00 2001 From: mabashian Date: Wed, 30 Jan 2019 15:27:02 -0500 Subject: [PATCH 4/4] Only update selected instance groups if the select button is clicked in the modal --- __tests__/components/Lookup.test.jsx | 85 ++++++++++++++++--- .../screens/OrganizationAdd.test.jsx | 55 +++++------- src/components/Lookup/Lookup.jsx | 59 +++++++++---- .../Organizations/screens/OrganizationAdd.jsx | 32 ++----- 4 files changed, 141 insertions(+), 90 deletions(-) diff --git a/__tests__/components/Lookup.test.jsx b/__tests__/components/Lookup.test.jsx index 03555d868b..d5623aad55 100644 --- a/__tests__/components/Lookup.test.jsx +++ b/__tests__/components/Lookup.test.jsx @@ -3,34 +3,41 @@ import { mount } from 'enzyme'; import { I18nProvider } from '@lingui/react'; import Lookup from '../../src/components/Lookup'; -let mockData = [{ name: 'foo', id: 0, isChecked: false }]; +let mockData = [{ name: 'foo', id: 1, isChecked: false }]; describe('', () => { test('initially renders succesfully', () => { mount( { }} + onLookupSave={() => { }} data={mockData} selected={[]} /> ); }); - test('calls "onLookup" when search icon is clicked', () => { - const spy = jest.spyOn(Lookup.prototype, 'onLookup'); + test('Opens modal when search icon is clicked', () => { + const spy = jest.spyOn(Lookup.prototype, 'handleModalToggle'); + const mockSelected = [{ name: 'foo', id: 1 }]; const wrapper = mount( { }} + onLookupSave={() => { }} data={mockData} - selected={[]} + selected={mockSelected} /> - ); + ).find('Lookup'); expect(spy).not.toHaveBeenCalled(); + expect(wrapper.state('lookupSelectedItems')).toEqual([]); const searchItem = wrapper.find('.pf-c-input-group__text#search'); searchItem.first().simulate('click'); expect(spy).toHaveBeenCalled(); + expect(wrapper.state('lookupSelectedItems')).toEqual([{ + id: 1, + name: 'foo' + }]); + expect(wrapper.state('isModalOpen')).toEqual(true); }); test('calls "toggleSelected" when a user changes a checkbox', () => { const spy = jest.spyOn(Lookup.prototype, 'toggleSelected'); @@ -38,7 +45,7 @@ describe('', () => { { }} + onLookupSave={() => { }} data={mockData} selected={[]} /> @@ -51,14 +58,15 @@ describe('', () => { }); test('calls "toggleSelected" when remove icon is clicked', () => { const spy = jest.spyOn(Lookup.prototype, 'toggleSelected'); - mockData = [{ name: 'foo', id: 0, isChecked: false }, { name: 'bar', id: 1, isChecked: true }]; + mockData = [{ name: 'foo', id: 1, isChecked: false }, { name: 'bar', id: 2, isChecked: true }]; + const mockSelected = [{ name: 'foo', id: 1 }, { name: 'bar', id: 2 }]; const wrapper = mount( { }} + onLookupSave={() => { }} data={mockData} - selected={[]} + selected={mockSelected} /> ); @@ -73,7 +81,7 @@ describe('', () => { { }} + onLookupSave={() => { }} data={mockData} selected={[]} /> @@ -83,4 +91,57 @@ describe('', () => { const pill = wrapper.find('span.awx-c-tag--pill'); expect(pill).toHaveLength(0); }); + test('toggleSelected successfully adds/removes row from lookupSelectedItems state', () => { + mockData = [{ name: 'foo', id: 1 }]; + const wrapper = mount( + + { }} + data={mockData} + selected={[]} + /> + + ).find('Lookup'); + wrapper.instance().toggleSelected({ + id: 1, + name: 'foo' + }); + expect(wrapper.state('lookupSelectedItems')).toEqual([{ + id: 1, + name: 'foo' + }]); + wrapper.instance().toggleSelected({ + id: 1, + name: 'foo' + }); + expect(wrapper.state('lookupSelectedItems')).toEqual([]); + }); + test('saveModal calls callback with selected items', () => { + mockData = [{ name: 'foo', id: 1 }]; + const onLookupSaveFn = jest.fn(); + const wrapper = mount( + + + + ).find('Lookup'); + wrapper.instance().toggleSelected({ + id: 1, + name: 'foo' + }); + expect(wrapper.state('lookupSelectedItems')).toEqual([{ + id: 1, + name: 'foo' + }]); + wrapper.instance().saveModal(); + expect(onLookupSaveFn).toHaveBeenCalledWith([{ + id: 1, + name: 'foo' + }]); + }); }); diff --git a/__tests__/pages/Organizations/screens/OrganizationAdd.test.jsx b/__tests__/pages/Organizations/screens/OrganizationAdd.test.jsx index b035c21a60..27e0b7b07b 100644 --- a/__tests__/pages/Organizations/screens/OrganizationAdd.test.jsx +++ b/__tests__/pages/Organizations/screens/OrganizationAdd.test.jsx @@ -93,6 +93,26 @@ describe('', () => { }); }); + test('updateSelectedInstanceGroups successfully sets selectedInstanceGroups state', () => { + const wrapper = mount( + + + + ).find('OrganizationAdd'); + wrapper.instance().updateSelectedInstanceGroups([ + { + id: 1, + name: 'foo' + } + ]); + expect(wrapper.state('selectedInstanceGroups')).toEqual([ + { + id: 1, + name: 'foo' + } + ]); + }); + test('onSelectChange successfully sets custom_virtualenv state', () => { const wrapper = mount( @@ -103,41 +123,6 @@ describe('', () => { expect(wrapper.state('custom_virtualenv')).toBe('foobar'); }); - test('onLookupChange successfully adds/removes row from selectedInstanceGroups state', () => { - const wrapper = mount( - - - - ).find('OrganizationAdd'); - wrapper.setState({ results: [{ - id: 1, - name: 'foo' - }] }); - wrapper.instance().onLookupChange({ - id: 1, - name: 'foo' - }); - expect(wrapper.state('results')).toEqual([{ - id: 1, - name: 'foo', - isChecked: true - }]); - expect(wrapper.state('selectedInstanceGroups')).toEqual([{ - id: 1, - name: 'foo' - }]); - wrapper.instance().onLookupChange({ - id: 1, - name: 'foo' - }); - expect(wrapper.state('results')).toEqual([{ - id: 1, - name: 'foo', - isChecked: false - }]); - expect(wrapper.state('selectedInstanceGroups')).toEqual([]); - }); - test('onSubmit posts instance groups from selectedInstanceGroups', async () => { const createOrganizationFn = jest.fn().mockResolvedValue({ data: { diff --git a/src/components/Lookup/Lookup.jsx b/src/components/Lookup/Lookup.jsx index e1170702bf..c4ffe97030 100644 --- a/src/components/Lookup/Lookup.jsx +++ b/src/components/Lookup/Lookup.jsx @@ -9,7 +9,7 @@ import { ToolbarGroup, } from '@patternfly/react-core'; import { I18n } from '@lingui/react'; -import { t } from '@lingui/macro'; +import { t, Trans } from '@lingui/macro'; import CheckboxListItem from '../ListItem'; @@ -20,30 +20,51 @@ class Lookup extends React.Component { super(props); this.state = { isModalOpen: false, + lookupSelectedItems: [] }; this.handleModalToggle = this.handleModalToggle.bind(this); - this.onLookup = this.onLookup.bind(this); this.wrapTags = this.wrapTags.bind(this); this.toggleSelected = this.toggleSelected.bind(this); - } - - onLookup () { - this.handleModalToggle(); + this.saveModal = this.saveModal.bind(this); } toggleSelected (row) { - const { lookupChange } = this.props; - lookupChange(row); + const { lookupSelectedItems } = this.state; + const selectedIndex = lookupSelectedItems + .findIndex(selectedRow => selectedRow.id === row.id); + if (selectedIndex > -1) { + lookupSelectedItems.splice(selectedIndex, 1); + this.setState({ lookupSelectedItems }); + } else { + this.setState(prevState => ({ + lookupSelectedItems: [...prevState.lookupSelectedItems, row] + })); + } } handleModalToggle () { + const { isModalOpen } = this.state; + const { selected } = this.props; + // Resets the selected items from parent state whenever modal is opened + // This handles the case where the user closes/cancels the modal and + // opens it again + if (!isModalOpen) { + this.setState({ lookupSelectedItems: [...selected] }); + } this.setState((prevState) => ({ isModalOpen: !prevState.isModalOpen, })); } + saveModal () { + const { onLookupSave } = this.props; + const { lookupSelectedItems } = this.state; + onLookupSave(lookupSelectedItems); + this.handleModalToggle(); + } + wrapTags (tags) { - return tags.filter(tag => tag.isChecked).map((tag) => ( + return tags.map(tag => ( {tag.name} -
{this.wrapTags(data)}
+
{this.wrapTags(selected)}
item.id === i.id)} onSelect={() => this.toggleSelected(i)} /> ))} - {selected.length > 0 && ( + {lookupSelectedItems.length > 0 && ( {({ i18n }) => ( @@ -94,10 +115,14 @@ class Lookup extends React.Component { - + - + diff --git a/src/pages/Organizations/screens/OrganizationAdd.jsx b/src/pages/Organizations/screens/OrganizationAdd.jsx index f6d251373b..cadd5d7c9e 100644 --- a/src/pages/Organizations/screens/OrganizationAdd.jsx +++ b/src/pages/Organizations/screens/OrganizationAdd.jsx @@ -34,11 +34,11 @@ class OrganizationAdd extends React.Component { this.handleChange = this.handleChange.bind(this); this.onSelectChange = this.onSelectChange.bind(this); - this.onLookupChange = this.onLookupChange.bind(this); this.onSubmit = this.onSubmit.bind(this); this.resetForm = this.resetForm.bind(this); this.onSuccess = this.onSuccess.bind(this); this.onCancel = this.onCancel.bind(this); + this.updateSelectedInstanceGroups = this.updateSelectedInstanceGroups.bind(this); } state = { @@ -65,30 +65,6 @@ class OrganizationAdd extends React.Component { this.setState({ custom_virtualenv: value }); } - onLookupChange (row) { - const { results, selectedInstanceGroups } = this.state; - const selectedIndex = selectedInstanceGroups - .findIndex(instanceGroup => instanceGroup.id === row.id); - const resultsIndex = results.findIndex(instanceGroup => instanceGroup.id === row.id); - if (selectedIndex > -1) { - // Remove it from the list of selected instance groups - selectedInstanceGroups.splice(selectedIndex, 1); - if (resultsIndex > -1) { - results[resultsIndex].isChecked = false; - } - this.setState({ selectedInstanceGroups, results }); - } else { - // Add it to the list of selected instance groups - if (resultsIndex > -1) { - results[resultsIndex].isChecked = true; - } - this.setState(prevState => ({ - results, - selectedInstanceGroups: [...prevState.selectedInstanceGroups, row] - })); - } - } - async onSubmit () { const { api } = this.props; const { name, description, custom_virtualenv } = this.state; @@ -128,6 +104,10 @@ class OrganizationAdd extends React.Component { history.push(`/organizations/${id}`); } + updateSelectedInstanceGroups (selectedInstanceGroups) { + this.setState({ selectedInstanceGroups }); + } + handleChange (_, evt) { this.setState({ [evt.target.name]: evt.target.value }); } @@ -184,7 +164,7 @@ class OrganizationAdd extends React.Component {