diff --git a/x-pack/plugins/lens/common/constants.ts b/x-pack/plugins/lens/common/constants.ts index bba3ac7e8a9ca..edf7654deb7b7 100644 --- a/x-pack/plugins/lens/common/constants.ts +++ b/x-pack/plugins/lens/common/constants.ts @@ -17,7 +17,10 @@ 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 layerTypes: Record = { DATA: 'data', THRESHOLD: 'threshold' }; +export const layerTypes: Record = { + DATA: 'data', + REFERENCELINE: 'referenceLine', +}; export function getBasePath() { return `#/`; diff --git a/x-pack/plugins/lens/common/expressions/xy_chart/axis_config.ts b/x-pack/plugins/lens/common/expressions/xy_chart/axis_config.ts index 9ff1b5a4dc3f7..0b9667353706d 100644 --- a/x-pack/plugins/lens/common/expressions/xy_chart/axis_config.ts +++ b/x-pack/plugins/lens/common/expressions/xy_chart/axis_config.ts @@ -173,24 +173,24 @@ export const yAxisConfig: ExpressionFunctionDefinition< lineStyle: { types: ['string'], options: ['solid', 'dotted', 'dashed'], - help: 'The style of the threshold line', + help: 'The style of the reference line', }, lineWidth: { types: ['number'], - help: 'The width of the threshold line', + help: 'The width of the reference line', }, icon: { types: ['string'], - help: 'An optional icon used for threshold lines', + help: 'An optional icon used for reference lines', }, iconPosition: { types: ['string'], options: ['auto', 'above', 'below', 'left', 'right'], - help: 'The placement of the icon for the threshold line', + help: 'The placement of the icon for the reference line', }, textVisibility: { types: ['boolean'], - help: 'Visibility of the label on the threshold line', + help: 'Visibility of the label on the reference line', }, fill: { types: ['string'], diff --git a/x-pack/plugins/lens/common/types.ts b/x-pack/plugins/lens/common/types.ts index 659d3c0eced26..38e198c01e730 100644 --- a/x-pack/plugins/lens/common/types.ts +++ b/x-pack/plugins/lens/common/types.ts @@ -61,4 +61,4 @@ export interface CustomPaletteParams { export type RequiredPaletteParamTypes = Required; -export type LayerType = 'data' | 'threshold'; +export type LayerType = 'data' | 'referenceLine'; diff --git a/x-pack/plugins/lens/public/assets/chart_bar_threshold.tsx b/x-pack/plugins/lens/public/assets/chart_bar_reference_line.tsx similarity index 97% rename from x-pack/plugins/lens/public/assets/chart_bar_threshold.tsx rename to x-pack/plugins/lens/public/assets/chart_bar_reference_line.tsx index 88e0a46b5538c..447641540a284 100644 --- a/x-pack/plugins/lens/public/assets/chart_bar_threshold.tsx +++ b/x-pack/plugins/lens/public/assets/chart_bar_reference_line.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiIconProps } from '@elastic/eui'; -export const LensIconChartBarThreshold = ({ +export const LensIconChartBarReferenceLine = ({ title, titleId, ...props diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx index 61d37d4cc9fed..a8436edb63f63 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx @@ -280,7 +280,7 @@ describe('ConfigPanel', () => { instance.update(); act(() => { instance - .find(`[data-test-subj="lnsLayerAddButton-${layerTypes.THRESHOLD}"]`) + .find(`[data-test-subj="lnsLayerAddButton-${layerTypes.REFERENCELINE}"]`) .first() .simulate('click'); }); @@ -301,8 +301,8 @@ describe('ConfigPanel', () => { props.activeVisualization.getSupportedLayers = jest.fn(() => [ { type: layerTypes.DATA, label: 'Data Layer' }, { - type: layerTypes.THRESHOLD, - label: 'Threshold layer', + type: layerTypes.REFERENCELINE, + label: 'Reference layer', }, ]); datasourceMap.testDatasource.initializeDimension = jest.fn(); @@ -331,8 +331,8 @@ describe('ConfigPanel', () => { ], }, { - type: layerTypes.THRESHOLD, - label: 'Threshold layer', + type: layerTypes.REFERENCELINE, + label: 'Reference layer', }, ]); datasourceMap.testDatasource.initializeDimension = jest.fn(); @@ -349,8 +349,8 @@ describe('ConfigPanel', () => { props.activeVisualization.getSupportedLayers = jest.fn(() => [ { type: layerTypes.DATA, label: 'Data Layer' }, { - type: layerTypes.THRESHOLD, - label: 'Threshold layer', + type: layerTypes.REFERENCELINE, + label: 'Reference layer', initialDimensions: [ { groupId: 'testGroup', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx index 8286ab492f14d..93718c88b251c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx @@ -26,6 +26,7 @@ import { insertOrReplaceColumn, replaceColumn, updateColumnParam, + updateDefaultLabels, resetIncomplete, FieldBasedIndexPatternColumn, canTransition, @@ -151,13 +152,27 @@ export function DimensionEditor(props: DimensionEditorProps) { const addStaticValueColumn = (prevLayer = props.state.layers[props.layerId]) => { if (selectedColumn?.operationType !== staticValueOperationName) { trackUiEvent(`indexpattern_dimension_operation_static_value`); - return insertOrReplaceColumn({ + const layer = insertOrReplaceColumn({ layer: prevLayer, indexPattern: currentIndexPattern, columnId, op: staticValueOperationName, visualizationGroups: dimensionGroups, }); + const value = props.activeData?.[layerId]?.rows[0]?.[columnId]; + // replace the default value with the one from the active data + if (value != null) { + return updateDefaultLabels( + updateColumnParam({ + layer, + columnId, + paramName: 'value', + value: props.activeData?.[layerId]?.rows[0]?.[columnId], + }), + currentIndexPattern + ); + } + return layer; } return prevLayer; }; @@ -173,7 +188,18 @@ export function DimensionEditor(props: DimensionEditorProps) { if (temporaryStaticValue) { setTemporaryState('none'); } - return setStateWrapper(setter, { forceRender: true }); + if (typeof setter === 'function') { + return setState( + (prevState) => { + const layer = setter(addStaticValueColumn(prevState.layers[layerId])); + return mergeLayer({ state: prevState, layerId, newLayer: layer }); + }, + { + isDimensionComplete: true, + forceRender: true, + } + ); + } }; const ParamEditor = getParamEditor( diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx index bf4b10de386a1..9315b61adcc54 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx @@ -1206,11 +1206,11 @@ describe('IndexPattern Data Source suggestions', () => { const modifiedState: IndexPatternPrivateState = { ...initialState, layers: { - thresholdLayer: { + referenceLineLayer: { indexPatternId: '1', - columnOrder: ['threshold'], + columnOrder: ['referenceLine'], columns: { - threshold: { + referenceLine: { dataType: 'number', isBucketed: false, label: 'Static Value: 0', @@ -1251,10 +1251,10 @@ describe('IndexPattern Data Source suggestions', () => { modifiedState, '1', documentField, - (layerId) => layerId !== 'thresholdLayer' + (layerId) => layerId !== 'referenceLineLayer' ) ); - // should ignore the threshold layer + // should ignore the referenceLine layer expect(suggestions).toContainEqual( expect.objectContaining({ table: expect.objectContaining({ @@ -1704,7 +1704,7 @@ describe('IndexPattern Data Source suggestions', () => { ); }); - it('adds date histogram over default time field for tables without time dimension and a threshold', async () => { + it('adds date histogram over default time field for tables without time dimension and a referenceLine', async () => { const initialState = testInitialState(); const state: IndexPatternPrivateState = { ...initialState, @@ -1738,11 +1738,11 @@ describe('IndexPattern Data Source suggestions', () => { }, }, }, - threshold: { + referenceLine: { indexPatternId: '2', - columnOrder: ['thresholda'], + columnOrder: ['referenceLineA'], columns: { - thresholda: { + referenceLineA: { label: 'My Op', customLabel: true, dataType: 'number', @@ -1758,7 +1758,7 @@ describe('IndexPattern Data Source suggestions', () => { expect( getSuggestionSubset( - getDatasourceSuggestionsFromCurrentState(state, (layerId) => layerId !== 'threshold') + getDatasourceSuggestionsFromCurrentState(state, (layerId) => layerId !== 'referenceLine') ) ).toContainEqual( expect.objectContaining({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.test.ts index d68fd8b9555f9..8b1eaeb109d9b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.test.ts @@ -21,7 +21,7 @@ describe('utils', () => { describe('checkForDataLayerType', () => { it('should return an error if the layer is of the wrong type', () => { - expect(checkForDataLayerType(layerTypes.THRESHOLD, 'Operation')).toEqual([ + expect(checkForDataLayerType(layerTypes.REFERENCELINE, 'Operation')).toEqual([ 'Operation is disabled for this type of layer.', ]); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.ts index 87c4355c1dc9f..0ec7ad046ac2a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.ts @@ -24,7 +24,7 @@ export const buildLabelFunction = }; export function checkForDataLayerType(layerType: LayerType, name: string) { - if (layerType === layerTypes.THRESHOLD) { + if (layerType === layerTypes.REFERENCELINE) { return [ i18n.translate('xpack.lens.indexPattern.calculations.layerDataType', { defaultMessage: '{name} is disabled for this type of layer.', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx index 0a6620eecf308..1c574fe69611c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx @@ -80,14 +80,14 @@ describe('static_value', () => { }; }); - function getLayerWithStaticValue(newValue: string): IndexPatternLayer { + function getLayerWithStaticValue(newValue: string | null | undefined): IndexPatternLayer { return { ...layer, columns: { ...layer.columns, col2: { ...layer.columns.col2, - label: `Static value: ${newValue}`, + label: `Static value: ${newValue ?? String(newValue)}`, params: { value: newValue, }, @@ -155,8 +155,9 @@ describe('static_value', () => { ).toBeUndefined(); }); - it('should return error for invalid values', () => { - for (const value of ['NaN', 'Infinity', 'string']) { + it.each(['NaN', 'Infinity', 'string'])( + 'should return error for invalid values: %s', + (value) => { expect( staticValueOperation.getErrorMessage!( getLayerWithStaticValue(value), @@ -165,6 +166,16 @@ describe('static_value', () => { ) ).toEqual(expect.arrayContaining([expect.stringMatching('is not a valid number')])); } + ); + + it.each([null, undefined])('should return no error for: %s', (value) => { + expect( + staticValueOperation.getErrorMessage!( + getLayerWithStaticValue(value), + 'col2', + createMockedIndexPattern() + ) + ).toBe(undefined); }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx index a76c5f64d1750..26be4e7b114da 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx @@ -61,7 +61,7 @@ export const staticValueOperation: OperationDefinition< getErrorMessage(layer, columnId) { const column = layer.columns[columnId] as StaticValueIndexPatternColumn; - return !isValidNumber(column.params.value) + return column.params.value != null && !isValidNumber(column.params.value) ? [ i18n.translate('xpack.lens.indexPattern.staticValueError', { defaultMessage: 'The static value of {value} is not a valid number', @@ -176,10 +176,7 @@ export const staticValueOperation: OperationDefinition< // Pick the data from the current activeData (to be used when the current operation is not static_value) const activeDataValue = - activeData && - activeData[layerId] && - activeData[layerId]?.rows?.length === 1 && - activeData[layerId].rows[0][columnId]; + activeData?.[layerId]?.rows?.length === 1 && activeData[layerId].rows[0][columnId]; const fallbackValue = currentColumn?.operationType !== 'static_value' && activeDataValue != null @@ -206,7 +203,7 @@ export const staticValueOperation: OperationDefinition<
{i18n.translate('xpack.lens.indexPattern.staticValue.label', { - defaultMessage: 'Threshold value', + defaultMessage: 'Reference line value', })} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts index b3b98e5054aa6..9f3cba89ce17b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts @@ -1406,7 +1406,7 @@ export function isOperationAllowedAsReference({ // Labels need to be updated when columns are added because reference-based column labels // are sometimes copied into the parents -function updateDefaultLabels( +export function updateDefaultLabels( layer: IndexPatternLayer, indexPattern: IndexPattern ): IndexPatternLayer { diff --git a/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts b/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts index 30238507c3566..5ed6ec052a0da 100644 --- a/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts +++ b/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts @@ -24,7 +24,7 @@ interface LayerColorConfig { layerType: LayerType; } -export const defaultThresholdColor = euiLightVars.euiColorDarkShade; +export const defaultReferenceLineColor = euiLightVars.euiColorDarkShade; export type ColorAssignments = Record< string, @@ -117,11 +117,11 @@ export function getAccessorColorConfig( triggerIcon: 'disabled', }; } - if (layer.layerType === layerTypes.THRESHOLD) { + if (layer.layerType === layerTypes.REFERENCELINE) { return { columnId: accessor as string, triggerIcon: 'color', - color: currentYConfig?.color || defaultThresholdColor, + color: currentYConfig?.color || defaultReferenceLineColor, }; } const columnToLabel = getColumnToLabelMap(layer, frame.datasourceLayers[layer.layerId]); diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx index af2995fb65b71..9c272202e4565 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx @@ -330,7 +330,7 @@ function sampleArgs() { return { data, args }; } -function sampleArgsWithThreshold(thresholdValue: number = 150) { +function sampleArgsWithReferenceLine(value: number = 150) { const { data, args } = sampleArgs(); return { @@ -338,16 +338,16 @@ function sampleArgsWithThreshold(thresholdValue: number = 150) { ...data, tables: { ...data.tables, - threshold: { + referenceLine: { type: 'datatable', columns: [ { - id: 'threshold-a', + id: 'referenceLine-a', meta: { params: { id: 'number' }, type: 'number' }, name: 'Static value', }, ], - rows: [{ 'threshold-a': thresholdValue }], + rows: [{ 'referenceLine-a': value }], }, }, } as LensMultiTable, @@ -356,16 +356,16 @@ function sampleArgsWithThreshold(thresholdValue: number = 150) { layers: [ ...args.layers, { - layerType: layerTypes.THRESHOLD, - accessors: ['threshold-a'], - layerId: 'threshold', + layerType: layerTypes.REFERENCELINE, + accessors: ['referenceLine-a'], + layerId: 'referenceLine', seriesType: 'line', xScaleType: 'linear', yScaleType: 'linear', palette: mockPaletteOutput, isHistogram: false, hide: true, - yConfig: [{ axisMode: 'left', forAccessor: 'threshold-a', type: 'lens_xy_yConfig' }], + yConfig: [{ axisMode: 'left', forAccessor: 'referenceLine-a', type: 'lens_xy_yConfig' }], }, ], } as XYArgs, @@ -874,8 +874,8 @@ describe('xy_expression', () => { }); }); - test('it does include threshold values when in full extent mode', () => { - const { data, args } = sampleArgsWithThreshold(); + test('it does include referenceLine values when in full extent mode', () => { + const { data, args } = sampleArgsWithReferenceLine(); const component = shallow(); expect(component.find(Axis).find('[id="left"]').prop('domain')).toEqual({ @@ -885,8 +885,8 @@ describe('xy_expression', () => { }); }); - test('it should ignore threshold values when set to custom extents', () => { - const { data, args } = sampleArgsWithThreshold(); + test('it should ignore referenceLine values when set to custom extents', () => { + const { data, args } = sampleArgsWithReferenceLine(); const component = shallow( { }); }); - test('it should work for negative values in thresholds', () => { - const { data, args } = sampleArgsWithThreshold(-150); + test('it should work for negative values in referenceLines', () => { + const { data, args } = sampleArgsWithReferenceLine(-150); const component = shallow(); expect(component.find(Axis).find('[id="left"]').prop('domain')).toEqual({ diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index 7aee537ebbedd..36f1b92b8a1f4 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -64,10 +64,10 @@ import { getXDomain, XyEndzones } from './x_domain'; import { getLegendAction } from './get_legend_action'; import { computeChartMargins, - getThresholdRequiredPaddings, - ThresholdAnnotations, -} from './expression_thresholds'; -import { computeOverallDataDomain } from './threshold_helpers'; + getReferenceLineRequiredPaddings, + ReferenceLineAnnotations, +} from './expression_reference_lines'; +import { computeOverallDataDomain } from './reference_line_helpers'; declare global { interface Window { @@ -264,7 +264,9 @@ export function XYChart({ const icon: IconType = layers.length > 0 ? getIconForSeriesType(layers[0].seriesType) : 'bar'; return ; } - const thresholdLayers = layers.filter((layer) => layer.layerType === layerTypes.THRESHOLD); + const referenceLineLayers = layers.filter( + (layer) => layer.layerType === layerTypes.REFERENCELINE + ); // use formatting hint of first x axis column to format ticks const xAxisColumn = data.tables[filteredLayers[0].layerId].columns.find( @@ -332,7 +334,7 @@ export function XYChart({ left: yAxesConfiguration.find(({ groupId }) => groupId === 'left'), right: yAxesConfiguration.find(({ groupId }) => groupId === 'right'), }; - const thresholdPaddings = getThresholdRequiredPaddings(thresholdLayers, yAxesMap); + const referenceLinePaddings = getReferenceLineRequiredPaddings(referenceLineLayers, yAxesMap); const getYAxesTitles = ( axisSeries: Array<{ layer: string; accessor: string }>, @@ -364,9 +366,9 @@ export function XYChart({ ? args.labelsOrientation?.yRight || 0 : args.labelsOrientation?.yLeft || 0, padding: - thresholdPaddings[groupId] != null + referenceLinePaddings[groupId] != null ? { - inner: thresholdPaddings[groupId], + inner: referenceLinePaddings[groupId], } : undefined, }, @@ -377,9 +379,9 @@ export function XYChart({ : axisTitlesVisibilitySettings?.yLeft, // if labels are not visible add the padding to the title padding: - !tickVisible && thresholdPaddings[groupId] != null + !tickVisible && referenceLinePaddings[groupId] != null ? { - inner: thresholdPaddings[groupId], + inner: referenceLinePaddings[groupId], } : undefined, }, @@ -406,10 +408,10 @@ export function XYChart({ max = extent.upperBound ?? NaN; } } else { - const axisHasThreshold = thresholdLayers.some(({ yConfig }) => + const axisHasReferenceLine = referenceLineLayers.some(({ yConfig }) => yConfig?.some(({ axisMode }) => axisMode === axis.groupId) ); - if (!fit && axisHasThreshold) { + if (!fit && axisHasReferenceLine) { // Remove this once the chart will support automatic annotation fit for other type of charts const { min: computedMin, max: computedMax } = computeOverallDataDomain( filteredLayers, @@ -421,7 +423,7 @@ export function XYChart({ max = Math.max(computedMax, max || 0); min = Math.min(computedMin, min || 0); } - for (const { layerId, yConfig } of thresholdLayers) { + for (const { layerId, yConfig } of referenceLineLayers) { const table = data.tables[layerId]; for (const { axisMode, forAccessor } of yConfig || []) { if (axis.groupId === axisMode) { @@ -575,11 +577,11 @@ export function XYChart({ legend: { labelOptions: { maxLines: legend.shouldTruncate ? legend?.maxLines ?? 1 : 0 }, }, - // if not title or labels are shown for axes, add some padding if required by threshold markers + // if not title or labels are shown for axes, add some padding if required by reference line markers chartMargins: { ...chartTheme.chartPaddings, ...computeChartMargins( - thresholdPaddings, + referenceLinePaddings, tickLabelsVisibilitySettings, axisTitlesVisibilitySettings, yAxesMap, @@ -622,13 +624,15 @@ export function XYChart({ visible: tickLabelsVisibilitySettings?.x, rotation: labelsOrientation?.x, padding: - thresholdPaddings.bottom != null ? { inner: thresholdPaddings.bottom } : undefined, + referenceLinePaddings.bottom != null + ? { inner: referenceLinePaddings.bottom } + : undefined, }, axisTitle: { visible: axisTitlesVisibilitySettings.x, padding: - !tickLabelsVisibilitySettings?.x && thresholdPaddings.bottom != null - ? { inner: thresholdPaddings.bottom } + !tickLabelsVisibilitySettings?.x && referenceLinePaddings.bottom != null + ? { inner: referenceLinePaddings.bottom } : undefined, }, }} @@ -911,9 +915,9 @@ export function XYChart({ } }) )} - {thresholdLayers.length ? ( - ) : null} diff --git a/x-pack/plugins/lens/public/xy_visualization/expression_reference_lines.scss b/x-pack/plugins/lens/public/xy_visualization/expression_reference_lines.scss new file mode 100644 index 0000000000000..07946b52b0000 --- /dev/null +++ b/x-pack/plugins/lens/public/xy_visualization/expression_reference_lines.scss @@ -0,0 +1,18 @@ +.lnsXyDecorationRotatedWrapper { + display: inline-block; + overflow: hidden; + line-height: 1.5; + + .lnsXyDecorationRotatedWrapper__label { + display: inline-block; + white-space: nowrap; + transform: translate(0, 100%) rotate(-90deg); + transform-origin: 0 0; + + &::after { + content: ''; + float: left; + margin-top: 100%; + } + } +} \ No newline at end of file diff --git a/x-pack/plugins/lens/public/xy_visualization/expression_thresholds.tsx b/x-pack/plugins/lens/public/xy_visualization/expression_reference_lines.tsx similarity index 81% rename from x-pack/plugins/lens/public/xy_visualization/expression_thresholds.tsx rename to x-pack/plugins/lens/public/xy_visualization/expression_reference_lines.tsx index 67e994b734b84..42e02871026df 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression_thresholds.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression_reference_lines.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import './expression_thresholds.scss'; +import './expression_reference_lines.scss'; import React from 'react'; import { groupBy } from 'lodash'; import { EuiIcon } from '@elastic/eui'; @@ -15,59 +15,59 @@ import type { FieldFormat } from 'src/plugins/field_formats/common'; import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; import type { LayerArgs, YConfig } from '../../common/expressions'; import type { LensMultiTable } from '../../common/types'; -import { hasIcon } from './xy_config_panel/threshold_panel'; +import { hasIcon } from './xy_config_panel/reference_line_panel'; -const THRESHOLD_MARKER_SIZE = 20; +const REFERENCE_LINE_MARKER_SIZE = 20; export const computeChartMargins = ( - thresholdPaddings: Partial>, + referenceLinePaddings: Partial>, labelVisibility: Partial>, titleVisibility: Partial>, axesMap: Record<'left' | 'right', unknown>, isHorizontal: boolean ) => { const result: Partial> = {}; - if (!labelVisibility?.x && !titleVisibility?.x && thresholdPaddings.bottom) { + if (!labelVisibility?.x && !titleVisibility?.x && referenceLinePaddings.bottom) { const placement = isHorizontal ? mapVerticalToHorizontalPlacement('bottom') : 'bottom'; - result[placement] = thresholdPaddings.bottom; + result[placement] = referenceLinePaddings.bottom; } if ( - thresholdPaddings.left && + referenceLinePaddings.left && (isHorizontal || (!labelVisibility?.yLeft && !titleVisibility?.yLeft)) ) { const placement = isHorizontal ? mapVerticalToHorizontalPlacement('left') : 'left'; - result[placement] = thresholdPaddings.left; + result[placement] = referenceLinePaddings.left; } if ( - thresholdPaddings.right && + referenceLinePaddings.right && (isHorizontal || !axesMap.right || (!labelVisibility?.yRight && !titleVisibility?.yRight)) ) { const placement = isHorizontal ? mapVerticalToHorizontalPlacement('right') : 'right'; - result[placement] = thresholdPaddings.right; + result[placement] = referenceLinePaddings.right; } // there's no top axis, so just check if a margin has been computed - if (thresholdPaddings.top) { + if (referenceLinePaddings.top) { const placement = isHorizontal ? mapVerticalToHorizontalPlacement('top') : 'top'; - result[placement] = thresholdPaddings.top; + result[placement] = referenceLinePaddings.top; } return result; }; -// Note: it does not take into consideration whether the threshold is in view or not -export const getThresholdRequiredPaddings = ( - thresholdLayers: LayerArgs[], +// Note: it does not take into consideration whether the reference line is in view or not +export const getReferenceLineRequiredPaddings = ( + referenceLineLayers: LayerArgs[], axesMap: Record<'left' | 'right', unknown> ) => { // collect all paddings for the 4 axis: if any text is detected double it. const paddings: Partial> = {}; const icons: Partial> = {}; - thresholdLayers.forEach((layer) => { + referenceLineLayers.forEach((layer) => { layer.yConfig?.forEach(({ axisMode, icon, iconPosition, textVisibility }) => { if (axisMode && (hasIcon(icon) || textVisibility)) { const placement = getBaseIconPlacement(iconPosition, axisMode, axesMap); paddings[placement] = Math.max( paddings[placement] || 0, - THRESHOLD_MARKER_SIZE * (textVisibility ? 2 : 1) // double the padding size if there's text + REFERENCE_LINE_MARKER_SIZE * (textVisibility ? 2 : 1) // double the padding size if there's text ); icons[placement] = (icons[placement] || 0) + (hasIcon(icon) ? 1 : 0); } @@ -77,7 +77,7 @@ export const getThresholdRequiredPaddings = ( // if no icon is present for the placement, just reduce the padding (Object.keys(paddings) as Position[]).forEach((placement) => { if (!icons[placement]) { - paddings[placement] = THRESHOLD_MARKER_SIZE; + paddings[placement] = REFERENCE_LINE_MARKER_SIZE; } }); @@ -133,7 +133,7 @@ function getMarkerBody(label: string | undefined, isHorizontal: boolean) { } if (isHorizontal) { return ( -
+
{label}
); @@ -142,13 +142,13 @@ function getMarkerBody(label: string | undefined, isHorizontal: boolean) {
{label} @@ -180,32 +180,32 @@ function getMarkerToShow( } } -export const ThresholdAnnotations = ({ - thresholdLayers, +export const ReferenceLineAnnotations = ({ + layers, data, formatters, paletteService, syncColors, axesMap, isHorizontal, - thresholdPaddingMap, + paddingMap, }: { - thresholdLayers: LayerArgs[]; + layers: LayerArgs[]; data: LensMultiTable; formatters: Record<'left' | 'right' | 'bottom', FieldFormat | undefined>; paletteService: PaletteRegistry; syncColors: boolean; axesMap: Record<'left' | 'right', boolean>; isHorizontal: boolean; - thresholdPaddingMap: Partial>; + paddingMap: Partial>; }) => { return ( <> - {thresholdLayers.flatMap((thresholdLayer) => { - if (!thresholdLayer.yConfig) { + {layers.flatMap((layer) => { + if (!layer.yConfig) { return []; } - const { columnToLabel, yConfig: yConfigs, layerId } = thresholdLayer; + const { columnToLabel, yConfig: yConfigs, layerId } = layer; const columnToLabelMap: Record = columnToLabel ? JSON.parse(columnToLabel) : {}; @@ -218,6 +218,9 @@ export const ThresholdAnnotations = ({ ); const groupedByDirection = groupBy(yConfigByValue, 'fill'); + if (groupedByDirection.below) { + groupedByDirection.below.reverse(); + } return yConfigByValue.flatMap((yConfig, i) => { // Find the formatter for the given axis @@ -240,7 +243,7 @@ export const ThresholdAnnotations = ({ ); // the padding map is built for vertical chart const hasReducedPadding = - thresholdPaddingMap[markerPositionVertical] === THRESHOLD_MARKER_SIZE; + paddingMap[markerPositionVertical] === REFERENCE_LINE_MARKER_SIZE; const props = { groupId, @@ -306,7 +309,7 @@ export const ThresholdAnnotations = ({ const indexFromSameType = groupedByDirection[yConfig.fill].findIndex( ({ forAccessor }) => forAccessor === yConfig.forAccessor ); - const shouldCheckNextThreshold = + const shouldCheckNextReferenceLine = indexFromSameType < groupedByDirection[yConfig.fill].length - 1; annotations.push( { + const nextValue = + !isFillAbove && shouldCheckNextReferenceLine + ? row[groupedByDirection[yConfig.fill!][indexFromSameType + 1].forAccessor] + : undefined; if (yConfig.axisMode === 'bottom') { return { coordinates: { - x0: isFillAbove ? row[yConfig.forAccessor] : undefined, + x0: isFillAbove ? row[yConfig.forAccessor] : nextValue, y0: undefined, - x1: isFillAbove - ? shouldCheckNextThreshold - ? row[ - groupedByDirection[yConfig.fill!][indexFromSameType + 1].forAccessor - ] - : undefined - : row[yConfig.forAccessor], + x1: isFillAbove ? nextValue : row[yConfig.forAccessor], y1: undefined, }, header: columnToLabelMap[yConfig.forAccessor], @@ -336,15 +337,9 @@ export const ThresholdAnnotations = ({ return { coordinates: { x0: undefined, - y0: isFillAbove ? row[yConfig.forAccessor] : undefined, + y0: isFillAbove ? row[yConfig.forAccessor] : nextValue, x1: undefined, - y1: isFillAbove - ? shouldCheckNextThreshold - ? row[ - groupedByDirection[yConfig.fill!][indexFromSameType + 1].forAccessor - ] - : undefined - : row[yConfig.forAccessor], + y1: isFillAbove ? nextValue : row[yConfig.forAccessor], }, header: columnToLabelMap[yConfig.forAccessor], details: diff --git a/x-pack/plugins/lens/public/xy_visualization/threshold_helpers.test.ts b/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.test.ts similarity index 99% rename from x-pack/plugins/lens/public/xy_visualization/threshold_helpers.test.ts rename to x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.test.ts index d7286de0316d6..9dacc12c68d65 100644 --- a/x-pack/plugins/lens/public/xy_visualization/threshold_helpers.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.test.ts @@ -7,7 +7,7 @@ import { XYLayerConfig } from '../../common/expressions'; import { FramePublicAPI } from '../types'; -import { computeOverallDataDomain, getStaticValue } from './threshold_helpers'; +import { computeOverallDataDomain, getStaticValue } from './reference_line_helpers'; function getActiveData(json: Array<{ id: string; rows: Array> }>) { return json.reduce((memo, { id, rows }) => { @@ -25,7 +25,7 @@ function getActiveData(json: Array<{ id: string; rows: Array); } -describe('threshold helpers', () => { +describe('reference_line helpers', () => { describe('getStaticValue', () => { const hasDateHistogram = () => false; const hasAllNumberHistogram = () => true; diff --git a/x-pack/plugins/lens/public/xy_visualization/threshold_helpers.tsx b/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.tsx similarity index 83% rename from x-pack/plugins/lens/public/xy_visualization/threshold_helpers.tsx rename to x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.tsx index 8bf5f84b15bad..71ce2d0ea2082 100644 --- a/x-pack/plugins/lens/public/xy_visualization/threshold_helpers.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.tsx @@ -15,17 +15,17 @@ import { isPercentageSeries, isStackedChart } from './state_helpers'; import type { XYState } from './types'; import { checkScaleOperation } from './visualization_helpers'; -export interface ThresholdBase { +export interface ReferenceLineBase { label: 'x' | 'yRight' | 'yLeft'; } /** - * Return the threshold layers groups to show based on multiple criteria: + * Return the reference layers groups to show based on multiple criteria: * * what groups are current defined in data layers - * * what existing threshold are currently defined in data thresholds + * * what existing reference line are currently defined in reference layers */ -export function getGroupsToShow( - thresholdLayers: T[], +export function getGroupsToShow( + referenceLayers: T[], state: XYState | undefined, datasourceLayers: Record, tables: Record | undefined @@ -37,16 +37,16 @@ export function getGroupsToShow layerType === layerTypes.DATA ); const groupsAvailable = getGroupsAvailableInData(dataLayers, datasourceLayers, tables); - return thresholdLayers + return referenceLayers .filter(({ label, config }: T) => groupsAvailable[label] || config?.length) .map((layer) => ({ ...layer, valid: groupsAvailable[layer.label] })); } /** - * Returns the threshold layers groups to show based on what groups are current defined in data layers. + * Returns the reference layers groups to show based on what groups are current defined in data layers. */ -export function getGroupsRelatedToData( - thresholdLayers: T[], +export function getGroupsRelatedToData( + referenceLayers: T[], state: XYState | undefined, datasourceLayers: Record, tables: Record | undefined @@ -58,7 +58,7 @@ export function getGroupsRelatedToData( ({ layerType = layerTypes.DATA }) => layerType === layerTypes.DATA ); const groupsAvailable = getGroupsAvailableInData(dataLayers, datasourceLayers, tables); - return thresholdLayers.filter(({ label }: T) => groupsAvailable[label]); + return referenceLayers.filter(({ label }: T) => groupsAvailable[label]); } /** * Returns a dictionary with the groups filled in all the data layers @@ -90,7 +90,7 @@ export function getStaticValue( return fallbackValue; } - // filter and organize data dimensions into threshold groups + // filter and organize data dimensions into reference layer groups // now pick the columnId in the active data const { dataLayers: filteredLayers, @@ -128,29 +128,22 @@ function getAccessorCriteriaForGroup( ...rest, accessors: [xAccessor] as string[], })), - // need the untouched ones for some checks later on + // need the untouched ones to check if there are invalid layers from the filtered ones + // to perform the checks the original accessor structure needs to be accessed untouchedDataLayers: filteredDataLayers, accessors: filteredDataLayers.map(({ xAccessor }) => xAccessor) as string[], }; } - case 'yLeft': { - const { left } = groupAxesByType(dataLayers, activeData); - const leftIds = new Set(left.map(({ layer }) => layer)); - const filteredDataLayers = dataLayers.filter(({ layerId }) => leftIds.has(layerId)); - return { - dataLayers: filteredDataLayers, - untouchedDataLayers: filteredDataLayers, - accessors: left.map(({ accessor }) => accessor), - }; - } + case 'yLeft': case 'yRight': { - const { right } = groupAxesByType(dataLayers, activeData); - const rightIds = new Set(right.map(({ layer }) => layer)); + const prop = groupId === 'yLeft' ? 'left' : 'right'; + const { [prop]: axis } = groupAxesByType(dataLayers, activeData); + const rightIds = new Set(axis.map(({ layer }) => layer)); const filteredDataLayers = dataLayers.filter(({ layerId }) => rightIds.has(layerId)); return { dataLayers: filteredDataLayers, untouchedDataLayers: filteredDataLayers, - accessors: right.map(({ accessor }) => accessor), + accessors: axis.map(({ accessor }) => accessor), }; } } @@ -224,11 +217,11 @@ function computeStaticValueForGroup( activeData: NonNullable, minZeroOrNegativeBase: boolean = true ) { - const defaultThresholdFactor = 3 / 4; + const defaultReferenceLineFactor = 3 / 4; if (dataLayers.length && accessorIds.length) { if (dataLayers.some(({ seriesType }) => isPercentageSeries(seriesType))) { - return defaultThresholdFactor; + return defaultReferenceLineFactor; } const { min, max } = computeOverallDataDomain(dataLayers, accessorIds, activeData); @@ -237,7 +230,7 @@ function computeStaticValueForGroup( // Custom axis bounds can go below 0, so consider also lower values than 0 const finalMinValue = minZeroOrNegativeBase ? Math.min(0, min) : min; const interval = max - finalMinValue; - return Number((finalMinValue + interval * defaultThresholdFactor).toFixed(2)); + return Number((finalMinValue + interval * defaultReferenceLineFactor).toFixed(2)); } } } diff --git a/x-pack/plugins/lens/public/xy_visualization/to_expression.test.ts b/x-pack/plugins/lens/public/xy_visualization/to_expression.test.ts index d174fb831c2dc..7d1bd64abe906 100644 --- a/x-pack/plugins/lens/public/xy_visualization/to_expression.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/to_expression.test.ts @@ -13,7 +13,7 @@ import { Operation } from '../types'; import { createMockDatasource, createMockFramePublicAPI } from '../mocks'; import { layerTypes } from '../../common'; import { fieldFormatsServiceMock } from '../../../../../src/plugins/field_formats/public/mocks'; -import { defaultThresholdColor } from './color_assignment'; +import { defaultReferenceLineColor } from './color_assignment'; describe('#toExpression', () => { const xyVisualization = getXyVisualization({ @@ -338,8 +338,8 @@ describe('#toExpression', () => { yConfig: [{ forAccessor: 'a' }], }, { - layerId: 'threshold', - layerType: layerTypes.THRESHOLD, + layerId: 'referenceLine', + layerType: layerTypes.REFERENCELINE, seriesType: 'area', splitAccessor: 'd', xAccessor: 'a', @@ -348,7 +348,7 @@ describe('#toExpression', () => { }, ], }, - { ...frame.datasourceLayers, threshold: mockDatasource.publicAPIMock } + { ...frame.datasourceLayers, referenceLine: mockDatasource.publicAPIMock } ) as Ast; function getYConfigColorForLayer(ast: Ast, index: number) { @@ -356,6 +356,6 @@ describe('#toExpression', () => { .chain[0].arguments.color; } expect(getYConfigColorForLayer(expression, 0)).toEqual([]); - expect(getYConfigColorForLayer(expression, 1)).toEqual([defaultThresholdColor]); + expect(getYConfigColorForLayer(expression, 1)).toEqual([defaultReferenceLineColor]); }); }); diff --git a/x-pack/plugins/lens/public/xy_visualization/to_expression.ts b/x-pack/plugins/lens/public/xy_visualization/to_expression.ts index 96ea9b84dd983..1cd0bab48cd68 100644 --- a/x-pack/plugins/lens/public/xy_visualization/to_expression.ts +++ b/x-pack/plugins/lens/public/xy_visualization/to_expression.ts @@ -13,8 +13,8 @@ import { OperationMetadata, DatasourcePublicAPI } from '../types'; import { getColumnToLabelMap } from './state_helpers'; import type { ValidLayer, XYLayerConfig } from '../../common/expressions'; import { layerTypes } from '../../common'; -import { hasIcon } from './xy_config_panel/threshold_panel'; -import { defaultThresholdColor } from './color_assignment'; +import { hasIcon } from './xy_config_panel/reference_line_panel'; +import { defaultReferenceLineColor } from './color_assignment'; export const getSortedAccessors = (datasource: DatasourcePublicAPI, layer: XYLayerConfig) => { const originalOrder = datasource @@ -59,7 +59,7 @@ export function toPreviewExpression( layers: state.layers.map((layer) => layer.layerType === layerTypes.DATA ? { ...layer, hide: true } - : // cap the threshold line to 1px + : // cap the reference line to 1px { ...layer, hide: true, @@ -338,8 +338,8 @@ export const buildExpression = ( forAccessor: [yConfig.forAccessor], axisMode: yConfig.axisMode ? [yConfig.axisMode] : [], color: - layer.layerType === layerTypes.THRESHOLD - ? [yConfig.color || defaultThresholdColor] + layer.layerType === layerTypes.REFERENCELINE + ? [yConfig.color || defaultReferenceLineColor] : yConfig.color ? [yConfig.color] : [], diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts index 8052b0d593215..01fbbd892a118 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts @@ -319,7 +319,7 @@ describe('xy_visualization', () => { }); }); - it('should add a dimension to a threshold layer', () => { + it('should add a dimension to a reference layer', () => { expect( xyVisualization.setDimension({ frame, @@ -327,20 +327,20 @@ describe('xy_visualization', () => { ...exampleState(), layers: [ { - layerId: 'threshold', - layerType: layerTypes.THRESHOLD, + layerId: 'referenceLine', + layerType: layerTypes.REFERENCELINE, seriesType: 'line', accessors: [], }, ], }, - layerId: 'threshold', - groupId: 'xThreshold', + layerId: 'referenceLine', + groupId: 'xReferenceLine', columnId: 'newCol', }).layers[0] ).toEqual({ - layerId: 'threshold', - layerType: layerTypes.THRESHOLD, + layerId: 'referenceLine', + layerType: layerTypes.REFERENCELINE, seriesType: 'line', accessors: ['newCol'], yConfig: [ @@ -538,15 +538,15 @@ describe('xy_visualization', () => { expect(ops.filter(filterOperations).map((x) => x.dataType)).toEqual(['number']); }); - describe('thresholds', () => { + describe('reference lines', () => { beforeEach(() => { frame.datasourceLayers = { first: mockDatasource.publicAPIMock, - threshold: mockDatasource.publicAPIMock, + referenceLine: mockDatasource.publicAPIMock, }; }); - function getStateWithBaseThreshold(): State { + function getStateWithBaseReferenceLine(): State { return { ...exampleState(), layers: [ @@ -559,8 +559,8 @@ describe('xy_visualization', () => { accessors: ['a'], }, { - layerId: 'threshold', - layerType: layerTypes.THRESHOLD, + layerId: 'referenceLine', + layerType: layerTypes.REFERENCELINE, seriesType: 'line', accessors: [], yConfig: [{ axisMode: 'left', forAccessor: 'a' }], @@ -570,28 +570,28 @@ describe('xy_visualization', () => { } it('should support static value', () => { - const state = getStateWithBaseThreshold(); + const state = getStateWithBaseReferenceLine(); state.layers[0].accessors = []; state.layers[1].yConfig = undefined; expect( xyVisualization.getConfiguration({ - state: getStateWithBaseThreshold(), + state: getStateWithBaseReferenceLine(), frame, - layerId: 'threshold', + layerId: 'referenceLine', }).supportStaticValue ).toBeTruthy(); }); - it('should return no threshold groups for a empty data layer', () => { - const state = getStateWithBaseThreshold(); + it('should return no referenceLine groups for a empty data layer', () => { + const state = getStateWithBaseReferenceLine(); state.layers[0].accessors = []; state.layers[1].yConfig = undefined; const options = xyVisualization.getConfiguration({ state, frame, - layerId: 'threshold', + layerId: 'referenceLine', }).groups; expect(options).toHaveLength(0); @@ -599,37 +599,37 @@ describe('xy_visualization', () => { it('should return a group for the vertical left axis', () => { const options = xyVisualization.getConfiguration({ - state: getStateWithBaseThreshold(), + state: getStateWithBaseReferenceLine(), frame, - layerId: 'threshold', + layerId: 'referenceLine', }).groups; expect(options).toHaveLength(1); - expect(options[0].groupId).toBe('yThresholdLeft'); + expect(options[0].groupId).toBe('yReferenceLineLeft'); }); it('should return a group for the vertical right axis', () => { - const state = getStateWithBaseThreshold(); + const state = getStateWithBaseReferenceLine(); state.layers[0].yConfig = [{ axisMode: 'right', forAccessor: 'a' }]; state.layers[1].yConfig![0].axisMode = 'right'; const options = xyVisualization.getConfiguration({ state, frame, - layerId: 'threshold', + layerId: 'referenceLine', }).groups; expect(options).toHaveLength(1); - expect(options[0].groupId).toBe('yThresholdRight'); + expect(options[0].groupId).toBe('yReferenceLineRight'); }); - it('should compute no groups for thresholds when the only data accessor available is a date histogram', () => { - const state = getStateWithBaseThreshold(); + it('should compute no groups for referenceLines when the only data accessor available is a date histogram', () => { + const state = getStateWithBaseReferenceLine(); state.layers[0].xAccessor = 'b'; state.layers[0].accessors = []; state.layers[1].yConfig = []; // empty the configuration // set the xAccessor as date_histogram - frame.datasourceLayers.threshold.getOperationForColumnId = jest.fn((accessor) => { + frame.datasourceLayers.referenceLine.getOperationForColumnId = jest.fn((accessor) => { if (accessor === 'b') { return { dataType: 'date', @@ -644,19 +644,19 @@ describe('xy_visualization', () => { const options = xyVisualization.getConfiguration({ state, frame, - layerId: 'threshold', + layerId: 'referenceLine', }).groups; expect(options).toHaveLength(0); }); it('should mark horizontal group is invalid when xAccessor is changed to a date histogram', () => { - const state = getStateWithBaseThreshold(); + const state = getStateWithBaseReferenceLine(); state.layers[0].xAccessor = 'b'; state.layers[0].accessors = []; state.layers[1].yConfig![0].axisMode = 'bottom'; // set the xAccessor as date_histogram - frame.datasourceLayers.threshold.getOperationForColumnId = jest.fn((accessor) => { + frame.datasourceLayers.referenceLine.getOperationForColumnId = jest.fn((accessor) => { if (accessor === 'b') { return { dataType: 'date', @@ -671,19 +671,19 @@ describe('xy_visualization', () => { const options = xyVisualization.getConfiguration({ state, frame, - layerId: 'threshold', + layerId: 'referenceLine', }).groups; expect(options[0]).toEqual( expect.objectContaining({ invalid: true, - groupId: 'xThreshold', + groupId: 'xReferenceLine', }) ); }); it('should return groups in a specific order (left, right, bottom)', () => { - const state = getStateWithBaseThreshold(); + const state = getStateWithBaseReferenceLine(); state.layers[0].xAccessor = 'c'; state.layers[0].accessors = ['a', 'b']; // invert them on purpose @@ -697,7 +697,7 @@ describe('xy_visualization', () => { { forAccessor: 'a', axisMode: 'left' }, ]; // set the xAccessor as number histogram - frame.datasourceLayers.threshold.getOperationForColumnId = jest.fn((accessor) => { + frame.datasourceLayers.referenceLine.getOperationForColumnId = jest.fn((accessor) => { if (accessor === 'c') { return { dataType: 'number', @@ -712,21 +712,21 @@ describe('xy_visualization', () => { const [left, right, bottom] = xyVisualization.getConfiguration({ state, frame, - layerId: 'threshold', + layerId: 'referenceLine', }).groups; - expect(left.groupId).toBe('yThresholdLeft'); - expect(right.groupId).toBe('yThresholdRight'); - expect(bottom.groupId).toBe('xThreshold'); + expect(left.groupId).toBe('yReferenceLineLeft'); + expect(right.groupId).toBe('yReferenceLineRight'); + expect(bottom.groupId).toBe('xReferenceLine'); }); it('should ignore terms operation for xAccessor', () => { - const state = getStateWithBaseThreshold(); + const state = getStateWithBaseReferenceLine(); state.layers[0].xAccessor = 'b'; state.layers[0].accessors = []; state.layers[1].yConfig = []; // empty the configuration // set the xAccessor as top values - frame.datasourceLayers.threshold.getOperationForColumnId = jest.fn((accessor) => { + frame.datasourceLayers.referenceLine.getOperationForColumnId = jest.fn((accessor) => { if (accessor === 'b') { return { dataType: 'string', @@ -741,19 +741,19 @@ describe('xy_visualization', () => { const options = xyVisualization.getConfiguration({ state, frame, - layerId: 'threshold', + layerId: 'referenceLine', }).groups; expect(options).toHaveLength(0); }); it('should mark horizontal group is invalid when accessor is changed to a terms operation', () => { - const state = getStateWithBaseThreshold(); + const state = getStateWithBaseReferenceLine(); state.layers[0].xAccessor = 'b'; state.layers[0].accessors = []; state.layers[1].yConfig![0].axisMode = 'bottom'; // set the xAccessor as date_histogram - frame.datasourceLayers.threshold.getOperationForColumnId = jest.fn((accessor) => { + frame.datasourceLayers.referenceLine.getOperationForColumnId = jest.fn((accessor) => { if (accessor === 'b') { return { dataType: 'string', @@ -768,13 +768,13 @@ describe('xy_visualization', () => { const options = xyVisualization.getConfiguration({ state, frame, - layerId: 'threshold', + layerId: 'referenceLine', }).groups; expect(options[0]).toEqual( expect.objectContaining({ invalid: true, - groupId: 'xThreshold', + groupId: 'xReferenceLine', }) ); }); @@ -813,20 +813,20 @@ describe('xy_visualization', () => { }, }; - const state = getStateWithBaseThreshold(); + const state = getStateWithBaseReferenceLine(); state.layers[0].accessors = ['yAccessorId', 'yAccessorId2']; state.layers[1].yConfig = []; // empty the configuration const options = xyVisualization.getConfiguration({ state, frame: { ...frame, activeData: tables }, - layerId: 'threshold', + layerId: 'referenceLine', }).groups; expect(options).toEqual( expect.arrayContaining([ - expect.objectContaining({ groupId: 'yThresholdLeft' }), - expect.objectContaining({ groupId: 'yThresholdRight' }), + expect.objectContaining({ groupId: 'yReferenceLineLeft' }), + expect.objectContaining({ groupId: 'yReferenceLineRight' }), ]) ); }); diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx index 4e279d2e0026d..db1a2aeffb670 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx @@ -27,14 +27,14 @@ import { LensIconChartMixedXy } from '../assets/chart_mixed_xy'; import { LensIconChartBarHorizontal } from '../assets/chart_bar_horizontal'; import { getAccessorColorConfig, getColorAssignments } from './color_assignment'; import { getColumnToLabelMap } from './state_helpers'; -import { LensIconChartBarThreshold } from '../assets/chart_bar_threshold'; +import { LensIconChartBarReferenceLine } from '../assets/chart_bar_reference_line'; import { generateId } from '../id_generator'; import { getGroupsAvailableInData, getGroupsRelatedToData, getGroupsToShow, getStaticValue, -} from './threshold_helpers'; +} from './reference_line_helpers'; import { checkScaleOperation, checkXAccessorCompatibility, @@ -194,17 +194,17 @@ export const getXyVisualization = ({ }, getSupportedLayers(state, frame) { - const thresholdGroupIds = [ + const referenceLineGroupIds = [ { - id: 'yThresholdLeft', + id: 'yReferenceLineLeft', label: 'yLeft' as const, }, { - id: 'yThresholdRight', + id: 'yReferenceLineRight', label: 'yRight' as const, }, { - id: 'xThreshold', + id: 'xReferenceLine', label: 'x' as const, }, ]; @@ -220,8 +220,8 @@ export const getXyVisualization = ({ 'number', frame?.datasourceLayers || {} ); - const thresholdGroups = getGroupsRelatedToData( - thresholdGroupIds, + const referenceLineGroups = getGroupsRelatedToData( + referenceLineGroupIds, state, frame?.datasourceLayers || {}, frame?.activeData @@ -236,22 +236,22 @@ export const getXyVisualization = ({ icon: LensIconChartMixedXy, }, { - type: layerTypes.THRESHOLD, - label: i18n.translate('xpack.lens.xyChart.addThresholdLayerLabel', { - defaultMessage: 'Add threshold layer', + type: layerTypes.REFERENCELINE, + label: i18n.translate('xpack.lens.xyChart.addReferenceLineLayerLabel', { + defaultMessage: 'Add reference layer', }), - icon: LensIconChartBarThreshold, + icon: LensIconChartBarReferenceLine, disabled: !filledDataLayers.length || (!dataLayers.some(layerHasNumberHistogram) && dataLayers.every(({ accessors }) => !accessors.length)), tooltipContent: filledDataLayers.length ? undefined - : i18n.translate('xpack.lens.xyChart.addThresholdLayerLabelDisabledHelp', { - defaultMessage: 'Add some data to enable threshold layer', + : i18n.translate('xpack.lens.xyChart.addReferenceLineLayerLabelDisabledHelp', { + defaultMessage: 'Add some data to enable reference layer', }), initialDimensions: state - ? thresholdGroups.map(({ id, label }) => ({ + ? referenceLineGroups.map(({ id, label }) => ({ groupId: id, columnId: generateId(), dataType: 'number', @@ -318,25 +318,25 @@ export const getXyVisualization = ({ ); const groupsToShow = getGroupsToShow( [ - // When a threshold layer panel is added, a static threshold should automatically be included by default + // When a reference layer panel is added, a static reference line should automatically be included by default // in the first available axis, in the following order: vertical left, vertical right, horizontal. { config: left, - id: 'yThresholdLeft', + id: 'yReferenceLineLeft', label: 'yLeft', - dataTestSubj: 'lnsXY_yThresholdLeftPanel', + dataTestSubj: 'lnsXY_yReferenceLineLeftPanel', }, { config: right, - id: 'yThresholdRight', + id: 'yReferenceLineRight', label: 'yRight', - dataTestSubj: 'lnsXY_yThresholdRightPanel', + dataTestSubj: 'lnsXY_yReferenceLineRightPanel', }, { config: bottom, - id: 'xThreshold', + id: 'xReferenceLine', label: 'x', - dataTestSubj: 'lnsXY_xThresholdPanel', + dataTestSubj: 'lnsXY_xReferenceLinePanel', }, ], state, @@ -346,9 +346,9 @@ export const getXyVisualization = ({ return { supportFieldFormat: false, supportStaticValue: true, - // Each thresholds layer panel will have sections for each available axis + // Each reference lines layer panel will have sections for each available axis // (horizontal axis, vertical axis left, vertical axis right). - // Only axes that support numeric thresholds should be shown + // Only axes that support numeric reference lines should be shown groups: groupsToShow.map(({ config = [], id, label, dataTestSubj, valid }) => ({ groupId: id, groupLabel: getAxisName(label, { isHorizontal }), @@ -363,10 +363,16 @@ export const getXyVisualization = ({ enableDimensionEditor: true, dataTestSubj, invalid: !valid, - invalidMessage: i18n.translate('xpack.lens.configure.invalidThresholdDimension', { - defaultMessage: - 'This threshold is assigned to an axis that no longer exists. You may move this threshold to another available axis or remove it.', - }), + invalidMessage: + label === 'x' + ? i18n.translate('xpack.lens.configure.invalidBottomReferenceLineDimension', { + defaultMessage: + 'This reference line is assigned to an axis that no longer exists or is no longer valid. You may move this reference line to another available axis or remove it.', + }) + : i18n.translate('xpack.lens.configure.invalidReferenceLineDimension', { + defaultMessage: + 'This reference line is assigned to an axis that no longer exists. You may move this reference line to another available axis or remove it.', + }), requiresPreviousColumnOnDuplicate: true, })), }; @@ -439,7 +445,7 @@ export const getXyVisualization = ({ newLayer.splitAccessor = columnId; } - if (newLayer.layerType === layerTypes.THRESHOLD) { + if (newLayer.layerType === layerTypes.REFERENCELINE) { newLayer.accessors = [...newLayer.accessors.filter((a) => a !== columnId), columnId]; const hasYConfig = newLayer.yConfig?.some(({ forAccessor }) => forAccessor === columnId); const previousYConfig = previousColumn @@ -454,9 +460,9 @@ export const getXyVisualization = ({ // but keep the new group & id config forAccessor: columnId, axisMode: - groupId === 'xThreshold' + groupId === 'xReferenceLine' ? 'bottom' - : groupId === 'yThresholdRight' + : groupId === 'yReferenceLineRight' ? 'right' : 'left', }, @@ -491,9 +497,9 @@ export const getXyVisualization = ({ } let newLayers = prevState.layers.map((l) => (l.layerId === layerId ? newLayer : l)); - // // check if there's any threshold layer and pull it off if all data layers have no dimensions set + // check if there's any reference layer and pull it off if all data layers have no dimensions set const layersByType = groupBy(newLayers, ({ layerType }) => layerType); - // // check for data layers if they all still have xAccessors + // check for data layers if they all still have xAccessors const groupsAvailable = getGroupsAvailableInData( layersByType[layerTypes.DATA], frame.datasourceLayers, diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/color_picker.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/color_picker.tsx index 516adbf585b9f..e3e53126015eb 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/color_picker.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/color_picker.tsx @@ -16,7 +16,7 @@ import { State } from '../types'; import { FormatFactory, layerTypes } from '../../../common'; import { getSeriesColor } from '../state_helpers'; import { - defaultThresholdColor, + defaultReferenceLineColor, getAccessorColorConfig, getColorAssignments, } from '../color_assignment'; @@ -60,8 +60,8 @@ export const ColorPicker = ({ const overwriteColor = getSeriesColor(layer, accessor); const currentColor = useMemo(() => { if (overwriteColor || !frame.activeData) return overwriteColor; - if (layer.layerType === layerTypes.THRESHOLD) { - return defaultThresholdColor; + if (layer.layerType === layerTypes.REFERENCELINE) { + return defaultReferenceLineColor; } const datasource = frame.datasourceLayers[layer.layerId]; diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/index.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/index.tsx index 41d00e2eef32a..e18ea18c30fb0 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/index.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/index.tsx @@ -24,7 +24,7 @@ import type { FramePublicAPI, } from '../../types'; import { State, visualizationTypes, XYState } from '../types'; -import type { FormatFactory } from '../../../common'; +import { FormatFactory, layerTypes } from '../../../common'; import { SeriesType, YAxisMode, @@ -39,7 +39,7 @@ import { getAxesConfiguration, GroupsConfiguration } from '../axes_configuration import { VisualOptionsPopover } from './visual_options_popover'; import { getScaleType } from '../to_expression'; import { ColorPicker } from './color_picker'; -import { ThresholdPanel } from './threshold_panel'; +import { ReferenceLinePanel } from './reference_line_panel'; import { PalettePicker, TooltipWrapper } from '../../shared_components'; type UnwrapArray = T extends Array ? P : T; @@ -564,8 +564,8 @@ export function DimensionEditor( ); } - if (layer.layerType === 'threshold') { - return ; + if (layer.layerType === layerTypes.REFERENCELINE) { + return ; } return ( diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/layer_header.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/layer_header.tsx index dde4de0dd4bc3..d81979f603943 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/layer_header.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/layer_header.tsx @@ -17,7 +17,7 @@ import { isHorizontalChart, isHorizontalSeries } from '../state_helpers'; import { trackUiEvent } from '../../lens_ui_telemetry'; import { StaticHeader } from '../../shared_components'; import { ToolbarButton } from '../../../../../../src/plugins/kibana_react/public'; -import { LensIconChartBarThreshold } from '../../assets/chart_bar_threshold'; +import { LensIconChartBarReferenceLine } from '../../assets/chart_bar_reference_line'; import { updateLayer } from '.'; export function LayerHeader(props: VisualizationLayerWidgetProps) { @@ -29,13 +29,13 @@ export function LayerHeader(props: VisualizationLayerWidgetProps) { if (!layer) { return null; } - // if it's a threshold just draw a static text - if (layer.layerType === layerTypes.THRESHOLD) { + // if it's a reference line just draw a static text + if (layer.layerType === layerTypes.REFERENCELINE) { return ( ); diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/threshold_panel.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/reference_line_panel.tsx similarity index 71% rename from x-pack/plugins/lens/public/xy_visualization/xy_config_panel/threshold_panel.tsx rename to x-pack/plugins/lens/public/xy_visualization/xy_config_panel/reference_line_panel.tsx index 7c31d72e6cbde..7b9fd01e540fe 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/threshold_panel.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_config_panel/reference_line_panel.tsx @@ -30,53 +30,55 @@ import { TooltipWrapper, useDebouncedValue } from '../../shared_components'; const icons = [ { value: 'none', - label: i18n.translate('xpack.lens.xyChart.thresholds.noIconLabel', { defaultMessage: 'None' }), + label: i18n.translate('xpack.lens.xyChart.referenceLine.noIconLabel', { + defaultMessage: 'None', + }), }, { value: 'asterisk', - label: i18n.translate('xpack.lens.xyChart.thresholds.asteriskIconLabel', { + label: i18n.translate('xpack.lens.xyChart.referenceLine.asteriskIconLabel', { defaultMessage: 'Asterisk', }), }, { value: 'bell', - label: i18n.translate('xpack.lens.xyChart.thresholds.bellIconLabel', { + label: i18n.translate('xpack.lens.xyChart.referenceLine.bellIconLabel', { defaultMessage: 'Bell', }), }, { value: 'bolt', - label: i18n.translate('xpack.lens.xyChart.thresholds.boltIconLabel', { + label: i18n.translate('xpack.lens.xyChart.referenceLine.boltIconLabel', { defaultMessage: 'Bolt', }), }, { value: 'bug', - label: i18n.translate('xpack.lens.xyChart.thresholds.bugIconLabel', { + label: i18n.translate('xpack.lens.xyChart.referenceLine.bugIconLabel', { defaultMessage: 'Bug', }), }, { value: 'editorComment', - label: i18n.translate('xpack.lens.xyChart.thresholds.commentIconLabel', { + label: i18n.translate('xpack.lens.xyChart.referenceLine.commentIconLabel', { defaultMessage: 'Comment', }), }, { value: 'alert', - label: i18n.translate('xpack.lens.xyChart.thresholds.alertIconLabel', { + label: i18n.translate('xpack.lens.xyChart.referenceLine.alertIconLabel', { defaultMessage: 'Alert', }), }, { value: 'flag', - label: i18n.translate('xpack.lens.xyChart.thresholds.flagIconLabel', { + label: i18n.translate('xpack.lens.xyChart.referenceLine.flagIconLabel', { defaultMessage: 'Flag', }), }, { value: 'tag', - label: i18n.translate('xpack.lens.xyChart.thresholds.tagIconLabel', { + label: i18n.translate('xpack.lens.xyChart.referenceLine.tagIconLabel', { defaultMessage: 'Tag', }), }, @@ -116,20 +118,57 @@ const IconSelect = ({ ); }; -function getIconPositionOptions({ - isHorizontal, - axisMode, -}: { +interface LabelConfigurationOptions { isHorizontal: boolean; axisMode: YConfig['axisMode']; -}) { +} + +function getFillPositionOptions({ isHorizontal, axisMode }: LabelConfigurationOptions) { + const aboveLabel = i18n.translate('xpack.lens.xyChart.referenceLineFill.above', { + defaultMessage: 'Above', + }); + const belowLabel = i18n.translate('xpack.lens.xyChart.referenceLineFill.below', { + defaultMessage: 'Below', + }); + const beforeLabel = i18n.translate('xpack.lens.xyChart.referenceLineFill.before', { + defaultMessage: 'Before', + }); + const afterLabel = i18n.translate('xpack.lens.xyChart.referenceLineFill.after', { + defaultMessage: 'After', + }); + + const aboveOptionLabel = axisMode !== 'bottom' && !isHorizontal ? aboveLabel : afterLabel; + const belowOptionLabel = axisMode !== 'bottom' && !isHorizontal ? belowLabel : beforeLabel; + + return [ + { + id: `${idPrefix}none`, + label: i18n.translate('xpack.lens.xyChart.referenceLineFill.none', { + defaultMessage: 'None', + }), + 'data-test-subj': 'lnsXY_referenceLine_fill_none', + }, + { + id: `${idPrefix}above`, + label: aboveOptionLabel, + 'data-test-subj': 'lnsXY_referenceLine_fill_above', + }, + { + id: `${idPrefix}below`, + label: belowOptionLabel, + 'data-test-subj': 'lnsXY_referenceLine_fill_below', + }, + ]; +} + +function getIconPositionOptions({ isHorizontal, axisMode }: LabelConfigurationOptions) { const options = [ { id: `${idPrefix}auto`, - label: i18n.translate('xpack.lens.xyChart.thresholdMarker.auto', { + label: i18n.translate('xpack.lens.xyChart.referenceLineMarker.auto', { defaultMessage: 'Auto', }), - 'data-test-subj': 'lnsXY_markerPosition_auto', + 'data-test-subj': 'lnsXY_referenceLine_markerPosition_auto', }, ]; const topLabel = i18n.translate('xpack.lens.xyChart.markerPosition.above', { @@ -149,12 +188,12 @@ function getIconPositionOptions({ { id: `${idPrefix}above`, label: isHorizontal ? rightLabel : topLabel, - 'data-test-subj': 'lnsXY_markerPosition_above', + 'data-test-subj': 'lnsXY_referenceLine_markerPosition_above', }, { id: `${idPrefix}below`, label: isHorizontal ? leftLabel : bottomLabel, - 'data-test-subj': 'lnsXY_markerPosition_below', + 'data-test-subj': 'lnsXY_referenceLine_markerPosition_below', }, ]; if (isHorizontal) { @@ -168,12 +207,12 @@ function getIconPositionOptions({ { id: `${idPrefix}left`, label: isHorizontal ? bottomLabel : leftLabel, - 'data-test-subj': 'lnsXY_markerPosition_left', + 'data-test-subj': 'lnsXY_referenceLine_markerPosition_left', }, { id: `${idPrefix}right`, label: isHorizontal ? topLabel : rightLabel, - 'data-test-subj': 'lnsXY_markerPosition_right', + 'data-test-subj': 'lnsXY_referenceLine_markerPosition_right', }, ]; if (isHorizontal) { @@ -188,7 +227,7 @@ export function hasIcon(icon: string | undefined): icon is string { return icon != null && icon !== 'none'; } -export const ThresholdPanel = ( +export const ReferenceLinePanel = ( props: VisualizationDimensionEditorProps & { formatFactory: FormatFactory; paletteService: PaletteRegistry; @@ -232,18 +271,18 @@ export const ThresholdPanel = ( return ( <> { setYConfig({ forAccessor: accessor, textVisibility: !currentYConfig?.textVisibility }); @@ -253,7 +292,7 @@ export const ThresholdPanel = ( @@ -268,15 +307,18 @@ export const ThresholdPanel = ( display="columnCompressed" fullWidth isDisabled={!hasIcon(currentYConfig?.icon) && !currentYConfig?.textVisibility} - label={i18n.translate('xpack.lens.xyChart.thresholdMarker.position', { + label={i18n.translate('xpack.lens.xyChart.referenceLineMarker.position', { defaultMessage: 'Decoration position', })} > @@ -372,41 +414,19 @@ export const ThresholdPanel = ( { const newMode = id.replace(idPrefix, '') as FillStyle; @@ -440,7 +460,7 @@ const LineThicknessSlider = ({ return ( lns-dimensionTrigger', + dimension: 'lnsXY_yReferenceLineLeftPanel > lns-dimensionTrigger', operation: 'formula', formula: `count()`, keepOpen: true, @@ -263,9 +263,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.lens.closeDimensionEditor(); await PageObjects.common.sleep(1000); - expect(await PageObjects.lens.getDimensionTriggerText('lnsXY_yThresholdLeftPanel', 0)).to.eql( - 'count()' - ); + expect( + await PageObjects.lens.getDimensionTriggerText('lnsXY_yReferenceLineLeftPanel', 0) + ).to.eql('count()'); }); it('should allow numeric only formulas', async () => { diff --git a/x-pack/test/functional/apps/lens/index.ts b/x-pack/test/functional/apps/lens/index.ts index 50dbe05df166c..db0f41cc9e270 100644 --- a/x-pack/test/functional/apps/lens/index.ts +++ b/x-pack/test/functional/apps/lens/index.ts @@ -47,7 +47,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./lens_tagging')); loadTestFile(require.resolve('./formula')); loadTestFile(require.resolve('./heatmap')); - loadTestFile(require.resolve('./thresholds')); + loadTestFile(require.resolve('./reference_lines')); loadTestFile(require.resolve('./inspector')); // has to be last one in the suite because it overrides saved objects diff --git a/x-pack/test/functional/apps/lens/thresholds.ts b/x-pack/test/functional/apps/lens/reference_lines.ts similarity index 57% rename from x-pack/test/functional/apps/lens/thresholds.ts rename to x-pack/test/functional/apps/lens/reference_lines.ts index 10e330114442b..8ea66cb29f5a8 100644 --- a/x-pack/test/functional/apps/lens/thresholds.ts +++ b/x-pack/test/functional/apps/lens/reference_lines.ts @@ -14,21 +14,21 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); const testSubjects = getService('testSubjects'); - describe('lens thresholds tests', () => { - it('should show a disabled threshold layer button if no data dimension is defined', async () => { + describe('lens reference lines tests', () => { + it('should show a disabled reference layer button if no data dimension is defined', async () => { await PageObjects.visualize.navigateToNewVisualization(); await PageObjects.visualize.clickVisType('lens'); await testSubjects.click('lnsLayerAddButton'); await retry.waitFor('wait for layer popup to appear', async () => - testSubjects.exists(`lnsLayerAddButton-threshold`) + testSubjects.exists(`lnsLayerAddButton-referenceLine`) ); expect( - await (await testSubjects.find(`lnsLayerAddButton-threshold`)).getAttribute('disabled') + await (await testSubjects.find(`lnsLayerAddButton-referenceLine`)).getAttribute('disabled') ).to.be('true'); }); - it('should add a threshold layer with a static value in it', async () => { + it('should add a reference layer with a static value in it', async () => { await PageObjects.lens.goToTimeRange(); await PageObjects.lens.configureDimension({ @@ -43,29 +43,28 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { field: 'bytes', }); - await PageObjects.lens.createLayer('threshold'); + await PageObjects.lens.createLayer('referenceLine'); expect((await find.allByCssSelector(`[data-test-subj^="lns-layerPanel-"]`)).length).to.eql(2); expect( await ( - await testSubjects.find('lnsXY_yThresholdLeftPanel > lns-dimensionTrigger') + await testSubjects.find('lnsXY_yReferenceLineLeftPanel > lns-dimensionTrigger') ).getVisibleText() ).to.eql('Static value: 4992.44'); }); - it('should create a dynamic threshold when dragging a field to a threshold dimension group', async () => { + it('should create a dynamic referenceLine when dragging a field to a referenceLine dimension group', async () => { await PageObjects.lens.dragFieldToDimensionTrigger( 'bytes', - 'lnsXY_yThresholdLeftPanel > lns-empty-dimension' + 'lnsXY_yReferenceLineLeftPanel > lns-empty-dimension' ); - expect(await PageObjects.lens.getDimensionTriggersTexts('lnsXY_yThresholdLeftPanel')).to.eql([ - 'Static value: 4992.44', - 'Median of bytes', - ]); + expect( + await PageObjects.lens.getDimensionTriggersTexts('lnsXY_yReferenceLineLeftPanel') + ).to.eql(['Static value: 4992.44', 'Median of bytes']); }); - it('should add a new group to the threshold layer when a right axis is enabled', async () => { + it('should add a new group to the reference layer when a right axis is enabled', async () => { await PageObjects.lens.configureDimension({ dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', operation: 'average', @@ -77,42 +76,46 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.lens.closeDimensionEditor(); - await testSubjects.existOrFail('lnsXY_yThresholdRightPanel > lns-empty-dimension'); + await testSubjects.existOrFail('lnsXY_yReferenceLineRightPanel > lns-empty-dimension'); }); - it('should carry the style when moving a threshold to another group', async () => { + it('should carry the style when moving a reference line to another group', async () => { // style it enabling the fill - await testSubjects.click('lnsXY_yThresholdLeftPanel > lns-dimensionTrigger'); - await testSubjects.click('lnsXY_fill_below'); + await testSubjects.click('lnsXY_yReferenceLineLeftPanel > lns-dimensionTrigger'); + await testSubjects.click('lnsXY_referenceLine_fill_below'); await PageObjects.lens.closeDimensionEditor(); // drag and drop it to the left axis await PageObjects.lens.dragDimensionToDimension( - 'lnsXY_yThresholdLeftPanel > lns-dimensionTrigger', - 'lnsXY_yThresholdRightPanel > lns-empty-dimension' + 'lnsXY_yReferenceLineLeftPanel > lns-dimensionTrigger', + 'lnsXY_yReferenceLineRightPanel > lns-empty-dimension' ); - await testSubjects.click('lnsXY_yThresholdRightPanel > lns-dimensionTrigger'); + await testSubjects.click('lnsXY_yReferenceLineRightPanel > lns-dimensionTrigger'); expect( - await find.existsByCssSelector('[data-test-subj="lnsXY_fill_below"][class$="isSelected"]') + await find.existsByCssSelector( + '[data-test-subj="lnsXY_referenceLine_fill_below"][class$="isSelected"]' + ) ).to.be(true); await PageObjects.lens.closeDimensionEditor(); }); - it('should duplicate also the original style when duplicating a threshold', async () => { + it('should duplicate also the original style when duplicating a reference line', async () => { // drag and drop to the empty field to generate a duplicate await PageObjects.lens.dragDimensionToDimension( - 'lnsXY_yThresholdRightPanel > lns-dimensionTrigger', - 'lnsXY_yThresholdRightPanel > lns-empty-dimension' + 'lnsXY_yReferenceLineRightPanel > lns-dimensionTrigger', + 'lnsXY_yReferenceLineRightPanel > lns-empty-dimension' ); await ( await find.byCssSelector( - '[data-test-subj="lnsXY_yThresholdRightPanel"]:nth-child(2) [data-test-subj="lns-dimensionTrigger"]' + '[data-test-subj="lnsXY_yReferenceLineRightPanel"]:nth-child(2) [data-test-subj="lns-dimensionTrigger"]' ) ).click(); expect( - await find.existsByCssSelector('[data-test-subj="lnsXY_fill_below"][class$="isSelected"]') + await find.existsByCssSelector( + '[data-test-subj="lnsXY_referenceLine_fill_below"][class$="isSelected"]' + ) ).to.be(true); await PageObjects.lens.closeDimensionEditor(); });