Merge pull request #6090 from marshmalien/6085-hostListItem-remove-duplicates

HostListItem - Remove duplicate action items

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
softwarefactory-project-zuul[bot]
2020-02-26 22:39:43 +00:00
committed by GitHub
3 changed files with 136 additions and 164 deletions

View File

@@ -27,97 +27,78 @@ const DataListAction = styled(_DataListAction)`
grid-template-columns: min-content 40px; grid-template-columns: min-content 40px;
`; `;
class HostListItem extends React.Component { function HostListItem({ i18n, host, isSelected, onSelect, detailUrl }) {
static propTypes = { const labelId = `check-action-${host.id}`;
host: Host.isRequired, const recentPlaybookJobs = host.summary_fields.recent_jobs.map(job => ({
detailUrl: string.isRequired, ...job,
isSelected: bool.isRequired, type: 'job',
onSelect: func.isRequired, }));
};
render() { return (
const { host, isSelected, onSelect, detailUrl, i18n } = this.props; <DataListItem key={host.id} aria-labelledby={labelId} id={`${host.id}`}>
<DataListItemRow>
const recentPlaybookJobs = host.summary_fields.recent_jobs.map(job => ({ <DataListCheck
...job, id={`select-host-${host.id}`}
type: 'job', checked={isSelected}
})); onChange={onSelect}
aria-labelledby={labelId}
const labelId = `check-action-${host.id}`; />
return ( <DataListItemCells
<DataListItem key={host.id} aria-labelledby={labelId} id={`${host.id}`}> dataListCells={[
<DataListItemRow> <DataListCell key="name">
<DataListCheck <Link to={`${detailUrl}`}>
id={`select-host-${host.id}`} <b>{host.name}</b>
checked={isSelected} </Link>
onChange={onSelect} </DataListCell>,
aria-labelledby={labelId} <DataListCell key="recentJobs">
/> <Sparkline jobs={recentPlaybookJobs} />
<DataListItemCells </DataListCell>,
dataListCells={[ <DataListCell key="inventory">
<DataListCell key="name"> {host.summary_fields.inventory && (
<Link to={`${detailUrl}`}> <Fragment>
<b>{host.name}</b> <b css="margin-right: 24px">{i18n._(t`Inventory`)}</b>
</Link> <Link
</DataListCell>, to={`/inventories/${
<DataListCell key="recentJobs"> host.summary_fields.inventory.kind === 'smart'
<Sparkline jobs={recentPlaybookJobs} /> ? 'smart_inventory'
</DataListCell>, : 'inventory'
<DataListCell key="inventory"> }/${host.summary_fields.inventory.id}/details`}
{host.summary_fields.inventory && ( >
<Fragment> {host.summary_fields.inventory.name}
<b css="margin-right: 24px">{i18n._(t`Inventory`)}</b> </Link>
<Link </Fragment>
to={`/inventories/${ )}
host.summary_fields.inventory.kind === 'smart' </DataListCell>,
? 'smart_inventory' ]}
: 'inventory' />
}/${host.summary_fields.inventory.id}/details`} <DataListAction
> aria-label="actions"
{host.summary_fields.inventory.name} aria-labelledby={labelId}
</Link> id={labelId}
</Fragment> >
)} <HostToggle host={host} />
</DataListCell>, {host.summary_fields.user_capabilities.edit && (
<DataListCell key="enable" alignRight isFilled={false}> <Tooltip content={i18n._(t`Edit Host`)} position="top">
<HostToggle host={host} /> <Button
</DataListCell>, variant="plain"
<DataListCell key="edit" alignRight isFilled={false}> component={Link}
{host.summary_fields.user_capabilities.edit && ( to={`/hosts/${host.id}/edit`}
<Tooltip content={i18n._(t`Edit Host`)} position="top"> >
<Button <PencilAltIcon />
variant="plain" </Button>
component={Link} </Tooltip>
to={`/hosts/${host.id}/edit`} )}
> </DataListAction>
<PencilAltIcon /> </DataListItemRow>
</Button> </DataListItem>
</Tooltip> );
)}
</DataListCell>,
]}
/>
<DataListAction
aria-label="actions"
aria-labelledby={labelId}
id={labelId}
>
<HostToggle host={host} />
{host.summary_fields.user_capabilities.edit && (
<Tooltip content={i18n._(t`Edit Host`)} position="top">
<Button
variant="plain"
component={Link}
to={`/hosts/${host.id}/edit`}
>
<PencilAltIcon />
</Button>
</Tooltip>
)}
</DataListAction>
</DataListItemRow>
</DataListItem>
);
}
} }
HostListItem.propTypes = {
host: Host.isRequired,
detailUrl: string.isRequired,
isSelected: bool.isRequired,
onSelect: func.isRequired,
};
export default withI18n()(HostListItem); export default withI18n()(HostListItem);

View File

@@ -3,7 +3,7 @@ import { mountWithContexts } from '@testUtils/enzymeHelpers';
import HostsListItem from './HostListItem'; import HostsListItem from './HostListItem';
let onToggleHost; const onToggleHost = jest.fn();
const mockHost = { const mockHost = {
id: 1, id: 1,
@@ -23,16 +23,10 @@ const mockHost = {
}; };
describe('<HostsListItem />', () => { describe('<HostsListItem />', () => {
let wrapper;
beforeEach(() => { beforeEach(() => {
onToggleHost = jest.fn(); wrapper = mountWithContexts(
});
afterEach(() => {
jest.clearAllMocks();
});
test('edit button shown to users with edit capabilities', () => {
const wrapper = mountWithContexts(
<HostsListItem <HostsListItem
isSelected={false} isSelected={false}
detailUrl="/host/1" detailUrl="/host/1"
@@ -41,13 +35,20 @@ describe('<HostsListItem />', () => {
onToggleHost={onToggleHost} onToggleHost={onToggleHost}
/> />
); );
});
afterEach(() => {
jest.clearAllMocks();
});
test('edit button shown to users with edit capabilities', () => {
expect(wrapper.find('PencilAltIcon').exists()).toBeTruthy(); expect(wrapper.find('PencilAltIcon').exists()).toBeTruthy();
}); });
test('edit button hidden from users without edit capabilities', () => { test('edit button hidden from users without edit capabilities', () => {
const copyMockHost = Object.assign({}, mockHost); const copyMockHost = Object.assign({}, mockHost);
copyMockHost.summary_fields.user_capabilities.edit = false; copyMockHost.summary_fields.user_capabilities.edit = false;
const wrapper = mountWithContexts( wrapper = mountWithContexts(
<HostsListItem <HostsListItem
isSelected={false} isSelected={false}
detailUrl="/host/1" detailUrl="/host/1"
@@ -58,4 +59,8 @@ describe('<HostsListItem />', () => {
); );
expect(wrapper.find('PencilAltIcon').exists()).toBeFalsy(); expect(wrapper.find('PencilAltIcon').exists()).toBeFalsy();
}); });
test('should display host toggle', () => {
expect(wrapper.find('HostToggle').length).toBe(1);
});
}); });

View File

@@ -1,5 +1,5 @@
import React, { Component, Fragment } from 'react'; import React, { useState, useCallback } from 'react';
import { Route, withRouter, Switch } from 'react-router-dom'; import { Route, Switch } from 'react-router-dom';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
@@ -11,70 +11,56 @@ import HostList from './HostList';
import HostAdd from './HostAdd'; import HostAdd from './HostAdd';
import Host from './Host'; import Host from './Host';
class Hosts extends Component { function Hosts({ i18n }) {
constructor(props) { const [breadcrumbConfig, setBreadcrumbConfig] = useState({
super(props); '/hosts': i18n._(t`Hosts`),
'/hosts/add': i18n._(t`Create New Host`),
});
const { i18n } = props; const buildBreadcrumbConfig = useCallback(
host => {
this.state = { if (!host) {
breadcrumbConfig: { return;
}
setBreadcrumbConfig({
'/hosts': i18n._(t`Hosts`), '/hosts': i18n._(t`Hosts`),
'/hosts/add': i18n._(t`Create New Host`), '/hosts/add': i18n._(t`Create New Host`),
}, [`/hosts/${host.id}`]: `${host.name}`,
}; [`/hosts/${host.id}/edit`]: i18n._(t`Edit Details`),
} [`/hosts/${host.id}/details`]: i18n._(t`Details`),
[`/hosts/${host.id}/facts`]: i18n._(t`Facts`),
[`/hosts/${host.id}/groups`]: i18n._(t`Groups`),
[`/hosts/${host.id}/completed_jobs`]: i18n._(t`Completed Jobs`),
});
},
[i18n]
);
setBreadcrumbConfig = host => { return (
const { i18n } = this.props; <>
<Breadcrumbs breadcrumbConfig={breadcrumbConfig} />
if (!host) { <PageSection>
return; <Card>
} <Switch>
<Route path="/hosts/add">
const breadcrumbConfig = { <HostAdd />
'/hosts': i18n._(t`Hosts`), </Route>
'/hosts/add': i18n._(t`Create New Host`), <Route path="/hosts/:id">
[`/hosts/${host.id}`]: `${host.name}`, <Config>
[`/hosts/${host.id}/edit`]: i18n._(t`Edit Details`), {({ me }) => (
[`/hosts/${host.id}/details`]: i18n._(t`Details`), <Host setBreadcrumb={buildBreadcrumbConfig} me={me || {}} />
[`/hosts/${host.id}/facts`]: i18n._(t`Facts`), )}
[`/hosts/${host.id}/groups`]: i18n._(t`Groups`), </Config>
[`/hosts/${host.id}/completed_jobs`]: i18n._(t`Completed Jobs`), </Route>
}; <Route path="/hosts">
<HostList />
this.setState({ breadcrumbConfig }); </Route>
}; </Switch>
</Card>
render() { </PageSection>
const { match } = this.props; </>
const { breadcrumbConfig } = this.state; );
return (
<Fragment>
<Breadcrumbs breadcrumbConfig={breadcrumbConfig} />
<PageSection>
<Card>
<Switch>
<Route path={`${match.path}/add`} render={() => <HostAdd />} />
<Route path={`${match.path}/:id`}>
<Config>
{({ me }) => (
<Host
setBreadcrumb={this.setBreadcrumbConfig}
me={me || {}}
/>
)}
</Config>
</Route>
<Route path={`${match.path}`} render={() => <HostList />} />
</Switch>
</Card>
</PageSection>
</Fragment>
);
}
} }
export { Hosts as _Hosts }; export { Hosts as _Hosts };
export default withI18n()(withRouter(Hosts)); export default withI18n()(Hosts);