From 2579e30ca183ad48982b49c2db9ab0c77e0e5a84 Mon Sep 17 00:00:00 2001 From: mabashian Date: Tue, 29 Jan 2019 13:23:52 -0500 Subject: [PATCH] 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 (