mirror of
https://github.com/ansible/awx.git
synced 2026-02-28 00:08:44 -03:30
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:
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user