mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 18:09:57 -03:30
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.
This commit is contained in:
parent
1564dfc80f
commit
052f101a70
@ -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={<ToolbarAddButton onClick={() => setIsOpen(!isOpen)} />}
|
||||
dropdownItems={[
|
||||
<Link
|
||||
key="job"
|
||||
className="pf-c-dropdown__menu-item"
|
||||
to={`${match.url}/job_template/add/`}
|
||||
>
|
||||
{i18n._(t`Job Template`)}
|
||||
<Link key="top" className="pf-c-dropdown__menu-item" to={`${topUrl}`}>
|
||||
{`${topLabel}`}
|
||||
</Link>,
|
||||
<Link
|
||||
key="workflow"
|
||||
key="bottom"
|
||||
className="pf-c-dropdown__menu-item"
|
||||
to={`${match.url}_workflow/add/`}
|
||||
to={`${bottomUrl}`}
|
||||
>
|
||||
{i18n._(t`Workflow Template`)}
|
||||
{`${bottomLabel}`}
|
||||
</Link>,
|
||||
]}
|
||||
/>
|
||||
@ -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));
|
||||
@ -1,22 +1,22 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
||||
import TemplateAddButton from './TemplateAddButton';
|
||||
import AddDropDownButton from './AddDropDownButton';
|
||||
|
||||
describe('<TemplateAddButton />', () => {
|
||||
describe('<AddDropDownButton />', () => {
|
||||
test('should be closed initially', () => {
|
||||
const wrapper = mountWithContexts(<TemplateAddButton />);
|
||||
const wrapper = mountWithContexts(<AddDropDownButton />);
|
||||
expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(false);
|
||||
});
|
||||
|
||||
test('should render two links', () => {
|
||||
const wrapper = mountWithContexts(<TemplateAddButton />);
|
||||
const wrapper = mountWithContexts(<AddDropDownButton />);
|
||||
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(<TemplateAddButton />);
|
||||
const wrapper = mountWithContexts(<AddDropDownButton />);
|
||||
wrapper.find('button').simulate('click');
|
||||
expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(true);
|
||||
wrapper.find('button').simulate('click');
|
||||
4
awx/ui_next/src/components/AddDropDownButton/index.js
Normal file
4
awx/ui_next/src/components/AddDropDownButton/index.js
Normal file
@ -0,0 +1,4 @@
|
||||
export {
|
||||
default
|
||||
}
|
||||
from './AddDropDownButton'
|
||||
@ -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 && (
|
||||
<div
|
||||
ref={node => {
|
||||
this.node = node;
|
||||
}}
|
||||
<AddDropDownButton
|
||||
key="add"
|
||||
>
|
||||
<Dropdown
|
||||
isPlain
|
||||
isOpen={isAddOpen}
|
||||
position={DropdownPosition.right}
|
||||
toggle={
|
||||
<ToolbarAddButton onClick={this.handleAddToggle} />
|
||||
}
|
||||
dropdownItems={[
|
||||
<DropdownItem key="inventory">
|
||||
<Link to={`${match.url}/inventory/add/`}>
|
||||
{i18n._(t`Inventory`)}
|
||||
</Link>
|
||||
</DropdownItem>,
|
||||
<DropdownItem key="smart_inventory">
|
||||
<Link to={`${match.url}/smart_inventory/add/`}>
|
||||
{i18n._(t`Smart Inventory`)}
|
||||
</Link>
|
||||
</DropdownItem>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
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 && (
|
||||
<div
|
||||
ref={node => {
|
||||
this.node = node;
|
||||
}}
|
||||
<AddDropDownButton
|
||||
key="add"
|
||||
>
|
||||
<Dropdown
|
||||
isPlain
|
||||
isOpen={isAddOpen}
|
||||
position={DropdownPosition.right}
|
||||
toggle={<ToolbarAddButton onClick={this.handleAddToggle} />}
|
||||
dropdownItems={[
|
||||
<DropdownItem key="inventory">
|
||||
<Link to={`${match.url}/inventory/add/`}>
|
||||
{i18n._(t`Inventory`)}
|
||||
</Link>
|
||||
</DropdownItem>,
|
||||
<DropdownItem key="smart_inventory">
|
||||
<Link to={`${match.url}/smart_inventory/add/`}>
|
||||
{i18n._(t`Smart Inventory`)}
|
||||
</Link>
|
||||
</DropdownItem>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
topUrl={`${match.url}/inventory/add/`}
|
||||
bottomUrl={`${match.url}/smart_inventory/add/`}
|
||||
topLabel={i18n._(t`Inventory`)}
|
||||
bottomLabel={i18n._(t`Smart Inventory`)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
@ -284,7 +284,7 @@ describe('<InventoriesList />', () => {
|
||||
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(<InventoriesList />);
|
||||
await waitForElement(
|
||||
wrapper,
|
||||
|
||||
@ -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 && <TemplateAddButton key="add" />,
|
||||
canAdd && (
|
||||
<AddDropDownButton
|
||||
key="add"
|
||||
topUrl={`${match.url}/job_template/add/`}
|
||||
bottomUrl={`${match.url}_workflow/add/`}
|
||||
topLabel={i18n._(t`Job Template`)}
|
||||
bottomLabel={i18n._(t`Workflow Template`)}
|
||||
/>
|
||||
),
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
@ -220,7 +228,17 @@ class TemplatesList extends Component {
|
||||
isSelected={selected.some(row => row.id === template.id)}
|
||||
/>
|
||||
)}
|
||||
emptyStateControls={canAdd && <TemplateAddButton />}
|
||||
emptyStateControls={
|
||||
canAdd && (
|
||||
<AddDropDownButton
|
||||
key="add"
|
||||
topUrl={`${match.url}/job_template/add/`}
|
||||
bottomUrl={`${match.url}_workflow/add/`}
|
||||
topLabel={i18n._(t`Job Template`)}
|
||||
bottomLabel={i18n._(t`Workflow Template`)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
<AlertModal
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user