Explore: Fix ANSI dim style being unreadable in dark mode (#41226)

* Explore: Fix ANSI dim style being unreadable in dark mode

* use GrafanaTheme2 instead of opacity

* tweak code and comment

* fix existing tests and add new test for ANSI dim code

* fix failing test
This commit is contained in:
Oliver Frye 2021-12-03 21:35:16 +10:00 committed by GitHub
parent f30debf7ad
commit 32f2a75c44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 15 deletions

View File

@ -1,19 +1,18 @@
import React from 'react';
import { createTheme } from '@grafana/data';
import { shallow } from 'enzyme';
import { LogMessageAnsi } from './LogMessageAnsi';
import React from 'react';
import { UnThemedLogMessageAnsi as LogMessageAnsi } from './LogMessageAnsi';
describe('<LogMessageAnsi />', () => {
it('renders string without ANSI codes', () => {
const wrapper = shallow(<LogMessageAnsi value="Lorem ipsum" />);
const wrapper = shallow(<LogMessageAnsi value="Lorem ipsum" theme={createTheme()} />);
expect(wrapper.find('span').exists()).toBe(false);
expect(wrapper.text()).toBe('Lorem ipsum');
});
it('renders string with ANSI codes', () => {
const value = 'Lorem \u001B[31mipsum\u001B[0m et dolor';
const wrapper = shallow(<LogMessageAnsi value={value} />);
const wrapper = shallow(<LogMessageAnsi value={value} theme={createTheme()} />);
expect(wrapper.find('span')).toHaveLength(1);
expect(wrapper.find('span').first().prop('style')).toMatchObject(
@ -24,8 +23,8 @@ describe('<LogMessageAnsi />', () => {
expect(wrapper.find('span').first().text()).toBe('ipsum');
});
it('renders string with ANSI codes with correctly converted css classnames', () => {
const value = 'Lorem Ipsum';
const wrapper = shallow(<LogMessageAnsi value={value} />);
const value = 'Lorem \u001B[1;32mIpsum';
const wrapper = shallow(<LogMessageAnsi value={value} theme={createTheme()} />);
expect(wrapper.find('span')).toHaveLength(1);
expect(wrapper.find('span').first().prop('style')).toMatchObject(
@ -34,4 +33,16 @@ describe('<LogMessageAnsi />', () => {
})
);
});
it('renders string with ANSI dim code with appropriate themed color', () => {
const value = 'Lorem \u001B[1;2mIpsum';
const theme = createTheme();
const wrapper = shallow(<LogMessageAnsi value={value} theme={theme} />);
expect(wrapper.find('span')).toHaveLength(1);
expect(wrapper.find('span').first().prop('style')).toMatchObject(
expect.objectContaining({
color: theme.colors.text.secondary,
})
);
});
});

View File

@ -1,8 +1,10 @@
import { findHighlightChunksInText } from '@grafana/data';
import { findHighlightChunksInText, GrafanaTheme2 } from '@grafana/data';
import ansicolor from 'ansicolor';
import React, { PureComponent } from 'react';
// @ts-ignore
import Highlighter from 'react-highlight-words';
import { withTheme2 } from '../../themes';
import { Themeable2 } from '../../types';
interface Style {
[key: string]: string;
@ -13,13 +15,19 @@ interface ParsedChunk {
text: string;
}
function convertCSSToStyle(css: string): Style {
return css.split(/;\s*/).reduce((accumulated, line) => {
function convertCSSToStyle(theme: GrafanaTheme2, css: string): Style {
return css.split(/;\s*/).reduce<Style>((accumulated, line) => {
// The ansicolor package returns this color if the chunk has the ANSI dim
// style (`\e[2m`), but it is nearly unreadable in the dark theme, so we use
// GrafanaTheme2 instead to style it in a way that works across all themes.
if (line === 'color:rgba(0,0,0,0.5)') {
return { color: theme.colors.text.secondary };
}
const match = line.match(/([^:\s]+)\s*:\s*(.+)/);
if (match && match[1] && match[2]) {
const key = match[1].replace(/-([a-z])/g, (_, character) => character.toUpperCase());
// @ts-ignore
accumulated[key] = match[2];
}
@ -27,7 +35,7 @@ function convertCSSToStyle(css: string): Style {
}, {});
}
interface Props {
interface Props extends Themeable2 {
value: string;
highlight?: {
searchWords: string[];
@ -40,7 +48,7 @@ interface State {
prevValue: string;
}
export class LogMessageAnsi extends PureComponent<Props, State> {
export class UnThemedLogMessageAnsi extends PureComponent<Props, State> {
state: State = {
chunks: [],
prevValue: '',
@ -57,7 +65,7 @@ export class LogMessageAnsi extends PureComponent<Props, State> {
chunks: parsed.spans.map((span) => {
return span.css
? {
style: convertCSSToStyle(span.css),
style: convertCSSToStyle(props.theme, span.css),
text: span.text,
}
: { text: span.text };
@ -90,3 +98,6 @@ export class LogMessageAnsi extends PureComponent<Props, State> {
});
}
}
export const LogMessageAnsi = withTheme2(UnThemedLogMessageAnsi);
LogMessageAnsi.displayName = 'LogMessageAnsi';