[maps] clean up maps app state (#73337)

* [maps] clean up maps app state

* remove time, query and refreshConfig from react state

* clean up

* move getInitialLayersFromUrlParam out of MapsAppView

* clean up _updateFromGlobalState to just call _onQueryChange

* inline _getAppStateFilters

* tslint cleanup and fix refresh config

* fix functional test

* fix functional tests take 2

* review feedback

* fix timing issue by not providing default query context value from props

* minor cleanup

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2020-07-30 08:37:10 -06:00 committed by GitHub
parent aa68e3b63a
commit d8d830657b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 211 additions and 308 deletions

View file

@ -14,9 +14,11 @@ import { Filter, Query, TimeRange } from 'src/plugins/data/public';
import { MapStoreState } from '../reducers/store';
import {
getDataFilters,
getFilters,
getMapSettings,
getWaitingForMapReadyLayerListRaw,
getQuery,
getTimeFilters,
} from '../selectors/map_selectors';
import {
CLEAR_GOTO,
@ -217,13 +219,13 @@ export function setQuery({
dispatch({
type: SET_QUERY,
timeFilters,
timeFilters: timeFilters ? timeFilters : getTimeFilters(getState()),
query: {
...query,
...(query ? query : getQuery(getState())),
// ensure query changes to trigger re-fetch when "Refresh" clicked
queryLastTriggeredAt: refresh ? generateQueryTimestamp() : prevTriggeredAt,
},
filters,
filters: filters ? filters : getFilters(getState()),
});
if (getMapSettings(getState()).autoFitToDataBounds) {

View file

@ -48,7 +48,7 @@ export class MapEmbeddableFactory implements EmbeddableFactoryDefinition {
const {
addLayerWithoutDataSync,
createMapStore,
getIndexPatternService,
getIndexPatternsFromIds,
getQueryableUniqueIndexPatternIds,
} = await lazyLoadMapModules();
const store = createMapStore();
@ -66,17 +66,7 @@ export class MapEmbeddableFactory implements EmbeddableFactoryDefinition {
);
}
const promises = queryableIndexPatternIds.map(async (indexPatternId) => {
try {
// @ts-ignore
return await getIndexPatternService().get(indexPatternId);
} catch (error) {
// Unable to load index pattern, better to not throw error so map embeddable can render
// Error will be surfaced by map embeddable since it too will be unable to locate the index pattern
return null;
}
});
const indexPatterns = await Promise.all(promises);
const indexPatterns = await getIndexPatternsFromIds(queryableIndexPatternIds);
return _.compact(indexPatterns) as IIndexPattern[];
}

View file

@ -30,11 +30,17 @@ export function getGeoTileAggNotSupportedReason(field: IFieldType): string | nul
export async function getIndexPatternsFromIds(
indexPatternIds: string[] = []
): Promise<IndexPattern[]> {
const promises: Array<Promise<IndexPattern>> = [];
indexPatternIds.forEach((id) => {
promises.push(getIndexPatternService().get(id));
const promises: IndexPattern[] = [];
indexPatternIds.forEach(async (indexPatternId) => {
try {
// @ts-ignore
promises.push(getIndexPatternService().get(indexPatternId));
} catch (error) {
// Unable to load index pattern, better to not throw error so map can render
// Error will be surfaced by layer since it too will be unable to locate the index pattern
return null;
}
});
return await Promise.all(promises);
}

View file

@ -8,6 +8,7 @@ import { AnyAction } from 'redux';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { IndexPatternsService } from 'src/plugins/data/public/index_patterns';
import { ReactElement } from 'react';
import { IndexPattern } from 'src/plugins/data/public';
import { Embeddable, IContainer } from '../../../../../src/plugins/embeddable/public';
import { LayerDescriptor } from '../../common/descriptor_types';
import { MapStore, MapStoreState } from '../reducers/store';
@ -44,8 +45,9 @@ interface LazyLoadedMapModules {
indexPatternId: string,
indexPatternTitle: string
) => LayerDescriptor[];
registerLayerWizard(layerWizard: LayerWizard): void;
registerLayerWizard: (layerWizard: LayerWizard) => void;
registerSource(entry: SourceRegistryEntry): void;
getIndexPatternsFromIds: (indexPatternIds: string[]) => Promise<IndexPattern[]>;
}
export async function lazyLoadMapModules(): Promise<LazyLoadedMapModules> {
@ -71,6 +73,7 @@ export async function lazyLoadMapModules(): Promise<LazyLoadedMapModules> {
createSecurityLayerDescriptors,
registerLayerWizard,
registerSource,
getIndexPatternsFromIds,
} = await import('./lazy');
resolve({
@ -88,6 +91,7 @@ export async function lazyLoadMapModules(): Promise<LazyLoadedMapModules> {
createSecurityLayerDescriptors,
registerLayerWizard,
registerSource,
getIndexPatternsFromIds,
});
});
return loadModulesPromise;

View file

@ -21,3 +21,4 @@ export * from '../../routing/maps_router';
export * from '../../classes/layers/solution_layers/security';
export { registerLayerWizard } from '../../classes/layers/layer_wizard_registry';
export { registerSource } from '../../classes/sources/source_registry';
export { getIndexPatternsFromIds } from '../../index_pattern_util';

View file

@ -3,7 +3,10 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import _ from 'lodash';
import rison from 'rison-node';
import { i18n } from '@kbn/i18n';
// Import each layer type, even those not used, to init in registry
import '../../classes/sources/wms_source';
import '../../classes/sources/ems_file_source';
@ -16,7 +19,7 @@ import { KibanaTilemapSource } from '../../classes/sources/kibana_tilemap_source
import { TileLayer } from '../../classes/layers/tile_layer/tile_layer';
import { EMSTMSSource } from '../../classes/sources/ems_tms_source';
import { VectorTileLayer } from '../../classes/layers/vector_tile_layer/vector_tile_layer';
import { getIsEmsEnabled } from '../../kibana_services';
import { getIsEmsEnabled, getToasts } from '../../kibana_services';
import { getKibanaTileMap } from '../../meta';
export function getInitialLayers(layerListJSON, initialLayers = []) {
@ -41,3 +44,33 @@ export function getInitialLayers(layerListJSON, initialLayers = []) {
return initialLayers;
}
export function getInitialLayersFromUrlParam() {
const locationSplit = window.location.href.split('?');
if (locationSplit.length <= 1) {
return [];
}
const mapAppParams = new URLSearchParams(locationSplit[1]);
if (!mapAppParams.has('initialLayers')) {
return [];
}
try {
let mapInitLayers = mapAppParams.get('initialLayers');
if (mapInitLayers[mapInitLayers.length - 1] === '#') {
mapInitLayers = mapInitLayers.substr(0, mapInitLayers.length - 1);
}
return rison.decode_array(mapInitLayers);
} catch (e) {
getToasts().addWarning({
title: i18n.translate('xpack.maps.initialLayers.unableToParseTitle', {
defaultMessage: `Initial layers not added to map`,
}),
text: i18n.translate('xpack.maps.initialLayers.unableToParseMessage', {
defaultMessage: `Unable to parse contents of 'initialLayers' parameter. Error: {errorMsg}`,
values: { errorMsg: e.message },
}),
});
return [];
}
}

View file

@ -10,20 +10,27 @@ import {
enableFullScreen,
openMapSettings,
removePreviewLayers,
setRefreshConfig,
setSelectedLayer,
updateFlyout,
} from '../../../actions';
import { FLYOUT_STATE } from '../../../reducers/ui';
import { getInspectorAdapters } from '../../../reducers/non_serializable_instances';
import { getFlyoutDisplay } from '../../../selectors/ui_selectors';
import { hasDirtyState } from '../../../selectors/map_selectors';
import {
getQuery,
getRefreshConfig,
getTimeFilters,
hasDirtyState,
} from '../../../selectors/map_selectors';
function mapStateToProps(state = {}) {
return {
isOpenSettingsDisabled: getFlyoutDisplay(state) !== FLYOUT_STATE.NONE,
inspectorAdapters: getInspectorAdapters(state),
isSaveDisabled: hasDirtyState(state),
query: getQuery(state),
refreshConfig: getRefreshConfig(state),
timeFilters: getTimeFilters(state),
};
}
@ -34,7 +41,6 @@ function mapDispatchToProps(dispatch) {
dispatch(updateFlyout(FLYOUT_STATE.NONE));
dispatch(removePreviewLayers());
},
setRefreshStoreConfig: (refreshConfig) => dispatch(setRefreshConfig(refreshConfig)),
enableFullScreen: () => dispatch(enableFullScreen()),
openMapSettings: () => dispatch(openMapSettings()),
};

View file

@ -29,18 +29,16 @@ export function MapsTopNavMenu({
onQuerySaved,
onSavedQueryUpdated,
savedQuery,
time,
timeFilters,
refreshConfig,
setRefreshConfig,
setRefreshStoreConfig,
onRefreshConfigChange,
indexPatterns,
updateFiltersAndDispatch,
onFiltersChange,
isSaveDisabled,
closeFlyout,
enableFullScreen,
openMapSettings,
inspectorAdapters,
syncAppAndGlobalState,
setBreadcrumbs,
isOpenSettingsDisabled,
}) {
@ -75,31 +73,20 @@ export function MapsTopNavMenu({
});
};
const onRefreshChange = function ({ isPaused, refreshInterval }) {
const newRefreshConfig = {
isPaused,
interval: isNaN(refreshInterval) ? refreshConfig.interval : refreshInterval,
};
setRefreshConfig(newRefreshConfig, () => {
setRefreshStoreConfig(newRefreshConfig);
syncAppAndGlobalState();
});
};
return (
<TopNavMenu
appName="maps"
config={config}
indexPatterns={indexPatterns || []}
indexPatterns={indexPatterns}
filters={filterManager.getFilters()}
query={query}
onQuerySubmit={submitQuery}
onFiltersUpdated={updateFiltersAndDispatch}
dateRangeFrom={time.from}
dateRangeTo={time.to}
onFiltersUpdated={onFiltersChange}
dateRangeFrom={timeFilters.from}
dateRangeTo={timeFilters.to}
isRefreshPaused={refreshConfig.isPaused}
refreshInterval={refreshConfig.interval}
onRefreshChange={onRefreshChange}
onRefreshChange={onRefreshConfigChange}
showSearchBar={true}
showFilterBar={true}
showDatePicker={true}

View file

@ -9,8 +9,10 @@ import { MapsAppView } from './maps_app_view';
import { getFlyoutDisplay, getIsFullScreen } from '../../../selectors/ui_selectors';
import {
getFilters,
getQuery,
getQueryableUniqueIndexPatternIds,
getRefreshConfig,
getTimeFilters,
hasUnsavedChanges,
} from '../../../selectors/map_selectors';
import {
@ -38,17 +40,19 @@ function mapStateToProps(state = {}) {
hasUnsavedChanges: (savedMap, initialLayerListConfig) => {
return hasUnsavedChanges(state, savedMap, initialLayerListConfig);
},
query: getQuery(state),
timeFilters: getTimeFilters(state),
};
}
function mapDispatchToProps(dispatch) {
return {
dispatchSetQuery: (refresh, filters, query, time) => {
dispatchSetQuery: ({ refresh, filters, query, timeFilters }) => {
dispatch(
setQuery({
filters,
query,
timeFilters: time,
timeFilters,
refresh,
})
);

View file

@ -9,15 +9,9 @@ import { i18n } from '@kbn/i18n';
import 'mapbox-gl/dist/mapbox-gl.css';
import _ from 'lodash';
import { DEFAULT_IS_LAYER_TOC_OPEN } from '../../../reducers/ui';
import {
getIndexPatternService,
getToasts,
getData,
getCoreChrome,
} from '../../../kibana_services';
import { getData, getCoreChrome } from '../../../kibana_services';
import { copyPersistentState } from '../../../reducers/util';
import { getInitialLayers } from '../../bootstrap/get_initial_layers';
import rison from 'rison-node';
import { getInitialLayers, getInitialLayersFromUrlParam } from '../../bootstrap/get_initial_layers';
import { getInitialTimeFilters } from '../../bootstrap/get_initial_time_filters';
import { getInitialRefreshConfig } from '../../bootstrap/get_initial_refresh_config';
import { getInitialQuery } from '../../bootstrap/get_initial_query';
@ -25,13 +19,14 @@ import { MapsTopNavMenu } from '../../page_elements/top_nav_menu';
import {
getGlobalState,
updateGlobalState,
useGlobalStateSyncing,
startGlobalStateSyncing,
} from '../../state_syncing/global_sync';
import { AppStateManager } from '../../state_syncing/app_state_manager';
import { useAppStateSyncing } from '../../state_syncing/app_sync';
import { startAppStateSyncing } from '../../state_syncing/app_sync';
import { esFilters } from '../../../../../../../src/plugins/data/public';
import { MapContainer } from '../../../connected_components/map_container';
import { goToSpecifiedPath } from '../../maps_router';
import { getIndexPatternsFromIds } from '../../../index_pattern_util';
const unsavedChangesWarning = i18n.translate('xpack.maps.breadCrumbs.unsavedChangesWarning', {
defaultMessage: 'Your map has unsaved changes. Are you sure you want to leave?',
@ -42,12 +37,12 @@ export class MapsAppView extends React.Component {
_globalSyncChangeMonitorSubscription = null;
_appSyncUnsubscribe = null;
_appStateManager = new AppStateManager();
_prevIndexPatternIds = null;
constructor(props) {
super(props);
this.state = {
indexPatterns: [],
prevIndexPatternIds: [],
initialized: false,
savedQuery: '',
initialLayerListConfig: null,
@ -55,21 +50,15 @@ export class MapsAppView extends React.Component {
}
componentDidMount() {
// Init sync utils
// eslint-disable-next-line react-hooks/rules-of-hooks
this._globalSyncUnsubscribe = useGlobalStateSyncing();
// eslint-disable-next-line react-hooks/rules-of-hooks
this._appSyncUnsubscribe = useAppStateSyncing(this._appStateManager);
this._isMounted = true;
this._globalSyncUnsubscribe = startGlobalStateSyncing();
this._appSyncUnsubscribe = startAppStateSyncing(this._appStateManager);
this._globalSyncChangeMonitorSubscription = getData().query.state$.subscribe(
this._updateFromGlobalState
);
// Check app state in case of refresh
const initAppState = this._appStateManager.getAppState();
this._onQueryChange(initAppState);
if (initAppState.savedQuery) {
this._updateStateFromSavedQuery(initAppState.savedQuery);
}
this._updateStateFromSavedQuery(this._appStateManager.getAppState().savedQuery);
this._initMap();
@ -86,11 +75,12 @@ export class MapsAppView extends React.Component {
}
componentDidUpdate() {
// TODO: Handle null when converting to TS
this._handleStoreChanges();
this._updateIndexPatterns();
}
componentWillUnmount() {
this._isMounted = false;
if (this._globalSyncUnsubscribe) {
this._globalSyncUnsubscribe();
}
@ -138,183 +128,96 @@ export class MapsAppView extends React.Component {
};
_updateFromGlobalState = ({ changes, state: globalState }) => {
if (!changes || !globalState) {
if (!this.state.initialized || !changes || !globalState) {
return;
}
const newState = {};
Object.keys(changes).forEach((key) => {
if (changes[key]) {
newState[key] = globalState[key];
}
});
this.setState(newState, () => {
this._appStateManager.setQueryAndFilters({
filters: getData().query.filterManager.getAppFilters(),
});
const { time, filters, refreshInterval } = globalState;
this.props.dispatchSetQuery(refreshInterval, filters, this.state.query, time);
});
this._onQueryChange({ time: globalState.time, refresh: true });
};
_getInitialLayersFromUrlParam() {
const locationSplit = window.location.href.split('?');
if (locationSplit.length <= 1) {
return [];
}
const mapAppParams = new URLSearchParams(locationSplit[1]);
if (!mapAppParams.has('initialLayers')) {
return [];
}
try {
let mapInitLayers = mapAppParams.get('initialLayers');
if (mapInitLayers[mapInitLayers.length - 1] === '#') {
mapInitLayers = mapInitLayers.substr(0, mapInitLayers.length - 1);
}
return rison.decode_array(mapInitLayers);
} catch (e) {
getToasts().addWarning({
title: i18n.translate('xpack.maps.initialLayers.unableToParseTitle', {
defaultMessage: `Initial layers not added to map`,
}),
text: i18n.translate('xpack.maps.initialLayers.unableToParseMessage', {
defaultMessage: `Unable to parse contents of 'initialLayers' parameter. Error: {errorMsg}`,
values: { errorMsg: e.message },
}),
});
return [];
}
}
async _updateIndexPatterns(nextIndexPatternIds) {
const indexPatterns = [];
const getIndexPatternPromises = nextIndexPatternIds.map(async (indexPatternId) => {
try {
const indexPattern = await getIndexPatternService().get(indexPatternId);
indexPatterns.push(indexPattern);
} catch (err) {
// unable to fetch index pattern
}
});
await Promise.all(getIndexPatternPromises);
this.setState({
indexPatterns,
});
}
_handleStoreChanges = () => {
const { prevIndexPatternIds } = this.state;
async _updateIndexPatterns() {
const { nextIndexPatternIds } = this.props;
if (nextIndexPatternIds !== prevIndexPatternIds) {
this.setState({ prevIndexPatternIds: nextIndexPatternIds });
this._updateIndexPatterns(nextIndexPatternIds);
if (_.isEqual(nextIndexPatternIds, this._prevIndexPatternIds)) {
return;
}
};
_getAppStateFilters = () => {
return this._appStateManager.getFilters() || [];
};
this._prevIndexPatternIds = nextIndexPatternIds;
_syncAppAndGlobalState = () => {
const { query, time, initialized } = this.state;
const { refreshConfig } = this.props;
const indexPatterns = await getIndexPatternsFromIds(nextIndexPatternIds);
if (this._isMounted) {
this.setState({ indexPatterns });
}
}
_onQueryChange = ({ filters, query, time, refresh = false }) => {
const { filterManager } = getData().query;
// appState
this._appStateManager.setQueryAndFilters({
query: query,
filters: filterManager.getAppFilters(),
});
// globalState
const refreshInterval = {
pause: refreshConfig.isPaused,
value: refreshConfig.interval,
};
updateGlobalState(
{
time: time,
refreshInterval,
filters: filterManager.getGlobalFilters(),
},
!initialized
);
this.setState({ refreshInterval });
};
_onQueryChange = async ({ filters, query, time, refresh }) => {
const { filterManager } = getData().query;
const { dispatchSetQuery } = this.props;
const newState = {};
let newFilters;
if (filters) {
filterManager.setFilters(filters); // Maps and merges filters
newFilters = filterManager.getFilters();
filterManager.setFilters(filters);
}
if (query) {
newState.query = query;
}
if (time) {
newState.time = time;
}
this.setState(newState, () => {
this._syncAppAndGlobalState();
dispatchSetQuery(
refresh,
newFilters || this.props.filters,
query || this.state.query,
time || this.state.time
);
this.props.dispatchSetQuery({
refresh,
filters: filterManager.getFilters(),
query,
timeFilters: time,
});
// sync appState
this._appStateManager.setQueryAndFilters({
filters: filterManager.getAppFilters(),
query,
});
// sync globalState
const updatedGlobalState = { filters: filterManager.getGlobalFilters() };
if (time) {
updatedGlobalState.time = time;
}
updateGlobalState(updatedGlobalState, !this.state.initialized);
};
_initQueryTimeRefresh() {
const { setRefreshConfig, savedMap } = this.props;
const { queryString } = getData().query;
// TODO: Handle null when converting to TS
_initMapAndLayerSettings() {
const globalState = getGlobalState();
const mapStateJSON = savedMap ? savedMap.mapStateJSON : undefined;
const newState = {
query: getInitialQuery({
mapStateJSON,
appState: this._appStateManager.getAppState(),
}),
const mapStateJSON = this.props.savedMap.mapStateJSON;
let savedObjectFilters = [];
if (mapStateJSON) {
const mapState = JSON.parse(mapStateJSON);
if (mapState.filters) {
savedObjectFilters = mapState.filters;
}
}
const appFilters = this._appStateManager.getFilters() || [];
const query = getInitialQuery({
mapStateJSON,
appState: this._appStateManager.getAppState(),
});
if (query) {
getData().query.queryString.setQuery(query);
}
this._onQueryChange({
filters: [..._.get(globalState, 'filters', []), ...appFilters, ...savedObjectFilters],
query,
time: getInitialTimeFilters({
mapStateJSON,
globalState,
}),
refreshConfig: getInitialRefreshConfig({
});
this._onRefreshConfigChange(
getInitialRefreshConfig({
mapStateJSON,
globalState,
}),
};
if (newState.query) queryString.setQuery(newState.query);
this.setState({ query: newState.query, time: newState.time });
updateGlobalState(
{
time: newState.time,
refreshInterval: {
value: newState.refreshConfig.interval,
pause: newState.refreshConfig.isPaused,
},
},
!this.state.initialized
})
);
setRefreshConfig(newState.refreshConfig);
}
_initMapAndLayerSettings() {
const { savedMap } = this.props;
// Get saved map & layer settings
this._initQueryTimeRefresh();
const layerList = getInitialLayers(
savedMap.layerListJSON,
this._getInitialLayersFromUrlParam()
this.props.savedMap.layerListJSON,
getInitialLayersFromUrlParam()
);
this.props.replaceLayerList(layerList);
this.setState({
@ -322,20 +225,31 @@ export class MapsAppView extends React.Component {
});
}
_updateFiltersAndDispatch = (filters) => {
_onFiltersChange = (filters) => {
this._onQueryChange({
filters,
});
};
_onRefreshChange = ({ isPaused, refreshInterval }) => {
const { refreshConfig } = this.props;
const newRefreshConfig = {
// mapRefreshConfig: MapRefreshConfig
_onRefreshConfigChange(mapRefreshConfig) {
this.props.setRefreshConfig(mapRefreshConfig);
updateGlobalState(
{
refreshInterval: {
pause: mapRefreshConfig.isPaused,
value: mapRefreshConfig.interval,
},
},
!this.state.initialized
);
}
_onTopNavRefreshConfig = ({ isPaused, refreshInterval }) => {
this._onRefreshConfigChange({
isPaused,
interval: isNaN(refreshInterval) ? refreshConfig.interval : refreshInterval,
};
this.setState({ refreshConfig: newRefreshConfig }, this._syncAppAndGlobalState);
this.props.setRefreshConfig(newRefreshConfig);
interval: refreshInterval,
});
};
_updateStateFromSavedQuery(savedQuery) {
@ -348,98 +262,55 @@ export class MapsAppView extends React.Component {
const globalFilters = filterManager.getGlobalFilters();
const allFilters = [...savedQueryFilters, ...globalFilters];
if (savedQuery.attributes.timefilter) {
if (savedQuery.attributes.timefilter.refreshInterval) {
this._onRefreshChange({
isPaused: savedQuery.attributes.timefilter.refreshInterval.pause,
refreshInterval: savedQuery.attributes.timefilter.refreshInterval.value,
});
}
this._onQueryChange({
filters: allFilters,
query: savedQuery.attributes.query,
time: savedQuery.attributes.timefilter,
});
} else {
this._onQueryChange({
filters: allFilters,
query: savedQuery.attributes.query,
const refreshInterval = _.get(savedQuery, 'attributes.timefilter.refreshInterval');
if (refreshInterval) {
this._onRefreshConfigChange({
isPaused: refreshInterval.pause,
interval: refreshInterval.value,
});
}
this._onQueryChange({
filters: allFilters,
query: savedQuery.attributes.query,
time: savedQuery.attributes.timefilter,
});
}
_syncStoreAndGetFilters() {
const {
savedMap,
setGotoWithCenter,
setMapSettings,
setIsLayerTOCOpen,
setOpenTOCDetails,
} = this.props;
let savedObjectFilters = [];
if (savedMap.mapStateJSON) {
const mapState = JSON.parse(savedMap.mapStateJSON);
setGotoWithCenter({
_initMap() {
this._initMapAndLayerSettings();
this.props.clearUi();
if (this.props.savedMap.mapStateJSON) {
const mapState = JSON.parse(this.props.savedMap.mapStateJSON);
this.props.setGotoWithCenter({
lat: mapState.center.lat,
lon: mapState.center.lon,
zoom: mapState.zoom,
});
if (mapState.filters) {
savedObjectFilters = mapState.filters;
}
if (mapState.settings) {
setMapSettings(mapState.settings);
this.props.setMapSettings(mapState.settings);
}
}
if (savedMap.uiStateJSON) {
const uiState = JSON.parse(savedMap.uiStateJSON);
setIsLayerTOCOpen(_.get(uiState, 'isLayerTOCOpen', DEFAULT_IS_LAYER_TOC_OPEN));
setOpenTOCDetails(_.get(uiState, 'openTOCDetails', []));
if (this.props.savedMap.uiStateJSON) {
const uiState = JSON.parse(this.props.savedMap.uiStateJSON);
this.props.setIsLayerTOCOpen(_.get(uiState, 'isLayerTOCOpen', DEFAULT_IS_LAYER_TOC_OPEN));
this.props.setOpenTOCDetails(_.get(uiState, 'openTOCDetails', []));
}
return savedObjectFilters;
}
async _initMap() {
const { clearUi, savedMap } = this.props;
// TODO: Handle null when converting to TS
const globalState = getGlobalState();
this._initMapAndLayerSettings();
clearUi();
const savedObjectFilters = this._syncStoreAndGetFilters(savedMap);
await this._onQueryChange({
filters: [
..._.get(globalState, 'filters', []),
...this._getAppStateFilters(),
...savedObjectFilters,
],
});
this.setState({ initialized: true });
}
_renderTopNav() {
const { query, time, savedQuery, indexPatterns } = this.state;
const { savedMap, refreshConfig, isFullScreen } = this.props;
return !isFullScreen ? (
return !this.props.isFullScreen ? (
<MapsTopNavMenu
savedMap={savedMap}
query={query}
savedQuery={savedQuery}
savedMap={this.props.savedMap}
savedQuery={this.state.savedQuery}
onQueryChange={this._onQueryChange}
time={time}
refreshConfig={refreshConfig}
setRefreshConfig={(newConfig, callback) => {
this.setState(
{
refreshConfig: newConfig,
},
callback
);
}}
indexPatterns={indexPatterns}
updateFiltersAndDispatch={this._updateFiltersAndDispatch}
onRefreshConfigChange={this._onTopNavRefreshConfig}
indexPatterns={this.state.indexPatterns}
onFiltersChange={this._onFiltersChange}
onQuerySaved={(query) => {
this.setState({ savedQuery: query });
this._appStateManager.setQueryAndFilters({ savedQuery: query });
@ -450,7 +321,6 @@ export class MapsAppView extends React.Component {
this._appStateManager.setQueryAndFilters({ savedQuery: query });
this._updateStateFromSavedQuery(query);
}}
syncAppAndGlobalState={this._syncAppAndGlobalState}
setBreadcrumbs={this._setBreadcrumbs}
/>
) : null;
@ -469,7 +339,7 @@ export class MapsAppView extends React.Component {
newFilters.forEach((filter) => {
filter.$state = { store: esFilters.FilterStateStore.APP_STATE };
});
this._updateFiltersAndDispatch([...filters, ...newFilters]);
this._onFiltersChange([...filters, ...newFilters]);
}}
/>
</div>

View file

@ -14,13 +14,13 @@ export class AppStateManager {
_updated$ = new Subject();
setQueryAndFilters({ query, savedQuery, filters }) {
if (this._query !== query) {
if (query && this._query !== query) {
this._query = query;
}
if (this._savedQuery !== savedQuery) {
if (savedQuery && this._savedQuery !== savedQuery) {
this._savedQuery = savedQuery;
}
if (this._filters !== filters) {
if (filters && this._filters !== filters) {
this._filters = filters;
}
this._updated$.next();

View file

@ -10,7 +10,7 @@ import { map } from 'rxjs/operators';
import { getData } from '../../kibana_services';
import { kbnUrlStateStorage } from '../maps_router';
export function useAppStateSyncing(appStateManager) {
export function startAppStateSyncing(appStateManager) {
// get appStateContainer
// sync app filters with app state container from data.query to state container
const { query } = getData();

View file

@ -9,7 +9,7 @@ import { getData } from '../../kibana_services';
// @ts-ignore
import { kbnUrlStateStorage } from '../maps_router';
export function useGlobalStateSyncing() {
export function startGlobalStateSyncing() {
const { stop } = syncQueryStateWithUrl(getData().query, kbnUrlStateStorage);
return stop;
}