"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkScaleOperation = checkScaleOperation; exports.checkXAccessorCompatibility = checkXAccessorCompatibility; exports.getAnnotationsLayers = exports.defaultSeriesType = exports.defaultIcon = void 0; exports.getAxisName = getAxisName; exports.getDataLayers = void 0; exports.getDescription = getDescription; exports.getLayerTypeOptions = exports.getFirstDataLayer = void 0; exports.getLayersByType = getLayersByType; exports.getMessageIdsForDimension = getMessageIdsForDimension; exports.getReferenceLayers = void 0; exports.getVisualizationType = getVisualizationType; exports.isReferenceLayer = exports.isPersistedLinkedByValueAnnotationsLayer = exports.isPersistedByValueAnnotationsLayer = exports.isPersistedByReferenceAnnotationsLayer = exports.isPersistedAnnotationsLayer = exports.isNumericMetric = exports.isNumericDynamicMetric = exports.isDataLayer = exports.isByReferenceAnnotationsLayer = exports.isBucketed = exports.isAnnotationsLayer = void 0; exports.newLayerState = newLayerState; exports.supportedDataLayer = void 0; exports.validateLayersForDimension = validateLayersForDimension; var _i18n = require("@kbn/i18n"); var _lodash = require("lodash"); var _chartIcons = require("@kbn/chart-icons"); var _types = require("./types"); var _state_helpers = require("./state_helpers"); var _ = require("../.."); /* * 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. */ function getAxisName(axis, { isHorizontal }) { const vertical = _i18n.i18n.translate('xpack.lens.xyChart.verticalAxisLabel', { defaultMessage: 'Vertical axis' }); const horizontal = _i18n.i18n.translate('xpack.lens.xyChart.horizontalAxisLabel', { defaultMessage: 'Horizontal axis' }); if (axis === 'x') { return isHorizontal ? vertical : horizontal; } if (axis === 'y') { return isHorizontal ? horizontal : vertical; } const verticalLeft = _i18n.i18n.translate('xpack.lens.xyChart.verticalLeftAxisLabel', { defaultMessage: 'Vertical left axis' }); const verticalRight = _i18n.i18n.translate('xpack.lens.xyChart.verticalRightAxisLabel', { defaultMessage: 'Vertical right axis' }); const horizontalTop = _i18n.i18n.translate('xpack.lens.xyChart.horizontalLeftAxisLabel', { defaultMessage: 'Horizontal top axis' }); const horizontalBottom = _i18n.i18n.translate('xpack.lens.xyChart.horizontalRightAxisLabel', { defaultMessage: 'Horizontal bottom axis' }); if (axis === 'yLeft') { return isHorizontal ? horizontalBottom : verticalLeft; } return isHorizontal ? horizontalTop : verticalRight; } // min requirement for the bug: // * 2 or more layers // * at least one with date histogram // * at least one with interval function function checkXAccessorCompatibility(state, datasourceLayers) { const dataLayers = getDataLayers(state.layers); const errors = []; const hasDateHistogramSetIndex = dataLayers.findIndex(checkScaleOperation('interval', 'date', datasourceLayers)); const hasNumberHistogramIndex = dataLayers.findIndex(checkScaleOperation('interval', 'number', datasourceLayers)); const hasOrdinalAxisIndex = dataLayers.findIndex(checkScaleOperation('ordinal', undefined, datasourceLayers)); if (state.layers.length > 1) { const erroredLayers = [hasDateHistogramSetIndex, hasNumberHistogramIndex, hasOrdinalAxisIndex].filter(v => v >= 0).sort((a, b) => a - b); if (erroredLayers.length > 1) { const [firstLayer, ...otherLayers] = erroredLayers; const axis = getAxisName('x', { isHorizontal: (0, _state_helpers.isHorizontalChart)(state.layers) }); for (const otherLayer of otherLayers) { errors.push({ shortMessage: _i18n.i18n.translate('xpack.lens.xyVisualization.dataTypeFailureXShort', { defaultMessage: `Wrong data type for {axis}.`, values: { axis } }), longMessage: _i18n.i18n.translate('xpack.lens.xyVisualization.dataTypeFailureXLong', { defaultMessage: `The {axis} data in layer {firstLayer} is incompatible with the data in layer {secondLayer}. Select a new function for the {axis}.`, values: { axis, firstLayer: firstLayer + 1, secondLayer: otherLayer + 1 } }) }); } } } return errors; } function checkScaleOperation(scaleType, dataType, datasourceLayers) { return layer => { const datasourceAPI = datasourceLayers[layer.layerId]; if (!layer.xAccessor) { return false; } const operation = datasourceAPI === null || datasourceAPI === void 0 ? void 0 : datasourceAPI.getOperationForColumnId(layer.xAccessor); return Boolean(operation && (!dataType || operation.dataType === dataType) && operation.scale === scaleType); }; } const isDataLayer = layer => layer.layerType === _.layerTypes.DATA || !layer.layerType; exports.isDataLayer = isDataLayer; const getDataLayers = layers => (layers || []).filter(layer => isDataLayer(layer)); exports.getDataLayers = getDataLayers; const getFirstDataLayer = layers => (layers || []).find(layer => isDataLayer(layer)); exports.getFirstDataLayer = getFirstDataLayer; const isReferenceLayer = layer => layer.layerType === _.layerTypes.REFERENCELINE; exports.isReferenceLayer = isReferenceLayer; const getReferenceLayers = layers => (layers || []).filter(layer => isReferenceLayer(layer)); exports.getReferenceLayers = getReferenceLayers; const isAnnotationsLayer = layer => layer.layerType === _.layerTypes.ANNOTATIONS && 'indexPatternId' in layer; exports.isAnnotationsLayer = isAnnotationsLayer; const isPersistedAnnotationsLayer = layer => layer.layerType === _.layerTypes.ANNOTATIONS && !('indexPatternId' in layer); exports.isPersistedAnnotationsLayer = isPersistedAnnotationsLayer; const isPersistedByValueAnnotationsLayer = layer => isPersistedAnnotationsLayer(layer) && (layer.persistanceType === 'byValue' || !layer.persistanceType); exports.isPersistedByValueAnnotationsLayer = isPersistedByValueAnnotationsLayer; const isByReferenceAnnotationsLayer = layer => 'annotationGroupId' in layer && '__lastSaved' in layer; exports.isByReferenceAnnotationsLayer = isByReferenceAnnotationsLayer; const isPersistedByReferenceAnnotationsLayer = layer => isPersistedAnnotationsLayer(layer) && layer.persistanceType === 'byReference'; exports.isPersistedByReferenceAnnotationsLayer = isPersistedByReferenceAnnotationsLayer; const isPersistedLinkedByValueAnnotationsLayer = layer => isPersistedAnnotationsLayer(layer) && layer.persistanceType === 'linked'; exports.isPersistedLinkedByValueAnnotationsLayer = isPersistedLinkedByValueAnnotationsLayer; const getAnnotationsLayers = layers => (layers || []).filter(layer => isAnnotationsLayer(layer)); exports.getAnnotationsLayers = getAnnotationsLayers; const getLayerTypeOptions = (layer, options) => { if (isDataLayer(layer)) { return options[_.layerTypes.DATA](layer); } else if (isReferenceLayer(layer)) { return options[_.layerTypes.REFERENCELINE](layer); } return options[_.layerTypes.ANNOTATIONS](layer); }; exports.getLayerTypeOptions = getLayerTypeOptions; function getVisualizationType(state) { if (!state.layers.length) { var _visualizationTypes$f; return (_visualizationTypes$f = _types.visualizationTypes.find(t => t.id === state.preferredSeriesType)) !== null && _visualizationTypes$f !== void 0 ? _visualizationTypes$f : _types.visualizationTypes[0]; } const dataLayers = getDataLayers(state === null || state === void 0 ? void 0 : state.layers); const visualizationType = _types.visualizationTypes.find(t => t.id === (dataLayers === null || dataLayers === void 0 ? void 0 : dataLayers[0].seriesType)); const seriesTypes = (0, _lodash.uniq)(dataLayers.map(l => l.seriesType)); return visualizationType && seriesTypes.length === 1 ? visualizationType : 'mixed'; } function getDescription(state) { if (!state) { return { icon: defaultIcon, label: _i18n.i18n.translate('xpack.lens.xyVisualization.xyLabel', { defaultMessage: 'XY' }) }; } const visualizationType = getVisualizationType(state); if (visualizationType === 'mixed' && (0, _state_helpers.isHorizontalChart)(state.layers)) { return { icon: _chartIcons.IconChartBarHorizontal, label: _i18n.i18n.translate('xpack.lens.xyVisualization.mixedBarHorizontalLabel', { defaultMessage: 'Mixed bar horizontal' }) }; } if (visualizationType === 'mixed') { return { icon: _chartIcons.IconChartMixedXy, label: _i18n.i18n.translate('xpack.lens.xyVisualization.mixedLabel', { defaultMessage: 'Mixed XY' }) }; } return { icon: visualizationType.icon || defaultIcon, label: visualizationType.fullLabel || visualizationType.label }; } const defaultIcon = _chartIcons.IconChartBarStacked; exports.defaultIcon = defaultIcon; const defaultSeriesType = 'bar_stacked'; exports.defaultSeriesType = defaultSeriesType; const supportedDataLayer = { type: _.layerTypes.DATA, label: _i18n.i18n.translate('xpack.lens.xyChart.addDataLayerLabel', { defaultMessage: 'Visualization' }), icon: _chartIcons.IconChartMixedXy }; // i18n ids cannot be dynamically generated, hence the function below exports.supportedDataLayer = supportedDataLayer; function getMessageIdsForDimension(dimension, layers, isHorizontal) { const layersList = layers.map(i => i + 1).join(', '); switch (dimension) { case 'Break down': return { shortMessage: _i18n.i18n.translate('xpack.lens.xyVisualization.dataFailureSplitShort', { defaultMessage: `Missing {axis}.`, values: { axis: 'Break down by axis' } }), longMessage: _i18n.i18n.translate('xpack.lens.xyVisualization.dataFailureSplitLong', { defaultMessage: `{layers, plural, one {Layer} other {Layers}} {layersList} {layers, plural, one {requires} other {require}} a field for the {axis}.`, values: { layers: layers.length, layersList, axis: 'Break down by axis' } }) }; case 'Y': return { shortMessage: _i18n.i18n.translate('xpack.lens.xyVisualization.dataFailureYShort', { defaultMessage: `Missing {axis}.`, values: { axis: getAxisName('y', { isHorizontal }) } }), longMessage: _i18n.i18n.translate('xpack.lens.xyVisualization.dataFailureYLong', { defaultMessage: `{layers, plural, one {Layer} other {Layers}} {layersList} {layers, plural, one {requires} other {require}} a field for the {axis}.`, values: { layers: layers.length, layersList, axis: getAxisName('y', { isHorizontal }) } }) }; } return { shortMessage: '', longMessage: '' }; } const newLayerFn = { [_.layerTypes.DATA]: ({ layerId, seriesType }) => ({ layerId, layerType: _.layerTypes.DATA, accessors: [], seriesType }), [_.layerTypes.REFERENCELINE]: ({ layerId }) => ({ layerId, layerType: _.layerTypes.REFERENCELINE, accessors: [] }), [_.layerTypes.ANNOTATIONS]: ({ layerId, indexPatternId, extraArg }) => { if (extraArg) { const { annotationGroupId, ...libraryGroupConfig } = extraArg; const newLayer = { layerId, layerType: _.layerTypes.ANNOTATIONS, annotationGroupId, annotations: (0, _lodash.cloneDeep)(libraryGroupConfig.annotations), indexPatternId: libraryGroupConfig.indexPatternId, ignoreGlobalFilters: libraryGroupConfig.ignoreGlobalFilters, __lastSaved: libraryGroupConfig }; return newLayer; } const newLayer = { layerId, layerType: _.layerTypes.ANNOTATIONS, annotations: [], indexPatternId, ignoreGlobalFilters: true }; return newLayer; } }; function newLayerState({ layerId, layerType = _.layerTypes.DATA, seriesType, indexPatternId, extraArg }) { return newLayerFn[layerType]({ layerId, seriesType, indexPatternId, extraArg }); } function getLayersByType(state, byType) { return state.layers.filter(({ layerType = _.layerTypes.DATA }) => byType ? layerType === byType : true); } function validateLayersForDimension(dimension, layers, missingCriteria) { // Multiple layers must be consistent: // * either a dimension is missing in ALL of them // * or should not miss on any if (layers.every(missingCriteria) || !layers.some(missingCriteria)) { return { valid: true }; } // otherwise it's an error and it has to be reported const layerMissingAccessors = layers.reduce((missing, layer, i) => { if (missingCriteria(layer)) { missing.push(i); } return missing; }, []); return { valid: false, payload: getMessageIdsForDimension(dimension, layerMissingAccessors, (0, _state_helpers.isHorizontalChart)(layers)) }; } const isNumericMetric = op => !op.isBucketed && op.dataType === 'number'; exports.isNumericMetric = isNumericMetric; const isNumericDynamicMetric = op => isNumericMetric(op) && !op.isStaticValue; exports.isNumericDynamicMetric = isNumericDynamicMetric; const isBucketed = op => op.isBucketed; exports.isBucketed = isBucketed;