JobOutput: extract helper funcs into separate file

This commit is contained in:
Keith J. Grant 2021-08-12 14:30:35 -07:00
parent 5473e54219
commit 949c2b92af
2 changed files with 108 additions and 102 deletions

View File

@ -9,9 +9,6 @@ import {
InfiniteLoader,
List,
} from 'react-virtualized';
import Ansi from 'ansi-to-html';
import hasAnsi from 'has-ansi';
import { encode } from 'html-entities';
import { Button } from '@patternfly/react-core';
import AlertModal from 'components/AlertModal';
@ -33,110 +30,12 @@ import HostEventModal from './HostEventModal';
import JobOutputSearch from './JobOutputSearch';
import { HostStatusBar, OutputToolbar } from './shared';
import getRowRangePageSize from './shared/jobOutputUtils';
import getLineTextHtml from './getLineTextHtml';
const QS_CONFIG = getQSConfig('job_output', {
order_by: 'counter',
});
const EVENT_START_TASK = 'playbook_on_task_start';
const EVENT_START_PLAY = 'playbook_on_play_start';
const EVENT_STATS_PLAY = 'playbook_on_stats';
const TIME_EVENTS = [EVENT_START_TASK, EVENT_START_PLAY, EVENT_STATS_PLAY];
const ansi = new Ansi({
stream: true,
colors: {
0: '#000',
1: '#A30000',
2: '#486B00',
3: '#795600',
4: '#00A',
5: '#A0A',
6: '#004368',
7: '#AAA',
8: '#555',
9: '#F55',
10: '#5F5',
11: '#FF5',
12: '#55F',
13: '#F5F',
14: '#5FF',
15: '#FFF',
},
});
function getTimestamp({ created }) {
const date = new Date(created);
const dateHours = date.getHours();
const dateMinutes = date.getMinutes();
const dateSeconds = date.getSeconds();
const stampHours = dateHours < 10 ? `0${dateHours}` : dateHours;
const stampMinutes = dateMinutes < 10 ? `0${dateMinutes}` : dateMinutes;
const stampSeconds = dateSeconds < 10 ? `0${dateSeconds}` : dateSeconds;
return `${stampHours}:${stampMinutes}:${stampSeconds}`;
}
const styleAttrPattern = new RegExp('style="[^"]*"', 'g');
function createStyleAttrHash(styleAttr) {
let hash = 0;
for (let i = 0; i < styleAttr.length; i++) {
hash = (hash << 5) - hash; // eslint-disable-line no-bitwise
hash += styleAttr.charCodeAt(i);
hash &= hash; // eslint-disable-line no-bitwise
}
return `${hash}`;
}
function replaceStyleAttrs(html) {
const allStyleAttrs = [...new Set(html.match(styleAttrPattern))];
const cssMap = {};
let result = html;
for (let i = 0; i < allStyleAttrs.length; i++) {
const styleAttr = allStyleAttrs[i];
const cssClassName = `output-${createStyleAttrHash(styleAttr)}`;
cssMap[cssClassName] = styleAttr.replace('style="', '').slice(0, -1);
result = result.split(styleAttr).join(`class="${cssClassName}"`);
}
return { cssMap, result };
}
function getLineTextHtml({ created, event, start_line, stdout }) {
const sanitized = encode(stdout);
let lineCssMap = {};
const lineTextHtml = [];
sanitized.split('\r\n').forEach((lineText, index) => {
let html;
if (hasAnsi(lineText)) {
const { cssMap, result } = replaceStyleAttrs(ansi.toHtml(lineText));
html = result;
lineCssMap = { ...lineCssMap, ...cssMap };
} else {
html = lineText;
}
if (index === 1 && TIME_EVENTS.includes(event)) {
const time = getTimestamp({ created });
html += `<span class="time">${time}</span>`;
}
lineTextHtml.push({
lineNumber: start_line + index,
html,
});
});
return {
lineCssMap,
lineTextHtml,
};
}
const CardBody = styled(_CardBody)`
display: flex;
flex-flow: column;

View File

@ -0,0 +1,107 @@
import Ansi from 'ansi-to-html';
import hasAnsi from 'has-ansi';
import { encode } from 'html-entities';
const EVENT_START_TASK = 'playbook_on_task_start';
const EVENT_START_PLAY = 'playbook_on_play_start';
const EVENT_STATS_PLAY = 'playbook_on_stats';
const TIME_EVENTS = [EVENT_START_TASK, EVENT_START_PLAY, EVENT_STATS_PLAY];
const ansi = new Ansi({
stream: true,
colors: {
0: '#000',
1: '#A30000',
2: '#486B00',
3: '#795600',
4: '#00A',
5: '#A0A',
6: '#004368',
7: '#AAA',
8: '#555',
9: '#F55',
10: '#5F5',
11: '#FF5',
12: '#55F',
13: '#F5F',
14: '#5FF',
15: '#FFF',
},
});
function getTimestamp({ created }) {
const date = new Date(created);
const dateHours = date.getHours();
const dateMinutes = date.getMinutes();
const dateSeconds = date.getSeconds();
const stampHours = dateHours < 10 ? `0${dateHours}` : dateHours;
const stampMinutes = dateMinutes < 10 ? `0${dateMinutes}` : dateMinutes;
const stampSeconds = dateSeconds < 10 ? `0${dateSeconds}` : dateSeconds;
return `${stampHours}:${stampMinutes}:${stampSeconds}`;
}
function createStyleAttrHash(styleAttr) {
let hash = 0;
for (let i = 0; i < styleAttr.length; i++) {
hash = (hash << 5) - hash; // eslint-disable-line no-bitwise
hash += styleAttr.charCodeAt(i);
hash &= hash; // eslint-disable-line no-bitwise
}
return `${hash}`;
}
const styleAttrPattern = new RegExp('style="[^"]*"', 'g');
function replaceStyleAttrs(html) {
const allStyleAttrs = [...new Set(html.match(styleAttrPattern))];
const cssMap = {};
let result = html;
for (let i = 0; i < allStyleAttrs.length; i++) {
const styleAttr = allStyleAttrs[i];
const cssClassName = `output-${createStyleAttrHash(styleAttr)}`;
cssMap[cssClassName] = styleAttr.replace('style="', '').slice(0, -1);
result = result.split(styleAttr).join(`class="${cssClassName}"`);
}
return { cssMap, result };
}
export default function getLineTextHtml({
created,
event,
start_line,
stdout,
}) {
const sanitized = encode(stdout);
let lineCssMap = {};
const lineTextHtml = [];
sanitized.split('\r\n').forEach((lineText, index) => {
let html;
if (hasAnsi(lineText)) {
const { cssMap, result } = replaceStyleAttrs(ansi.toHtml(lineText));
html = result;
lineCssMap = { ...lineCssMap, ...cssMap };
} else {
html = lineText;
}
if (index === 1 && TIME_EVENTS.includes(event)) {
const time = getTimestamp({ created });
html += `<span class="time">${time}</span>`;
}
lineTextHtml.push({
lineNumber: start_line + index,
html,
});
});
return {
lineCssMap,
lineTextHtml,
};
}