Conditionally render ANSI console text with a black background

We render ANSI colors in 3 places:
* Streaming console
* Build task summary tab
* Build console tab

(We do not render ANSI colors in the Build log tab.)

In the streaming console, the default color scheme is white-on-black
which is probably what most devs expect when they render color output.
The other two locations maintain the black-on-white Patternfly default
scheme.  This means that some colors (eg yellow) are difficult to read.

In order to accommodate cases where ANSI colors are used, the
color scheme of the preformatted sections in the Build task summary or
Build console tabs is changed to white on black iff an ANSI color
sequence is detected.  Otherwise, it remains the Patternfly default
of black on white.

Change-Id: If99d09f614c51495af4ee400891b9a8f2e217db8
This commit is contained in:
James E. Blair 2023-03-11 13:42:12 -08:00
parent bb01c1613f
commit 68d705bad8
2 changed files with 43 additions and 15 deletions

View File

@ -40,6 +40,9 @@ import {
TimesCircleIcon,
} from '@patternfly/react-icons'
const ANSI_REGEX = new RegExp('\x33[[0-9;]+m')
class BuildOutputLabel extends React.Component {
static propTypes = {
ok: PropTypes.number,
@ -109,11 +112,32 @@ class BuildOutput extends React.Component {
)
}
renderFailedTask (host, task) {
getLines(lines) {
const max_lines = 42
if (lines && lines.length > 0) {
return [
lines.slice(0, -max_lines).join('\n'),
lines.slice(-max_lines).join('\n')
]
}
return ['', '']
}
renderFailedTask (host, task) {
let zuulOutputClass = 'zuul-build-output'
if (this.props.preferences.darkMode) {
zuulOutputClass = 'zuul-build-output-dark'
zuulOutputClass = 'zuul-build-output-dark'
}
const [stdout_early_lines, stdout_late_lines] = this.getLines(task.stdout_lines)
const [stderr_early_lines, stderr_late_lines] = this.getLines(task.stderr_lines)
// If there is an ANSI color escape string, set a white-on-black
// color scheme so the output looks more like what we would expect in a console.
let term_style = {}
if (ANSI_REGEX.test(stdout_early_lines) ||
ANSI_REGEX.test(stdout_late_lines) ||
ANSI_REGEX.test(stderr_early_lines) ||
ANSI_REGEX.test(stderr_late_lines)) {
term_style = {backgroundColor: 'black', color: 'white'}
}
return (
<Card key={host + task.zuul_log_id} className="zuul-task-summary-failed" style={this.props.preferences.darkMode ? {background: 'var(--pf-global--BackgroundColor--300)'} : {}}>
@ -135,30 +159,30 @@ class BuildOutput extends React.Component {
{task.exception && (
<pre key="exc" style={{ color: 'red' }} title="exc" className={zuulOutputClass}>{task.exception}</pre>
)}
{task.stdout_lines && task.stdout_lines.length > 0 && (
{stdout_late_lines.length > 0 && (
<Fragment>
{task.stdout_lines.length > max_lines && (
{stdout_early_lines.length > 0 && (
<details className={`${'foldable'} ${'stdout'}`}><summary></summary>
<pre key="stdout" title="stdout" className={zuulOutputClass}>
<ReAnsi log={task.stdout_lines.slice(0, -max_lines).join('\n')} />
<pre key="stdout" title="stdout" className={zuulOutputClass} style={term_style}>
<ReAnsi log={stdout_early_lines} />
</pre>
</details>)}
<pre key="stdout" title="stdout" className={zuulOutputClass}>
<ReAnsi log={task.stdout_lines.slice(-max_lines).join('\n')} />
<pre key="stdout" title="stdout" className={zuulOutputClass} style={term_style}>
<ReAnsi log={stdout_late_lines} />
</pre>
</Fragment>
)}
{task.stderr_lines && task.stderr_lines.length > 0 && (
{stderr_late_lines.length > 0 && (
<Fragment>
{task.stderr_lines.length > max_lines && (
{stderr_early_lines.length > 0 && (
<details className={`${'foldable'} ${'stderr'}`}><summary></summary>
<pre key="stderr" title="stderr" className={zuulOutputClass}>
<ReAnsi log={task.stderr_lines.slice(0, -max_lines).join('\n')} />
<pre key="stderr" title="stderr" className={zuulOutputClass} style={term_style}>
<ReAnsi log={stderr_early_lines} />
</pre>
</details>
)}
<pre key="stderr" title="stderr" className={zuulOutputClass}>
<ReAnsi log={task.stderr_lines.slice(-max_lines).join('\n')} />
<pre key="stderr" title="stderr" className={zuulOutputClass} style={term_style}>
<ReAnsi log={stderr_late_lines} />
</pre>
</Fragment>
)}

View File

@ -55,6 +55,7 @@ import {
} from '../../actions/build'
const INTERESTING_KEYS = ['msg', 'cmd', 'stdout', 'stderr']
const ANSI_REGEX = new RegExp('\x33[[0-9;]+m')
class TaskOutput extends React.Component {
@ -119,8 +120,11 @@ class TaskOutput extends React.Component {
</pre>
)
} else if (typeof(value) === 'string') {
// If there is an ANSI color escape string, set a white-on-black
// color scheme so the output looks more like what we would expect in a console.
const style = ANSI_REGEX.test(value) ? {backgroundColor: 'black', color: 'white'} : {}
ret = (
<pre>
<pre style={style}>
<ReAnsi log={value} />
</pre>
)