diff --git a/awx/ui_next/src/screens/Job/JobOutput/JobEvent.jsx b/awx/ui_next/src/screens/Job/JobOutput/JobEvent.jsx index 83ab56c811..4e41d50a90 100644 --- a/awx/ui_next/src/screens/Job/JobOutput/JobEvent.jsx +++ b/awx/ui_next/src/screens/Job/JobOutput/JobEvent.jsx @@ -1,8 +1,13 @@ import Ansi from 'ansi-to-html'; import hasAnsi from 'has-ansi'; import Entities from 'html-entities'; -import styled from 'styled-components'; import React from 'react'; +import { + JobEventLine, + JobEventLineToggle, + JobEventLineNumber, + JobEventLineText, +} from './shared'; const EVENT_START_TASK = 'playbook_on_task_start'; const EVENT_START_PLAY = 'playbook_on_play_start'; @@ -32,65 +37,6 @@ const ansi = new Ansi({ }); const entities = new Entities.AllHtmlEntities(); -const JobEventWrapper = styled.div``; -const JobEventLine = styled.div` - display: flex; - - &:hover { - background-color: white; - } - - &:hover div { - background-color: white; - } - - &--hidden { - display: none; - } - ${({ isFirst }) => (isFirst ? 'padding-top: 10px;' : '')} -`; -const JobEventLineToggle = styled.div` - background-color: #ebebeb; - color: #646972; - display: flex; - flex: 0 0 30px; - font-size: 18px; - justify-content: center; - line-height: 12px; - - & > i { - cursor: pointer; - } - - user-select: none; -`; -const JobEventLineNumber = styled.div` - color: #161b1f; - background-color: #ebebeb; - flex: 0 0 45px; - text-align: right; - vertical-align: top; - padding-right: 5px; - border-right: 1px solid #d7d7d7; - user-select: none; -`; -const JobEventLineText = styled.div` - padding: 0 15px; - white-space: pre-wrap; - word-break: break-all; - word-wrap: break-word; - - .time { - font-size: 14px; - font-weight: 600; - user-select: none; - background-color: #ebebeb; - border-radius: 12px; - padding: 2px 10px; - margin-left: 15px; - } -`; - function getTimestamp({ created }) { const date = new Date(created); @@ -127,9 +73,17 @@ function getLineTextHtml({ created, event, start_line, stdout }) { }); } -function JobEvent({ counter, created, event, stdout, start_line, ...rest }) { +function JobEvent({ + counter, + created, + event, + stdout, + start_line, + style, + type, +}) { return !stdout ? null : ( - +
{getLineTextHtml({ created, event, start_line, stdout }).map( ({ lineNumber, html }) => lineNumber >= 0 && ( @@ -148,7 +102,7 @@ function JobEvent({ counter, created, event, stdout, start_line, ...rest }) { ) )} - +
); } diff --git a/awx/ui_next/src/screens/Job/JobOutput/JobEvent.test.jsx b/awx/ui_next/src/screens/Job/JobOutput/JobEvent.test.jsx index 5377edbc58..5ea70b8e47 100644 --- a/awx/ui_next/src/screens/Job/JobOutput/JobEvent.test.jsx +++ b/awx/ui_next/src/screens/Job/JobOutput/JobEvent.test.jsx @@ -21,7 +21,7 @@ const mockRunnerOnOkEvent = { stdout: '\u001b[0;32mok: [localhost]\u001b[0m', }; const selectors = { - lineText: 'JobEvent__JobEventLineText', + lineText: 'JobEventLineText', }; describe('', () => { diff --git a/awx/ui_next/src/screens/Job/JobOutput/JobEventSkeleton.jsx b/awx/ui_next/src/screens/Job/JobOutput/JobEventSkeleton.jsx index 6eead9c4b0..1cae0c74df 100644 --- a/awx/ui_next/src/screens/Job/JobOutput/JobEventSkeleton.jsx +++ b/awx/ui_next/src/screens/Job/JobOutput/JobEventSkeleton.jsx @@ -1,83 +1,29 @@ -import styled from 'styled-components'; import React from 'react'; - -const JobEventSkeletonWrapper = styled.div``; -const JobEventSkeletonLine = styled.div` - display: flex; - - &:hover { - background-color: white; - } - - &:hover div { - background-color: white; - } - - &--hidden { - display: none; - } -`; -const JobEventSkeletonLineToggle = styled.div` - background-color: #ebebeb; - color: #646972; - display: flex; - flex: 0 0 30px; - font-size: 18px; - justify-content: center; - line-height: 12px; - - & > i { - cursor: pointer; - } - - user-select: none; -`; -const JobEventSkeletonLineNumber = styled.div` - color: #161b1f; - background-color: #ebebeb; - flex: 0 0 45px; - text-align: right; - vertical-align: top; - padding-right: 5px; - border-right: 1px solid #b7b7b7; - user-select: none; -`; -const JobEventSkeletonContentWrapper = styled.div` - padding: 0 15px; - white-space: pre-wrap; - word-break: break-all; - word-wrap: break-word; - - .content { - background: var(--pf-global--disabled-color--200); - background: linear-gradient( - to right, - #f5f5f5 10%, - #e8e8e8 18%, - #f5f5f5 33% - ); - border-radius: 5px; - } -`; +import { + JobEventLine, + JobEventLineToggle, + JobEventLineNumber, + JobEventLineText, +} from './shared'; function JobEventSkeletonContent({ contentLength }) { return ( - + {' '.repeat(contentLength)} - + ); } -function JobEventSkeleton({ counter, contentLength, ...rest }) { +function JobEventSkeleton({ counter, contentLength, style }) { return ( counter > 1 && ( - - - - +
+ + + - - + +
) ); } diff --git a/awx/ui_next/src/screens/Job/JobOutput/JobOutput.jsx b/awx/ui_next/src/screens/Job/JobOutput/JobOutput.jsx index 088f64b0ff..18508c1372 100644 --- a/awx/ui_next/src/screens/Job/JobOutput/JobOutput.jsx +++ b/awx/ui_next/src/screens/Job/JobOutput/JobOutput.jsx @@ -66,6 +66,7 @@ class JobOutput extends Component { defaultHeight: 25, }); + this._isMounted = false; this.loadJobEvents = this.loadJobEvents.bind(this); this.rowRenderer = this.rowRenderer.bind(this); this.handleScrollFirst = this.handleScrollFirst.bind(this); @@ -79,6 +80,7 @@ class JobOutput extends Component { } componentDidMount() { + this._isMounted = true; this.loadJobEvents(); } @@ -100,14 +102,19 @@ class JobOutput extends Component { } } + componentWillUnmount() { + this._isMounted = false; + } + async loadJobEvents() { const { job } = this.props; const loadRange = range(1, 50); - this.setState(({ currentlyLoading }) => ({ - hasContentLoading: true, - currentlyLoading: currentlyLoading.concat(loadRange), - })); + this._isMounted && + this.setState(({ currentlyLoading }) => ({ + hasContentLoading: true, + currentlyLoading: currentlyLoading.concat(loadRange), + })); try { const { data: { results: newResults = [], count }, @@ -115,19 +122,23 @@ class JobOutput extends Component { page_size: 50, order_by: 'start_line', }); - this.setState(({ results }) => { - newResults.forEach(jobEvent => { - results[jobEvent.counter] = jobEvent; + this._isMounted && + this.setState(({ results }) => { + newResults.forEach(jobEvent => { + results[jobEvent.counter] = jobEvent; + }); + return { results, remoteRowCount: count + 1 }; }); - return { results, remoteRowCount: count + 1 }; - }); } catch (err) { this.setState({ contentError: err }); } finally { - this.setState(({ currentlyLoading }) => ({ - hasContentLoading: false, - currentlyLoading: currentlyLoading.filter(n => !loadRange.includes(n)), - })); + this._isMounted && + this.setState(({ currentlyLoading }) => ({ + hasContentLoading: false, + currentlyLoading: currentlyLoading.filter( + n => !loadRange.includes(n) + ), + })); } } @@ -170,9 +181,10 @@ class JobOutput extends Component { const { job } = this.props; const loadRange = range(startIndex, stopIndex); - this.setState(({ currentlyLoading }) => ({ - currentlyLoading: currentlyLoading.concat(loadRange), - })); + this._isMounted && + this.setState(({ currentlyLoading }) => ({ + currentlyLoading: currentlyLoading.concat(loadRange), + })); const params = { counter__gte: startIndex, counter__lte: stopIndex, @@ -180,17 +192,18 @@ class JobOutput extends Component { }; return JobsAPI.readEvents(job.id, job.type, params).then(response => { - this.setState(({ results, currentlyLoading }) => { - response.data.results.forEach(jobEvent => { - results[jobEvent.counter] = jobEvent; + this._isMounted && + this.setState(({ results, currentlyLoading }) => { + response.data.results.forEach(jobEvent => { + results[jobEvent.counter] = jobEvent; + }); + return { + results, + currentlyLoading: currentlyLoading.filter( + n => !loadRange.includes(n) + ), + }; }); - return { - results, - currentlyLoading: currentlyLoading.filter( - n => !loadRange.includes(n) - ), - }; - }); }); } diff --git a/awx/ui_next/src/screens/Job/JobOutput/shared/JobEventLine.jsx b/awx/ui_next/src/screens/Job/JobOutput/shared/JobEventLine.jsx new file mode 100644 index 0000000000..5f48f8ad0a --- /dev/null +++ b/awx/ui_next/src/screens/Job/JobOutput/shared/JobEventLine.jsx @@ -0,0 +1,18 @@ +import styled from 'styled-components'; + +export default styled.div` + display: flex; + + &:hover { + background-color: white; + } + + &:hover div { + background-color: white; + } + + &--hidden { + display: none; + } + ${({ isFirst }) => (isFirst ? 'padding-top: 10px;' : '')} +`; diff --git a/awx/ui_next/src/screens/Job/JobOutput/shared/JobEventLineNumber.jsx b/awx/ui_next/src/screens/Job/JobOutput/shared/JobEventLineNumber.jsx new file mode 100644 index 0000000000..52b3c4b670 --- /dev/null +++ b/awx/ui_next/src/screens/Job/JobOutput/shared/JobEventLineNumber.jsx @@ -0,0 +1,12 @@ +import styled from 'styled-components'; + +export default styled.div` + color: #161b1f; + background-color: #ebebeb; + flex: 0 0 45px; + text-align: right; + vertical-align: top; + padding-right: 5px; + border-right: 1px solid #d7d7d7; + user-select: none; +`; diff --git a/awx/ui_next/src/screens/Job/JobOutput/shared/JobEventLineText.jsx b/awx/ui_next/src/screens/Job/JobOutput/shared/JobEventLineText.jsx new file mode 100644 index 0000000000..71f80a3134 --- /dev/null +++ b/awx/ui_next/src/screens/Job/JobOutput/shared/JobEventLineText.jsx @@ -0,0 +1,29 @@ +import styled from 'styled-components'; + +export default styled.div` + padding: 0 15px; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; + + .time { + font-size: 14px; + font-weight: 600; + user-select: none; + background-color: #ebebeb; + border-radius: 12px; + padding: 2px 10px; + margin-left: 15px; + } + + .content { + background: var(--pf-global--disabled-color--200); + background: linear-gradient( + to right, + #f5f5f5 10%, + #e8e8e8 18%, + #f5f5f5 33% + ); + border-radius: 5px; + } +`; diff --git a/awx/ui_next/src/screens/Job/JobOutput/shared/JobEventLineToggle.jsx b/awx/ui_next/src/screens/Job/JobOutput/shared/JobEventLineToggle.jsx new file mode 100644 index 0000000000..45ee8ffc94 --- /dev/null +++ b/awx/ui_next/src/screens/Job/JobOutput/shared/JobEventLineToggle.jsx @@ -0,0 +1,17 @@ +import styled from 'styled-components'; + +export default styled.div` + background-color: #ebebeb; + color: #646972; + display: flex; + flex: 0 0 30px; + font-size: 18px; + justify-content: center; + line-height: 12px; + + & > i { + cursor: pointer; + } + + user-select: none; +`; diff --git a/awx/ui_next/src/screens/Job/JobOutput/shared/index.jsx b/awx/ui_next/src/screens/Job/JobOutput/shared/index.jsx new file mode 100644 index 0000000000..d0edeb8e1f --- /dev/null +++ b/awx/ui_next/src/screens/Job/JobOutput/shared/index.jsx @@ -0,0 +1,4 @@ +export { default as JobEventLine } from './JobEventLine'; +export { default as JobEventLineToggle } from './JobEventLineToggle'; +export { default as JobEventLineNumber } from './JobEventLineNumber'; +export { default as JobEventLineText } from './JobEventLineText';