mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Lens] Introduce separate dimension groups for mosaic rows and columns (#139214)
* [Lens] Introduce separate dimension groups for mosaic rows and columns * swap labels * fix nits Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Joe Reuter <johannes.reuter@elastic.co>
This commit is contained in:
parent
c771828242
commit
6ed79f42db
22 changed files with 297 additions and 70 deletions
|
@ -311,7 +311,7 @@ function getLensAttributesPartition(
|
|||
const pieConfig: PieVisualizationState = {
|
||||
layers: [
|
||||
{
|
||||
groups: ['col1'],
|
||||
primaryGroups: ['col1'],
|
||||
metric: 'col2',
|
||||
layerId: 'layer1',
|
||||
layerType: 'data',
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
export * from './constants';
|
||||
export * from './types';
|
||||
export * from './visualizations';
|
||||
|
||||
// Note: do not import the expression folder here or the page bundle will be bloated with all
|
||||
// the package
|
||||
|
|
|
@ -63,7 +63,8 @@ export enum EmptySizeRatios {
|
|||
}
|
||||
|
||||
export interface SharedPieLayerState {
|
||||
groups: string[];
|
||||
primaryGroups: string[];
|
||||
secondaryGroups?: string[];
|
||||
metric?: string;
|
||||
numberDisplay: NumberDisplayType;
|
||||
categoryDisplay: CategoryDisplayType;
|
||||
|
|
8
x-pack/plugins/lens/common/visualizations/index.ts
Normal file
8
x-pack/plugins/lens/common/visualizations/index.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export { isPartitionShape } from './partition/utils';
|
11
x-pack/plugins/lens/common/visualizations/partition/utils.ts
Normal file
11
x-pack/plugins/lens/common/visualizations/partition/utils.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { PieChartType } from '../../types';
|
||||
|
||||
export const isPartitionShape = (shape: PieChartType | string) =>
|
||||
['donut', 'pie', 'treemap', 'mosaic', 'waffle'].includes(shape);
|
|
@ -30,7 +30,6 @@ interface PartitionChartMeta {
|
|||
groupLabel: string;
|
||||
maxBuckets: number;
|
||||
isExperimental?: boolean;
|
||||
requiredMinDimensionCount?: number;
|
||||
toolbarPopover: {
|
||||
isDisabled?: boolean;
|
||||
categoryOptions: Array<{
|
||||
|
@ -202,7 +201,6 @@ export const PartitionChartsMeta: Record<PieChartType, PartitionChartMeta> = {
|
|||
legend: {
|
||||
getShowLegendDefault: () => false,
|
||||
},
|
||||
requiredMinDimensionCount: 2,
|
||||
},
|
||||
waffle: {
|
||||
icon: IconChartWaffle,
|
||||
|
|
|
@ -9,9 +9,6 @@ import type { Datatable } from '@kbn/expressions-plugin/public';
|
|||
import type { PieChartType, PieLayerState } from '../../../common/types';
|
||||
import { PartitionChartsMeta } from './partition_charts_meta';
|
||||
|
||||
export const isPartitionShape = (shape: PieChartType | string) =>
|
||||
['donut', 'pie', 'treemap', 'mosaic', 'waffle'].includes(shape);
|
||||
|
||||
export const shouldShowValuesInLegend = (layer: PieLayerState, shape: PieChartType) => {
|
||||
if ('showValues' in PartitionChartsMeta[shape]?.legend) {
|
||||
return layer.showValuesInLegend ?? PartitionChartsMeta[shape]?.legend?.showValues ?? true;
|
||||
|
|
|
@ -65,7 +65,7 @@ describe('suggestions', () => {
|
|||
{
|
||||
layerId: 'first',
|
||||
layerType: layerTypes.DATA,
|
||||
groups: [],
|
||||
primaryGroups: [],
|
||||
metric: 'a',
|
||||
numberDisplay: NumberDisplay.HIDDEN,
|
||||
categoryDisplay: CategoryDisplay.DEFAULT,
|
||||
|
@ -555,7 +555,7 @@ describe('suggestions', () => {
|
|||
{
|
||||
layerId: 'first',
|
||||
layerType: layerTypes.DATA,
|
||||
groups: ['a'],
|
||||
primaryGroups: ['a'],
|
||||
metric: 'b',
|
||||
|
||||
numberDisplay: NumberDisplay.HIDDEN,
|
||||
|
@ -579,9 +579,8 @@ describe('suggestions', () => {
|
|||
{
|
||||
layerId: 'first',
|
||||
layerType: layerTypes.DATA,
|
||||
groups: ['a'],
|
||||
primaryGroups: ['a'],
|
||||
metric: 'b',
|
||||
|
||||
numberDisplay: NumberDisplay.HIDDEN,
|
||||
categoryDisplay: CategoryDisplay.INSIDE,
|
||||
legendDisplay: 'show',
|
||||
|
@ -613,7 +612,7 @@ describe('suggestions', () => {
|
|||
{
|
||||
layerId: 'first',
|
||||
layerType: layerTypes.DATA,
|
||||
groups: [],
|
||||
primaryGroups: [],
|
||||
metric: 'a',
|
||||
|
||||
numberDisplay: NumberDisplay.HIDDEN,
|
||||
|
@ -663,7 +662,7 @@ describe('suggestions', () => {
|
|||
{
|
||||
layerId: 'first',
|
||||
layerType: layerTypes.DATA,
|
||||
groups: ['a', 'b'],
|
||||
primaryGroups: ['a', 'b'],
|
||||
metric: 'e',
|
||||
numberDisplay: NumberDisplay.VALUE,
|
||||
categoryDisplay: CategoryDisplay.DEFAULT,
|
||||
|
@ -712,7 +711,7 @@ describe('suggestions', () => {
|
|||
{
|
||||
layerId: 'first',
|
||||
layerType: layerTypes.DATA,
|
||||
groups: ['a', 'b'],
|
||||
primaryGroups: ['a', 'b'],
|
||||
metric: 'e',
|
||||
numberDisplay: NumberDisplay.PERCENT,
|
||||
categoryDisplay: CategoryDisplay.DEFAULT,
|
||||
|
@ -749,7 +748,7 @@ describe('suggestions', () => {
|
|||
{
|
||||
layerId: 'first',
|
||||
layerType: layerTypes.DATA,
|
||||
groups: ['a'],
|
||||
primaryGroups: ['a'],
|
||||
metric: 'b',
|
||||
|
||||
numberDisplay: NumberDisplay.HIDDEN,
|
||||
|
@ -772,7 +771,7 @@ describe('suggestions', () => {
|
|||
{
|
||||
layerId: 'first',
|
||||
layerType: layerTypes.DATA,
|
||||
groups: ['a'],
|
||||
primaryGroups: ['a'],
|
||||
metric: 'b',
|
||||
|
||||
numberDisplay: NumberDisplay.HIDDEN,
|
||||
|
@ -806,7 +805,7 @@ describe('suggestions', () => {
|
|||
{
|
||||
layerId: 'first',
|
||||
layerType: layerTypes.DATA,
|
||||
groups: [],
|
||||
primaryGroups: [],
|
||||
metric: 'a',
|
||||
|
||||
numberDisplay: NumberDisplay.HIDDEN,
|
||||
|
@ -848,7 +847,7 @@ describe('suggestions', () => {
|
|||
{
|
||||
layerId: 'first',
|
||||
layerType: layerTypes.DATA,
|
||||
groups: ['a', 'b'],
|
||||
primaryGroups: ['a', 'b'],
|
||||
metric: 'c',
|
||||
|
||||
numberDisplay: NumberDisplay.HIDDEN,
|
||||
|
@ -883,7 +882,7 @@ describe('suggestions', () => {
|
|||
{
|
||||
layerId: 'first',
|
||||
layerType: layerTypes.DATA,
|
||||
groups: [],
|
||||
primaryGroups: [],
|
||||
metric: 'a',
|
||||
|
||||
numberDisplay: NumberDisplay.HIDDEN,
|
||||
|
@ -921,7 +920,7 @@ describe('suggestions', () => {
|
|||
{
|
||||
layerId: 'first',
|
||||
layerType: layerTypes.DATA,
|
||||
groups: ['a', 'b'],
|
||||
primaryGroups: ['a', 'b'],
|
||||
metric: 'c',
|
||||
numberDisplay: NumberDisplay.HIDDEN,
|
||||
categoryDisplay: CategoryDisplay.INSIDE,
|
||||
|
|
|
@ -19,10 +19,10 @@ import {
|
|||
NumberDisplay,
|
||||
PieChartTypes,
|
||||
PieVisualizationState,
|
||||
isPartitionShape,
|
||||
} from '../../../common';
|
||||
import type { PieChartType } from '../../../common/types';
|
||||
import { PartitionChartsMeta } from './partition_charts_meta';
|
||||
import { isPartitionShape } from './render_helpers';
|
||||
|
||||
function hasIntervalScale(columns: TableSuggestionColumn[]) {
|
||||
return columns.some((col) => col.operation.scale === 'interval');
|
||||
|
@ -131,13 +131,13 @@ export function suggestions({
|
|||
? {
|
||||
...state.layers[0],
|
||||
layerId: table.layerId,
|
||||
groups: groups.map((col) => col.columnId),
|
||||
primaryGroups: groups.map((col) => col.columnId),
|
||||
metric: metricColumnId,
|
||||
layerType: layerTypes.DATA,
|
||||
}
|
||||
: {
|
||||
layerId: table.layerId,
|
||||
groups: groups.map((col) => col.columnId),
|
||||
primaryGroups: groups.map((col) => col.columnId),
|
||||
metric: metricColumnId,
|
||||
numberDisplay: NumberDisplay.PERCENT,
|
||||
categoryDisplay: CategoryDisplay.DEFAULT,
|
||||
|
@ -196,7 +196,7 @@ export function suggestions({
|
|||
? {
|
||||
...state.layers[0],
|
||||
layerId: table.layerId,
|
||||
groups: groups.map((col) => col.columnId),
|
||||
primaryGroups: groups.map((col) => col.columnId),
|
||||
metric: metricColumnId,
|
||||
categoryDisplay:
|
||||
state.layers[0].categoryDisplay === CategoryDisplay.INSIDE
|
||||
|
@ -206,7 +206,7 @@ export function suggestions({
|
|||
}
|
||||
: {
|
||||
layerId: table.layerId,
|
||||
groups: groups.map((col) => col.columnId),
|
||||
primaryGroups: groups.map((col) => col.columnId),
|
||||
metric: metricColumnId,
|
||||
numberDisplay: NumberDisplay.PERCENT,
|
||||
categoryDisplay: CategoryDisplay.DEFAULT,
|
||||
|
@ -243,14 +243,16 @@ export function suggestions({
|
|||
? {
|
||||
...state.layers[0],
|
||||
layerId: table.layerId,
|
||||
groups: groups.map((col) => col.columnId),
|
||||
primaryGroups: groups[0] ? [groups[0].columnId] : [],
|
||||
secondaryGroups: groups[1] ? [groups[1].columnId] : [],
|
||||
metric: metricColumnId,
|
||||
categoryDisplay: CategoryDisplay.DEFAULT,
|
||||
layerType: layerTypes.DATA,
|
||||
}
|
||||
: {
|
||||
layerId: table.layerId,
|
||||
groups: groups.map((col) => col.columnId),
|
||||
primaryGroups: groups[0] ? [groups[0].columnId] : [],
|
||||
secondaryGroups: groups[1] ? [groups[1].columnId] : [],
|
||||
metric: metricColumnId,
|
||||
numberDisplay: NumberDisplay.PERCENT,
|
||||
categoryDisplay: CategoryDisplay.DEFAULT,
|
||||
|
@ -282,14 +284,14 @@ export function suggestions({
|
|||
? {
|
||||
...state.layers[0],
|
||||
layerId: table.layerId,
|
||||
groups: groups.map((col) => col.columnId),
|
||||
primaryGroups: groups.map((col) => col.columnId),
|
||||
metric: metricColumnId,
|
||||
categoryDisplay: CategoryDisplay.DEFAULT,
|
||||
layerType: layerTypes.DATA,
|
||||
}
|
||||
: {
|
||||
layerId: table.layerId,
|
||||
groups: groups.map((col) => col.columnId),
|
||||
primaryGroups: groups.map((col) => col.columnId),
|
||||
metric: metricColumnId,
|
||||
numberDisplay: NumberDisplay.PERCENT,
|
||||
categoryDisplay: CategoryDisplay.DEFAULT,
|
||||
|
|
|
@ -61,14 +61,16 @@ type GenerateLabelsAstArguments = (
|
|||
|
||||
export const getSortedGroups = (
|
||||
datasource: DatasourcePublicAPI | undefined,
|
||||
layer: PieLayerState
|
||||
layer: PieLayerState,
|
||||
accessor: 'primaryGroups' | 'secondaryGroups' = 'primaryGroups'
|
||||
) => {
|
||||
const originalOrder = datasource
|
||||
?.getTableSpec()
|
||||
.map(({ columnId }: { columnId: string }) => columnId)
|
||||
.filter((columnId: string) => layer.groups.includes(columnId));
|
||||
.filter((columnId: string) => layer[accessor]?.includes(columnId));
|
||||
|
||||
// When we add a column it could be empty, and therefore have no order
|
||||
return Array.from(new Set(originalOrder?.concat(layer.groups)));
|
||||
return Array.from(new Set(originalOrder?.concat(layer[accessor] ?? [])));
|
||||
};
|
||||
|
||||
const prepareDimension = (accessor: string) => {
|
||||
|
@ -262,7 +264,15 @@ function expressionHelper(
|
|||
): Ast | null {
|
||||
const layer = state.layers[0];
|
||||
const datasource = datasourceLayers[layer.layerId];
|
||||
const groups = getSortedGroups(datasource, layer);
|
||||
|
||||
const groups = Array.from(
|
||||
new Set(
|
||||
[
|
||||
getSortedGroups(datasource, layer, 'primaryGroups'),
|
||||
layer.secondaryGroups ? getSortedGroups(datasource, layer, 'secondaryGroups') : [],
|
||||
].flat()
|
||||
)
|
||||
);
|
||||
|
||||
const operations = groups
|
||||
.map((columnId) => ({
|
||||
|
|
|
@ -306,7 +306,7 @@ export function DimensionEditor(
|
|||
paletteService: PaletteRegistry;
|
||||
}
|
||||
) {
|
||||
if (props.accessor !== Object.values(props.state.layers)[0].groups[0]) return null;
|
||||
if (props.accessor !== Object.values(props.state.layers)[0].primaryGroups[0]) return null;
|
||||
return (
|
||||
<PalettePicker
|
||||
palettes={props.paletteService}
|
||||
|
|
|
@ -35,7 +35,7 @@ function getExampleState(): PieVisualizationState {
|
|||
{
|
||||
layerId: LAYER_ID,
|
||||
layerType: layerTypes.DATA,
|
||||
groups: [],
|
||||
primaryGroups: [],
|
||||
metric: undefined,
|
||||
numberDisplay: NumberDisplay.PERCENT,
|
||||
categoryDisplay: CategoryDisplay.DEFAULT,
|
||||
|
@ -84,7 +84,7 @@ describe('pie_visualization', () => {
|
|||
const prevState: PieVisualizationState = {
|
||||
layers: [
|
||||
{
|
||||
groups: ['a'],
|
||||
primaryGroups: ['a'],
|
||||
layerId: LAYER_ID,
|
||||
layerType: layerTypes.DATA,
|
||||
numberDisplay: NumberDisplay.PERCENT,
|
||||
|
|
|
@ -30,7 +30,8 @@ import { PieChartTypes, PieLayerState, PieVisualizationState } from '../../../co
|
|||
function newLayerState(layerId: string): PieLayerState {
|
||||
return {
|
||||
layerId,
|
||||
groups: [],
|
||||
primaryGroups: [],
|
||||
secondaryGroups: undefined,
|
||||
metric: undefined,
|
||||
numberDisplay: NumberDisplay.PERCENT,
|
||||
categoryDisplay: CategoryDisplay.DEFAULT,
|
||||
|
@ -122,21 +123,22 @@ export const getPieVisualization = ({
|
|||
}
|
||||
|
||||
const datasource = frame.datasourceLayers[layer.layerId];
|
||||
const originalOrder = getSortedGroups(datasource, layer);
|
||||
// When we add a column it could be empty, and therefore have no order
|
||||
const sortedColumns: AccessorConfig[] = originalOrder.map((accessor) => ({
|
||||
columnId: accessor,
|
||||
}));
|
||||
|
||||
if (sortedColumns.length) {
|
||||
applyPaletteToColumnConfig(sortedColumns, state, paletteService);
|
||||
}
|
||||
const getPrimaryGroupConfig = (): VisualizationDimensionGroupConfig => {
|
||||
const originalOrder = getSortedGroups(datasource, layer);
|
||||
// When we add a column it could be empty, and therefore have no order
|
||||
const accessors: AccessorConfig[] = originalOrder.map((accessor) => ({
|
||||
columnId: accessor,
|
||||
}));
|
||||
|
||||
const getSliceByGroup = (): VisualizationDimensionGroupConfig => {
|
||||
const baseProps = {
|
||||
if (accessors.length) {
|
||||
applyPaletteToColumnConfig(accessors, state, paletteService);
|
||||
}
|
||||
|
||||
const primaryGroupConfigBaseProps = {
|
||||
required: true,
|
||||
groupId: 'groups',
|
||||
accessors: sortedColumns,
|
||||
groupId: 'primaryGroups',
|
||||
accessors,
|
||||
enableDimensionEditor: true,
|
||||
filterOperations: bucketedOperations,
|
||||
};
|
||||
|
@ -145,33 +147,79 @@ export const getPieVisualization = ({
|
|||
case 'donut':
|
||||
case 'pie':
|
||||
return {
|
||||
...baseProps,
|
||||
...primaryGroupConfigBaseProps,
|
||||
groupLabel: i18n.translate('xpack.lens.pie.sliceGroupLabel', {
|
||||
defaultMessage: 'Slice by',
|
||||
}),
|
||||
dimensionEditorGroupLabel: i18n.translate('xpack.lens.pie.sliceDimensionGroupLabel', {
|
||||
defaultMessage: 'Slice',
|
||||
}),
|
||||
supportsMoreColumns: sortedColumns.length < PartitionChartsMeta.pie.maxBuckets,
|
||||
supportsMoreColumns: accessors.length < PartitionChartsMeta.pie.maxBuckets,
|
||||
dataTestSubj: 'lnsPie_sliceByDimensionPanel',
|
||||
};
|
||||
case 'mosaic':
|
||||
return {
|
||||
...primaryGroupConfigBaseProps,
|
||||
groupLabel: i18n.translate('xpack.lens.pie.verticalAxisLabel', {
|
||||
defaultMessage: 'Vertical axis',
|
||||
}),
|
||||
dimensionEditorGroupLabel: i18n.translate('xpack.lens.pie.verticalAxisDimensionLabel', {
|
||||
defaultMessage: 'Vertical axis',
|
||||
}),
|
||||
supportsMoreColumns: accessors.length === 0,
|
||||
dataTestSubj: 'lnsPie_verticalAxisDimensionPanel',
|
||||
};
|
||||
default:
|
||||
return {
|
||||
...baseProps,
|
||||
...primaryGroupConfigBaseProps,
|
||||
groupLabel: i18n.translate('xpack.lens.pie.treemapGroupLabel', {
|
||||
defaultMessage: 'Group by',
|
||||
}),
|
||||
dimensionEditorGroupLabel: i18n.translate('xpack.lens.pie.treemapDimensionGroupLabel', {
|
||||
defaultMessage: 'Group',
|
||||
}),
|
||||
supportsMoreColumns: sortedColumns.length < PartitionChartsMeta[state.shape].maxBuckets,
|
||||
supportsMoreColumns: accessors.length < PartitionChartsMeta[state.shape].maxBuckets,
|
||||
dataTestSubj: 'lnsPie_groupByDimensionPanel',
|
||||
requiredMinDimensionCount: PartitionChartsMeta[state.shape].requiredMinDimensionCount,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const getMetricGroup = (): VisualizationDimensionGroupConfig => ({
|
||||
const getSecondaryGroupConfig = (): VisualizationDimensionGroupConfig | undefined => {
|
||||
const originalSecondaryOrder = getSortedGroups(datasource, layer, 'secondaryGroups');
|
||||
const accessors = originalSecondaryOrder.map((accessor) => ({
|
||||
columnId: accessor,
|
||||
}));
|
||||
|
||||
const secondaryGroupConfigBaseProps = {
|
||||
required: true,
|
||||
groupId: 'secondaryGroups',
|
||||
accessors,
|
||||
enableDimensionEditor: true,
|
||||
filterOperations: bucketedOperations,
|
||||
};
|
||||
|
||||
switch (state.shape) {
|
||||
case 'mosaic':
|
||||
return {
|
||||
...secondaryGroupConfigBaseProps,
|
||||
groupLabel: i18n.translate('xpack.lens.pie.horizontalAxisLabel', {
|
||||
defaultMessage: 'Horizontal axis',
|
||||
}),
|
||||
dimensionEditorGroupLabel: i18n.translate(
|
||||
'xpack.lens.pie.horizontalAxisDimensionLabel',
|
||||
{
|
||||
defaultMessage: 'Horizontal axis',
|
||||
}
|
||||
),
|
||||
supportsMoreColumns: accessors.length === 0,
|
||||
dataTestSubj: 'lnsPie_horizontalAxisDimensionPanel',
|
||||
};
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const getMetricGroupConfig = (): VisualizationDimensionGroupConfig => ({
|
||||
groupId: 'metric',
|
||||
groupLabel: i18n.translate('xpack.lens.pie.groupsizeLabel', {
|
||||
defaultMessage: 'Size by',
|
||||
|
@ -192,7 +240,9 @@ export const getPieVisualization = ({
|
|||
});
|
||||
|
||||
return {
|
||||
groups: [getSliceByGroup(), getMetricGroup()],
|
||||
groups: [getPrimaryGroupConfig(), getSecondaryGroupConfig(), getMetricGroupConfig()].filter(
|
||||
Boolean
|
||||
) as VisualizationDimensionGroupConfig[],
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -203,8 +253,20 @@ export const getPieVisualization = ({
|
|||
if (l.layerId !== layerId) {
|
||||
return l;
|
||||
}
|
||||
if (groupId === 'groups') {
|
||||
return { ...l, groups: [...l.groups.filter((group) => group !== columnId), columnId] };
|
||||
if (groupId === 'primaryGroups') {
|
||||
return {
|
||||
...l,
|
||||
primaryGroups: [...l.primaryGroups.filter((group) => group !== columnId), columnId],
|
||||
};
|
||||
}
|
||||
if (groupId === 'secondaryGroups') {
|
||||
return {
|
||||
...l,
|
||||
secondaryGroups: [
|
||||
...(l.secondaryGroups?.filter((group) => group !== columnId) || []),
|
||||
columnId,
|
||||
],
|
||||
};
|
||||
}
|
||||
return { ...l, metric: columnId };
|
||||
}),
|
||||
|
@ -221,7 +283,11 @@ export const getPieVisualization = ({
|
|||
if (l.metric === columnId) {
|
||||
return { ...l, metric: undefined };
|
||||
}
|
||||
return { ...l, groups: l.groups.filter((c) => c !== columnId) };
|
||||
return {
|
||||
...l,
|
||||
primaryGroups: l.primaryGroups.filter((c) => c !== columnId),
|
||||
secondaryGroups: l.secondaryGroups?.filter((c) => c !== columnId) ?? undefined,
|
||||
};
|
||||
}),
|
||||
};
|
||||
},
|
||||
|
@ -288,7 +354,7 @@ export const getPieVisualization = ({
|
|||
if (
|
||||
numericColumn &&
|
||||
state.shape === 'waffle' &&
|
||||
layer.groups.length &&
|
||||
layer.primaryGroups.length &&
|
||||
checkTableForContainsSmallValues(frame.activeData[layerId], numericColumn.id, 1)
|
||||
) {
|
||||
warningMessages.push(
|
||||
|
|
|
@ -29,6 +29,7 @@ import {
|
|||
getLensFilterMigrations,
|
||||
getLensDataViewMigrations,
|
||||
commonMigrateMetricIds,
|
||||
commonMigratePartitionChartGroups,
|
||||
} from '../migrations/common_migrations';
|
||||
import {
|
||||
CustomVisualizationMigrations,
|
||||
|
@ -134,7 +135,13 @@ export const makeLensEmbeddableFactory =
|
|||
},
|
||||
'8.5.0': (state) => {
|
||||
const lensState = state as unknown as { attributes: LensDocShape840<VisState840> };
|
||||
const migratedLensState = commonMigrateMetricIds(lensState.attributes);
|
||||
let migratedLensState = commonMigrateMetricIds(lensState.attributes);
|
||||
migratedLensState = commonMigratePartitionChartGroups(
|
||||
migratedLensState as LensDocShape840<{
|
||||
shape: string;
|
||||
layers: Array<{ groups?: string[] }>;
|
||||
}>
|
||||
);
|
||||
return {
|
||||
...lensState,
|
||||
attributes: migratedLensState,
|
||||
|
|
|
@ -7,7 +7,12 @@
|
|||
|
||||
import { DataViewSpec } from '@kbn/data-views-plugin/common';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { getLensDataViewMigrations, getLensFilterMigrations } from './common_migrations';
|
||||
import {
|
||||
getLensDataViewMigrations,
|
||||
getLensFilterMigrations,
|
||||
commonMigratePartitionChartGroups,
|
||||
} from './common_migrations';
|
||||
import { LensDocShape840 } from '..';
|
||||
|
||||
describe('Lens migrations', () => {
|
||||
describe('applying filter migrations', () => {
|
||||
|
@ -106,4 +111,62 @@ describe('Lens migrations', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('migrate partition chart "groups" to new shape', () => {
|
||||
['donut', 'pie', 'treemap', 'mosaic', 'waffle'].forEach((chartType: string) => {
|
||||
it(`should migrate "group" to "primaryGroups" for "${chartType}" chart`, () => {
|
||||
const lensVisualizationSavedObject = {
|
||||
attributes: {
|
||||
state: {
|
||||
visualization: {
|
||||
shape: chartType,
|
||||
layers: [{ groups: ['a'] }],
|
||||
},
|
||||
},
|
||||
} as LensDocShape840<{
|
||||
shape: string;
|
||||
layers: Array<{ groups?: string[] }>;
|
||||
}>,
|
||||
};
|
||||
|
||||
const migratedVisualization = commonMigratePartitionChartGroups(
|
||||
lensVisualizationSavedObject.attributes
|
||||
).state.visualization;
|
||||
|
||||
expect(migratedVisualization.layers[0]).not.toHaveProperty('groups');
|
||||
expect(migratedVisualization.layers[0]).toHaveProperty('primaryGroups', ['a']);
|
||||
});
|
||||
});
|
||||
|
||||
it(`should migrate "group" to "primaryGroups" and "secondaryGroups" for mosaic`, () => {
|
||||
const lensVisualizationSavedObject = {
|
||||
attributes: {
|
||||
state: {
|
||||
visualization: {
|
||||
shape: 'mosaic',
|
||||
layers: [{ groups: ['a', 'b'] }],
|
||||
},
|
||||
},
|
||||
} as LensDocShape840<{
|
||||
shape: string;
|
||||
layers: Array<{ groups?: string[] }>;
|
||||
}>,
|
||||
};
|
||||
|
||||
const migratedVisualization = commonMigratePartitionChartGroups(
|
||||
lensVisualizationSavedObject.attributes
|
||||
).state.visualization;
|
||||
|
||||
expect(migratedVisualization.layers[0]).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"primaryGroups": Array [
|
||||
"a",
|
||||
],
|
||||
"secondaryGroups": Array [
|
||||
"b",
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -31,8 +31,9 @@ import {
|
|||
LensDocShape830,
|
||||
VisStatePre830,
|
||||
LensDocShape840,
|
||||
LensDocShape850,
|
||||
} from './types';
|
||||
import { DOCUMENT_FIELD_NAME, layerTypes, LegacyMetricState } from '../../common';
|
||||
import { DOCUMENT_FIELD_NAME, layerTypes, LegacyMetricState, isPartitionShape } from '../../common';
|
||||
import { LensDocShape } from './saved_object_migrations';
|
||||
|
||||
export const commonRenameOperationsForFormula = (
|
||||
|
@ -438,3 +439,51 @@ export const commonMigrateMetricIds = (
|
|||
|
||||
return newAttributes;
|
||||
};
|
||||
|
||||
export const commonMigratePartitionChartGroups = (
|
||||
attributes: LensDocShape840<{
|
||||
shape: string;
|
||||
layers: Array<{ groups?: string[] }>;
|
||||
}>
|
||||
): LensDocShape850<{
|
||||
shape: string;
|
||||
layers: Array<{ primaryGroups?: string[]; secondaryGroups?: string[] }>;
|
||||
}> => {
|
||||
if (
|
||||
attributes.state.visualization?.layers &&
|
||||
isPartitionShape(attributes.state.visualization.shape)
|
||||
) {
|
||||
return {
|
||||
...attributes,
|
||||
state: {
|
||||
...attributes.state,
|
||||
visualization: {
|
||||
...attributes.state.visualization,
|
||||
layers: attributes.state.visualization.layers.map((l) => {
|
||||
const groups = l.groups;
|
||||
|
||||
if (groups) {
|
||||
delete l.groups;
|
||||
if (attributes.state.visualization.shape === 'mosaic') {
|
||||
return {
|
||||
...l,
|
||||
primaryGroups: [groups[0]],
|
||||
secondaryGroups: groups.length === 2 ? [groups[1]] : undefined,
|
||||
};
|
||||
}
|
||||
return {
|
||||
...l,
|
||||
primaryGroups: groups,
|
||||
};
|
||||
}
|
||||
return l;
|
||||
}),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
return attributes as LensDocShape850<{
|
||||
shape: string;
|
||||
layers: Array<{ primaryGroups?: string[]; secondaryGroups?: string[] }>;
|
||||
}>;
|
||||
};
|
||||
|
|
|
@ -54,6 +54,7 @@ import {
|
|||
commonPreserveOldLegendSizeDefault,
|
||||
getLensDataViewMigrations,
|
||||
commonMigrateMetricIds,
|
||||
commonMigratePartitionChartGroups,
|
||||
} from './common_migrations';
|
||||
|
||||
interface LensDocShapePre710<VisualizationState = unknown> {
|
||||
|
@ -520,6 +521,18 @@ const migrateMetricIds: SavedObjectMigrationFn<LensDocShape840, LensDocShape840>
|
|||
attributes: commonMigrateMetricIds(doc.attributes),
|
||||
});
|
||||
|
||||
const migratePartitionChartGroups: SavedObjectMigrationFn<LensDocShape840, LensDocShape840> = (
|
||||
doc
|
||||
) => ({
|
||||
...doc,
|
||||
attributes: commonMigratePartitionChartGroups(
|
||||
doc.attributes as LensDocShape840<{
|
||||
shape: string;
|
||||
layers: Array<{ groups?: string[] }>;
|
||||
}>
|
||||
),
|
||||
});
|
||||
|
||||
const lensMigrations: SavedObjectMigrationMap = {
|
||||
'7.7.0': removeInvalidAccessors,
|
||||
// The order of these migrations matter, since the timefield migration relies on the aggConfigs
|
||||
|
@ -540,7 +553,7 @@ const lensMigrations: SavedObjectMigrationMap = {
|
|||
enhanceTableRowHeight
|
||||
),
|
||||
'8.3.0': flow(lockOldMetricVisSettings, preserveOldLegendSizeDefault, fixValueLabelsInXY),
|
||||
'8.5.0': flow(migrateMetricIds),
|
||||
'8.5.0': flow(migrateMetricIds, migratePartitionChartGroups),
|
||||
};
|
||||
|
||||
export const getAllMigrations = (
|
||||
|
|
|
@ -272,3 +272,5 @@ export type VisState830 = XYVisualizationState830;
|
|||
|
||||
export type VisState840 = VisState830;
|
||||
export type LensDocShape840<VisualizationState = unknown> = LensDocShape830<VisualizationState>;
|
||||
|
||||
export type LensDocShape850<VisualizationState = unknown> = LensDocShape840<VisualizationState>;
|
||||
|
|
|
@ -138,7 +138,7 @@ function getLensAttributes(
|
|||
layerId: 'layer1',
|
||||
metric: 'ed999e9d-204c-465b-897f-fe1a125b39ed',
|
||||
numberDisplay: 'percent',
|
||||
groups: ['8690befd-fd69-4246-af4a-dd485d2a3b38'],
|
||||
primaryGroups: ['8690befd-fd69-4246-af4a-dd485d2a3b38'],
|
||||
categoryDisplay: 'default',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -116,7 +116,7 @@ function getLensAttributes(
|
|||
layerId: 'layer1',
|
||||
metric: 'ed999e9d-204c-465b-897f-fe1a125b39ed',
|
||||
numberDisplay: 'percent',
|
||||
groups: ['8690befd-fd69-4246-af4a-dd485d2a3b38'],
|
||||
primaryGroups: ['8690befd-fd69-4246-af4a-dd485d2a3b38'],
|
||||
categoryDisplay: 'default',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -103,15 +103,15 @@ Object {
|
|||
"layers": Array [
|
||||
Object {
|
||||
"categoryDisplay": "default",
|
||||
"groups": Array [
|
||||
"col1",
|
||||
],
|
||||
"layerId": "layer1",
|
||||
"layerType": "data",
|
||||
"legendDisplay": "hide",
|
||||
"metric": "col2",
|
||||
"nestedLegend": false,
|
||||
"numberDisplay": "percent",
|
||||
"primaryGroups": Array [
|
||||
"col1",
|
||||
],
|
||||
"showValuesInLegend": true,
|
||||
},
|
||||
],
|
||||
|
|
|
@ -100,7 +100,7 @@ const visConfig: PieVisualizationState = {
|
|||
layers: [
|
||||
{
|
||||
layerId: 'layer1',
|
||||
groups: ['col1'],
|
||||
primaryGroups: ['col1'],
|
||||
metric: 'col2',
|
||||
categoryDisplay: 'default',
|
||||
legendDisplay: 'hide',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue