diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index ff7dde5649b251..a18c9337d79d59 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -52,7 +52,7 @@ pageLoadAssetSize: expressionLegacyMetricVis: 23121 expressionMetric: 22238 expressionMetricVis: 23121 - expressionPartitionVis: 28000 + expressionPartitionVis: 29000 expressionRepeatImage: 22341 expressionRevealImage: 25675 expressions: 140958 diff --git a/src/plugins/chart_expressions/common/chart_size_transition_veil.tsx b/src/plugins/chart_expressions/common/chart_size_transition_veil.tsx new file mode 100644 index 00000000000000..8a0c11f363f9c0 --- /dev/null +++ b/src/plugins/chart_expressions/common/chart_size_transition_veil.tsx @@ -0,0 +1,94 @@ +/* + * 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, { useEffect } from 'react'; +import { useCallback, useRef, useState } from 'react'; +import fastIsEqual from 'fast-deep-equal'; +import { useResizeObserver } from '@elastic/eui'; +import { euiThemeVars } from '@kbn/ui-theme'; +import type { ChartSizeSpec } from './types'; + +/** + * This hook is used to show a veil over the chart while it is being resized + * in response to a change in the container dimensions. + * + * It is only relevant if client dimensions are being requested based on chart configuration. + * + * This whole feature is a nice-to-have. If it proves to be a source of bugs, + * we can consider removing it and accepting the aesthetic drawback. + */ +export function useSizeTransitionVeil( + chartSizeSpec: ChartSizeSpec, + setChartSize: (d: ChartSizeSpec) => void, + // should be retrieved from handlers.shouldUseSizeTransitionVeil function + shouldUseVeil: boolean +) { + const containerRef = useRef(null); + const containerSize = useResizeObserver(containerRef.current); + const currentContainerSize = useRef<{ width: number; height: number }>(containerSize); + + // This useEffect hook is here to make up for the fact that the initial container size + // is not correctly reported by the useResizeObserver hook (see https://github.com/elastic/eui/issues/7458). + useEffect(() => { + currentContainerSize.current = { + width: containerRef.current?.clientWidth ?? 0, + height: containerRef.current?.clientHeight ?? 0, + }; + }, []); + + const [showVeil, setShowVeil] = useState(false); + const currentChartSizeSpec = useRef(); + const specJustChanged = useRef(false); + + useEffect(() => { + if (!fastIsEqual(containerSize, currentContainerSize.current) && specJustChanged.current) { + // If the container size has changed, we need to show the veil to hide the chart since it + // be rendered based on the previous container size before being updated to the current size. + // + // 1. we show the veil + // 2. the charts library will render the chart based on the previous container dimensions + // 3. the charts library will resize the chart to the updated container dimensions + // 4. we hide the veil + setShowVeil(true); + currentContainerSize.current = containerSize; + } + }, [setShowVeil, containerSize]); + + useEffect(() => { + if (!fastIsEqual(chartSizeSpec, currentChartSizeSpec.current)) { + setChartSize(chartSizeSpec); + currentChartSizeSpec.current = chartSizeSpec; + specJustChanged.current = true; + + setTimeout(() => { + specJustChanged.current = false; + }, 500); + } + }, [chartSizeSpec, setChartSize]); + + const onResize = useCallback(() => { + setShowVeil(false); + }, []); + + return { + veil: ( +
+ ), + onResize, + containerRef, + }; +} diff --git a/src/plugins/chart_expressions/common/index.ts b/src/plugins/chart_expressions/common/index.ts index acc3b4d8c88cd9..93b5d83710bb24 100644 --- a/src/plugins/chart_expressions/common/index.ts +++ b/src/plugins/chart_expressions/common/index.ts @@ -12,5 +12,7 @@ export { getOverridesFor, isOnAggBasedEditor, } from './utils'; -export type { Simplify, MakeOverridesSerializable } from './types'; +export type { Simplify, MakeOverridesSerializable, ChartSizeSpec, ChartSizeEvent } from './types'; +export { isChartSizeEvent } from './types'; export { getColorCategories } from './color_categories'; +export { useSizeTransitionVeil } from './chart_size_transition_veil'; diff --git a/src/plugins/chart_expressions/common/tsconfig.json b/src/plugins/chart_expressions/common/tsconfig.json index 7ac76523fcb6c8..37a3b2f5bf6075 100644 --- a/src/plugins/chart_expressions/common/tsconfig.json +++ b/src/plugins/chart_expressions/common/tsconfig.json @@ -4,11 +4,13 @@ "outDir": "target/types", "types": [ "jest", - "node" + "node", + "@emotion/react/types/css-prop", ] }, "include": [ "**/*.ts", + "**/*.tsx", ], "exclude": [ "target/**/*" @@ -17,5 +19,6 @@ "@kbn/core-execution-context-common", "@kbn/expressions-plugin", "@kbn/data-plugin", + "@kbn/ui-theme", ] } diff --git a/src/plugins/chart_expressions/common/types.ts b/src/plugins/chart_expressions/common/types.ts index acdd5909f1aec2..6413a8f644efc6 100644 --- a/src/plugins/chart_expressions/common/types.ts +++ b/src/plugins/chart_expressions/common/types.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import type { ExpressionRendererEvent } from '@kbn/expressions-plugin/public'; import React from 'react'; export type Simplify = { [KeyType in keyof T]: T[KeyType] } & {}; @@ -26,3 +27,27 @@ export type MakeOverridesSerializable = { ? MakeOverridesSerializable : NonNullable; }; + +export interface ChartSizeEvent extends ExpressionRendererEvent { + name: 'chartSize'; + data: ChartSizeSpec; +} + +export type ChartSizeUnit = 'pixels' | 'percentage'; + +interface ChartSizeDimensions { + x?: { value: number; unit: ChartSizeUnit }; + y?: { value: number; unit: ChartSizeUnit }; +} + +export interface ChartSizeSpec { + // if maxDimensions are provided, the aspect ratio will be computed from them + maxDimensions?: ChartSizeDimensions; + minDimensions?: ChartSizeDimensions; + aspectRatio?: { x: number; y: number }; +} + +export function isChartSizeEvent(event: ExpressionRendererEvent): event is ChartSizeEvent { + const expectedName: ChartSizeEvent['name'] = 'chartSize'; + return event.name === expectedName; +} diff --git a/src/plugins/chart_expressions/expression_gauge/common/types/expression_renderers.ts b/src/plugins/chart_expressions/expression_gauge/common/types/expression_renderers.ts index 1cdb5b464f3f5d..5bda3a872da000 100644 --- a/src/plugins/chart_expressions/expression_gauge/common/types/expression_renderers.ts +++ b/src/plugins/chart_expressions/expression_gauge/common/types/expression_renderers.ts @@ -11,6 +11,7 @@ import type { PersistedState } from '@kbn/visualizations-plugin/public'; import type { ChartsPluginSetup } from '@kbn/charts-plugin/public'; import type { IFieldFormat, SerializedFieldFormat } from '@kbn/field-formats-plugin/common'; import type { AllowedSettingsOverrides, AllowedChartOverrides } from '@kbn/charts-plugin/common'; +import type { ChartSizeSpec } from '@kbn/chart-expressions-common'; import type { AllowedGaugeOverrides, GaugeExpressionProps } from './expression_functions'; export type FormatFactory = (mapping?: SerializedFieldFormat) => IFieldFormat; @@ -22,4 +23,6 @@ export type GaugeRenderProps = GaugeExpressionProps & { renderComplete: () => void; uiState: PersistedState; overrides?: AllowedGaugeOverrides & AllowedSettingsOverrides & AllowedChartOverrides; + shouldUseVeil: boolean; + setChartSize: (d: ChartSizeSpec) => void; }; diff --git a/src/plugins/chart_expressions/expression_gauge/public/components/__snapshots__/gauge_component.test.tsx.snap b/src/plugins/chart_expressions/expression_gauge/public/components/__snapshots__/gauge_component.test.tsx.snap index f797f9ba344e07..30735f360e32cd 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/components/__snapshots__/gauge_component.test.tsx.snap +++ b/src/plugins/chart_expressions/expression_gauge/public/components/__snapshots__/gauge_component.test.tsx.snap @@ -536,6 +536,7 @@ exports[`GaugeComponent renders the chart 1`] = ` /> } onRenderChange={[Function]} + onResize={[Function]} theme={ Array [ Object { diff --git a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx index da8985d0427af1..29163b414d82b4 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx +++ b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx @@ -102,6 +102,8 @@ describe('GaugeComponent', function () { paletteService: await paletteThemeService.getPalettes(), uiState, renderComplete: jest.fn(), + setChartSize: jest.fn(), + shouldUseVeil: false, }; }); diff --git a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx index 6565673cea0daf..a5a71ffc25c347 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx +++ b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx @@ -12,7 +12,11 @@ import type { PaletteOutput } from '@kbn/coloring'; import { FieldFormat } from '@kbn/field-formats-plugin/common'; import type { CustomPaletteState } from '@kbn/charts-plugin/public'; import { EmptyPlaceholder } from '@kbn/charts-plugin/public'; -import { getOverridesFor } from '@kbn/chart-expressions-common'; +import { + type ChartSizeSpec, + getOverridesFor, + useSizeTransitionVeil, +} from '@kbn/chart-expressions-common'; import { isVisDimension } from '@kbn/visualizations-plugin/common/utils'; import { i18n } from '@kbn/i18n'; import { @@ -178,6 +182,8 @@ export const GaugeComponent: FC = memo( chartsThemeService, renderComplete, overrides, + shouldUseVeil, + setChartSize, }) => { const { shape: gaugeType, @@ -253,6 +259,26 @@ export const GaugeComponent: FC = memo( [renderComplete] ); + const chartSizeSpec: ChartSizeSpec = { + maxDimensions: { + ...(gaugeType === GaugeShapes.HORIZONTAL_BULLET + ? { + x: { value: 600, unit: 'pixels' }, + y: { value: 300, unit: 'pixels' }, + } + : { + y: { value: 600, unit: 'pixels' }, + x: { value: 300, unit: 'pixels' }, + }), + }, + }; + + const { veil, onResize, containerRef } = useSizeTransitionVeil( + chartSizeSpec, + setChartSize, + shouldUseVeil + ); + const table = data; const accessors = getAccessorsFromArgs(args, table.columns); @@ -359,7 +385,8 @@ export const GaugeComponent: FC = memo( : {}; return ( -
+
+ {veil} } @@ -369,6 +396,7 @@ export const GaugeComponent: FC = memo( ariaLabel={args.ariaLabel} ariaUseDefaultSummary={!args.ariaLabel} onRenderChange={onRenderChange} + onResize={onResize} locale={i18n.getLocale()} {...getOverridesFor(overrides, 'settings')} /> diff --git a/src/plugins/chart_expressions/expression_gauge/public/expression_renderers/gauge_renderer.tsx b/src/plugins/chart_expressions/expression_gauge/public/expression_renderers/gauge_renderer.tsx index f86d6f2bff508a..9759ceca52725b 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/expression_renderers/gauge_renderer.tsx +++ b/src/plugins/chart_expressions/expression_gauge/public/expression_renderers/gauge_renderer.tsx @@ -13,7 +13,11 @@ import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { ExpressionRenderDefinition } from '@kbn/expressions-plugin/common/expression_renderers'; import { StartServicesGetter } from '@kbn/kibana-utils-plugin/public'; import { METRIC_TYPE } from '@kbn/analytics'; -import { extractContainerType, extractVisualizationType } from '@kbn/chart-expressions-common'; +import { + ChartSizeEvent, + extractContainerType, + extractVisualizationType, +} from '@kbn/chart-expressions-common'; import { ExpressionGaugePluginStart } from '../plugin'; import { EXPRESSION_GAUGE_NAME, GaugeExpressionProps, GaugeShapes } from '../../common'; import { getFormatService, getPaletteService } from '../services'; @@ -66,16 +70,27 @@ export const gaugeRenderer: ( handlers.done(); }; + const setChartSize = (chartSizeSpec: ChartSizeEvent['data']) => { + const event: ChartSizeEvent = { + name: 'chartSize', + data: chartSizeSpec, + }; + + handlers.event(event); + }; + const { GaugeComponent } = await import('../components/gauge_component'); render(
diff --git a/src/plugins/chart_expressions/expression_heatmap/public/expression_renderers/heatmap_renderer.tsx b/src/plugins/chart_expressions/expression_heatmap/public/expression_renderers/heatmap_renderer.tsx index 1d324ad63be553..029a2782f70ace 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/expression_renderers/heatmap_renderer.tsx +++ b/src/plugins/chart_expressions/expression_heatmap/public/expression_renderers/heatmap_renderer.tsx @@ -14,7 +14,11 @@ import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { ExpressionRenderDefinition } from '@kbn/expressions-plugin/common/expression_renderers'; import { StartServicesGetter } from '@kbn/kibana-utils-plugin/public'; import { METRIC_TYPE } from '@kbn/analytics'; -import { extractContainerType, extractVisualizationType } from '@kbn/chart-expressions-common'; +import { + ChartSizeEvent, + extractContainerType, + extractVisualizationType, +} from '@kbn/chart-expressions-common'; import { I18nProvider } from '@kbn/i18n-react'; import { MultiFilterEvent } from '../../common/types'; import { ExpressionHeatmapPluginStart } from '../plugin'; @@ -78,6 +82,18 @@ export const heatmapRenderer: ( handlers.done(); }; + const chartSizeEvent: ChartSizeEvent = { + name: 'chartSize', + data: { + maxDimensions: { + x: { value: 100, unit: 'percentage' }, + y: { value: 100, unit: 'percentage' }, + }, + }, + }; + + handlers.event(chartSizeEvent); + const timeZone = getTimeZone(getUISettings()); const { HeatmapComponent } = await import('../components/heatmap_component'); const { isInteractive } = handlers; diff --git a/src/plugins/chart_expressions/expression_legacy_metric/public/expression_renderers/metric_vis_renderer.tsx b/src/plugins/chart_expressions/expression_legacy_metric/public/expression_renderers/metric_vis_renderer.tsx index 310f8e0ee54f4f..be9164101202e3 100644 --- a/src/plugins/chart_expressions/expression_legacy_metric/public/expression_renderers/metric_vis_renderer.tsx +++ b/src/plugins/chart_expressions/expression_legacy_metric/public/expression_renderers/metric_vis_renderer.tsx @@ -21,7 +21,11 @@ import { import { getColumnByAccessor } from '@kbn/visualizations-plugin/common/utils'; import { Datatable } from '@kbn/expressions-plugin/common'; import { StartServicesGetter } from '@kbn/kibana-utils-plugin/public'; -import { extractContainerType, extractVisualizationType } from '@kbn/chart-expressions-common'; +import { + ChartSizeEvent, + extractContainerType, + extractVisualizationType, +} from '@kbn/chart-expressions-common'; import { ExpressionLegacyMetricPluginStart } from '../plugin'; import { EXPRESSION_METRIC_NAME, MetricVisRenderConfig, VisParams } from '../../common'; @@ -92,6 +96,18 @@ export const getMetricVisRenderer: ( handlers.done(); }; + const chartSizeEvent: ChartSizeEvent = { + name: 'chartSize', + data: { + maxDimensions: { + x: { value: 100, unit: 'percentage' }, + y: { value: 100, unit: 'percentage' }, + }, + }, + }; + + handlers.event(chartSizeEvent); + render( ; +} as Pick; describe('MetricVisComponent', function () { afterEach(() => { @@ -239,7 +238,7 @@ describe('MetricVisComponent', function () { expect(visConfig).toMatchInlineSnapshot(` Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": [Function], "subtitle": undefined, @@ -299,7 +298,7 @@ describe('MetricVisComponent', function () { expect(configWithPrefix).toMatchInlineSnapshot(` Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": secondary prefix number-13.6328125 @@ -348,7 +347,7 @@ describe('MetricVisComponent', function () { expect(configWithProgress).toMatchInlineSnapshot(` Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 28.984375, "extra": , "icon": [Function], @@ -425,7 +424,7 @@ describe('MetricVisComponent', function () { expect(visConfig).toMatchInlineSnapshot(` Array [ Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -434,7 +433,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -443,7 +442,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -452,7 +451,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -461,7 +460,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -590,7 +589,7 @@ describe('MetricVisComponent', function () { Array [ Array [ Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -599,7 +598,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -608,7 +607,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -617,7 +616,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -626,7 +625,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -637,7 +636,7 @@ describe('MetricVisComponent', function () { ], Array [ Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -678,7 +677,7 @@ describe('MetricVisComponent', function () { Array [ Array [ Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 28.984375, "extra": , "icon": undefined, @@ -689,7 +688,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 28.984375, "extra": , "icon": undefined, @@ -700,7 +699,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 25.984375, "extra": , "icon": undefined, @@ -711,7 +710,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 25.784375, "extra": , "icon": undefined, @@ -722,7 +721,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 25.348011363636363, "extra": , "icon": undefined, @@ -735,7 +734,7 @@ describe('MetricVisComponent', function () { ], Array [ Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 24.984375, "extra": , "icon": undefined, @@ -849,124 +848,60 @@ describe('MetricVisComponent', function () { }); }); - describe('rendering with no data', () => {}); - it('should constrain dimensions in edit mode', () => { - const getContainerStyles = (editMode: boolean, multipleTiles: boolean) => - ( - shallow( - - ) - .find('div') - .at(0) - .props() as HtmlAttributes & { css: { styles: string } } - ).css.styles; - - expect(getContainerStyles(false, false)).toMatchInlineSnapshot(` - " - height: 100%; - width: 100%; - max-height: 100%; - max-width: 100%; - overflow-y: auto; - scrollbar-width: thin; - - &::-webkit-scrollbar { - inline-size: 16px; - block-size: 16px; - } - - &::-webkit-scrollbar-thumb { - background-color: rgba(105,112,125,0.5); - background-clip: content-box; - border-radius: 16px; - border: calc(8px * 0.75) solid transparent; - } - - &::-webkit-scrollbar-corner, - &::-webkit-scrollbar-track { - background-color: transparent; - } - - scrollbar-color: rgba(105,112,125,0.5) transparent; - - " - `); - - expect(getContainerStyles(true, false)).toMatchInlineSnapshot(` - " - height: 300px; - width: 300px; - max-height: 100%; - max-width: 100%; - overflow-y: auto; - scrollbar-width: thin; - - &::-webkit-scrollbar { - inline-size: 16px; - block-size: 16px; - } + const getDimensionsRequest = (multipleTiles: boolean) => { + const fireEvent = jest.fn(); + const wrapper = shallow( + + ); - &::-webkit-scrollbar-thumb { - background-color: rgba(105,112,125,0.5); - background-clip: content-box; - border-radius: 16px; - border: calc(8px * 0.75) solid transparent; - } + wrapper.find(Settings).props().onWillRender!(); - &::-webkit-scrollbar-corner, - &::-webkit-scrollbar-track { - background-color: transparent; - } + return fireEvent.mock.calls[0][0].data; + }; - scrollbar-color: rgba(105,112,125,0.5) transparent; - - " + expect(getDimensionsRequest(false)).toMatchInlineSnapshot(` + Object { + "maxDimensions": Object { + "x": Object { + "unit": "pixels", + "value": 300, + }, + "y": Object { + "unit": "pixels", + "value": 300, + }, + }, + } `); - expect(getContainerStyles(true, true)).toMatchInlineSnapshot(` - " - height: 400px; - width: 1000px; - max-height: 100%; - max-width: 100%; - overflow-y: auto; - scrollbar-width: thin; - - &::-webkit-scrollbar { - inline-size: 16px; - block-size: 16px; - } - - &::-webkit-scrollbar-thumb { - background-color: rgba(105,112,125,0.5); - background-clip: content-box; - border-radius: 16px; - border: calc(8px * 0.75) solid transparent; - } - - &::-webkit-scrollbar-corner, - &::-webkit-scrollbar-track { - background-color: transparent; - } - - scrollbar-color: rgba(105,112,125,0.5) transparent; - - " + expect(getDimensionsRequest(true)).toMatchInlineSnapshot(` + Object { + "maxDimensions": Object { + "x": Object { + "unit": "pixels", + "value": 1000, + }, + "y": Object { + "unit": "pixels", + "value": 400, + }, + }, + } `); }); @@ -1308,7 +1243,7 @@ describe('MetricVisComponent', function () { const [[datum]] = component.find(Metric).props().data!; - expect(datum!.color).toBe(euiThemeVars.euiColorLightestShade); + expect(datum!.color).toBe(euiThemeVars.euiColorEmptyShade); expect(mockGetColorForValue).not.toHaveBeenCalled(); }); }); diff --git a/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx b/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx index ba3ef124d7ed28..fb1383ce98d482 100644 --- a/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx +++ b/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx @@ -29,7 +29,6 @@ import type { DatatableColumn, DatatableRow, IInterpreterRenderHandlers, - RenderMode, } from '@kbn/expressions-plugin/common'; import { CustomPaletteState } from '@kbn/charts-plugin/public'; import { @@ -41,13 +40,13 @@ import { css } from '@emotion/react'; import { euiThemeVars } from '@kbn/ui-theme'; import { useResizeObserver, useEuiScrollBar, EuiIcon } from '@elastic/eui'; import { AllowedChartOverrides, AllowedSettingsOverrides } from '@kbn/charts-plugin/common'; -import { getOverridesFor } from '@kbn/chart-expressions-common'; +import { type ChartSizeEvent, getOverridesFor } from '@kbn/chart-expressions-common'; import { DEFAULT_TRENDLINE_NAME } from '../../common/constants'; import { VisParams } from '../../common'; import { getPaletteService, getThemeService, getFormatService } from '../services'; import { getDataBoundsForPalette } from '../utils'; -export const defaultColor = euiThemeVars.euiColorLightestShade; +export const defaultColor = euiThemeVars.euiColorEmptyShade; function enhanceFieldFormat(serializedFieldFormat: SerializedFieldFormat | undefined) { const formatId = serializedFieldFormat?.id || 'number'; @@ -140,7 +139,6 @@ export interface MetricVisComponentProps { config: Pick; renderComplete: IInterpreterRenderHandlers['done']; fireEvent: IInterpreterRenderHandlers['event']; - renderMode: RenderMode; filterable: boolean; overrides?: AllowedSettingsOverrides & AllowedChartOverrides; } @@ -150,10 +148,11 @@ export const MetricVis = ({ config, renderComplete, fireEvent, - renderMode, filterable, overrides, }: MetricVisComponentProps) => { + const grid = useRef([[]]); + const onRenderChange = useCallback( (isRendered) => { if (isRendered) { @@ -163,6 +162,20 @@ export const MetricVis = ({ [renderComplete] ); + const onWillRender = useCallback(() => { + const maxTileSideLength = grid.current.length * grid.current[0].length > 1 ? 200 : 300; + const event: ChartSizeEvent = { + name: 'chartSize', + data: { + maxDimensions: { + y: { value: grid.current.length * maxTileSideLength, unit: 'pixels' }, + x: { value: grid.current[0]?.length * maxTileSideLength, unit: 'pixels' }, + }, + }, + }; + fireEvent(event); + }, [fireEvent, grid]); + const [scrollChildHeight, setScrollChildHeight] = useState('100%'); const scrollContainerRef = useRef(null); const scrollDimensions = useResizeObserver(scrollContainerRef.current); @@ -289,28 +302,19 @@ export const MetricVis = ({ 'settings' ) as Partial; - const grid: MetricSpec['data'] = []; + const newGrid: MetricSpec['data'] = []; for (let i = 0; i < metricConfigs.length; i += maxCols) { - grid.push(metricConfigs.slice(i, i + maxCols)); + newGrid.push(metricConfigs.slice(i, i + maxCols)); } - let pixelHeight; - let pixelWidth; - if (renderMode === 'edit') { - // In the editor, we constrain the maximum size of the tiles for aesthetic reasons - const maxTileSideLength = metricConfigs.flat().length > 1 ? 200 : 300; - pixelHeight = grid.length * maxTileSideLength; - pixelWidth = grid[0]?.length * maxTileSideLength; - } + grid.current = newGrid; return (
{ const colRef = breakdownByColumn ?? primaryMetricColumn; - const rowLength = grid[0].length; + const rowLength = grid.current[0].length; events.forEach((event) => { if (isMetricElementEvent(event)) { const colIdx = data.columns.findIndex((col) => col === colRef); @@ -360,7 +365,7 @@ export const MetricVis = ({ } {...settingsOverrides} /> - +
diff --git a/src/plugins/chart_expressions/expression_metric/public/expression_renderers/metric_vis_renderer.tsx b/src/plugins/chart_expressions/expression_metric/public/expression_renderers/metric_vis_renderer.tsx index 9841e65d5ed206..4ba6076e032fa5 100644 --- a/src/plugins/chart_expressions/expression_metric/public/expression_renderers/metric_vis_renderer.tsx +++ b/src/plugins/chart_expressions/expression_metric/public/expression_renderers/metric_vis_renderer.tsx @@ -101,7 +101,6 @@ export const getMetricVisRenderer = ( config={visConfig} renderComplete={renderComplete} fireEvent={handlers.event} - renderMode={handlers.getRenderMode()} filterable={filterable} overrides={overrides} /> 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 2379096796639f..ac8a053f37ebdd 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 @@ -22,6 +22,7 @@ import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { METRIC_TYPE } from '@kbn/analytics'; import { getColumnByAccessor } from '@kbn/visualizations-plugin/common/utils'; import { + type ChartSizeEvent, extractContainerType, extractVisualizationType, isOnAggBasedEditor, @@ -116,6 +117,18 @@ export const getPartitionVisRenderer: ( const hasOpenedOnAggBasedEditor = isOnAggBasedEditor(handlers.getExecutionContext()); + const chartSizeEvent: ChartSizeEvent = { + name: 'chartSize', + data: { + maxDimensions: { + x: { value: 100, unit: 'percentage' }, + y: { value: 100, unit: 'percentage' }, + }, + }, + }; + + handlers.event(chartSizeEvent); + render( diff --git a/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/tagcloud_renderer.tsx b/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/tagcloud_renderer.tsx index 101c40b6b384d3..8dd3d7eb093585 100644 --- a/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/tagcloud_renderer.tsx +++ b/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/tagcloud_renderer.tsx @@ -15,7 +15,11 @@ import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { VisualizationContainer } from '@kbn/visualizations-plugin/public'; import { ExpressionRenderDefinition } from '@kbn/expressions-plugin/common/expression_renderers'; import { METRIC_TYPE } from '@kbn/analytics'; -import { extractContainerType, extractVisualizationType } from '@kbn/chart-expressions-common'; +import { + type ChartSizeEvent, + extractContainerType, + extractVisualizationType, +} from '@kbn/chart-expressions-common'; import { ExpressionTagcloudRendererDependencies } from '../plugin'; import { TagcloudRendererConfig } from '../../common/types'; @@ -66,6 +70,18 @@ export const tagcloudRenderer: ( handlers.done(); }; + const chartSizeEvent: ChartSizeEvent = { + name: 'chartSize', + data: { + maxDimensions: { + x: { value: 100, unit: 'percentage' }, + y: { value: 100, unit: 'percentage' }, + }, + }, + }; + + handlers.event(chartSizeEvent); + const palettesRegistry = await plugins.charts.palettes.getPalettes(); let isDarkMode = false; plugins.charts.theme.darkModeEnabled$ diff --git a/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap b/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap index 267833cba170dd..a2f62afd3aee61 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap +++ b/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap @@ -300,6 +300,18 @@ exports[`XYChart component it renders area 1`] = ` } } > +
+
+
+
+
+
+
+
+
+
{ eventAnnotationService: eventAnnotationServiceMock, renderComplete: jest.fn(), timeFormat: 'MMM D, YYYY @ HH:mm:ss.SSS', + setChartSize: jest.fn(), + shouldUseVeil: false, }; }); diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx index 4eb52c67f20bd1..7e4c5a5c6b974a 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx @@ -52,7 +52,11 @@ import { LegendSizeToPixels, } from '@kbn/visualizations-plugin/common/constants'; import { PersistedState } from '@kbn/visualizations-plugin/public'; -import { getOverridesFor } from '@kbn/chart-expressions-common'; +import { + useSizeTransitionVeil, + getOverridesFor, + ChartSizeSpec, +} from '@kbn/chart-expressions-common'; import type { FilterEvent, BrushEvent, @@ -144,8 +148,11 @@ export type XYChartRenderProps = Omit & { syncCursor: boolean; eventAnnotationService: EventAnnotationServiceType; renderComplete: () => void; + shouldUseVeil: boolean; uiState?: PersistedState; timeFormat: string; + setChartSize: (chartSizeSpec: ChartSizeSpec) => void; + shouldShowLegendAction?: (actionId: string) => boolean; }; function nonNullable(v: T): v is NonNullable { @@ -199,12 +206,16 @@ export function XYChart({ onClickMultiValue, layerCellValueActions, onSelectRange, + setChartSize, interactive = true, syncColors, syncTooltips, syncCursor, + shouldUseVeil, + useLegacyTimeAxis, renderComplete, + uiState, timeFormat, overrides, @@ -293,6 +304,34 @@ export function XYChart({ ); const dataLayers: CommonXYDataLayerConfig[] = filteredLayers.filter(isDataLayer); + + const isTimeViz = isTimeChart(dataLayers); + + const chartSizeSpec: ChartSizeSpec = + isTimeViz && !isHorizontalChart(dataLayers) + ? { + aspectRatio: { + x: 16, + y: 9, + }, + minDimensions: { + y: { value: 300, unit: 'pixels' }, + x: { value: 100, unit: 'percentage' }, + }, + } + : { + maxDimensions: { + x: { value: 100, unit: 'percentage' }, + y: { value: 100, unit: 'percentage' }, + }, + }; + + const { veil, onResize, containerRef } = useSizeTransitionVeil( + chartSizeSpec, + setChartSize, + shouldUseVeil + ); + const formattedDatatables = useMemo( () => getFormattedTablesByLayers(dataLayers, formatFactory, splitColumnAccessor, splitRowAccessor), @@ -371,8 +410,6 @@ export function XYChart({ (layer) => isDataLayer(layer) && layer.splitAccessors && layer.splitAccessors.length ); - const isTimeViz = isTimeChart(dataLayers); - const defaultXScaleType = isTimeViz ? XScaleTypes.TIME : XScaleTypes.ORDINAL; const isHistogramViz = dataLayers.every((l) => l.isHistogram); @@ -711,7 +748,8 @@ export function XYChart({ ); return ( -
+
+ {veil} {showLegend !== undefined && uiState && ( } onRenderChange={onRenderChange} + onResize={onResize} onPointerUpdate={syncCursor ? handleCursorUpdate : undefined} externalPointerEvents={{ tooltip: { visible: syncTooltips, placement: Placement.Right }, diff --git a/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx b/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx index c2561191deb9af..2d88ed53ac3f0e 100644 --- a/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx @@ -26,7 +26,12 @@ import { FormatFactory } from '@kbn/field-formats-plugin/common'; import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; import { getColumnByAccessor } from '@kbn/visualizations-plugin/common/utils'; -import { extractContainerType, extractVisualizationType } from '@kbn/chart-expressions-common'; +import { + type ChartSizeEvent, + type ChartSizeSpec, + extractContainerType, + extractVisualizationType, +} from '@kbn/chart-expressions-common'; import type { getDataLayers } from '../helpers'; import { LayerTypes, SeriesTypes } from '../../common/constants'; @@ -215,6 +220,10 @@ export const getXyChartRenderer = ({ const onClickMultiValue = (data: MultiFilterEvent['data']) => { handlers.event({ name: 'multiFilter', data }); }; + const setChartSize = (data: ChartSizeSpec) => { + const event: ChartSizeEvent = { name: 'chartSize', data }; + handlers.event(event); + }; const layerCellValueActions = await getLayerCellValueActions( getDataLayers(config.args.layers), @@ -275,8 +284,10 @@ export const getXyChartRenderer = ({ syncColors={config.syncColors} syncTooltips={config.syncTooltips} syncCursor={config.syncCursor} + shouldUseVeil={handlers.shouldUseSizeTransitionVeil()} uiState={handlers.uiState as PersistedState} renderComplete={renderComplete} + setChartSize={setChartSize} />
diff --git a/src/plugins/expressions/common/execution/execution.ts b/src/plugins/expressions/common/execution/execution.ts index 593e437fd9dc72..03a0923b4b3131 100644 --- a/src/plugins/expressions/common/execution/execution.ts +++ b/src/plugins/expressions/common/execution/execution.ts @@ -287,6 +287,7 @@ export class Execution< isSyncColorsEnabled: () => execution.params.syncColors!, isSyncCursorEnabled: () => execution.params.syncCursor!, isSyncTooltipsEnabled: () => execution.params.syncTooltips!, + shouldUseSizeTransitionVeil: () => execution.params.shouldUseSizeTransitionVeil!, ...execution.executor.context, getExecutionContext: () => execution.params.executionContext, }; diff --git a/src/plugins/expressions/common/execution/types.ts b/src/plugins/expressions/common/execution/types.ts index 03dbcc8a6ff137..ac216515a3f1b7 100644 --- a/src/plugins/expressions/common/execution/types.ts +++ b/src/plugins/expressions/common/execution/types.ts @@ -72,6 +72,11 @@ export interface ExecutionContext */ isSyncTooltipsEnabled?: () => boolean; + /** + * Returns whether or not to use the size transition veil when resizing visualizations. + */ + shouldUseSizeTransitionVeil?: () => boolean; + /** * Contains the meta-data about the source of the expression. */ diff --git a/src/plugins/expressions/common/expression_renderers/types.ts b/src/plugins/expressions/common/expression_renderers/types.ts index 7dae307aa6c019..46908e8b38e6ea 100644 --- a/src/plugins/expressions/common/expression_renderers/types.ts +++ b/src/plugins/expressions/common/expression_renderers/types.ts @@ -97,6 +97,9 @@ export interface IInterpreterRenderHandlers { isSyncCursorEnabled(): boolean; isSyncTooltipsEnabled(): boolean; + + shouldUseSizeTransitionVeil(): boolean; + /** * This uiState interface is actually `PersistedState` from the visualizations plugin, * but expressions cannot know about vis or it creates a mess of circular dependencies. diff --git a/src/plugins/expressions/common/service/expressions_services.ts b/src/plugins/expressions/common/service/expressions_services.ts index e73e07a387c468..2683921bc038ba 100644 --- a/src/plugins/expressions/common/service/expressions_services.ts +++ b/src/plugins/expressions/common/service/expressions_services.ts @@ -156,6 +156,11 @@ export interface ExpressionExecutionParams { syncTooltips?: boolean; + // if this is set to true, a veil will be shown when resizing visualizations in response + // to a chart resize event (see src/plugins/chart_expressions/common/chart_size_transition_veil.tsx). + // This should be only set to true if the client will be responding to the resize events + shouldUseSizeTransitionVeil?: boolean; + inspectorAdapters?: Adapters; executionContext?: KibanaExecutionContext; diff --git a/src/plugins/expressions/public/loader.ts b/src/plugins/expressions/public/loader.ts index f10b8db1f1287d..0a3c0e09906454 100644 --- a/src/plugins/expressions/public/loader.ts +++ b/src/plugins/expressions/public/loader.ts @@ -60,6 +60,7 @@ export class ExpressionLoader { syncColors: params?.syncColors, syncTooltips: params?.syncTooltips, syncCursor: params?.syncCursor, + shouldUseSizeTransitionVeil: params?.shouldUseSizeTransitionVeil, hasCompatibleActions: params?.hasCompatibleActions, getCompatibleCellValueActions: params?.getCompatibleCellValueActions, executionContext: params?.executionContext, @@ -148,6 +149,7 @@ export class ExpressionLoader { syncColors: params.syncColors, syncCursor: params?.syncCursor, syncTooltips: params.syncTooltips, + shouldUseSizeTransitionVeil: params.shouldUseSizeTransitionVeil, executionContext: params.executionContext, partial: params.partial, throttle: params.throttle, diff --git a/src/plugins/expressions/public/render.ts b/src/plugins/expressions/public/render.ts index a7b919625b8d66..0b494f30b2e692 100644 --- a/src/plugins/expressions/public/render.ts +++ b/src/plugins/expressions/public/render.ts @@ -33,6 +33,7 @@ export interface ExpressionRenderHandlerParams { syncCursor?: boolean; syncTooltips?: boolean; interactive?: boolean; + shouldUseSizeTransitionVeil?: boolean; hasCompatibleActions?: (event: ExpressionRendererEvent) => Promise; getCompatibleCellValueActions?: (data: object[]) => Promise; executionContext?: KibanaExecutionContext; @@ -62,6 +63,7 @@ export class ExpressionRenderHandler { syncColors, syncTooltips, syncCursor, + shouldUseSizeTransitionVeil, interactive, hasCompatibleActions = async () => false, getCompatibleCellValueActions = async () => [], @@ -113,6 +115,9 @@ export class ExpressionRenderHandler { isSyncCursorEnabled: () => { return syncCursor || true; }, + shouldUseSizeTransitionVeil: () => { + return Boolean(shouldUseSizeTransitionVeil); + }, isInteractive: () => { return interactive ?? true; }, diff --git a/src/plugins/expressions/public/types/index.ts b/src/plugins/expressions/public/types/index.ts index 7bbb486fde3901..27090f36fdc7c1 100644 --- a/src/plugins/expressions/public/types/index.ts +++ b/src/plugins/expressions/public/types/index.ts @@ -52,6 +52,10 @@ export interface IExpressionLoaderParams { syncColors?: boolean; syncCursor?: boolean; syncTooltips?: boolean; + // if this is set to true, a veil will be shown when resizing visualizations in response + // to a chart resize event (see src/plugins/chart_expressions/common/chart_size_transition_veil.tsx). + // This should be only set to true if the client will be responding to the resize events + shouldUseSizeTransitionVeil?: boolean; hasCompatibleActions?: ExpressionRenderHandlerParams['hasCompatibleActions']; getCompatibleCellValueActions?: ExpressionRenderHandlerParams['getCompatibleCellValueActions']; executionContext?: KibanaExecutionContext; diff --git a/src/plugins/presentation_util/public/__stories__/render.tsx b/src/plugins/presentation_util/public/__stories__/render.tsx index ca9f9688422702..e02f1c803d332e 100644 --- a/src/plugins/presentation_util/public/__stories__/render.tsx +++ b/src/plugins/presentation_util/public/__stories__/render.tsx @@ -18,6 +18,7 @@ export const defaultHandlers: IInterpreterRenderHandlers = { isSyncColorsEnabled: () => false, isSyncCursorEnabled: () => true, isSyncTooltipsEnabled: () => false, + shouldUseSizeTransitionVeil: () => false, isInteractive: () => true, getExecutionContext: () => undefined, done: action('done'), diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx index 7743ca46f95ba2..285612700863cd 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx @@ -40,6 +40,7 @@ import { import type { RenderMode } from '@kbn/expressions-plugin/common'; import { DATA_VIEW_SAVED_OBJECT_TYPE } from '@kbn/data-views-plugin/public'; import { mapAndFlattenFilters } from '@kbn/data-plugin/public'; +import { isChartSizeEvent } from '@kbn/chart-expressions-common'; import { isFallbackDataView } from '../visualize_app/utils'; import { VisualizationMissedSavedObjectError } from '../components/visualization_missed_saved_object_error'; import VisualizationError from '../components/visualization_error'; @@ -477,6 +478,10 @@ export class VisualizeEmbeddable this.handler.events$ .pipe( mergeMap(async (event) => { + // Visualize doesn't respond to sizing events, so ignore. + if (isChartSizeEvent(event)) { + return; + } if (!this.input.disableTriggers) { const triggerId = get(VIS_EVENT_TO_TRIGGER, event.name, VIS_EVENT_TO_TRIGGER.filter); let context; diff --git a/src/plugins/visualizations/tsconfig.json b/src/plugins/visualizations/tsconfig.json index 813c47ca83872e..296367543271a2 100644 --- a/src/plugins/visualizations/tsconfig.json +++ b/src/plugins/visualizations/tsconfig.json @@ -66,6 +66,7 @@ "@kbn/search-response-warnings", "@kbn/logging", "@kbn/content-management-table-list-view-common", + "@kbn/chart-expressions-common", "@kbn/shared-ux-utility" ], "exclude": [ diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/__stories__/render.tsx b/x-pack/plugins/canvas/canvas_plugin_src/renderers/__stories__/render.tsx index e53dce0a468867..c921bf5db2fe18 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/__stories__/render.tsx +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/__stories__/render.tsx @@ -17,6 +17,7 @@ export const defaultHandlers: RendererHandlers = { isSyncColorsEnabled: () => false, isSyncCursorEnabled: () => true, isSyncTooltipsEnabled: () => false, + shouldUseSizeTransitionVeil: () => false, isInteractive: () => true, onComplete: (fn) => undefined, onEmbeddableDestroyed: action('onEmbeddableDestroyed'), diff --git a/x-pack/plugins/canvas/public/lib/create_handlers.ts b/x-pack/plugins/canvas/public/lib/create_handlers.ts index 374bdaff997213..b9c0ad97f4eb1c 100644 --- a/x-pack/plugins/canvas/public/lib/create_handlers.ts +++ b/x-pack/plugins/canvas/public/lib/create_handlers.ts @@ -29,6 +29,7 @@ export const createBaseHandlers = (): IInterpreterRenderHandlers => ({ isSyncColorsEnabled: () => false, isSyncTooltipsEnabled: () => false, isSyncCursorEnabled: () => true, + shouldUseSizeTransitionVeil: () => false, isInteractive: () => true, getExecutionContext: () => undefined, }); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index 8b7705260c1e43..842904741ec9bc 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -27,6 +27,7 @@ import type { Datatable } from '@kbn/expressions-plugin/public'; import { DropIllustration } from '@kbn/chart-icons'; import { DragDrop, useDragDropContext, DragDropIdentifier } from '@kbn/dom-drag-drop'; import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; +import { ChartSizeSpec, isChartSizeEvent } from '@kbn/chart-expressions-common'; import { trackUiCounterEvents } from '../../../lens_ui_telemetry'; import { getSearchWarningMessages } from '../../../utils'; import { @@ -43,6 +44,7 @@ import { UserMessagesGetter, AddUserMessages, isMessageRemovable, + VisualizationDisplayOptions, } from '../../../types'; import { switchToSuggestion } from '../suggestion_helpers'; import { buildExpression } from '../expression_helpers'; @@ -413,6 +415,8 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ } }, [expressionExists, localState.expressionToRender]); + const [chartSizeSpec, setChartSize] = useState(); + const onEvent = useCallback( (event: ExpressionRendererEvent) => { if (!plugins.uiActions) { @@ -443,10 +447,15 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ }) ); } + + if (isChartSizeEvent(event)) { + setChartSize(event.data); + } }, [plugins.data.datatableUtilities, plugins.uiActions, activeVisualization, dispatchLens] ); + const displayOptions = activeVisualization?.getDisplayOptions?.(); const hasCompatibleActions = useCallback( async (event: ExpressionRendererEvent) => { if (!plugins.uiActions) { @@ -478,6 +487,10 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ const IS_DARK_THEME: boolean = useObservable(core.theme.theme$, { darkMode: false }).darkMode; const renderDragDropPrompt = () => { + if (chartSizeSpec) { + setChartSize(undefined); + } + return ( { + if (chartSizeSpec) { + setChartSize(undefined); + } + const applyChangesString = i18n.translate('xpack.lens.editorFrame.applyChanges', { defaultMessage: 'Apply changes', }); @@ -590,6 +607,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ onComponentRendered={() => { visualizationRenderStartTime.current = performance.now(); }} + displayOptions={displayOptions} /> ); }; @@ -639,7 +657,6 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ return ( {renderWorkspace()} @@ -686,6 +704,7 @@ export const VisualizationWrapper = ({ onRender$, onData$, onComponentRendered, + displayOptions, }: { expression: string | null | undefined; lensInspector: LensInspector; @@ -699,6 +718,7 @@ export const VisualizationWrapper = ({ onRender$: () => void; onData$: (data: unknown, adapters?: Partial) => void; onComponentRendered: () => void; + displayOptions: VisualizationDisplayOptions | undefined; }) => { useEffect(() => { onComponentRendered(); @@ -751,7 +771,7 @@ export const VisualizationWrapper = ({ > * { + &>* { flex: 1 1 100%; display: flex; align-items: center; @@ -37,6 +37,7 @@ &.lnsWorkspacePanelWrapper--fullscreen { margin-bottom: 0; + .lnsWorkspacePanelWrapper__pageContentBody { box-shadow: none; } @@ -45,8 +46,6 @@ } .lnsWorkspacePanel__dragDrop { - border: $euiBorderWidthThin solid transparent; - &.domDragDrop-isDropTarget { p { transition: filter $euiAnimSpeedFast ease-in-out; @@ -120,9 +119,7 @@ // Hard-coded px values OK (@cchaos) // sass-lint:disable-block indentation filter: - drop-shadow(0 6px 12px transparentize($euiShadowColor, .8)) - drop-shadow(0 4px 4px transparentize($euiShadowColor, .8)) - drop-shadow(0 2px 2px transparentize($euiShadowColor, .8)); + drop-shadow(0 6px 12px transparentize($euiShadowColor, .8)) drop-shadow(0 4px 4px transparentize($euiShadowColor, .8)) drop-shadow(0 2px 2px transparentize($euiShadowColor, .8)); } .lnsDropIllustration__adjustFill { @@ -134,20 +131,51 @@ } @keyframes lnsWorkspacePanel__illustrationPulseArrow { - 0% { transform: translateY(0%); } - 65% { transform: translateY(0%); } - 72% { transform: translateY(10%); } - 79% { transform: translateY(7%); } - 86% { transform: translateY(10%); } - 95% { transform: translateY(0); } + 0% { + transform: translateY(0%); + } + + 65% { + transform: translateY(0%); + } + + 72% { + transform: translateY(10%); + } + + 79% { + transform: translateY(7%); + } + + 86% { + transform: translateY(10%); + } + + 95% { + transform: translateY(0); + } } @keyframes lnsWorkspacePanel__illustrationPulseContinuous { - 0% { transform: translateY(10%); } - 25% { transform: translateY(15%); } - 50% { transform: translateY(10%); } - 75% { transform: translateY(15%); } - 100% { transform: translateY(10%); } + 0% { + transform: translateY(10%); + } + + 25% { + transform: translateY(15%); + } + + 50% { + transform: translateY(10%); + } + + 75% { + transform: translateY(15%); + } + + 100% { + transform: translateY(10%); + } } .lnsVisualizationToolbar--fixed { @@ -155,4 +183,4 @@ width: 100%; z-index: 1; background-color: $euiColorLightestShade; -} +} \ No newline at end of file diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.test.tsx index eeec3135841170..8694cc7c27dcf8 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.test.tsx @@ -34,7 +34,6 @@ describe('workspace_panel_wrapper', () => { <> { lensInspector={{} as unknown as LensInspector} getUserMessages={() => []} children={} + displayOptions={undefined} {...propsOverrides} /> = { + pixels: 'px', + percentage: '%', +}; + +const getAspectRatioStyles = ({ x, y }: { x: number; y: number }) => { + return { + aspectRatio: `${x}/${y}`, + ...(y > x + ? { + height: '100%', + width: 'auto', + } + : { + height: 'auto', + width: '100%', + }), + }; +}; + export function VisualizationToolbar(props: { activeVisualization: Visualization | null; framePublicAPI: FramePublicAPI; @@ -98,12 +120,12 @@ export function VisualizationToolbar(props: { export function WorkspacePanelWrapper({ children, framePublicAPI, - visualizationState, visualizationId, visualizationMap, datasourceMap, isFullscreen, getUserMessages, + displayOptions, }: WorkspacePanelWrapperProps) { const dispatchLens = useLensDispatch(); @@ -113,6 +135,34 @@ export function WorkspacePanelWrapper({ const activeVisualization = visualizationId ? visualizationMap[visualizationId] : null; const userMessages = getUserMessages('toolbar'); + const aspectRatio = displayOptions?.aspectRatio; + const maxDimensions = displayOptions?.maxDimensions; + const minDimensions = displayOptions?.minDimensions; + + let visDimensionsCSS: Interpolation = {}; + + if (aspectRatio) { + visDimensionsCSS = getAspectRatioStyles(aspectRatio ?? maxDimensions); + } + + if (maxDimensions) { + visDimensionsCSS.maxWidth = maxDimensions.x + ? `${maxDimensions.x.value}${unitToCSSUnit[maxDimensions.x.unit]}` + : ''; + visDimensionsCSS.maxHeight = maxDimensions.y + ? `${maxDimensions.y.value}${unitToCSSUnit[maxDimensions.y.unit]}` + : ''; + } + + if (minDimensions) { + visDimensionsCSS.minWidth = minDimensions.x + ? `${minDimensions.x.value}${unitToCSSUnit[minDimensions.x.unit]}` + : ''; + visDimensionsCSS.minHeight = minDimensions.y + ? `${minDimensions.y.value}${unitToCSSUnit[minDimensions.y.unit]}` + : ''; + } + return ( )} + - - {children} + + + + {children} + + ); diff --git a/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx b/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx index edb54facff31c0..6c038125b0718a 100644 --- a/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx +++ b/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx @@ -92,6 +92,7 @@ export function ExpressionWrapper({ syncTooltips={syncTooltips} syncCursor={syncCursor} executionContext={executionContext} + shouldUseSizeTransitionVeil={true} renderError={(errorMessage, error) => { const messages = getOriginalRequestErrorMessages(error || null); addUserMessages(messages); diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 53bb59c0a5459e..38054103183a59 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -42,6 +42,7 @@ import { CellValueContext } from '@kbn/embeddable-plugin/public'; import { EventAnnotationGroupConfig } from '@kbn/event-annotation-common'; import type { DraggingIdentifier, DragDropIdentifier, DropType } from '@kbn/dom-drag-drop'; import type { AccessorConfig } from '@kbn/visualization-ui-components'; +import type { ChartSizeEvent } from '@kbn/chart-expressions-common'; import type { DateRange, LayerType, SortingHint } from '../common/types'; import type { LensSortActionData, @@ -1391,6 +1392,7 @@ export interface ILensInterpreterRenderHandlers extends IInterpreterRenderHandle | BrushTriggerEvent | LensEditEvent | LensTableRowContextMenuEvent + | ChartSizeEvent ) => void; } diff --git a/x-pack/plugins/lens/public/visualizations/datatable/expression.tsx b/x-pack/plugins/lens/public/visualizations/datatable/expression.tsx index 6c97dae2baab12..eae35c5a925dcc 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/expression.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/expression.tsx @@ -18,6 +18,7 @@ import type { IInterpreterRenderHandlers, } from '@kbn/expressions-plugin/common'; import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import { ChartSizeEvent } from '@kbn/chart-expressions-common'; import { trackUiCounterEvents } from '../../lens_ui_telemetry'; import { DatatableComponent } from './components/table_basic'; @@ -103,6 +104,18 @@ export const getDatatableRenderer = (dependencies: { handlers.done(); }; + const chartSizeEvent: ChartSizeEvent = { + name: 'chartSize', + data: { + maxDimensions: { + x: { value: 100, unit: 'percentage' }, + y: { value: 100, unit: 'percentage' }, + }, + }, + }; + + handlers.event(chartSizeEvent); + // An entry for each table row, whether it has any actions attached to // ROW_CLICK_TRIGGER trigger. let rowHasRowClickTriggerActions: boolean[] = []; diff --git a/x-pack/plugins/lens/public/visualizations/metric/visualization.test.ts b/x-pack/plugins/lens/public/visualizations/metric/visualization.test.ts index 1b45671e29cc64..3b79cb69cd38c7 100644 --- a/x-pack/plugins/lens/public/visualizations/metric/visualization.test.ts +++ b/x-pack/plugins/lens/public/visualizations/metric/visualization.test.ts @@ -143,7 +143,7 @@ describe('metric visualization', () => { ).toMatchInlineSnapshot(` Array [ Object { - "color": "#f5f7fa", + "color": "#ffffff", "columnId": "metric-col-id", "triggerIconType": "color", }, @@ -727,7 +727,7 @@ describe('metric visualization', () => { datasourceLayers ) as ExpressionAstExpression ).chain[1].arguments.color[0] - ).toBe(euiLightVars.euiColorLightestShade); + ).toBe(euiLightVars.euiColorEmptyShade); expect( ( @@ -741,7 +741,7 @@ describe('metric visualization', () => { datasourceLayers ) as ExpressionAstExpression ).chain[1].arguments.color[0] - ).toBe(euiLightVars.euiColorLightestShade); + ).toBe(euiLightVars.euiColorEmptyShade); // this case isn't currently relevant because other parts of the code don't allow showBar to be // set when there isn't a max dimension but this test covers the branch anyhow @@ -757,7 +757,7 @@ describe('metric visualization', () => { datasourceLayers ) as ExpressionAstExpression ).chain[1].arguments.color[0] - ).toEqual(euiThemeVars.euiColorLightestShade); + ).toEqual(euiThemeVars.euiColorEmptyShade); }); }); diff --git a/x-pack/plugins/lens/public/visualizations/metric/visualization.tsx b/x-pack/plugins/lens/public/visualizations/metric/visualization.tsx index 00b931714c1bec..28c547df25ebdb 100644 --- a/x-pack/plugins/lens/public/visualizations/metric/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/metric/visualization.tsx @@ -45,7 +45,7 @@ export const showingBar = ( export const getDefaultColor = (state: MetricVisualizationState, isMetricNumeric?: boolean) => { return showingBar(state) && isMetricNumeric ? euiLightVars.euiColorPrimary - : euiThemeVars.euiColorLightestShade; + : euiThemeVars.euiColorEmptyShade; }; export interface MetricVisualizationState { diff --git a/x-pack/plugins/maps/public/lens/choropleth_chart/expression_renderer.tsx b/x-pack/plugins/maps/public/lens/choropleth_chart/expression_renderer.tsx index 615945280c264a..059d612883d82d 100644 --- a/x-pack/plugins/maps/public/lens/choropleth_chart/expression_renderer.tsx +++ b/x-pack/plugins/maps/public/lens/choropleth_chart/expression_renderer.tsx @@ -13,6 +13,7 @@ import { METRIC_TYPE } from '@kbn/analytics'; import type { CoreSetup, CoreStart } from '@kbn/core/public'; import type { FileLayer } from '@elastic/ems-client'; import type { KibanaExecutionContext } from '@kbn/core-execution-context-common'; +import { ChartSizeEvent } from '@kbn/chart-expressions-common'; import type { MapsPluginStartDependencies } from '../../plugin'; import type { ChoroplethChartProps } from './types'; import type { MapEmbeddableInput, MapEmbeddableOutput } from '../../embeddable'; @@ -92,6 +93,18 @@ export function getExpressionRenderer(coreSetup: CoreSetup { + let originalWindowSize: { + height: number; + width: number; + x: number; + y: number; + }; + + const DEFAULT_WINDOW_SIZE = [1400, 900]; + + before(async () => { + originalWindowSize = await browser.getWindowSize(); + + await PageObjects.visualize.navigateToNewVisualization(); + await PageObjects.visualize.clickVisType('lens'); + await PageObjects.lens.goToTimeRange(); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', + operation: 'average', + field: 'bytes', + }); + }); + + beforeEach(async () => { + await browser.setWindowSize(DEFAULT_WINDOW_SIZE[0], DEFAULT_WINDOW_SIZE[1]); + }); + + after(async () => { + await browser.setWindowSize(originalWindowSize.width, originalWindowSize.height); + }); + + const pxToN = (pixels: string) => Number(pixels.substring(0, pixels.length - 2)); + + const assertWorkspaceDimensions = async (expectedWidth: string, expectedHeight: string) => { + const tolerance = 1; + + await retry.try(async () => { + const { width, height } = await PageObjects.lens.getWorkspaceVisContainerDimensions(); + + expect(pxToN(width)).to.within( + pxToN(expectedWidth) - tolerance, + pxToN(expectedWidth) + tolerance + ); + expect(pxToN(height)).to.within( + pxToN(expectedHeight) - tolerance, + pxToN(expectedHeight) + tolerance + ); + }); + }; + + const assertWorkspaceAspectRatio = async (expectedRatio: number) => { + const tolerance = 0.05; + + await retry.try(async () => { + const { width, height } = await PageObjects.lens.getWorkspaceVisContainerDimensions(); + + expect(pxToN(width) / pxToN(height)).to.within( + expectedRatio - tolerance, + expectedRatio + tolerance + ); + }); + }; + + const assertWorkspaceStyles = async (expectedStyles: { + aspectRatio: string; + minHeight: string; + minWidth: string; + maxHeight: string; + maxWidth: string; + }) => { + const actualStyles = await PageObjects.lens.getWorkspaceVisContainerStyles(); + + expect(actualStyles).to.eql(expectedStyles); + }; + + const VERTICAL_16_9 = 16 / 9; + const outerWorkspaceDimensions = { width: 690, height: 400 }; + const UNCONSTRAINED = outerWorkspaceDimensions.width / outerWorkspaceDimensions.height; + + it('workspace size recovers from special vis types', async () => { + /** + * This list is specifically designed to test dimension transitions. + * + * I have attempted to order the vis types to maximize the number of transitions. + * + * Excluding XY charts since they are tested separately. + */ + const visTypes: Array<{ + id: string; + searchText?: string; + expectedHeight?: string; + expectedWidth?: string; + aspectRatio?: number; + }> = [ + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'lnsDatatable', aspectRatio: UNCONSTRAINED }, + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'lnsLegacyMetric', aspectRatio: UNCONSTRAINED }, + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'donut', aspectRatio: UNCONSTRAINED }, + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'mosaic', aspectRatio: UNCONSTRAINED }, + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'pie', aspectRatio: UNCONSTRAINED }, + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'treemap', aspectRatio: UNCONSTRAINED }, + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'waffle', aspectRatio: UNCONSTRAINED }, + // { id: 'heatmap', ...UNCONSTRAINED }, // heatmap blocks render unless it's given two dimensions. This stops the expression renderer from requesting new dimensions. + // { id: 'lnsChoropleth', ...UNCONSTRAINED }, // choropleth currently erases all dimensions + // { id: 'lnsTagcloud', ...UNCONSTRAINED }, // tag cloud currently erases all dimensions + ]; + + while (visTypes.length) { + const vis = visTypes.pop()!; + await retry.try(async () => { + await PageObjects.lens.switchToVisualization(vis.id, vis.searchText); + }); + + log.debug(`Testing ${vis.id}... expecting ${vis.expectedWidth}x${vis.expectedHeight}`); + + if (vis.aspectRatio) { + await assertWorkspaceAspectRatio(vis.aspectRatio); + } else { + await assertWorkspaceDimensions(vis.expectedWidth!, vis.expectedHeight!); + } + } + }); + + it('metric size (absolute pixels)', async () => { + await retry.try(async () => { + await PageObjects.lens.switchToVisualization('lnsMetric'); + }); + + await assertWorkspaceDimensions('300px', '300px'); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsMetric_breakdownByDimensionPanel > lns-empty-dimension', + operation: 'terms', + field: 'ip', + }); + + await assertWorkspaceDimensions('600px', '400px'); + + await PageObjects.lens.openDimensionEditor('lnsMetric_breakdownByDimensionPanel'); + await testSubjects.setValue('lnsMetric_max_cols', '2'); + + await assertWorkspaceDimensions('400px', '400px'); + }); + + it('gauge size (absolute pixels)', async () => { + await retry.try(async () => { + await PageObjects.lens.switchToVisualization('horizontalBullet', 'gauge'); + }); + + await assertWorkspaceDimensions('600px', '300px'); + + await retry.try(async () => { + await PageObjects.lens.switchToVisualization('verticalBullet', 'gauge'); + }); + + // this height is below the requested 600px + // that is because the window size isn't large enough to fit the requested dimensions + // and the chart is forced to shrink. + // + // this is a good thing because it makes this a test case for that scenario + await assertWorkspaceDimensions('300px', '400px'); + }); + + it('XY chart size', async () => { + // XY charts should have 100% width and 100% height unless they are a vertical chart with a time dimension + await retry.try(async () => { + // not important that this is specifically a line chart + await PageObjects.lens.switchToVisualization('line'); + }); + + await assertWorkspaceStyles({ + aspectRatio: 'auto', + minHeight: 'auto', + minWidth: 'auto', + maxHeight: '100%', + maxWidth: '100%', + }); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension', + operation: 'date_histogram', + field: '@timestamp', + }); + + await assertWorkspaceStyles({ + aspectRatio: '16 / 9', + minHeight: '300px', + minWidth: '100%', + maxHeight: 'none', + maxWidth: 'none', + }); + + await assertWorkspaceAspectRatio(VERTICAL_16_9); + + await retry.try(async () => { + await PageObjects.lens.switchToVisualization('bar_horizontal_stacked'); + }); + + await assertWorkspaceAspectRatio(UNCONSTRAINED); + }); + }); +} diff --git a/x-pack/test/functional/apps/lens/open_in_lens/agg_based/goal.ts b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/goal.ts index 55cb376db2e242..d9152af7411ba0 100644 --- a/x-pack/test/functional/apps/lens/open_in_lens/agg_based/goal.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/goal.ts @@ -48,7 +48,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '140.05%', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -80,7 +80,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '131,040,360.81%', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -112,7 +112,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '14.37%', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -156,7 +156,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '65,047,486.03', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -166,7 +166,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '66,144,823.35', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -176,7 +176,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '65,933,477.76', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -186,7 +186,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '65,157,898.23', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -196,7 +196,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '65,365,950.93', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, diff --git a/x-pack/test/functional/apps/lens/open_in_lens/agg_based/metric.ts b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/metric.ts index 89cb1d7880baa0..632af7eed9f988 100644 --- a/x-pack/test/functional/apps/lens/open_in_lens/agg_based/metric.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/metric.ts @@ -49,7 +49,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '14,005', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -80,7 +80,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '13,104,036,080.615', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -111,7 +111,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '1,437', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -166,7 +166,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,228,964,670.613', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -176,7 +176,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,186,695,551.251', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -186,7 +186,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,073,190,186.423', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -196,7 +196,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,031,579,645.108', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -206,7 +206,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,009,497,206.823', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 2af514b4a1fdc4..747767a71befe3 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -1947,5 +1947,28 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont await this.closeDimensionEditor(); }, + + async getWorkspaceVisContainerDimensions() { + const visContainer = await testSubjects.find('lnsWorkspacePanelWrapper__innerContent'); + const [width, height] = await Promise.all([ + visContainer.getComputedStyle('width'), + visContainer.getComputedStyle('height'), + ]); + + return { width, height }; + }, + + async getWorkspaceVisContainerStyles() { + const visContainer = await testSubjects.find('lnsWorkspacePanelWrapper__innerContent'); + const [maxWidth, maxHeight, minWidth, minHeight, aspectRatio] = await Promise.all([ + visContainer.getComputedStyle('max-width'), + visContainer.getComputedStyle('max-height'), + visContainer.getComputedStyle('min-width'), + visContainer.getComputedStyle('min-height'), + visContainer.getComputedStyle('aspect-ratio'), + ]); + + return { maxWidth, maxHeight, minWidth, minHeight, aspectRatio }; + }, }); } diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/goal.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/goal.ts index 5de789198f4201..01f655af00a1fa 100644 --- a/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/goal.ts +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/goal.ts @@ -50,7 +50,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '140.05%', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingBar: true, showingTrendline: false, }, @@ -77,7 +77,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '131,040,360.81%', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingBar: true, showingTrendline: false, }, @@ -105,7 +105,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '14.37%', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingBar: true, showingTrendline: false, }, @@ -133,7 +133,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,228,964,670.613', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingTrendline: false, showingBar: true, }, @@ -142,7 +142,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,186,695,551.251', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingTrendline: false, showingBar: true, }, @@ -151,7 +151,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,073,190,186.423', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingTrendline: false, showingBar: true, }, @@ -160,7 +160,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,031,579,645.108', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingTrendline: false, showingBar: true, }, @@ -169,7 +169,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,009,497,206.823', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingTrendline: false, showingBar: true, }, diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/metric.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/metric.ts index abd44aefe4d5a4..9bd990484cc81b 100644 --- a/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/metric.ts +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/metric.ts @@ -46,7 +46,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '14,005', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingBar: false, showingTrendline: false, }, @@ -72,7 +72,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '13,104,036,080.615', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingBar: false, showingTrendline: false, }, @@ -99,7 +99,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '1,437', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingBar: false, showingTrendline: false, },