mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[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:
parent
aa68e3b63a
commit
d8d830657b
13 changed files with 211 additions and 308 deletions
|
@ -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) {
|
||||
|
|
|
@ -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[];
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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 [];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()),
|
||||
};
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue