mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[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:
parent
37e107e1dc
commit
52ee949f6f
7 changed files with 230 additions and 53 deletions
|
@ -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>",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: (
|
||||
|
|
|
@ -12,4 +12,5 @@ export const DEFAULT_CONVERTER_COLOR = {
|
|||
regex: '<insert regex>',
|
||||
text: '#000000',
|
||||
background: '#ffffff',
|
||||
boolean: 'true',
|
||||
};
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue