mirror of
https://github.com/ansible/awx.git
synced 2026-03-27 22:05:07 -02:30
Moves tooltip and link logic out to the sparkline from the job status icon
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React from 'react';
|
||||||
import { node, number, shape, string } from 'prop-types';
|
import { string } from 'prop-types';
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import styled, { keyframes } from 'styled-components';
|
import styled, { keyframes } from 'styled-components';
|
||||||
import { Tooltip } from '@patternfly/react-core';
|
|
||||||
|
|
||||||
const Pulse = keyframes`
|
const Pulse = keyframes`
|
||||||
from {
|
from {
|
||||||
@@ -58,59 +56,31 @@ const FailedBottom = styled.div`
|
|||||||
background-color: #d9534f;
|
background-color: #d9534f;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const JobStatusIcon = ({ job, link, tooltip, ...props }) => {
|
const JobStatusIcon = ({ status, ...props }) => {
|
||||||
let Icon = (
|
return (
|
||||||
<Fragment>
|
<div {...props}>
|
||||||
{job.status === 'running' && <RunningJob />}
|
{status === 'running' && <RunningJob />}
|
||||||
{(job.status === 'new' ||
|
{(status === 'new' || status === 'pending' || status === 'waiting') && (
|
||||||
job.status === 'pending' ||
|
<WaitingJob />
|
||||||
job.status === 'waiting') && <WaitingJob />}
|
)}
|
||||||
{(job.status === 'failed' ||
|
{(status === 'failed' || status === 'error' || status === 'canceled') && (
|
||||||
job.status === 'error' ||
|
|
||||||
job.status === 'canceled') && (
|
|
||||||
<FinishedJob>
|
<FinishedJob>
|
||||||
<FailedTop />
|
<FailedTop />
|
||||||
<FailedBottom />
|
<FailedBottom />
|
||||||
</FinishedJob>
|
</FinishedJob>
|
||||||
)}
|
)}
|
||||||
{job.status === 'successful' && (
|
{status === 'successful' && (
|
||||||
<FinishedJob>
|
<FinishedJob>
|
||||||
<SuccessfulTop />
|
<SuccessfulTop />
|
||||||
<SuccessfulBottom />
|
<SuccessfulBottom />
|
||||||
</FinishedJob>
|
</FinishedJob>
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (link) {
|
|
||||||
Icon = <Link to={link}>{Icon}</Link>;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tooltip) {
|
|
||||||
return (
|
|
||||||
<div {...props}>
|
|
||||||
<Tooltip position="top" content={tooltip}>
|
|
||||||
{Icon}
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div {...props}>{Icon}</div>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
JobStatusIcon.propTypes = {
|
JobStatusIcon.propTypes = {
|
||||||
job: shape({
|
status: string.isRequired,
|
||||||
id: number.isRequired,
|
|
||||||
status: string.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
link: string,
|
|
||||||
tooltip: node,
|
|
||||||
};
|
|
||||||
|
|
||||||
JobStatusIcon.defaultProps = {
|
|
||||||
link: null,
|
|
||||||
tooltip: null,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default JobStatusIcon;
|
export default JobStatusIcon;
|
||||||
|
|||||||
@@ -1,63 +1,28 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { mount } from 'enzyme';
|
import { mount } from 'enzyme';
|
||||||
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
|
|
||||||
|
|
||||||
import JobStatusIcon from './JobStatusIcon';
|
import JobStatusIcon from './JobStatusIcon';
|
||||||
|
|
||||||
describe('JobStatusIcon', () => {
|
describe('JobStatusIcon', () => {
|
||||||
const job = {
|
test('renders the successful job', () => {
|
||||||
id: 1,
|
const wrapper = mount(<JobStatusIcon status="successful" />);
|
||||||
status: 'successful',
|
|
||||||
};
|
|
||||||
|
|
||||||
test('renders the expected content', () => {
|
|
||||||
const wrapper = mount(<JobStatusIcon job={job} />);
|
|
||||||
expect(wrapper).toHaveLength(1);
|
expect(wrapper).toHaveLength(1);
|
||||||
expect(wrapper.find('Tooltip')).toHaveLength(0);
|
|
||||||
expect(wrapper.find('Link')).toHaveLength(0);
|
|
||||||
});
|
|
||||||
test('renders with tooltip if tooltip passed', () => {
|
|
||||||
const wrapper = mount(<JobStatusIcon job={job} tooltip="Foo Bar" />);
|
|
||||||
expect(wrapper).toHaveLength(1);
|
|
||||||
expect(wrapper.find('Tooltip')).toHaveLength(1);
|
|
||||||
expect(wrapper.find('Link')).toHaveLength(0);
|
|
||||||
});
|
|
||||||
test('renders with link if link passed', () => {
|
|
||||||
const wrapper = mountWithContexts(
|
|
||||||
<JobStatusIcon job={job} link="/jobs/playbook/1" />
|
|
||||||
);
|
|
||||||
expect(wrapper).toHaveLength(1);
|
|
||||||
expect(wrapper.find('Tooltip')).toHaveLength(0);
|
|
||||||
expect(wrapper.find('Link')).toHaveLength(1);
|
|
||||||
});
|
|
||||||
test('renders running job', () => {
|
|
||||||
const runningJob = {
|
|
||||||
id: 2,
|
|
||||||
status: 'running',
|
|
||||||
};
|
|
||||||
const wrapper = mount(<JobStatusIcon job={runningJob} />);
|
|
||||||
expect(wrapper.find('JobStatusIcon__RunningJob')).toHaveLength(1);
|
|
||||||
});
|
|
||||||
test('renders waiting job', () => {
|
|
||||||
const waitingJob = {
|
|
||||||
id: 3,
|
|
||||||
status: 'waiting',
|
|
||||||
};
|
|
||||||
const wrapper = mount(<JobStatusIcon job={waitingJob} />);
|
|
||||||
expect(wrapper.find('JobStatusIcon__WaitingJob')).toHaveLength(1);
|
|
||||||
});
|
|
||||||
test('renders failed job', () => {
|
|
||||||
const failedJob = {
|
|
||||||
id: 4,
|
|
||||||
status: 'failed',
|
|
||||||
};
|
|
||||||
const wrapper = mount(<JobStatusIcon job={failedJob} />);
|
|
||||||
expect(wrapper.find('JobStatusIcon__FailedTop')).toHaveLength(1);
|
|
||||||
expect(wrapper.find('JobStatusIcon__FailedBottom')).toHaveLength(1);
|
|
||||||
});
|
|
||||||
test('renders successful job', () => {
|
|
||||||
const wrapper = mount(<JobStatusIcon job={job} />);
|
|
||||||
expect(wrapper.find('JobStatusIcon__SuccessfulTop')).toHaveLength(1);
|
expect(wrapper.find('JobStatusIcon__SuccessfulTop')).toHaveLength(1);
|
||||||
expect(wrapper.find('JobStatusIcon__SuccessfulBottom')).toHaveLength(1);
|
expect(wrapper.find('JobStatusIcon__SuccessfulBottom')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
test('renders running job', () => {
|
||||||
|
const wrapper = mount(<JobStatusIcon status="running" />);
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('JobStatusIcon__RunningJob')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
test('renders waiting job', () => {
|
||||||
|
const wrapper = mount(<JobStatusIcon status="waiting" />);
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('JobStatusIcon__WaitingJob')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
test('renders failed job', () => {
|
||||||
|
const wrapper = mount(<JobStatusIcon status="failed" />);
|
||||||
|
expect(wrapper).toHaveLength(1);
|
||||||
|
expect(wrapper.find('JobStatusIcon__FailedTop')).toHaveLength(1);
|
||||||
|
expect(wrapper.find('JobStatusIcon__FailedBottom')).toHaveLength(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import { arrayOf, object } from 'prop-types';
|
import { arrayOf, object } from 'prop-types';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { JobStatusIcon as _JobStatusIcon } from '@components/Sparkline';
|
import { Link as _Link } from 'react-router-dom';
|
||||||
|
import { JobStatusIcon } from '@components/Sparkline';
|
||||||
|
import { Tooltip } from '@patternfly/react-core';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { JOB_TYPE_URL_SEGMENTS } from '../../constants';
|
import { JOB_TYPE_URL_SEGMENTS } from '../../constants';
|
||||||
|
|
||||||
/* eslint-disable react/jsx-pascal-case */
|
/* eslint-disable react/jsx-pascal-case */
|
||||||
const JobStatusIcon = styled(props => <_JobStatusIcon {...props} />)`
|
const Link = styled(props => <_Link {...props} />)`
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
`;
|
`;
|
||||||
/* eslint-enable react/jsx-pascal-case */
|
/* eslint-enable react/jsx-pascal-case */
|
||||||
@@ -30,12 +32,11 @@ const Sparkline = ({ i18n, jobs }) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return jobs.map(job => (
|
return jobs.map(job => (
|
||||||
<JobStatusIcon
|
<Tooltip position="top" content={generateTooltip(job)} key={job.id}>
|
||||||
key={job.id}
|
<Link to={`/jobs/${JOB_TYPE_URL_SEGMENTS[job.type]}/${job.id}`}>
|
||||||
job={job}
|
<JobStatusIcon status={job.status} />
|
||||||
link={`/jobs/${JOB_TYPE_URL_SEGMENTS[job.type]}/${job.id}`}
|
</Link>
|
||||||
tooltip={generateTooltip(job)}
|
</Tooltip>
|
||||||
/>
|
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,18 +9,22 @@ describe('Sparkline', () => {
|
|||||||
const wrapper = mount(<Sparkline />);
|
const wrapper = mount(<Sparkline />);
|
||||||
expect(wrapper).toHaveLength(1);
|
expect(wrapper).toHaveLength(1);
|
||||||
});
|
});
|
||||||
test('renders an icon for each job', () => {
|
test('renders an icon with tooltips and links for each job', () => {
|
||||||
const jobs = [
|
const jobs = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
status: 'successful',
|
status: 'successful',
|
||||||
|
finished: '2019-08-08T15:27:57.320120Z',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
status: 'failed',
|
status: 'failed',
|
||||||
|
finished: '2019-08-09T15:27:57.320120Z',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const wrapper = mountWithContexts(<Sparkline jobs={jobs} />);
|
const wrapper = mountWithContexts(<Sparkline jobs={jobs} />);
|
||||||
expect(wrapper.find('JobStatusIcon')).toHaveLength(2);
|
expect(wrapper.find('JobStatusIcon')).toHaveLength(2);
|
||||||
|
expect(wrapper.find('Tooltip')).toHaveLength(2);
|
||||||
|
expect(wrapper.find('Link')).toHaveLength(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user