From 052f101a7032cc0aa439d0f3a4492ea001b6b64a Mon Sep 17 00:00:00 2001 From: Alex Corey Date: Fri, 8 Nov 2019 13:14:37 -0500 Subject: [PATCH] Adds AddDropDownButton removes TemplateDropDown Button Both Inventory List and Template List use the same add button that has a drop down. I decided to make a component that both can use. This also addresses a typo in a InventoryList test. --- .../AddDropDownButton/AddDropDownButton.jsx} | 21 ++--- .../AddDropDownButton.test.jsx} | 10 +-- .../src/components/AddDropDownButton/index.js | 4 + .../Inventory/InventoryList/InventoryList.jsx | 83 ++++--------------- .../InventoryList/InventoryList.test.jsx | 2 +- .../Template/TemplateList/TemplateList.jsx | 24 +++++- 6 files changed, 55 insertions(+), 89 deletions(-) rename awx/ui_next/src/{screens/Template/TemplateList/TemplateAddButton.jsx => components/AddDropDownButton/AddDropDownButton.jsx} (68%) rename awx/ui_next/src/{screens/Template/TemplateList/TemplateAddButton.test.jsx => components/AddDropDownButton/AddDropDownButton.test.jsx} (71%) create mode 100644 awx/ui_next/src/components/AddDropDownButton/index.js diff --git a/awx/ui_next/src/screens/Template/TemplateList/TemplateAddButton.jsx b/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.jsx similarity index 68% rename from awx/ui_next/src/screens/Template/TemplateList/TemplateAddButton.jsx rename to awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.jsx index ff96a0b6c0..bd56d3d1a4 100644 --- a/awx/ui_next/src/screens/Template/TemplateList/TemplateAddButton.jsx +++ b/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.jsx @@ -1,11 +1,10 @@ import React, { useState, useRef, useEffect } from 'react'; import { Link, withRouter } from 'react-router-dom'; import { withI18n } from '@lingui/react'; -import { t } from '@lingui/macro'; import { Dropdown, DropdownPosition } from '@patternfly/react-core'; import { ToolbarAddButton } from '@components/PaginatedDataList'; -function TemplateAddButton({ match, i18n }) { +function AddDropDownButton({ topUrl, bottomUrl, topLabel, bottomLabel }) { const [isOpen, setIsOpen] = useState(false); const element = useRef(null); @@ -30,19 +29,15 @@ function TemplateAddButton({ match, i18n }) { position={DropdownPosition.right} toggle={ setIsOpen(!isOpen)} />} dropdownItems={[ - - {i18n._(t`Job Template`)} + + {`${topLabel}`} , - {i18n._(t`Workflow Template`)} + {`${bottomLabel}`} , ]} /> @@ -50,5 +45,5 @@ function TemplateAddButton({ match, i18n }) { ); } -export { TemplateAddButton as _TemplateAddButton }; -export default withI18n()(withRouter(TemplateAddButton)); +export { AddDropDownButton as _AddDropDownButton }; +export default withI18n()(withRouter(AddDropDownButton)); diff --git a/awx/ui_next/src/screens/Template/TemplateList/TemplateAddButton.test.jsx b/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.test.jsx similarity index 71% rename from awx/ui_next/src/screens/Template/TemplateList/TemplateAddButton.test.jsx rename to awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.test.jsx index 1a0e75e29e..a6e4c1b1a3 100644 --- a/awx/ui_next/src/screens/Template/TemplateList/TemplateAddButton.test.jsx +++ b/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.test.jsx @@ -1,22 +1,22 @@ import React from 'react'; import { mountWithContexts } from '@testUtils/enzymeHelpers'; -import TemplateAddButton from './TemplateAddButton'; +import AddDropDownButton from './AddDropDownButton'; -describe('', () => { +describe('', () => { test('should be closed initially', () => { - const wrapper = mountWithContexts(); + const wrapper = mountWithContexts(); expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(false); }); test('should render two links', () => { - const wrapper = mountWithContexts(); + const wrapper = mountWithContexts(); wrapper.find('button').simulate('click'); expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(true); expect(wrapper.find('Link')).toHaveLength(2); }); test('should close when button re-clicked', () => { - const wrapper = mountWithContexts(); + const wrapper = mountWithContexts(); wrapper.find('button').simulate('click'); expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(true); wrapper.find('button').simulate('click'); diff --git a/awx/ui_next/src/components/AddDropDownButton/index.js b/awx/ui_next/src/components/AddDropDownButton/index.js new file mode 100644 index 0000000000..1ba2828957 --- /dev/null +++ b/awx/ui_next/src/components/AddDropDownButton/index.js @@ -0,0 +1,4 @@ +export { + default +} +from './AddDropDownButton' diff --git a/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx b/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx index c949b39656..fa8ac6e584 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx +++ b/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx @@ -1,15 +1,9 @@ import React, { Component } from 'react'; -import { withRouter, Link } from 'react-router-dom'; +import { withRouter } from 'react-router-dom'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; -import { - Card, - PageSection, - Dropdown, - DropdownItem, - DropdownPosition, -} from '@patternfly/react-core'; +import { Card, PageSection } from '@patternfly/react-core'; import { InventoriesAPI } from '@api'; import AlertModal from '@components/AlertModal'; @@ -17,10 +11,10 @@ import DatalistToolbar from '@components/DataListToolbar'; import ErrorDetail from '@components/ErrorDetail'; import PaginatedDataList, { ToolbarDeleteButton, - ToolbarAddButton, } from '@components/PaginatedDataList'; -import { getQSConfig, parseQueryString } from '@util/qs'; +import { getQSConfig, parseQueryString } from '@util/qs'; +import AddDropDownButton from '@components/AddDropDownButton'; import InventoryListItem from './InventoryListItem'; // The type value in const QS_CONFIG below does not have a space between job_inventory and @@ -65,10 +59,6 @@ class InventoriesList extends Component { } } - componentWillUnmount() { - document.removeEventListener('click', this.handleAddToggle, false); - } - handleDeleteErrorClose() { this.setState({ deletionError: null }); } @@ -90,16 +80,13 @@ class InventoriesList extends Component { handleAddToggle(e) { const { isAddOpen } = this.state; - document.addEventListener('click', this.handleAddToggle, false); if (this.node && this.node.contains(e.target) && isAddOpen) { - document.removeEventListener('click', this.handleAddToggle, false); this.setState({ isAddOpen: false }); } else if (this.node && this.node.contains(e.target) && !isAddOpen) { this.setState({ isAddOpen: true }); } else { this.setState({ isAddOpen: false }); - document.removeEventListener('click', this.handleAddToggle, false); } } @@ -222,33 +209,13 @@ class InventoriesList extends Component { pluralizedItemName="Inventories" />, canAdd && ( -
{ - this.node = node; - }} + - - } - dropdownItems={[ - - - {i18n._(t`Inventory`)} - - , - - - {i18n._(t`Smart Inventory`)} - - , - ]} - /> -
+ topUrl={`${match.url}/inventory/add/`} + bottomdUrl={`${match.url}/smart_inventory/add/`} + topLabel={i18n._(t`Inventory`)} + bottomLabel={i18n._(t`Smart Inventory`)} + /> ), ]} /> @@ -269,31 +236,13 @@ class InventoriesList extends Component { )} emptyStateControls={ canAdd && ( -
{ - this.node = node; - }} + - } - dropdownItems={[ - - - {i18n._(t`Inventory`)} - - , - - - {i18n._(t`Smart Inventory`)} - - , - ]} - /> -
+ topUrl={`${match.url}/inventory/add/`} + bottomUrl={`${match.url}/smart_inventory/add/`} + topLabel={i18n._(t`Inventory`)} + bottomLabel={i18n._(t`Smart Inventory`)} + /> ) } /> diff --git a/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.test.jsx b/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.test.jsx index c312f92b7f..796ae9eff1 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.test.jsx +++ b/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.test.jsx @@ -284,7 +284,7 @@ describe('', () => { done(); }); - test('Add button shown for users without ability to POST', async done => { + test('Add button shown for users with ability to POST', async done => { const wrapper = mountWithContexts(); await waitForElement( wrapper, diff --git a/awx/ui_next/src/screens/Template/TemplateList/TemplateList.jsx b/awx/ui_next/src/screens/Template/TemplateList/TemplateList.jsx index 68e2bb7400..d687cf5de9 100644 --- a/awx/ui_next/src/screens/Template/TemplateList/TemplateList.jsx +++ b/awx/ui_next/src/screens/Template/TemplateList/TemplateList.jsx @@ -13,8 +13,8 @@ import PaginatedDataList, { } from '@components/PaginatedDataList'; import { getQSConfig, parseQueryString } from '@util/qs'; +import AddDropDownButton from '@components/AddDropDownButton'; import TemplateListItem from './TemplateListItem'; -import TemplateAddButton from './TemplateAddButton'; // The type value in const QS_CONFIG below does not have a space between job_template and // workflow_job_template so the params sent to the API match what the api expects. @@ -206,7 +206,15 @@ class TemplatesList extends Component { itemsToDelete={selected} pluralizedItemName="Templates" />, - canAdd && , + canAdd && ( + + ), ]} /> )} @@ -220,7 +228,17 @@ class TemplatesList extends Component { isSelected={selected.some(row => row.id === template.id)} /> )} - emptyStateControls={canAdd && } + emptyStateControls={ + canAdd && ( + + ) + } />