[FieldFormatters] Allow boolean field to be colored (#203498)

## Summary

This PR allows for boolean type field to be colored. 

Closes: #195861
This commit is contained in:
Krzysztof Kowalczyk 2024-12-11 20:18:33 +01:00 committed by GitHub
parent 37e107e1dc
commit 52ee949f6f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 230 additions and 53 deletions

View file

@ -1,5 +1,99 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ColorFormatEditor should render boolean type normally 1`] = `
<Fragment>
<EuiBasicTable
columns={
Array [
Object {
"field": "boolean",
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Boolean"
id="indexPatternFieldEditor.color.booleanLabel"
/>,
"render": [Function],
},
Object {
"field": "text",
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Text color"
id="indexPatternFieldEditor.color.textColorLabel"
/>,
"render": [Function],
},
Object {
"field": "background",
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Background color"
id="indexPatternFieldEditor.color.backgroundLabel"
/>,
"render": [Function],
},
Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Example"
id="indexPatternFieldEditor.color.exampleLabel"
/>,
"render": [Function],
},
Object {
"actions": Array [
Object {
"available": [Function],
"color": "danger",
"data-test-subj": "colorEditorRemoveColor",
"description": "Delete color format",
"icon": "trash",
"name": "Delete",
"onClick": [Function],
"type": "icon",
},
],
"field": "actions",
"name": "Actions",
},
]
}
items={
Array [
Object {
"background": "#ffffff",
"boolean": "true",
"index": 0,
"range": "-Infinity:Infinity",
"regex": "<insert regex>",
"text": "#000000",
},
]
}
noItemsMessage={
<EuiI18n
default="No items found"
token="euiBasicTable.noItemsMessage"
/>
}
tableLayout="fixed"
/>
<EuiSpacer
size="m"
/>
<EuiButton
data-test-subj="colorEditorAddColor"
iconType="plusInCircle"
onClick={[Function]}
size="s"
>
<MemoizedFormattedMessage
defaultMessage="Add color"
id="indexPatternFieldEditor.color.addColorButton"
/>
</EuiButton>
<EuiSpacer
size="l"
/>
</Fragment>
`;
exports[`ColorFormatEditor should render multiple colors 1`] = `
<Fragment>
<EuiBasicTable
@ -58,6 +152,7 @@ exports[`ColorFormatEditor should render multiple colors 1`] = `
Array [
Object {
"background": "#ffffff",
"boolean": "true",
"index": 0,
"range": "-Infinity:Infinity",
"regex": "<insert regex>",
@ -65,6 +160,7 @@ exports[`ColorFormatEditor should render multiple colors 1`] = `
},
Object {
"background": "#ffffff",
"boolean": "true",
"index": 1,
"range": "-Infinity:Infinity",
"regex": "<insert regex>",
@ -158,6 +254,7 @@ exports[`ColorFormatEditor should render other type normally (range field) 1`] =
Array [
Object {
"background": "#ffffff",
"boolean": "true",
"index": 0,
"range": "-Infinity:Infinity",
"regex": "<insert regex>",
@ -251,6 +348,7 @@ exports[`ColorFormatEditor should render string type normally (regex field) 1`]
Array [
Object {
"background": "#ffffff",
"boolean": "true",
"index": 0,
"range": "-Infinity:Infinity",
"regex": "<insert regex>",

View file

@ -57,6 +57,20 @@ describe('ColorFormatEditor', () => {
expect(component).toMatchSnapshot();
});
it('should render boolean type normally', async () => {
const component = shallowWithI18nProvider(
<ColorFormatEditor
fieldType={'boolean'}
format={format as unknown as FieldFormat}
formatParams={formatParams}
onChange={onChange}
onError={onError}
/>
);
expect(component).toMatchSnapshot();
});
it('should render other type normally (range field)', async () => {
const component = shallowWithI18nProvider(
<ColorFormatEditor

View file

@ -15,6 +15,7 @@ import {
EuiColorPicker,
EuiIcon,
EuiFieldText,
EuiSelect,
EuiSpacer,
} from '@elastic/eui';
@ -29,6 +30,7 @@ import { FormatEditorProps } from '../types';
interface Color {
range?: string;
regex?: string;
boolean?: string;
text: string;
background: string;
}
@ -76,6 +78,90 @@ export class ColorFormatEditor extends DefaultFormatEditor<ColorFormatEditorForm
});
};
getFirstColumn = (fieldType: string) => {
if (fieldType === 'boolean')
return {
field: 'boolean',
name: (
<FormattedMessage
id="indexPatternFieldEditor.color.booleanLabel"
defaultMessage="Boolean"
/>
),
render: (value: string, item: IndexedColor) => {
return (
<EuiSelect
options={[
{ value: 'true', text: 'true' },
{ value: 'false', text: 'false' },
]}
value={value}
data-test-subj={`colorEditorKeyBoolean ${item.index}`}
onChange={(e) => {
this.onColorChange(
{
boolean: e.target.value,
},
item.index
);
}}
/>
);
},
};
if (fieldType === 'string')
return {
field: 'regex',
name: (
<FormattedMessage
id="indexPatternFieldEditor.color.patternLabel"
defaultMessage="Pattern (regular expression)"
/>
),
render: (value: string, item: IndexedColor) => {
return (
<EuiFieldText
value={value}
data-test-subj={`colorEditorKeyPattern ${item.index}`}
onChange={(e) => {
this.onColorChange(
{
regex: e.target.value,
},
item.index
);
}}
/>
);
},
};
return {
field: 'range',
name: (
<FormattedMessage
id="indexPatternFieldEditor.color.rangeLabel"
defaultMessage="Range (min:max)"
/>
),
render: (value: string, item: IndexedColor) => {
return (
<EuiFieldText
value={value}
data-test-subj={`colorEditorKeyRange ${item.index}`}
onChange={(e) => {
this.onColorChange(
{
range: e.target.value,
},
item.index
);
}}
/>
);
},
};
};
render() {
const { formatParams, fieldType } = this.props;
@ -91,57 +177,7 @@ export class ColorFormatEditor extends DefaultFormatEditor<ColorFormatEditorForm
[];
const columns = [
fieldType === 'string'
? {
field: 'regex',
name: (
<FormattedMessage
id="indexPatternFieldEditor.color.patternLabel"
defaultMessage="Pattern (regular expression)"
/>
),
render: (value: string, item: IndexedColor) => {
return (
<EuiFieldText
value={value}
data-test-subj={`colorEditorKeyPattern ${item.index}`}
onChange={(e) => {
this.onColorChange(
{
regex: e.target.value,
},
item.index
);
}}
/>
);
},
}
: {
field: 'range',
name: (
<FormattedMessage
id="indexPatternFieldEditor.color.rangeLabel"
defaultMessage="Range (min:max)"
/>
),
render: (value: string, item: IndexedColor) => {
return (
<EuiFieldText
value={value}
data-test-subj={`colorEditorKeyRange ${item.index}`}
onChange={(e) => {
this.onColorChange(
{
range: e.target.value,
},
item.index
);
}}
/>
);
},
},
this.getFirstColumn(fieldType),
{
field: 'text',
name: (

View file

@ -12,4 +12,5 @@ export const DEFAULT_CONVERTER_COLOR = {
regex: '<insert regex>',
text: '#000000',
background: '#ffffff',
boolean: 'true',
};

View file

@ -56,6 +56,29 @@ describe('Color Format', () => {
});
});
describe('field is a boolean', () => {
test('should add colors if the value is true or false', () => {
const colorer = new ColorFormat(
{
fieldType: 'boolean',
colors: [
{
boolean: 'true',
text: 'blue',
background: 'yellow',
},
],
},
jest.fn()
);
expect(colorer.convert(true, HTML_CONTEXT_TYPE)).toBe(
'<span style="color:blue;background-color:yellow">true</span>'
);
expect(colorer.convert(false, HTML_CONTEXT_TYPE)).toBe('false');
});
});
describe('field is a string', () => {
test('should add colors if the regex matches', () => {
const colorer = new ColorFormat(

View file

@ -23,7 +23,7 @@ export class ColorFormat extends FieldFormat {
static title = i18n.translate('fieldFormats.color.title', {
defaultMessage: 'Color',
});
static fieldType = [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.STRING];
static fieldType = [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.STRING, KBN_FIELD_TYPES.BOOLEAN];
getParamDefaults() {
return {
@ -32,7 +32,7 @@ export class ColorFormat extends FieldFormat {
};
}
findColorRuleForVal(val: string | number) {
findColorRuleForVal(val: string | number | boolean) {
switch (this.param('fieldType')) {
case 'string':
return findLast(this.param('colors'), (colorParam: typeof DEFAULT_CONVERTER_COLOR) => {
@ -50,6 +50,10 @@ export class ColorFormat extends FieldFormat {
// @ts-expect-error upgrade typescript v5.1.6
return val >= Number(start) && val <= Number(end);
});
case 'boolean':
return findLast(this.param('colors'), ({ boolean }) => {
return boolean === val.toString();
});
default:
return null;

View file

@ -315,6 +315,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
// check available formats for ES_FIELD_TYPES.BOOLEAN
expectFormatterTypes: [
FIELD_FORMAT_IDS.BOOLEAN,
FIELD_FORMAT_IDS.COLOR,
FIELD_FORMAT_IDS.STATIC_LOOKUP,
FIELD_FORMAT_IDS.STRING,
FIELD_FORMAT_IDS.URL,