mirror of
https://github.com/elastic/kibana.git
synced 2025-06-28 03:01:21 -04:00
[Lens] Configurable color syncing (#86180)
This commit is contained in:
parent
9c74a1090e
commit
57a72a78f7
41 changed files with 574 additions and 560 deletions
|
@ -17,5 +17,6 @@ export declare type EmbeddableInput = {
|
|||
disabledActions?: string[];
|
||||
disableTriggers?: boolean;
|
||||
searchSessionId?: string;
|
||||
syncColors?: boolean;
|
||||
};
|
||||
```
|
||||
|
|
|
@ -9,7 +9,7 @@ Constructs a new instance of the `ExpressionRenderHandler` class
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
constructor(element: HTMLElement, { onRenderError, renderMode, hasCompatibleActions, }?: ExpressionRenderHandlerParams);
|
||||
constructor(element: HTMLElement, { onRenderError, renderMode, syncColors, hasCompatibleActions, }?: ExpressionRenderHandlerParams);
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
@ -17,5 +17,5 @@ constructor(element: HTMLElement, { onRenderError, renderMode, hasCompatibleActi
|
|||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| element | <code>HTMLElement</code> | |
|
||||
| { onRenderError, renderMode, hasCompatibleActions, } | <code>ExpressionRenderHandlerParams</code> | |
|
||||
| { onRenderError, renderMode, syncColors, hasCompatibleActions, } | <code>ExpressionRenderHandlerParams</code> | |
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ export declare class ExpressionRenderHandler
|
|||
|
||||
| Constructor | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [(constructor)(element, { onRenderError, renderMode, hasCompatibleActions, })](./kibana-plugin-plugins-expressions-public.expressionrenderhandler._constructor_.md) | | Constructs a new instance of the <code>ExpressionRenderHandler</code> class |
|
||||
| [(constructor)(element, { onRenderError, renderMode, syncColors, hasCompatibleActions, })](./kibana-plugin-plugins-expressions-public.expressionrenderhandler._constructor_.md) | | Constructs a new instance of the <code>ExpressionRenderHandler</code> class |
|
||||
|
||||
## Properties
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ export interface IExpressionLoaderParams
|
|||
| [renderMode](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.rendermode.md) | <code>RenderMode</code> | |
|
||||
| [searchContext](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.searchcontext.md) | <code>SerializableState</code> | |
|
||||
| [searchSessionId](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.searchsessionid.md) | <code>string</code> | |
|
||||
| [syncColors](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.synccolors.md) | <code>boolean</code> | |
|
||||
| [uiState](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.uistate.md) | <code>unknown</code> | |
|
||||
| [variables](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.variables.md) | <code>Record<string, any></code> | |
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [IExpressionLoaderParams](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.md) > [syncColors](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.synccolors.md)
|
||||
|
||||
## IExpressionLoaderParams.syncColors property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
syncColors?: boolean;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [IInterpreterRenderHandlers](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.md) > [isSyncColorsEnabled](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.issynccolorsenabled.md)
|
||||
|
||||
## IInterpreterRenderHandlers.isSyncColorsEnabled property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
isSyncColorsEnabled: () => boolean;
|
||||
```
|
|
@ -18,6 +18,7 @@ export interface IInterpreterRenderHandlers
|
|||
| [event](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.event.md) | <code>(event: any) => void</code> | |
|
||||
| [getRenderMode](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.getrendermode.md) | <code>() => RenderMode</code> | |
|
||||
| [hasCompatibleActions](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.hascompatibleactions.md) | <code>(event: any) => Promise<boolean></code> | |
|
||||
| [isSyncColorsEnabled](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.issynccolorsenabled.md) | <code>() => boolean</code> | |
|
||||
| [onDestroy](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.ondestroy.md) | <code>(fn: () => void) => void</code> | |
|
||||
| [reload](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.reload.md) | <code>() => void</code> | |
|
||||
| [uiState](./kibana-plugin-plugins-expressions-public.iinterpreterrenderhandlers.uistate.md) | <code>unknown</code> | This uiState interface is actually <code>PersistedState</code> from the visualizations plugin, but expressions cannot know about vis or it creates a mess of circular dependencies. Downstream consumers of the uiState handler will need to cast for now. |
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-expressions-server](./kibana-plugin-plugins-expressions-server.md) > [IInterpreterRenderHandlers](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.md) > [isSyncColorsEnabled](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.issynccolorsenabled.md)
|
||||
|
||||
## IInterpreterRenderHandlers.isSyncColorsEnabled property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
isSyncColorsEnabled: () => boolean;
|
||||
```
|
|
@ -18,6 +18,7 @@ export interface IInterpreterRenderHandlers
|
|||
| [event](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.event.md) | <code>(event: any) => void</code> | |
|
||||
| [getRenderMode](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.getrendermode.md) | <code>() => RenderMode</code> | |
|
||||
| [hasCompatibleActions](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.hascompatibleactions.md) | <code>(event: any) => Promise<boolean></code> | |
|
||||
| [isSyncColorsEnabled](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.issynccolorsenabled.md) | <code>() => boolean</code> | |
|
||||
| [onDestroy](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.ondestroy.md) | <code>(fn: () => void) => void</code> | |
|
||||
| [reload](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.reload.md) | <code>() => void</code> | |
|
||||
| [uiState](./kibana-plugin-plugins-expressions-server.iinterpreterrenderhandlers.uistate.md) | <code>unknown</code> | This uiState interface is actually <code>PersistedState</code> from the visualizations plugin, but expressions cannot know about vis or it creates a mess of circular dependencies. Downstream consumers of the uiState handler will need to cast for now. |
|
||||
|
|
|
@ -81,6 +81,21 @@ Put the dashboard in *Edit* mode, then use the following options:
|
|||
* To delete, open the panel menu, then select *Delete from dashboard*. When you delete a panel from the dashboard, the
|
||||
visualization or saved search from the panel is still available in Kibana.
|
||||
|
||||
[float]
|
||||
[[sync-colors]]
|
||||
=== Synchronize colors
|
||||
|
||||
By default, dashboard panels that share a non-gradient based color palette will synchronize their color assignment to improve readability.
|
||||
Color assignment is based on the series name, and the total number of colors is based on the number of unique series names.
|
||||
|
||||
The color synchronizing logic can make the dashboard less readable when there are too many unique series names. It is possible to disable the synchronization behavior:
|
||||
|
||||
. Put the dashboard in *Edit* mode.
|
||||
|
||||
. Click the "Options" button in the top navigation bar.
|
||||
|
||||
. Disable "Sync color palettes across panels".
|
||||
|
||||
[float]
|
||||
[[clone-panels]]
|
||||
=== Clone panels
|
||||
|
|
|
@ -37,15 +37,15 @@ export class MappedColors {
|
|||
private _mapping: any;
|
||||
|
||||
constructor(
|
||||
private uiSettings: CoreSetup['uiSettings'],
|
||||
private uiSettings?: CoreSetup['uiSettings'],
|
||||
private colorPaletteFn: (num: number) => string[] = createColorPalette
|
||||
) {
|
||||
this._oldMap = {};
|
||||
this._mapping = {};
|
||||
}
|
||||
|
||||
private getConfigColorMapping() {
|
||||
return _.mapValues(this.uiSettings.get(COLOR_MAPPING_SETTING), standardizeColor);
|
||||
private getConfigColorMapping(): Record<string, string> {
|
||||
return _.mapValues(this.uiSettings?.get(COLOR_MAPPING_SETTING) || {}, standardizeColor);
|
||||
}
|
||||
|
||||
public get oldMap(): any {
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
*/
|
||||
|
||||
import { coreMock } from '../../../../../core/public/mocks';
|
||||
import { createColorPalette as createLegacyColorPalette } from '../../../../../../src/plugins/charts/public';
|
||||
import { PaletteDefinition } from './types';
|
||||
import { buildPalettes } from './palettes';
|
||||
import { colorsServiceMock } from '../legacy_colors/mock';
|
||||
import { euiPaletteColorBlind, euiPaletteColorBlindBehindText } from '@elastic/eui';
|
||||
|
||||
describe('palettes', () => {
|
||||
const palettes: Record<string, PaletteDefinition> = buildPalettes(
|
||||
|
@ -28,6 +30,7 @@ describe('palettes', () => {
|
|||
colorsServiceMock
|
||||
);
|
||||
describe('default palette', () => {
|
||||
describe('syncColors: false', () => {
|
||||
it('should return different colors based on behind text flag', () => {
|
||||
const palette = palettes.default;
|
||||
|
||||
|
@ -104,6 +107,183 @@ describe('palettes', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('syncColors: true', () => {
|
||||
it('should return different colors based on behind text flag', () => {
|
||||
const palette = palettes.default;
|
||||
|
||||
const color1 = palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'abc',
|
||||
rankAtDepth: 0,
|
||||
totalSeriesAtDepth: 5,
|
||||
},
|
||||
],
|
||||
{
|
||||
syncColors: true,
|
||||
}
|
||||
);
|
||||
const color2 = palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'abc',
|
||||
rankAtDepth: 0,
|
||||
totalSeriesAtDepth: 5,
|
||||
},
|
||||
],
|
||||
{
|
||||
behindText: true,
|
||||
syncColors: true,
|
||||
}
|
||||
);
|
||||
expect(color1).not.toEqual(color2);
|
||||
});
|
||||
|
||||
it('should return different colors for different keys', () => {
|
||||
const palette = palettes.default;
|
||||
|
||||
const color1 = palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'abc',
|
||||
rankAtDepth: 0,
|
||||
totalSeriesAtDepth: 5,
|
||||
},
|
||||
],
|
||||
{
|
||||
syncColors: true,
|
||||
}
|
||||
);
|
||||
const color2 = palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'def',
|
||||
rankAtDepth: 0,
|
||||
totalSeriesAtDepth: 5,
|
||||
},
|
||||
],
|
||||
{
|
||||
syncColors: true,
|
||||
}
|
||||
);
|
||||
expect(color1).not.toEqual(color2);
|
||||
});
|
||||
|
||||
it('should return the same color for the same key, irregardless of rank', () => {
|
||||
const palette = palettes.default;
|
||||
|
||||
const color1 = palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'hij',
|
||||
rankAtDepth: 0,
|
||||
totalSeriesAtDepth: 5,
|
||||
},
|
||||
],
|
||||
{
|
||||
syncColors: true,
|
||||
}
|
||||
);
|
||||
const color2 = palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'hij',
|
||||
rankAtDepth: 5,
|
||||
totalSeriesAtDepth: 5,
|
||||
},
|
||||
],
|
||||
{
|
||||
syncColors: true,
|
||||
}
|
||||
);
|
||||
expect(color1).toEqual(color2);
|
||||
});
|
||||
|
||||
it('should return the same color for different positions on outer series layers', () => {
|
||||
const palette = palettes.default;
|
||||
|
||||
const color1 = palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'klm',
|
||||
rankAtDepth: 0,
|
||||
totalSeriesAtDepth: 5,
|
||||
},
|
||||
{
|
||||
name: 'def',
|
||||
rankAtDepth: 0,
|
||||
totalSeriesAtDepth: 2,
|
||||
},
|
||||
],
|
||||
{
|
||||
syncColors: true,
|
||||
}
|
||||
);
|
||||
const color2 = palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'klm',
|
||||
rankAtDepth: 3,
|
||||
totalSeriesAtDepth: 5,
|
||||
},
|
||||
{
|
||||
name: 'ghj',
|
||||
rankAtDepth: 1,
|
||||
totalSeriesAtDepth: 1,
|
||||
},
|
||||
],
|
||||
{
|
||||
syncColors: true,
|
||||
}
|
||||
);
|
||||
expect(color1).toEqual(color2);
|
||||
});
|
||||
|
||||
it('should return the same index of the behind text palette for same key', () => {
|
||||
const palette = palettes.default;
|
||||
|
||||
const color1 = palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'klm',
|
||||
rankAtDepth: 0,
|
||||
totalSeriesAtDepth: 5,
|
||||
},
|
||||
{
|
||||
name: 'def',
|
||||
rankAtDepth: 0,
|
||||
totalSeriesAtDepth: 2,
|
||||
},
|
||||
],
|
||||
{
|
||||
syncColors: true,
|
||||
}
|
||||
);
|
||||
const color2 = palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'klm',
|
||||
rankAtDepth: 3,
|
||||
totalSeriesAtDepth: 5,
|
||||
},
|
||||
{
|
||||
name: 'ghj',
|
||||
rankAtDepth: 1,
|
||||
totalSeriesAtDepth: 1,
|
||||
},
|
||||
],
|
||||
{
|
||||
syncColors: true,
|
||||
behindText: true,
|
||||
}
|
||||
);
|
||||
const color1Index = euiPaletteColorBlind({ rotations: 2 }).indexOf(color1!);
|
||||
const color2Index = euiPaletteColorBlindBehindText({ rotations: 2 }).indexOf(color2!);
|
||||
expect(color1Index).toEqual(color2Index);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('gradient palette', () => {
|
||||
const palette = palettes.warm;
|
||||
|
||||
|
@ -136,20 +316,67 @@ describe('palettes', () => {
|
|||
(colorsServiceMock.mappedColors.get as jest.Mock).mockClear();
|
||||
});
|
||||
|
||||
it('should query legacy color service', () => {
|
||||
palette.getColor([
|
||||
describe('syncColors: false', () => {
|
||||
it('should not query legacy color service', () => {
|
||||
palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'abc',
|
||||
rankAtDepth: 0,
|
||||
totalSeriesAtDepth: 10,
|
||||
},
|
||||
]);
|
||||
],
|
||||
{
|
||||
syncColors: false,
|
||||
}
|
||||
);
|
||||
expect(colorsServiceMock.mappedColors.mapKeys).not.toHaveBeenCalled();
|
||||
expect(colorsServiceMock.mappedColors.get).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return a color from the legacy palette based on position of first series', () => {
|
||||
const result = palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'abc',
|
||||
rankAtDepth: 2,
|
||||
totalSeriesAtDepth: 10,
|
||||
},
|
||||
{
|
||||
name: 'def',
|
||||
rankAtDepth: 0,
|
||||
totalSeriesAtDepth: 10,
|
||||
},
|
||||
],
|
||||
{
|
||||
syncColors: false,
|
||||
}
|
||||
);
|
||||
expect(result).toEqual(createLegacyColorPalette(20)[2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('syncColors: true', () => {
|
||||
it('should query legacy color service', () => {
|
||||
palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'abc',
|
||||
rankAtDepth: 0,
|
||||
totalSeriesAtDepth: 10,
|
||||
},
|
||||
],
|
||||
{
|
||||
syncColors: true,
|
||||
}
|
||||
);
|
||||
expect(colorsServiceMock.mappedColors.mapKeys).toHaveBeenCalledWith(['abc']);
|
||||
expect(colorsServiceMock.mappedColors.get).toHaveBeenCalledWith('abc');
|
||||
});
|
||||
|
||||
it('should always use root series', () => {
|
||||
palette.getColor([
|
||||
palette.getColor(
|
||||
[
|
||||
{
|
||||
name: 'abc',
|
||||
rankAtDepth: 0,
|
||||
|
@ -160,13 +387,18 @@ describe('palettes', () => {
|
|||
rankAtDepth: 0,
|
||||
totalSeriesAtDepth: 10,
|
||||
},
|
||||
]);
|
||||
],
|
||||
{
|
||||
syncColors: true,
|
||||
}
|
||||
);
|
||||
expect(colorsServiceMock.mappedColors.mapKeys).toHaveBeenCalledTimes(1);
|
||||
expect(colorsServiceMock.mappedColors.mapKeys).toHaveBeenCalledWith(['abc']);
|
||||
expect(colorsServiceMock.mappedColors.get).toHaveBeenCalledTimes(1);
|
||||
expect(colorsServiceMock.mappedColors.get).toHaveBeenCalledWith('abc');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('custom palette', () => {
|
||||
const palette = palettes.custom;
|
||||
|
|
|
@ -28,26 +28,45 @@ import {
|
|||
euiPaletteNegative,
|
||||
euiPalettePositive,
|
||||
euiPaletteWarm,
|
||||
euiPaletteColorBlindBehindText,
|
||||
euiPaletteForStatus,
|
||||
euiPaletteForTemperature,
|
||||
euiPaletteComplimentary,
|
||||
euiPaletteColorBlindBehindText,
|
||||
} from '@elastic/eui';
|
||||
import { ChartsPluginSetup } from '../../../../../../src/plugins/charts/public';
|
||||
import { flatten, zip } from 'lodash';
|
||||
import {
|
||||
ChartsPluginSetup,
|
||||
createColorPalette as createLegacyColorPalette,
|
||||
} from '../../../../../../src/plugins/charts/public';
|
||||
import { lightenColor } from './lighten_color';
|
||||
import { ChartColorConfiguration, PaletteDefinition, SeriesLayer } from './types';
|
||||
import { LegacyColorsService } from '../legacy_colors';
|
||||
import { MappedColors } from '../mapped_colors';
|
||||
|
||||
function buildRoundRobinCategoricalWithMappedColors(): Omit<PaletteDefinition, 'title'> {
|
||||
const colors = euiPaletteColorBlind({ rotations: 2 });
|
||||
const behindTextColors = euiPaletteColorBlindBehindText({ rotations: 2 });
|
||||
const behindTextColorMap: Record<string, string> = Object.fromEntries(
|
||||
zip(colors, behindTextColors)
|
||||
);
|
||||
const mappedColors = new MappedColors(undefined, (num: number) => {
|
||||
return flatten(new Array(Math.ceil(num / 10)).fill(colors)).map((color) => color.toLowerCase());
|
||||
});
|
||||
function getColor(
|
||||
series: SeriesLayer[],
|
||||
chartConfiguration: ChartColorConfiguration = { behindText: false }
|
||||
) {
|
||||
const outputColor = chartConfiguration.behindText
|
||||
let outputColor: string;
|
||||
if (chartConfiguration.syncColors) {
|
||||
const colorKey = series[0].name;
|
||||
mappedColors.mapKeys([colorKey]);
|
||||
const mappedColor = mappedColors.get(colorKey);
|
||||
outputColor = chartConfiguration.behindText ? behindTextColorMap[mappedColor] : mappedColor;
|
||||
} else {
|
||||
outputColor = chartConfiguration.behindText
|
||||
? behindTextColors[series[0].rankAtDepth % behindTextColors.length]
|
||||
: colors[series[0].rankAtDepth % colors.length];
|
||||
}
|
||||
|
||||
if (!chartConfiguration.maxDepth || chartConfiguration.maxDepth === 1) {
|
||||
return outputColor;
|
||||
|
@ -115,9 +134,15 @@ function buildGradient(
|
|||
function buildSyncedKibanaPalette(
|
||||
colors: ChartsPluginSetup['legacyColors']
|
||||
): Omit<PaletteDefinition, 'title'> {
|
||||
const staticColors = createLegacyColorPalette(20);
|
||||
function getColor(series: SeriesLayer[], chartConfiguration: ChartColorConfiguration = {}) {
|
||||
let outputColor: string;
|
||||
if (chartConfiguration.syncColors) {
|
||||
colors.mappedColors.mapKeys([series[0].name]);
|
||||
const outputColor = colors.mappedColors.get(series[0].name);
|
||||
outputColor = colors.mappedColors.get(series[0].name);
|
||||
} else {
|
||||
outputColor = staticColors[series[0].rankAtDepth % staticColors.length];
|
||||
}
|
||||
|
||||
if (!chartConfiguration.maxDepth || chartConfiguration.maxDepth === 1) {
|
||||
return outputColor;
|
||||
|
|
|
@ -55,6 +55,11 @@ export interface ChartColorConfiguration {
|
|||
* adjust colors for better a11y. Might be ignored depending on the palette.
|
||||
*/
|
||||
behindText?: boolean;
|
||||
/**
|
||||
* Flag whether a color assignment to a given key should be remembered and re-used the next time the key shows up.
|
||||
* This setting might be ignored based on the palette.
|
||||
*/
|
||||
syncColors?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -151,6 +151,7 @@ export const getDashboardContainerInput = ({
|
|||
description: dashboardStateManager.getDescription(),
|
||||
id: dashboardStateManager.savedDashboard.id || '',
|
||||
useMargins: dashboardStateManager.getUseMargins(),
|
||||
syncColors: dashboardStateManager.getSyncColors(),
|
||||
viewMode: dashboardStateManager.getViewMode(),
|
||||
filters: query.filterManager.getFilters(),
|
||||
query: dashboardStateManager.getQuery(),
|
||||
|
|
|
@ -68,6 +68,7 @@ describe('DashboardState', function () {
|
|||
query: {} as DashboardContainerInput['query'],
|
||||
timeRange: {} as DashboardContainerInput['timeRange'],
|
||||
useMargins: true,
|
||||
syncColors: false,
|
||||
title: 'ultra awesome test dashboard',
|
||||
isFullScreenMode: false,
|
||||
panels: {} as DashboardContainerInput['panels'],
|
||||
|
|
|
@ -404,6 +404,15 @@ export class DashboardStateManager {
|
|||
this.stateContainer.transitions.setOption('useMargins', useMargins);
|
||||
}
|
||||
|
||||
public getSyncColors() {
|
||||
// Existing dashboards that don't define this should default to true.
|
||||
return this.appState.options.syncColors === undefined ? true : this.appState.options.syncColors;
|
||||
}
|
||||
|
||||
public setSyncColors(syncColors: boolean) {
|
||||
this.stateContainer.transitions.setOption('syncColors', syncColors);
|
||||
}
|
||||
|
||||
public getHidePanelTitles() {
|
||||
return this.appState.options.hidePanelTitles;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ export interface DashboardContainerInput extends ContainerInput {
|
|||
timeRange: TimeRange;
|
||||
description?: string;
|
||||
useMargins: boolean;
|
||||
syncColors?: boolean;
|
||||
viewMode: ViewMode;
|
||||
filters: Filter[];
|
||||
title: string;
|
||||
|
@ -93,6 +94,7 @@ export interface InheritedChildInput extends IndexSignature {
|
|||
hidePanelTitles?: boolean;
|
||||
id: string;
|
||||
searchSessionId?: string;
|
||||
syncColors?: boolean;
|
||||
}
|
||||
|
||||
export type DashboardReactContextValue = KibanaReactContextValue<DashboardContainerServices>;
|
||||
|
@ -269,6 +271,7 @@ export class DashboardContainer extends Container<InheritedChildInput, Dashboard
|
|||
hidePanelTitles,
|
||||
filters,
|
||||
searchSessionId,
|
||||
syncColors,
|
||||
} = this.input;
|
||||
return {
|
||||
filters,
|
||||
|
@ -279,6 +282,7 @@ export class DashboardContainer extends Container<InheritedChildInput, Dashboard
|
|||
viewMode,
|
||||
id,
|
||||
searchSessionId,
|
||||
syncColors,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ export class DashboardContainerFactoryDefinition
|
|||
isEmbeddedExternally: false,
|
||||
isFullScreenMode: false,
|
||||
useMargins: true,
|
||||
syncColors: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -348,6 +348,10 @@ export function DashboardTopNav({
|
|||
onUseMarginsChange: (isChecked: boolean) => {
|
||||
dashboardStateManager.setUseMargins(isChecked);
|
||||
},
|
||||
syncColors: dashboardStateManager.getSyncColors(),
|
||||
onSyncColorsChange: (isChecked: boolean) => {
|
||||
dashboardStateManager.setSyncColors(isChecked);
|
||||
},
|
||||
hidePanelTitles: dashboardStateManager.getHidePanelTitles(),
|
||||
onHidePanelTitlesChange: (isChecked: boolean) => {
|
||||
dashboardStateManager.setHidePanelTitles(isChecked);
|
||||
|
|
|
@ -27,17 +27,21 @@ interface Props {
|
|||
onUseMarginsChange: (useMargins: boolean) => void;
|
||||
hidePanelTitles: boolean;
|
||||
onHidePanelTitlesChange: (hideTitles: boolean) => void;
|
||||
syncColors: boolean;
|
||||
onSyncColorsChange: (syncColors: boolean) => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
useMargins: boolean;
|
||||
hidePanelTitles: boolean;
|
||||
syncColors: boolean;
|
||||
}
|
||||
|
||||
export class OptionsMenu extends Component<Props, State> {
|
||||
state = {
|
||||
useMargins: this.props.useMargins,
|
||||
hidePanelTitles: this.props.hidePanelTitles,
|
||||
syncColors: this.props.syncColors,
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
|
@ -56,6 +60,12 @@ export class OptionsMenu extends Component<Props, State> {
|
|||
this.setState({ hidePanelTitles: isChecked });
|
||||
};
|
||||
|
||||
handleSyncColorsChange = (evt: any) => {
|
||||
const isChecked = evt.target.checked;
|
||||
this.props.onSyncColorsChange(isChecked);
|
||||
this.setState({ syncColors: isChecked });
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<EuiForm data-test-subj="dashboardOptionsMenu">
|
||||
|
@ -80,6 +90,17 @@ export class OptionsMenu extends Component<Props, State> {
|
|||
data-test-subj="dashboardPanelTitlesCheckbox"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
||||
<EuiFormRow>
|
||||
<EuiSwitch
|
||||
label={i18n.translate('dashboard.topNav.options.syncColorsBetweenPanelsSwitchLabel', {
|
||||
defaultMessage: 'Sync color palettes across panels',
|
||||
})}
|
||||
checked={this.state.syncColors}
|
||||
onChange={this.handleSyncColorsChange}
|
||||
data-test-subj="dashboardSyncColorsCheckbox"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiForm>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -39,10 +39,14 @@ export function showOptionsPopover({
|
|||
onUseMarginsChange,
|
||||
hidePanelTitles,
|
||||
onHidePanelTitlesChange,
|
||||
syncColors,
|
||||
onSyncColorsChange,
|
||||
}: {
|
||||
anchorElement: HTMLElement;
|
||||
useMargins: boolean;
|
||||
onUseMarginsChange: (useMargins: boolean) => void;
|
||||
syncColors: boolean;
|
||||
onSyncColorsChange: (syncColors: boolean) => void;
|
||||
hidePanelTitles: boolean;
|
||||
onHidePanelTitlesChange: (hideTitles: boolean) => void;
|
||||
}) {
|
||||
|
@ -62,6 +66,8 @@ export function showOptionsPopover({
|
|||
onUseMarginsChange={onUseMarginsChange}
|
||||
hidePanelTitles={hidePanelTitles}
|
||||
onHidePanelTitlesChange={onHidePanelTitlesChange}
|
||||
syncColors={syncColors}
|
||||
onSyncColorsChange={onSyncColorsChange}
|
||||
/>
|
||||
</EuiWrappingPopover>
|
||||
</I18nProvider>
|
||||
|
|
|
@ -78,6 +78,7 @@ export interface DashboardAppState {
|
|||
options: {
|
||||
hidePanelTitles: boolean;
|
||||
useMargins: boolean;
|
||||
syncColors?: boolean;
|
||||
};
|
||||
query: Query | string;
|
||||
filters: Filter[];
|
||||
|
|
|
@ -55,6 +55,11 @@ export type EmbeddableInput = {
|
|||
* Search session id to group searches
|
||||
*/
|
||||
searchSessionId?: string;
|
||||
|
||||
/**
|
||||
* Flag whether colors should be synced with other panels
|
||||
*/
|
||||
syncColors?: boolean;
|
||||
};
|
||||
|
||||
export interface PanelState<E extends EmbeddableInput & { id: string } = { id: string }> {
|
||||
|
|
|
@ -410,6 +410,7 @@ export type EmbeddableInput = {
|
|||
disabledActions?: string[];
|
||||
disableTriggers?: boolean;
|
||||
searchSessionId?: string;
|
||||
syncColors?: boolean;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "EmbeddableInstanceConfiguration" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
|
|
|
@ -82,6 +82,7 @@ export interface IInterpreterRenderHandlers {
|
|||
event: (event: any) => void;
|
||||
hasCompatibleActions?: (event: any) => Promise<boolean>;
|
||||
getRenderMode: () => RenderMode;
|
||||
isSyncColorsEnabled: () => boolean;
|
||||
/**
|
||||
* This uiState interface is actually `PersistedState` from the visualizations plugin,
|
||||
* but expressions cannot know about vis or it creates a mess of circular dependencies.
|
||||
|
|
|
@ -64,6 +64,7 @@ export class ExpressionLoader {
|
|||
this.renderHandler = new ExpressionRenderHandler(element, {
|
||||
onRenderError: params && params.onRenderError,
|
||||
renderMode: params?.renderMode,
|
||||
syncColors: params?.syncColors,
|
||||
hasCompatibleActions: params?.hasCompatibleActions,
|
||||
});
|
||||
this.render$ = this.renderHandler.render$;
|
||||
|
|
|
@ -531,7 +531,7 @@ export interface ExpressionRenderError extends Error {
|
|||
// @public (undocumented)
|
||||
export class ExpressionRenderHandler {
|
||||
// Warning: (ae-forgotten-export) The symbol "ExpressionRenderHandlerParams" needs to be exported by the entry point index.d.ts
|
||||
constructor(element: HTMLElement, { onRenderError, renderMode, hasCompatibleActions, }?: ExpressionRenderHandlerParams);
|
||||
constructor(element: HTMLElement, { onRenderError, renderMode, syncColors, hasCompatibleActions, }?: ExpressionRenderHandlerParams);
|
||||
// (undocumented)
|
||||
destroy: () => void;
|
||||
// (undocumented)
|
||||
|
@ -903,6 +903,8 @@ export interface IExpressionLoaderParams {
|
|||
// (undocumented)
|
||||
searchSessionId?: string;
|
||||
// (undocumented)
|
||||
syncColors?: boolean;
|
||||
// (undocumented)
|
||||
uiState?: unknown;
|
||||
// (undocumented)
|
||||
variables?: Record<string, any>;
|
||||
|
@ -920,6 +922,8 @@ export interface IInterpreterRenderHandlers {
|
|||
// (undocumented)
|
||||
hasCompatibleActions?: (event: any) => Promise<boolean>;
|
||||
// (undocumented)
|
||||
isSyncColorsEnabled: () => boolean;
|
||||
// (undocumented)
|
||||
onDestroy: (fn: () => void) => void;
|
||||
// (undocumented)
|
||||
reload: () => void;
|
||||
|
|
|
@ -170,7 +170,12 @@ export const ReactExpressionRenderer = ({
|
|||
|
||||
errorRenderHandlerRef.current = null;
|
||||
};
|
||||
}, [hasCustomRenderErrorHandler, onEvent]);
|
||||
}, [
|
||||
hasCustomRenderErrorHandler,
|
||||
onEvent,
|
||||
expressionLoaderOptions.renderMode,
|
||||
expressionLoaderOptions.syncColors,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = reload$?.subscribe(() => {
|
||||
|
|
|
@ -31,6 +31,7 @@ export type IExpressionRendererExtraHandlers = Record<string, any>;
|
|||
export interface ExpressionRenderHandlerParams {
|
||||
onRenderError?: RenderErrorHandlerFnType;
|
||||
renderMode?: RenderMode;
|
||||
syncColors?: boolean;
|
||||
hasCompatibleActions?: (event: ExpressionRendererEvent) => Promise<boolean>;
|
||||
}
|
||||
|
||||
|
@ -63,6 +64,7 @@ export class ExpressionRenderHandler {
|
|||
{
|
||||
onRenderError,
|
||||
renderMode,
|
||||
syncColors,
|
||||
hasCompatibleActions = async () => false,
|
||||
}: ExpressionRenderHandlerParams = {}
|
||||
) {
|
||||
|
@ -101,6 +103,9 @@ export class ExpressionRenderHandler {
|
|||
getRenderMode: () => {
|
||||
return renderMode || 'display';
|
||||
},
|
||||
isSyncColorsEnabled: () => {
|
||||
return syncColors || false;
|
||||
},
|
||||
hasCompatibleActions,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ export interface IExpressionLoaderParams {
|
|||
onRenderError?: RenderErrorHandlerFnType;
|
||||
searchSessionId?: string;
|
||||
renderMode?: RenderMode;
|
||||
syncColors?: boolean;
|
||||
hasCompatibleActions?: ExpressionRenderHandlerParams['hasCompatibleActions'];
|
||||
}
|
||||
|
||||
|
|
|
@ -737,6 +737,8 @@ export interface IInterpreterRenderHandlers {
|
|||
// (undocumented)
|
||||
hasCompatibleActions?: (event: any) => Promise<boolean>;
|
||||
// (undocumented)
|
||||
isSyncColorsEnabled: () => boolean;
|
||||
// (undocumented)
|
||||
onDestroy: (fn: () => void) => void;
|
||||
// (undocumented)
|
||||
reload: () => void;
|
||||
|
|
|
@ -12,6 +12,7 @@ export const defaultHandlers: RendererHandlers = {
|
|||
getElementId: () => 'element-id',
|
||||
getFilter: () => 'filter',
|
||||
getRenderMode: () => 'display',
|
||||
isSyncColorsEnabled: () => false,
|
||||
onComplete: (fn) => undefined,
|
||||
onEmbeddableDestroyed: action('onEmbeddableDestroyed'),
|
||||
onEmbeddableInputChange: action('onEmbeddableInputChange'),
|
||||
|
|
|
@ -26,6 +26,9 @@ export const createHandlers = (): RendererHandlers => ({
|
|||
getRenderMode() {
|
||||
return 'display';
|
||||
},
|
||||
isSyncColorsEnabled() {
|
||||
return false;
|
||||
},
|
||||
onComplete(fn: () => void) {
|
||||
this.done = fn;
|
||||
},
|
||||
|
|
|
@ -260,6 +260,7 @@ export class Embeddable
|
|||
handleEvent={this.handleEvent}
|
||||
onData$={this.updateActiveData}
|
||||
renderMode={input.renderMode}
|
||||
syncColors={input.syncColors}
|
||||
hasCompatibleActions={this.hasCompatibleActions}
|
||||
/>,
|
||||
domNode
|
||||
|
|
|
@ -29,6 +29,7 @@ export interface ExpressionWrapperProps {
|
|||
inspectorAdapters?: Partial<DefaultInspectorAdapters> | undefined
|
||||
) => void;
|
||||
renderMode?: RenderMode;
|
||||
syncColors?: boolean;
|
||||
hasCompatibleActions?: ReactExpressionRendererProps['hasCompatibleActions'];
|
||||
}
|
||||
|
||||
|
@ -41,6 +42,7 @@ export function ExpressionWrapper({
|
|||
searchSessionId,
|
||||
onData$,
|
||||
renderMode,
|
||||
syncColors,
|
||||
hasCompatibleActions,
|
||||
}: ExpressionWrapperProps) {
|
||||
return (
|
||||
|
@ -70,6 +72,7 @@ export function ExpressionWrapper({
|
|||
searchSessionId={searchSessionId}
|
||||
onData$={onData$}
|
||||
renderMode={renderMode}
|
||||
syncColors={syncColors}
|
||||
renderError={(errorMessage, error) => (
|
||||
<div data-test-subj="expression-renderer-error">
|
||||
<EuiFlexGroup direction="column" alignItems="center" justifyContent="center">
|
||||
|
|
|
@ -140,6 +140,7 @@ export const getPieRenderer = (dependencies: {
|
|||
paletteService={dependencies.paletteService}
|
||||
onClickValue={onClickValue}
|
||||
renderMode={handlers.getRenderMode()}
|
||||
syncColors={handlers.isSyncColorsEnabled()}
|
||||
/>
|
||||
</I18nProvider>,
|
||||
domNode,
|
||||
|
|
|
@ -71,6 +71,7 @@ describe('PieVisualization component', () => {
|
|||
chartsThemeService,
|
||||
paletteService: chartPluginMock.createPaletteRegistry(),
|
||||
renderMode: 'display' as const,
|
||||
syncColors: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -172,6 +173,7 @@ describe('PieVisualization component', () => {
|
|||
{
|
||||
maxDepth: 2,
|
||||
totalSeries: 5,
|
||||
syncColors: false,
|
||||
behindText: true,
|
||||
},
|
||||
undefined
|
||||
|
|
|
@ -47,12 +47,13 @@ export function PieComponent(
|
|||
paletteService: PaletteRegistry;
|
||||
onClickValue: (data: LensFilterEvent['data']) => void;
|
||||
renderMode: RenderMode;
|
||||
syncColors: boolean;
|
||||
}
|
||||
) {
|
||||
const [firstTable] = Object.values(props.data.tables);
|
||||
const formatters: Record<string, ReturnType<FormatFactory>> = {};
|
||||
|
||||
const { chartsThemeService, paletteService, onClickValue } = props;
|
||||
const { chartsThemeService, paletteService, syncColors, onClickValue } = props;
|
||||
const {
|
||||
shape,
|
||||
groups,
|
||||
|
@ -145,6 +146,7 @@ export function PieComponent(
|
|||
behindText: categoryDisplay !== 'hide',
|
||||
maxDepth: bucketColumns.length,
|
||||
totalSeries: totalSeriesCount,
|
||||
syncColors,
|
||||
},
|
||||
palette.params
|
||||
);
|
||||
|
|
|
@ -18,7 +18,13 @@ import {
|
|||
Fit,
|
||||
} from '@elastic/charts';
|
||||
import { PaletteOutput } from 'src/plugins/charts/public';
|
||||
import { calculateMinInterval, xyChart, XYChart, XYChartProps } from './expression';
|
||||
import {
|
||||
calculateMinInterval,
|
||||
xyChart,
|
||||
XYChart,
|
||||
XYChartProps,
|
||||
XYChartRenderProps,
|
||||
} from './expression';
|
||||
import { LensMultiTable } from '../types';
|
||||
import { Datatable, DatatableRow } from '../../../../../src/plugins/expressions/public';
|
||||
import React from 'react';
|
||||
|
@ -382,6 +388,7 @@ describe('xy_expression', () => {
|
|||
describe('XYChart component', () => {
|
||||
let getFormatSpy: jest.Mock;
|
||||
let convertSpy: jest.Mock;
|
||||
let defaultProps: Omit<XYChartRenderProps, 'data' | 'args'>;
|
||||
|
||||
const dataWithoutFormats: LensMultiTable = {
|
||||
type: 'lens_multitable',
|
||||
|
@ -421,26 +428,25 @@ describe('xy_expression', () => {
|
|||
};
|
||||
|
||||
const getRenderedComponent = (data: LensMultiTable, args: XYArgs) => {
|
||||
return shallow(
|
||||
<XYChart
|
||||
data={data}
|
||||
args={args}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
return shallow(<XYChart {...defaultProps} data={data} args={args} />);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
convertSpy = jest.fn((x) => x);
|
||||
getFormatSpy = jest.fn();
|
||||
getFormatSpy.mockReturnValue({ convert: convertSpy });
|
||||
|
||||
defaultProps = {
|
||||
formatFactory: getFormatSpy,
|
||||
timeZone: 'UTC',
|
||||
renderMode: 'display',
|
||||
chartsThemeService,
|
||||
paletteService,
|
||||
minInterval: 50,
|
||||
onClickValue,
|
||||
onSelectRange,
|
||||
syncColors: false,
|
||||
};
|
||||
});
|
||||
|
||||
test('it renders line', () => {
|
||||
|
@ -448,16 +454,9 @@ describe('xy_expression', () => {
|
|||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{ ...args, layers: [{ ...args.layers[0], seriesType: 'line' }] }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
|
@ -493,6 +492,7 @@ describe('xy_expression', () => {
|
|||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={{
|
||||
...data,
|
||||
dateRange: {
|
||||
|
@ -504,14 +504,7 @@ describe('xy_expression', () => {
|
|||
...args,
|
||||
layers: [{ ...args.layers[0], seriesType: 'line', xScaleType: 'time' }],
|
||||
}}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={undefined}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component.find(Settings).prop('xDomain')).toMatchInlineSnapshot(`
|
||||
|
@ -534,6 +527,7 @@ describe('xy_expression', () => {
|
|||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={{
|
||||
...data,
|
||||
dateRange: {
|
||||
|
@ -542,14 +536,6 @@ describe('xy_expression', () => {
|
|||
},
|
||||
}}
|
||||
args={multiLayerArgs}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -569,6 +555,7 @@ describe('xy_expression', () => {
|
|||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={{
|
||||
...data,
|
||||
dateRange: {
|
||||
|
@ -580,14 +567,6 @@ describe('xy_expression', () => {
|
|||
...args,
|
||||
layers: [{ ...args.layers[0], seriesType: 'line', xScaleType: 'linear' }],
|
||||
}}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component.find(Settings).prop('xDomain')).toBeUndefined();
|
||||
|
@ -597,16 +576,9 @@ describe('xy_expression', () => {
|
|||
const { data, args } = sampleArgs();
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{ ...args, layers: [{ ...args.layers[0], seriesType: 'bar' }] }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
|
@ -619,16 +591,9 @@ describe('xy_expression', () => {
|
|||
const { data, args } = sampleArgs();
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{ ...args, layers: [{ ...args.layers[0], seriesType: 'area' }] }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
|
@ -641,16 +606,9 @@ describe('xy_expression', () => {
|
|||
const { data, args } = sampleArgs();
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{ ...args, layers: [{ ...args.layers[0], seriesType: 'bar_horizontal' }] }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
|
@ -666,20 +624,7 @@ describe('xy_expression', () => {
|
|||
// send empty data to the chart
|
||||
data.tables.first.rows = [];
|
||||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
data={data}
|
||||
args={args}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
const component = shallow(<XYChart {...defaultProps} data={data} args={args} />);
|
||||
|
||||
expect(component.find(BarSeries)).toHaveLength(0);
|
||||
expect(component.find(EmptyPlaceholder).prop('icon')).toBeDefined();
|
||||
|
@ -690,19 +635,12 @@ describe('xy_expression', () => {
|
|||
|
||||
const wrapper = mountWithIntl(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={dateHistogramData}
|
||||
args={{
|
||||
...args,
|
||||
layers: [dateHistogramLayer],
|
||||
}}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -776,19 +714,12 @@ describe('xy_expression', () => {
|
|||
|
||||
const wrapper = mountWithIntl(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={numberHistogramData}
|
||||
args={{
|
||||
...args,
|
||||
layers: [numberLayer],
|
||||
}}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -806,18 +737,7 @@ describe('xy_expression', () => {
|
|||
const { args, data } = sampleArgs();
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<XYChart
|
||||
data={data}
|
||||
args={args}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="noInteractivity"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
<XYChart {...defaultProps} data={data} args={args} renderMode="noInteractivity" />
|
||||
);
|
||||
|
||||
expect(wrapper.find(Settings).first().prop('onBrushEnd')).toBeUndefined();
|
||||
|
@ -837,6 +757,7 @@ describe('xy_expression', () => {
|
|||
|
||||
const wrapper = mountWithIntl(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{
|
||||
...args,
|
||||
|
@ -855,14 +776,6 @@ describe('xy_expression', () => {
|
|||
},
|
||||
],
|
||||
}}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -892,18 +805,7 @@ describe('xy_expression', () => {
|
|||
const { args, data } = sampleArgs();
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<XYChart
|
||||
data={data}
|
||||
args={args}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="noInteractivity"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
<XYChart {...defaultProps} data={data} args={args} renderMode="noInteractivity" />
|
||||
);
|
||||
|
||||
expect(wrapper.find(Settings).first().prop('onElementClick')).toBeUndefined();
|
||||
|
@ -913,16 +815,9 @@ describe('xy_expression', () => {
|
|||
const { data, args } = sampleArgs();
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{ ...args, layers: [{ ...args.layers[0], seriesType: 'bar_stacked' }] }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
|
@ -935,16 +830,9 @@ describe('xy_expression', () => {
|
|||
const { data, args } = sampleArgs();
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{ ...args, layers: [{ ...args.layers[0], seriesType: 'area_stacked' }] }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
|
@ -957,19 +845,12 @@ describe('xy_expression', () => {
|
|||
const { data, args } = sampleArgs();
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{
|
||||
...args,
|
||||
layers: [{ ...args.layers[0], seriesType: 'bar_horizontal_stacked' }],
|
||||
}}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
|
@ -984,6 +865,7 @@ describe('xy_expression', () => {
|
|||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{
|
||||
...args,
|
||||
|
@ -996,14 +878,6 @@ describe('xy_expression', () => {
|
|||
},
|
||||
],
|
||||
}}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -1014,18 +888,7 @@ describe('xy_expression', () => {
|
|||
test('it passes time zone to the series', () => {
|
||||
const { data, args } = sampleArgs();
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
data={data}
|
||||
args={args}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="CEST"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
<XYChart {...defaultProps} data={data} args={args} timeZone="CEST" />
|
||||
);
|
||||
expect(component.find(LineSeries).at(0).prop('timeZone')).toEqual('CEST');
|
||||
expect(component.find(LineSeries).at(1).prop('timeZone')).toEqual('CEST');
|
||||
|
@ -1041,18 +904,7 @@ describe('xy_expression', () => {
|
|||
};
|
||||
delete firstLayer.splitAccessor;
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
data={data}
|
||||
args={{ ...args, layers: [firstLayer] }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
<XYChart {...defaultProps} data={data} args={{ ...args, layers: [firstLayer] }} />
|
||||
);
|
||||
expect(component.find(BarSeries).at(0).prop('enableHistogramMode')).toEqual(true);
|
||||
});
|
||||
|
@ -1062,18 +914,7 @@ describe('xy_expression', () => {
|
|||
const firstLayer: LayerArgs = { ...args.layers[0], seriesType: 'bar', isHistogram: true };
|
||||
delete firstLayer.splitAccessor;
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
data={data}
|
||||
args={{ ...args, layers: [firstLayer] }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
<XYChart {...defaultProps} data={data} args={{ ...args, layers: [firstLayer] }} />
|
||||
);
|
||||
expect(component.find(BarSeries).at(0).prop('enableHistogramMode')).toEqual(false);
|
||||
expect(component.find(BarSeries).at(1).prop('enableHistogramMode')).toEqual(false);
|
||||
|
@ -1087,16 +928,9 @@ describe('xy_expression', () => {
|
|||
delete secondLayer.splitAccessor;
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{ ...args, layers: [firstLayer, secondLayer] }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component.find(LineSeries).at(0).prop('enableHistogramMode')).toEqual(true);
|
||||
|
@ -1107,6 +941,7 @@ describe('xy_expression', () => {
|
|||
const { data, args } = sampleArgs();
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{
|
||||
...args,
|
||||
|
@ -1118,14 +953,6 @@ describe('xy_expression', () => {
|
|||
},
|
||||
],
|
||||
}}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component.find(BarSeries).at(0).prop('enableHistogramMode')).toEqual(true);
|
||||
|
@ -1136,19 +963,12 @@ describe('xy_expression', () => {
|
|||
const { data, args } = sampleArgs();
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{
|
||||
...args,
|
||||
layers: [{ ...args.layers[0], seriesType: 'bar', isHistogram: true }],
|
||||
}}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component.find(BarSeries).at(0).prop('enableHistogramMode')).toEqual(false);
|
||||
|
@ -1541,16 +1361,9 @@ describe('xy_expression', () => {
|
|||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{ ...args, layers: [{ ...args.layers[0], xScaleType: 'ordinal' }] }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component.find(LineSeries).at(0).prop('xScaleType')).toEqual(ScaleType.Ordinal);
|
||||
|
@ -1562,16 +1375,9 @@ describe('xy_expression', () => {
|
|||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={data}
|
||||
args={{ ...args, layers: [{ ...args.layers[0], yScaleType: 'sqrt' }] }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(component.find(LineSeries).at(0).prop('yScaleType')).toEqual(ScaleType.Sqrt);
|
||||
|
@ -1581,20 +1387,7 @@ describe('xy_expression', () => {
|
|||
test('it gets the formatter for the x axis', () => {
|
||||
const { data, args } = sampleArgs();
|
||||
|
||||
shallow(
|
||||
<XYChart
|
||||
data={{ ...data }}
|
||||
args={{ ...args }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
shallow(<XYChart {...defaultProps} data={{ ...data }} args={{ ...args }} />);
|
||||
|
||||
expect(getFormatSpy).toHaveBeenCalledWith({ id: 'string' });
|
||||
});
|
||||
|
@ -1604,16 +1397,9 @@ describe('xy_expression', () => {
|
|||
|
||||
shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={{ ...data }}
|
||||
args={{ ...args, layers: [{ ...args.layers[0], accessors: ['a'] }] }}
|
||||
formatFactory={getFormatSpy}
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
expect(getFormatSpy).toHaveBeenCalledWith({
|
||||
|
@ -1625,20 +1411,7 @@ describe('xy_expression', () => {
|
|||
test('it should pass the formatter function to the axis', () => {
|
||||
const { data, args } = sampleArgs();
|
||||
|
||||
const instance = shallow(
|
||||
<XYChart
|
||||
data={{ ...data }}
|
||||
args={{ ...args }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
const instance = shallow(<XYChart {...defaultProps} data={{ ...data }} args={{ ...args }} />);
|
||||
|
||||
const tickFormatter = instance.find(Axis).first().prop('tickFormat');
|
||||
|
||||
|
@ -1661,20 +1434,7 @@ describe('xy_expression', () => {
|
|||
type: 'lens_xy_tickLabelsConfig',
|
||||
};
|
||||
|
||||
const instance = shallow(
|
||||
<XYChart
|
||||
data={{ ...data }}
|
||||
args={{ ...args }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
const instance = shallow(<XYChart {...defaultProps} data={{ ...data }} args={{ ...args }} />);
|
||||
|
||||
const axisStyle = instance.find(Axis).first().prop('style');
|
||||
|
||||
|
@ -1695,20 +1455,7 @@ describe('xy_expression', () => {
|
|||
type: 'lens_xy_tickLabelsConfig',
|
||||
};
|
||||
|
||||
const instance = shallow(
|
||||
<XYChart
|
||||
data={{ ...data }}
|
||||
args={{ ...args }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
const instance = shallow(<XYChart {...defaultProps} data={{ ...data }} args={{ ...args }} />);
|
||||
|
||||
const axisStyle = instance.find(Axis).at(1).prop('style');
|
||||
|
||||
|
@ -1729,20 +1476,7 @@ describe('xy_expression', () => {
|
|||
type: 'lens_xy_tickLabelsConfig',
|
||||
};
|
||||
|
||||
const instance = shallow(
|
||||
<XYChart
|
||||
data={{ ...data }}
|
||||
args={{ ...args }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
const instance = shallow(<XYChart {...defaultProps} data={{ ...data }} args={{ ...args }} />);
|
||||
|
||||
const axisStyle = instance.find(Axis).first().prop('style');
|
||||
|
||||
|
@ -1763,20 +1497,7 @@ describe('xy_expression', () => {
|
|||
type: 'lens_xy_tickLabelsConfig',
|
||||
};
|
||||
|
||||
const instance = shallow(
|
||||
<XYChart
|
||||
data={{ ...data }}
|
||||
args={{ ...args }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
const instance = shallow(<XYChart {...defaultProps} data={{ ...data }} args={{ ...args }} />);
|
||||
|
||||
const axisStyle = instance.find(Axis).at(1).prop('style');
|
||||
|
||||
|
@ -1864,20 +1585,7 @@ describe('xy_expression', () => {
|
|||
],
|
||||
};
|
||||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
data={data}
|
||||
args={args}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
const component = shallow(<XYChart {...defaultProps} data={data} args={args} />);
|
||||
|
||||
const series = component.find(LineSeries);
|
||||
|
||||
|
@ -1939,20 +1647,7 @@ describe('xy_expression', () => {
|
|||
],
|
||||
};
|
||||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
data={data}
|
||||
args={args}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
const component = shallow(<XYChart {...defaultProps} data={data} args={args} />);
|
||||
|
||||
const series = component.find(LineSeries);
|
||||
|
||||
|
@ -2012,20 +1707,7 @@ describe('xy_expression', () => {
|
|||
],
|
||||
};
|
||||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
data={data}
|
||||
args={args}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
const component = shallow(<XYChart {...defaultProps} data={data} args={args} />);
|
||||
|
||||
expect(component.find(Settings).prop('showLegend')).toEqual(true);
|
||||
});
|
||||
|
@ -2035,20 +1717,13 @@ describe('xy_expression', () => {
|
|||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={{ ...data }}
|
||||
args={{
|
||||
...args,
|
||||
layers: [{ ...args.layers[0], accessors: ['a'], splitAccessor: undefined }],
|
||||
legend: { ...args.legend, isVisible: true, showSingleSeries: true },
|
||||
}}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -2060,19 +1735,12 @@ describe('xy_expression', () => {
|
|||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={{ ...data }}
|
||||
args={{
|
||||
...args,
|
||||
legend: { ...args.legend, isVisible: false },
|
||||
}}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -2084,19 +1752,12 @@ describe('xy_expression', () => {
|
|||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={{ ...data }}
|
||||
args={{
|
||||
...args,
|
||||
legend: { ...args.legend, position: 'top' },
|
||||
}}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -2123,16 +1784,9 @@ describe('xy_expression', () => {
|
|||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
{...defaultProps}
|
||||
data={{ ...data }}
|
||||
args={{ ...args, fittingFunction: 'Carry' }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -2150,18 +1804,7 @@ describe('xy_expression', () => {
|
|||
args.layers[0].accessors = ['a'];
|
||||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
data={{ ...data }}
|
||||
args={{ ...args }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
<XYChart {...defaultProps} data={{ ...data }} args={{ ...args }} />
|
||||
);
|
||||
|
||||
expect(component.find(LineSeries).prop('fit')).toEqual({ type: Fit.None });
|
||||
|
@ -2173,18 +1816,7 @@ describe('xy_expression', () => {
|
|||
args.xTitle = 'My custom x-axis title';
|
||||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
data={{ ...data }}
|
||||
args={{ ...args }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
<XYChart {...defaultProps} data={{ ...data }} args={{ ...args }} />
|
||||
);
|
||||
|
||||
expect(component.find(Axis).at(0).prop('title')).toEqual('My custom x-axis title');
|
||||
|
@ -2201,18 +1833,7 @@ describe('xy_expression', () => {
|
|||
};
|
||||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
data={{ ...data }}
|
||||
args={{ ...args }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
<XYChart {...defaultProps} data={{ ...data }} args={{ ...args }} />
|
||||
);
|
||||
|
||||
const axisStyle = component.find(Axis).first().prop('style');
|
||||
|
@ -2235,18 +1856,7 @@ describe('xy_expression', () => {
|
|||
};
|
||||
|
||||
const component = shallow(
|
||||
<XYChart
|
||||
data={{ ...data }}
|
||||
args={{ ...args }}
|
||||
formatFactory={getFormatSpy}
|
||||
timeZone="UTC"
|
||||
renderMode="display"
|
||||
chartsThemeService={chartsThemeService}
|
||||
paletteService={paletteService}
|
||||
minInterval={50}
|
||||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
/>
|
||||
<XYChart {...defaultProps} data={{ ...data }} args={{ ...args }} />
|
||||
);
|
||||
|
||||
expect(component.find(Axis).at(0).prop('gridLine')).toMatchObject({
|
||||
|
|
|
@ -76,7 +76,7 @@ export interface XYRender {
|
|||
value: XYChartProps;
|
||||
}
|
||||
|
||||
type XYChartRenderProps = XYChartProps & {
|
||||
export type XYChartRenderProps = XYChartProps & {
|
||||
chartsThemeService: ChartsPluginSetup['theme'];
|
||||
paletteService: PaletteRegistry;
|
||||
formatFactory: FormatFactory;
|
||||
|
@ -85,6 +85,7 @@ type XYChartRenderProps = XYChartProps & {
|
|||
onClickValue: (data: LensFilterEvent['data']) => void;
|
||||
onSelectRange: (data: LensBrushEvent['data']) => void;
|
||||
renderMode: RenderMode;
|
||||
syncColors: boolean;
|
||||
};
|
||||
|
||||
export const xyChart: ExpressionFunctionDefinition<
|
||||
|
@ -240,6 +241,7 @@ export const getXyChartRenderer = (dependencies: {
|
|||
onClickValue={onClickValue}
|
||||
onSelectRange={onSelectRange}
|
||||
renderMode={handlers.getRenderMode()}
|
||||
syncColors={handlers.isSyncColorsEnabled()}
|
||||
/>
|
||||
</I18nProvider>,
|
||||
domNode,
|
||||
|
@ -309,6 +311,7 @@ export function XYChart({
|
|||
onClickValue,
|
||||
onSelectRange,
|
||||
renderMode,
|
||||
syncColors,
|
||||
}: XYChartRenderProps) {
|
||||
const { legend, layers, fittingFunction, gridlinesVisibilitySettings, valueLabels } = args;
|
||||
const chartTheme = chartsThemeService.useChartsTheme();
|
||||
|
@ -681,6 +684,7 @@ export function XYChart({
|
|||
maxDepth: 1,
|
||||
behindText: false,
|
||||
totalSeries: colorAssignment.totalSeriesCount,
|
||||
syncColors,
|
||||
},
|
||||
palette.params
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue