"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.updateVisualizationState = exports.updateIndexPatterns = exports.updateDatasourceState = exports.switchVisualization = exports.switchDatasource = exports.switchAndCleanDatasource = exports.submitSuggestion = exports.setToggleFullscreen = exports.setState = exports.setSaveable = exports.setLayerDefaultDimension = exports.setIsLoadLibraryVisible = exports.setExecutionContext = exports.setChangesApplied = exports.rollbackSuggestion = exports.replaceIndexpattern = exports.removeOrClearLayer = exports.removeLayers = exports.removeDimension = exports.registerLibraryAnnotationGroup = exports.onDropToDimension = exports.onActiveDataChange = exports.navigateAway = exports.makeLensReducer = exports.loadInitial = exports.lensActions = exports.insertLayer = exports.initialState = exports.initExisting = exports.initEmpty = exports.getPreloadedState = exports.enableAutoApply = exports.editVisualizationAction = exports.disableAutoApply = exports.cloneLayer = exports.changeIndexPattern = exports.applyChanges = exports.addLayer = void 0; var _toolkit = require("@reduxjs/toolkit"); var _lodash = require("lodash"); var _public = require("@kbn/expression-xy-plugin/public"); var _utils = require("../utils"); var _id_generator = require("../id_generator"); var _suggestion_helpers = require("../editor_frame_service/editor_frame/suggestion_helpers"); var _selectors = require("./selectors"); var _drop_targets_utils = require("../editor_frame_service/editor_frame/config_panel/buttons/drop_targets_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 getQueryFromContext = (context, data) => { if ('searchQuery' in context && context.searchQuery) { return context.searchQuery; } if ('query' in context && context.query) { return context.query; } return data.query.queryString.getQuery(); }; const initialState = { persistedDoc: undefined, searchSessionId: '', filters: [], query: { language: 'kuery', query: '' }, resolvedDateRange: { fromDate: '', toDate: '' }, isFullscreenDatasource: false, isSaveable: false, isLoading: false, isLinkedToOriginatingApp: false, activeDatasourceId: null, datasourceStates: {}, visualization: { state: null, activeId: null }, dataViews: { indexPatternRefs: [], indexPatterns: {} }, annotationGroups: {} }; exports.initialState = initialState; const getPreloadedState = ({ lensServices: { data }, initialContext, initialStateFromLocator, embeddableEditorIncomingState, datasourceMap, visualizationMap }) => { const initialDatasourceId = (0, _utils.getInitialDatasourceId)(datasourceMap); const datasourceStates = {}; // Initialize an empty datasourceStates for each datasource if (initialDatasourceId) { Object.keys(datasourceMap).forEach(datasourceId => { datasourceStates[datasourceId] = { state: null, isLoading: true }; }); } if (initialStateFromLocator) { // if anything is passed via locator then populate the empty state if ('datasourceStates' in initialStateFromLocator) { Object.keys(datasourceMap).forEach(datasourceId => { datasourceStates[datasourceId].state = initialStateFromLocator.datasourceStates[datasourceId]; }); } return { ...initialState, isLoading: true, ...initialStateFromLocator, activeDatasourceId: 'activeDatasourceId' in initialStateFromLocator && initialStateFromLocator.activeDatasourceId || initialDatasourceId, datasourceStates }; } const query = !initialContext ? data.query.queryString.getDefaultQuery() : getQueryFromContext(initialContext, data); const state = { ...initialState, isLoading: true, // Do not use app-specific filters from previous app, // only if Lens was opened with the intention to visualize a field (e.g. coming from Discover) query: query, filters: !initialContext ? data.query.filterManager.getGlobalFilters() : 'searchFilters' in initialContext && initialContext.searchFilters ? initialContext.searchFilters : data.query.filterManager.getFilters(), searchSessionId: data.search.session.getSessionId() || '', resolvedDateRange: (0, _utils.getResolvedDateRange)(data.query.timefilter.timefilter), isLinkedToOriginatingApp: Boolean((embeddableEditorIncomingState === null || embeddableEditorIncomingState === void 0 ? void 0 : embeddableEditorIncomingState.originatingApp) || initialContext && 'isEmbeddable' in initialContext && (initialContext === null || initialContext === void 0 ? void 0 : initialContext.isEmbeddable)), activeDatasourceId: initialDatasourceId, datasourceStates, visualization: { state: null, activeId: Object.keys(visualizationMap)[0] || null } }; return state; }; exports.getPreloadedState = getPreloadedState; const setState = (0, _toolkit.createAction)('lens/setState'); exports.setState = setState; const setExecutionContext = (0, _toolkit.createAction)('lens/setExecutionContext'); exports.setExecutionContext = setExecutionContext; const initExisting = (0, _toolkit.createAction)('lens/initExisting'); exports.initExisting = initExisting; const onActiveDataChange = (0, _toolkit.createAction)('lens/onActiveDataChange'); exports.onActiveDataChange = onActiveDataChange; const setSaveable = (0, _toolkit.createAction)('lens/setSaveable'); exports.setSaveable = setSaveable; const enableAutoApply = (0, _toolkit.createAction)('lens/enableAutoApply'); exports.enableAutoApply = enableAutoApply; const disableAutoApply = (0, _toolkit.createAction)('lens/disableAutoApply'); exports.disableAutoApply = disableAutoApply; const applyChanges = (0, _toolkit.createAction)('lens/applyChanges'); exports.applyChanges = applyChanges; const setChangesApplied = (0, _toolkit.createAction)('lens/setChangesApplied'); exports.setChangesApplied = setChangesApplied; const updateDatasourceState = (0, _toolkit.createAction)('lens/updateDatasourceState'); exports.updateDatasourceState = updateDatasourceState; const updateVisualizationState = (0, _toolkit.createAction)('lens/updateVisualizationState'); exports.updateVisualizationState = updateVisualizationState; const insertLayer = (0, _toolkit.createAction)('lens/insertLayer'); exports.insertLayer = insertLayer; const switchVisualization = (0, _toolkit.createAction)('lens/switchVisualization'); exports.switchVisualization = switchVisualization; const rollbackSuggestion = (0, _toolkit.createAction)('lens/rollbackSuggestion'); exports.rollbackSuggestion = rollbackSuggestion; const setToggleFullscreen = (0, _toolkit.createAction)('lens/setToggleFullscreen'); exports.setToggleFullscreen = setToggleFullscreen; const setIsLoadLibraryVisible = (0, _toolkit.createAction)('lens/setIsLoadLibraryVisible'); exports.setIsLoadLibraryVisible = setIsLoadLibraryVisible; const submitSuggestion = (0, _toolkit.createAction)('lens/submitSuggestion'); exports.submitSuggestion = submitSuggestion; const switchDatasource = (0, _toolkit.createAction)('lens/switchDatasource'); exports.switchDatasource = switchDatasource; const switchAndCleanDatasource = (0, _toolkit.createAction)('lens/switchAndCleanDatasource'); exports.switchAndCleanDatasource = switchAndCleanDatasource; const navigateAway = (0, _toolkit.createAction)('lens/navigateAway'); exports.navigateAway = navigateAway; const loadInitial = (0, _toolkit.createAction)('lens/loadInitial'); exports.loadInitial = loadInitial; const initEmpty = (0, _toolkit.createAction)('initEmpty', function prepare({ newState, initialContext }) { return { payload: { layerId: (0, _id_generator.generateId)(), newState, initialContext } }; }); exports.initEmpty = initEmpty; const editVisualizationAction = (0, _toolkit.createAction)('lens/editVisualizationAction'); exports.editVisualizationAction = editVisualizationAction; const removeLayers = (0, _toolkit.createAction)('lens/removeLayers'); exports.removeLayers = removeLayers; const removeOrClearLayer = (0, _toolkit.createAction)('lens/removeOrClearLayer'); exports.removeOrClearLayer = removeOrClearLayer; const cloneLayer = (0, _toolkit.createAction)('cloneLayer', function prepare({ layerId }) { return { payload: { newLayerId: (0, _id_generator.generateId)(), layerId } }; }); exports.cloneLayer = cloneLayer; const addLayer = (0, _toolkit.createAction)('lens/addLayer'); exports.addLayer = addLayer; const onDropToDimension = (0, _toolkit.createAction)('lens/onDropToDimension'); exports.onDropToDimension = onDropToDimension; const setLayerDefaultDimension = (0, _toolkit.createAction)('lens/setLayerDefaultDimension'); exports.setLayerDefaultDimension = setLayerDefaultDimension; const updateIndexPatterns = (0, _toolkit.createAction)('lens/updateIndexPatterns'); exports.updateIndexPatterns = updateIndexPatterns; const replaceIndexpattern = (0, _toolkit.createAction)('lens/replaceIndexPattern'); exports.replaceIndexpattern = replaceIndexpattern; const changeIndexPattern = (0, _toolkit.createAction)('lens/changeIndexPattern'); exports.changeIndexPattern = changeIndexPattern; const removeDimension = (0, _toolkit.createAction)('lens/removeDimension'); exports.removeDimension = removeDimension; const registerLibraryAnnotationGroup = (0, _toolkit.createAction)('lens/registerLibraryAnnotationGroup'); exports.registerLibraryAnnotationGroup = registerLibraryAnnotationGroup; const lensActions = { initExisting, setState, setExecutionContext, onActiveDataChange, setSaveable, enableAutoApply, disableAutoApply, applyChanges, setChangesApplied, updateDatasourceState, updateVisualizationState, insertLayer, switchVisualization, rollbackSuggestion, setToggleFullscreen, setIsLoadLibraryVisible, submitSuggestion, switchDatasource, switchAndCleanDatasource, navigateAway, loadInitial, initEmpty, editVisualizationAction, removeLayers, removeOrClearLayer, addLayer, onDropToDimension, cloneLayer, setLayerDefaultDimension, updateIndexPatterns, replaceIndexpattern, changeIndexPattern, removeDimension, syncLinkedDimensions, registerLibraryAnnotationGroup }; exports.lensActions = lensActions; const makeLensReducer = storeDeps => { const { datasourceMap, visualizationMap } = storeDeps; return (0, _toolkit.createReducer)(initialState, { [setState.type]: (state, { payload }) => { return { ...state, ...payload }; }, [setExecutionContext.type]: (state, { payload }) => { return { ...state, ...payload }; }, [initExisting.type]: (state, { payload }) => { return { ...state, ...payload }; }, [onActiveDataChange.type]: (state, { payload: { activeData } }) => { return { ...state, activeData }; }, [setSaveable.type]: (state, { payload }) => { return { ...state, isSaveable: payload }; }, [enableAutoApply.type]: state => { state.autoApplyDisabled = false; }, [disableAutoApply.type]: state => { state.autoApplyDisabled = true; state.changesApplied = true; }, [applyChanges.type]: state => { if (typeof state.applyChangesCounter === 'undefined') { state.applyChangesCounter = 0; } state.applyChangesCounter++; }, [setChangesApplied.type]: (state, { payload: applied }) => { state.changesApplied = applied; }, [cloneLayer.type]: (state, { payload: { layerId, newLayerId } }) => { const clonedIDsMap = new Map(); const getNewId = prevId => { const inMapValue = clonedIDsMap.get(prevId); if (!inMapValue) { const newId = (0, _id_generator.generateId)(); clonedIDsMap.set(prevId, newId); return newId; } return inMapValue; }; if (!state.activeDatasourceId || !state.visualization.activeId) { return state; } state.datasourceStates = (0, _lodash.mapValues)(state.datasourceStates, (datasourceState, datasourceId) => datasourceId ? { ...datasourceState, state: datasourceMap[datasourceId].cloneLayer(datasourceState.state, layerId, newLayerId, getNewId) } : datasourceState); state.visualization.state = visualizationMap[state.visualization.activeId].cloneLayer(state.visualization.state, layerId, newLayerId, clonedIDsMap); }, [removeOrClearLayer.type]: (state, { payload: { visualizationId, layerId, layerIds } }) => { const activeVisualization = visualizationMap[visualizationId]; const activeDataSource = datasourceMap[state.activeDatasourceId]; const isOnlyLayer = (0, _utils.getRemoveOperation)(activeVisualization, state.visualization.state, layerId, layerIds.length) === 'clear'; let removedLayerIds = []; state.datasourceStates = (0, _lodash.mapValues)(state.datasourceStates, (datasourceState, datasourceId) => { const datasource = datasourceMap[datasourceId]; const { newState, removedLayerIds: removedLayerIdsForThisDatasource } = isOnlyLayer ? datasource.clearLayer(datasourceState.state, layerId) : datasource.removeLayer(datasourceState.state, layerId); removedLayerIds = [...removedLayerIds, ...removedLayerIdsForThisDatasource]; return { ...datasourceState, ...(datasourceId === state.activeDatasourceId && { state: newState }) }; }); state.stagedPreview = undefined; // reuse the activeDatasource current dataView id for the moment const currentDataViewsId = activeDataSource.getUsedDataView(state.datasourceStates[state.activeDatasourceId].state); if (isOnlyLayer || !activeVisualization.removeLayer) { state.visualization.state = activeVisualization.clearLayer(state.visualization.state, layerId, currentDataViewsId); } (0, _lodash.uniq)(removedLayerIds).forEach(removedId => { var _activeVisualization$; return state.visualization.state = (_activeVisualization$ = activeVisualization.removeLayer) === null || _activeVisualization$ === void 0 ? void 0 : _activeVisualization$.call(activeVisualization, state.visualization.state, removedId); }); }, [changeIndexPattern.type]: (state, { payload }) => { const { visualizationIds, datasourceIds, layerId, indexPatternId, dataViews } = payload; const newIndexPatternRefs = [...state.dataViews.indexPatternRefs]; const availableRefs = new Set(newIndexPatternRefs.map(ref => ref.id)); // check for missing refs Object.values(dataViews.indexPatterns || {}).forEach(indexPattern => { if (!availableRefs.has(indexPattern.id)) { newIndexPatternRefs.push({ id: indexPattern.id, name: indexPattern.name, title: indexPattern.title }); } }); const newState = { dataViews: { ...state.dataViews, indexPatterns: dataViews.indexPatterns, indexPatternRefs: newIndexPatternRefs } }; if (visualizationIds !== null && visualizationIds !== void 0 && visualizationIds.length) { for (const visualizationId of visualizationIds) { const activeVisualization = visualizationId && state.visualization.activeId === visualizationId && visualizationMap[visualizationId]; if (activeVisualization && layerId && activeVisualization !== null && activeVisualization !== void 0 && activeVisualization.onIndexPatternChange) { newState.visualization = { ...state.visualization, state: activeVisualization.onIndexPatternChange(state.visualization.state, indexPatternId, layerId) }; } } } if (datasourceIds !== null && datasourceIds !== void 0 && datasourceIds.length) { newState.datasourceStates = { ...state.datasourceStates }; const frame = (0, _selectors.selectFramePublicAPI)({ lens: { ...(0, _toolkit.current)(state), dataViews: newState.dataViews } }, datasourceMap); const datasourceLayers = frame.datasourceLayers; for (const datasourceId of datasourceIds) { const activeDatasource = datasourceId && datasourceMap[datasourceId]; if (activeDatasource && activeDatasource !== null && activeDatasource !== void 0 && activeDatasource.onIndexPatternChange) { newState.datasourceStates = { ...newState.datasourceStates, [datasourceId]: { isLoading: false, state: activeDatasource.onIndexPatternChange(newState.datasourceStates[datasourceId].state, dataViews.indexPatterns, indexPatternId, layerId) } }; // Update the visualization columns if (layerId && state.visualization.activeId) { const nextPublicAPI = activeDatasource.getPublicAPI({ state: newState.datasourceStates[datasourceId].state, layerId, indexPatterns: dataViews.indexPatterns }); const nextTable = new Set(nextPublicAPI.getTableSpec().map(({ columnId }) => columnId)); const datasourcePublicAPI = datasourceLayers[layerId]; if (datasourcePublicAPI) { const removed = datasourcePublicAPI.getTableSpec().map(({ columnId }) => columnId).filter(columnId => !nextTable.has(columnId)); const activeVisualization = visualizationMap[state.visualization.activeId]; let nextVisState = (newState.visualization || state.visualization).state; removed.forEach(columnId => { nextVisState = activeVisualization.removeDimension({ layerId, columnId, prevState: nextVisState, frame }); }); newState.visualization = { ...state.visualization, state: nextVisState }; } } } } } return { ...state, ...newState }; }, [updateIndexPatterns.type]: (state, { payload }) => { return { ...state, dataViews: { ...state.dataViews, ...payload } }; }, [replaceIndexpattern.type]: (state, { payload }) => { var _visualization$onInde, _visualization$onInde2; state.dataViews.indexPatterns[payload.newIndexPattern.id] = payload.newIndexPattern; delete state.dataViews.indexPatterns[payload.oldId]; state.dataViews.indexPatternRefs = state.dataViews.indexPatternRefs.filter(r => r.id !== payload.oldId); state.dataViews.indexPatternRefs.push({ id: payload.newIndexPattern.id, title: payload.newIndexPattern.title, name: payload.newIndexPattern.name }); const visualization = visualizationMap[state.visualization.activeId]; state.visualization.state = (_visualization$onInde = (_visualization$onInde2 = visualization.onIndexPatternRename) === null || _visualization$onInde2 === void 0 ? void 0 : _visualization$onInde2.call(visualization, state.visualization.state, payload.oldId, payload.newIndexPattern.id)) !== null && _visualization$onInde !== void 0 ? _visualization$onInde : state.visualization.state; Object.entries(state.datasourceStates).forEach(([datasourceId, datasourceState]) => { var _datasource$onIndexPa, _datasource$onIndexPa2; const datasource = datasourceMap[datasourceId]; state.datasourceStates[datasourceId].state = (_datasource$onIndexPa = datasource === null || datasource === void 0 ? void 0 : (_datasource$onIndexPa2 = datasource.onIndexPatternRename) === null || _datasource$onIndexPa2 === void 0 ? void 0 : _datasource$onIndexPa2.call(datasource, datasourceState.state, payload.oldId, payload.newIndexPattern.id)) !== null && _datasource$onIndexPa !== void 0 ? _datasource$onIndexPa : datasourceState.state; }); }, [updateDatasourceState.type]: (state, { payload }) => { if (payload.clearStagedPreview) { state.stagedPreview = undefined; } state.datasourceStates[payload.datasourceId] = { state: payload.newDatasourceState, isLoading: false }; if (payload.dontSyncLinkedDimensions) { return; } const currentState = (0, _toolkit.current)(state); const { datasourceState: syncedDatasourceState, visualizationState: syncedVisualizationState } = syncLinkedDimensions(currentState, visualizationMap, datasourceMap, payload.datasourceId); state.visualization.state = syncedVisualizationState; state.datasourceStates[payload.datasourceId].state = syncedDatasourceState; }, [updateVisualizationState.type]: (state, { payload }) => { if (!state.visualization.activeId) { throw new Error('Invariant: visualization state got updated without active visualization'); } // This is a safeguard that prevents us from accidentally updating the // wrong visualization. This occurs in some cases due to the uncoordinated // way we manage state across plugins. if (state.visualization.activeId !== payload.visualizationId) { return state; } state.visualization.state = payload.newState; if (!state.activeDatasourceId) { return; } if (payload.dontSyncLinkedDimensions) { return; } // TODO - consolidate into applySyncLinkedDimensions const { datasourceState: syncedDatasourceState, visualizationState: syncedVisualizationState } = syncLinkedDimensions((0, _toolkit.current)(state), visualizationMap, datasourceMap); state.datasourceStates[state.activeDatasourceId].state = syncedDatasourceState; state.visualization.state = syncedVisualizationState; }, [switchVisualization.type]: (state, { payload }) => { const { newVisualizationId, visualizationState, datasourceState, datasourceId } = payload.suggestion; return { ...state, datasourceStates: datasourceId ? { ...state.datasourceStates, [datasourceId]: { ...state.datasourceStates[datasourceId], state: datasourceState } } : state.datasourceStates, visualization: { ...state.visualization, activeId: newVisualizationId, state: visualizationState }, stagedPreview: payload.clearStagedPreview ? undefined : state.stagedPreview || { datasourceStates: state.datasourceStates, visualization: state.visualization, activeData: state.activeData } }; }, [rollbackSuggestion.type]: state => { return { ...state, ...(state.stagedPreview || {}), stagedPreview: undefined }; }, [setToggleFullscreen.type]: state => { return { ...state, isFullscreenDatasource: !state.isFullscreenDatasource }; }, [submitSuggestion.type]: state => { return { ...state, stagedPreview: undefined }; }, [switchDatasource.type]: (state, { payload }) => { return { ...state, datasourceStates: { ...state.datasourceStates, [payload.newDatasourceId]: state.datasourceStates[payload.newDatasourceId] || { state: null, isLoading: true } }, activeDatasourceId: payload.newDatasourceId }; }, [switchAndCleanDatasource.type]: (state, { payload }) => { var _current$datasourceSt, _payload$currentIndex; const activeVisualization = payload.visualizationId && visualizationMap[payload.visualizationId]; const visualization = state.visualization; let newVizState = visualization.state; const ids = []; if (activeVisualization && activeVisualization.getLayerIds) { const layerIds = activeVisualization.getLayerIds(visualization.state); ids.push(...Object.values(layerIds)); newVizState = activeVisualization.initialize(() => ids[0]); } const currentVizId = ids[0]; const datasourceState = (0, _toolkit.current)(state).datasourceStates[payload.newDatasourceId] ? (_current$datasourceSt = (0, _toolkit.current)(state).datasourceStates[payload.newDatasourceId]) === null || _current$datasourceSt === void 0 ? void 0 : _current$datasourceSt.state : datasourceMap[payload.newDatasourceId].createEmptyLayer((_payload$currentIndex = payload.currentIndexPatternId) !== null && _payload$currentIndex !== void 0 ? _payload$currentIndex : ''); const updatedState = datasourceMap[payload.newDatasourceId].insertLayer(datasourceState, currentVizId); return { ...state, datasourceStates: { [payload.newDatasourceId]: { state: updatedState, isLoading: false } }, activeDatasourceId: payload.newDatasourceId, visualization: { ...visualization, state: newVizState } }; }, [navigateAway.type]: state => state, [loadInitial.type]: (state, payload) => state, [initEmpty.type]: (state, { payload }) => { const newState = { ...state, ...payload.newState }; const suggestion = (0, _suggestion_helpers.getVisualizeFieldSuggestions)({ datasourceMap, datasourceStates: newState.datasourceStates, visualizationMap, visualizeTriggerFieldContext: payload.initialContext, dataViews: newState.dataViews }); if (suggestion) { return { ...newState, datasourceStates: { ...newState.datasourceStates, [suggestion.datasourceId]: { ...newState.datasourceStates[suggestion.datasourceId], state: suggestion.datasourceState } }, visualization: { ...newState.visualization, activeId: suggestion.visualizationId, state: suggestion.visualizationState }, stagedPreview: undefined }; } const visualization = newState.visualization; if (!visualization.activeId) { throw new Error('Invariant: visualization state got updated without active visualization'); } const activeVisualization = visualizationMap[visualization.activeId]; if (visualization.state === null && activeVisualization) { var _newState$datasourceS; const activeDatasourceId = (0, _utils.getInitialDatasourceId)(datasourceMap); const newVisState = activeVisualization.initialize(() => payload.layerId); const activeDatasource = datasourceMap[activeDatasourceId]; return { ...newState, activeDatasourceId, datasourceStates: { ...newState.datasourceStates, [activeDatasourceId]: { ...newState.datasourceStates[activeDatasourceId], state: activeDatasource.insertLayer((_newState$datasourceS = newState.datasourceStates[activeDatasourceId]) === null || _newState$datasourceS === void 0 ? void 0 : _newState$datasourceS.state, payload.layerId) } }, visualization: { ...visualization, state: newVisState } }; } return newState; }, [editVisualizationAction.type]: (state, { payload }) => { if (!state.visualization.activeId) { throw new Error('Invariant: visualization state got updated without active visualization'); } // This is a safeguard that prevents us from accidentally updating the // wrong visualization. This occurs in some cases due to the uncoordinated // way we manage state across plugins. if (state.visualization.activeId !== payload.visualizationId) { return state; } const activeVisualization = visualizationMap[payload.visualizationId]; if (activeVisualization !== null && activeVisualization !== void 0 && activeVisualization.onEditAction) { state.visualization.state = activeVisualization.onEditAction(state.visualization.state, payload.event); } }, [insertLayer.type]: (state, { payload }) => { const updater = datasourceMap[payload.datasourceId].insertLayer; return { ...state, datasourceStates: { ...state.datasourceStates, [payload.datasourceId]: { ...state.datasourceStates[payload.datasourceId], state: updater((0, _toolkit.current)(state).datasourceStates[payload.datasourceId].state, payload.layerId) } } }; }, [removeLayers.type]: (state, { payload: { visualizationId, layerIds } }) => { if (!state.visualization.activeId) { throw new Error('Invariant: visualization state got updated without active visualization'); } const activeVisualization = visualizationId && visualizationMap[visualizationId]; // This is a safeguard that prevents us from accidentally updating the // wrong visualization. This occurs in some cases due to the uncoordinated // way we manage state across plugins. if (state.visualization.activeId === visualizationId && activeVisualization && activeVisualization.removeLayer && state.visualization.state) { const updater = layerIds.reduce((acc, layerId) => activeVisualization.removeLayer ? activeVisualization.removeLayer(acc, layerId) : acc, state.visualization.state); state.visualization.state = typeof updater === 'function' ? updater((0, _toolkit.current)(state.visualization.state)) : updater; } layerIds.forEach(layerId => { var _Object$entries$find; const [layerDatasourceId] = (_Object$entries$find = Object.entries(datasourceMap).find(([datasourceId, datasource]) => { return state.datasourceStates[datasourceId] && datasource.getLayers(state.datasourceStates[datasourceId].state).includes(layerId); })) !== null && _Object$entries$find !== void 0 ? _Object$entries$find : []; if (layerDatasourceId) { const { newState } = datasourceMap[layerDatasourceId].removeLayer((0, _toolkit.current)(state).datasourceStates[layerDatasourceId].state, layerId); state.datasourceStates[layerDatasourceId].state = newState; // TODO - call removeLayer for any extra (linked) layers removed by the datasource } }); }, [addLayer.type]: (state, { payload: { layerId, layerType, extraArg, ignoreInitialValues } }) => { var _activeVisualization$2, _activeVisualization$3; if (!state.activeDatasourceId || !state.visualization.activeId) { return state; } const activeVisualization = visualizationMap[state.visualization.activeId]; const activeDatasource = datasourceMap[state.activeDatasourceId]; // reuse the active datasource dataView id for the new layer const currentDataViewsId = activeDatasource.getUsedDataView(state.datasourceStates[state.activeDatasourceId].state); const visualizationState = activeVisualization.appendLayer(state.visualization.state, layerId, layerType, currentDataViewsId, extraArg); const framePublicAPI = (0, _selectors.selectFramePublicAPI)({ lens: (0, _toolkit.current)(state) }, datasourceMap); const { noDatasource } = activeVisualization.getSupportedLayers(visualizationState, framePublicAPI).find(({ type }) => type === layerType) || {}; const layersToLinkTo = (_activeVisualization$2 = (_activeVisualization$3 = activeVisualization.getLayersToLinkTo) === null || _activeVisualization$3 === void 0 ? void 0 : _activeVisualization$3.call(activeVisualization, visualizationState, layerId)) !== null && _activeVisualization$2 !== void 0 ? _activeVisualization$2 : []; const datasourceState = !noDatasource && activeDatasource ? activeDatasource.insertLayer(state.datasourceStates[state.activeDatasourceId].state, layerId, layersToLinkTo) : state.datasourceStates[state.activeDatasourceId].state; const { activeDatasourceState, activeVisualizationState } = ignoreInitialValues ? { activeDatasourceState: datasourceState, activeVisualizationState: visualizationState } : addInitialValueIfAvailable({ datasourceState, visualizationState, framePublicAPI, activeVisualization, activeDatasource, layerId, layerType }); state.visualization.state = activeVisualizationState; state.datasourceStates[state.activeDatasourceId].state = activeDatasourceState; state.stagedPreview = undefined; const { datasourceState: syncedDatasourceState, visualizationState: syncedVisualizationState } = syncLinkedDimensions((0, _toolkit.current)(state), visualizationMap, datasourceMap); state.datasourceStates[state.activeDatasourceId].state = syncedDatasourceState; state.visualization.state = syncedVisualizationState; }, [onDropToDimension.type]: (state, { payload: { source, target, dropType } }) => { var _activeVisualization$4, _ref; if (!state.visualization.activeId) { return state; } const activeVisualization = visualizationMap[state.visualization.activeId]; const framePublicAPI = (0, _selectors.selectFramePublicAPI)({ lens: (0, _toolkit.current)(state) }, datasourceMap); const { groups } = activeVisualization.getConfiguration({ layerId: target.layerId, frame: framePublicAPI, state: state.visualization.state }); const [layerDatasourceId, layerDatasource] = Object.entries(datasourceMap).find(([datasourceId, datasource]) => state.datasourceStates[datasourceId] && datasource.getLayers(state.datasourceStates[datasourceId].state).includes(target.layerId)) || []; let newDatasourceState; if (layerDatasource && layerDatasourceId) { var _groups$find; newDatasourceState = layerDatasource === null || layerDatasource === void 0 ? void 0 : layerDatasource.onDrop({ state: state.datasourceStates[layerDatasourceId].state, source, target: { ...target, filterOperations: ((_groups$find = groups.find(({ groupId: gId }) => gId === target.groupId)) === null || _groups$find === void 0 ? void 0 : _groups$find.filterOperations) || Boolean }, targetLayerDimensionGroups: groups, dropType, indexPatterns: framePublicAPI.dataViews.indexPatterns }); if (!newDatasourceState) { return; } state.datasourceStates[layerDatasourceId].state = newDatasourceState; } activeVisualization.onDrop = (_activeVisualization$4 = activeVisualization.onDrop) === null || _activeVisualization$4 === void 0 ? void 0 : _activeVisualization$4.bind(activeVisualization); const newVisualizationState = (_ref = activeVisualization.onDrop || _drop_targets_utils.onDropForVisualization) === null || _ref === void 0 ? void 0 : _ref({ prevState: state.visualization.state, frame: framePublicAPI, target, source, dropType, group: groups.find(({ groupId: gId }) => gId === target.groupId) }, activeVisualization); state.visualization.state = newVisualizationState; if (layerDatasourceId) { const { datasourceState: syncedDatasourceState, visualizationState: syncedVisualizationState } = syncLinkedDimensions((0, _toolkit.current)(state), visualizationMap, datasourceMap); state.datasourceStates[layerDatasourceId].state = syncedDatasourceState; state.visualization.state = syncedVisualizationState; } state.stagedPreview = undefined; }, [setLayerDefaultDimension.type]: (state, { payload: { layerId, columnId, groupId } }) => { if (!state.activeDatasourceId || !state.visualization.activeId) { return state; } const activeDatasource = datasourceMap[state.activeDatasourceId]; const activeVisualization = visualizationMap[state.visualization.activeId]; const layerType = activeVisualization.getLayerType(layerId, state.visualization.state) || _public.LayerTypes.DATA; const { activeDatasourceState, activeVisualizationState } = addInitialValueIfAvailable({ datasourceState: state.datasourceStates[state.activeDatasourceId].state, visualizationState: state.visualization.state, framePublicAPI: (0, _selectors.selectFramePublicAPI)({ lens: (0, _toolkit.current)(state) }, datasourceMap), activeVisualization, activeDatasource, layerId, layerType, columnId, groupId }); state.visualization.state = activeVisualizationState; state.datasourceStates[state.activeDatasourceId].state = activeDatasourceState; }, [removeDimension.type]: (state, { payload: { layerId, columnId, datasourceId } }) => { var _activeVisualization$5, _links$filter; if (!state.visualization.activeId) { return state; } const activeVisualization = visualizationMap[state.visualization.activeId]; const links = (_activeVisualization$5 = activeVisualization.getLinkedDimensions) === null || _activeVisualization$5 === void 0 ? void 0 : _activeVisualization$5.call(activeVisualization, state.visualization.state); const linkedDimensions = links === null || links === void 0 ? void 0 : (_links$filter = links.filter(({ from: { columnId: fromId } }) => columnId === fromId)) === null || _links$filter === void 0 ? void 0 : _links$filter.map(({ to }) => to); const datasource = datasourceId ? datasourceMap[datasourceId] : undefined; const frame = (0, _selectors.selectFramePublicAPI)({ lens: (0, _toolkit.current)(state) }, datasourceMap); const remove = dimensionProps => { if (datasource && datasourceId) { let datasourceState; try { datasourceState = (0, _toolkit.current)(state.datasourceStates[datasourceId].state); } catch { datasourceState = state.datasourceStates[datasourceId].state; } state.datasourceStates[datasourceId].state = datasource === null || datasource === void 0 ? void 0 : datasource.removeColumn({ layerId: dimensionProps.layerId, columnId: dimensionProps.columnId, prevState: datasourceState, indexPatterns: frame.dataViews.indexPatterns }); } let visualizationState; try { visualizationState = (0, _toolkit.current)(state.visualization.state); } catch { visualizationState = state.visualization.state; } state.visualization.state = activeVisualization.removeDimension({ layerId: dimensionProps.layerId, columnId: dimensionProps.columnId, prevState: visualizationState, frame }); }; remove({ layerId, columnId }); linkedDimensions === null || linkedDimensions === void 0 ? void 0 : linkedDimensions.forEach(linkedDimension => linkedDimension.columnId && // if there's no columnId, there's no dimension to remove remove({ columnId: linkedDimension.columnId, layerId: linkedDimension.layerId })); }, [registerLibraryAnnotationGroup.type]: (state, { payload: { group, id } }) => { state.annotationGroups[id] = group; } }); }; exports.makeLensReducer = makeLensReducer; function addInitialValueIfAvailable({ visualizationState, datasourceState, activeVisualization, activeDatasource, framePublicAPI, layerType, layerId, columnId, groupId }) { const { initialDimensions, noDatasource } = activeVisualization.getSupportedLayers(visualizationState, framePublicAPI).find(({ type }) => type === layerType) || {}; if (initialDimensions) { const info = groupId ? initialDimensions.find(({ groupId: id }) => id === groupId) : initialDimensions[0]; // pick the first available one if not passed if (info) { const activeVisualizationState = activeVisualization.setDimension({ groupId: info.groupId, layerId, columnId: columnId || info.columnId, prevState: visualizationState, frame: framePublicAPI }); if (!noDatasource && activeDatasource !== null && activeDatasource !== void 0 && activeDatasource.initializeDimension) { return { activeDatasourceState: activeDatasource.initializeDimension(datasourceState, layerId, framePublicAPI.dataViews.indexPatterns, { ...info, columnId: columnId || info.columnId, visualizationGroups: activeVisualization.getConfiguration({ layerId, frame: framePublicAPI, state: activeVisualizationState }).groups }), activeVisualizationState }; } else { return { activeDatasourceState: datasourceState, activeVisualizationState }; } } } return { activeDatasourceState: datasourceState, activeVisualizationState: visualizationState }; } function syncLinkedDimensions(state, visualizationMap, datasourceMap, _datasourceId) { var _activeVisualization$6; const datasourceId = _datasourceId !== null && _datasourceId !== void 0 ? _datasourceId : state.activeDatasourceId; if (!datasourceId) { return { datasourceState: null, visualizationState: state.visualization.state }; } const indexPatterns = (0, _selectors.selectDataViews)({ lens: state }).indexPatterns; let datasourceState = state.datasourceStates[datasourceId].state; let visualizationState = state.visualization.state; const activeVisualization = visualizationMap[state.visualization.activeId]; // TODO - double check the safety of this coercion const linkedDimensions = (_activeVisualization$6 = activeVisualization.getLinkedDimensions) === null || _activeVisualization$6 === void 0 ? void 0 : _activeVisualization$6.call(activeVisualization, visualizationState); const frame = (0, _selectors.selectFramePublicAPI)({ lens: state }, datasourceMap); const getDimensionGroups = layerId => activeVisualization.getConfiguration({ state: visualizationState, layerId, frame }).groups; if (linkedDimensions) { const idAssuredLinks = linkedDimensions.map(link => { var _link$to$columnId; return { ...link, to: { ...link.to, columnId: (_link$to$columnId = link.to.columnId) !== null && _link$to$columnId !== void 0 ? _link$to$columnId : (0, _id_generator.generateId)() } }; }); datasourceState = datasourceMap[datasourceId].syncColumns({ state: datasourceState, links: idAssuredLinks, getDimensionGroups, indexPatterns }); idAssuredLinks.forEach(({ from, to }) => { var _ref2; const dropSource = { ...from, id: from.columnId, // don't need to worry about accessibility here humanData: { label: '' } }; const dropTarget = { ...to, filterOperations: () => true }; visualizationState = (_ref2 = activeVisualization.onDrop || _drop_targets_utils.onDropForVisualization) === null || _ref2 === void 0 ? void 0 : _ref2({ prevState: visualizationState, frame, target: dropTarget, source: dropSource, dropType: 'duplicate_compatible', group: getDimensionGroups(to.layerId).find(({ groupId }) => groupId === dropTarget.groupId) }, activeVisualization); }); } return { datasourceState, visualizationState }; }