diff --git a/awx/ui_next/src/components/Sparkline/HostStatusIcon.jsx b/awx/ui_next/src/components/Sparkline/HostStatusIcon.jsx deleted file mode 100644 index 5558016bf2..0000000000 --- a/awx/ui_next/src/components/Sparkline/HostStatusIcon.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import React from 'react'; -import { string } from 'prop-types'; -import { - ChangedBottom, - ChangedTop, - FailedBottom, - FailedTop, - FinishedJob, - SkippedBottom, - SkippedTop, - SuccessfulBottom, - SuccessfulTop, - UnreachableBottom, - UnreachableTop, -} from './shared/StatusIcon'; - -const HostStatusIcon = ({ status }) => { - return ( -
- {status === 'changed' && ( - - - - - )} - {status === 'failed' && ( - - - - - )} - {status === 'skipped' && ( - - - - - )} - {status === 'ok' && ( - - - - - )} - {status === 'unreachable' && ( - - - - - )} -
- ); -}; - -HostStatusIcon.propTypes = { - status: string.isRequired, -}; - -export default HostStatusIcon; diff --git a/awx/ui_next/src/components/Sparkline/HostStatusIcon.test.jsx b/awx/ui_next/src/components/Sparkline/HostStatusIcon.test.jsx deleted file mode 100644 index 69c2070582..0000000000 --- a/awx/ui_next/src/components/Sparkline/HostStatusIcon.test.jsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import HostStatusIcon from './HostStatusIcon'; - -describe('HostStatusIcon', () => { - test('renders the "ok" host status', () => { - const wrapper = mount(); - expect(wrapper).toHaveLength(1); - expect(wrapper.find('StatusIcon__SuccessfulTop')).toHaveLength(1); - expect(wrapper.find('StatusIcon__SuccessfulBottom')).toHaveLength(1); - }); - test('renders "failed" host status', () => { - const wrapper = mount(); - expect(wrapper).toHaveLength(1); - expect(wrapper.find('StatusIcon__FailedTop')).toHaveLength(1); - expect(wrapper.find('StatusIcon__FailedBottom')).toHaveLength(1); - }); - test('renders "changed" host status', () => { - const wrapper = mount(); - expect(wrapper).toHaveLength(1); - expect(wrapper.find('StatusIcon__ChangedTop')).toHaveLength(1); - expect(wrapper.find('StatusIcon__ChangedBottom')).toHaveLength(1); - }); - test('renders "skipped" host status', () => { - const wrapper = mount(); - expect(wrapper).toHaveLength(1); - expect(wrapper.find('StatusIcon__SkippedTop')).toHaveLength(1); - expect(wrapper.find('StatusIcon__SkippedBottom')).toHaveLength(1); - }); - test('renders "unreachable" host status', () => { - const wrapper = mount(); - expect(wrapper).toHaveLength(1); - expect(wrapper.find('StatusIcon__UnreachableTop')).toHaveLength(1); - expect(wrapper.find('StatusIcon__UnreachableBottom')).toHaveLength(1); - }); -}); diff --git a/awx/ui_next/src/components/Sparkline/JobStatusIcon.jsx b/awx/ui_next/src/components/Sparkline/JobStatusIcon.jsx deleted file mode 100644 index 0167793fa8..0000000000 --- a/awx/ui_next/src/components/Sparkline/JobStatusIcon.jsx +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; -import { string } from 'prop-types'; -import { - RunningJob, - WaitingJob, - FinishedJob, - SuccessfulTop, - SuccessfulBottom, - FailedBottom, - FailedTop, -} from './shared/StatusIcon'; - -const JobStatusIcon = ({ status, ...props }) => { - return ( -
- {status === 'running' && } - {(status === 'new' || status === 'pending' || status === 'waiting') && ( - - )} - {(status === 'failed' || status === 'error' || status === 'canceled') && ( - - - - - )} - {status === 'successful' && ( - - - - - )} -
- ); -}; - -JobStatusIcon.propTypes = { - status: string.isRequired, -}; - -export default JobStatusIcon; diff --git a/awx/ui_next/src/components/Sparkline/JobStatusIcon.test.jsx b/awx/ui_next/src/components/Sparkline/JobStatusIcon.test.jsx deleted file mode 100644 index 86485223ab..0000000000 --- a/awx/ui_next/src/components/Sparkline/JobStatusIcon.test.jsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import JobStatusIcon from './JobStatusIcon'; - -describe('JobStatusIcon', () => { - test('renders the successful job', () => { - const wrapper = mount(); - expect(wrapper).toHaveLength(1); - expect(wrapper.find('StatusIcon__SuccessfulTop')).toHaveLength(1); - expect(wrapper.find('StatusIcon__SuccessfulBottom')).toHaveLength(1); - }); - test('renders running job', () => { - const wrapper = mount(); - expect(wrapper).toHaveLength(1); - expect(wrapper.find('StatusIcon__RunningJob')).toHaveLength(1); - }); - test('renders waiting job', () => { - const wrapper = mount(); - expect(wrapper).toHaveLength(1); - expect(wrapper.find('StatusIcon__WaitingJob')).toHaveLength(1); - }); - test('renders failed job', () => { - const wrapper = mount(); - expect(wrapper).toHaveLength(1); - expect(wrapper.find('StatusIcon__FailedTop')).toHaveLength(1); - expect(wrapper.find('StatusIcon__FailedBottom')).toHaveLength(1); - }); -}); diff --git a/awx/ui_next/src/components/Sparkline/Sparkline.jsx b/awx/ui_next/src/components/Sparkline/Sparkline.jsx index 5291eeca85..57029ce73a 100644 --- a/awx/ui_next/src/components/Sparkline/Sparkline.jsx +++ b/awx/ui_next/src/components/Sparkline/Sparkline.jsx @@ -2,7 +2,7 @@ import React, { Fragment } from 'react'; import { arrayOf, object } from 'prop-types'; import { withI18n } from '@lingui/react'; import { Link as _Link } from 'react-router-dom'; -import { JobStatusIcon } from '@components/Sparkline'; +import { StatusIcon } from '@components/Sparkline'; import { Tooltip } from '@patternfly/react-core'; import styled from 'styled-components'; import { t } from '@lingui/macro'; @@ -34,7 +34,7 @@ const Sparkline = ({ i18n, jobs }) => { return jobs.map(job => ( - + )); diff --git a/awx/ui_next/src/components/Sparkline/Sparkline.test.jsx b/awx/ui_next/src/components/Sparkline/Sparkline.test.jsx index e39003a841..0d4d5579e9 100644 --- a/awx/ui_next/src/components/Sparkline/Sparkline.test.jsx +++ b/awx/ui_next/src/components/Sparkline/Sparkline.test.jsx @@ -23,7 +23,7 @@ describe('Sparkline', () => { }, ]; const wrapper = mountWithContexts(); - expect(wrapper.find('JobStatusIcon')).toHaveLength(2); + expect(wrapper.find('StatusIcon')).toHaveLength(2); expect(wrapper.find('Tooltip')).toHaveLength(2); expect(wrapper.find('Link')).toHaveLength(2); }); diff --git a/awx/ui_next/src/components/Sparkline/StatusIcon.jsx b/awx/ui_next/src/components/Sparkline/StatusIcon.jsx new file mode 100644 index 0000000000..5f048f5cb5 --- /dev/null +++ b/awx/ui_next/src/components/Sparkline/StatusIcon.jsx @@ -0,0 +1,121 @@ +import React from 'react'; +import { string } from 'prop-types'; +import styled, { keyframes } from 'styled-components'; + +const Pulse = keyframes` + from { + -webkit-transform:scale(1); + } + to { + -webkit-transform:scale(0); + } +`; + +const Wrapper = styled.div` + width: 14px; + height: 14px; +`; + +const WhiteTop = styled.div` + border: 1px solid #b7b7b7; + border-bottom: 0; + background: #ffffff; +`; + +const WhiteBottom = styled.div` + border: 1px solid #b7b7b7; + border-top: 0; + background: #ffffff; +`; + +const RunningJob = styled(Wrapper)` + background-color: #5cb85c; + padding-right: 0px; + text-shadow: -1px -1px 0 #ffffff, 1px -1px 0 #ffffff, -1px 1px 0 #ffffff, + 1px 1px 0 #ffffff; + animation: ${Pulse} 1.5s linear infinite alternate; +`; + +const WaitingJob = styled(Wrapper)` + border: 1px solid #d7d7d7; +`; + +const FinishedJob = styled(Wrapper)` + flex: 0 1 auto; + > * { + width: 14px; + height: 7px; + } +`; + +const SuccessfulTop = styled.div` + background-color: #5cb85c; +`; +const SuccessfulBottom = styled(WhiteBottom)``; + +const FailedTop = styled(WhiteTop)``; +const FailedBottom = styled.div` + background-color: #d9534f; +`; + +const UnreachableTop = styled(WhiteTop)``; +const UnreachableBottom = styled.div` + background-color: #ff0000; +`; + +const ChangedTop = styled(WhiteTop)``; +const ChangedBottom = styled.div` + background-color: #ff9900; +`; + +const SkippedTop = styled(WhiteTop)``; +const SkippedBottom = styled.div` + background-color: #2dbaba; +`; + +const StatusIcon = ({ status, ...props }) => { + return ( +
+ {status === 'running' && } + {(status === 'new' || status === 'pending' || status === 'waiting') && ( + + )} + {(status === 'failed' || status === 'error' || status === 'canceled') && ( + + + + + )} + {(status === 'successful' || status === 'ok') && ( + + + + + )} + {status === 'changed' && ( + + + + + )} + {status === 'skipped' && ( + + + + + )} + {status === 'unreachable' && ( + + + + + )} +
+ ); +}; + +StatusIcon.propTypes = { + status: string.isRequired, +}; + +export default StatusIcon; diff --git a/awx/ui_next/src/components/Sparkline/StatusIcon.test.jsx b/awx/ui_next/src/components/Sparkline/StatusIcon.test.jsx new file mode 100644 index 0000000000..fd47a309c8 --- /dev/null +++ b/awx/ui_next/src/components/Sparkline/StatusIcon.test.jsx @@ -0,0 +1,59 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import StatusIcon from './StatusIcon'; + +describe('StatusIcon', () => { + test('renders the successful status', () => { + const wrapper = mount(); + expect(wrapper).toHaveLength(1); + expect(wrapper.find('StatusIcon__SuccessfulTop')).toHaveLength(1); + expect(wrapper.find('StatusIcon__SuccessfulBottom')).toHaveLength(1); + }); + test('renders running status', () => { + const wrapper = mount(); + expect(wrapper).toHaveLength(1); + expect(wrapper.find('StatusIcon__RunningJob')).toHaveLength(1); + }); + test('renders waiting status', () => { + const wrapper = mount(); + expect(wrapper).toHaveLength(1); + expect(wrapper.find('StatusIcon__WaitingJob')).toHaveLength(1); + }); + test('renders failed status', () => { + const wrapper = mount(); + expect(wrapper).toHaveLength(1); + expect(wrapper.find('StatusIcon__FailedTop')).toHaveLength(1); + expect(wrapper.find('StatusIcon__FailedBottom')).toHaveLength(1); + }); + test('renders a successful status when host status is "ok"', () => { + const wrapper = mount(); + wrapper.debug(); + expect(wrapper).toHaveLength(1); + expect(wrapper.find('StatusIcon__SuccessfulTop')).toHaveLength(1); + expect(wrapper.find('StatusIcon__SuccessfulBottom')).toHaveLength(1); + }); + test('renders "failed" host status', () => { + const wrapper = mount(); + expect(wrapper).toHaveLength(1); + expect(wrapper.find('StatusIcon__FailedTop')).toHaveLength(1); + expect(wrapper.find('StatusIcon__FailedBottom')).toHaveLength(1); + }); + test('renders "changed" host status', () => { + const wrapper = mount(); + expect(wrapper).toHaveLength(1); + expect(wrapper.find('StatusIcon__ChangedTop')).toHaveLength(1); + expect(wrapper.find('StatusIcon__ChangedBottom')).toHaveLength(1); + }); + test('renders "skipped" host status', () => { + const wrapper = mount(); + expect(wrapper).toHaveLength(1); + expect(wrapper.find('StatusIcon__SkippedTop')).toHaveLength(1); + expect(wrapper.find('StatusIcon__SkippedBottom')).toHaveLength(1); + }); + test('renders "unreachable" host status', () => { + const wrapper = mount(); + expect(wrapper).toHaveLength(1); + expect(wrapper.find('StatusIcon__UnreachableTop')).toHaveLength(1); + expect(wrapper.find('StatusIcon__UnreachableBottom')).toHaveLength(1); + }); +}); diff --git a/awx/ui_next/src/components/Sparkline/index.js b/awx/ui_next/src/components/Sparkline/index.js index 2b299b651e..f7b30c0d98 100644 --- a/awx/ui_next/src/components/Sparkline/index.js +++ b/awx/ui_next/src/components/Sparkline/index.js @@ -1,3 +1,2 @@ export { default as Sparkline } from './Sparkline'; -export { default as JobStatusIcon } from './JobStatusIcon'; -export { default as HostStatusIcon } from './HostStatusIcon'; +export { default as StatusIcon } from './StatusIcon'; diff --git a/awx/ui_next/src/components/Sparkline/shared/StatusIcon.jsx b/awx/ui_next/src/components/Sparkline/shared/StatusIcon.jsx deleted file mode 100644 index c02af801b1..0000000000 --- a/awx/ui_next/src/components/Sparkline/shared/StatusIcon.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import styled, { keyframes } from 'styled-components'; - -const Pulse = keyframes` - from { - -webkit-transform:scale(1); - } - to { - -webkit-transform:scale(0); - } -`; - -const Wrapper = styled.div` - width: 14px; - height: 14px; -`; - -const WhiteTop = styled.div` - border: 1px solid #b7b7b7; - border-bottom: 0; - background: #ffffff; -`; - -const WhiteBottom = styled.div` - border: 1px solid #b7b7b7; - border-top: 0; - background: #ffffff; -`; - -export const RunningJob = styled(Wrapper)` - background-color: #5cb85c; - padding-right: 0px; - text-shadow: -1px -1px 0 #ffffff, 1px -1px 0 #ffffff, -1px 1px 0 #ffffff, - 1px 1px 0 #ffffff; - animation: ${Pulse} 1.5s linear infinite alternate; -`; - -export const WaitingJob = styled(Wrapper)` - border: 1px solid #d7d7d7; -`; - -export const FinishedJob = styled(Wrapper)` - flex: 0 1 auto; - > * { - width: 14px; - height: 7px; - } -`; - -export const SuccessfulTop = styled.div` - background-color: #5cb85c; -`; -export const SuccessfulBottom = styled(WhiteBottom)``; - -export const FailedTop = styled(WhiteTop)``; -export const FailedBottom = styled.div` - background-color: #d9534f; -`; - -export const UnreachableTop = styled(WhiteTop)``; -export const UnreachableBottom = styled.div` - background-color: #ff0000; -`; - -export const ChangedTop = styled(WhiteTop)``; -export const ChangedBottom = styled.div` - background-color: #ff9900; -`; - -export const SkippedTop = styled(WhiteTop)``; -export const SkippedBottom = styled.div` - background-color: #2dbaba; -`; diff --git a/awx/ui_next/src/screens/Job/JobOutput/HostEventModal.jsx b/awx/ui_next/src/screens/Job/JobOutput/HostEventModal.jsx index 7c826518a1..79aa92a560 100644 --- a/awx/ui_next/src/screens/Job/JobOutput/HostEventModal.jsx +++ b/awx/ui_next/src/screens/Job/JobOutput/HostEventModal.jsx @@ -9,7 +9,7 @@ import CodeMirrorInput from '@components/CodeMirrorInput'; import ContentEmpty from '@components/ContentEmpty'; import PropTypes from 'prop-types'; import { DetailList, Detail } from '@components/DetailList'; -import { HostStatusIcon } from '@components/Sparkline'; +import { StatusIcon } from '@components/Sparkline'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import styled from 'styled-components'; @@ -76,7 +76,7 @@ const processEventStatus = event => { ) { status = 'ok'; } - // catch the 'changed' case after 'ok', because both can be true + // if 'ok' and 'changed' are both true, show 'changed' if (event.changed) { status = 'changed'; } @@ -160,7 +160,7 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false, i18n }) { label={i18n._(t`Host Name`)} value={ - {hostStatus ? : null} + {hostStatus ? : null} {hostEvent.host_name} } diff --git a/awx/ui_next/src/screens/Job/JobOutput/HostEventModal.test.jsx b/awx/ui_next/src/screens/Job/JobOutput/HostEventModal.test.jsx index 716562ddb6..c67640d7ce 100644 --- a/awx/ui_next/src/screens/Job/JobOutput/HostEventModal.test.jsx +++ b/awx/ui_next/src/screens/Job/JobOutput/HostEventModal.test.jsx @@ -128,7 +128,7 @@ describe('HostEventModal', () => { isOpen /> ); - const icon = wrapper.find('HostStatusIcon'); + const icon = wrapper.find('StatusIcon'); expect(icon.prop('status')).toBe('ok'); expect(icon.find('StatusIcon__SuccessfulTop').length).toBe(1); expect(icon.find('StatusIcon__SuccessfulBottom').length).toBe(1); @@ -140,7 +140,7 @@ describe('HostEventModal', () => { {}} isOpen /> ); - const icon = wrapper.find('HostStatusIcon'); + const icon = wrapper.find('StatusIcon'); expect(icon.prop('status')).toBe('skipped'); expect(icon.find('StatusIcon__SkippedTop').length).toBe(1); expect(icon.find('StatusIcon__SkippedBottom').length).toBe(1); @@ -160,7 +160,7 @@ describe('HostEventModal', () => { /> ); - const icon = wrapper.find('HostStatusIcon'); + const icon = wrapper.find('StatusIcon'); expect(icon.prop('status')).toBe('unreachable'); expect(icon.find('StatusIcon__UnreachableTop').length).toBe(1); expect(icon.find('StatusIcon__UnreachableBottom').length).toBe(1); @@ -181,7 +181,7 @@ describe('HostEventModal', () => { /> ); - const icon = wrapper.find('HostStatusIcon'); + const icon = wrapper.find('StatusIcon'); expect(icon.prop('status')).toBe('failed'); expect(icon.find('StatusIcon__FailedTop').length).toBe(1); expect(icon.find('StatusIcon__FailedBottom').length).toBe(1);