"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.isNumericMetric = exports.isNumericDynamicMetric = exports.getGaugeVisualization = exports.CHART_NAMES = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _react = _interopRequireDefault(require("react")); var _i18n = require("@kbn/i18n"); var _i18nReact = require("@kbn/i18n-react"); var _common = require("@kbn/expressions-plugin/common"); var _coloring = require("@kbn/coloring"); var _common2 = require("@kbn/expression-gauge-plugin/common"); var _public = require("@kbn/expression-gauge-plugin/public"); var _chartIcons = require("@kbn/chart-icons"); var _public2 = require("@kbn/expression-xy-plugin/public"); var _suggestions = require("./suggestions"); var _constants = require("./constants"); var _toolbar_component = require("./toolbar_component"); var _shared_components = require("../../shared_components"); var _dimension_editor = require("./dimension_editor"); var _id_generator = require("../../id_generator"); var _utils = require("./utils"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ const groupLabelForGauge = _i18n.i18n.translate('xpack.lens.metric.groupLabel', { defaultMessage: 'Goal and single value' }); const isNumericMetric = op => !op.isBucketed && op.dataType === 'number'; exports.isNumericMetric = isNumericMetric; const isNumericDynamicMetric = op => isNumericMetric(op) && !op.isStaticValue; exports.isNumericDynamicMetric = isNumericDynamicMetric; const CHART_NAMES = { horizontalBullet: { icon: _chartIcons.IconChartHorizontalBullet, label: _i18n.i18n.translate('xpack.lens.gaugeHorizontal.gaugeLabel', { defaultMessage: 'Gauge horizontal' }), groupLabel: groupLabelForGauge }, verticalBullet: { icon: _chartIcons.IconChartVerticalBullet, label: _i18n.i18n.translate('xpack.lens.gaugeVertical.gaugeLabel', { defaultMessage: 'Gauge vertical' }), groupLabel: groupLabelForGauge } }; exports.CHART_NAMES = CHART_NAMES; function computePaletteParams(params) { return { ...params, // rewrite colors and stops as two distinct arguments colors: ((params === null || params === void 0 ? void 0 : params.stops) || []).map(({ color }) => color), stops: (params === null || params === void 0 ? void 0 : params.name) === 'custom' ? ((params === null || params === void 0 ? void 0 : params.stops) || []).map(({ stop }) => stop) : [], reverse: false // managed at UI level }; } const getErrorMessages = (row, state) => { if (!row || !state) { return []; } const errors = []; const minAccessor = state === null || state === void 0 ? void 0 : state.minAccessor; const maxAccessor = state === null || state === void 0 ? void 0 : state.maxAccessor; const minValue = minAccessor ? (0, _public.getValueFromAccessor)(minAccessor, row) : undefined; const maxValue = maxAccessor ? (0, _public.getValueFromAccessor)(maxAccessor, row) : undefined; if (maxValue !== null && maxValue !== undefined && minValue != null && minValue !== undefined) { if (maxValue < minValue) { errors.push({ severity: 'error', displayLocations: [{ id: 'dimensionButton', dimensionId: minAccessor }, { id: 'dimensionButton', dimensionId: maxAccessor }], fixableInEditor: true, shortMessage: _i18n.i18n.translate('xpack.lens.guageVisualization.chartCannotRenderMinGreaterMax', { defaultMessage: 'Minimum value may not be greater than maximum value' }), longMessage: '' }); } if (maxValue === minValue) { errors.push({ severity: 'error', displayLocations: [{ id: 'dimensionButton', dimensionId: minAccessor }, { id: 'dimensionButton', dimensionId: maxAccessor }], fixableInEditor: true, shortMessage: _i18n.i18n.translate('xpack.lens.guageVisualization.chartCannotRenderEqual', { defaultMessage: 'Minimum and maximum values may not be equal' }), longMessage: '' }); } } return errors; }; const toExpression = (paletteService, state, datasourceLayers, attributes, datasourceExpressionsByLayers = {}) => { var _state$shape, _state$colorMode, _state$palette, _state$ticksPosition, _state$labelMajorMode, _datasourceExpression; const datasource = datasourceLayers[state.layerId]; const datasourceExpression = datasourceExpressionsByLayers[state.layerId]; const originalOrder = datasource === null || datasource === void 0 ? void 0 : datasource.getTableSpec().map(({ columnId }) => columnId); if (!originalOrder || !state.metricAccessor) { return null; } const gaugeFn = (0, _common.buildExpressionFunction)('gauge', { metric: state.metricAccessor, min: state.minAccessor, max: state.maxAccessor, goal: state.goalAccessor, shape: (_state$shape = state.shape) !== null && _state$shape !== void 0 ? _state$shape : _common2.GaugeShapes.HORIZONTAL_BULLET, colorMode: (_state$colorMode = state === null || state === void 0 ? void 0 : state.colorMode) !== null && _state$colorMode !== void 0 ? _state$colorMode : 'none', palette: (_state$palette = state.palette) !== null && _state$palette !== void 0 && _state$palette.params ? paletteService.get(_coloring.CUSTOM_PALETTE).toExpression(computePaletteParams(state.palette.params)) : undefined, ticksPosition: (_state$ticksPosition = state.ticksPosition) !== null && _state$ticksPosition !== void 0 ? _state$ticksPosition : 'auto', labelMinor: state.labelMinor, labelMajor: state.labelMajor, labelMajorMode: (_state$labelMajorMode = state.labelMajorMode) !== null && _state$labelMajorMode !== void 0 ? _state$labelMajorMode : 'auto' }); return { type: 'expression', chain: [...((_datasourceExpression = datasourceExpression === null || datasourceExpression === void 0 ? void 0 : datasourceExpression.chain) !== null && _datasourceExpression !== void 0 ? _datasourceExpression : []), gaugeFn.toAst()] }; }; const getGaugeVisualization = ({ paletteService, theme }) => ({ id: _constants.LENS_GAUGE_ID, visualizationTypes: [{ ...CHART_NAMES.horizontalBullet, id: _common2.GaugeShapes.HORIZONTAL_BULLET, showExperimentalBadge: true }, { ...CHART_NAMES.verticalBullet, id: _common2.GaugeShapes.VERTICAL_BULLET, showExperimentalBadge: true }], getVisualizationTypeId(state) { return state.shape; }, getLayerIds(state) { return [state.layerId]; }, clearLayer(state) { const newState = { ...state }; delete newState.metricAccessor; delete newState.minAccessor; delete newState.maxAccessor; delete newState.goalAccessor; delete newState.palette; delete newState.colorMode; return newState; }, getDescription(state) { if (state.shape === _common2.GaugeShapes.HORIZONTAL_BULLET) { return CHART_NAMES.horizontalBullet; } return CHART_NAMES.verticalBullet; }, switchVisualizationType: (visualizationTypeId, state) => { return { ...state, shape: visualizationTypeId === _common2.GaugeShapes.HORIZONTAL_BULLET ? _common2.GaugeShapes.HORIZONTAL_BULLET : _common2.GaugeShapes.VERTICAL_BULLET }; }, initialize(addNewLayer, state, mainPalette) { return state || { layerId: addNewLayer(), layerType: _public2.LayerTypes.DATA, shape: _common2.GaugeShapes.HORIZONTAL_BULLET, palette: mainPalette, ticksPosition: 'auto', labelMajorMode: 'auto' }; }, getSuggestions: _suggestions.getSuggestions, getConfiguration({ state, frame }) { var _frame$activeData, _frame$activeData$sta, _frame$activeData$sta2; const row = state !== null && state !== void 0 && state.layerId ? frame === null || frame === void 0 ? void 0 : (_frame$activeData = frame.activeData) === null || _frame$activeData === void 0 ? void 0 : (_frame$activeData$sta = _frame$activeData[state === null || state === void 0 ? void 0 : state.layerId]) === null || _frame$activeData$sta === void 0 ? void 0 : (_frame$activeData$sta2 = _frame$activeData$sta.rows) === null || _frame$activeData$sta2 === void 0 ? void 0 : _frame$activeData$sta2[0] : undefined; const { palette, metricAccessor, accessors } = getConfigurationAccessorsAndPalette(state, paletteService, frame.activeData); return { groups: [{ enableFormatSelector: true, layerId: state.layerId, groupId: _constants.GROUP_ID.METRIC, groupLabel: _i18n.i18n.translate('xpack.lens.gauge.metricLabel', { defaultMessage: 'Metric' }), paramEditorCustomProps: { headingLabel: _i18n.i18n.translate('xpack.lens.gauge.headingLabel', { defaultMessage: 'Value' }) }, isMetricDimension: true, accessors: metricAccessor ? [palette ? { columnId: metricAccessor, triggerIconType: 'colorBy', palette } : { columnId: metricAccessor, triggerIconType: 'none' }] : [], filterOperations: isNumericDynamicMetric, supportsMoreColumns: !metricAccessor, requiredMinDimensionCount: 1, dataTestSubj: 'lnsGauge_metricDimensionPanel', enableDimensionEditor: true }, { supportStaticValue: true, enableFormatSelector: false, layerId: state.layerId, groupId: _constants.GROUP_ID.MIN, groupLabel: _i18n.i18n.translate('xpack.lens.gauge.minValueLabel', { defaultMessage: 'Minimum value' }), paramEditorCustomProps: { labels: [_i18n.i18n.translate('xpack.lens.gauge.minValueLabel', { defaultMessage: 'Minimum value' })], headingLabel: _i18n.i18n.translate('xpack.lens.gauge.headingLabel', { defaultMessage: 'Value' }) }, isMetricDimension: true, accessors: state.minAccessor ? [{ columnId: state.minAccessor }] : [], filterOperations: isNumericMetric, supportsMoreColumns: !state.minAccessor, dataTestSubj: 'lnsGauge_minDimensionPanel', prioritizedOperation: 'min', suggestedValue: () => state.metricAccessor ? (0, _public.getMinValue)(row, accessors) : undefined }, { supportStaticValue: true, enableFormatSelector: false, layerId: state.layerId, groupId: _constants.GROUP_ID.MAX, groupLabel: _i18n.i18n.translate('xpack.lens.gauge.maxValueLabel', { defaultMessage: 'Maximum value' }), paramEditorCustomProps: { labels: [_i18n.i18n.translate('xpack.lens.gauge.maxValueLabel', { defaultMessage: 'Maximum value' })], headingLabel: _i18n.i18n.translate('xpack.lens.gauge.headingLabel', { defaultMessage: 'Value' }) }, isMetricDimension: true, accessors: state.maxAccessor ? [{ columnId: state.maxAccessor }] : [], filterOperations: isNumericMetric, supportsMoreColumns: !state.maxAccessor, dataTestSubj: 'lnsGauge_maxDimensionPanel', prioritizedOperation: 'max', suggestedValue: () => state.metricAccessor ? (0, _public.getMaxValue)(row, accessors) : undefined }, { supportStaticValue: true, enableFormatSelector: false, layerId: state.layerId, groupId: _constants.GROUP_ID.GOAL, groupLabel: _i18n.i18n.translate('xpack.lens.gauge.goalValueLabel', { defaultMessage: 'Goal value' }), paramEditorCustomProps: { labels: [_i18n.i18n.translate('xpack.lens.gauge.goalValueLabel', { defaultMessage: 'Goal value' })], headingLabel: _i18n.i18n.translate('xpack.lens.gauge.headingLabel', { defaultMessage: 'Value' }) }, isMetricDimension: true, accessors: state.goalAccessor ? [{ columnId: state.goalAccessor }] : [], filterOperations: isNumericMetric, supportsMoreColumns: !state.goalAccessor, requiredMinDimensionCount: 0, dataTestSubj: 'lnsGauge_goalDimensionPanel' }] }; }, setDimension({ prevState, layerId, columnId, groupId, previousColumn }) { const update = {}; if (groupId === _constants.GROUP_ID.MIN) { update.minAccessor = columnId; } if (groupId === _constants.GROUP_ID.MAX) { update.maxAccessor = columnId; } if (groupId === _constants.GROUP_ID.GOAL) { update.goalAccessor = columnId; } if (groupId === _constants.GROUP_ID.METRIC) { update.metricAccessor = columnId; } return { ...prevState, ...update }; }, removeDimension({ prevState, layerId, columnId }) { const update = { ...prevState }; if (prevState.goalAccessor === columnId) { delete update.goalAccessor; } if (prevState.minAccessor === columnId) { delete update.minAccessor; } if (prevState.maxAccessor === columnId) { delete update.maxAccessor; } if (prevState.metricAccessor === columnId) { delete update.metricAccessor; delete update.palette; delete update.colorMode; update.ticksPosition = 'auto'; } return update; }, DimensionEditorComponent(props) { return /*#__PURE__*/_react.default.createElement(_dimension_editor.GaugeDimensionEditor, (0, _extends2.default)({}, props, { paletteService: paletteService })); }, ToolbarComponent(props) { return /*#__PURE__*/_react.default.createElement(_toolbar_component.GaugeToolbar, props); }, getSupportedLayers(state, frame) { var _frame$activeData2, _frame$activeData2$st, _frame$activeData2$st2; const row = state !== null && state !== void 0 && state.layerId ? frame === null || frame === void 0 ? void 0 : (_frame$activeData2 = frame.activeData) === null || _frame$activeData2 === void 0 ? void 0 : (_frame$activeData2$st = _frame$activeData2[state === null || state === void 0 ? void 0 : state.layerId]) === null || _frame$activeData2$st === void 0 ? void 0 : (_frame$activeData2$st2 = _frame$activeData2$st.rows) === null || _frame$activeData2$st2 === void 0 ? void 0 : _frame$activeData2$st2[0] : undefined; const accessors = (0, _utils.getAccessorsFromState)(state); const minValue = (0, _public.getMinValue)(row, accessors); const maxValue = (0, _public.getMaxValue)(row, accessors); const goalValue = (0, _public.getGoalValue)(row, accessors); return [{ type: _public2.LayerTypes.DATA, label: _i18n.i18n.translate('xpack.lens.gauge.addLayer', { defaultMessage: 'Visualization' }), initialDimensions: state ? [{ groupId: 'min', columnId: (0, _id_generator.generateId)(), staticValue: minValue }, { groupId: 'max', columnId: (0, _id_generator.generateId)(), staticValue: maxValue }, { groupId: 'goal', columnId: (0, _id_generator.generateId)(), staticValue: goalValue }] : undefined }]; }, getLayerType(layerId, state) { if ((state === null || state === void 0 ? void 0 : state.layerId) === layerId) { return state.layerType; } }, toExpression: (state, datasourceLayers, attributes, datasourceExpressionsByLayers = {}) => toExpression(paletteService, state, datasourceLayers, { ...attributes }, datasourceExpressionsByLayers), toPreviewExpression: (state, datasourceLayers, datasourceExpressionsByLayers = {}) => toExpression(paletteService, state, datasourceLayers, undefined, datasourceExpressionsByLayers), getUserMessages(state, { frame }) { var _frame$activeData3, _frame$activeData3$st, _frame$activeData3$st2; const { maxAccessor, minAccessor, goalAccessor, metricAccessor } = state; if (!maxAccessor && !minAccessor && !goalAccessor && !metricAccessor) { // nothing configured yet return []; } if (!metricAccessor) { return []; } const row = (_frame$activeData3 = frame.activeData) === null || _frame$activeData3 === void 0 ? void 0 : (_frame$activeData3$st = _frame$activeData3[state.layerId]) === null || _frame$activeData3$st === void 0 ? void 0 : (_frame$activeData3$st2 = _frame$activeData3$st.rows) === null || _frame$activeData3$st2 === void 0 ? void 0 : _frame$activeData3$st2[0]; if (!row) { return []; } const errors = getErrorMessages(row, state); if (errors.length) { return errors; } const metricValue = row[metricAccessor]; const maxValue = maxAccessor && row[maxAccessor]; const minValue = minAccessor && row[minAccessor]; const goalValue = goalAccessor && row[goalAccessor]; const warnings = []; if (typeof minValue === 'number') { if (minValue > metricValue) { warnings.push({ severity: 'warning', fixableInEditor: true, displayLocations: [{ id: 'toolbar' }], shortMessage: '', longMessage: /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.lens.gaugeVisualization.minValueGreaterMetricShortMessage", defaultMessage: "Minimum value is greater than metric value." }) }); } if (minValue > goalValue) { warnings.push({ severity: 'warning', fixableInEditor: true, displayLocations: [{ id: 'toolbar' }], shortMessage: '', longMessage: /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.lens.gaugeVisualization.minimumValueGreaterGoalShortMessage", defaultMessage: "Minimum value is greater than goal value." }) }); } } if (typeof maxValue === 'number') { if (metricValue > maxValue) { warnings.push({ severity: 'warning', fixableInEditor: true, displayLocations: [{ id: 'toolbar' }], shortMessage: '', longMessage: /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.lens.gaugeVisualization.metricValueGreaterMaximumShortMessage", defaultMessage: "Metric value is greater than maximum value." }) }); } if (typeof goalValue === 'number' && goalValue > maxValue) { warnings.push({ severity: 'warning', fixableInEditor: true, displayLocations: [{ id: 'toolbar' }], shortMessage: '', longMessage: /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.lens.gaugeVisualization.goalValueGreaterMaximumShortMessage", defaultMessage: "Goal value is greater than maximum value." }) }); } } return warnings; }, getSuggestionFromConvertToLensContext({ suggestions, context }) { const allSuggestions = suggestions; const suggestion = { ...allSuggestions[0], datasourceState: { ...allSuggestions[0].datasourceState, layers: allSuggestions.reduce((acc, s) => { var _s$datasourceState; return { ...acc, ...((_s$datasourceState = s.datasourceState) === null || _s$datasourceState === void 0 ? void 0 : _s$datasourceState.layers) }; }, {}) }, visualizationState: { ...allSuggestions[0].visualizationState, ...context.configuration } }; return suggestion; }, getVisualizationInfo(state, frame) { const { palette, accessors } = getConfigurationAccessorsAndPalette(state, paletteService, frame === null || frame === void 0 ? void 0 : frame.activeData); const dimensions = []; if (accessors !== null && accessors !== void 0 && accessors.metric) { dimensions.push({ id: accessors.metric, name: _i18n.i18n.translate('xpack.lens.gauge.metricLabel', { defaultMessage: 'Metric' }), dimensionType: 'metric' }); } if (accessors !== null && accessors !== void 0 && accessors.max) { dimensions.push({ id: accessors.max, name: _i18n.i18n.translate('xpack.lens.gauge.maxValueLabel', { defaultMessage: 'Maximum value' }), dimensionType: 'max' }); } if (accessors !== null && accessors !== void 0 && accessors.min) { dimensions.push({ id: accessors.min, name: _i18n.i18n.translate('xpack.lens.gauge.minValueLabel', { defaultMessage: 'Minimum value' }), dimensionType: 'min' }); } if (accessors !== null && accessors !== void 0 && accessors.goal) { dimensions.push({ id: accessors.goal, name: _i18n.i18n.translate('xpack.lens.gauge.goalValueLabel', { defaultMessage: 'Goal value' }), dimensionType: 'goal' }); } return { layers: [{ layerId: state.layerId, layerType: state.layerType, chartType: state.shape, ...this.getDescription(state), dimensions, palette }] }; } }); // When the active data comes from the embeddable side it might not have been indexed by layerId // rather using a "default" key exports.getGaugeVisualization = getGaugeVisualization; function getActiveDataForLayer(layerId, activeData) { if (activeData && layerId) { return activeData[layerId] || activeData.default; } } function getConfigurationAccessorsAndPalette(state, paletteService, activeData) { var _state$palette2, _state$palette2$param, _getActiveDataForLaye, _getActiveDataForLaye2; const hasColoring = Boolean(state.colorMode !== 'none' && ((_state$palette2 = state.palette) === null || _state$palette2 === void 0 ? void 0 : (_state$palette2$param = _state$palette2.params) === null || _state$palette2$param === void 0 ? void 0 : _state$palette2$param.stops)); const row = (_getActiveDataForLaye = getActiveDataForLayer(state === null || state === void 0 ? void 0 : state.layerId, activeData)) === null || _getActiveDataForLaye === void 0 ? void 0 : (_getActiveDataForLaye2 = _getActiveDataForLaye.rows) === null || _getActiveDataForLaye2 === void 0 ? void 0 : _getActiveDataForLaye2[0]; const { metricAccessor } = state !== null && state !== void 0 ? state : {}; const accessors = (0, _utils.getAccessorsFromState)(state); let palette; if (row != null && metricAccessor != null && (state === null || state === void 0 ? void 0 : state.palette) != null && hasColoring) { const currentMinMax = { min: (0, _public.getMinValue)(row, accessors), max: (0, _public.getMaxValue)(row, accessors) }; const displayStops = (0, _shared_components.applyPaletteParams)(paletteService, state === null || state === void 0 ? void 0 : state.palette, currentMinMax); palette = displayStops.map(({ color }) => color); } return { metricAccessor, accessors, palette }; }