Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TSVB] Use default Kibana palette for split series #62241

Merged
merged 10 commits into from
Apr 20, 2020
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();
});
});
});