mirror of https://github.com/grafana/grafana
Merge pull request #15305 from avaly/feature/ansi-colors
Support ANSI colors codes in Loki logspull/15294/head^2
commit
2c92365969
@ -0,0 +1,24 @@ |
||||
import React from 'react'; |
||||
import { shallow } from 'enzyme'; |
||||
|
||||
import { LogMessageAnsi } from './LogMessageAnsi'; |
||||
|
||||
describe('<LogMessageAnsi />', () => { |
||||
it('renders string without ANSI codes', () => { |
||||
const wrapper = shallow(<LogMessageAnsi value="Lorem ipsum" />); |
||||
|
||||
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} />); |
||||
|
||||
expect(wrapper.find('span')).toHaveLength(1); |
||||
expect(wrapper.find('span').first().prop('style')).toMatchObject(expect.objectContaining({ |
||||
color: expect.any(String) |
||||
})); |
||||
expect(wrapper.find('span').first().text()).toBe('ipsum'); |
||||
}); |
||||
}); |
@ -0,0 +1,70 @@ |
||||
import React, { PureComponent } from 'react'; |
||||
import ansicolor from 'ansicolor'; |
||||
|
||||
interface Style { |
||||
[key: string]: string; |
||||
} |
||||
|
||||
interface ParsedChunk { |
||||
style: Style; |
||||
text: string; |
||||
} |
||||
|
||||
function convertCSSToStyle(css: string): Style { |
||||
return css.split(/;\s*/).reduce((accumulated, line) => { |
||||
const match = line.match(/([^:\s]+)\s*:\s*(.+)/); |
||||
|
||||
if (match && match[1] && match[2]) { |
||||
const key = match[1].replace(/-(a-z)/g, (_, character) => character.toUpperCase()); |
||||
accumulated[key] = match[2]; |
||||
} |
||||
|
||||
return accumulated; |
||||
}, {}); |
||||
} |
||||
|
||||
interface Props { |
||||
value: string; |
||||
} |
||||
|
||||
interface State { |
||||
chunks: ParsedChunk[]; |
||||
prevValue: string; |
||||
} |
||||
|
||||
export class LogMessageAnsi extends PureComponent<Props, State> { |
||||
state = { |
||||
chunks: [], |
||||
prevValue: '', |
||||
}; |
||||
|
||||
static getDerivedStateFromProps(props, state) { |
||||
if (props.value === state.prevValue) { |
||||
return null; |
||||
} |
||||
|
||||
const parsed = ansicolor.parse(props.value); |
||||
|
||||
return { |
||||
chunks: parsed.spans.map((span) => { |
||||
return span.css ? |
||||
{ |
||||
style: convertCSSToStyle(span.css), |
||||
text: span.text |
||||
} : |
||||
{ text: span.text }; |
||||
}), |
||||
prevValue: props.value |
||||
}; |
||||
} |
||||
|
||||
render() { |
||||
const { chunks } = this.state; |
||||
|
||||
return chunks.map( |
||||
(chunk, index) => chunk.style ? |
||||
<span key={index} style={chunk.style}>{chunk.text}</span> : |
||||
chunk.text |
||||
); |
||||
} |
||||
} |
Loading…
Reference in new issue