Merge pull request #6109 from marshmalien/inventory-host-toggle

Use HostToggle component in InventoryHostList

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
softwarefactory-project-zuul[bot] 2020-02-27 23:53:50 +00:00 committed by GitHub
commit 33df6f8ad2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 50 additions and 112 deletions

View File

@ -0,0 +1 @@
export { default } from './HostToggle';

View File

@ -12,7 +12,7 @@ import { VariablesDetail } from '@components/CodeMirrorInput';
import Sparkline from '@components/Sparkline';
import DeleteButton from '@components/DeleteButton';
import { HostsAPI } from '@api';
import HostToggle from '../shared/HostToggle';
import HostToggle from '@components/HostToggle';
function HostDetail({ host, i18n, onUpdateHost }) {
const {

View File

@ -121,7 +121,7 @@ describe('<HostList />', () => {
expect(wrapper.find('HostListItem')).toHaveLength(3);
});
test('should select single item', async () => {
test('should select and deselect a single item', async () => {
let wrapper;
await act(async () => {
wrapper = mountWithContexts(<HostList />);
@ -141,6 +141,19 @@ describe('<HostList />', () => {
.first()
.prop('isSelected')
).toEqual(true);
act(() => {
wrapper
.find('input#select-host-1')
.closest('DataListCheck')
.invoke('onChange')();
});
wrapper.update();
expect(
wrapper
.find('HostListItem')
.first()
.prop('isSelected')
).toEqual(false);
});
test('should select all items', async () => {

View File

@ -18,7 +18,7 @@ import { PencilAltIcon } from '@patternfly/react-icons';
import Sparkline from '@components/Sparkline';
import { Host } from '@types';
import styled from 'styled-components';
import HostToggle from '../shared/HostToggle';
import HostToggle from '@components/HostToggle';
const DataListAction = styled(_DataListAction)`
align-items: center;

View File

@ -3,8 +3,6 @@ import { mountWithContexts } from '@testUtils/enzymeHelpers';
import HostsListItem from './HostListItem';
const onToggleHost = jest.fn();
const mockHost = {
id: 1,
name: 'Host 1',
@ -32,13 +30,12 @@ describe('<HostsListItem />', () => {
detailUrl="/host/1"
onSelect={() => {}}
host={mockHost}
onToggleHost={onToggleHost}
/>
);
});
afterEach(() => {
jest.clearAllMocks();
wrapper.unmount();
});
test('edit button shown to users with edit capabilities', () => {
@ -54,7 +51,6 @@ describe('<HostsListItem />', () => {
detailUrl="/host/1"
onSelect={() => {}}
host={copyMockHost}
onToggleHost={onToggleHost}
/>
);
expect(wrapper.find('PencilAltIcon').exists()).toBeFalsy();

View File

@ -10,11 +10,11 @@ import {
DataListItem,
DataListItemCells,
DataListItemRow,
Switch,
Tooltip,
} from '@patternfly/react-core';
import { Link } from 'react-router-dom';
import { PencilAltIcon } from '@patternfly/react-icons';
import HostToggle from '@components/HostToggle';
import Sparkline from '@components/Sparkline';
import { Host } from '@types';
import styled from 'styled-components';
@ -27,16 +27,7 @@ const DataListAction = styled(_DataListAction)`
`;
function InventoryHostItem(props) {
const {
detailUrl,
editUrl,
host,
i18n,
isSelected,
onSelect,
toggleHost,
toggleLoading,
} = props;
const { detailUrl, editUrl, host, i18n, isSelected, onSelect } = props;
const recentPlaybookJobs = host.summary_fields.recent_jobs.map(job => ({
...job,
@ -71,27 +62,7 @@ function InventoryHostItem(props) {
aria-labelledby={labelId}
id={labelId}
>
<Tooltip
content={i18n._(
t`Indicates if a host is available and should be included
in running jobs. For hosts that are part of an external
inventory, this may be reset by the inventory sync process.`
)}
position="top"
>
<Switch
css="display: inline-flex;"
id={`host-${host.id}-toggle`}
label={i18n._(t`On`)}
labelOff={i18n._(t`Off`)}
isChecked={host.enabled}
isDisabled={
toggleLoading || !host.summary_fields.user_capabilities?.edit
}
onChange={() => toggleHost(host)}
aria-label={i18n._(t`Toggle host`)}
/>
</Tooltip>
<HostToggle host={host} />
{host.summary_fields.user_capabilities?.edit && (
<Tooltip content={i18n._(t`Edit Host`)} position="top">
<Button variant="plain" component={Link} to={`${editUrl}`}>
@ -110,8 +81,6 @@ InventoryHostItem.propTypes = {
host: Host.isRequired,
isSelected: bool.isRequired,
onSelect: func.isRequired,
toggleHost: func.isRequired,
toggleLoading: bool.isRequired,
};
export default withI18n()(InventoryHostItem);

View File

@ -2,8 +2,6 @@ import React from 'react';
import { mountWithContexts } from '@testUtils/enzymeHelpers';
import InventoryHostItem from './InventoryHostItem';
let toggleHost;
const mockHost = {
id: 1,
name: 'Host 1',
@ -17,65 +15,54 @@ const mockHost = {
user_capabilities: {
edit: true,
},
recent_jobs: [],
recent_jobs: [
{
id: 123,
name: 'Demo Job Template',
status: 'failed',
finished: '2020-02-26T22:38:41.037991Z',
},
],
},
};
describe('<InventoryHostItem />', () => {
let wrapper;
beforeEach(() => {
toggleHost = jest.fn();
});
afterEach(() => {
jest.clearAllMocks();
});
test('edit button shown to users with edit capabilities', () => {
const wrapper = mountWithContexts(
wrapper = mountWithContexts(
<InventoryHostItem
isSelected={false}
detailUrl="/host/1"
onSelect={() => {}}
host={mockHost}
toggleHost={toggleHost}
toggleLoading={false}
/>
);
});
afterEach(() => {
wrapper.unmount();
});
test('edit button shown to users with edit capabilities', () => {
expect(wrapper.find('PencilAltIcon').exists()).toBeTruthy();
});
test('edit button hidden from users without edit capabilities', () => {
const copyMockHost = Object.assign({}, mockHost);
copyMockHost.summary_fields.user_capabilities.edit = false;
const wrapper = mountWithContexts(
wrapper = mountWithContexts(
<InventoryHostItem
isSelected={false}
detailUrl="/host/1"
onSelect={() => {}}
host={copyMockHost}
toggleHost={toggleHost}
toggleLoading={false}
/>
);
expect(wrapper.find('PencilAltIcon').exists()).toBeFalsy();
});
test('handles toggle click when host is enabled', () => {
const wrapper = mountWithContexts(
<InventoryHostItem
isSelected={false}
detailUrl="/host/1"
onSelect={() => {}}
host={mockHost}
toggleHost={toggleHost}
toggleLoading={false}
/>
);
wrapper
.find('Switch')
.first()
.find('input')
.simulate('change');
expect(toggleHost).toHaveBeenCalledWith(mockHost);
test('should display host toggle', () => {
expect(wrapper.find('HostToggle').length).toBe(1);
});
});

View File

@ -28,8 +28,6 @@ function InventoryHostList({ i18n, location, match }) {
const [hosts, setHosts] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [selected, setSelected] = useState([]);
const [toggleError, setToggleError] = useState(null);
const [toggleLoading, setToggleLoading] = useState(null);
const fetchHosts = (id, queryString) => {
const params = parseQueryString(QS_CONFIG, queryString);
@ -100,24 +98,6 @@ function InventoryHostList({ i18n, location, match }) {
}
};
const handleToggle = async hostToToggle => {
setToggleLoading(hostToToggle.id);
try {
const { data: updatedHost } = await HostsAPI.update(hostToToggle.id, {
enabled: !hostToToggle.enabled,
});
setHosts(
hosts.map(host => (host.id === updatedHost.id ? updatedHost : host))
);
} catch (error) {
setToggleError(error);
} finally {
setToggleLoading(null);
}
};
const canAdd =
actions && Object.prototype.hasOwnProperty.call(actions, 'POST');
const isAllSelected = selected.length > 0 && selected.length === hosts.length;
@ -184,8 +164,6 @@ function InventoryHostList({ i18n, location, match }) {
editUrl={`/inventories/inventory/${match.params.id}/hosts/${o.id}/edit`}
isSelected={selected.some(row => row.id === o.id)}
onSelect={() => handleSelect(o)}
toggleHost={handleToggle}
toggleLoading={toggleLoading === o.id}
/>
)}
emptyStateControls={
@ -197,19 +175,6 @@ function InventoryHostList({ i18n, location, match }) {
)
}
/>
{toggleError && !toggleLoading && (
<AlertModal
variant="error"
title={i18n._(t`Error!`)}
isOpen={toggleError && !toggleLoading}
onClose={() => setToggleError(false)}
>
{i18n._(t`Failed to toggle host.`)}
<ErrorDetail error={toggleError} />
</AlertModal>
)}
{deletionError && (
<AlertModal
isOpen={deletionError}

View File

@ -60,7 +60,14 @@ const mockHosts = [
delete: false,
update: false,
},
recent_jobs: [],
recent_jobs: [
{
id: 123,
name: 'Recent Job',
status: 'success',
finished: '2020-01-27T19:40:36.208728Z',
},
],
},
},
];