mirror of
https://github.com/ansible/awx.git
synced 2026-02-17 03:00:04 -03:30
Move job event line styles into a shared dir
Set a field to avoid setState warnings Fix lint errors
This commit is contained in:
@@ -1,8 +1,13 @@
|
|||||||
import Ansi from 'ansi-to-html';
|
import Ansi from 'ansi-to-html';
|
||||||
import hasAnsi from 'has-ansi';
|
import hasAnsi from 'has-ansi';
|
||||||
import Entities from 'html-entities';
|
import Entities from 'html-entities';
|
||||||
import styled from 'styled-components';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
JobEventLine,
|
||||||
|
JobEventLineToggle,
|
||||||
|
JobEventLineNumber,
|
||||||
|
JobEventLineText,
|
||||||
|
} from './shared';
|
||||||
|
|
||||||
const EVENT_START_TASK = 'playbook_on_task_start';
|
const EVENT_START_TASK = 'playbook_on_task_start';
|
||||||
const EVENT_START_PLAY = 'playbook_on_play_start';
|
const EVENT_START_PLAY = 'playbook_on_play_start';
|
||||||
@@ -32,65 +37,6 @@ const ansi = new Ansi({
|
|||||||
});
|
});
|
||||||
const entities = new Entities.AllHtmlEntities();
|
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 }) {
|
function getTimestamp({ created }) {
|
||||||
const date = new Date(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 : (
|
return !stdout ? null : (
|
||||||
<JobEventWrapper {...rest}>
|
<div style={style} type={type}>
|
||||||
{getLineTextHtml({ created, event, start_line, stdout }).map(
|
{getLineTextHtml({ created, event, start_line, stdout }).map(
|
||||||
({ lineNumber, html }) =>
|
({ lineNumber, html }) =>
|
||||||
lineNumber >= 0 && (
|
lineNumber >= 0 && (
|
||||||
@@ -148,7 +102,7 @@ function JobEvent({ counter, created, event, stdout, start_line, ...rest }) {
|
|||||||
</JobEventLine>
|
</JobEventLine>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</JobEventWrapper>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const mockRunnerOnOkEvent = {
|
|||||||
stdout: '\u001b[0;32mok: [localhost]\u001b[0m',
|
stdout: '\u001b[0;32mok: [localhost]\u001b[0m',
|
||||||
};
|
};
|
||||||
const selectors = {
|
const selectors = {
|
||||||
lineText: 'JobEvent__JobEventLineText',
|
lineText: 'JobEventLineText',
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('<JobEvent />', () => {
|
describe('<JobEvent />', () => {
|
||||||
|
|||||||
@@ -1,83 +1,29 @@
|
|||||||
import styled from 'styled-components';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {
|
||||||
const JobEventSkeletonWrapper = styled.div``;
|
JobEventLine,
|
||||||
const JobEventSkeletonLine = styled.div`
|
JobEventLineToggle,
|
||||||
display: flex;
|
JobEventLineNumber,
|
||||||
|
JobEventLineText,
|
||||||
&:hover {
|
} from './shared';
|
||||||
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;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
function JobEventSkeletonContent({ contentLength }) {
|
function JobEventSkeletonContent({ contentLength }) {
|
||||||
return (
|
return (
|
||||||
<JobEventSkeletonContentWrapper>
|
<JobEventLineText>
|
||||||
<span className="content">{' '.repeat(contentLength)}</span>
|
<span className="content">{' '.repeat(contentLength)}</span>
|
||||||
</JobEventSkeletonContentWrapper>
|
</JobEventLineText>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function JobEventSkeleton({ counter, contentLength, ...rest }) {
|
function JobEventSkeleton({ counter, contentLength, style }) {
|
||||||
return (
|
return (
|
||||||
counter > 1 && (
|
counter > 1 && (
|
||||||
<JobEventSkeletonWrapper {...rest}>
|
<div style={style}>
|
||||||
<JobEventSkeletonLine key={counter}>
|
<JobEventLine key={counter}>
|
||||||
<JobEventSkeletonLineToggle />
|
<JobEventLineToggle />
|
||||||
<JobEventSkeletonLineNumber />
|
<JobEventLineNumber />
|
||||||
<JobEventSkeletonContent contentLength={contentLength} />
|
<JobEventSkeletonContent contentLength={contentLength} />
|
||||||
</JobEventSkeletonLine>
|
</JobEventLine>
|
||||||
</JobEventSkeletonWrapper>
|
</div>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class JobOutput extends Component {
|
|||||||
defaultHeight: 25,
|
defaultHeight: 25,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._isMounted = false;
|
||||||
this.loadJobEvents = this.loadJobEvents.bind(this);
|
this.loadJobEvents = this.loadJobEvents.bind(this);
|
||||||
this.rowRenderer = this.rowRenderer.bind(this);
|
this.rowRenderer = this.rowRenderer.bind(this);
|
||||||
this.handleScrollFirst = this.handleScrollFirst.bind(this);
|
this.handleScrollFirst = this.handleScrollFirst.bind(this);
|
||||||
@@ -79,6 +80,7 @@ class JobOutput extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
this._isMounted = true;
|
||||||
this.loadJobEvents();
|
this.loadJobEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,14 +102,19 @@ class JobOutput extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this._isMounted = false;
|
||||||
|
}
|
||||||
|
|
||||||
async loadJobEvents() {
|
async loadJobEvents() {
|
||||||
const { job } = this.props;
|
const { job } = this.props;
|
||||||
|
|
||||||
const loadRange = range(1, 50);
|
const loadRange = range(1, 50);
|
||||||
this.setState(({ currentlyLoading }) => ({
|
this._isMounted &&
|
||||||
hasContentLoading: true,
|
this.setState(({ currentlyLoading }) => ({
|
||||||
currentlyLoading: currentlyLoading.concat(loadRange),
|
hasContentLoading: true,
|
||||||
}));
|
currentlyLoading: currentlyLoading.concat(loadRange),
|
||||||
|
}));
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
data: { results: newResults = [], count },
|
data: { results: newResults = [], count },
|
||||||
@@ -115,19 +122,23 @@ class JobOutput extends Component {
|
|||||||
page_size: 50,
|
page_size: 50,
|
||||||
order_by: 'start_line',
|
order_by: 'start_line',
|
||||||
});
|
});
|
||||||
this.setState(({ results }) => {
|
this._isMounted &&
|
||||||
newResults.forEach(jobEvent => {
|
this.setState(({ results }) => {
|
||||||
results[jobEvent.counter] = jobEvent;
|
newResults.forEach(jobEvent => {
|
||||||
|
results[jobEvent.counter] = jobEvent;
|
||||||
|
});
|
||||||
|
return { results, remoteRowCount: count + 1 };
|
||||||
});
|
});
|
||||||
return { results, remoteRowCount: count + 1 };
|
|
||||||
});
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.setState({ contentError: err });
|
this.setState({ contentError: err });
|
||||||
} finally {
|
} finally {
|
||||||
this.setState(({ currentlyLoading }) => ({
|
this._isMounted &&
|
||||||
hasContentLoading: false,
|
this.setState(({ currentlyLoading }) => ({
|
||||||
currentlyLoading: currentlyLoading.filter(n => !loadRange.includes(n)),
|
hasContentLoading: false,
|
||||||
}));
|
currentlyLoading: currentlyLoading.filter(
|
||||||
|
n => !loadRange.includes(n)
|
||||||
|
),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,9 +181,10 @@ class JobOutput extends Component {
|
|||||||
const { job } = this.props;
|
const { job } = this.props;
|
||||||
|
|
||||||
const loadRange = range(startIndex, stopIndex);
|
const loadRange = range(startIndex, stopIndex);
|
||||||
this.setState(({ currentlyLoading }) => ({
|
this._isMounted &&
|
||||||
currentlyLoading: currentlyLoading.concat(loadRange),
|
this.setState(({ currentlyLoading }) => ({
|
||||||
}));
|
currentlyLoading: currentlyLoading.concat(loadRange),
|
||||||
|
}));
|
||||||
const params = {
|
const params = {
|
||||||
counter__gte: startIndex,
|
counter__gte: startIndex,
|
||||||
counter__lte: stopIndex,
|
counter__lte: stopIndex,
|
||||||
@@ -180,17 +192,18 @@ class JobOutput extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return JobsAPI.readEvents(job.id, job.type, params).then(response => {
|
return JobsAPI.readEvents(job.id, job.type, params).then(response => {
|
||||||
this.setState(({ results, currentlyLoading }) => {
|
this._isMounted &&
|
||||||
response.data.results.forEach(jobEvent => {
|
this.setState(({ results, currentlyLoading }) => {
|
||||||
results[jobEvent.counter] = jobEvent;
|
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)
|
|
||||||
),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;' : '')}
|
||||||
|
`;
|
||||||
@@ -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;
|
||||||
|
`;
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -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;
|
||||||
|
`;
|
||||||
4
awx/ui_next/src/screens/Job/JobOutput/shared/index.jsx
Normal file
4
awx/ui_next/src/screens/Job/JobOutput/shared/index.jsx
Normal file
@@ -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';
|
||||||
Reference in New Issue
Block a user