mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Lens] collapse by for partition charts (#140336)
This commit is contained in:
parent
11b6ca8160
commit
1a30682fce
8 changed files with 386 additions and 50 deletions
|
@ -66,6 +66,7 @@ export interface SharedPieLayerState {
|
|||
primaryGroups: string[];
|
||||
secondaryGroups?: string[];
|
||||
metric?: string;
|
||||
collapseFns?: Record<string, string>;
|
||||
numberDisplay: NumberDisplayType;
|
||||
categoryDisplay: CategoryDisplayType;
|
||||
legendDisplay: LegendDisplayType;
|
||||
|
|
|
@ -249,6 +249,52 @@ describe('LayerPanel', () => {
|
|||
expect(group).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should tell the user to remove the correct number of dimensions', async () => {
|
||||
mockVisualization.getConfiguration.mockReturnValue({
|
||||
groups: [
|
||||
{
|
||||
groupLabel: 'A',
|
||||
groupId: 'a',
|
||||
accessors: [{ columnId: 'x' }],
|
||||
filterOperations: () => true,
|
||||
supportsMoreColumns: false,
|
||||
dataTestSubj: 'lnsGroup',
|
||||
dimensionsTooMany: 1,
|
||||
},
|
||||
{
|
||||
groupLabel: 'A',
|
||||
groupId: 'a',
|
||||
accessors: [{ columnId: 'x' }],
|
||||
filterOperations: () => true,
|
||||
supportsMoreColumns: false,
|
||||
dataTestSubj: 'lnsGroup',
|
||||
dimensionsTooMany: -1,
|
||||
},
|
||||
{
|
||||
groupLabel: 'B',
|
||||
groupId: 'b',
|
||||
accessors: [],
|
||||
filterOperations: () => true,
|
||||
supportsMoreColumns: true,
|
||||
dataTestSubj: 'lnsGroup',
|
||||
dimensionsTooMany: 3,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { instance } = await mountWithProvider(<LayerPanel {...getDefaultProps()} />);
|
||||
|
||||
const groups = instance.find(EuiFormRow);
|
||||
|
||||
expect(groups.findWhere((e) => e.prop('error') === 'Please remove a dimension')).toHaveLength(
|
||||
1
|
||||
);
|
||||
expect(
|
||||
groups.findWhere((e) => e.prop('error') === 'Please remove 3 dimensions')
|
||||
).toHaveLength(1);
|
||||
expect(groups.findWhere((e) => e.prop('error') === '')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should render the required warning when only one group is configured (with requiredMinDimensionCount)', async () => {
|
||||
mockVisualization.getConfiguration.mockReturnValue({
|
||||
groups: [
|
||||
|
|
|
@ -370,26 +370,36 @@ export function LayerPanel(
|
|||
</header>
|
||||
|
||||
{groups.map((group, groupIndex) => {
|
||||
let isMissing = false;
|
||||
let errorText: string = '';
|
||||
|
||||
if (!isEmptyLayer) {
|
||||
if (group.requiredMinDimensionCount) {
|
||||
isMissing = group.accessors.length < group.requiredMinDimensionCount;
|
||||
} else if (group.required) {
|
||||
isMissing = group.accessors.length === 0;
|
||||
}
|
||||
}
|
||||
|
||||
const isMissingError = group.requiredMinDimensionCount
|
||||
? i18n.translate('xpack.lens.editorFrame.requiresTwoOrMoreFieldsWarningLabel', {
|
||||
defaultMessage: 'Requires {requiredMinDimensionCount} fields',
|
||||
values: {
|
||||
requiredMinDimensionCount: group.requiredMinDimensionCount,
|
||||
},
|
||||
})
|
||||
: i18n.translate('xpack.lens.editorFrame.requiresFieldWarningLabel', {
|
||||
errorText = i18n.translate(
|
||||
'xpack.lens.editorFrame.requiresTwoOrMoreFieldsWarningLabel',
|
||||
{
|
||||
defaultMessage: 'Requires {requiredMinDimensionCount} fields',
|
||||
values: {
|
||||
requiredMinDimensionCount: group.requiredMinDimensionCount,
|
||||
},
|
||||
}
|
||||
);
|
||||
} else if (group.required && group.accessors.length === 0) {
|
||||
errorText = i18n.translate('xpack.lens.editorFrame.requiresFieldWarningLabel', {
|
||||
defaultMessage: 'Requires field',
|
||||
});
|
||||
} else if (group.dimensionsTooMany && group.dimensionsTooMany > 0) {
|
||||
errorText = i18n.translate(
|
||||
'xpack.lens.editorFrame.tooManyDimensionsSingularWarningLabel',
|
||||
{
|
||||
defaultMessage:
|
||||
'Please remove {dimensionsTooMany, plural, one {a dimension} other {{dimensionsTooMany} dimensions}}',
|
||||
values: {
|
||||
dimensionsTooMany: group.dimensionsTooMany,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
const isOptional = !group.required && !group.suggestedValue;
|
||||
return (
|
||||
<EuiFormRow
|
||||
|
@ -425,8 +435,8 @@ export function LayerPanel(
|
|||
}
|
||||
labelType="legend"
|
||||
key={group.groupId}
|
||||
isInvalid={isMissing}
|
||||
error={isMissing ? isMissingError : []}
|
||||
isInvalid={Boolean(errorText)}
|
||||
error={errorText}
|
||||
>
|
||||
<>
|
||||
{group.accessors.length ? (
|
||||
|
|
|
@ -712,6 +712,7 @@ export type VisualizationDimensionGroupConfig = SharedDimensionProps & {
|
|||
groupId: string;
|
||||
accessors: AccessorConfig[];
|
||||
supportsMoreColumns: boolean;
|
||||
dimensionsTooMany?: number;
|
||||
/** If required, a warning will appear if accessors are empty */
|
||||
required?: boolean;
|
||||
requiredMinDimensionCount?: number;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { Ast } from '@kbn/interpreter';
|
||||
import type { Ast, AstFunction } from '@kbn/interpreter';
|
||||
import { Position } from '@elastic/charts';
|
||||
import type { PaletteOutput, PaletteRegistry } from '@kbn/coloring';
|
||||
|
||||
|
@ -23,6 +23,7 @@ import {
|
|||
LegendDisplay,
|
||||
} from '../../../common';
|
||||
import { getDefaultVisualValuesForLayer } from '../../shared_components/datasource_default_values';
|
||||
import { isCollapsed } from './visualization';
|
||||
|
||||
interface Attributes {
|
||||
isPreview: boolean;
|
||||
|
@ -142,7 +143,10 @@ const generateCommonArguments: GenerateExpressionAstArguments = (
|
|||
) => {
|
||||
return {
|
||||
labels: generateCommonLabelsAstArgs(state, attributes, layer),
|
||||
buckets: operations.map((o) => o.columnId).map(prepareDimension),
|
||||
buckets: operations
|
||||
.filter(({ columnId }) => !isCollapsed(columnId, layer))
|
||||
.map(({ columnId }) => columnId)
|
||||
.map(prepareDimension),
|
||||
metric: layer.metric ? [prepareDimension(layer.metric)] : [],
|
||||
legendDisplay: [attributes.isPreview ? LegendDisplay.HIDE : layer.legendDisplay],
|
||||
legendPosition: [layer.legendPosition || Position.Right],
|
||||
|
@ -218,6 +222,7 @@ const generateMosaicVisAst: GenerateExpressionAstFunction = (...rest) => ({
|
|||
...generateCommonArguments(...rest),
|
||||
// flip order of bucket dimensions so the rows are fetched before the columns to keep them stable
|
||||
buckets: rest[2]
|
||||
.filter(({ columnId }) => !isCollapsed(columnId, rest[3]))
|
||||
.reverse()
|
||||
.map((o) => o.columnId)
|
||||
.map(prepareDimension),
|
||||
|
@ -298,6 +303,19 @@ function expressionHelper(
|
|||
type: 'expression',
|
||||
chain: [
|
||||
...(datasourceAst ? datasourceAst.chain : []),
|
||||
...groups
|
||||
.filter((columnId) => layer.collapseFns?.[columnId])
|
||||
.map((columnId) => {
|
||||
return {
|
||||
type: 'function',
|
||||
function: 'lens_collapse',
|
||||
arguments: {
|
||||
by: groups.filter((chk) => chk !== columnId),
|
||||
metric: [layer.metric],
|
||||
fn: [layer.collapseFns![columnId]!],
|
||||
},
|
||||
} as AstFunction;
|
||||
}),
|
||||
...(visualizationAst ? visualizationAst.chain : []),
|
||||
],
|
||||
};
|
||||
|
|
|
@ -31,6 +31,8 @@ import {
|
|||
} from '../../shared_components';
|
||||
import { getDefaultVisualValuesForLayer } from '../../shared_components/datasource_default_values';
|
||||
import { shouldShowValuesInLegend } from './render_helpers';
|
||||
import { CollapseSetting } from '../../shared_components/collapse_setting';
|
||||
import { isCollapsed } from './visualization';
|
||||
|
||||
const legendOptions: Array<{
|
||||
value: SharedPieLayerState['legendDisplay'];
|
||||
|
@ -306,14 +308,46 @@ export function DimensionEditor(
|
|||
paletteService: PaletteRegistry;
|
||||
}
|
||||
) {
|
||||
if (props.accessor !== Object.values(props.state.layers)[0].primaryGroups[0]) return null;
|
||||
const currentLayer = props.state.layers.find((layer) => layer.layerId === props.layerId);
|
||||
|
||||
if (!currentLayer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const firstNonCollapsedColumnId = currentLayer.primaryGroups.find(
|
||||
(columnId) => !isCollapsed(columnId, currentLayer)
|
||||
);
|
||||
|
||||
return (
|
||||
<PalettePicker
|
||||
palettes={props.paletteService}
|
||||
activePalette={props.state.palette}
|
||||
setPalette={(newPalette) => {
|
||||
props.setState({ ...props.state, palette: newPalette });
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
{props.accessor === firstNonCollapsedColumnId && (
|
||||
<PalettePicker
|
||||
palettes={props.paletteService}
|
||||
activePalette={props.state.palette}
|
||||
setPalette={(newPalette) => {
|
||||
props.setState({ ...props.state, palette: newPalette });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<CollapseSetting
|
||||
value={currentLayer?.collapseFns?.[props.accessor] || ''}
|
||||
onChange={(collapseFn: string) => {
|
||||
props.setState({
|
||||
...props.state,
|
||||
layers: props.state.layers.map((layer) =>
|
||||
layer.layerId !== props.layerId
|
||||
? layer
|
||||
: {
|
||||
...layer,
|
||||
collapseFns: {
|
||||
...layer.collapseFns,
|
||||
[props.accessor]: collapseFn,
|
||||
},
|
||||
}
|
||||
),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ import { chartPluginMock } from '@kbn/charts-plugin/public/mocks';
|
|||
import { createMockDatasource, createMockFramePublicAPI } from '../../mocks';
|
||||
import { FramePublicAPI } from '../../types';
|
||||
import { themeServiceMock } from '@kbn/core/public/mocks';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { PartitionChartsMeta } from './partition_charts_meta';
|
||||
|
||||
jest.mock('../../id_generator');
|
||||
|
||||
|
@ -59,10 +61,26 @@ function mockFrame(): FramePublicAPI {
|
|||
// Just a basic bootstrap here to kickstart the tests
|
||||
describe('pie_visualization', () => {
|
||||
describe('#getErrorMessages', () => {
|
||||
it('returns undefined if no error is raised', () => {
|
||||
const error = pieVisualization.getErrorMessages(getExampleState());
|
||||
describe('too many dimensions', () => {
|
||||
const state = { ...getExampleState(), shape: PieChartTypes.MOSAIC };
|
||||
const colIds = new Array(PartitionChartsMeta.mosaic.maxBuckets + 1)
|
||||
.fill(undefined)
|
||||
.map((_, i) => String(i + 1));
|
||||
|
||||
expect(error).not.toBeDefined();
|
||||
state.layers[0].primaryGroups = colIds.slice(0, 2);
|
||||
state.layers[0].secondaryGroups = colIds.slice(2);
|
||||
|
||||
it('returns error', () => {
|
||||
expect(pieVisualization.getErrorMessages(state)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("doesn't count collapsed dimensions", () => {
|
||||
state.layers[0].collapseFns = {
|
||||
[colIds[0]]: 'some-fn',
|
||||
};
|
||||
|
||||
expect(pieVisualization.getErrorMessages(state)).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -111,4 +129,147 @@ describe('pie_visualization', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#removeDimension', () => {
|
||||
it('removes corresponding collapse function if exists', () => {
|
||||
const state = getExampleState();
|
||||
|
||||
const colIds = ['1', '2', '3', '4'];
|
||||
|
||||
state.layers[0].primaryGroups = colIds;
|
||||
|
||||
state.layers[0].collapseFns = {
|
||||
'1': 'sum',
|
||||
'3': 'max',
|
||||
};
|
||||
|
||||
const newState = pieVisualization.removeDimension({
|
||||
layerId: LAYER_ID,
|
||||
columnId: '3',
|
||||
prevState: state,
|
||||
frame: mockFrame(),
|
||||
});
|
||||
|
||||
expect(newState.layers[0].collapseFns).not.toHaveProperty('3');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getConfiguration', () => {
|
||||
it('assigns correct icons to accessors', () => {
|
||||
const colIds = ['1', '2', '3', '4'];
|
||||
|
||||
const frame = mockFrame();
|
||||
frame.datasourceLayers[LAYER_ID]!.getTableSpec = () =>
|
||||
colIds.map((id) => ({ columnId: id, fields: [] }));
|
||||
|
||||
const state = getExampleState();
|
||||
state.layers[0].primaryGroups = colIds;
|
||||
state.layers[0].collapseFns = {
|
||||
'1': 'sum',
|
||||
'3': 'max',
|
||||
};
|
||||
const configuration = pieVisualization.getConfiguration({
|
||||
state,
|
||||
frame,
|
||||
layerId: state.layers[0].layerId,
|
||||
});
|
||||
|
||||
// palette should be assigned to the first non-collapsed dimension
|
||||
expect(configuration.groups[0].accessors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"columnId": "1",
|
||||
"triggerIcon": "aggregate",
|
||||
},
|
||||
Object {
|
||||
"columnId": "2",
|
||||
"palette": Array [
|
||||
"red",
|
||||
"black",
|
||||
],
|
||||
"triggerIcon": "colorBy",
|
||||
},
|
||||
Object {
|
||||
"columnId": "3",
|
||||
"triggerIcon": "aggregate",
|
||||
},
|
||||
Object {
|
||||
"columnId": "4",
|
||||
"triggerIcon": undefined,
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
||||
const mosaicState = getExampleState();
|
||||
mosaicState.shape = PieChartTypes.MOSAIC;
|
||||
mosaicState.layers[0].primaryGroups = colIds.slice(0, 2);
|
||||
mosaicState.layers[0].secondaryGroups = colIds.slice(2);
|
||||
mosaicState.layers[0].collapseFns = {
|
||||
'1': 'sum',
|
||||
'3': 'max',
|
||||
};
|
||||
const mosaicConfiguration = pieVisualization.getConfiguration({
|
||||
state: mosaicState,
|
||||
frame,
|
||||
layerId: mosaicState.layers[0].layerId,
|
||||
});
|
||||
|
||||
expect(mosaicConfiguration.groups.map(({ accessors }) => accessors)).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
Object {
|
||||
"columnId": "1",
|
||||
"triggerIcon": "aggregate",
|
||||
},
|
||||
Object {
|
||||
"columnId": "2",
|
||||
"palette": Array [
|
||||
"red",
|
||||
"black",
|
||||
],
|
||||
"triggerIcon": "colorBy",
|
||||
},
|
||||
],
|
||||
Array [
|
||||
Object {
|
||||
"columnId": "3",
|
||||
"triggerIcon": "aggregate",
|
||||
},
|
||||
Object {
|
||||
"columnId": "4",
|
||||
"triggerIcon": undefined,
|
||||
},
|
||||
],
|
||||
Array [],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it("doesn't count collapsed columns toward the dimension limits", () => {
|
||||
const colIds = new Array(PartitionChartsMeta.pie.maxBuckets)
|
||||
.fill(undefined)
|
||||
.map((_, i) => String(i + 1));
|
||||
|
||||
const frame = mockFrame();
|
||||
frame.datasourceLayers[LAYER_ID]!.getTableSpec = () =>
|
||||
colIds.map((id) => ({ columnId: id, fields: [] }));
|
||||
|
||||
const state = getExampleState();
|
||||
state.layers[0].primaryGroups = colIds;
|
||||
|
||||
const getConfig = (_state: PieVisualizationState) =>
|
||||
pieVisualization.getConfiguration({
|
||||
state: _state,
|
||||
frame,
|
||||
layerId: state.layers[0].layerId,
|
||||
});
|
||||
|
||||
expect(getConfig(state).groups[0].supportsMoreColumns).toBeFalsy();
|
||||
|
||||
const stateWithCollapsed = cloneDeep(state);
|
||||
stateWithCollapsed.layers[0].collapseFns = { '1': 'sum' };
|
||||
|
||||
expect(getConfig(stateWithCollapsed).groups[0].supportsMoreColumns).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,6 +13,7 @@ import type { PaletteRegistry } from '@kbn/coloring';
|
|||
import { ThemeServiceStart } from '@kbn/core/public';
|
||||
import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import { VIS_EVENT_TO_TRIGGER } from '@kbn/visualizations-plugin/public';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import type {
|
||||
Visualization,
|
||||
OperationMetadata,
|
||||
|
@ -45,18 +46,28 @@ const bucketedOperations = (op: OperationMetadata) => op.isBucketed;
|
|||
const numberMetricOperations = (op: OperationMetadata) =>
|
||||
!op.isBucketed && op.dataType === 'number' && !op.isStaticValue;
|
||||
|
||||
export const isCollapsed = (columnId: string, layer: PieLayerState) =>
|
||||
Boolean(layer.collapseFns?.[columnId]);
|
||||
|
||||
const applyPaletteToColumnConfig = (
|
||||
columns: AccessorConfig[],
|
||||
{ palette }: PieVisualizationState,
|
||||
layer: PieLayerState,
|
||||
palette: PieVisualizationState['palette'],
|
||||
paletteService: PaletteRegistry
|
||||
) => {
|
||||
columns[0] = {
|
||||
columnId: columns[0].columnId,
|
||||
triggerIcon: 'colorBy',
|
||||
palette: paletteService
|
||||
.get(palette?.name || 'default')
|
||||
.getCategoricalColors(10, palette?.params),
|
||||
};
|
||||
const firstNonCollapsedColumnIdx = columns.findIndex(
|
||||
(column) => !isCollapsed(column.columnId, layer)
|
||||
);
|
||||
|
||||
if (firstNonCollapsedColumnIdx > -1) {
|
||||
columns[firstNonCollapsedColumnIdx] = {
|
||||
columnId: columns[firstNonCollapsedColumnIdx].columnId,
|
||||
triggerIcon: 'colorBy',
|
||||
palette: paletteService
|
||||
.get(palette?.name || 'default')
|
||||
.getCategoricalColors(10, palette?.params),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const getPieVisualization = ({
|
||||
|
@ -129,10 +140,11 @@ export const getPieVisualization = ({
|
|||
// When we add a column it could be empty, and therefore have no order
|
||||
const accessors: AccessorConfig[] = originalOrder.map((accessor) => ({
|
||||
columnId: accessor,
|
||||
triggerIcon: isCollapsed(accessor, layer) ? ('aggregate' as const) : undefined,
|
||||
}));
|
||||
|
||||
if (accessors.length) {
|
||||
applyPaletteToColumnConfig(accessors, state, paletteService);
|
||||
applyPaletteToColumnConfig(accessors, layer, state.palette, paletteService);
|
||||
}
|
||||
|
||||
const primaryGroupConfigBaseProps = {
|
||||
|
@ -143,6 +155,11 @@ export const getPieVisualization = ({
|
|||
filterOperations: bucketedOperations,
|
||||
};
|
||||
|
||||
const totalNonCollapsedAccessors = accessors.reduce(
|
||||
(total, { columnId }) => total + (isCollapsed(columnId, layer) ? 0 : 1),
|
||||
0
|
||||
);
|
||||
|
||||
switch (state.shape) {
|
||||
case 'donut':
|
||||
case 'pie':
|
||||
|
@ -154,7 +171,8 @@ export const getPieVisualization = ({
|
|||
dimensionEditorGroupLabel: i18n.translate('xpack.lens.pie.sliceDimensionGroupLabel', {
|
||||
defaultMessage: 'Slice',
|
||||
}),
|
||||
supportsMoreColumns: accessors.length < PartitionChartsMeta.pie.maxBuckets,
|
||||
supportsMoreColumns: totalNonCollapsedAccessors < PartitionChartsMeta.pie.maxBuckets,
|
||||
dimensionsTooMany: totalNonCollapsedAccessors - PartitionChartsMeta.pie.maxBuckets,
|
||||
dataTestSubj: 'lnsPie_sliceByDimensionPanel',
|
||||
};
|
||||
case 'mosaic':
|
||||
|
@ -166,7 +184,8 @@ export const getPieVisualization = ({
|
|||
dimensionEditorGroupLabel: i18n.translate('xpack.lens.pie.verticalAxisDimensionLabel', {
|
||||
defaultMessage: 'Vertical axis',
|
||||
}),
|
||||
supportsMoreColumns: accessors.length === 0,
|
||||
supportsMoreColumns: totalNonCollapsedAccessors === 0,
|
||||
dimensionsTooMany: totalNonCollapsedAccessors - 1,
|
||||
dataTestSubj: 'lnsPie_verticalAxisDimensionPanel',
|
||||
};
|
||||
default:
|
||||
|
@ -178,7 +197,10 @@ export const getPieVisualization = ({
|
|||
dimensionEditorGroupLabel: i18n.translate('xpack.lens.pie.treemapDimensionGroupLabel', {
|
||||
defaultMessage: 'Group',
|
||||
}),
|
||||
supportsMoreColumns: accessors.length < PartitionChartsMeta[state.shape].maxBuckets,
|
||||
supportsMoreColumns:
|
||||
totalNonCollapsedAccessors < PartitionChartsMeta[state.shape].maxBuckets,
|
||||
dimensionsTooMany:
|
||||
totalNonCollapsedAccessors - PartitionChartsMeta[state.shape].maxBuckets,
|
||||
dataTestSubj: 'lnsPie_groupByDimensionPanel',
|
||||
};
|
||||
}
|
||||
|
@ -188,6 +210,7 @@ export const getPieVisualization = ({
|
|||
const originalSecondaryOrder = getSortedGroups(datasource, layer, 'secondaryGroups');
|
||||
const accessors = originalSecondaryOrder.map((accessor) => ({
|
||||
columnId: accessor,
|
||||
triggerIcon: isCollapsed(accessor, layer) ? ('aggregate' as const) : undefined,
|
||||
}));
|
||||
|
||||
const secondaryGroupConfigBaseProps = {
|
||||
|
@ -198,6 +221,11 @@ export const getPieVisualization = ({
|
|||
filterOperations: bucketedOperations,
|
||||
};
|
||||
|
||||
const totalNonCollapsedAccessors = accessors.reduce(
|
||||
(total, { columnId }) => total + (isCollapsed(columnId, layer) ? 0 : 1),
|
||||
0
|
||||
);
|
||||
|
||||
switch (state.shape) {
|
||||
case 'mosaic':
|
||||
return {
|
||||
|
@ -211,7 +239,8 @@ export const getPieVisualization = ({
|
|||
defaultMessage: 'Horizontal axis',
|
||||
}
|
||||
),
|
||||
supportsMoreColumns: accessors.length === 0,
|
||||
supportsMoreColumns: totalNonCollapsedAccessors === 0,
|
||||
dimensionsTooMany: totalNonCollapsedAccessors - 1,
|
||||
dataTestSubj: 'lnsPie_horizontalAxisDimensionPanel',
|
||||
};
|
||||
default:
|
||||
|
@ -280,13 +309,21 @@ export const getPieVisualization = ({
|
|||
return l;
|
||||
}
|
||||
|
||||
if (l.metric === columnId) {
|
||||
return { ...l, metric: undefined };
|
||||
const newLayer = { ...l };
|
||||
|
||||
if (l.collapseFns?.[columnId]) {
|
||||
const newCollapseFns = { ...l.collapseFns };
|
||||
delete newCollapseFns[columnId];
|
||||
newLayer.collapseFns = newCollapseFns;
|
||||
}
|
||||
|
||||
if (newLayer.metric === columnId) {
|
||||
return { ...newLayer, metric: undefined };
|
||||
}
|
||||
return {
|
||||
...l,
|
||||
primaryGroups: l.primaryGroups.filter((c) => c !== columnId),
|
||||
secondaryGroups: l.secondaryGroups?.filter((c) => c !== columnId) ?? undefined,
|
||||
...newLayer,
|
||||
primaryGroups: newLayer.primaryGroups.filter((c) => c !== columnId),
|
||||
secondaryGroups: newLayer.secondaryGroups?.filter((c) => c !== columnId) ?? undefined,
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
@ -386,7 +423,35 @@ export const getPieVisualization = ({
|
|||
},
|
||||
|
||||
getErrorMessages(state) {
|
||||
// not possible to break it?
|
||||
return undefined;
|
||||
const hasTooManyBucketDimensions = state.layers
|
||||
.map(
|
||||
(layer) =>
|
||||
Array.from(new Set([...layer.primaryGroups, ...(layer.secondaryGroups ?? [])])).filter(
|
||||
(columnId) => !isCollapsed(columnId, layer)
|
||||
).length > PartitionChartsMeta[state.shape].maxBuckets
|
||||
)
|
||||
.some(Boolean);
|
||||
|
||||
return hasTooManyBucketDimensions
|
||||
? [
|
||||
{
|
||||
shortMessage: i18n.translate('xpack.lens.pie.tooManyDimensions', {
|
||||
defaultMessage: 'Your visualization has too many dimensions.',
|
||||
}),
|
||||
longMessage: (
|
||||
<span>
|
||||
{i18n.translate('xpack.lens.pie.tooManyDimensionsLong', {
|
||||
defaultMessage:
|
||||
'Your visualization has too many dimensions. Please follow the instructions in the layer panel.',
|
||||
})}
|
||||
<EuiSpacer size="s" />
|
||||
{i18n.translate('xpack.lens.pie.collapsedDimensionsDontCount', {
|
||||
defaultMessage: "(Collapsed dimensions don't count toward this limit.)",
|
||||
})}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
]
|
||||
: [];
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue