css`
- ${partitionVisWrapperStyle};
+export const partitionVisContainerStyle = css`
+ min-height: 0;
+ min-width: 0;
+ margin-left: auto;
+ margin-right: auto;
+ width: 100%;
+ height: 100%;
+`;
+
+export const partitionVisContainerWithToggleStyleFactory = (theme: EuiThemeComputed) => css`
+ ${partitionVisContainerStyle}
+ inset: 0;
position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
padding: ${theme.size.s};
- margin-left: auto;
- margin-right: auto;
- overflow: hidden;
`;
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.test.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.test.tsx
index ddade06c2c7e0..001f2390799e6 100644
--- a/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.test.tsx
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.test.tsx
@@ -221,7 +221,9 @@ describe('PartitionVisComponent', function () {
} as unknown as Datatable;
const newProps = { ...wrapperProps, visData: newVisData };
const component = mount(
);
- expect(findTestSubject(component, 'pieVisualizationError').text()).toEqual('No results found');
+ expect(findTestSubject(component, 'partitionVisEmptyValues').text()).toEqual(
+ 'No results found'
+ );
});
it('renders the no results component if there are negative values', () => {
@@ -250,8 +252,8 @@ describe('PartitionVisComponent', function () {
} as unknown as Datatable;
const newProps = { ...wrapperProps, visData: newVisData };
const component = mount(
);
- expect(findTestSubject(component, 'pieVisualizationError').text()).toEqual(
- "Pie/donut charts can't render with negative values."
+ expect(findTestSubject(component, 'partitionVisNegativeValues').text()).toEqual(
+ "Pie chart can't render with negative values."
);
});
});
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx
index cc96baac3a8ae..42a298d00d48c 100644
--- a/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/components/partition_vis_component.tsx
@@ -20,12 +20,7 @@ import {
SeriesIdentifier,
} from '@elastic/charts';
import { useEuiTheme } from '@elastic/eui';
-import {
- LegendToggle,
- ClickTriggerEvent,
- ChartsPluginSetup,
- PaletteRegistry,
-} from '../../../../charts/public';
+import { LegendToggle, ChartsPluginSetup, PaletteRegistry } from '../../../../charts/public';
import type { PersistedState } from '../../../../visualizations/public';
import {
Datatable,
@@ -63,10 +58,12 @@ import { VisualizationNoResults } from './visualization_noresults';
import { VisTypePiePluginStartDependencies } from '../plugin';
import {
partitionVisWrapperStyle,
- partitionVisContainerStyleFactory,
+ partitionVisContainerStyle,
+ partitionVisContainerWithToggleStyleFactory,
} from './partition_vis_component.styles';
import { ChartTypes } from '../../common/types';
import { filterOutConfig } from '../utils/filter_out_config';
+import { FilterEvent } from '../types';
declare global {
interface Window {
@@ -93,7 +90,6 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => {
const { visData, visParams: preVisParams, visType, services, syncColors } = props;
const visParams = useMemo(() => filterOutConfig(visType, preVisParams), [preVisParams, visType]);
- const theme = useEuiTheme();
const chartTheme = props.chartsThemeService.useChartsTheme();
const chartBaseTheme = props.chartsThemeService.useChartsBaseTheme();
@@ -103,8 +99,8 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => {
);
const formatters = useMemo(
- () => generateFormatters(visParams, visData, services.fieldFormats.deserialize),
- [services.fieldFormats.deserialize, visData, visParams]
+ () => generateFormatters(visData, services.fieldFormats.deserialize),
+ [services.fieldFormats.deserialize, visData]
);
const showLegendDefault = useCallback(() => {
@@ -114,6 +110,8 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => {
const [showLegend, setShowLegend] = useState
(() => showLegendDefault());
+ const showToggleLegendElement = props.uiState !== undefined;
+
const [dimensions, setDimensions] = useState();
const parentRef = useRef(null);
@@ -157,11 +155,7 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => {
splitChartDimension,
splitChartFormatter
);
- const event = {
- name: 'filterBucket',
- data: { data },
- };
- props.fireEvent(event);
+ props.fireEvent({ name: 'filter', data: { data } });
},
[props]
);
@@ -169,11 +163,11 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => {
// handles legend action event data
const getLegendActionEventData = useCallback(
(vData: Datatable) =>
- (series: SeriesIdentifier): ClickTriggerEvent | null => {
+ (series: SeriesIdentifier): FilterEvent => {
const data = getFilterEventData(vData, series);
return {
- name: 'filterBucket',
+ name: 'filter',
data: {
negate: false,
data,
@@ -184,7 +178,7 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => {
);
const handleLegendAction = useCallback(
- (event: ClickTriggerEvent, negate = false) => {
+ (event: FilterEvent, negate = false) => {
props.fireEvent({
...event,
data: {
@@ -318,6 +312,9 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => {
[visData.rows, metricColumn]
);
+ const isEmpty = visData.rows.length === 0;
+ const isMetricEmpty = visData.rows.every((row) => !row[metricColumn.id]);
+
/**
* Checks whether data have negative values.
* If so, the no data container is loaded.
@@ -330,14 +327,23 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => {
}),
[visData.rows, metricColumn]
);
+
const flatLegend = isLegendFlat(visType, splitChartDimension);
- const canShowPieChart = !isAllZeros && !hasNegative;
+
+ const canShowPieChart = !isEmpty && !isMetricEmpty && !isAllZeros && !hasNegative;
+
+ const { euiTheme } = useEuiTheme();
+
+ const chartContainerStyle = showToggleLegendElement
+ ? partitionVisContainerWithToggleStyleFactory(euiTheme)
+ : partitionVisContainerStyle;
+
const partitionType = getPartitionType(visType);
return (
-
+
{!canShowPieChart ? (
-
+
) : (
{
distinctColors: visParams.distinctColors ?? false,
}}
>
-
+ {showToggleLegendElement && (
+
+ )}
{
/>
{
- return (
-
- {hasNegativeValues
- ? i18n.translate('expressionPartitionVis.negativeValuesFound', {
- defaultMessage: "Pie/donut charts can't render with negative values.",
- })
- : i18n.translate('expressionPartitionVis.noResultsFoundTitle', {
- defaultMessage: 'No results found',
- })}
-
- }
- />
- );
+interface Props {
+ hasNegativeValues?: boolean;
+ chartType: ChartTypes;
+}
+
+export const VisualizationNoResults: FC = ({ hasNegativeValues = false, chartType }) => {
+ if (hasNegativeValues) {
+ const message = (
+
+ );
+
+ return (
+
+ );
+ }
+
+ return ;
};
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/expression_renderers/partition_vis_renderer.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/expression_renderers/partition_vis_renderer.tsx
index c3521c7346a81..53e729466c1d2 100644
--- a/src/plugins/chart_expressions/expression_partition_vis/public/expression_renderers/partition_vis_renderer.tsx
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/expression_renderers/partition_vis_renderer.tsx
@@ -10,35 +10,27 @@ import React, { lazy } from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { I18nProvider } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
-import { Datatable, ExpressionRenderDefinition } from '../../../../expressions/public';
-import { VisualizationContainer } from '../../../../visualizations/public';
+import { ExpressionRenderDefinition } from '../../../../expressions/public';
import type { PersistedState } from '../../../../visualizations/public';
+import { VisTypePieDependencies } from '../plugin';
+import { withSuspense } from '../../../../presentation_util/public';
import { KibanaThemeProvider } from '../../../../kibana_react/public';
-
import { PARTITION_VIS_RENDERER_NAME } from '../../common/constants';
import { ChartTypes, RenderValue } from '../../common/types';
-import { VisTypePieDependencies } from '../plugin';
-
export const strings = {
getDisplayName: () =>
- i18n.translate('expressionPartitionVis.renderer.pieVis.displayName', {
- defaultMessage: 'Pie visualization',
+ i18n.translate('expressionPartitionVis.renderer.partitionVis.pie.displayName', {
+ defaultMessage: 'Partition visualization',
}),
getHelpDescription: () =>
- i18n.translate('expressionPartitionVis.renderer.pieVis.helpDescription', {
- defaultMessage: 'Render a pie',
+ i18n.translate('expressionPartitionVis.renderer.partitionVis.pie.helpDescription', {
+ defaultMessage: 'Render pie/donut/treemap/mosaic/waffle charts',
}),
};
-const PartitionVisComponent = lazy(() => import('../components/partition_vis_component'));
-
-function shouldShowNoResultsMessage(visData: Datatable | undefined): boolean {
- const rows: object[] | undefined = visData?.rows;
- const isZeroHits = !rows || !rows.length;
-
- return Boolean(isZeroHits);
-}
+const LazyPartitionVisComponent = lazy(() => import('../components/partition_vis_component'));
+const PartitionVisComponent = withSuspense(LazyPartitionVisComponent);
export const getPartitionVisRenderer: (
deps: VisTypePieDependencies
@@ -48,8 +40,6 @@ export const getPartitionVisRenderer: (
help: strings.getHelpDescription(),
reuseDomNode: true,
render: async (domNode, { visConfig, visData, visType, syncColors }, handlers) => {
- const showNoResult = shouldShowNoResultsMessage(visData);
-
handlers.onDestroy(() => {
unmountComponentAtNode(domNode);
});
@@ -60,7 +50,7 @@ export const getPartitionVisRenderer: (
render(
-
+
,
- domNode
+ domNode,
+ () => {
+ handlers.done();
+ }
);
},
});
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/icons/donut.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/icons/donut.tsx
new file mode 100644
index 0000000000000..5846fe0e7e8ba
--- /dev/null
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/icons/donut.tsx
@@ -0,0 +1,32 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React from 'react';
+import { EuiIconProps } from '@elastic/eui';
+
+export const DonutIcon = ({ title, titleId, ...props }: Omit) => (
+
+);
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/icons/index.ts b/src/plugins/chart_expressions/expression_partition_vis/public/icons/index.ts
new file mode 100644
index 0000000000000..e61bd6557d581
--- /dev/null
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/icons/index.ts
@@ -0,0 +1,13 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+export { PieIcon } from './pie';
+export { DonutIcon } from './donut';
+export { TreemapIcon } from './treemap';
+export { MosaicIcon } from './mosaic';
+export { WaffleIcon } from './waffle';
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/icons/mosaic.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/icons/mosaic.tsx
new file mode 100644
index 0000000000000..f8582495f2e0c
--- /dev/null
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/icons/mosaic.tsx
@@ -0,0 +1,32 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React from 'react';
+import type { EuiIconProps } from '@elastic/eui';
+
+export const MosaicIcon = ({ title, titleId, ...props }: Omit) => (
+
+);
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/icons/pie.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/icons/pie.tsx
new file mode 100644
index 0000000000000..9176ac3fdd5c1
--- /dev/null
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/icons/pie.tsx
@@ -0,0 +1,32 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React from 'react';
+import { EuiIconProps } from '@elastic/eui';
+
+export const PieIcon = ({ title, titleId, ...props }: Omit) => (
+
+);
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/icons/treemap.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/icons/treemap.tsx
new file mode 100644
index 0000000000000..1860132fa9ffd
--- /dev/null
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/icons/treemap.tsx
@@ -0,0 +1,36 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React from 'react';
+import { EuiIconProps } from '@elastic/eui';
+
+export const TreemapIcon = ({ title, titleId, ...props }: Omit) => (
+
+);
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/icons/waffle.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/icons/waffle.tsx
new file mode 100644
index 0000000000000..30f05dd57f348
--- /dev/null
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/icons/waffle.tsx
@@ -0,0 +1,32 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import React from 'react';
+import type { EuiIconProps } from '@elastic/eui';
+
+export const WaffleIcon = ({ title, titleId, ...props }: Omit) => (
+
+);
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/types.ts b/src/plugins/chart_expressions/expression_partition_vis/public/types.ts
index 64e132d2ddadb..aa87124ed2b4b 100755
--- a/src/plugins/chart_expressions/expression_partition_vis/public/types.ts
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/types.ts
@@ -5,6 +5,7 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
+import type { ValueClickContext } from '../../../embeddable/public';
import { ChartsPluginSetup } from '../../../charts/public';
import { ExpressionsPublicPlugin, ExpressionsServiceStart } from '../../../expressions/public';
@@ -19,3 +20,8 @@ export interface SetupDeps {
export interface StartDeps {
expression: ExpressionsServiceStart;
}
+
+export interface FilterEvent {
+ name: 'filter';
+ data: ValueClickContext['data'];
+}
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/filter_helpers.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/filter_helpers.ts
index 47641a7f270c2..5b48d68f68201 100644
--- a/src/plugins/chart_expressions/expression_partition_vis/public/utils/filter_helpers.ts
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/filter_helpers.ts
@@ -9,13 +9,13 @@
import { LayerValue, SeriesIdentifier } from '@elastic/charts';
import { Datatable, DatatableColumn } from '../../../../expressions/public';
import { DataPublicPluginStart } from '../../../../data/public';
-import { ClickTriggerEvent } from '../../../../charts/public';
import { ValueClickContext } from '../../../../embeddable/public';
import type { FieldFormat } from '../../../../field_formats/common';
import { BucketColumns } from '../../common/types';
+import { FilterEvent } from '../types';
export const canFilter = async (
- event: ClickTriggerEvent | null,
+ event: FilterEvent | null,
actions: DataPublicPluginStart['actions']
): Promise => {
if (!event) {
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/formatters.test.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/formatters.test.ts
index 69443dcfea5fb..18f89cb5f3e4e 100644
--- a/src/plugins/chart_expressions/expression_partition_vis/public/utils/formatters.test.ts
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/formatters.test.ts
@@ -8,31 +8,19 @@
import { fieldFormatsMock } from '../../../../field_formats/common/mocks';
import { Datatable } from '../../../../expressions';
-import { createMockPieParams, createMockVisData } from '../mocks';
+import { createMockVisData } from '../mocks';
import { generateFormatters, getAvailableFormatter, getFormatter } from './formatters';
import { BucketColumns } from '../../common/types';
describe('generateFormatters', () => {
- const visParams = createMockPieParams();
const visData = createMockVisData();
const defaultFormatter = jest.fn((...args) => fieldFormatsMock.deserialize(...args));
beforeEach(() => {
defaultFormatter.mockClear();
});
- it('returns empty object, if labels should not be should ', () => {
- const formatters = generateFormatters(
- { ...visParams, labels: { ...visParams.labels, show: false } },
- visData,
- defaultFormatter
- );
-
- expect(formatters).toEqual({});
- expect(defaultFormatter).toHaveBeenCalledTimes(0);
- });
-
it('returns formatters, if columns have meta parameters', () => {
- const formatters = generateFormatters(visParams, visData, defaultFormatter);
+ const formatters = generateFormatters(visData, defaultFormatter);
const formattingResult = fieldFormatsMock.deserialize();
const serializedFormatters = Object.keys(formatters).reduce(
@@ -62,7 +50,7 @@ describe('generateFormatters', () => {
columns: visData.columns.map(({ meta, ...col }) => ({ ...col, meta: { type: 'string' } })),
};
- const formatters = generateFormatters(visParams, newVisData, defaultFormatter);
+ const formatters = generateFormatters(newVisData, defaultFormatter);
expect(formatters).toEqual({
'col-0-2': undefined,
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/formatters.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/formatters.ts
index 59574dd248518..bbb30169928d4 100644
--- a/src/plugins/chart_expressions/expression_partition_vis/public/utils/formatters.ts
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/formatters.ts
@@ -8,25 +8,16 @@
import type { FieldFormat, FormatFactory } from '../../../../field_formats/common';
import type { Datatable } from '../../../../expressions/public';
-import { BucketColumns, PartitionVisParams } from '../../common/types';
+import { BucketColumns } from '../../common/types';
-export const generateFormatters = (
- visParams: PartitionVisParams,
- visData: Datatable,
- formatFactory: FormatFactory
-) => {
- if (!visParams.labels.show) {
- return {};
- }
-
- return visData.columns.reduce | undefined>>(
+export const generateFormatters = (visData: Datatable, formatFactory: FormatFactory) =>
+ visData.columns.reduce | undefined>>(
(newFormatters, column) => ({
...newFormatters,
[column.id]: column?.meta?.params ? formatFactory(column.meta.params) : undefined,
}),
{}
);
-};
export const getAvailableFormatter = (
column: Partial,
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_icon.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_icon.ts
new file mode 100644
index 0000000000000..cac282553af11
--- /dev/null
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_icon.ts
@@ -0,0 +1,19 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { ChartTypes } from '../../common/types';
+import { PieIcon, DonutIcon, TreemapIcon, MosaicIcon, WaffleIcon } from '../icons';
+
+export const getIcon = (chart: ChartTypes) =>
+ ({
+ [ChartTypes.PIE]: PieIcon,
+ [ChartTypes.DONUT]: DonutIcon,
+ [ChartTypes.TREEMAP]: TreemapIcon,
+ [ChartTypes.MOSAIC]: MosaicIcon,
+ [ChartTypes.WAFFLE]: WaffleIcon,
+ }[chart]);
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_legend_actions.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_legend_actions.tsx
index 28b85f6300977..72793d771a0ee 100644
--- a/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_legend_actions.tsx
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/get_legend_actions.tsx
@@ -13,16 +13,16 @@ import { EuiContextMenuPanelDescriptor, EuiIcon, EuiPopover, EuiContextMenu } fr
import { LegendAction, SeriesIdentifier, useLegendAction } from '@elastic/charts';
import { DataPublicPluginStart } from '../../../../data/public';
import { PartitionVisParams } from '../../common/types';
-import { ClickTriggerEvent } from '../../../../charts/public';
import { FieldFormatsStart } from '../../../../field_formats/public';
+import { FilterEvent } from '../types';
export const getLegendActions = (
canFilter: (
- data: ClickTriggerEvent | null,
+ data: FilterEvent | null,
actions: DataPublicPluginStart['actions']
) => Promise,
- getFilterEventData: (series: SeriesIdentifier) => ClickTriggerEvent | null,
- onFilter: (data: ClickTriggerEvent, negate?: any) => void,
+ getFilterEventData: (series: SeriesIdentifier) => FilterEvent | null,
+ onFilter: (data: FilterEvent, negate?: any) => void,
visParams: PartitionVisParams,
actions: DataPublicPluginStart['actions'],
formatter: FieldFormatsStart
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/index.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/index.ts
index afa0b82a87eb1..b0ce92f1205e8 100644
--- a/src/plugins/chart_expressions/expression_partition_vis/public/utils/index.ts
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/index.ts
@@ -18,3 +18,4 @@ export { getColumnByAccessor } from './accessor';
export { isLegendFlat, shouldShowLegend } from './legend';
export { generateFormatters, getAvailableFormatter, getFormatter } from './formatters';
export { getPartitionType } from './get_partition_type';
+export { getIcon } from './get_icon';
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_color.test.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_color.test.ts
new file mode 100644
index 0000000000000..efeb1f038232d
--- /dev/null
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/get_color.test.ts
@@ -0,0 +1,90 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { PaletteDefinition, PaletteOutput } from '../../../../../charts/public';
+import { chartPluginMock } from '../../../../../charts/public/mocks';
+import { Datatable } from '../../../../../expressions';
+import { byDataColorPaletteMap } from './get_color';
+
+describe('#byDataColorPaletteMap', () => {
+ let datatable: Datatable;
+ let paletteDefinition: PaletteDefinition;
+ let palette: PaletteOutput;
+ const columnId = 'foo';
+
+ beforeEach(() => {
+ datatable = {
+ rows: [
+ {
+ [columnId]: '1',
+ },
+ {
+ [columnId]: '2',
+ },
+ ],
+ } as unknown as Datatable;
+ paletteDefinition = chartPluginMock.createPaletteRegistry().get('default');
+ palette = { type: 'palette' } as PaletteOutput;
+ });
+
+ it('should create byDataColorPaletteMap', () => {
+ expect(byDataColorPaletteMap(datatable.rows, columnId, paletteDefinition, palette))
+ .toMatchInlineSnapshot(`
+ Object {
+ "getColor": [Function],
+ }
+ `);
+ });
+
+ it('should get color', () => {
+ const colorPaletteMap = byDataColorPaletteMap(
+ datatable.rows,
+ columnId,
+ paletteDefinition,
+ palette
+ );
+
+ expect(colorPaletteMap.getColor('1')).toBe('black');
+ });
+
+ it('should return undefined in case if values not in datatable', () => {
+ const colorPaletteMap = byDataColorPaletteMap(
+ datatable.rows,
+ columnId,
+ paletteDefinition,
+ palette
+ );
+
+ expect(colorPaletteMap.getColor('wrong')).toBeUndefined();
+ });
+
+ it('should increase rankAtDepth for each new value', () => {
+ const colorPaletteMap = byDataColorPaletteMap(
+ datatable.rows,
+ columnId,
+ paletteDefinition,
+ palette
+ );
+ colorPaletteMap.getColor('1');
+ colorPaletteMap.getColor('2');
+
+ expect(paletteDefinition.getCategoricalColor).toHaveBeenNthCalledWith(
+ 1,
+ [{ name: '1', rankAtDepth: 0, totalSeriesAtDepth: 2 }],
+ { behindText: false },
+ undefined
+ );
+
+ expect(paletteDefinition.getCategoricalColor).toHaveBeenNthCalledWith(
+ 2,
+ [{ name: '2', rankAtDepth: 1, totalSeriesAtDepth: 2 }],
+ { behindText: false },
+ undefined
+ );
+ });
+});
diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/sort_predicate.test.ts b/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/sort_predicate.test.ts
new file mode 100644
index 0000000000000..1ccfdb7a5b1f9
--- /dev/null
+++ b/src/plugins/chart_expressions/expression_partition_vis/public/utils/layers/sort_predicate.test.ts
@@ -0,0 +1,41 @@
+/*
+ * 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 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { Datatable } from '../../../../../expressions';
+import { extractUniqTermsMap } from './sort_predicate';
+
+describe('#extractUniqTermsMap', () => {
+ it('should extract map', () => {
+ const table: Datatable = {
+ type: 'datatable',
+ columns: [
+ { id: 'a', name: 'A', meta: { type: 'string' } },
+ { id: 'b', name: 'B', meta: { type: 'string' } },
+ { id: 'c', name: 'C', meta: { type: 'number' } },
+ ],
+ rows: [
+ { a: 'Hi', b: 'Two', c: 2 },
+ { a: 'Test', b: 'Two', c: 5 },
+ { a: 'Foo', b: 'Three', c: 6 },
+ ],
+ };
+ expect(extractUniqTermsMap(table, 'a')).toMatchInlineSnapshot(`
+ Object {
+ "Foo": 2,
+ "Hi": 0,
+ "Test": 1,
+ }
+ `);
+ expect(extractUniqTermsMap(table, 'b')).toMatchInlineSnapshot(`
+ Object {
+ "Three": 1,
+ "Two": 0,
+ }
+ `);
+ });
+});
diff --git a/src/plugins/chart_expressions/expression_partition_vis/tsconfig.json b/src/plugins/chart_expressions/expression_partition_vis/tsconfig.json
index d480d7d27df5a..97a0c8a9fc515 100644
--- a/src/plugins/chart_expressions/expression_partition_vis/tsconfig.json
+++ b/src/plugins/chart_expressions/expression_partition_vis/tsconfig.json
@@ -15,6 +15,7 @@
"references": [
{ "path": "../../../core/tsconfig.json" },
{ "path": "../../expressions/tsconfig.json" },
+ { "path": "../../presentation_util/tsconfig.json" },
{ "path": "../../data/tsconfig.json" },
{ "path": "../../field_formats/tsconfig.json" },
{ "path": "../../charts/tsconfig.json" },
diff --git a/src/plugins/charts/public/static/components/empty_placeholder.tsx b/src/plugins/charts/public/static/components/empty_placeholder.tsx
index e376120c9cd9e..6989ea7a7a63b 100644
--- a/src/plugins/charts/public/static/components/empty_placeholder.tsx
+++ b/src/plugins/charts/public/static/components/empty_placeholder.tsx
@@ -13,14 +13,24 @@ import './empty_placeholder.scss';
export const EmptyPlaceholder = ({
icon,
+ iconColor = 'subdued',
message = ,
+ dataTestSubj = 'emptyPlaceholder',
}: {
icon: IconType;
+ iconColor?: string;
message?: JSX.Element;
+ dataTestSubj?: string;
}) => (
<>
-
-
+
+
{message}
diff --git a/test/functional/apps/visualize/_pie_chart.ts b/test/functional/apps/visualize/_pie_chart.ts
index 744ba3caa719e..48d49d3007b68 100644
--- a/test/functional/apps/visualize/_pie_chart.ts
+++ b/test/functional/apps/visualize/_pie_chart.ts
@@ -432,7 +432,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
'360,000',
'CN',
].sort();
- if (await PageObjects.visChart.isNewLibraryChart('visTypePieChart')) {
+ if (await PageObjects.visChart.isNewLibraryChart('partitionVisChart')) {
await PageObjects.visEditor.clickOptionsTab();
await PageObjects.visEditor.togglePieLegend();
await PageObjects.visEditor.togglePieNestedLegend();
diff --git a/test/functional/page_objects/visualize_chart_page.ts b/test/functional/page_objects/visualize_chart_page.ts
index 60d7c6e7d7435..3eec4e2ce1a2b 100644
--- a/test/functional/page_objects/visualize_chart_page.ts
+++ b/test/functional/page_objects/visualize_chart_page.ts
@@ -11,7 +11,7 @@ import chroma from 'chroma-js';
import { FtrService } from '../ftr_provider_context';
-const pieChartSelector = 'visTypePieChart';
+const partitionVisChartSelector = 'partitionVisChart';
const heatmapChartSelector = 'heatmapChart';
export class VisualizeChartPageObject extends FtrService {
@@ -149,7 +149,7 @@ export class VisualizeChartPageObject extends FtrService {
}
private async toggleLegend(force = false) {
- const isVisTypePieChart = await this.isNewLibraryChart(pieChartSelector);
+ const isVisTypePieChart = await this.isNewLibraryChart(partitionVisChartSelector);
const legendSelector = force || isVisTypePieChart ? '.echLegend' : '.visLegend';
await this.retry.try(async () => {
@@ -182,10 +182,11 @@ export class VisualizeChartPageObject extends FtrService {
}
public async doesSelectedLegendColorExistForPie(matchingColor: string) {
- if (await this.isNewLibraryChart(pieChartSelector)) {
+ if (await this.isNewLibraryChart(partitionVisChartSelector)) {
const hexMatchingColor = chroma(matchingColor).hex().toUpperCase();
const slices =
- (await this.getEsChartDebugState(pieChartSelector))?.partition?.[0]?.partitions ?? [];
+ (await this.getEsChartDebugState(partitionVisChartSelector))?.partition?.[0]?.partitions ??
+ [];
return slices.some(({ color }) => {
return hexMatchingColor === chroma(color).hex().toUpperCase();
});
@@ -195,7 +196,7 @@ export class VisualizeChartPageObject extends FtrService {
}
public async expectError() {
- if (!this.isNewLibraryChart(pieChartSelector)) {
+ if (!this.isNewLibraryChart(partitionVisChartSelector)) {
await this.testSubjects.existOrFail('vislibVisualizeError');
}
}
@@ -244,12 +245,13 @@ export class VisualizeChartPageObject extends FtrService {
}
public async getLegendEntries() {
- const isVisTypePieChart = await this.isNewLibraryChart(pieChartSelector);
+ const isVisTypePieChart = await this.isNewLibraryChart(partitionVisChartSelector);
const isVisTypeHeatmapChart = await this.isNewLibraryChart(heatmapChartSelector);
if (isVisTypePieChart) {
const slices =
- (await this.getEsChartDebugState(pieChartSelector))?.partition?.[0]?.partitions ?? [];
+ (await this.getEsChartDebugState(partitionVisChartSelector))?.partition?.[0]?.partitions ??
+ [];
return slices.map(({ name }) => name);
}
@@ -290,7 +292,7 @@ export class VisualizeChartPageObject extends FtrService {
public async openLegendOptionColorsForPie(name: string, chartSelector: string) {
await this.waitForVisualizationRenderingStabilized();
await this.retry.try(async () => {
- if (await this.isNewLibraryChart(pieChartSelector)) {
+ if (await this.isNewLibraryChart(partitionVisChartSelector)) {
const chart = await this.find.byCssSelector(chartSelector);
const legendItemColor = await chart.findByCssSelector(
`[data-ech-series-name="${name}"] .echLegendItem__color`
diff --git a/test/functional/services/visualizations/pie_chart.ts b/test/functional/services/visualizations/pie_chart.ts
index ff0c24e2830cf..16133140e4abf 100644
--- a/test/functional/services/visualizations/pie_chart.ts
+++ b/test/functional/services/visualizations/pie_chart.ts
@@ -10,7 +10,7 @@ import expect from '@kbn/expect';
import { isNil } from 'lodash';
import { FtrService } from '../../ftr_provider_context';
-const pieChartSelector = 'visTypePieChart';
+const partitionVisChartSelector = 'partitionVisChart';
export class PieChartService extends FtrService {
private readonly log = this.ctx.getService('log');
@@ -27,16 +27,16 @@ export class PieChartService extends FtrService {
async clickOnPieSlice(name?: string) {
this.log.debug(`PieChart.clickOnPieSlice(${name})`);
- if (await this.visChart.isNewLibraryChart(pieChartSelector)) {
+ if (await this.visChart.isNewLibraryChart(partitionVisChartSelector)) {
const slices =
- (await this.visChart.getEsChartDebugState(pieChartSelector))?.partition?.[0]?.partitions ??
- [];
+ (await this.visChart.getEsChartDebugState(partitionVisChartSelector))?.partition?.[0]
+ ?.partitions ?? [];
let sliceLabel = name || slices[0].name;
if (name === 'Other') {
sliceLabel = '__other__';
}
const pieSlice = slices.find((slice) => slice.name === sliceLabel);
- const pie = await this.testSubjects.find(pieChartSelector);
+ const pie = await this.testSubjects.find(partitionVisChartSelector);
if (pieSlice) {
const pieSize = await pie.getSize();
const pieHeight = pieSize.height;
@@ -88,10 +88,10 @@ export class PieChartService extends FtrService {
async getPieSliceStyle(name: string) {
this.log.debug(`VisualizePage.getPieSliceStyle(${name})`);
- if (await this.visChart.isNewLibraryChart(pieChartSelector)) {
+ if (await this.visChart.isNewLibraryChart(partitionVisChartSelector)) {
const slices =
- (await this.visChart.getEsChartDebugState(pieChartSelector))?.partition?.[0]?.partitions ??
- [];
+ (await this.visChart.getEsChartDebugState(partitionVisChartSelector))?.partition?.[0]
+ ?.partitions ?? [];
const selectedSlice = slices.filter((slice) => {
return slice.name.toString() === name.replace(',', '');
});
@@ -103,10 +103,10 @@ export class PieChartService extends FtrService {
async getAllPieSliceColor(name: string) {
this.log.debug(`VisualizePage.getAllPieSliceColor(${name})`);
- if (await this.visChart.isNewLibraryChart(pieChartSelector)) {
+ if (await this.visChart.isNewLibraryChart(partitionVisChartSelector)) {
const slices =
- (await this.visChart.getEsChartDebugState(pieChartSelector))?.partition?.[0]?.partitions ??
- [];
+ (await this.visChart.getEsChartDebugState(partitionVisChartSelector))?.partition?.[0]
+ ?.partitions ?? [];
const selectedSlice = slices.filter((slice) => {
return slice.name.toString() === name.replace(',', '');
});
@@ -143,10 +143,10 @@ export class PieChartService extends FtrService {
}
async getPieChartLabels() {
- if (await this.visChart.isNewLibraryChart(pieChartSelector)) {
+ if (await this.visChart.isNewLibraryChart(partitionVisChartSelector)) {
const slices =
- (await this.visChart.getEsChartDebugState(pieChartSelector))?.partition?.[0]?.partitions ??
- [];
+ (await this.visChart.getEsChartDebugState(partitionVisChartSelector))?.partition?.[0]
+ ?.partitions ?? [];
return slices.map((slice) => {
if (slice.name === '__missing__') {
return 'Missing';
@@ -169,10 +169,10 @@ export class PieChartService extends FtrService {
async getPieSliceCount() {
this.log.debug('PieChart.getPieSliceCount');
- if (await this.visChart.isNewLibraryChart(pieChartSelector)) {
+ if (await this.visChart.isNewLibraryChart(partitionVisChartSelector)) {
const slices =
- (await this.visChart.getEsChartDebugState(pieChartSelector))?.partition?.[0]?.partitions ??
- [];
+ (await this.visChart.getEsChartDebugState(partitionVisChartSelector))?.partition?.[0]
+ ?.partitions ?? [];
return slices?.length;
}
const slices = await this.find.allByCssSelector('svg > g > g.arcs > path.slice');
@@ -181,8 +181,8 @@ export class PieChartService extends FtrService {
async expectPieSliceCountEsCharts(expectedCount: number) {
const slices =
- (await this.visChart.getEsChartDebugState(pieChartSelector))?.partition?.[0]?.partitions ??
- [];
+ (await this.visChart.getEsChartDebugState(partitionVisChartSelector))?.partition?.[0]
+ ?.partitions ?? [];
expect(slices.length).to.be(expectedCount);
}
diff --git a/x-pack/plugins/lens/common/constants.ts b/x-pack/plugins/lens/common/constants.ts
index f0db3385cefc1..bd507be52e2ab 100644
--- a/x-pack/plugins/lens/common/constants.ts
+++ b/x-pack/plugins/lens/common/constants.ts
@@ -17,6 +17,32 @@ export const NOT_INTERNATIONALIZED_PRODUCT_NAME = 'Lens Visualizations';
export const BASE_API_URL = '/api/lens';
export const LENS_EDIT_BY_VALUE = 'edit_by_value';
+export const PieChartTypes = {
+ PIE: 'pie',
+ DONUT: 'donut',
+ TREEMAP: 'treemap',
+ MOSAIC: 'mosaic',
+ WAFFLE: 'waffle',
+} as const;
+
+export const CategoryDisplay = {
+ DEFAULT: 'default',
+ INSIDE: 'inside',
+ HIDE: 'hide',
+} as const;
+
+export const NumberDisplay = {
+ HIDDEN: 'hidden',
+ PERCENT: 'percent',
+ VALUE: 'value',
+} as const;
+
+export const LegendDisplay = {
+ DEFAULT: 'default',
+ SHOW: 'show',
+ HIDE: 'hide',
+} as const;
+
export const layerTypes: Record = {
DATA: 'data',
REFERENCELINE: 'referenceLine',
diff --git a/x-pack/plugins/lens/common/expressions/index.ts b/x-pack/plugins/lens/common/expressions/index.ts
index c5ee16ed4bcfd..d7c27c4436b42 100644
--- a/x-pack/plugins/lens/common/expressions/index.ts
+++ b/x-pack/plugins/lens/common/expressions/index.ts
@@ -12,7 +12,6 @@ export * from './merge_tables';
export * from './time_scale';
export * from './datatable';
export * from './metric_chart';
-export * from './pie_chart';
export * from './xy_chart';
export * from './expression_types';
diff --git a/x-pack/plugins/lens/common/expressions/pie_chart/index.ts b/x-pack/plugins/lens/common/expressions/pie_chart/index.ts
deleted file mode 100644
index 1c1f6fdae4578..0000000000000
--- a/x-pack/plugins/lens/common/expressions/pie_chart/index.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * 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 { pie } from './pie_chart';
-
-export type {
- SharedPieLayerState,
- PieLayerState,
- PieVisualizationState,
- PieExpressionArgs,
- PieExpressionProps,
-} from './types';
diff --git a/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts b/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts
deleted file mode 100644
index feec2117632c0..0000000000000
--- a/x-pack/plugins/lens/common/expressions/pie_chart/pie_chart.ts
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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 { Position } from '@elastic/charts';
-import { i18n } from '@kbn/i18n';
-
-import type { ExpressionFunctionDefinition } from '../../../../../../src/plugins/expressions/common';
-import type { LensMultiTable } from '../../types';
-import type { PieExpressionProps, PieExpressionArgs } from './types';
-
-interface PieRender {
- type: 'render';
- as: 'lens_pie_renderer';
- value: PieExpressionProps;
-}
-
-export const pie: ExpressionFunctionDefinition<
- 'lens_pie',
- LensMultiTable,
- PieExpressionArgs,
- PieRender
-> = {
- name: 'lens_pie',
- type: 'render',
- help: i18n.translate('xpack.lens.pie.expressionHelpLabel', {
- defaultMessage: 'Pie renderer',
- }),
- args: {
- title: {
- types: ['string'],
- help: 'The chart title.',
- },
- description: {
- types: ['string'],
- help: '',
- },
- groups: {
- types: ['string'],
- multi: true,
- help: '',
- },
- metric: {
- types: ['string'],
- help: '',
- },
- shape: {
- types: ['string'],
- options: ['pie', 'donut', 'treemap', 'mosaic'],
- help: '',
- },
- hideLabels: {
- types: ['boolean'],
- help: '',
- },
- numberDisplay: {
- types: ['string'],
- options: ['hidden', 'percent', 'value'],
- help: '',
- },
- categoryDisplay: {
- types: ['string'],
- options: ['default', 'inside', 'hide'],
- help: '',
- },
- legendDisplay: {
- types: ['string'],
- options: ['default', 'show', 'hide'],
- help: '',
- },
- nestedLegend: {
- types: ['boolean'],
- help: '',
- },
- legendMaxLines: {
- types: ['number'],
- help: '',
- },
- truncateLegend: {
- types: ['boolean'],
- help: '',
- },
- showValuesInLegend: {
- types: ['boolean'],
- help: '',
- },
- legendPosition: {
- types: ['string'],
- options: [Position.Top, Position.Right, Position.Bottom, Position.Left],
- help: '',
- },
- percentDecimals: {
- types: ['number'],
- help: '',
- },
- palette: {
- default: `{theme "palette" default={system_palette name="default"} }`,
- help: '',
- types: ['palette'],
- },
- emptySizeRatio: {
- types: ['number'],
- help: '',
- },
- ariaLabel: {
- types: ['string'],
- help: '',
- required: false,
- },
- },
- inputTypes: ['lens_multitable'],
- fn(data: LensMultiTable, args: PieExpressionArgs, handlers) {
- return {
- type: 'render',
- as: 'lens_pie_renderer',
- value: {
- data,
- args: {
- ...args,
- ariaLabel:
- args.ariaLabel ??
- (handlers.variables?.embeddableTitle as string) ??
- handlers.getExecutionContext?.()?.description,
- },
- },
- };
- },
-};
diff --git a/x-pack/plugins/lens/common/expressions/pie_chart/types.ts b/x-pack/plugins/lens/common/expressions/pie_chart/types.ts
deleted file mode 100644
index aa84488dbc2c2..0000000000000
--- a/x-pack/plugins/lens/common/expressions/pie_chart/types.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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 { PaletteOutput } from '../../../../../../src/plugins/charts/common';
-import type { LensMultiTable, LayerType } from '../../types';
-
-export type PieChartTypes = 'donut' | 'pie' | 'treemap' | 'mosaic' | 'waffle';
-
-export interface SharedPieLayerState {
- groups: string[];
- metric?: string;
- numberDisplay: 'hidden' | 'percent' | 'value';
- categoryDisplay: 'default' | 'inside' | 'hide';
- legendDisplay: 'default' | 'show' | 'hide';
- legendPosition?: 'left' | 'right' | 'top' | 'bottom';
- showValuesInLegend?: boolean;
- nestedLegend?: boolean;
- percentDecimals?: number;
- emptySizeRatio?: number;
- legendMaxLines?: number;
- truncateLegend?: boolean;
-}
-
-export type PieLayerState = SharedPieLayerState & {
- layerId: string;
- layerType: LayerType;
-};
-
-export interface PieVisualizationState {
- shape: PieChartTypes;
- layers: PieLayerState[];
- palette?: PaletteOutput;
-}
-
-export type PieExpressionArgs = SharedPieLayerState & {
- title?: string;
- description?: string;
- shape: PieChartTypes;
- hideLabels: boolean;
- palette: PaletteOutput;
- ariaLabel?: string;
-};
-
-export interface PieExpressionProps {
- data: LensMultiTable;
- args: PieExpressionArgs;
-}
diff --git a/x-pack/plugins/lens/common/types.ts b/x-pack/plugins/lens/common/types.ts
index f3572fea90f9e..0b2b5d5d739d0 100644
--- a/x-pack/plugins/lens/common/types.ts
+++ b/x-pack/plugins/lens/common/types.ts
@@ -6,12 +6,16 @@
*/
import type { Filter, FilterMeta } from '@kbn/es-query';
+import { Position } from '@elastic/charts';
+import { $Values } from '@kbn/utility-types';
import type {
IFieldFormat,
SerializedFieldFormat,
} from '../../../../src/plugins/field_formats/common';
import type { Datatable } from '../../../../src/plugins/expressions/common';
import type { PaletteContinuity } from '../../../../src/plugins/charts/common';
+import type { PaletteOutput } from '../../../../src/plugins/charts/common';
+import { CategoryDisplay, LegendDisplay, NumberDisplay, PieChartTypes } from './constants';
export type FormatFactory = (mapping?: SerializedFieldFormat) => IFieldFormat;
@@ -73,3 +77,41 @@ export type LayerType = 'data' | 'referenceLine';
// Shared by XY Chart and Heatmap as for now
export type ValueLabelConfig = 'hide' | 'inside' | 'outside';
+
+export type PieChartType = $Values;
+export type CategoryDisplayType = $Values;
+export type NumberDisplayType = $Values;
+
+export type LegendDisplayType = $Values;
+
+export enum EmptySizeRatios {
+ SMALL = 0.3,
+ MEDIUM = 0.54,
+ LARGE = 0.7,
+}
+
+export interface SharedPieLayerState {
+ groups: string[];
+ metric?: string;
+ numberDisplay: NumberDisplayType;
+ categoryDisplay: CategoryDisplayType;
+ legendDisplay: LegendDisplayType;
+ legendPosition?: Position;
+ showValuesInLegend?: boolean;
+ nestedLegend?: boolean;
+ percentDecimals?: number;
+ emptySizeRatio?: number;
+ legendMaxLines?: number;
+ truncateLegend?: boolean;
+}
+
+export type PieLayerState = SharedPieLayerState & {
+ layerId: string;
+ layerType: LayerType;
+};
+
+export interface PieVisualizationState {
+ shape: $Values;
+ layers: PieLayerState[];
+ palette?: PaletteOutput;
+}
diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx b/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx
index b8fd06a09ebcd..482a5b931ed78 100644
--- a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx
+++ b/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx
@@ -23,7 +23,8 @@ import type { LensByReferenceInput, LensByValueInput } from './embeddable';
import type { Document } from '../persistence';
import type { IndexPatternPersistedState } from '../indexpattern_datasource/types';
import type { XYState } from '../xy_visualization/types';
-import type { PieVisualizationState, MetricState } from '../../common/expressions';
+import type { MetricState } from '../../common/expressions';
+import type { PieVisualizationState } from '../../common';
import type { DatatableVisualizationState } from '../datatable_visualization/visualization';
import type { HeatmapVisualizationState } from '../heatmap_visualization/types';
import type { GaugeVisualizationState } from '../visualizations/gauge/constants';
diff --git a/x-pack/plugins/lens/public/expressions.ts b/x-pack/plugins/lens/public/expressions.ts
index 22e43addefcdd..2e5a30345633f 100644
--- a/x-pack/plugins/lens/public/expressions.ts
+++ b/x-pack/plugins/lens/public/expressions.ts
@@ -24,7 +24,6 @@ import { datatableColumn } from '../common/expressions/datatable/datatable_colum
import { mergeTables } from '../common/expressions/merge_tables';
import { renameColumns } from '../common/expressions/rename_columns/rename_columns';
-import { pie } from '../common/expressions/pie_chart/pie_chart';
import { formatColumn } from '../common/expressions/format_column';
import { counterRate } from '../common/expressions/counter_rate';
import { getTimeScale } from '../common/expressions/time_scale/time_scale';
@@ -39,7 +38,6 @@ export const setupExpressions = (
[lensMultitable].forEach((expressionType) => expressions.registerType(expressionType));
[
- pie,
xyChart,
mergeTables,
counterRate,
diff --git a/x-pack/plugins/lens/public/index.ts b/x-pack/plugins/lens/public/index.ts
index 1c045e63e9e26..f6ccb071075ac 100644
--- a/x-pack/plugins/lens/public/index.ts
+++ b/x-pack/plugins/lens/public/index.ts
@@ -14,9 +14,6 @@ export type {
export type { XYState } from './xy_visualization/types';
export type { DataType, OperationMetadata, Visualization } from './types';
export type {
- PieVisualizationState,
- PieLayerState,
- SharedPieLayerState,
MetricState,
AxesSettingsConfig,
XYLayerConfig,
@@ -26,7 +23,13 @@ export type {
XYCurveType,
YConfig,
} from '../common/expressions';
-export type { ValueLabelConfig } from '../common/types';
+export type {
+ ValueLabelConfig,
+ PieVisualizationState,
+ PieLayerState,
+ SharedPieLayerState,
+} from '../common/types';
+
export type { DatatableVisualizationState } from './datatable_visualization/visualization';
export type { HeatmapVisualizationState } from './heatmap_visualization/types';
export type { GaugeVisualizationState } from './visualizations/gauge/constants';
diff --git a/x-pack/plugins/lens/public/pie_visualization/constants.ts b/x-pack/plugins/lens/public/pie_visualization/constants.ts
index e32320bb75ff0..bfb263b415891 100644
--- a/x-pack/plugins/lens/public/pie_visualization/constants.ts
+++ b/x-pack/plugins/lens/public/pie_visualization/constants.ts
@@ -6,9 +6,3 @@
*/
export const DEFAULT_PERCENT_DECIMALS = 2;
-
-export enum EMPTY_SIZE_RATIOS {
- SMALL = 0.3,
- MEDIUM = 0.54,
- LARGE = 0.7,
-}
diff --git a/x-pack/plugins/lens/public/pie_visualization/expression.tsx b/x-pack/plugins/lens/public/pie_visualization/expression.tsx
deleted file mode 100644
index bf52fb6ba5e5e..0000000000000
--- a/x-pack/plugins/lens/public/pie_visualization/expression.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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 React from 'react';
-import ReactDOM from 'react-dom';
-import { i18n } from '@kbn/i18n';
-import { I18nProvider } from '@kbn/i18n-react';
-import type {
- IInterpreterRenderHandlers,
- ExpressionRenderDefinition,
-} from 'src/plugins/expressions/public';
-import { ThemeServiceStart } from 'kibana/public';
-import { KibanaThemeProvider } from '../../../../../src/plugins/kibana_react/public';
-import type { LensFilterEvent } from '../types';
-import { PieComponent } from './render_function';
-import type { FormatFactory } from '../../common';
-import type { PieExpressionProps } from '../../common/expressions';
-import type { ChartsPluginSetup, PaletteRegistry } from '../../../../../src/plugins/charts/public';
-
-export const getPieRenderer = (dependencies: {
- formatFactory: FormatFactory;
- chartsThemeService: ChartsPluginSetup['theme'];
- paletteService: PaletteRegistry;
- kibanaTheme: ThemeServiceStart;
-}): ExpressionRenderDefinition => ({
- name: 'lens_pie_renderer',
- displayName: i18n.translate('xpack.lens.pie.visualizationName', {
- defaultMessage: 'Pie',
- }),
- help: '',
- validate: () => undefined,
- reuseDomNode: true,
- render: (domNode: Element, config: PieExpressionProps, handlers: IInterpreterRenderHandlers) => {
- const onClickValue = (data: LensFilterEvent['data']) => {
- handlers.event({ name: 'filter', data });
- };
-
- ReactDOM.render(
-
-
-
-
- ,
- domNode,
- () => {
- handlers.done();
- }
- );
- handlers.onDestroy(() => ReactDOM.unmountComponentAtNode(domNode));
- },
-});
-
-const MemoizedChart = React.memo(PieComponent);
diff --git a/x-pack/plugins/lens/public/pie_visualization/get_legend_action.test.tsx b/x-pack/plugins/lens/public/pie_visualization/get_legend_action.test.tsx
deleted file mode 100644
index df0648aa40d74..0000000000000
--- a/x-pack/plugins/lens/public/pie_visualization/get_legend_action.test.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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 React from 'react';
-import { LegendActionProps, SeriesIdentifier } from '@elastic/charts';
-import { EuiPopover } from '@elastic/eui';
-import { mountWithIntl } from '@kbn/test-jest-helpers';
-import { ComponentType, ReactWrapper } from 'enzyme';
-import type { Datatable } from 'src/plugins/expressions/public';
-import { getLegendAction } from './get_legend_action';
-import { LegendActionPopover } from '../shared_components';
-
-const table: Datatable = {
- type: 'datatable',
- columns: [
- { id: 'a', name: 'A', meta: { type: 'string' } },
- { id: 'b', name: 'B', meta: { type: 'number' } },
- ],
- rows: [
- { a: 'Hi', b: 2 },
- { a: 'Test', b: 4 },
- { a: 'Foo', b: 6 },
- ],
-};
-
-describe('getLegendAction', function () {
- let wrapperProps: LegendActionProps;
- const Component: ComponentType = getLegendAction(table, jest.fn());
- let wrapper: ReactWrapper;
-
- beforeAll(() => {
- wrapperProps = {
- color: 'rgb(109, 204, 177)',
- label: 'Bar',
- series: [
- {
- specId: 'donut',
- key: 'Bar',
- },
- ] as unknown as SeriesIdentifier[],
- };
- });
-
- it('is not rendered if row does not exist', () => {
- wrapper = mountWithIntl();
- expect(wrapper).toEqual({});
- expect(wrapper.find(EuiPopover).length).toBe(0);
- });
-
- it('is rendered if row is detected', () => {
- const newProps = {
- ...wrapperProps,
- label: 'Hi',
- series: [
- {
- specId: 'donut',
- key: 'Hi',
- },
- ] as unknown as SeriesIdentifier[],
- };
- wrapper = mountWithIntl();
- expect(wrapper.find(EuiPopover).length).toBe(1);
- expect(wrapper.find(EuiPopover).prop('title')).toEqual('Hi, filter options');
- expect(wrapper.find(LegendActionPopover).prop('context')).toEqual({
- data: [
- {
- column: 0,
- row: 0,
- table,
- value: 'Hi',
- },
- ],
- });
- });
-});
diff --git a/x-pack/plugins/lens/public/pie_visualization/get_legend_action.tsx b/x-pack/plugins/lens/public/pie_visualization/get_legend_action.tsx
deleted file mode 100644
index 9f16ad863a415..0000000000000
--- a/x-pack/plugins/lens/public/pie_visualization/get_legend_action.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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 React from 'react';
-
-import type { LegendAction } from '@elastic/charts';
-import type { Datatable } from 'src/plugins/expressions/public';
-import type { LensFilterEvent } from '../types';
-import { LegendActionPopover } from '../shared_components';
-
-export const getLegendAction = (
- table: Datatable,
- onFilter: (data: LensFilterEvent['data']) => void
-): LegendAction =>
- React.memo(({ series: [pieSeries], label }) => {
- const data = table.columns.reduce((acc, { id }, column) => {
- const value = pieSeries.key;
- const row = table.rows.findIndex((r) => r[id] === value);
- if (row > -1) {
- acc.push({
- table,
- column,
- row,
- value,
- });
- }
-
- return acc;
- }, []);
-
- if (data.length === 0) {
- return null;
- }
-
- const context: LensFilterEvent['data'] = {
- data,
- };
-
- return ;
- });
diff --git a/x-pack/plugins/lens/public/pie_visualization/index.ts b/x-pack/plugins/lens/public/pie_visualization/index.ts
index ce54f53c1cc93..b86c2fc90e4fa 100644
--- a/x-pack/plugins/lens/public/pie_visualization/index.ts
+++ b/x-pack/plugins/lens/public/pie_visualization/index.ts
@@ -6,16 +6,12 @@
*/
import type { CoreSetup } from 'src/core/public';
-import type { ExpressionsSetup } from 'src/plugins/expressions/public';
import type { EditorFrameSetup } from '../types';
import type { UiActionsStart } from '../../../../../src/plugins/ui_actions/public';
import type { ChartsPluginSetup } from '../../../../../src/plugins/charts/public';
-import type { FormatFactory } from '../../common';
export interface PieVisualizationPluginSetupPlugins {
editorFrame: EditorFrameSetup;
- expressions: ExpressionsSetup;
- formatFactory: FormatFactory;
charts: ChartsPluginSetup;
}
@@ -24,22 +20,11 @@ export interface PieVisualizationPluginStartPlugins {
}
export class PieVisualization {
- setup(
- core: CoreSetup,
- { expressions, formatFactory, editorFrame, charts }: PieVisualizationPluginSetupPlugins
- ) {
+ setup(core: CoreSetup, { editorFrame, charts }: PieVisualizationPluginSetupPlugins) {
editorFrame.registerVisualization(async () => {
- const { getPieVisualization, getPieRenderer } = await import('../async_services');
+ const { getPieVisualization } = await import('../async_services');
const palettes = await charts.palettes.getPalettes();
- expressions.registerRenderer(
- getPieRenderer({
- formatFactory,
- chartsThemeService: charts.theme,
- paletteService: palettes,
- kibanaTheme: core.theme,
- })
- );
return getPieVisualization({ paletteService: palettes, kibanaTheme: core.theme });
});
}
diff --git a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts
index 3d02c0f6d513e..d77a09ae10689 100644
--- a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts
+++ b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts
@@ -6,24 +6,20 @@
*/
import { i18n } from '@kbn/i18n';
-import { ArrayEntry, PartitionLayout } from '@elastic/charts';
import type { EuiIconProps } from '@elastic/eui';
+import type { DatatableColumn } from '../../../../../src/plugins/expressions';
import { LensIconChartDonut } from '../assets/chart_donut';
import { LensIconChartPie } from '../assets/chart_pie';
import { LensIconChartTreemap } from '../assets/chart_treemap';
import { LensIconChartMosaic } from '../assets/chart_mosaic';
import { LensIconChartWaffle } from '../assets/chart_waffle';
-import { EMPTY_SIZE_RATIOS } from './constants';
-
-import type { SharedPieLayerState } from '../../common/expressions';
-import type { PieChartTypes } from '../../common/expressions/pie_chart/types';
-import type { DatatableColumn } from '../../../../../src/plugins/expressions';
+import { CategoryDisplay, NumberDisplay, SharedPieLayerState, EmptySizeRatios } from '../../common';
+import type { PieChartType } from '../../common/types';
interface PartitionChartMeta {
icon: ({ title, titleId, ...props }: Omit) => JSX.Element;
label: string;
- partitionType: PartitionLayout;
groupLabel: string;
maxBuckets: number;
isExperimental?: boolean;
@@ -40,7 +36,7 @@ interface PartitionChartMeta {
}>;
emptySizeRatioOptions?: Array<{
id: string;
- value: EMPTY_SIZE_RATIOS;
+ value: EmptySizeRatios;
label: string;
}>;
};
@@ -50,10 +46,6 @@ interface PartitionChartMeta {
hideNestedLegendSwitch?: boolean;
getShowLegendDefault?: (bucketColumns: DatatableColumn[]) => boolean;
};
- sortPredicate?: (
- bucketColumns: DatatableColumn[],
- sortingMap: Record
- ) => (node1: ArrayEntry, node2: ArrayEntry) => number;
}
const groupLabel = i18n.translate('xpack.lens.pie.groupLabel', {
@@ -62,19 +54,19 @@ const groupLabel = i18n.translate('xpack.lens.pie.groupLabel', {
const categoryOptions: PartitionChartMeta['toolbarPopover']['categoryOptions'] = [
{
- value: 'default',
+ value: CategoryDisplay.DEFAULT,
inputDisplay: i18n.translate('xpack.lens.pieChart.showCategoriesLabel', {
defaultMessage: 'Inside or outside',
}),
},
{
- value: 'inside',
+ value: CategoryDisplay.INSIDE,
inputDisplay: i18n.translate('xpack.lens.pieChart.fitInsideOnlyLabel', {
defaultMessage: 'Inside only',
}),
},
{
- value: 'hide',
+ value: CategoryDisplay.HIDE,
inputDisplay: i18n.translate('xpack.lens.pieChart.categoriesInLegendLabel', {
defaultMessage: 'Hide labels',
}),
@@ -83,13 +75,13 @@ const categoryOptions: PartitionChartMeta['toolbarPopover']['categoryOptions'] =
const categoryOptionsTreemap: PartitionChartMeta['toolbarPopover']['categoryOptions'] = [
{
- value: 'default',
+ value: CategoryDisplay.DEFAULT,
inputDisplay: i18n.translate('xpack.lens.pieChart.showTreemapCategoriesLabel', {
defaultMessage: 'Show labels',
}),
},
{
- value: 'hide',
+ value: CategoryDisplay.HIDE,
inputDisplay: i18n.translate('xpack.lens.pieChart.categoriesInLegendLabel', {
defaultMessage: 'Hide labels',
}),
@@ -98,19 +90,19 @@ const categoryOptionsTreemap: PartitionChartMeta['toolbarPopover']['categoryOpti
const numberOptions: PartitionChartMeta['toolbarPopover']['numberOptions'] = [
{
- value: 'hidden',
+ value: NumberDisplay.HIDDEN,
inputDisplay: i18n.translate('xpack.lens.pieChart.hiddenNumbersLabel', {
defaultMessage: 'Hide from chart',
}),
},
{
- value: 'percent',
+ value: NumberDisplay.PERCENT,
inputDisplay: i18n.translate('xpack.lens.pieChart.showPercentValuesLabel', {
defaultMessage: 'Show percent',
}),
},
{
- value: 'value',
+ value: NumberDisplay.VALUE,
inputDisplay: i18n.translate('xpack.lens.pieChart.showFormatterValuesLabel', {
defaultMessage: 'Show value',
}),
@@ -120,34 +112,33 @@ const numberOptions: PartitionChartMeta['toolbarPopover']['numberOptions'] = [
const emptySizeRatioOptions: PartitionChartMeta['toolbarPopover']['emptySizeRatioOptions'] = [
{
id: 'emptySizeRatioOption-small',
- value: EMPTY_SIZE_RATIOS.SMALL,
+ value: EmptySizeRatios.SMALL,
label: i18n.translate('xpack.lens.pieChart.emptySizeRatioOptions.small', {
defaultMessage: 'Small',
}),
},
{
id: 'emptySizeRatioOption-medium',
- value: EMPTY_SIZE_RATIOS.MEDIUM,
+ value: EmptySizeRatios.MEDIUM,
label: i18n.translate('xpack.lens.pieChart.emptySizeRatioOptions.medium', {
defaultMessage: 'Medium',
}),
},
{
id: 'emptySizeRatioOption-large',
- value: EMPTY_SIZE_RATIOS.LARGE,
+ value: EmptySizeRatios.LARGE,
label: i18n.translate('xpack.lens.pieChart.emptySizeRatioOptions.large', {
defaultMessage: 'Large',
}),
},
];
-export const PartitionChartsMeta: Record = {
+export const PartitionChartsMeta: Record = {
donut: {
icon: LensIconChartDonut,
label: i18n.translate('xpack.lens.pie.donutLabel', {
defaultMessage: 'Donut',
}),
- partitionType: PartitionLayout.sunburst,
groupLabel,
maxBuckets: 3,
toolbarPopover: {
@@ -164,7 +155,6 @@ export const PartitionChartsMeta: Record = {
label: i18n.translate('xpack.lens.pie.pielabel', {
defaultMessage: 'Pie',
}),
- partitionType: PartitionLayout.sunburst,
groupLabel,
maxBuckets: 3,
toolbarPopover: {
@@ -180,7 +170,6 @@ export const PartitionChartsMeta: Record = {
label: i18n.translate('xpack.lens.pie.treemaplabel', {
defaultMessage: 'Treemap',
}),
- partitionType: PartitionLayout.treemap,
groupLabel,
maxBuckets: 2,
toolbarPopover: {
@@ -196,7 +185,6 @@ export const PartitionChartsMeta: Record = {
label: i18n.translate('xpack.lens.pie.mosaiclabel', {
defaultMessage: 'Mosaic',
}),
- partitionType: PartitionLayout.mosaic,
groupLabel,
maxBuckets: 2,
isExperimental: true,
@@ -208,23 +196,12 @@ export const PartitionChartsMeta: Record = {
getShowLegendDefault: () => false,
},
requiredMinDimensionCount: 2,
- sortPredicate:
- (bucketColumns, sortingMap) =>
- ([name1, node1], [, node2]) => {
- // Sorting for first group
- if (bucketColumns.length === 1 || (node1.children.length && name1 in sortingMap)) {
- return sortingMap[name1];
- }
- // Sorting for second group
- return node2.value - node1.value;
- },
},
waffle: {
icon: LensIconChartWaffle,
label: i18n.translate('xpack.lens.pie.wafflelabel', {
defaultMessage: 'Waffle',
}),
- partitionType: PartitionLayout.waffle,
groupLabel,
maxBuckets: 1,
isExperimental: true,
@@ -239,9 +216,5 @@ export const PartitionChartsMeta: Record = {
hideNestedLegendSwitch: true,
getShowLegendDefault: () => true,
},
- sortPredicate:
- () =>
- ([, node1], [, node2]) =>
- node2.value - node1.value,
},
};
diff --git a/x-pack/plugins/lens/public/pie_visualization/pie_visualization.ts b/x-pack/plugins/lens/public/pie_visualization/pie_visualization.ts
index 231b6bacbbe20..78f082b8c0e29 100644
--- a/x-pack/plugins/lens/public/pie_visualization/pie_visualization.ts
+++ b/x-pack/plugins/lens/public/pie_visualization/pie_visualization.ts
@@ -5,5 +5,4 @@
* 2.0.
*/
-export * from './expression';
export * from './visualization';
diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.test.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.test.tsx
deleted file mode 100644
index 8cd8e4f50d625..0000000000000
--- a/x-pack/plugins/lens/public/pie_visualization/render_function.test.tsx
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * 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 React from 'react';
-import {
- Partition,
- SeriesIdentifier,
- Settings,
- NodeColorAccessor,
- ShapeTreeNode,
- HierarchyOfArrays,
- Chart,
- PartialTheme,
-} from '@elastic/charts';
-import { shallow } from 'enzyme';
-import type { LensMultiTable } from '../../common';
-import type { PieExpressionArgs } from '../../common/expressions';
-import { PieComponent } from './render_function';
-import { VisualizationContainer } from '../visualization_container';
-import { EmptyPlaceholder } from '../../../../../src/plugins/charts/public';
-import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks';
-import { LensIconChartDonut } from '../assets/chart_donut';
-
-const chartsThemeService = chartPluginMock.createSetupContract().theme;
-
-describe('PieVisualization component', () => {
- let getFormatSpy: jest.Mock;
- let convertSpy: jest.Mock;
-
- beforeEach(() => {
- convertSpy = jest.fn((x) => x);
- getFormatSpy = jest.fn();
- getFormatSpy.mockReturnValue({ convert: convertSpy });
- });
-
- describe('legend options', () => {
- const data: LensMultiTable = {
- type: 'lens_multitable',
- tables: {
- first: {
- type: 'datatable',
- columns: [
- { id: 'a', name: 'a', meta: { type: 'number' } },
- { id: 'b', name: 'b', meta: { type: 'string' } },
- { id: 'c', name: 'c', meta: { type: 'number' } },
- ],
- rows: [
- { a: 6, b: 'I', c: 2, d: 'Row 1' },
- { a: 1, b: 'J', c: 5, d: 'Row 2' },
- ],
- },
- },
- };
-
- const args: PieExpressionArgs = {
- shape: 'pie',
- groups: ['a', 'b'],
- metric: 'c',
- numberDisplay: 'hidden',
- categoryDisplay: 'default',
- legendDisplay: 'default',
- legendMaxLines: 1,
- truncateLegend: true,
- nestedLegend: false,
- percentDecimals: 3,
- hideLabels: false,
- palette: { name: 'mock', type: 'palette' },
- };
-
- function getDefaultArgs() {
- return {
- data,
- formatFactory: getFormatSpy,
- onClickValue: jest.fn(),
- chartsThemeService,
- paletteService: chartPluginMock.createPaletteRegistry(),
- renderMode: 'view' as const,
- syncColors: false,
- };
- }
-
- test('it shows legend on correct side', () => {
- const component = shallow(
-
- );
- expect(component.find(Settings).prop('legendPosition')).toEqual('top');
- });
-
- test('it shows legend for 2 groups using default legendDisplay', () => {
- const component = shallow();
- expect(component.find(Settings).prop('showLegend')).toEqual(true);
- });
-
- test('it hides legend for 1 group using default legendDisplay', () => {
- const component = shallow(
-
- );
- expect(component.find(Settings).prop('showLegend')).toEqual(false);
- });
-
- test('it hides legend that would show otherwise in preview mode', () => {
- const component = shallow(
-
- );
- expect(component.find(Settings).prop('showLegend')).toEqual(false);
- });
-
- test('it sets the correct lines per legend item', () => {
- const component = shallow();
- expect(component.find(Settings).prop('theme')[0]).toMatchObject({
- background: {
- color: undefined,
- },
- legend: {
- labelOptions: {
- maxLines: 1,
- },
- },
- });
- });
-
- test('it calls the color function with the right series layers', () => {
- const defaultArgs = getDefaultArgs();
- const component = shallow(
-
- );
-
- (component.find(Partition).prop('layers')![1].shape!.fillColor as NodeColorAccessor)(
- {
- dataName: 'third',
- depth: 2,
- parent: {
- children: [
- ['first', {}],
- ['second', {}],
- ['third', {}],
- ],
- depth: 1,
- value: 200,
- dataName: 'css',
- parent: {
- children: [
- ['empty', {}],
- ['css', {}],
- ['gz', {}],
- ],
- depth: 0,
- sortIndex: 0,
- value: 500,
- },
- sortIndex: 1,
- },
- value: 41,
- sortIndex: 2,
- } as unknown as ShapeTreeNode,
- 0,
- [] as HierarchyOfArrays
- );
-
- expect(defaultArgs.paletteService.get('mock').getCategoricalColor).toHaveBeenCalledWith(
- [
- {
- name: 'css',
- rankAtDepth: 1,
- totalSeriesAtDepth: 3,
- },
- {
- name: 'third',
- rankAtDepth: 2,
- totalSeriesAtDepth: 3,
- },
- ],
- {
- maxDepth: 2,
- totalSeries: 5,
- syncColors: false,
- behindText: true,
- },
- undefined
- );
- });
-
- test('it hides legend with 2 groups for treemap', () => {
- const component = shallow(
-
- );
- expect(component.find(Settings).prop('showLegend')).toEqual(false);
- });
-
- test('it shows treemap legend only when forced on', () => {
- const component = shallow(
-
- );
- expect(component.find(Settings).prop('showLegend')).toEqual(true);
- });
-
- test('it defaults to 1-level legend depth', () => {
- const component = shallow();
- expect(component.find(Settings).prop('legendMaxDepth')).toEqual(1);
- });
-
- test('it shows nested legend only when forced on', () => {
- const component = shallow(
-
- );
- expect(component.find(Settings).prop('legendMaxDepth')).toBeUndefined();
- });
-
- test('it calls filter callback with the given context', () => {
- const defaultArgs = getDefaultArgs();
- const component = shallow();
- component.find(Settings).first().prop('onElementClick')!([
- [
- [
- {
- groupByRollup: 6,
- value: 6,
- depth: 1,
- path: [],
- sortIndex: 1,
- smAccessorValue: '',
- },
- ],
- {} as SeriesIdentifier,
- ],
- ]);
-
- expect(defaultArgs.onClickValue.mock.calls[0][0]).toMatchInlineSnapshot(`
- Object {
- "data": Array [
- Object {
- "column": 0,
- "row": 0,
- "table": Object {
- "columns": Array [
- Object {
- "id": "a",
- "meta": Object {
- "type": "number",
- },
- "name": "a",
- },
- Object {
- "id": "b",
- "meta": Object {
- "type": "string",
- },
- "name": "b",
- },
- Object {
- "id": "c",
- "meta": Object {
- "type": "number",
- },
- "name": "c",
- },
- ],
- "rows": Array [
- Object {
- "a": 6,
- "b": "I",
- "c": 2,
- "d": "Row 1",
- },
- Object {
- "a": 1,
- "b": "J",
- "c": 5,
- "d": "Row 2",
- },
- ],
- "type": "datatable",
- },
- "value": 6,
- },
- ],
- }
- `);
- });
-
- test('does not set click listener and legend actions on non-interactive mode', () => {
- const defaultArgs = getDefaultArgs();
- const component = shallow(
-
- );
- expect(component.find(Settings).first().prop('onElementClick')).toBeUndefined();
- expect(component.find(Settings).first().prop('legendAction')).toBeUndefined();
- });
-
- test('it renders the empty placeholder when metric contains only falsy data', () => {
- const defaultData = getDefaultArgs().data;
- const emptyData: LensMultiTable = {
- ...defaultData,
- tables: {
- first: {
- ...defaultData.tables.first,
- rows: [
- { a: 0, b: 'I', c: 0, d: 'Row 1' },
- { a: 0, b: 'J', c: null, d: 'Row 2' },
- ],
- },
- },
- };
-
- const component = shallow(
-
- );
- expect(component.find(VisualizationContainer)).toHaveLength(1);
- expect(component.find(EmptyPlaceholder)).toHaveLength(1);
- });
-
- test('it renders the chart when metric contains truthy data and buckets contain only falsy data', () => {
- const defaultData = getDefaultArgs().data;
- const emptyData: LensMultiTable = {
- ...defaultData,
- tables: {
- first: {
- ...defaultData.tables.first,
- // a and b are buckets, c is a metric
- rows: [{ a: 0, b: undefined, c: 12 }],
- },
- },
- };
-
- const component = shallow(
-
- );
-
- expect(component.find(VisualizationContainer)).toHaveLength(1);
- expect(component.find(EmptyPlaceholder)).toHaveLength(0);
- expect(component.find(Chart)).toHaveLength(1);
- });
-
- test('it shows emptyPlaceholder for undefined grouped data', () => {
- const defaultData = getDefaultArgs().data;
- const emptyData: LensMultiTable = {
- ...defaultData,
- tables: {
- first: {
- ...defaultData.tables.first,
- rows: [
- { a: undefined, b: 'I', c: undefined, d: 'Row 1' },
- { a: undefined, b: 'J', c: undefined, d: 'Row 2' },
- ],
- },
- },
- };
-
- const component = shallow(
-
- );
- expect(component.find(VisualizationContainer)).toHaveLength(1);
- expect(component.find(EmptyPlaceholder).prop('icon')).toEqual(LensIconChartDonut);
- });
-
- test('it should dynamically shrink the chart area to when some small slices are detected', () => {
- const defaultData = getDefaultArgs().data;
- const emptyData: LensMultiTable = {
- ...defaultData,
- tables: {
- first: {
- ...defaultData.tables.first,
- rows: [
- { a: 60, b: 'I', c: 200, d: 'Row 1' },
- { a: 1, b: 'J', c: 0.1, d: 'Row 2' },
- ],
- },
- },
- };
-
- const component = shallow(
-
- );
- expect(
- component.find(Settings).prop('theme')[0].partition?.outerSizeRatio
- ).toBeCloseTo(1 / 1.05);
- });
-
- test('it should bound the shrink the chart area to ~20% when some small slices are detected', () => {
- const defaultData = getDefaultArgs().data;
- const emptyData: LensMultiTable = {
- ...defaultData,
- tables: {
- first: {
- ...defaultData.tables.first,
- rows: [
- { a: 60, b: 'I', c: 200, d: 'Row 1' },
- { a: 1, b: 'J', c: 0.1, d: 'Row 2' },
- { a: 1, b: 'K', c: 0.1, d: 'Row 3' },
- { a: 1, b: 'G', c: 0.1, d: 'Row 4' },
- { a: 1, b: 'H', c: 0.1, d: 'Row 5' },
- ],
- },
- },
- };
-
- const component = shallow(
-
- );
- expect(
- component.find(Settings).prop('theme')[0].partition?.outerSizeRatio
- ).toBeCloseTo(1 / 1.2);
- });
- });
-});
diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx
deleted file mode 100644
index 15706e69d1e16..0000000000000
--- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * 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 { uniq } from 'lodash';
-import React from 'react';
-import { FormattedMessage } from '@kbn/i18n-react';
-import { Required } from '@kbn/utility-types';
-import { EuiText } from '@elastic/eui';
-import {
- Chart,
- Datum,
- LayerValue,
- Partition,
- PartitionLayer,
- Position,
- Settings,
- ElementClickListener,
- PartialTheme,
-} from '@elastic/charts';
-import { RenderMode } from 'src/plugins/expressions';
-import type { LensFilterEvent } from '../types';
-import { VisualizationContainer } from '../visualization_container';
-import { DEFAULT_PERCENT_DECIMALS } from './constants';
-import { PartitionChartsMeta } from './partition_charts_meta';
-import type { FormatFactory } from '../../common';
-import type { PieExpressionProps } from '../../common/expressions';
-import {
- getSliceValue,
- getFilterContext,
- isTreemapOrMosaicShape,
- byDataColorPaletteMap,
- extractUniqTermsMap,
-} from './render_helpers';
-import { EmptyPlaceholder } from '../../../../../src/plugins/charts/public';
-import './visualization.scss';
-import {
- ChartsPluginSetup,
- PaletteRegistry,
- SeriesLayer,
-} from '../../../../../src/plugins/charts/public';
-import { LensIconChartDonut } from '../assets/chart_donut';
-import { getLegendAction } from './get_legend_action';
-
-declare global {
- interface Window {
- /**
- * Flag used to enable debugState on elastic charts
- */
- _echDebugStateFlag?: boolean;
- }
-}
-
-const EMPTY_SLICE = Symbol('empty_slice');
-
-export function PieComponent(
- props: PieExpressionProps & {
- formatFactory: FormatFactory;
- chartsThemeService: ChartsPluginSetup['theme'];
- interactive?: boolean;
- paletteService: PaletteRegistry;
- onClickValue: (data: LensFilterEvent['data']) => void;
- renderMode: RenderMode;
- syncColors: boolean;
- }
-) {
- const [firstTable] = Object.values(props.data.tables);
- const formatters: Record> = {};
-
- const { chartsThemeService, paletteService, syncColors, onClickValue } = props;
- const {
- shape,
- groups,
- metric,
- numberDisplay,
- categoryDisplay,
- legendDisplay,
- legendPosition,
- nestedLegend,
- percentDecimals,
- emptySizeRatio,
- legendMaxLines,
- truncateLegend,
- hideLabels,
- palette,
- showValuesInLegend,
- } = props.args;
- const chartTheme = chartsThemeService.useChartsTheme();
- const chartBaseTheme = chartsThemeService.useChartsBaseTheme();
- const isDarkMode = chartsThemeService.useDarkMode();
-
- if (!hideLabels) {
- firstTable.columns.forEach((column) => {
- formatters[column.id] = props.formatFactory(column.meta.params);
- });
- }
-
- const fillLabel: PartitionLayer['fillLabel'] = {
- valueFont: {
- fontWeight: 700,
- },
- };
-
- if (numberDisplay === 'hidden') {
- // Hides numbers from appearing inside chart, but they still appear in linkLabel
- // and tooltips.
- fillLabel.valueFormatter = () => '';
- }
-
- const bucketColumns = firstTable.columns.filter((col) => groups.includes(col.id));
- const totalSeriesCount = uniq(
- firstTable.rows.map((row) => {
- return bucketColumns.map(({ id: columnId }) => row[columnId]).join(',');
- })
- ).length;
-
- const shouldUseByDataPalette = !syncColors && ['mosaic'].includes(shape) && bucketColumns[1]?.id;
- let byDataPalette: ReturnType;
- if (shouldUseByDataPalette) {
- byDataPalette = byDataColorPaletteMap(
- firstTable,
- bucketColumns[1].id,
- paletteService.get(palette.name),
- palette
- );
- }
-
- let sortingMap: Record = {};
- if (shape === 'mosaic') {
- sortingMap = extractUniqTermsMap(firstTable, bucketColumns[0].id);
- }
-
- const layers: PartitionLayer[] = bucketColumns.map((col, layerIndex) => {
- return {
- groupByRollup: (d: Datum) => d[col.id] ?? EMPTY_SLICE,
- showAccessor: (d: Datum) => d !== EMPTY_SLICE,
- nodeLabel: (d: unknown) => {
- if (hideLabels || d === EMPTY_SLICE) {
- return '';
- }
- if (col.meta.params) {
- return formatters[col.id].convert(d) ?? '';
- }
- return String(d);
- },
- fillLabel,
- sortPredicate: PartitionChartsMeta[shape].sortPredicate?.(bucketColumns, sortingMap),
- shape: {
- fillColor: (d) => {
- const seriesLayers: SeriesLayer[] = [];
-
- // Mind the difference here: the contrast computation for the text ignores the alpha/opacity
- // therefore change it for dask mode
- const defaultColor = isDarkMode ? 'rgba(0,0,0,0)' : 'rgba(255,255,255,0)';
-
- // Color is determined by round-robin on the index of the innermost slice
- // This has to be done recursively until we get to the slice index
- let tempParent: typeof d | typeof d['parent'] = d;
-
- while (tempParent.parent && tempParent.depth > 0) {
- seriesLayers.unshift({
- name: String(tempParent.parent.children[tempParent.sortIndex][0]),
- rankAtDepth: tempParent.sortIndex,
- totalSeriesAtDepth: tempParent.parent.children.length,
- });
- tempParent = tempParent.parent;
- }
-
- if (byDataPalette && seriesLayers[1]) {
- return byDataPalette.getColor(seriesLayers[1].name) || defaultColor;
- }
-
- if (isTreemapOrMosaicShape(shape)) {
- // Only highlight the innermost color of the treemap, as it accurately represents area
- if (layerIndex < bucketColumns.length - 1) {
- return defaultColor;
- }
- // only use the top level series layer for coloring
- if (seriesLayers.length > 1) {
- seriesLayers.pop();
- }
- }
-
- const outputColor = paletteService.get(palette.name).getCategoricalColor(
- seriesLayers,
- {
- behindText: categoryDisplay !== 'hide' || isTreemapOrMosaicShape(shape),
- maxDepth: bucketColumns.length,
- totalSeries: totalSeriesCount,
- syncColors,
- },
- palette.params
- );
-
- return outputColor || defaultColor;
- },
- },
- };
- });
-
- const { legend, partitionType, label: chartType } = PartitionChartsMeta[shape];
-
- const themeOverrides: Required = {
- chartMargins: { top: 0, bottom: 0, left: 0, right: 0 },
- background: {
- color: undefined, // removes background for embeddables
- },
- legend: {
- labelOptions: { maxLines: truncateLegend ? legendMaxLines ?? 1 : 0 },
- },
- partition: {
- fontFamily: chartTheme.barSeriesStyle?.displayValue?.fontFamily,
- outerSizeRatio: 1,
- minFontSize: 10,
- maxFontSize: 16,
- // Labels are added outside the outer ring when the slice is too small
- linkLabel: {
- maxCount: 5,
- fontSize: 11,
- // Dashboard background color is affected by dark mode, which we need
- // to account for in outer labels
- // This does not handle non-dashboard embeddables, which are allowed to
- // have different backgrounds.
- textColor: chartTheme.axes?.axisTitle?.fill,
- },
- sectorLineStroke: chartTheme.lineSeriesStyle?.point?.fill,
- sectorLineWidth: 1.5,
- circlePadding: 4,
- },
- };
- if (isTreemapOrMosaicShape(shape)) {
- if (hideLabels || categoryDisplay === 'hide') {
- themeOverrides.partition.fillLabel = { textColor: 'rgba(0,0,0,0)' };
- }
- } else {
- themeOverrides.partition.emptySizeRatio = shape === 'donut' ? emptySizeRatio : 0;
-
- if (hideLabels || categoryDisplay === 'hide') {
- // Force all labels to be linked, then prevent links from showing
- themeOverrides.partition.linkLabel = {
- maxCount: 0,
- maximumSection: Number.POSITIVE_INFINITY,
- };
- } else if (categoryDisplay === 'inside') {
- // Prevent links from showing
- themeOverrides.partition.linkLabel = { maxCount: 0 };
- } else {
- // if it contains any slice below 2% reduce the ratio
- // first step: sum it up the overall sum
- const overallSum = firstTable.rows.reduce((sum, row) => sum + row[metric!], 0);
- const slices = firstTable.rows.map((row) => row[metric!] / overallSum);
- const smallSlices = slices.filter((value) => value < 0.02).length;
- if (smallSlices) {
- // shrink up to 20% to give some room for the linked values
- themeOverrides.partition.outerSizeRatio = 1 / (1 + Math.min(smallSlices * 0.05, 0.2));
- }
- }
- }
- const metricColumn = firstTable.columns.find((c) => c.id === metric)!;
- const percentFormatter = props.formatFactory({
- id: 'percent',
- params: {
- pattern: `0,0.[${'0'.repeat(percentDecimals ?? DEFAULT_PERCENT_DECIMALS)}]%`,
- },
- });
-
- const hasNegative = firstTable.rows.some((row) => {
- const value = row[metricColumn.id];
- return typeof value === 'number' && value < 0;
- });
-
- const isMetricEmpty = firstTable.rows.every((row) => {
- return !row[metricColumn.id];
- });
-
- const isEmpty =
- firstTable.rows.length === 0 ||
- firstTable.rows.every((row) => groups.every((colId) => typeof row[colId] === 'undefined')) ||
- isMetricEmpty;
-
- if (isEmpty) {
- return (
-
-
-
- );
- }
-
- if (hasNegative) {
- return (
-
-
-
- );
- }
-
- const onElementClickHandler: ElementClickListener = (args) => {
- const context = getFilterContext(args[0][0] as LayerValue[], groups, firstTable);
-
- onClickValue(context);
- };
-
- return (
-
-
-
- getSliceValue(d, metricColumn)}
- percentFormatter={(d: number) => percentFormatter.convert(d / 100)}
- valueGetter={hideLabels || numberDisplay === 'value' ? undefined : 'percent'}
- valueFormatter={(d: number) => (hideLabels ? '' : formatters[metricColumn.id].convert(d))}
- layers={layers}
- topGroove={hideLabels || categoryDisplay === 'hide' ? 0 : undefined}
- />
-
-
- );
-}
diff --git a/x-pack/plugins/lens/public/pie_visualization/render_helpers.test.ts b/x-pack/plugins/lens/public/pie_visualization/render_helpers.test.ts
index bcd9d79babbab..bf09b3f2706e5 100644
--- a/x-pack/plugins/lens/public/pie_visualization/render_helpers.test.ts
+++ b/x-pack/plugins/lens/public/pie_visualization/render_helpers.test.ts
@@ -6,321 +6,11 @@
*/
import type { Datatable } from 'src/plugins/expressions/public';
-import type { PaletteDefinition, PaletteOutput } from 'src/plugins/charts/public';
-import {
- getSliceValue,
- getFilterContext,
- byDataColorPaletteMap,
- extractUniqTermsMap,
- checkTableForContainsSmallValues,
- shouldShowValuesInLegend,
-} from './render_helpers';
-import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks';
-import type { PieLayerState } from '../../common/expressions';
+import { checkTableForContainsSmallValues, shouldShowValuesInLegend } from './render_helpers';
+import { PieLayerState, PieChartTypes } from '../../common';
describe('render helpers', () => {
- describe('#getSliceValue', () => {
- it('returns the metric when positive number', () => {
- expect(
- getSliceValue(
- { a: 'Cat', b: 'Home', c: 5 },
- {
- id: 'c',
- name: 'C',
- meta: { type: 'number' },
- }
- )
- ).toEqual(5);
- });
-
- it('returns the metric when negative number', () => {
- expect(
- getSliceValue(
- { a: 'Cat', b: 'Home', c: -100 },
- {
- id: 'c',
- name: 'C',
- meta: { type: 'number' },
- }
- )
- ).toEqual(0);
- });
-
- it('returns 0 when metric value is 0', () => {
- expect(
- getSliceValue(
- { a: 'Cat', b: 'Home', c: 0 },
- {
- id: 'c',
- name: 'C',
- meta: { type: 'number' },
- }
- )
- ).toEqual(0);
- });
-
- it('returns 0 when metric value is infinite', () => {
- expect(
- getSliceValue(
- { a: 'Cat', b: 'Home', c: Number.POSITIVE_INFINITY },
- {
- id: 'c',
- name: 'C',
- meta: { type: 'number' },
- }
- )
- ).toEqual(0);
- });
- });
-
- describe('#getFilterContext', () => {
- it('handles single slice click for single ring', () => {
- const table: Datatable = {
- type: 'datatable',
- columns: [
- { id: 'a', name: 'A', meta: { type: 'string' } },
- { id: 'b', name: 'B', meta: { type: 'number' } },
- ],
- rows: [
- { a: 'Hi', b: 2 },
- { a: 'Test', b: 4 },
- { a: 'Foo', b: 6 },
- ],
- };
- expect(
- getFilterContext(
- [
- {
- groupByRollup: 'Test',
- value: 100,
- depth: 1,
- path: [],
- sortIndex: 1,
- smAccessorValue: '',
- },
- ],
- ['a'],
- table
- )
- ).toEqual({
- data: [
- {
- row: 1,
- column: 0,
- value: 'Test',
- table,
- },
- ],
- });
- });
-
- it('handles single slice click with 2 rings', () => {
- const table: Datatable = {
- type: 'datatable',
- columns: [
- { id: 'a', name: 'A', meta: { type: 'string' } },
- { id: 'b', name: 'B', meta: { type: 'string' } },
- { id: 'c', name: 'C', meta: { type: 'number' } },
- ],
- rows: [
- { a: 'Hi', b: 'Two', c: 2 },
- { a: 'Test', b: 'Two', c: 5 },
- { a: 'Foo', b: 'Three', c: 6 },
- ],
- };
- expect(
- getFilterContext(
- [
- {
- groupByRollup: 'Test',
- value: 100,
- depth: 1,
- path: [],
- sortIndex: 1,
- smAccessorValue: '',
- },
- ],
- ['a', 'b'],
- table
- )
- ).toEqual({
- data: [
- {
- row: 1,
- column: 0,
- value: 'Test',
- table,
- },
- ],
- });
- });
-
- it('finds right row for multi slice click', () => {
- const table: Datatable = {
- type: 'datatable',
- columns: [
- { id: 'a', name: 'A', meta: { type: 'string' } },
- { id: 'b', name: 'B', meta: { type: 'string' } },
- { id: 'c', name: 'C', meta: { type: 'number' } },
- ],
- rows: [
- { a: 'Hi', b: 'Two', c: 2 },
- { a: 'Test', b: 'Two', c: 5 },
- { a: 'Foo', b: 'Three', c: 6 },
- ],
- };
- expect(
- getFilterContext(
- [
- {
- groupByRollup: 'Test',
- value: 100,
- depth: 1,
- path: [],
- sortIndex: 1,
- smAccessorValue: '',
- },
- {
- groupByRollup: 'Two',
- value: 5,
- depth: 1,
- path: [],
- sortIndex: 1,
- smAccessorValue: '',
- },
- ],
- ['a', 'b'],
- table
- )
- ).toEqual({
- data: [
- {
- row: 1,
- column: 0,
- value: 'Test',
- table,
- },
- {
- row: 1,
- column: 1,
- value: 'Two',
- table,
- },
- ],
- });
- });
- });
-
- describe('#extractUniqTermsMap', () => {
- it('should extract map', () => {
- const table: Datatable = {
- type: 'datatable',
- columns: [
- { id: 'a', name: 'A', meta: { type: 'string' } },
- { id: 'b', name: 'B', meta: { type: 'string' } },
- { id: 'c', name: 'C', meta: { type: 'number' } },
- ],
- rows: [
- { a: 'Hi', b: 'Two', c: 2 },
- { a: 'Test', b: 'Two', c: 5 },
- { a: 'Foo', b: 'Three', c: 6 },
- ],
- };
- expect(extractUniqTermsMap(table, 'a')).toMatchInlineSnapshot(`
- Object {
- "Foo": 2,
- "Hi": 0,
- "Test": 1,
- }
- `);
- expect(extractUniqTermsMap(table, 'b')).toMatchInlineSnapshot(`
- Object {
- "Three": 1,
- "Two": 0,
- }
- `);
- });
- });
-
- describe('#byDataColorPaletteMap', () => {
- let datatable: Datatable;
- let paletteDefinition: PaletteDefinition;
- let palette: PaletteOutput;
- const columnId = 'foo';
-
- beforeEach(() => {
- datatable = {
- rows: [
- {
- [columnId]: '1',
- },
- {
- [columnId]: '2',
- },
- ],
- } as unknown as Datatable;
- paletteDefinition = chartPluginMock.createPaletteRegistry().get('default');
- palette = { type: 'palette' } as PaletteOutput;
- });
-
- it('should create byDataColorPaletteMap', () => {
- expect(byDataColorPaletteMap(datatable, columnId, paletteDefinition, palette))
- .toMatchInlineSnapshot(`
- Object {
- "getColor": [Function],
- }
- `);
- });
-
- it('should get color', () => {
- const colorPaletteMap = byDataColorPaletteMap(
- datatable,
- columnId,
- paletteDefinition,
- palette
- );
-
- expect(colorPaletteMap.getColor('1')).toBe('black');
- });
-
- it('should return undefined in case if values not in datatable', () => {
- const colorPaletteMap = byDataColorPaletteMap(
- datatable,
- columnId,
- paletteDefinition,
- palette
- );
-
- expect(colorPaletteMap.getColor('wrong')).toBeUndefined();
- });
-
- it('should increase rankAtDepth for each new value', () => {
- const colorPaletteMap = byDataColorPaletteMap(
- datatable,
- columnId,
- paletteDefinition,
- palette
- );
- colorPaletteMap.getColor('1');
- colorPaletteMap.getColor('2');
-
- expect(paletteDefinition.getCategoricalColor).toHaveBeenNthCalledWith(
- 1,
- [{ name: '1', rankAtDepth: 0, totalSeriesAtDepth: 2 }],
- { behindText: false },
- undefined
- );
-
- expect(paletteDefinition.getCategoricalColor).toHaveBeenNthCalledWith(
- 2,
- [{ name: '2', rankAtDepth: 1, totalSeriesAtDepth: 2 }],
- { behindText: false },
- undefined
- );
- });
- });
-
describe('#checkTableForContainsSmallValues', () => {
let datatable: Datatable;
const columnId = 'foo';
@@ -380,23 +70,35 @@ describe('render helpers', () => {
describe('#shouldShowValuesInLegend', () => {
it('should firstly read the state value', () => {
expect(
- shouldShowValuesInLegend({ showValuesInLegend: true } as PieLayerState, 'waffle')
+ shouldShowValuesInLegend(
+ { showValuesInLegend: true } as PieLayerState,
+ PieChartTypes.WAFFLE
+ )
).toBeTruthy();
expect(
- shouldShowValuesInLegend({ showValuesInLegend: false } as PieLayerState, 'waffle')
+ shouldShowValuesInLegend(
+ { showValuesInLegend: false } as PieLayerState,
+ PieChartTypes.WAFFLE
+ )
).toBeFalsy();
});
it('should read value from meta in case of value in state is undefined', () => {
expect(
- shouldShowValuesInLegend({ showValuesInLegend: undefined } as PieLayerState, 'waffle')
+ shouldShowValuesInLegend(
+ { showValuesInLegend: undefined } as PieLayerState,
+ PieChartTypes.WAFFLE
+ )
).toBeTruthy();
- expect(shouldShowValuesInLegend({} as PieLayerState, 'waffle')).toBeTruthy();
+ expect(shouldShowValuesInLegend({} as PieLayerState, PieChartTypes.WAFFLE)).toBeTruthy();
expect(
- shouldShowValuesInLegend({ showValuesInLegend: undefined } as PieLayerState, 'pie')
+ shouldShowValuesInLegend(
+ { showValuesInLegend: undefined } as PieLayerState,
+ PieChartTypes.PIE
+ )
).toBeFalsy();
});
});
diff --git a/x-pack/plugins/lens/public/pie_visualization/render_helpers.ts b/x-pack/plugins/lens/public/pie_visualization/render_helpers.ts
index a9685e13e1774..1f6d40abc32ec 100644
--- a/x-pack/plugins/lens/public/pie_visualization/render_helpers.ts
+++ b/x-pack/plugins/lens/public/pie_visualization/render_helpers.ts
@@ -5,47 +5,14 @@
* 2.0.
*/
-import type { Datum, LayerValue } from '@elastic/charts';
-import type { Datatable, DatatableColumn } from 'src/plugins/expressions/public';
-import type { LensFilterEvent } from '../types';
-import type { PieChartTypes, PieLayerState } from '../../common/expressions/pie_chart/types';
-import type { PaletteDefinition, PaletteOutput } from '../../../../../src/plugins/charts/public';
+import type { Datatable } from 'src/plugins/expressions/public';
+import type { PieChartType, PieLayerState } from '../../common/types';
import { PartitionChartsMeta } from './partition_charts_meta';
-export function getSliceValue(d: Datum, metricColumn: DatatableColumn) {
- const value = d[metricColumn.id];
- return Number.isFinite(value) && value >= 0 ? value : 0;
-}
-
-export function getFilterContext(
- clickedLayers: LayerValue[],
- layerColumnIds: string[],
- table: Datatable
-): LensFilterEvent['data'] {
- const matchingIndex = table.rows.findIndex((row) =>
- clickedLayers.every((layer, index) => {
- const columnId = layerColumnIds[index];
- return row[columnId] === layer.groupByRollup;
- })
- );
-
- return {
- data: clickedLayers.map((clickedLayer, index) => ({
- column: table.columns.findIndex((col) => col.id === layerColumnIds[index]),
- row: matchingIndex,
- value: clickedLayer.groupByRollup,
- table,
- })),
- };
-}
-
-export const isPartitionShape = (shape: PieChartTypes | string) =>
+export const isPartitionShape = (shape: PieChartType | string) =>
['donut', 'pie', 'treemap', 'mosaic', 'waffle'].includes(shape);
-export const isTreemapOrMosaicShape = (shape: PieChartTypes | string) =>
- ['treemap', 'mosaic'].includes(shape);
-
-export const shouldShowValuesInLegend = (layer: PieLayerState, shape: PieChartTypes) => {
+export const shouldShowValuesInLegend = (layer: PieLayerState, shape: PieChartType) => {
if ('showValues' in PartitionChartsMeta[shape]?.legend) {
return layer.showValuesInLegend ?? PartitionChartsMeta[shape]?.legend?.showValues ?? true;
}
@@ -53,58 +20,6 @@ export const shouldShowValuesInLegend = (layer: PieLayerState, shape: PieChartTy
return false;
};
-export const extractUniqTermsMap = (dataTable: Datatable, columnId: string) =>
- [...new Set(dataTable.rows.map((item) => item[columnId]))].reduce(
- (acc, item, index) => ({
- ...acc,
- [item]: index,
- }),
- {}
- );
-
-export const byDataColorPaletteMap = (
- dataTable: Datatable,
- columnId: string,
- paletteDefinition: PaletteDefinition,
- { params }: PaletteOutput
-) => {
- const colorMap = new Map(
- dataTable.rows.map((item) => [String(item[columnId]), undefined])
- );
- let rankAtDepth = 0;
-
- return {
- getColor: (item: unknown) => {
- const key = String(item);
-
- if (colorMap.has(key)) {
- let color = colorMap.get(key);
-
- if (color) {
- return color;
- }
- color =
- paletteDefinition.getCategoricalColor(
- [
- {
- name: key,
- totalSeriesAtDepth: colorMap.size,
- rankAtDepth: rankAtDepth++,
- },
- ],
- {
- behindText: false,
- },
- params
- ) || undefined;
-
- colorMap.set(key, color);
- return color;
- }
- },
- };
-};
-
export const checkTableForContainsSmallValues = (
dataTable: Datatable,
columnId: string,
diff --git a/x-pack/plugins/lens/public/pie_visualization/suggestions.test.ts b/x-pack/plugins/lens/public/pie_visualization/suggestions.test.ts
index 229ef9b387ac0..f951d4f07e865 100644
--- a/x-pack/plugins/lens/public/pie_visualization/suggestions.test.ts
+++ b/x-pack/plugins/lens/public/pie_visualization/suggestions.test.ts
@@ -8,7 +8,14 @@
import { PaletteOutput } from 'src/plugins/charts/public';
import { suggestions } from './suggestions';
import type { DataType, SuggestionRequest } from '../types';
-import type { PieLayerState, PieVisualizationState } from '../../common/expressions';
+import {
+ CategoryDisplay,
+ LegendDisplay,
+ NumberDisplay,
+ PieChartTypes,
+ PieLayerState,
+ PieVisualizationState,
+} from '../../common';
import { layerTypes } from '../../common';
describe('suggestions', () => {
@@ -53,16 +60,16 @@ describe('suggestions', () => {
changeType: 'unchanged',
},
state: {
- shape: 'pie',
+ shape: PieChartTypes.PIE,
layers: [
{
layerId: 'first',
layerType: layerTypes.DATA,
groups: [],
metric: 'a',
- numberDisplay: 'hidden',
- categoryDisplay: 'default',
- legendDisplay: 'default',
+ numberDisplay: NumberDisplay.HIDDEN,
+ categoryDisplay: CategoryDisplay.DEFAULT,
+ legendDisplay: LegendDisplay.DEFAULT,
},
],
},
@@ -168,7 +175,7 @@ describe('suggestions', () => {
changeType: 'initial',
},
state: {
- shape: 'mosaic',
+ shape: PieChartTypes.MOSAIC,
layers: [{} as PieLayerState],
},
keptLayerIds: ['first'],
@@ -380,7 +387,7 @@ describe('suggestions', () => {
expect(results).toContainEqual(
expect.objectContaining({
- state: expect.objectContaining({ shape: 'donut' }),
+ state: expect.objectContaining({ shape: PieChartTypes.DONUT }),
})
);
});
@@ -412,7 +419,7 @@ describe('suggestions', () => {
expect(results).toContainEqual(
expect.objectContaining({
- state: expect.objectContaining({ shape: 'pie' }),
+ state: expect.objectContaining({ shape: PieChartTypes.PIE }),
})
);
});
@@ -542,7 +549,7 @@ describe('suggestions', () => {
changeType: 'unchanged',
},
state: {
- shape: 'treemap',
+ shape: PieChartTypes.TREEMAP,
palette,
layers: [
{
@@ -551,9 +558,9 @@ describe('suggestions', () => {
groups: ['a'],
metric: 'b',
- numberDisplay: 'hidden',
- categoryDisplay: 'inside',
- legendDisplay: 'show',
+ numberDisplay: NumberDisplay.HIDDEN,
+ categoryDisplay: CategoryDisplay.INSIDE,
+ legendDisplay: LegendDisplay.SHOW,
percentDecimals: 0,
legendMaxLines: 1,
truncateLegend: true,
@@ -566,7 +573,7 @@ describe('suggestions', () => {
).toContainEqual(
expect.objectContaining({
state: {
- shape: 'donut',
+ shape: PieChartTypes.DONUT,
palette,
layers: [
{
@@ -575,8 +582,8 @@ describe('suggestions', () => {
groups: ['a'],
metric: 'b',
- numberDisplay: 'hidden',
- categoryDisplay: 'inside',
+ numberDisplay: NumberDisplay.HIDDEN,
+ categoryDisplay: CategoryDisplay.INSIDE,
legendDisplay: 'show',
percentDecimals: 0,
legendMaxLines: 1,
@@ -601,7 +608,7 @@ describe('suggestions', () => {
changeType: 'unchanged',
},
state: {
- shape: 'treemap',
+ shape: PieChartTypes.TREEMAP,
layers: [
{
layerId: 'first',
@@ -609,9 +616,9 @@ describe('suggestions', () => {
groups: [],
metric: 'a',
- numberDisplay: 'hidden',
- categoryDisplay: 'default',
- legendDisplay: 'default',
+ numberDisplay: NumberDisplay.HIDDEN,
+ categoryDisplay: CategoryDisplay.DEFAULT,
+ legendDisplay: LegendDisplay.DEFAULT,
},
],
},
@@ -651,16 +658,16 @@ describe('suggestions', () => {
changeType: 'extended',
},
state: {
- shape: 'treemap',
+ shape: PieChartTypes.TREEMAP,
layers: [
{
layerId: 'first',
layerType: layerTypes.DATA,
groups: ['a', 'b'],
metric: 'e',
- numberDisplay: 'value',
- categoryDisplay: 'default',
- legendDisplay: 'default',
+ numberDisplay: NumberDisplay.VALUE,
+ categoryDisplay: CategoryDisplay.DEFAULT,
+ legendDisplay: LegendDisplay.DEFAULT,
},
],
},
@@ -700,16 +707,16 @@ describe('suggestions', () => {
changeType: 'initial',
},
state: {
- shape: 'treemap',
+ shape: PieChartTypes.TREEMAP,
layers: [
{
layerId: 'first',
layerType: layerTypes.DATA,
groups: ['a', 'b'],
metric: 'e',
- numberDisplay: 'percent',
- categoryDisplay: 'default',
- legendDisplay: 'default',
+ numberDisplay: NumberDisplay.PERCENT,
+ categoryDisplay: CategoryDisplay.DEFAULT,
+ legendDisplay: LegendDisplay.DEFAULT,
},
],
},
@@ -737,7 +744,7 @@ describe('suggestions', () => {
changeType: 'unchanged',
},
state: {
- shape: 'pie',
+ shape: PieChartTypes.PIE,
layers: [
{
layerId: 'first',
@@ -745,9 +752,9 @@ describe('suggestions', () => {
groups: ['a'],
metric: 'b',
- numberDisplay: 'hidden',
- categoryDisplay: 'inside',
- legendDisplay: 'show',
+ numberDisplay: NumberDisplay.HIDDEN,
+ categoryDisplay: CategoryDisplay.INSIDE,
+ legendDisplay: LegendDisplay.SHOW,
percentDecimals: 0,
legendMaxLines: 1,
truncateLegend: true,
@@ -760,7 +767,7 @@ describe('suggestions', () => {
).toContainEqual(
expect.objectContaining({
state: {
- shape: 'treemap',
+ shape: PieChartTypes.TREEMAP,
layers: [
{
layerId: 'first',
@@ -768,8 +775,8 @@ describe('suggestions', () => {
groups: ['a'],
metric: 'b',
- numberDisplay: 'hidden',
- categoryDisplay: 'default', // This is changed
+ numberDisplay: NumberDisplay.HIDDEN,
+ categoryDisplay: CategoryDisplay.DEFAULT, // This is changed
legendDisplay: 'show',
percentDecimals: 0,
legendMaxLines: 1,
@@ -794,7 +801,7 @@ describe('suggestions', () => {
changeType: 'unchanged',
},
state: {
- shape: 'mosaic',
+ shape: PieChartTypes.MOSAIC,
layers: [
{
layerId: 'first',
@@ -802,9 +809,9 @@ describe('suggestions', () => {
groups: [],
metric: 'a',
- numberDisplay: 'hidden',
- categoryDisplay: 'default',
- legendDisplay: 'default',
+ numberDisplay: NumberDisplay.HIDDEN,
+ categoryDisplay: CategoryDisplay.DEFAULT,
+ legendDisplay: LegendDisplay.DEFAULT,
},
],
},
@@ -836,7 +843,7 @@ describe('suggestions', () => {
changeType: 'unchanged',
},
state: {
- shape: 'treemap',
+ shape: PieChartTypes.TREEMAP,
layers: [
{
layerId: 'first',
@@ -844,9 +851,9 @@ describe('suggestions', () => {
groups: ['a', 'b'],
metric: 'c',
- numberDisplay: 'hidden',
- categoryDisplay: 'inside',
- legendDisplay: 'show',
+ numberDisplay: NumberDisplay.HIDDEN,
+ categoryDisplay: CategoryDisplay.INSIDE,
+ legendDisplay: LegendDisplay.SHOW,
percentDecimals: 0,
legendMaxLines: 1,
truncateLegend: true,
@@ -871,7 +878,7 @@ describe('suggestions', () => {
changeType: 'unchanged',
},
state: {
- shape: 'waffle',
+ shape: PieChartTypes.WAFFLE,
layers: [
{
layerId: 'first',
@@ -879,9 +886,9 @@ describe('suggestions', () => {
groups: [],
metric: 'a',
- numberDisplay: 'hidden',
- categoryDisplay: 'default',
- legendDisplay: 'default',
+ numberDisplay: NumberDisplay.HIDDEN,
+ categoryDisplay: CategoryDisplay.DEFAULT,
+ legendDisplay: LegendDisplay.DEFAULT,
},
],
},
@@ -909,16 +916,16 @@ describe('suggestions', () => {
changeType: 'unchanged',
},
state: {
- shape: 'pie',
+ shape: PieChartTypes.PIE,
layers: [
{
layerId: 'first',
layerType: layerTypes.DATA,
groups: ['a', 'b'],
metric: 'c',
- numberDisplay: 'hidden',
- categoryDisplay: 'inside',
- legendDisplay: 'show',
+ numberDisplay: NumberDisplay.HIDDEN,
+ categoryDisplay: CategoryDisplay.INSIDE,
+ legendDisplay: LegendDisplay.SHOW,
percentDecimals: 0,
legendMaxLines: 1,
truncateLegend: true,
diff --git a/x-pack/plugins/lens/public/pie_visualization/suggestions.ts b/x-pack/plugins/lens/public/pie_visualization/suggestions.ts
index dd42dd6474e0b..0ff75ee823d42 100644
--- a/x-pack/plugins/lens/public/pie_visualization/suggestions.ts
+++ b/x-pack/plugins/lens/public/pie_visualization/suggestions.ts
@@ -8,11 +8,17 @@
import { partition } from 'lodash';
import { i18n } from '@kbn/i18n';
import type { SuggestionRequest, TableSuggestionColumn, VisualizationSuggestion } from '../types';
-import { layerTypes } from '../../common';
-import type { PieVisualizationState } from '../../common/expressions';
+import {
+ CategoryDisplay,
+ layerTypes,
+ LegendDisplay,
+ NumberDisplay,
+ PieChartTypes,
+ PieVisualizationState,
+} from '../../common';
+import type { PieChartType } from '../../common/types';
import { PartitionChartsMeta } from './partition_charts_meta';
import { isPartitionShape } from './render_helpers';
-import { PieChartTypes } from '../../common/expressions/pie_chart/types';
function hasIntervalScale(columns: TableSuggestionColumn[]) {
return columns.some((col) => col.operation.scale === 'interval');
@@ -43,14 +49,19 @@ function getNewShape(
let newShape: PieVisualizationState['shape'] | undefined;
if (groups.length !== 1 && !subVisualizationId) {
- newShape = 'pie';
+ newShape = PieChartTypes.PIE;
}
- return newShape ?? 'donut';
+ return newShape ?? PieChartTypes.DONUT;
}
-function hasCustomSuggestionsExists(shape: PieChartTypes | string | undefined) {
- return shape ? ['treemap', 'waffle', 'mosaic'].includes(shape) : false;
+function hasCustomSuggestionsExists(shape: PieChartType | string | undefined) {
+ const shapes: Array = [
+ PieChartTypes.TREEMAP,
+ PieChartTypes.WAFFLE,
+ PieChartTypes.MOSAIC,
+ ];
+ return shape ? shapes.includes(shape) : false;
}
const maximumGroupLength = Math.max(
@@ -116,9 +127,9 @@ export function suggestions({
layerId: table.layerId,
groups: groups.map((col) => col.columnId),
metric: metricColumnId,
- numberDisplay: 'percent',
- categoryDisplay: 'default',
- legendDisplay: 'default',
+ numberDisplay: NumberDisplay.PERCENT,
+ categoryDisplay: CategoryDisplay.DEFAULT,
+ legendDisplay: LegendDisplay.DEFAULT,
nestedLegend: false,
layerType: layerTypes.DATA,
},
@@ -137,13 +148,18 @@ export function suggestions({
...baseSuggestion,
title: i18n.translate('xpack.lens.pie.suggestionLabel', {
defaultMessage: 'As {chartName}',
- values: { chartName: PartitionChartsMeta[newShape === 'pie' ? 'donut' : 'pie'].label },
+ values: {
+ chartName:
+ PartitionChartsMeta[
+ newShape === PieChartTypes.PIE ? PieChartTypes.DONUT : PieChartTypes.PIE
+ ].label,
+ },
description: 'chartName is already translated',
}),
score: 0.1,
state: {
...baseSuggestion.state,
- shape: newShape === 'pie' ? 'donut' : 'pie',
+ shape: newShape === PieChartTypes.PIE ? PieChartTypes.DONUT : PieChartTypes.PIE,
},
hide: true,
});
@@ -159,9 +175,9 @@ export function suggestions({
}),
// Use a higher score when currently active, to prevent chart type switching
// on the user unintentionally
- score: state?.shape === 'treemap' ? 0.7 : 0.5,
+ score: state?.shape === PieChartTypes.TREEMAP ? 0.7 : 0.5,
state: {
- shape: 'treemap',
+ shape: PieChartTypes.TREEMAP,
palette: mainPalette || state?.palette,
layers: [
state?.layers[0]
@@ -171,8 +187,8 @@ export function suggestions({
groups: groups.map((col) => col.columnId),
metric: metricColumnId,
categoryDisplay:
- state.layers[0].categoryDisplay === 'inside'
- ? 'default'
+ state.layers[0].categoryDisplay === CategoryDisplay.INSIDE
+ ? CategoryDisplay.DEFAULT
: state.layers[0].categoryDisplay,
layerType: layerTypes.DATA,
}
@@ -180,9 +196,9 @@ export function suggestions({
layerId: table.layerId,
groups: groups.map((col) => col.columnId),
metric: metricColumnId,
- numberDisplay: 'percent',
- categoryDisplay: 'default',
- legendDisplay: 'default',
+ numberDisplay: NumberDisplay.PERCENT,
+ categoryDisplay: CategoryDisplay.DEFAULT,
+ legendDisplay: LegendDisplay.DEFAULT,
nestedLegend: false,
layerType: layerTypes.DATA,
},
@@ -194,21 +210,21 @@ export function suggestions({
table.changeType === 'reduced' ||
!state ||
hasIntervalScale(groups) ||
- (state && state.shape === 'treemap'),
+ (state && state.shape === PieChartTypes.TREEMAP),
});
}
if (
groups.length <= PartitionChartsMeta.mosaic.maxBuckets &&
- (!subVisualizationId || subVisualizationId === 'mosaic')
+ (!subVisualizationId || subVisualizationId === PieChartTypes.MOSAIC)
) {
results.push({
title: i18n.translate('xpack.lens.pie.mosaicSuggestionLabel', {
defaultMessage: 'As Mosaic',
}),
- score: state?.shape === 'mosaic' ? 0.7 : 0.5,
+ score: state?.shape === PieChartTypes.MOSAIC ? 0.7 : 0.5,
state: {
- shape: 'mosaic',
+ shape: PieChartTypes.MOSAIC,
palette: mainPalette || state?.palette,
layers: [
state?.layers[0]
@@ -217,16 +233,16 @@ export function suggestions({
layerId: table.layerId,
groups: groups.map((col) => col.columnId),
metric: metricColumnId,
- categoryDisplay: 'default',
+ categoryDisplay: CategoryDisplay.DEFAULT,
layerType: layerTypes.DATA,
}
: {
layerId: table.layerId,
groups: groups.map((col) => col.columnId),
metric: metricColumnId,
- numberDisplay: 'percent',
- categoryDisplay: 'default',
- legendDisplay: 'default',
+ numberDisplay: NumberDisplay.PERCENT,
+ categoryDisplay: CategoryDisplay.DEFAULT,
+ legendDisplay: LegendDisplay.DEFAULT,
nestedLegend: false,
layerType: layerTypes.DATA,
},
@@ -239,15 +255,15 @@ export function suggestions({
if (
groups.length <= PartitionChartsMeta.waffle.maxBuckets &&
- (!subVisualizationId || subVisualizationId === 'waffle')
+ (!subVisualizationId || subVisualizationId === PieChartTypes.WAFFLE)
) {
results.push({
title: i18n.translate('xpack.lens.pie.waffleSuggestionLabel', {
defaultMessage: 'As Waffle',
}),
- score: state?.shape === 'waffle' ? 0.7 : 0.5,
+ score: state?.shape === PieChartTypes.WAFFLE ? 0.7 : 0.5,
state: {
- shape: 'waffle',
+ shape: PieChartTypes.WAFFLE,
palette: mainPalette || state?.palette,
layers: [
state?.layers[0]
@@ -256,16 +272,16 @@ export function suggestions({
layerId: table.layerId,
groups: groups.map((col) => col.columnId),
metric: metricColumnId,
- categoryDisplay: 'default',
+ categoryDisplay: CategoryDisplay.DEFAULT,
layerType: layerTypes.DATA,
}
: {
layerId: table.layerId,
groups: groups.map((col) => col.columnId),
metric: metricColumnId,
- numberDisplay: 'percent',
- categoryDisplay: 'default',
- legendDisplay: 'default',
+ numberDisplay: NumberDisplay.PERCENT,
+ categoryDisplay: CategoryDisplay.DEFAULT,
+ legendDisplay: LegendDisplay.DEFAULT,
nestedLegend: false,
layerType: layerTypes.DATA,
},
diff --git a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts
index f703b1b5f419b..9ae9f4ac0cae4 100644
--- a/x-pack/plugins/lens/public/pie_visualization/to_expression.ts
+++ b/x-pack/plugins/lens/public/pie_visualization/to_expression.ts
@@ -6,13 +6,62 @@
*/
import type { Ast } from '@kbn/interpreter';
-import type { PaletteRegistry } from 'src/plugins/charts/public';
+import { Position } from '@elastic/charts';
+
+import type { PaletteOutput, PaletteRegistry } from '../../../../../src/plugins/charts/public';
+import {
+ buildExpression,
+ buildExpressionFunction,
+} from '../../../../../src/plugins/expressions/public';
import type { Operation, DatasourcePublicAPI } from '../types';
-import { DEFAULT_PERCENT_DECIMALS, EMPTY_SIZE_RATIOS } from './constants';
+import { DEFAULT_PERCENT_DECIMALS } from './constants';
import { shouldShowValuesInLegend } from './render_helpers';
-import type { PieLayerState, PieVisualizationState } from '../../common/expressions';
+import {
+ CategoryDisplay,
+ NumberDisplay,
+ PieChartTypes,
+ PieLayerState,
+ PieVisualizationState,
+ EmptySizeRatios,
+ LegendDisplay,
+} from '../../common';
import { getDefaultVisualValuesForLayer } from '../shared_components/datasource_default_values';
+interface Attributes {
+ isPreview: boolean;
+ title?: string;
+ description?: string;
+}
+
+interface OperationColumnId {
+ columnId: string;
+ operation: Operation;
+}
+
+type GenerateExpressionAstFunction = (
+ state: PieVisualizationState,
+ attributes: Attributes,
+ operations: OperationColumnId[],
+ layer: PieLayerState,
+ datasourceLayers: Record,
+ paletteService: PaletteRegistry
+) => Ast | null;
+
+type GenerateExpressionAstArguments = (
+ state: PieVisualizationState,
+ attributes: Attributes,
+ operations: OperationColumnId[],
+ layer: PieLayerState,
+ datasourceLayers: Record,
+ paletteService: PaletteRegistry
+) => Ast['chain'][number]['arguments'];
+
+type GenerateLabelsAstArguments = (
+ state: PieVisualizationState,
+ attributes: Attributes,
+ layer: PieLayerState
+) => [Ast];
+
export const getSortedGroups = (datasource: DatasourcePublicAPI, layer: PieLayerState) => {
const originalOrder = datasource
.getTableSpec()
@@ -22,23 +71,183 @@ export const getSortedGroups = (datasource: DatasourcePublicAPI, layer: PieLayer
return Array.from(new Set(originalOrder.concat(layer.groups)));
};
-export function toExpression(
- state: PieVisualizationState,
- datasourceLayers: Record,
+const prepareDimension = (accessor: string) => {
+ const visdimension = buildExpressionFunction('visdimension', { accessor });
+ return buildExpression([visdimension]).toAst();
+};
+
+const generateCommonLabelsAstArgs: GenerateLabelsAstArguments = (state, attributes, layer) => {
+ const show = [!attributes.isPreview && layer.categoryDisplay !== CategoryDisplay.HIDE];
+ const position = layer.categoryDisplay !== CategoryDisplay.HIDE ? [layer.categoryDisplay] : [];
+ const values = [layer.numberDisplay !== NumberDisplay.HIDDEN];
+ const valuesFormat = layer.numberDisplay !== NumberDisplay.HIDDEN ? [layer.numberDisplay] : [];
+ const percentDecimals = [layer.percentDecimals ?? DEFAULT_PERCENT_DECIMALS];
+
+ return [
+ {
+ type: 'expression',
+ chain: [
+ {
+ type: 'function',
+ function: 'partitionLabels',
+ arguments: { show, position, values, valuesFormat, percentDecimals },
+ },
+ ],
+ },
+ ];
+};
+
+const generateWaffleLabelsAstArguments: GenerateLabelsAstArguments = (...args) => {
+ const [labelsExpr] = generateCommonLabelsAstArgs(...args);
+ const [labels] = labelsExpr.chain;
+ return [
+ {
+ ...labelsExpr,
+ chain: [{ ...labels, percentDecimals: DEFAULT_PERCENT_DECIMALS }],
+ },
+ ];
+};
+
+const generatePaletteAstArguments = (
paletteService: PaletteRegistry,
- attributes: Partial<{ title: string; description: string }> = {}
-) {
- return expressionHelper(state, datasourceLayers, paletteService, {
- ...attributes,
- isPreview: false,
- });
-}
+ palette?: PaletteOutput
+): [Ast] =>
+ palette
+ ? [
+ {
+ type: 'expression',
+ chain: [
+ {
+ type: 'function',
+ function: 'theme',
+ arguments: {
+ variable: ['palette'],
+ default: [paletteService.get(palette.name).toExpression(palette.params)],
+ },
+ },
+ ],
+ },
+ ]
+ : [paletteService.get('default').toExpression()];
+
+const generateCommonArguments: GenerateExpressionAstArguments = (
+ state,
+ attributes,
+ operations,
+ layer,
+ datasourceLayers,
+ paletteService
+) => ({
+ labels: generateCommonLabelsAstArgs(state, attributes, layer),
+ buckets: operations.map((o) => o.columnId).map(prepareDimension),
+ metric: layer.metric ? [prepareDimension(layer.metric)] : [],
+ legendDisplay: [attributes.isPreview ? LegendDisplay.HIDE : layer.legendDisplay],
+ legendPosition: [layer.legendPosition || Position.Right],
+ maxLegendLines: [layer.legendMaxLines ?? 1],
+ nestedLegend: [!!layer.nestedLegend],
+ truncateLegend: [
+ layer.truncateLegend ?? getDefaultVisualValuesForLayer(state, datasourceLayers).truncateText,
+ ],
+ palette: generatePaletteAstArguments(paletteService, state.palette),
+});
+
+const generatePieVisAst: GenerateExpressionAstFunction = (...rest) => ({
+ type: 'expression',
+ chain: [
+ {
+ type: 'function',
+ function: 'pieVis',
+ arguments: {
+ ...generateCommonArguments(...rest),
+ respectSourceOrder: [false],
+ startFromSecondLargestSlice: [true],
+ },
+ },
+ ],
+});
+
+const generateDonutVisAst: GenerateExpressionAstFunction = (...rest) => {
+ const [, , , layer] = rest;
+ return {
+ type: 'expression',
+ chain: [
+ {
+ type: 'function',
+ function: 'pieVis',
+ arguments: {
+ ...generateCommonArguments(...rest),
+ respectSourceOrder: [false],
+ isDonut: [true],
+ startFromSecondLargestSlice: [true],
+ emptySizeRatio: [layer.emptySizeRatio ?? EmptySizeRatios.SMALL],
+ },
+ },
+ ],
+ };
+};
+
+const generateTreemapVisAst: GenerateExpressionAstFunction = (...rest) => {
+ const [, , , layer] = rest;
+ return {
+ type: 'expression',
+ chain: [
+ {
+ type: 'function',
+ function: 'treemapVis',
+ arguments: {
+ ...generateCommonArguments(...rest),
+ nestedLegend: [!!layer.nestedLegend],
+ },
+ },
+ ],
+ };
+};
+
+const generateMosaicVisAst: GenerateExpressionAstFunction = (...rest) => ({
+ type: 'expression',
+ chain: [
+ {
+ type: 'function',
+ function: 'mosaicVis',
+ arguments: generateCommonArguments(...rest),
+ },
+ ],
+});
+
+const generateWaffleVisAst: GenerateExpressionAstFunction = (...rest) => {
+ const { buckets, nestedLegend, ...args } = generateCommonArguments(...rest);
+ const [state, attributes, , layer] = rest;
+ return {
+ type: 'expression',
+ chain: [
+ {
+ type: 'function',
+ function: 'waffleVis',
+ arguments: {
+ ...args,
+ bucket: buckets,
+ labels: generateWaffleLabelsAstArguments(state, attributes, layer),
+ showValuesInLegend: [shouldShowValuesInLegend(layer, state.shape)],
+ },
+ },
+ ],
+ };
+};
+
+const generateExprAst: GenerateExpressionAstFunction = (state, ...restArgs) =>
+ ({
+ [PieChartTypes.PIE]: () => generatePieVisAst(state, ...restArgs),
+ [PieChartTypes.DONUT]: () => generateDonutVisAst(state, ...restArgs),
+ [PieChartTypes.TREEMAP]: () => generateTreemapVisAst(state, ...restArgs),
+ [PieChartTypes.MOSAIC]: () => generateMosaicVisAst(state, ...restArgs),
+ [PieChartTypes.WAFFLE]: () => generateWaffleVisAst(state, ...restArgs),
+ }[state.shape]());
function expressionHelper(
state: PieVisualizationState,
datasourceLayers: Record,
paletteService: PaletteRegistry,
- attributes: { isPreview: boolean; title?: string; description?: string } = { isPreview: false }
+ attributes: Attributes = { isPreview: false }
): Ast | null {
const layer = state.layers[0];
const datasource = datasourceLayers[layer.layerId];
@@ -51,63 +260,20 @@ function expressionHelper(
if (!layer.metric || !operations.length) {
return null;
}
- return {
- type: 'expression',
- chain: [
- {
- type: 'function',
- function: 'lens_pie',
- arguments: {
- title: [attributes.title || ''],
- description: [attributes.description || ''],
- shape: [state.shape],
- hideLabels: [attributes.isPreview],
- groups: operations.map((o) => o.columnId),
- metric: [layer.metric],
- numberDisplay: [layer.numberDisplay],
- categoryDisplay: [layer.categoryDisplay],
- legendDisplay: [layer.legendDisplay],
- legendPosition: [layer.legendPosition || 'right'],
- emptySizeRatio: [layer.emptySizeRatio ?? EMPTY_SIZE_RATIOS.SMALL],
- showValuesInLegend: [shouldShowValuesInLegend(layer, state.shape)],
- percentDecimals: [
- state.shape === 'waffle'
- ? DEFAULT_PERCENT_DECIMALS
- : layer.percentDecimals ?? DEFAULT_PERCENT_DECIMALS,
- ],
- legendMaxLines: [layer.legendMaxLines ?? 1],
- truncateLegend: [
- layer.truncateLegend ??
- getDefaultVisualValuesForLayer(state, datasourceLayers).truncateText,
- ],
- nestedLegend: [!!layer.nestedLegend],
- ...(state.palette
- ? {
- palette: [
- {
- type: 'expression',
- chain: [
- {
- type: 'function',
- function: 'theme',
- arguments: {
- variable: ['palette'],
- default: [
- paletteService
- .get(state.palette.name)
- .toExpression(state.palette.params),
- ],
- },
- },
- ],
- },
- ],
- }
- : {}),
- },
- },
- ],
- };
+
+ return generateExprAst(state, attributes, operations, layer, datasourceLayers, paletteService);
+}
+
+export function toExpression(
+ state: PieVisualizationState,
+ datasourceLayers: Record,
+ paletteService: PaletteRegistry,
+ attributes: Partial<{ title: string; description: string }> = {}
+) {
+ return expressionHelper(state, datasourceLayers, paletteService, {
+ ...attributes,
+ isPreview: false,
+ });
}
export function toPreviewExpression(
diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx
index cebacd5c95863..f188aa12069d7 100644
--- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx
+++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx
@@ -20,7 +20,7 @@ import type { Position } from '@elastic/charts';
import type { PaletteRegistry } from 'src/plugins/charts/public';
import { DEFAULT_PERCENT_DECIMALS } from './constants';
import { PartitionChartsMeta } from './partition_charts_meta';
-import type { PieVisualizationState, SharedPieLayerState } from '../../common/expressions';
+import { LegendDisplay, PieVisualizationState, SharedPieLayerState } from '../../common';
import { VisualizationDimensionEditorProps, VisualizationToolbarProps } from '../types';
import { ToolbarPopover, LegendSettingsPopover, useDebouncedValue } from '../shared_components';
import { PalettePicker } from '../shared_components';
@@ -34,21 +34,21 @@ const legendOptions: Array<{
}> = [
{
id: 'pieLegendDisplay-default',
- value: 'default',
+ value: LegendDisplay.DEFAULT,
label: i18n.translate('xpack.lens.pieChart.legendVisibility.auto', {
defaultMessage: 'Auto',
}),
},
{
id: 'pieLegendDisplay-show',
- value: 'show',
+ value: LegendDisplay.SHOW,
label: i18n.translate('xpack.lens.pieChart.legendVisibility.show', {
defaultMessage: 'Show',
}),
},
{
id: 'pieLegendDisplay-hide',
- value: 'hide',
+ value: LegendDisplay.HIDE,
label: i18n.translate('xpack.lens.pieChart.legendVisibility.hide', {
defaultMessage: 'Hide',
}),
diff --git a/x-pack/plugins/lens/public/pie_visualization/visualization.scss b/x-pack/plugins/lens/public/pie_visualization/visualization.scss
deleted file mode 100644
index a8890208596b6..0000000000000
--- a/x-pack/plugins/lens/public/pie_visualization/visualization.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-.lnsPieExpression__container {
- height: 100%;
- width: 100%;
- // the FocusTrap is adding extra divs which are making the visualization redraw twice
- // with a visible glitch. This make the chart library resilient to this extra reflow
- overflow-x: hidden;
-}
diff --git a/x-pack/plugins/lens/public/pie_visualization/visualization.test.ts b/x-pack/plugins/lens/public/pie_visualization/visualization.test.ts
index 86ac635e36068..c178613657947 100644
--- a/x-pack/plugins/lens/public/pie_visualization/visualization.test.ts
+++ b/x-pack/plugins/lens/public/pie_visualization/visualization.test.ts
@@ -6,7 +6,13 @@
*/
import { getPieVisualization } from './visualization';
-import type { PieVisualizationState } from '../../common/expressions';
+import {
+ PieVisualizationState,
+ PieChartTypes,
+ CategoryDisplay,
+ NumberDisplay,
+ LegendDisplay,
+} from '../../common';
import { layerTypes } from '../../common';
import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks';
import { createMockDatasource, createMockFramePublicAPI } from '../mocks';
@@ -24,16 +30,16 @@ const pieVisualization = getPieVisualization({
function getExampleState(): PieVisualizationState {
return {
- shape: 'pie',
+ shape: PieChartTypes.PIE,
layers: [
{
layerId: LAYER_ID,
layerType: layerTypes.DATA,
groups: [],
metric: undefined,
- numberDisplay: 'percent',
- categoryDisplay: 'default',
- legendDisplay: 'default',
+ numberDisplay: NumberDisplay.PERCENT,
+ categoryDisplay: CategoryDisplay.DEFAULT,
+ legendDisplay: LegendDisplay.DEFAULT,
nestedLegend: false,
},
],
@@ -81,14 +87,14 @@ describe('pie_visualization', () => {
groups: ['a'],
layerId: LAYER_ID,
layerType: layerTypes.DATA,
- numberDisplay: 'percent',
- categoryDisplay: 'default',
- legendDisplay: 'default',
+ numberDisplay: NumberDisplay.PERCENT,
+ categoryDisplay: CategoryDisplay.DEFAULT,
+ legendDisplay: LegendDisplay.DEFAULT,
nestedLegend: false,
metric: undefined,
},
],
- shape: 'donut',
+ shape: PieChartTypes.DONUT,
};
const setDimensionResult = pieVisualization.setDimension({
prevState,
@@ -100,7 +106,7 @@ describe('pie_visualization', () => {
expect(setDimensionResult).toEqual(
expect.objectContaining({
- shape: 'donut',
+ shape: PieChartTypes.DONUT,
})
);
});
diff --git a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx
index 8c52fc5a52fd8..0e8f05eff8920 100644
--- a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx
+++ b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx
@@ -20,21 +20,21 @@ import type {
VisualizationDimensionGroupConfig,
} from '../types';
import { getSortedGroups, toExpression, toPreviewExpression } from './to_expression';
-import type { PieLayerState, PieVisualizationState } from '../../common/expressions';
-import { layerTypes } from '../../common';
+import { CategoryDisplay, layerTypes, LegendDisplay, NumberDisplay } from '../../common';
import { suggestions } from './suggestions';
import { PartitionChartsMeta } from './partition_charts_meta';
import { DimensionEditor, PieToolbar } from './toolbar';
import { checkTableForContainsSmallValues } from './render_helpers';
+import { PieChartTypes, PieLayerState, PieVisualizationState } from '../../common';
function newLayerState(layerId: string): PieLayerState {
return {
layerId,
groups: [],
metric: undefined,
- numberDisplay: 'percent',
- categoryDisplay: 'default',
- legendDisplay: 'default',
+ numberDisplay: NumberDisplay.PERCENT,
+ categoryDisplay: CategoryDisplay.DEFAULT,
+ legendDisplay: LegendDisplay.DEFAULT,
nestedLegend: false,
layerType: layerTypes.DATA,
};
@@ -108,7 +108,7 @@ export const getPieVisualization = ({
initialize(addNewLayer, state, mainPalette) {
return (
state || {
- shape: 'donut',
+ shape: PieChartTypes.DONUT,
layers: [newLayerState(addNewLayer())],
palette: mainPalette,
}
diff --git a/x-pack/plugins/lens/server/expressions/expressions.ts b/x-pack/plugins/lens/server/expressions/expressions.ts
index a04ad27d1a276..f258db7f9aede 100644
--- a/x-pack/plugins/lens/server/expressions/expressions.ts
+++ b/x-pack/plugins/lens/server/expressions/expressions.ts
@@ -7,7 +7,6 @@
import type { CoreSetup } from 'kibana/server';
import {
- pie,
xyChart,
counterRate,
metricChart,
@@ -36,7 +35,6 @@ export const setupExpressions = (
[lensMultitable].forEach((expressionType) => expressions.registerType(expressionType));
[
- pie,
xyChart,
counterRate,
metricChart,
diff --git a/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx b/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx
index 8b8d361611a2d..c982cdd5604d1 100644
--- a/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx
+++ b/x-pack/plugins/osquery/public/packs/pack_queries_status_table.tsx
@@ -24,7 +24,7 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage, FormattedDate, FormattedTime, FormattedRelative } from '@kbn/i18n-react';
import moment from 'moment-timezone';
-import {
+import type {
TypedLensByValueInput,
PersistedIndexPatternLayer,
PieVisualizationState,
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index a5020c1122651..125c9ff096507 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -631,17 +631,14 @@
"xpack.lens.pie.addLayer": "ビジュアライゼーションレイヤーを追加",
"xpack.lens.pie.arrayValues": "{label}には配列値が含まれます。可視化が想定通りに表示されない場合があります。",
"xpack.lens.pie.donutLabel": "ドーナッツ",
- "xpack.lens.pie.expressionHelpLabel": "円表示",
"xpack.lens.pie.groupLabel": "比率",
"xpack.lens.pie.groupsizeLabel": "サイズ単位",
"xpack.lens.pie.pielabel": "円",
- "xpack.lens.pie.pieWithNegativeWarningLabel": "{chartType}グラフは負の値では表示できません。",
"xpack.lens.pie.sliceGroupLabel": "スライス",
"xpack.lens.pie.suggestionLabel": "{chartName}として",
"xpack.lens.pie.treemapGroupLabel": "グループ分けの条件",
"xpack.lens.pie.treemaplabel": "ツリーマップ",
"xpack.lens.pie.treemapSuggestionLabel": "ツリーマップとして",
- "xpack.lens.pie.visualizationName": "円",
"xpack.lens.pieChart.categoriesInLegendLabel": "ラベルを非表示",
"xpack.lens.pieChart.fitInsideOnlyLabel": "内部のみ",
"xpack.lens.pieChart.hiddenNumbersLabel": "グラフから非表示",
@@ -2983,8 +2980,6 @@
"expressionPartitionVis.legend.filterForValueButtonAriaLabel": "値でフィルター",
"expressionPartitionVis.legend.filterOptionsLegend": "{legendDataLabel}、フィルターオプション",
"expressionPartitionVis.legend.filterOutValueButtonAriaLabel": "値を除外",
- "expressionPartitionVis.negativeValuesFound": "円/ドーナツグラフは負の値では表示できません。",
- "expressionPartitionVis.noResultsFoundTitle": "結果が見つかりませんでした",
"fieldFormats.advancedSettings.format.bytesFormat.numeralFormatLinkText": "数字フォーマット",
"fieldFormats.advancedSettings.format.bytesFormatText": "「バイト」フォーマットのデフォルト{numeralFormatLink}です",
"fieldFormats.advancedSettings.format.bytesFormatTitle": "バイトフォーマット",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index ab50cb20956a8..69e9f293f845d 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -643,17 +643,14 @@
"xpack.lens.pie.addLayer": "添加可视化图层",
"xpack.lens.pie.arrayValues": "{label} 包含数组值。您的可视化可能无法正常渲染。",
"xpack.lens.pie.donutLabel": "圆环图",
- "xpack.lens.pie.expressionHelpLabel": "饼图呈现器",
"xpack.lens.pie.groupLabel": "比例",
"xpack.lens.pie.groupsizeLabel": "大小调整依据",
"xpack.lens.pie.pielabel": "饼图",
- "xpack.lens.pie.pieWithNegativeWarningLabel": "{chartType} 图表无法使用负值进行呈现。",
"xpack.lens.pie.sliceGroupLabel": "切片依据",
"xpack.lens.pie.suggestionLabel": "为 {chartName}",
"xpack.lens.pie.treemapGroupLabel": "分组依据",
"xpack.lens.pie.treemaplabel": "树状图",
"xpack.lens.pie.treemapSuggestionLabel": "为树状图",
- "xpack.lens.pie.visualizationName": "饼图",
"xpack.lens.pieChart.categoriesInLegendLabel": "隐藏标签",
"xpack.lens.pieChart.fitInsideOnlyLabel": "仅内部",
"xpack.lens.pieChart.hiddenNumbersLabel": "在图表中隐藏",
@@ -2767,8 +2764,6 @@
"expressionPartitionVis.legend.filterForValueButtonAriaLabel": "筛留值",
"expressionPartitionVis.legend.filterOptionsLegend": "{legendDataLabel}, 筛选选项",
"expressionPartitionVis.legend.filterOutValueButtonAriaLabel": "筛除值",
- "expressionPartitionVis.negativeValuesFound": "饼图/圆环图无法使用负值进行呈现。",
- "expressionPartitionVis.noResultsFoundTitle": "找不到结果",
"fieldFormats.advancedSettings.format.bytesFormat.numeralFormatLinkText": "数值格式",
"fieldFormats.advancedSettings.format.bytesFormatText": "“字节”格式的默认{numeralFormatLink}",
"fieldFormats.advancedSettings.format.bytesFormatTitle": "字节格式",
diff --git a/x-pack/test/functional/apps/dashboard/dashboard_lens_by_value.ts b/x-pack/test/functional/apps/dashboard/dashboard_lens_by_value.ts
index 26efa4248850b..382449e5e2586 100644
--- a/x-pack/test/functional/apps/dashboard/dashboard_lens_by_value.ts
+++ b/x-pack/test/functional/apps/dashboard/dashboard_lens_by_value.ts
@@ -11,7 +11,6 @@ import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getPageObjects, getService }: FtrProviderContext) {
const PageObjects = getPageObjects(['common', 'dashboard', 'visualize', 'lens', 'timePicker']);
- const find = getService('find');
const esArchiver = getService('esArchiver');
const testSubjects = getService('testSubjects');
const dashboardPanelActions = getService('dashboardPanelActions');
@@ -49,8 +48,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
await PageObjects.lens.saveAndReturn();
await PageObjects.dashboard.waitForRenderComplete();
- const pieExists = await find.existsByCssSelector('.lnsPieExpression__container');
- expect(pieExists).to.be(true);
+ const partitionVisExists = await testSubjects.exists('partitionVisChart');
+ expect(partitionVisExists).to.be(true);
});
it('editing and saving a lens by value panel retains number of panels', async () => {
diff --git a/x-pack/test/functional/apps/dashboard/feature_controls/time_to_visualize_security.ts b/x-pack/test/functional/apps/dashboard/feature_controls/time_to_visualize_security.ts
index f6692a2edb3bf..1d2d3f6862e43 100644
--- a/x-pack/test/functional/apps/dashboard/feature_controls/time_to_visualize_security.ts
+++ b/x-pack/test/functional/apps/dashboard/feature_controls/time_to_visualize_security.ts
@@ -103,8 +103,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
await PageObjects.lens.saveAndReturn();
await PageObjects.dashboard.waitForRenderComplete();
- const pieExists = await find.existsByCssSelector('.lnsPieExpression__container');
- expect(pieExists).to.be(true);
+ const partitionVisExists = await testSubjects.exists('partitionVisChart');
+ expect(partitionVisExists).to.be(true);
});
it('disables save to library button without visualize save permissions', async () => {