Skip to content

Commit

Permalink
[TSVB] Use default Kibana palette for split series (elastic#62241)
Browse files Browse the repository at this point in the history
* [TSVB] Rainbow palette shares colors with dashboard

* Add migration

* Add charts as NP dependency

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
2 people authored and wylieconlon committed Apr 20, 2020
1 parent 1ab454c commit 778f812
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 50 deletions.
2 changes: 1 addition & 1 deletion src/plugins/vis_type_timeseries/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
"kibanaVersion": "kibana",
"server": true,
"ui": true,
"requiredPlugins": ["data", "expressions", "visualizations"],
"requiredPlugins": ["charts", "data", "expressions", "visualizations"],
"optionalPlugins": ["usageCollection"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const TimeseriesConfig = injectI18n(function(props) {
point_size: '',
value_template: '{{value}}',
offset_time: '',
split_color_mode: 'gradient',
split_color_mode: 'kibana',
axis_min: '',
axis_max: '',
stacked: STACKED_OPTIONS.NONE,
Expand Down Expand Up @@ -140,10 +140,10 @@ export const TimeseriesConfig = injectI18n(function(props) {
const splitColorOptions = [
{
label: intl.formatMessage({
id: 'visTypeTimeseries.timeSeries.gradientLabel',
defaultMessage: 'Gradient',
id: 'visTypeTimeseries.timeSeries.defaultPaletteLabel',
defaultMessage: 'Default palette',
}),
value: 'gradient',
value: 'kibana',
},
{
label: intl.formatMessage({
Expand All @@ -152,6 +152,13 @@ export const TimeseriesConfig = injectI18n(function(props) {
}),
value: 'rainbow',
},
{
label: intl.formatMessage({
id: 'visTypeTimeseries.timeSeries.gradientLabel',
defaultMessage: 'Gradient',
}),
value: 'gradient',
},
];
const selectedSplitColorOption = splitColorOptions.find(option => {
return model.split_color_mode === option.value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
import { EuiIcon } from '@elastic/eui';
import { getTimezone } from '../../../lib/get_timezone';
import { eventBus, ACTIVE_CURSOR } from '../../lib/active_cursor';
import { getUISettings } from '../../../../services';
import { getUISettings, getChartsSetup } from '../../../../services';
import { GRID_LINE_CONFIG, ICON_TYPES_MAP, STACKED_OPTIONS } from '../../constants';
import { AreaSeriesDecorator } from './decorators/area_decorator';
import { BarSeriesDecorator } from './decorators/bar_decorator';
Expand Down Expand Up @@ -94,6 +94,12 @@ export const TimeSeries = ({
// apply legend style change if bgColor is configured
const classes = classNames('tvbVisTimeSeries', getChartClasses(backgroundColor));

// If the color isn't configured by the user, use the color mapping service
// to assign a color from the Kibana palette. Colors will be shared across the
// session, including dashboards.
const { colors } = getChartsSetup();
colors.mappedColors.mapKeys(series.filter(({ color }) => !color).map(({ label }) => label));

return (
<Chart ref={chartRef} renderer="canvas" className={classes}>
<Settings
Expand Down Expand Up @@ -163,6 +169,8 @@ export const TimeSeries = ({
const stackAccessors = getStackAccessors(stack);
const isPercentage = stack === STACKED_OPTIONS.PERCENT;
const key = `${id}-${label}`;
// Only use color mapping if there is no color from the server
const finalColor = color ?? colors.mappedColors.mapping[label];

if (bars.show) {
return (
Expand All @@ -174,7 +182,7 @@ export const TimeSeries = ({
data={data}
hideInLegend={hideInLegend}
bars={bars}
color={color}
color={finalColor}
stackAccessors={stackAccessors}
stackAsPercentage={isPercentage}
xScaleType={xScaleType}
Expand All @@ -199,7 +207,7 @@ export const TimeSeries = ({
data={data}
hideInLegend={hideInLegend}
lines={lines}
color={color}
color={finalColor}
stackAccessors={stackAccessors}
stackAsPercentage={isPercentage}
points={points}
Expand Down
1 change: 1 addition & 0 deletions src/plugins/vis_type_timeseries/public/metrics_type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const metricsVisDefinition = {
id: '61ca57f1-469d-11e7-af02-69e470af7417',
color: '#68BC00',
split_mode: 'everything',
split_color_mode: 'kibana',
metrics: [
{
id: '61ca57f2-469d-11e7-af02-69e470af7417',
Expand Down
6 changes: 5 additions & 1 deletion src/plugins/vis_type_timeseries/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@ import {
setFieldFormats,
setCoreStart,
setDataStart,
setChartsSetup,
} from './services';
import { DataPublicPluginStart } from '../../data/public';
import { ChartsPluginSetup } from '../../charts/public';

/** @internal */
export interface MetricsPluginSetupDependencies {
expressions: ReturnType<ExpressionsPublicPlugin['setup']>;
visualizations: VisualizationsSetup;
charts: ChartsPluginSetup;
}

/** @internal */
Expand All @@ -56,10 +59,11 @@ export class MetricsPlugin implements Plugin<Promise<void>, void> {

public async setup(
core: CoreSetup,
{ expressions, visualizations }: MetricsPluginSetupDependencies
{ expressions, visualizations, charts }: MetricsPluginSetupDependencies
) {
expressions.registerFunction(createMetricsFn);
setUISettings(core.uiSettings);
setChartsSetup(charts);
visualizations.createReactVisualization(metricsVisDefinition);
}

Expand Down
5 changes: 5 additions & 0 deletions src/plugins/vis_type_timeseries/public/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import { I18nStart, SavedObjectsStart, IUiSettingsClient, CoreStart } from 'src/core/public';
import { createGetterSetter } from '../../kibana_utils/public';
import { ChartsPluginSetup } from '../../charts/public';
import { DataPublicPluginStart } from '../../data/public';

export const [getUISettings, setUISettings] = createGetterSetter<IUiSettingsClient>('UISettings');
Expand All @@ -36,3 +37,7 @@ export const [getCoreStart, setCoreStart] = createGetterSetter<CoreStart>('CoreS
export const [getDataStart, setDataStart] = createGetterSetter<DataPublicPluginStart>('DataStart');

export const [getI18n, setI18n] = createGetterSetter<I18nStart>('I18n');

export const [getChartsSetup, setChartsSetup] = createGetterSetter<ChartsPluginSetup>(
'ChartsPluginSetup'
);
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import Color from 'color';

export function getSplitColors(inputColor, size = 10, style = 'gradient') {
export function getSplitColors(inputColor, size = 10, style = 'kibana') {
const color = new Color(inputColor);
const colors = [];
let workingColor = Color.hsl(color.hsl().object());
Expand Down Expand Up @@ -49,7 +49,7 @@ export function getSplitColors(inputColor, size = 10, style = 'gradient') {
'#0F1419',
'#666666',
];
} else {
} else if (style === 'gradient') {
colors.push(color.string());
const rotateBy = color.luminosity() / (size - 1);
for (let i = 0; i < size - 1; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ describe('getSplits(resp, panel, series)', () => {
]);
});

test('should return a splits for terms group bys', () => {
describe('terms group bys', () => {
const resp = {
aggregations: {
SERIES: {
Expand All @@ -126,38 +126,89 @@ describe('getSplits(resp, panel, series)', () => {
},
},
};
const series = {
id: 'SERIES',
color: '#F00',
split_mode: 'terms',
terms_field: 'beat.hostname',
terms_size: 10,
metrics: [
{ id: 'AVG', type: 'avg', field: 'cpu' },
{ id: 'SIBAGG', type: 'avg_bucket', field: 'AVG' },
],
};
const panel = { type: 'timeseries' };
expect(getSplits(resp, panel, series)).toEqual([
{
id: 'SERIES:example-01',
key: 'example-01',
label: 'example-01',
meta: { bucketSize: 10 },
color: 'rgb(255, 0, 0)',
timeseries: { buckets: [] },
SIBAGG: { value: 1 },
},
{
id: 'SERIES:example-02',
key: 'example-02',
label: 'example-02',
meta: { bucketSize: 10 },
color: 'rgb(147, 0, 0)',
timeseries: { buckets: [] },
SIBAGG: { value: 2 },
},
]);

test('should return a splits with no color', () => {
const series = {
id: 'SERIES',
color: '#F00',
split_mode: 'terms',
terms_field: 'beat.hostname',
terms_size: 10,
metrics: [
{ id: 'AVG', type: 'avg', field: 'cpu' },
{ id: 'SIBAGG', type: 'avg_bucket', field: 'AVG' },
],
};
const panel = { type: 'timeseries' };
expect(getSplits(resp, panel, series)).toEqual([
{
id: 'SERIES:example-01',
key: 'example-01',
label: 'example-01',
meta: { bucketSize: 10 },
color: undefined,
timeseries: { buckets: [] },
SIBAGG: { value: 1 },
},
{
id: 'SERIES:example-02',
key: 'example-02',
label: 'example-02',
meta: { bucketSize: 10 },
color: undefined,
timeseries: { buckets: [] },
SIBAGG: { value: 2 },
},
]);
});

test('should return gradient color', () => {
const series = {
id: 'SERIES',
color: '#F00',
split_mode: 'terms',
split_color_mode: 'gradient',
terms_field: 'beat.hostname',
terms_size: 10,
metrics: [
{ id: 'AVG', type: 'avg', field: 'cpu' },
{ id: 'SIBAGG', type: 'avg_bucket', field: 'AVG' },
],
};
const panel = { type: 'timeseries' };
expect(getSplits(resp, panel, series)).toEqual([
expect.objectContaining({
color: 'rgb(255, 0, 0)',
}),
expect.objectContaining({
color: 'rgb(147, 0, 0)',
}),
]);
});

test('should return rainbow color', () => {
const series = {
id: 'SERIES',
color: '#F00',
split_mode: 'terms',
split_color_mode: 'rainbow',
terms_field: 'beat.hostname',
terms_size: 10,
metrics: [
{ id: 'AVG', type: 'avg', field: 'cpu' },
{ id: 'SIBAGG', type: 'avg_bucket', field: 'AVG' },
],
};
const panel = { type: 'timeseries' };
expect(getSplits(resp, panel, series)).toEqual([
expect.objectContaining({
color: '#68BC00',
}),
expect.objectContaining({
color: '#009CE0',
}),
]);
});
});

test('should return a splits for filters group bys', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1460,4 +1460,62 @@ describe('migration visualization', () => {
expect(migratedParams.gauge_color_rules[1]).toEqual(params.gauge_color_rules[1]);
});
});

describe('7.8.0 tsvb split_color_mode', () => {
const migrate = (doc: any) =>
visualizationSavedObjectTypeMigrations['7.8.0'](
doc as Parameters<SavedObjectMigrationFn>[0],
savedObjectMigrationContext
);

const generateDoc = (params: any) => ({
attributes: {
title: 'My Vis',
type: 'visualization',
description: 'This is my super cool vis.',
visState: JSON.stringify(params),
uiStateJSON: '{}',
version: 1,
kibanaSavedObjectMeta: {
searchSourceJSON: '{}',
},
},
});

it('should change a missing split_color_mode to gradient', () => {
const params = { type: 'metrics', params: { series: [{}] } };
const testDoc1 = generateDoc(params);
const migratedTestDoc1 = migrate(testDoc1);
const series = JSON.parse(migratedTestDoc1.attributes.visState).params.series;

expect(series[0].split_color_mode).toEqual('gradient');
});

it('should not change the color mode if it is set', () => {
const params = { type: 'metrics', params: { series: [{ split_color_mode: 'gradient' }] } };
const testDoc1 = generateDoc(params);
const migratedTestDoc1 = migrate(testDoc1);
const series = JSON.parse(migratedTestDoc1.attributes.visState).params.series;

expect(series[0].split_color_mode).toEqual('gradient');
});

it('should not change the color mode if it is non-default', () => {
const params = { type: 'metrics', params: { series: [{ split_color_mode: 'rainbow' }] } };
const testDoc1 = generateDoc(params);
const migratedTestDoc1 = migrate(testDoc1);
const series = JSON.parse(migratedTestDoc1.attributes.visState).params.series;

expect(series[0].split_color_mode).toEqual('rainbow');
});

it('should not migrate a visualization of unknown type', () => {
const params = { type: 'unknown', params: { series: [{}] } };
const doc = generateDoc(params);
const migratedDoc = migrate(doc);
const series = JSON.parse(migratedDoc.attributes.visState).params.series;

expect(series[0].split_color_mode).toBeUndefined();
});
});
});

0 comments on commit 778f812

Please sign in to comment.