"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getState = getState; exports.isEqualFilters = isEqualFilters; var _lodash = require("lodash"); var _esQuery = require("@kbn/es-query"); var _public = require("@kbn/kibana-utils-plugin/public"); var _public2 = require("@kbn/data-plugin/public"); var _get_valid_filters = require("../../../utils/get_valid_filters"); var _state_helpers = require("../../../utils/state_helpers"); /* * 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 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ const GLOBAL_STATE_URL_KEY = '_g'; const APP_STATE_URL_KEY = '_a'; /** * Builds and returns appState and globalState containers * provides helper functions to start/stop syncing with URL */ function getState({ defaultSize, storeInSessionStorage = false, history, toasts, uiSettings, data, dataView }) { const stateStorage = (0, _public.createKbnUrlStateStorage)({ useHash: storeInSessionStorage, history, ...(toasts && (0, _public.withNotifyOnErrors)(toasts)) }); const globalStateFromUrl = stateStorage.get(GLOBAL_STATE_URL_KEY); const globalStateInitial = createInitialGlobalState(globalStateFromUrl); const globalStateContainer = (0, _public.createStateContainer)(globalStateInitial); const appStateFromUrl = stateStorage.get(APP_STATE_URL_KEY); const appStateInitial = createInitialAppState(defaultSize, appStateFromUrl, uiSettings); const appStateContainer = (0, _public.createStateContainer)(appStateInitial); const getAllFilters = () => [...getFilters(globalStateContainer.getState()), ...getFilters(appStateContainer.getState())]; const { start: startSyncingStates, stop: stopSyncingStates } = (0, _public.syncStates)([{ storageKey: GLOBAL_STATE_URL_KEY, stateContainer: { ...globalStateContainer, ...{ set: value => { if (value) { globalStateContainer.set(value); } } } }, stateStorage }, { storageKey: APP_STATE_URL_KEY, stateContainer: { ...appStateContainer, ...{ set: value => { if (value) { appStateContainer.set(value); } } } }, stateStorage }]); let stopSyncingFilters = () => {}; return { globalState: globalStateContainer, appState: appStateContainer, startSync: () => { // some filters may not be valid for this context, so update // the filter manager with a modified list of valid filters data.query.filterManager.setFilters((0, _get_valid_filters.getValidFilters)(dataView, getAllFilters())); const stopSyncingAppFilters = (0, _public2.connectToQueryState)(data.query, appStateContainer, { filters: _esQuery.FilterStateStore.APP_STATE }); const stopSyncingGlobalFilters = (0, _public2.connectToQueryState)(data.query, globalStateContainer, { filters: _esQuery.FilterStateStore.GLOBAL_STATE }); stopSyncingFilters = () => { stopSyncingAppFilters(); stopSyncingGlobalFilters(); }; startSyncingStates(); }, stopSync: () => { stopSyncingFilters(); stopSyncingFilters = () => {}; stopSyncingStates(); }, setAppState: newState => { const oldState = appStateContainer.getState(); const mergedState = { ...oldState, ...newState }; if (!isEqualState(oldState, mergedState)) { stateStorage.set(APP_STATE_URL_KEY, mergedState, { replace: true }); } }, getFilters: getAllFilters, setFilters: filterManager => { // global state filters const globalFilters = filterManager.getGlobalFilters(); const globalFilterChanged = !isEqualFilters(globalFilters, getFilters(globalStateContainer.getState())); if (globalFilterChanged) { globalStateContainer.set({ filters: globalFilters }); } // app state filters const appFilters = filterManager.getAppFilters(); const appFilterChanged = !isEqualFilters(appFilters, getFilters(appStateContainer.getState())); if (appFilterChanged) { appStateContainer.set({ ...appStateContainer.getState(), ...{ filters: appFilters } }); } }, // helper function just needed for testing flushToUrl: replace => stateStorage.kbnUrlControls.flush(replace) }; } /** * Helper function to compare 2 different filter states */ function isEqualFilters(filtersA, filtersB) { if (!filtersA && !filtersB) { return true; } else if (!filtersA || !filtersB) { return false; } return (0, _esQuery.compareFilters)(filtersA, filtersB, _esQuery.COMPARE_ALL_OPTIONS); } /** * Helper function to compare 2 different states, is needed since comparing filters * works differently, doesn't work with _.isEqual */ function isEqualState(stateA, stateB) { if (!stateA && !stateB) { return true; } else if (!stateA || !stateB) { return false; } const { filters: stateAFilters = [], ...stateAPartial } = stateA; const { filters: stateBFilters = [], ...stateBPartial } = stateB; return (0, _lodash.isEqual)(stateAPartial, stateBPartial) && (0, _esQuery.compareFilters)(stateAFilters, stateBFilters, _esQuery.COMPARE_ALL_OPTIONS); } /** * Helper function to return array of filter object of a given state */ function getFilters(state) { if (!state || !Array.isArray(state.filters)) { return []; } return state.filters; } /** * Helper function to return the initial app state, which is a merged object of url state and * default state. The default size is the default number of successor/predecessor records to fetch */ function createInitialAppState(defaultSize, urlState, uiSettings) { const defaultState = { columns: ['_source'], filters: [], predecessorCount: defaultSize, successorCount: defaultSize }; if (typeof urlState !== 'object') { return defaultState; } return (0, _state_helpers.handleSourceColumnState)({ ...defaultState, ...urlState }, uiSettings); } /** * Helper function to return the initial global state, which is a merged object of url state and * default state */ function createInitialGlobalState(urlState) { const defaultState = { filters: [] }; if (typeof urlState !== 'object') { return defaultState; } return { ...defaultState, ...urlState }; }