"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getTextBasedDatasource = getTextBasedDatasource; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _react = _interopRequireDefault(require("react")); var _i18n = require("@kbn/i18n"); var _eui = require("@elastic/eui"); var _uiTheme = require("@kbn/ui-theme"); var _visualizationUiComponents = require("@kbn/visualization-ui-components"); var _memoizeOne = _interopRequireDefault(require("memoize-one")); var _lodash = require("lodash"); var _datapanel = require("./datapanel"); var _to_expression = require("./to_expression"); var _id_generator = require("../../id_generator"); var _field_select = require("./field_select"); var _layerpanel = require("./layerpanel"); var _utils = require("../../utils"); var _dnd = require("./dnd"); var _remove_column = require("./remove_column"); /* * 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 getLayerReferenceName(layerId) { return `textBasedLanguages-datasource-layer-${layerId}`; } const getSelectedFieldsFromColumns = (0, _memoizeOne.default)(columns => columns.map(c => { if ('fieldName' in c) { return c.fieldName; } }).filter(_utils.nonNullable), _lodash.isEqual); function getTextBasedDatasource({ core, storage, data, expressions, dataViews }) { const getSuggestionsForState = state => { var _Object$entries; return (_Object$entries = Object.entries(state.layers)) === null || _Object$entries === void 0 ? void 0 : _Object$entries.map(([id, layer]) => { var _layer$columns$map, _layer$columns; return { state: { ...state }, table: { changeType: 'unchanged', isMultiRow: false, layerId: id, columns: (_layer$columns$map = (_layer$columns = layer.columns) === null || _layer$columns === void 0 ? void 0 : _layer$columns.map(f => { var _f$meta, _f$meta2; return { columnId: f.columnId, operation: { dataType: f === null || f === void 0 ? void 0 : (_f$meta = f.meta) === null || _f$meta === void 0 ? void 0 : _f$meta.type, label: f.fieldName, isBucketed: Boolean((f === null || f === void 0 ? void 0 : (_f$meta2 = f.meta) === null || _f$meta2 === void 0 ? void 0 : _f$meta2.type) !== 'number') } }; })) !== null && _layer$columns$map !== void 0 ? _layer$columns$map : [] }, keptLayerIds: [id] }; }); }; const getSuggestionsForVisualizeField = (state, indexPatternId, fieldName) => { const context = state.initialContext; // on text based mode we offer suggestions for the query and not for a specific field if (fieldName) return []; if (context && 'dataViewSpec' in context && context.dataViewSpec.title && context.query) { var _context$textBasedCol, _context$dataViewSpec, _newColumns$map; const newLayerId = (0, _id_generator.generateId)(); const textBasedQueryColumns = (_context$textBasedCol = context.textBasedColumns) !== null && _context$textBasedCol !== void 0 ? _context$textBasedCol : []; const newColumns = textBasedQueryColumns.map(c => { return { columnId: c.id, fieldName: c.name, meta: c.meta }; }); const index = (_context$dataViewSpec = context.dataViewSpec.id) !== null && _context$dataViewSpec !== void 0 ? _context$dataViewSpec : context.dataViewSpec.title; const query = context.query; const updatedState = { ...state, fieldList: textBasedQueryColumns, layers: { ...state.layers, [newLayerId]: { index, query, columns: newColumns !== null && newColumns !== void 0 ? newColumns : [], allColumns: newColumns !== null && newColumns !== void 0 ? newColumns : [], timeField: context.dataViewSpec.timeFieldName } } }; return [{ state: { ...updatedState }, table: { changeType: 'initial', isMultiRow: false, layerId: newLayerId, columns: (_newColumns$map = newColumns === null || newColumns === void 0 ? void 0 : newColumns.map(f => { var _f$meta3, _f$meta4; return { columnId: f.columnId, operation: { dataType: f === null || f === void 0 ? void 0 : (_f$meta3 = f.meta) === null || _f$meta3 === void 0 ? void 0 : _f$meta3.type, label: f.fieldName, isBucketed: Boolean((f === null || f === void 0 ? void 0 : (_f$meta4 = f.meta) === null || _f$meta4 === void 0 ? void 0 : _f$meta4.type) !== 'number') } }; })) !== null && _newColumns$map !== void 0 ? _newColumns$map : [] }, keptLayerIds: [newLayerId] }]; } return []; }; const TextBasedDatasource = { id: 'textBased', checkIntegrity: () => { return []; }, getUserMessages: state => { const errors = []; Object.values(state.layers).forEach(layer => { if (layer.errors && layer.errors.length > 0) { errors.push(...layer.errors); } }); return errors.map(err => { const message = { severity: 'error', fixableInEditor: true, displayLocations: [{ id: 'visualization' }, { id: 'textBasedLanguagesQueryInput' }], shortMessage: err.message, longMessage: err.message }; return message; }); }, initialize(state, savedObjectReferences, context, indexPatternRefs, indexPatterns) { const patterns = indexPatterns ? Object.values(indexPatterns) : []; const refs = patterns.map(p => { return { id: p.id, title: p.title, timeField: p.timeFieldName }; }); const initState = state || { layers: {} }; return { ...initState, indexPatternRefs: refs, initialContext: context }; }, syncColumns({ state }) { // TODO implement this for real return state; }, onRefreshIndexPattern() {}, getUsedDataViews: state => { return Object.values(state.layers).map(({ index }) => index); }, getPersistableState({ layers }) { const savedObjectReferences = []; Object.entries(layers).forEach(([layerId, { index, ...persistableLayer }]) => { if (index) { savedObjectReferences.push({ type: 'index-pattern', id: index, name: getLayerReferenceName(layerId) }); } }); return { state: { layers }, savedObjectReferences }; }, insertLayer(state, newLayerId) { var _Object$values, _layer$allColumns, _layer$index; const layer = (_Object$values = Object.values(state === null || state === void 0 ? void 0 : state.layers)) === null || _Object$values === void 0 ? void 0 : _Object$values[0]; const query = layer === null || layer === void 0 ? void 0 : layer.query; const columns = (_layer$allColumns = layer === null || layer === void 0 ? void 0 : layer.allColumns) !== null && _layer$allColumns !== void 0 ? _layer$allColumns : []; const index = (_layer$index = layer === null || layer === void 0 ? void 0 : layer.index) !== null && _layer$index !== void 0 ? _layer$index : JSON.parse(localStorage.getItem('lens-settings') || '{}').indexPatternId || state.indexPatternRefs[0].id; return { ...state, layers: { ...state.layers, [newLayerId]: blankLayer(index, query, columns) } }; }, createEmptyLayer() { return { indexPatternRefs: [], layers: {}, fieldList: [] }; }, cloneLayer(state, layerId, newLayerId, getNewId) { return { ...state }; }, removeLayer(state, layerId) { const newLayers = { ...state.layers, [layerId]: { ...state.layers[layerId], columns: [] } }; return { removedLayerIds: [layerId], newState: { ...state, layers: newLayers, fieldList: state.fieldList } }; }, clearLayer(state, layerId) { return { removedLayerIds: [], newState: { ...state, layers: { ...state.layers, [layerId]: { ...state.layers[layerId], columns: [] } } } }; }, getLayers(state) { return state && state.layers ? Object.keys(state === null || state === void 0 ? void 0 : state.layers) : []; }, isTimeBased: (state, indexPatterns) => { if (!state) return false; const { layers } = state; return Boolean(layers) && Object.values(layers).some(layer => { var _indexPatterns$layer$; return Boolean((_indexPatterns$layer$ = indexPatterns[layer.index]) === null || _indexPatterns$layer$ === void 0 ? void 0 : _indexPatterns$layer$.timeFieldName); }); }, getUsedDataView: (state, layerId) => { if (!layerId) { var _layers$; const layers = Object.values(state.layers); return layers === null || layers === void 0 ? void 0 : (_layers$ = layers[0]) === null || _layers$ === void 0 ? void 0 : _layers$.index; } return state.layers[layerId].index; }, removeColumn: _remove_column.removeColumn, toExpression: (state, layerId, indexPatterns, dateRange, searchSessionId) => { return (0, _to_expression.toExpression)(state, layerId); }, getSelectedFields(state) { var _Object$values2; return getSelectedFieldsFromColumns((_Object$values2 = Object.values(state === null || state === void 0 ? void 0 : state.layers)) === null || _Object$values2 === void 0 ? void 0 : _Object$values2.flatMap(l => Object.values(l.columns))); }, DataPanelComponent(props) { var _TextBasedDatasource$; const layerFields = TextBasedDatasource === null || TextBasedDatasource === void 0 ? void 0 : (_TextBasedDatasource$ = TextBasedDatasource.getSelectedFields) === null || _TextBasedDatasource$ === void 0 ? void 0 : _TextBasedDatasource$.call(TextBasedDatasource, props.state); return /*#__PURE__*/_react.default.createElement(_datapanel.TextBasedDataPanel, (0, _extends2.default)({ data: data, dataViews: dataViews, expressions: expressions, layerFields: layerFields }, props)); }, DimensionTriggerComponent: props => { var _layer$allColumns2, _customLabel; const columnLabelMap = TextBasedDatasource.uniqueLabels(props.state, props.indexPatterns); const layer = props.state.layers[props.layerId]; const selectedField = layer === null || layer === void 0 ? void 0 : (_layer$allColumns2 = layer.allColumns) === null || _layer$allColumns2 === void 0 ? void 0 : _layer$allColumns2.find(column => column.columnId === props.columnId); let customLabel = columnLabelMap[props.columnId]; if (!customLabel) { customLabel = selectedField === null || selectedField === void 0 ? void 0 : selectedField.fieldName; } return /*#__PURE__*/_react.default.createElement(_visualizationUiComponents.DimensionTrigger, { id: props.columnId, color: customLabel && selectedField ? 'primary' : 'danger', dataTestSubj: "lns-dimensionTrigger-textBased", label: (_customLabel = customLabel) !== null && _customLabel !== void 0 ? _customLabel : _i18n.i18n.translate('xpack.lens.textBasedLanguages.missingField', { defaultMessage: 'Missing field' }) }); }, getRenderEventCounters(state) { return []; }, DimensionEditorComponent: props => { var _props$state$layers$p, _props$state$layers$p2; const fields = props.state.fieldList; const selectedField = (_props$state$layers$p = props.state.layers[props.layerId]) === null || _props$state$layers$p === void 0 ? void 0 : (_props$state$layers$p2 = _props$state$layers$p.allColumns) === null || _props$state$layers$p2 === void 0 ? void 0 : _props$state$layers$p2.find(column => column.columnId === props.columnId); const updatedFields = fields === null || fields === void 0 ? void 0 : fields.map(f => { var _f$meta5; return { ...f, compatible: props.isMetricDimension ? props.filterOperations({ dataType: f.meta.type, isBucketed: Boolean((f === null || f === void 0 ? void 0 : (_f$meta5 = f.meta) === null || _f$meta5 === void 0 ? void 0 : _f$meta5.type) !== 'number'), scale: 'ordinal' }) : true }; }); return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_eui.EuiFormRow, { "data-test-subj": "text-based-languages-field-selection-row", label: _i18n.i18n.translate('xpack.lens.textBasedLanguages.chooseField', { defaultMessage: 'Field' }), fullWidth: true, className: "lnsIndexPatternDimensionEditor--padded" }, /*#__PURE__*/_react.default.createElement(_field_select.FieldSelect, { existingFields: updatedFields !== null && updatedFields !== void 0 ? updatedFields : [], selectedField: selectedField, onChoose: choice => { var _fields$find; const meta = fields === null || fields === void 0 ? void 0 : (_fields$find = fields.find(f => f.name === choice.field)) === null || _fields$find === void 0 ? void 0 : _fields$find.meta; const newColumn = { columnId: props.columnId, fieldName: choice.field, meta }; return props.setState(!selectedField ? { ...props.state, layers: { ...props.state.layers, [props.layerId]: { ...props.state.layers[props.layerId], columns: [...props.state.layers[props.layerId].columns, newColumn], allColumns: [...props.state.layers[props.layerId].allColumns, newColumn] } } } : { ...props.state, layers: { ...props.state.layers, [props.layerId]: { ...props.state.layers[props.layerId], columns: props.state.layers[props.layerId].columns.map(col => col.columnId !== props.columnId ? col : { ...col, fieldName: choice.field, meta }), allColumns: props.state.layers[props.layerId].allColumns.map(col => col.columnId !== props.columnId ? col : { ...col, fieldName: choice.field, meta }) } } }); } })), props.dataSectionExtra && /*#__PURE__*/_react.default.createElement("div", { style: { paddingLeft: _uiTheme.euiThemeVars.euiSize, paddingRight: _uiTheme.euiThemeVars.euiSize } }, props.dataSectionExtra)); }, LayerPanelComponent: props => { return /*#__PURE__*/_react.default.createElement(_layerpanel.LayerPanel, props); }, uniqueLabels(state) { const layers = state.layers; const columnLabelMap = {}; const uniqueLabelGenerator = (0, _utils.getUniqueLabelGenerator)(); Object.values(layers).forEach(layer => { if (!layer.columns) { return; } Object.values(layer.columns).forEach(column => { columnLabelMap[column.columnId] = uniqueLabelGenerator(column.fieldName); }); }); return columnLabelMap; }, getDropProps: _dnd.getDropProps, onDrop: _dnd.onDrop, getPublicAPI({ state, layerId, indexPatterns }) { return { datasourceId: 'textBased', getTableSpec: () => { var _state$layers$layerId; const columns = (_state$layers$layerId = state.layers[layerId]) === null || _state$layers$layerId === void 0 ? void 0 : _state$layers$layerId.columns.filter(c => { var _state$fieldList; const columnExists = state === null || state === void 0 ? void 0 : (_state$fieldList = state.fieldList) === null || _state$fieldList === void 0 ? void 0 : _state$fieldList.some(f => f.name === (c === null || c === void 0 ? void 0 : c.fieldName)); if (columnExists) return c; }); return columns.map(column => ({ columnId: column.columnId, fields: [column.fieldName] })) || []; }, getOperationForColumnId: columnId => { var _layer$allColumns3; const layer = state.layers[layerId]; const column = layer === null || layer === void 0 ? void 0 : (_layer$allColumns3 = layer.allColumns) === null || _layer$allColumns3 === void 0 ? void 0 : _layer$allColumns3.find(c => c.columnId === columnId); const columnLabelMap = TextBasedDatasource.uniqueLabels(state, indexPatterns); if (column) { var _column$meta, _columnLabelMap$colum, _column$meta2; return { dataType: column === null || column === void 0 ? void 0 : (_column$meta = column.meta) === null || _column$meta === void 0 ? void 0 : _column$meta.type, label: (_columnLabelMap$colum = columnLabelMap[columnId]) !== null && _columnLabelMap$colum !== void 0 ? _columnLabelMap$colum : column === null || column === void 0 ? void 0 : column.fieldName, isBucketed: Boolean((column === null || column === void 0 ? void 0 : (_column$meta2 = column.meta) === null || _column$meta2 === void 0 ? void 0 : _column$meta2.type) !== 'number'), hasTimeShift: false, hasReducedTimeRange: false }; } return null; }, getVisualDefaults: () => ({}), isTextBasedLanguage: () => true, getMaxPossibleNumValues: columnId => { return null; }, getSourceId: () => { const layer = state.layers[layerId]; return layer.index; }, getFilters: () => { return { enabled: { kuery: [], lucene: [] }, disabled: { kuery: [], lucene: [] } }; }, hasDefaultTimeField: () => false }; }, getDatasourceSuggestionsForField(state, draggedField) { var _state$fieldList2, _Object$entries2; const field = (_state$fieldList2 = state.fieldList) === null || _state$fieldList2 === void 0 ? void 0 : _state$fieldList2.find(f => f.id === draggedField.id); if (!field) return []; return (_Object$entries2 = Object.entries(state.layers)) === null || _Object$entries2 === void 0 ? void 0 : _Object$entries2.map(([id, layer]) => { var _field$name, _layer$columns2, _field$meta, _field$name2, _field$meta2; const newId = (0, _id_generator.generateId)(); const newColumn = { columnId: newId, fieldName: (_field$name = field === null || field === void 0 ? void 0 : field.name) !== null && _field$name !== void 0 ? _field$name : '', meta: field === null || field === void 0 ? void 0 : field.meta }; return { state: { ...state, layers: { ...state.layers, [id]: { ...state.layers[id], columns: [...layer.columns, newColumn], allColumns: [...layer.allColumns, newColumn] } } }, table: { changeType: 'initial', isMultiRow: false, layerId: id, columns: [...((_layer$columns2 = layer.columns) === null || _layer$columns2 === void 0 ? void 0 : _layer$columns2.map(f => { var _f$meta6, _f$meta7; return { columnId: f.columnId, operation: { dataType: f === null || f === void 0 ? void 0 : (_f$meta6 = f.meta) === null || _f$meta6 === void 0 ? void 0 : _f$meta6.type, label: f.fieldName, isBucketed: Boolean((f === null || f === void 0 ? void 0 : (_f$meta7 = f.meta) === null || _f$meta7 === void 0 ? void 0 : _f$meta7.type) !== 'number') } }; })), { columnId: newId, operation: { dataType: field === null || field === void 0 ? void 0 : (_field$meta = field.meta) === null || _field$meta === void 0 ? void 0 : _field$meta.type, label: (_field$name2 = field === null || field === void 0 ? void 0 : field.name) !== null && _field$name2 !== void 0 ? _field$name2 : '', isBucketed: Boolean((field === null || field === void 0 ? void 0 : (_field$meta2 = field.meta) === null || _field$meta2 === void 0 ? void 0 : _field$meta2.type) !== 'number') } }] }, keptLayerIds: [id] }; }); return []; }, getDatasourceSuggestionsForVisualizeField: getSuggestionsForVisualizeField, getDatasourceSuggestionsFromCurrentState: getSuggestionsForState, getDatasourceSuggestionsForVisualizeCharts: getSuggestionsForState, isEqual: () => true, getDatasourceInfo: async (state, references, dataViewsService) => { const indexPatterns = []; for (const { index } of Object.values(state.layers)) { const dataView = await (dataViewsService === null || dataViewsService === void 0 ? void 0 : dataViewsService.get(index)); if (dataView) { indexPatterns.push(dataView); } } return Object.entries(state.layers).reduce((acc, [key, layer]) => { const columns = Object.entries(layer.columns).map(([colId, col]) => { var _col$meta, _col$meta2, _col$meta3, _col$meta4; return { id: colId, role: ((_col$meta = col.meta) === null || _col$meta === void 0 ? void 0 : _col$meta.type) !== 'number' ? 'split' : 'metric', operation: { dataType: col === null || col === void 0 ? void 0 : (_col$meta2 = col.meta) === null || _col$meta2 === void 0 ? void 0 : _col$meta2.type, label: col.fieldName, isBucketed: Boolean((col === null || col === void 0 ? void 0 : (_col$meta3 = col.meta) === null || _col$meta3 === void 0 ? void 0 : _col$meta3.type) !== 'number'), hasTimeShift: false, hasReducedTimeRange: false, fields: [col.fieldName], type: ((_col$meta4 = col.meta) === null || _col$meta4 === void 0 ? void 0 : _col$meta4.type) || 'unknown', filter: undefined } }; }); acc.push({ layerId: key, columns, dataView: indexPatterns === null || indexPatterns === void 0 ? void 0 : indexPatterns.find(dataView => dataView.id === layer.index) }); return acc; }, []); } }; return TextBasedDatasource; } function blankLayer(index, query, columns) { return { index, query, columns: [], allColumns: columns !== null && columns !== void 0 ? columns : [] }; }