Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
d66a86c
Allow users to change the colors series for terms split
stratoula Jan 20, 2021
332715f
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Jan 20, 2021
365b7a3
Save overwritten colors by series id
stratoula Jan 20, 2021
fd0aaaf
Remove unnecessary console
stratoula Jan 20, 2021
c8ac179
Add the getSeriesColor logic to a separate function and unit test
stratoula Jan 20, 2021
5d9348d
Change the prop from disabled to hide
stratoula Jan 20, 2021
59f401c
Add unit test for useColorPicker util
stratoula Jan 20, 2021
b20e551
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Jan 21, 2021
fb70a89
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Jan 25, 2021
e4db16c
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Jan 27, 2021
cb82d83
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Feb 1, 2021
6fa2a54
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Feb 2, 2021
c190d4d
Update the panel color anchor with the legend overwritten colors
stratoula Feb 3, 2021
692f12b
Make things simpler
stratoula Feb 3, 2021
6d00775
Fix color picker input
stratoula Feb 3, 2021
cb5f8bb
Fix all scenarios
stratoula Feb 3, 2021
f855c4f
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Feb 4, 2021
53e5eb8
Update license
stratoula Feb 4, 2021
c8c10bf
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Feb 5, 2021
b134926
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Feb 8, 2021
02a3f2c
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Feb 15, 2021
36efe43
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Feb 18, 2021
5769e68
Fix problem created by merging with master
stratoula Feb 18, 2021
81d4c44
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Feb 22, 2021
a76305e
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Feb 22, 2021
093b86f
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Feb 23, 2021
29b7d91
Merge with master and resolve conflicts
stratoula Mar 1, 2021
f4ba733
Use TSVB color picker for consistency instead the charts implementation
stratoula Mar 1, 2021
409bc81
Fix bug
stratoula Mar 1, 2021
fdda29e
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Mar 2, 2021
c475a16
Refactor to use a color service
stratoula Mar 2, 2021
e4d87e0
Fix bug
stratoula Mar 2, 2021
ebc28a2
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Mar 2, 2021
e39b7db
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Mar 3, 2021
5517e47
Merge branch 'master' into tsvb-legend-color-picker
kibanamachine Mar 3, 2021
12ee9ff
Fix ci
stratoula Mar 3, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions api_docs/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -26227,8 +26227,8 @@
"description": [],
"source": {
"path": "src/plugins/data/common/es_query/filters/phrase_filter.ts",
"lineNumber": 102,
"link": "https://github.com/elastic/kibana/tree/mastersrc/plugins/data/common/es_query/filters/phrase_filter.ts#L102"
"lineNumber": 107,
"link": "https://github.com/elastic/kibana/tree/mastersrc/plugins/data/common/es_query/filters/phrase_filter.ts#L107"
}
},
{
Expand All @@ -26241,8 +26241,8 @@
"description": [],
"source": {
"path": "src/plugins/data/common/es_query/filters/phrase_filter.ts",
"lineNumber": 102,
"link": "https://github.com/elastic/kibana/tree/mastersrc/plugins/data/common/es_query/filters/phrase_filter.ts#L102"
"lineNumber": 107,
"link": "https://github.com/elastic/kibana/tree/mastersrc/plugins/data/common/es_query/filters/phrase_filter.ts#L107"
}
}
],
Expand All @@ -26257,12 +26257,14 @@
},
", value: any) => any"
],
"description": [],
"description": [
"\nSee issues bellow for the reason behind this change.\nValues need to be converted to correct types for boolean \\ numeric fields.\nhttps://github.com/elastic/kibana/issues/74301\nhttps://github.com/elastic/kibana/issues/8677\nhttps://github.com/elastic/elasticsearch/issues/20941\nhttps://github.com/elastic/elasticsearch/pull/22201"
],
"label": "getConvertedValueForField",
"source": {
"path": "src/plugins/data/common/es_query/filters/phrase_filter.ts",
"lineNumber": 102,
"link": "https://github.com/elastic/kibana/tree/mastersrc/plugins/data/common/es_query/filters/phrase_filter.ts#L102"
"lineNumber": 107,
"link": "https://github.com/elastic/kibana/tree/mastersrc/plugins/data/common/es_query/filters/phrase_filter.ts#L107"
},
"tags": [],
"returnComment": [],
Expand All @@ -26282,8 +26284,8 @@
"description": [],
"source": {
"path": "src/plugins/data/common/es_query/filters/phrase_filter.ts",
"lineNumber": 123,
"link": "https://github.com/elastic/kibana/tree/mastersrc/plugins/data/common/es_query/filters/phrase_filter.ts#L123"
"lineNumber": 132,
"link": "https://github.com/elastic/kibana/tree/mastersrc/plugins/data/common/es_query/filters/phrase_filter.ts#L132"
}
}
],
Expand All @@ -26296,8 +26298,8 @@
"label": "buildInlineScriptForPhraseFilter",
"source": {
"path": "src/plugins/data/common/es_query/filters/phrase_filter.ts",
"lineNumber": 123,
"link": "https://github.com/elastic/kibana/tree/mastersrc/plugins/data/common/es_query/filters/phrase_filter.ts#L123"
"lineNumber": 132,
"link": "https://github.com/elastic/kibana/tree/mastersrc/plugins/data/common/es_query/filters/phrase_filter.ts#L132"
},
"tags": [],
"returnComment": [
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/vis_type_timeseries/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ export type PanelSchema = TypeOf<typeof panel>;
export type VisPayload = TypeOf<typeof visPayloadSchema>;
export type FieldObject = TypeOf<typeof fieldObject>;

interface PanelData {
export interface PanelData {
id: string;
label: string;
data: Array<[number, number]>;
labelFormatted?: string;
}

// series data is not fully typed yet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
position: relative;
}

.tvbColorPicker__legend {
flex-direction: column;
}

.tvbColorPicker__clear {
margin-left: $euiSizeXS;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { mount } from 'enzyme';
import { ReactWrapper } from 'enzyme';
import { EuiColorPicker, EuiIconTip } from '@elastic/eui';
import { findTestSubject } from '@elastic/eui/lib/test';
import type { PersistedState } from '../../../../visualizations/public';

describe('ColorPicker', () => {
const defaultProps: ColorPickerProps = {
Expand All @@ -21,6 +22,17 @@ describe('ColorPicker', () => {
disableTrash: true,
};
let component: ReactWrapper<ColorPickerProps>;
const mockState = new Map();
const uiState = ({
get: jest
.fn()
.mockImplementation((key, fallback) => (mockState.has(key) ? mockState.get(key) : fallback)),
set: jest.fn().mockImplementation((key, value) => mockState.set(key, value)),
emit: jest.fn(),
setSilent: jest.fn(),
on: jest.fn(),
off: jest.fn(),
} as unknown) as PersistedState;

it('should render the EuiColorPicker', () => {
component = mount(<ColorPicker {...defaultProps} />);
Expand Down Expand Up @@ -64,4 +76,53 @@ describe('ColorPicker', () => {
expect(component.find(EuiIconTip).length).toBe(1);
expect(defaultProps.onChange).toHaveBeenCalled();
});

it('renders correctly the color picker if the isOnLegend prop is true', () => {
const props = { ...defaultProps, isOnLegend: true, value: 'rgba(85,66,177,1)' };
component = mount(<ColorPicker {...props} />);
expect(component.find(EuiColorPicker).prop('display')).toBe('inline');
expect(component.find(EuiColorPicker).prop('button')).toBeUndefined();
});

it('renders the correct color if is overwritten by the user', () => {
uiState.set('vis.colors', [
{
id: '61ca57f1-469d-11e7-af02-69e470af7417',
overwrite: {
Count: '#4CE7A6',
},
},
{
id: '61ca57f1-469d-11e7-af02-69e470af7417:JetBeats',
overwrite: {
JetBeats: '#6092C0',
},
},
]);
const props = {
...defaultProps,
uiState,
value: 'rgba(85,66,177,1)',
seriesName: 'JetBeats',
seriesId: '61ca57f1-469d-11e7-af02-69e470af7417:JetBeats',
};
component = mount(<ColorPicker {...props} />);
expect(component.find(EuiColorPicker).prop('color')).toBe('#6092C0');
component.find('.tvbColorPicker button').simulate('click');
const input = findTestSubject(component, 'topColorPickerInput');
expect(input.props().value).toBe('#6092C0');
});

it('renders the clear color button if isOnLegend prop is true and user has overwritten the series color', () => {
const props = {
...defaultProps,
uiState,
value: 'rgba(85,66,177,1)',
seriesName: 'JetBeats',
seriesId: '61ca57f1-469d-11e7-af02-69e470af7417:JetBeats',
isOnLegend: true,
};
component = mount(<ColorPicker {...props} />);
expect(findTestSubject(component, 'tvbColorPickerClearColor').length).toBe(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,22 @@
/* eslint-disable jsx-a11y/click-events-have-key-events */
// The color picker is not yet accessible.

import React, { useState } from 'react';
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import {
EuiIconTip,
EuiColorPicker,
EuiColorPickerProps,
EuiColorPickerSwatch,
EuiButtonEmpty,
EuiSpacer,
} from '@elastic/eui';
import classNames from 'classnames';
import { i18n } from '@kbn/i18n';
import type { PersistedState } from '../../../../visualizations/public';
import { ColorsService } from '../lib';

const COMMAS_NUMS_ONLY_RE = /[^0-9,]/g;

interface ColorProps {
export interface ColorProps {
[key: string]: string | null;
}

Expand All @@ -29,27 +33,78 @@ export interface ColorPickerProps {
value: string | null;
disableTrash?: boolean;
onChange: (props: ColorProps) => void;
seriesName?: string;
uiState?: PersistedState;
seriesId?: string;
isOnLegend?: boolean;
}

export function ColorPicker({ name, value, disableTrash = false, onChange }: ColorPickerProps) {
const initialColorValue = value?.includes('rgba')
? value.replace(COMMAS_NUMS_ONLY_RE, '')
: value;
export function ColorPicker({
name,
value,
disableTrash = false,
onChange,
seriesName,
uiState,
seriesId,
isOnLegend = false,
}: ColorPickerProps) {
const initialColorValue = value?.includes('rgb') ? value.replace(COMMAS_NUMS_ONLY_RE, '') : value;
const overwrittenColorsService = useMemo(
() => (uiState ? new ColorsService(uiState) : undefined),
[uiState]
);

const initialOverwrittenColor =
seriesId && seriesName && overwrittenColorsService?.getSeriesColor(seriesId, seriesName, '');

const [color, setColor] = useState(initialColorValue || '');
const [overwrittenColor, setOverwrittenColor] = useState(initialOverwrittenColor || '');

const handleColorChange: EuiColorPickerProps['onChange'] = (text: string, { rgba, hex }) => {
setColor(text);
const part: ColorProps = {};
part[name] = hex ? `rgba(${rgba.join(',')})` : '';
onChange(part);
};
const clearOverwriteColor = useCallback(() => {
if (overwrittenColor && seriesName && seriesId) {
// remove the overwrittenColor from the uiState
overwrittenColorsService?.deleteFromUiState(seriesName, seriesId);
}
}, [overwrittenColor, overwrittenColorsService, seriesId, seriesName]);

const handleColorChange = useCallback(
(text: string, { rgba, hex }) => {
const part: ColorProps = {};
part[name] = hex ? `rgba(${rgba.join(',')})` : '';
onChange(part);
setColor(text);
if (!isOnLegend) {
clearOverwriteColor();
} else {
setOverwrittenColor(text);
}
},
[name, onChange, clearOverwriteColor, isOnLegend]
);

useEffect(() => {
const updateColor = () => {
const newOverwrittenColor =
uiState &&
seriesId &&
seriesName &&
new ColorsService(uiState).getSeriesColor(seriesId, seriesName, '');
setOverwrittenColor(newOverwrittenColor ?? '');
};
uiState?.on('change', updateColor);

return () => {
uiState?.off('change', updateColor);
};
}, [initialColorValue, seriesId, seriesName, uiState]);

const handleClear = () => {
const handleClear = useCallback(() => {
setColor('');
const part: ColorProps = {};
part[name] = null;
onChange(part);
};
}, [name, onChange]);

const label = value
? i18n.translate('visTypeTimeseries.colorPicker.notAccessibleWithValueAriaLabel', {
Expand All @@ -61,14 +116,36 @@ export function ColorPicker({ name, value, disableTrash = false, onChange }: Col
});

return (
<div className="tvbColorPicker" data-test-subj="tvbColorPicker">
<div
className={classNames('tvbColorPicker', isOnLegend && 'tvbColorPicker__legend')}
data-test-subj="tvbColorPicker"
>
<EuiColorPicker
onChange={handleColorChange}
color={color}
display={isOnLegend ? 'inline' : 'default'}
color={overwrittenColor || color}
secondaryInputDisplay="top"
showAlpha
button={<EuiColorPickerSwatch color={color} aria-label={label} />}
button={
!isOnLegend ? (
<EuiColorPickerSwatch color={overwrittenColor || color} aria-label={label} />
) : undefined
}
/>
{isOnLegend && overwrittenColor && (
<>
<EuiSpacer size="m" />
<EuiButtonEmpty
size="s"
onClick={() => clearOverwriteColor()}
data-test-subj="tvbColorPickerClearColor"
>
{i18n.translate('visTypeTimeseries.colorPicker.clearColorLabel', {
defaultMessage: 'Clear Color',
})}
</EuiButtonEmpty>
</>
)}
{!disableTrash && (
<div className="tvbColorPicker__clear" onClick={handleClear}>
<EuiIconTip
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ class TimeseriesPanelConfigUi extends Component {
model={this.props.model}
name={this.props.name}
onChange={this.props.onChange}
uiState={this.props.uiState}
/>
);
} else if (selectedTab === 'annotations') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export class Series extends Component {
visible={this.state.visible}
dragHandleProps={this.props.dragHandleProps}
indexPatternForQuery={panel.index_pattern || panel.default_index_pattern}
uiState={this.props.uiState}
/>
);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class SeriesEditor extends Component {
};

render() {
const { limit, model, name, fields, colorPicker } = this.props;
const { limit, model, name, fields, colorPicker, uiState } = this.props;
const list = model[name].filter((val, index) => index < (limit || Infinity));

return (
Expand Down Expand Up @@ -92,6 +92,7 @@ export class SeriesEditor extends Component {
onDelete={() => handleDelete(this.props, row)}
model={row}
panel={model}
uiState={uiState}
dragHandleProps={provided.dragHandleProps}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export class Split extends Component {
}

render() {
const { model, panel, uiRestrictions, seriesQuantity } = this.props;
const { model, panel, uiRestrictions, seriesQuantity, uiState } = this.props;
const indexPattern =
(model.override_index_pattern && model.series_index_pattern) || panel.index_pattern;
const splitMode = get(this.props, 'model.split_mode', SPLIT_MODES.EVERYTHING);
Expand All @@ -76,6 +76,7 @@ export class Split extends Component {
onChange={this.props.onChange}
uiRestrictions={uiRestrictions}
seriesQuantity={seriesQuantity}
uiState={uiState}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ class FilterItemsUi extends Component {
onChange={handleChange}
name="color"
value={model.color}
uiState={this.props.uiState}
seriesId={`${this.props.model.id}:${model.id}`}
seriesName={model.label || model.filter.query}
/>
</EuiFlexItem>
<EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic
import { FormattedMessage } from '@kbn/i18n/react';

export const SplitByFilters = (props) => {
const { onChange, model, uiRestrictions, indexPattern } = props;
const { onChange, model, uiRestrictions, indexPattern, uiState } = props;
const htmlId = htmlIdGenerator();
const handleSelectChange = createSelectHandler(onChange);
return (
Expand Down Expand Up @@ -45,6 +45,7 @@ export const SplitByFilters = (props) => {
model={model}
onChange={onChange}
indexPatterns={indexPattern}
uiState={uiState}
/>
</div>
);
Expand Down
Loading