mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Maps] Add force-refresh toggle (#104691)
Adds the ability for users to control whether a layer should refresh on auto-update or when the refresh-button is clicked. This is required to display static layers from geo-data indexed in Elasticsearch.
This commit is contained in:
parent
c51c92cd7a
commit
c006c82db9
55 changed files with 536 additions and 422 deletions
|
@ -11,6 +11,7 @@ export const mockLayerList = [
|
|||
{
|
||||
leftField: 'iso2',
|
||||
right: {
|
||||
applyForceRefresh: true,
|
||||
applyGlobalQuery: true,
|
||||
applyGlobalTime: true,
|
||||
type: 'ES_TERM_SOURCE',
|
||||
|
@ -86,6 +87,7 @@ export const mockLayerList = [
|
|||
{
|
||||
leftField: 'region_iso_code',
|
||||
right: {
|
||||
applyForceRefresh: true,
|
||||
applyGlobalQuery: true,
|
||||
applyGlobalTime: true,
|
||||
type: 'ES_TERM_SOURCE',
|
||||
|
|
|
@ -45,6 +45,7 @@ const ES_TERM_SOURCE_COUNTRY: ESTermSourceDescriptor = {
|
|||
indexPatternId: APM_STATIC_INDEX_PATTERN_ID,
|
||||
applyGlobalQuery: true,
|
||||
applyGlobalTime: true,
|
||||
applyForceRefresh: true,
|
||||
};
|
||||
|
||||
const ES_TERM_SOURCE_REGION: ESTermSourceDescriptor = {
|
||||
|
@ -60,6 +61,7 @@ const ES_TERM_SOURCE_REGION: ESTermSourceDescriptor = {
|
|||
indexPatternId: APM_STATIC_INDEX_PATTERN_ID,
|
||||
applyGlobalQuery: true,
|
||||
applyGlobalTime: true,
|
||||
applyForceRefresh: true,
|
||||
};
|
||||
|
||||
const getWhereQuery = (serviceName: string) => {
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
/* eslint-disable @typescript-eslint/consistent-type-definitions */
|
||||
|
||||
import { Query } from 'src/plugins/data/public';
|
||||
import type { Query } from 'src/plugins/data/common';
|
||||
import { SortDirection } from 'src/plugins/data/common/search';
|
||||
import { RENDER_AS, SCALING_TYPES } from '../constants';
|
||||
import { MapExtent, MapQuery } from './map_descriptor';
|
||||
import { MapExtent } from './map_descriptor';
|
||||
import { Filter, TimeRange } from '../../../../../src/plugins/data/common';
|
||||
import { ESTermSourceDescriptor } from './source_descriptor_types';
|
||||
|
||||
|
@ -20,12 +20,11 @@ export type Timeslice = {
|
|||
};
|
||||
|
||||
// Global map state passed to every layer.
|
||||
export type MapFilters = {
|
||||
export type DataFilters = {
|
||||
buffer?: MapExtent; // extent with additional buffer
|
||||
extent?: MapExtent; // map viewport
|
||||
filters: Filter[];
|
||||
query?: MapQuery;
|
||||
refreshTimerLastTriggeredAt?: string;
|
||||
query?: Query;
|
||||
searchSessionId?: string;
|
||||
timeFilters: TimeRange;
|
||||
timeslice?: Timeslice;
|
||||
|
@ -60,24 +59,24 @@ export type VectorSourceSyncMeta =
|
|||
| ESTermSourceSyncMeta
|
||||
| null;
|
||||
|
||||
export type VectorSourceRequestMeta = MapFilters & {
|
||||
export type VectorSourceRequestMeta = DataFilters & {
|
||||
applyGlobalQuery: boolean;
|
||||
applyGlobalTime: boolean;
|
||||
applyForceRefresh: boolean;
|
||||
fieldNames: string[];
|
||||
geogridPrecision?: number;
|
||||
timesiceMaskField?: string;
|
||||
sourceQuery?: MapQuery;
|
||||
sourceMeta: VectorSourceSyncMeta;
|
||||
};
|
||||
|
||||
export type VectorJoinSourceRequestMeta = Omit<VectorSourceRequestMeta, 'geogridPrecision'> & {
|
||||
timesliceMaskField?: string;
|
||||
sourceQuery?: Query;
|
||||
sourceMeta: VectorSourceSyncMeta;
|
||||
isForceRefresh: boolean;
|
||||
};
|
||||
|
||||
export type VectorStyleRequestMeta = MapFilters & {
|
||||
export type VectorJoinSourceRequestMeta = Omit<VectorSourceRequestMeta, 'geogridPrecision'>;
|
||||
|
||||
export type VectorStyleRequestMeta = DataFilters & {
|
||||
dynamicStyleFields: string[];
|
||||
isTimeAware: boolean;
|
||||
sourceQuery: MapQuery;
|
||||
sourceQuery: Query;
|
||||
timeFilters: TimeRange;
|
||||
};
|
||||
|
||||
|
@ -107,7 +106,7 @@ export type VectorTileLayerMeta = {
|
|||
};
|
||||
|
||||
// Partial because objects are justified downstream in constructors
|
||||
export type DataMeta = Partial<
|
||||
export type DataRequestMeta = Partial<
|
||||
VectorSourceRequestMeta &
|
||||
VectorJoinSourceRequestMeta &
|
||||
VectorStyleRequestMeta &
|
||||
|
@ -134,8 +133,8 @@ export type StyleMetaData = {
|
|||
|
||||
export type DataRequestDescriptor = {
|
||||
dataId: string;
|
||||
dataMetaAtStart?: DataMeta | null;
|
||||
dataRequestMetaAtStart?: DataRequestMeta | null;
|
||||
dataRequestToken?: symbol;
|
||||
data?: object;
|
||||
dataMeta?: DataMeta;
|
||||
dataRequestMeta?: DataRequestMeta;
|
||||
};
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
import { ReactNode } from 'react';
|
||||
import { GeoJsonProperties } from 'geojson';
|
||||
import { Geometry } from 'geojson';
|
||||
import { Query } from '../../../../../src/plugins/data/common';
|
||||
import { DRAW_SHAPE, ES_SPATIAL_RELATIONS } from '../constants';
|
||||
|
||||
export type MapExtent = {
|
||||
|
@ -20,10 +19,6 @@ export type MapExtent = {
|
|||
maxLat: number;
|
||||
};
|
||||
|
||||
export type MapQuery = Query & {
|
||||
queryLastTriggeredAt?: string;
|
||||
};
|
||||
|
||||
export type MapCenter = {
|
||||
lat: number;
|
||||
lon: number;
|
||||
|
|
|
@ -42,6 +42,7 @@ export type AbstractESSourceDescriptor = AbstractSourceDescriptor & {
|
|||
geoField?: string;
|
||||
applyGlobalQuery: boolean;
|
||||
applyGlobalTime: boolean;
|
||||
applyForceRefresh: boolean;
|
||||
};
|
||||
|
||||
type AbstractAggDescriptor = {
|
||||
|
|
|
@ -45,22 +45,28 @@ import {
|
|||
} from './map_action_constants';
|
||||
import { ILayer } from '../classes/layers/layer';
|
||||
import { IVectorLayer } from '../classes/layers/vector_layer';
|
||||
import { DataMeta, MapExtent, MapFilters } from '../../common/descriptor_types';
|
||||
import { DataRequestMeta, MapExtent, DataFilters } from '../../common/descriptor_types';
|
||||
import { DataRequestAbortError } from '../classes/util/data_request';
|
||||
import { scaleBounds, turfBboxToBounds } from '../../common/elasticsearch_util';
|
||||
|
||||
const FIT_TO_BOUNDS_SCALE_FACTOR = 0.1;
|
||||
|
||||
export type DataRequestContext = {
|
||||
startLoading(dataId: string, requestToken: symbol, requestMeta?: DataMeta): void;
|
||||
stopLoading(dataId: string, requestToken: symbol, data: object, resultsMeta?: DataMeta): void;
|
||||
startLoading(dataId: string, requestToken: symbol, requestMeta?: DataRequestMeta): void;
|
||||
stopLoading(
|
||||
dataId: string,
|
||||
requestToken: symbol,
|
||||
data: object,
|
||||
resultsMeta?: DataRequestMeta
|
||||
): void;
|
||||
onLoadError(dataId: string, requestToken: symbol, errorMessage: string): void;
|
||||
onJoinError(errorMessage: string): void;
|
||||
updateSourceData(newData: unknown): void;
|
||||
isRequestStillActive(dataId: string, requestToken: symbol): boolean;
|
||||
registerCancelCallback(requestToken: symbol, callback: () => void): void;
|
||||
dataFilters: MapFilters;
|
||||
forceRefresh: boolean;
|
||||
dataFilters: DataFilters;
|
||||
forceRefreshDueToDrawing: boolean; // Boolean signaling data request triggered by a user updating layer features via drawing tools. When true, layer will re-load regardless of "source.applyForceRefresh" flag.
|
||||
isForceRefresh: boolean; // Boolean signaling data request triggered by auto-refresh timer or user clicking refresh button. When true, layer will re-load only when "source.applyForceRefresh" flag is set to true.
|
||||
};
|
||||
|
||||
export function clearDataRequests(layer: ILayer) {
|
||||
|
@ -112,13 +118,14 @@ function getDataRequestContext(
|
|||
dispatch: ThunkDispatch<MapStoreState, void, AnyAction>,
|
||||
getState: () => MapStoreState,
|
||||
layerId: string,
|
||||
forceRefresh: boolean = false
|
||||
forceRefreshDueToDrawing: boolean,
|
||||
isForceRefresh: boolean
|
||||
): DataRequestContext {
|
||||
return {
|
||||
dataFilters: getDataFilters(getState()),
|
||||
startLoading: (dataId: string, requestToken: symbol, meta: DataMeta) =>
|
||||
startLoading: (dataId: string, requestToken: symbol, meta: DataRequestMeta) =>
|
||||
dispatch(startDataLoad(layerId, dataId, requestToken, meta)),
|
||||
stopLoading: (dataId: string, requestToken: symbol, data: object, meta: DataMeta) =>
|
||||
stopLoading: (dataId: string, requestToken: symbol, data: object, meta: DataRequestMeta) =>
|
||||
dispatch(endDataLoad(layerId, dataId, requestToken, data, meta)),
|
||||
onLoadError: (dataId: string, requestToken: symbol, errorMessage: string) =>
|
||||
dispatch(onDataLoadError(layerId, dataId, requestToken, errorMessage)),
|
||||
|
@ -136,17 +143,18 @@ function getDataRequestContext(
|
|||
},
|
||||
registerCancelCallback: (requestToken: symbol, callback: () => void) =>
|
||||
dispatch(registerCancelCallback(requestToken, callback)),
|
||||
forceRefresh,
|
||||
forceRefreshDueToDrawing,
|
||||
isForceRefresh,
|
||||
};
|
||||
}
|
||||
|
||||
export function syncDataForAllLayers() {
|
||||
export function syncDataForAllLayers(isForceRefresh: boolean) {
|
||||
return async (
|
||||
dispatch: ThunkDispatch<MapStoreState, void, AnyAction>,
|
||||
getState: () => MapStoreState
|
||||
) => {
|
||||
const syncPromises = getLayerList(getState()).map((layer) => {
|
||||
return dispatch(syncDataForLayer(layer));
|
||||
return dispatch(syncDataForLayer(layer, isForceRefresh));
|
||||
});
|
||||
await Promise.all(syncPromises);
|
||||
};
|
||||
|
@ -162,19 +170,20 @@ function syncDataForAllJoinLayers() {
|
|||
return 'hasJoins' in layer ? (layer as IVectorLayer).hasJoins() : false;
|
||||
})
|
||||
.map((layer) => {
|
||||
return dispatch(syncDataForLayer(layer));
|
||||
return dispatch(syncDataForLayer(layer, false));
|
||||
});
|
||||
await Promise.all(syncPromises);
|
||||
};
|
||||
}
|
||||
|
||||
export function syncDataForLayer(layer: ILayer, forceRefresh: boolean = false) {
|
||||
export function syncDataForLayerDueToDrawing(layer: ILayer) {
|
||||
return async (dispatch: Dispatch, getState: () => MapStoreState) => {
|
||||
const dataRequestContext = getDataRequestContext(
|
||||
dispatch,
|
||||
getState,
|
||||
layer.getId(),
|
||||
forceRefresh
|
||||
true,
|
||||
false
|
||||
);
|
||||
if (!layer.isVisible() || !layer.showAtZoomLevel(dataRequestContext.dataFilters.zoom)) {
|
||||
return;
|
||||
|
@ -183,14 +192,30 @@ export function syncDataForLayer(layer: ILayer, forceRefresh: boolean = false) {
|
|||
};
|
||||
}
|
||||
|
||||
export function syncDataForLayerId(layerId: string | null) {
|
||||
export function syncDataForLayer(layer: ILayer, isForceRefresh: boolean) {
|
||||
return async (dispatch: Dispatch, getState: () => MapStoreState) => {
|
||||
const dataRequestContext = getDataRequestContext(
|
||||
dispatch,
|
||||
getState,
|
||||
layer.getId(),
|
||||
false,
|
||||
isForceRefresh
|
||||
);
|
||||
if (!layer.isVisible() || !layer.showAtZoomLevel(dataRequestContext.dataFilters.zoom)) {
|
||||
return;
|
||||
}
|
||||
await layer.syncData(dataRequestContext);
|
||||
};
|
||||
}
|
||||
|
||||
export function syncDataForLayerId(layerId: string | null, isForceRefresh: boolean) {
|
||||
return async (
|
||||
dispatch: ThunkDispatch<MapStoreState, void, AnyAction>,
|
||||
getState: () => MapStoreState
|
||||
) => {
|
||||
const layer = getLayerById(layerId, getState());
|
||||
if (layer) {
|
||||
dispatch(syncDataForLayer(layer));
|
||||
dispatch(syncDataForLayer(layer, isForceRefresh));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -204,7 +229,12 @@ function setLayerDataLoadErrorStatus(layerId: string, errorMessage: string | nul
|
|||
};
|
||||
}
|
||||
|
||||
function startDataLoad(layerId: string, dataId: string, requestToken: symbol, meta: DataMeta) {
|
||||
function startDataLoad(
|
||||
layerId: string,
|
||||
dataId: string,
|
||||
requestToken: symbol,
|
||||
meta: DataRequestMeta
|
||||
) {
|
||||
return (
|
||||
dispatch: ThunkDispatch<MapStoreState, void, AnyAction>,
|
||||
getState: () => MapStoreState
|
||||
|
@ -237,7 +267,7 @@ function endDataLoad(
|
|||
dataId: string,
|
||||
requestToken: symbol,
|
||||
data: object,
|
||||
meta: DataMeta
|
||||
meta: DataRequestMeta
|
||||
) {
|
||||
return (
|
||||
dispatch: ThunkDispatch<MapStoreState, void, AnyAction>,
|
||||
|
@ -342,7 +372,7 @@ export function fitToLayerExtent(layerId: string) {
|
|||
if (targetLayer) {
|
||||
try {
|
||||
const bounds = await targetLayer.getBounds(
|
||||
getDataRequestContext(dispatch, getState, layerId)
|
||||
getDataRequestContext(dispatch, getState, layerId, false, false)
|
||||
);
|
||||
if (bounds) {
|
||||
await dispatch(setGotoWithBounds(scaleBounds(bounds, FIT_TO_BOUNDS_SCALE_FACTOR)));
|
||||
|
@ -374,7 +404,9 @@ export function fitToDataBounds(onNoBounds?: () => void) {
|
|||
if (!(await layer.isFittable())) {
|
||||
return null;
|
||||
}
|
||||
return layer.getBounds(getDataRequestContext(dispatch, getState, layer.getId()));
|
||||
return layer.getBounds(
|
||||
getDataRequestContext(dispatch, getState, layer.getId(), false, false)
|
||||
);
|
||||
});
|
||||
|
||||
let bounds;
|
||||
|
@ -442,7 +474,7 @@ export function autoFitToBounds() {
|
|||
// Ensure layer syncing occurs when setGotoWithBounds is not triggered.
|
||||
function onNoBounds() {
|
||||
if (localSetQueryCallId === lastSetQueryCallId) {
|
||||
dispatch(syncDataForAllLayers());
|
||||
dispatch(syncDataForAllLayers(false));
|
||||
}
|
||||
}
|
||||
dispatch(fitToDataBounds(onNoBounds));
|
||||
|
|
|
@ -80,7 +80,7 @@ export function rollbackToTrackedLayerStateForSelectedLayer() {
|
|||
// syncDataForLayer may not trigger endDataLoad if no re-fetch is required
|
||||
dispatch(updateStyleMeta(layerId));
|
||||
|
||||
dispatch(syncDataForLayerId(layerId));
|
||||
dispatch(syncDataForLayerId(layerId, false));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ export function addLayer(layerDescriptor: LayerDescriptor) {
|
|||
type: ADD_LAYER,
|
||||
layer: layerDescriptor,
|
||||
});
|
||||
dispatch(syncDataForLayerId(layerDescriptor.id));
|
||||
dispatch(syncDataForLayerId(layerDescriptor.id, false));
|
||||
|
||||
const layer = createLayerInstance(layerDescriptor);
|
||||
const features = await layer.getLicensedFeatures();
|
||||
|
@ -226,7 +226,7 @@ export function setLayerVisibility(layerId: string, makeVisible: boolean) {
|
|||
visibility: makeVisible,
|
||||
});
|
||||
if (makeVisible) {
|
||||
dispatch(syncDataForLayerId(layerId));
|
||||
dispatch(syncDataForLayerId(layerId, false));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -330,7 +330,7 @@ function updateMetricsProp(layerId: string, value: unknown) {
|
|||
value,
|
||||
});
|
||||
await dispatch(updateStyleProperties(layerId, previousFields as IESAggField[]));
|
||||
dispatch(syncDataForLayerId(layerId));
|
||||
dispatch(syncDataForLayerId(layerId, false));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -356,7 +356,7 @@ export function updateSourceProp(
|
|||
if (newLayerType) {
|
||||
dispatch(updateLayerType(layerId, newLayerType));
|
||||
}
|
||||
dispatch(syncDataForLayerId(layerId));
|
||||
dispatch(syncDataForLayerId(layerId, false));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -459,7 +459,7 @@ export function setLayerQuery(id: string, query: Query) {
|
|||
newValue: query,
|
||||
});
|
||||
|
||||
dispatch(syncDataForLayerId(id));
|
||||
dispatch(syncDataForLayerId(id, false));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -563,7 +563,7 @@ export function updateLayerStyle(layerId: string, styleDescriptor: StyleDescript
|
|||
dispatch(updateStyleMeta(layerId));
|
||||
|
||||
// Style update may require re-fetch, for example ES search may need to retrieve field used for dynamic styling
|
||||
dispatch(syncDataForLayerId(layerId));
|
||||
dispatch(syncDataForLayerId(layerId, false));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -589,7 +589,7 @@ export function setJoinsForLayer(layer: ILayer, joins: JoinDescriptor[]) {
|
|||
joins,
|
||||
});
|
||||
await dispatch(updateStyleProperties(layer.getId(), previousFields));
|
||||
dispatch(syncDataForLayerId(layer.getId()));
|
||||
dispatch(syncDataForLayerId(layer.getId(), false));
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -277,7 +277,6 @@ describe('map_actions', () => {
|
|||
const query = {
|
||||
language: 'kuery',
|
||||
query: '',
|
||||
queryLastTriggeredAt: '2020-08-14T15:07:12.276Z',
|
||||
};
|
||||
const timeFilters = { from: 'now-1y', to: 'now' };
|
||||
const filters = [
|
||||
|
@ -327,7 +326,6 @@ describe('map_actions', () => {
|
|||
const newQuery = {
|
||||
language: 'kuery',
|
||||
query: 'foobar',
|
||||
queryLastTriggeredAt: '2020-08-14T15:07:12.276Z',
|
||||
};
|
||||
const setQueryAction = await setQuery({
|
||||
query: newQuery,
|
||||
|
@ -384,7 +382,6 @@ describe('map_actions', () => {
|
|||
});
|
||||
await setQueryAction(dispatchMock, getStoreMock);
|
||||
|
||||
// Only checking calls length instead of calls because queryLastTriggeredAt changes on this run
|
||||
expect(dispatchMock.mock.calls.length).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -51,7 +51,11 @@ import {
|
|||
UPDATE_MAP_SETTING,
|
||||
UPDATE_EDIT_STATE,
|
||||
} from './map_action_constants';
|
||||
import { autoFitToBounds, syncDataForAllLayers, syncDataForLayer } from './data_request_actions';
|
||||
import {
|
||||
autoFitToBounds,
|
||||
syncDataForAllLayers,
|
||||
syncDataForLayerDueToDrawing,
|
||||
} from './data_request_actions';
|
||||
import { addLayer, addLayerWithoutDataSync } from './layer_actions';
|
||||
import { MapSettings } from '../reducers/map';
|
||||
import { DrawState, MapCenterAndZoom, MapExtent, Timeslice } from '../../common/descriptor_types';
|
||||
|
@ -172,7 +176,7 @@ export function mapExtentChanged(mapExtentState: MapExtentState) {
|
|||
});
|
||||
}
|
||||
|
||||
dispatch(syncDataForAllLayers());
|
||||
dispatch(syncDataForAllLayers(false));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -212,10 +216,6 @@ export function clearGoto() {
|
|||
return { type: CLEAR_GOTO };
|
||||
}
|
||||
|
||||
function generateQueryTimestamp() {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
|
||||
export function setQuery({
|
||||
query,
|
||||
timeFilters,
|
||||
|
@ -240,11 +240,6 @@ export function setQuery({
|
|||
getState: () => MapStoreState
|
||||
) => {
|
||||
const prevQuery = getQuery(getState());
|
||||
const prevTriggeredAt =
|
||||
prevQuery && prevQuery.queryLastTriggeredAt
|
||||
? prevQuery.queryLastTriggeredAt
|
||||
: generateQueryTimestamp();
|
||||
|
||||
const prevTimeFilters = getTimeFilters(getState());
|
||||
|
||||
function getNextTimeslice() {
|
||||
|
@ -261,11 +256,7 @@ export function setQuery({
|
|||
const nextQueryContext = {
|
||||
timeFilters: timeFilters ? timeFilters : prevTimeFilters,
|
||||
timeslice: getNextTimeslice(),
|
||||
query: {
|
||||
...(query ? query : prevQuery),
|
||||
// ensure query changes to trigger re-fetch when "Refresh" clicked
|
||||
queryLastTriggeredAt: forceRefresh ? generateQueryTimestamp() : prevTriggeredAt,
|
||||
},
|
||||
query: query ? query : prevQuery,
|
||||
filters: filters ? filters : getFilters(getState()),
|
||||
searchSessionId: searchSessionId ? searchSessionId : getSearchSessionId(getState()),
|
||||
searchSessionMapBuffer,
|
||||
|
@ -280,7 +271,7 @@ export function setQuery({
|
|||
searchSessionMapBuffer: getSearchSessionMapBuffer(getState()),
|
||||
};
|
||||
|
||||
if (_.isEqual(nextQueryContext, prevQueryContext)) {
|
||||
if (!forceRefresh && _.isEqual(nextQueryContext, prevQueryContext)) {
|
||||
// do nothing if query context has not changed
|
||||
return;
|
||||
}
|
||||
|
@ -293,7 +284,7 @@ export function setQuery({
|
|||
if (getMapSettings(getState()).autoFitToDataBounds) {
|
||||
dispatch(autoFitToBounds());
|
||||
} else {
|
||||
await dispatch(syncDataForAllLayers());
|
||||
await dispatch(syncDataForAllLayers(forceRefresh));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -372,7 +363,7 @@ export function addNewFeatureToIndex(geometry: Geometry | Position[]) {
|
|||
|
||||
try {
|
||||
await layer.addFeature(geometry);
|
||||
await dispatch(syncDataForLayer(layer, true));
|
||||
await dispatch(syncDataForLayerDueToDrawing(layer));
|
||||
} catch (e) {
|
||||
getToasts().addError(e, {
|
||||
title: i18n.translate('xpack.maps.mapActions.addFeatureError', {
|
||||
|
@ -399,7 +390,7 @@ export function deleteFeatureFromIndex(featureId: string) {
|
|||
}
|
||||
try {
|
||||
await layer.deleteFeature(featureId);
|
||||
await dispatch(syncDataForLayer(layer, true));
|
||||
await dispatch(syncDataForLayerDueToDrawing(layer));
|
||||
} catch (e) {
|
||||
getToasts().addError(e, {
|
||||
title: i18n.translate('xpack.maps.mapActions.removeFeatureError', {
|
||||
|
|
|
@ -7,21 +7,22 @@
|
|||
|
||||
import sinon from 'sinon';
|
||||
import { DataRequestContext } from '../../../actions';
|
||||
import { DataMeta, MapFilters } from '../../../../common/descriptor_types';
|
||||
import { DataRequestMeta, DataFilters } from '../../../../common/descriptor_types';
|
||||
|
||||
export class MockSyncContext implements DataRequestContext {
|
||||
dataFilters: MapFilters;
|
||||
dataFilters: DataFilters;
|
||||
isRequestStillActive: (dataId: string, requestToken: symbol) => boolean;
|
||||
onLoadError: (dataId: string, requestToken: symbol, errorMessage: string) => void;
|
||||
registerCancelCallback: (requestToken: symbol, callback: () => void) => void;
|
||||
startLoading: (dataId: string, requestToken: symbol, meta: DataMeta) => void;
|
||||
stopLoading: (dataId: string, requestToken: symbol, data: object, meta: DataMeta) => void;
|
||||
startLoading: (dataId: string, requestToken: symbol, meta: DataRequestMeta) => void;
|
||||
stopLoading: (dataId: string, requestToken: symbol, data: object, meta: DataRequestMeta) => void;
|
||||
onJoinError: (errorMessage: string) => void;
|
||||
updateSourceData: (newData: unknown) => void;
|
||||
forceRefresh: boolean;
|
||||
forceRefreshDueToDrawing: boolean;
|
||||
isForceRefresh: boolean;
|
||||
|
||||
constructor({ dataFilters }: { dataFilters: Partial<MapFilters> }) {
|
||||
const mapFilters: MapFilters = {
|
||||
constructor({ dataFilters }: { dataFilters: Partial<DataFilters> }) {
|
||||
const mapFilters: DataFilters = {
|
||||
filters: [],
|
||||
timeFilters: {
|
||||
from: 'now',
|
||||
|
@ -41,6 +42,7 @@ export class MockSyncContext implements DataRequestContext {
|
|||
this.stopLoading = sinon.spy();
|
||||
this.onJoinError = sinon.spy();
|
||||
this.updateSourceData = sinon.spy();
|
||||
this.forceRefresh = false;
|
||||
this.forceRefreshDueToDrawing = false;
|
||||
this.isForceRefresh = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ describe('getSource', () => {
|
|||
...documentSourceDescriptor,
|
||||
applyGlobalQuery: false,
|
||||
applyGlobalTime: false,
|
||||
applyForceRefresh: false,
|
||||
}),
|
||||
layerDescriptor: BlendedVectorLayer.createDescriptor(
|
||||
{
|
||||
|
@ -86,6 +87,7 @@ describe('getSource', () => {
|
|||
geoField: sourceDescriptor.geoField,
|
||||
applyGlobalQuery: sourceDescriptor.applyGlobalQuery,
|
||||
applyGlobalTime: sourceDescriptor.applyGlobalTime,
|
||||
applyForceRefresh: sourceDescriptor.applyForceRefresh,
|
||||
};
|
||||
expect(abstractEsSourceDescriptor).toEqual({
|
||||
type: sourceDescriptor.type,
|
||||
|
@ -94,6 +96,7 @@ describe('getSource', () => {
|
|||
indexPatternId: 'myIndexPattern',
|
||||
applyGlobalQuery: false,
|
||||
applyGlobalTime: false,
|
||||
applyForceRefresh: false,
|
||||
} as AbstractESSourceDescriptor);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -60,6 +60,7 @@ function getClusterSource(documentSource: IESSource, documentStyle: IVectorStyle
|
|||
});
|
||||
clusterSourceDescriptor.applyGlobalQuery = documentSource.getApplyGlobalQuery();
|
||||
clusterSourceDescriptor.applyGlobalTime = documentSource.getApplyGlobalTime();
|
||||
clusterSourceDescriptor.applyForceRefresh = documentSource.getApplyForceRefresh();
|
||||
clusterSourceDescriptor.metrics = [
|
||||
{
|
||||
type: AGG_TYPE.COUNT,
|
||||
|
@ -290,16 +291,18 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer {
|
|||
async syncData(syncContext: DataRequestContext) {
|
||||
const dataRequestId = ACTIVE_COUNT_DATA_ID;
|
||||
const requestToken = Symbol(`layer-active-count:${this.getId()}`);
|
||||
const searchFilters: VectorSourceRequestMeta = await this._getSearchFilters(
|
||||
const requestMeta: VectorSourceRequestMeta = await this._getVectorSourceRequestMeta(
|
||||
syncContext.isForceRefresh,
|
||||
syncContext.dataFilters,
|
||||
this.getSource(),
|
||||
this.getCurrentStyle()
|
||||
);
|
||||
const source = this.getSource();
|
||||
const canSkipFetch = await canSkipSourceUpdate({
|
||||
|
||||
const canSkipSourceFetch = await canSkipSourceUpdate({
|
||||
source,
|
||||
prevDataRequest: this.getDataRequest(dataRequestId),
|
||||
nextMeta: searchFilters,
|
||||
nextRequestMeta: requestMeta,
|
||||
extentAware: source.isFilterByMapBounds(),
|
||||
getUpdateDueToTimeslice: (timeslice?: Timeslice) => {
|
||||
return this._getUpdateDueToTimesliceFromSourceRequestMeta(source, timeslice);
|
||||
|
@ -308,7 +311,7 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer {
|
|||
|
||||
let activeSource;
|
||||
let activeStyle;
|
||||
if (canSkipFetch) {
|
||||
if (canSkipSourceFetch) {
|
||||
// Even when source fetch is skipped, need to call super._syncData to sync StyleMeta and formatters
|
||||
if (this._isClustered) {
|
||||
activeSource = this._clusterSource;
|
||||
|
@ -320,12 +323,12 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer {
|
|||
} else {
|
||||
let isSyncClustered;
|
||||
try {
|
||||
syncContext.startLoading(dataRequestId, requestToken, searchFilters);
|
||||
syncContext.startLoading(dataRequestId, requestToken, requestMeta);
|
||||
isSyncClustered = !(await this._documentSource.canLoadAllDocuments(
|
||||
searchFilters,
|
||||
requestMeta,
|
||||
syncContext.registerCancelCallback.bind(null, requestToken)
|
||||
));
|
||||
syncContext.stopLoading(dataRequestId, requestToken, { isSyncClustered }, searchFilters);
|
||||
syncContext.stopLoading(dataRequestId, requestToken, { isSyncClustered }, requestMeta);
|
||||
} catch (error) {
|
||||
if (!(error instanceof DataRequestAbortError) || !isSearchSourceAbortError(error)) {
|
||||
syncContext.onLoadError(dataRequestId, requestToken, error.message);
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import type { Query } from 'src/plugins/data/common';
|
||||
import { DataFilters, VectorSourceRequestMeta } from '../../../common/descriptor_types';
|
||||
import { IVectorSource } from '../sources/vector_source';
|
||||
import { ITermJoinSource } from '../sources/term_join_source';
|
||||
|
||||
export function buildVectorRequestMeta(
|
||||
source: IVectorSource | ITermJoinSource,
|
||||
fieldNames: string[],
|
||||
dataFilters: DataFilters,
|
||||
sourceQuery: Query | null | undefined,
|
||||
isForceRefresh: boolean
|
||||
): VectorSourceRequestMeta {
|
||||
return {
|
||||
...dataFilters,
|
||||
fieldNames: _.uniq(fieldNames).sort(),
|
||||
geogridPrecision: source.getGeoGridPrecision(dataFilters.zoom),
|
||||
sourceQuery: sourceQuery ? sourceQuery : undefined,
|
||||
applyGlobalQuery: source.getApplyGlobalQuery(),
|
||||
applyGlobalTime: source.getApplyGlobalTime(),
|
||||
sourceMeta: source.getSyncMeta(),
|
||||
applyForceRefresh: source.isESSource() ? source.getApplyForceRefresh() : false,
|
||||
isForceRefresh,
|
||||
};
|
||||
}
|
|
@ -64,6 +64,7 @@ function createChoroplethLayerDescriptor({
|
|||
metrics: [metricsDescriptor],
|
||||
applyGlobalQuery: true,
|
||||
applyGlobalTime: true,
|
||||
applyForceRefresh: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -148,6 +149,8 @@ export function createEsChoroplethLayerDescriptor({
|
|||
scalingType: SCALING_TYPES.LIMIT,
|
||||
tooltipProperties: [leftJoinField],
|
||||
applyGlobalQuery: false,
|
||||
applyGlobalTime: false,
|
||||
applyForceRefresh: false,
|
||||
}),
|
||||
leftField: leftJoinField,
|
||||
rightIndexPatternId,
|
||||
|
|
|
@ -92,6 +92,7 @@ export function createRegionMapLayerDescriptor({
|
|||
metrics: [metricsDescriptor],
|
||||
applyGlobalQuery: true,
|
||||
applyGlobalTime: true,
|
||||
applyForceRefresh: true,
|
||||
};
|
||||
if (termsSize !== undefined) {
|
||||
termSourceDescriptor.size = termsSize;
|
||||
|
|
|
@ -10,11 +10,12 @@ import { FeatureCollection } from 'geojson';
|
|||
import { AbstractLayer } from '../layer';
|
||||
import { HeatmapStyle } from '../../styles/heatmap/heatmap_style';
|
||||
import { EMPTY_FEATURE_COLLECTION, LAYER_TYPE } from '../../../../common/constants';
|
||||
import { HeatmapLayerDescriptor, MapQuery } from '../../../../common/descriptor_types';
|
||||
import { HeatmapLayerDescriptor } from '../../../../common/descriptor_types';
|
||||
import { ESGeoGridSource } from '../../sources/es_geo_grid_source';
|
||||
import { addGeoJsonMbSource, getVectorSourceBounds, syncVectorSource } from '../vector_layer';
|
||||
import { DataRequestContext } from '../../../actions';
|
||||
import { DataRequestAbortError } from '../../util/data_request';
|
||||
import { buildVectorRequestMeta } from '../build_vector_request_meta';
|
||||
|
||||
const SCALED_PROPERTY_NAME = '__kbn_heatmap_weight__'; // unique name to store scaled value for weighting
|
||||
|
||||
|
@ -94,21 +95,18 @@ export class HeatmapLayer extends AbstractLayer {
|
|||
return;
|
||||
}
|
||||
|
||||
const sourceQuery = this.getQuery() as MapQuery;
|
||||
try {
|
||||
await syncVectorSource({
|
||||
layerId: this.getId(),
|
||||
layerName: await this.getDisplayName(this.getSource()),
|
||||
prevDataRequest: this.getSourceDataRequest(),
|
||||
requestMeta: {
|
||||
...syncContext.dataFilters,
|
||||
fieldNames: this.getSource().getFieldNames(),
|
||||
geogridPrecision: this.getSource().getGeoGridPrecision(syncContext.dataFilters.zoom),
|
||||
sourceQuery: sourceQuery ? sourceQuery : undefined,
|
||||
applyGlobalQuery: this.getSource().getApplyGlobalQuery(),
|
||||
applyGlobalTime: this.getSource().getApplyGlobalTime(),
|
||||
sourceMeta: this.getSource().getSyncMeta(),
|
||||
},
|
||||
requestMeta: buildVectorRequestMeta(
|
||||
this.getSource(),
|
||||
this.getSource().getFieldNames(),
|
||||
syncContext.dataFilters,
|
||||
this.getQuery(),
|
||||
syncContext.isForceRefresh
|
||||
),
|
||||
syncContext,
|
||||
source: this.getSource(),
|
||||
getUpdateDueToTimeslice: () => {
|
||||
|
@ -194,7 +192,7 @@ export class HeatmapLayer extends AbstractLayer {
|
|||
layerId: this.getId(),
|
||||
syncContext,
|
||||
source: this.getSource(),
|
||||
sourceQuery: this.getQuery() as MapQuery,
|
||||
sourceQuery: this.getQuery(),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ describe('cloneDescriptor', () => {
|
|||
type: SOURCE_TYPES.ES_TERM_SOURCE,
|
||||
applyGlobalQuery: true,
|
||||
applyGlobalTime: true,
|
||||
applyForceRefresh: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -61,6 +61,7 @@ describe('createLayerDescriptor', () => {
|
|||
type: 'avg',
|
||||
},
|
||||
],
|
||||
applyForceRefresh: true,
|
||||
term: 'client.geo.country_iso_code',
|
||||
type: 'ES_TERM_SOURCE',
|
||||
whereQuery: {
|
||||
|
@ -201,6 +202,7 @@ describe('createLayerDescriptor', () => {
|
|||
],
|
||||
requestType: 'heatmap',
|
||||
resolution: 'MOST_FINE',
|
||||
applyForceRefresh: true,
|
||||
type: 'ES_GEO_GRID',
|
||||
},
|
||||
style: {
|
||||
|
@ -245,6 +247,7 @@ describe('createLayerDescriptor', () => {
|
|||
],
|
||||
requestType: 'point',
|
||||
resolution: 'MOST_FINE',
|
||||
applyForceRefresh: true,
|
||||
type: 'ES_GEO_GRID',
|
||||
},
|
||||
style: {
|
||||
|
|
|
@ -179,6 +179,7 @@ export function createLayerDescriptor({
|
|||
whereQuery: apmSourceQuery,
|
||||
applyGlobalQuery: true,
|
||||
applyGlobalTime: true,
|
||||
applyForceRefresh: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -47,6 +47,7 @@ describe('createLayerDescriptor', () => {
|
|||
geoField: 'client.geo.location',
|
||||
id: '12345',
|
||||
indexPatternId: 'id',
|
||||
applyForceRefresh: true,
|
||||
scalingType: 'TOP_HITS',
|
||||
sortField: '',
|
||||
sortOrder: 'desc',
|
||||
|
@ -156,6 +157,7 @@ describe('createLayerDescriptor', () => {
|
|||
geoField: 'server.geo.location',
|
||||
id: '12345',
|
||||
indexPatternId: 'id',
|
||||
applyForceRefresh: true,
|
||||
scalingType: 'TOP_HITS',
|
||||
sortField: '',
|
||||
sortOrder: 'desc',
|
||||
|
@ -274,6 +276,7 @@ describe('createLayerDescriptor', () => {
|
|||
type: 'sum',
|
||||
},
|
||||
],
|
||||
applyForceRefresh: true,
|
||||
sourceGeoField: 'client.geo.location',
|
||||
type: 'ES_PEW_PEW',
|
||||
},
|
||||
|
@ -386,6 +389,7 @@ describe('createLayerDescriptor', () => {
|
|||
geoField: 'source.geo.location',
|
||||
id: '12345',
|
||||
indexPatternId: 'id',
|
||||
applyForceRefresh: true,
|
||||
scalingType: 'TOP_HITS',
|
||||
sortField: '',
|
||||
sortOrder: 'desc',
|
||||
|
@ -495,6 +499,7 @@ describe('createLayerDescriptor', () => {
|
|||
geoField: 'destination.geo.location',
|
||||
id: '12345',
|
||||
indexPatternId: 'id',
|
||||
applyForceRefresh: true,
|
||||
scalingType: 'TOP_HITS',
|
||||
sortField: '',
|
||||
sortOrder: 'desc',
|
||||
|
@ -613,6 +618,7 @@ describe('createLayerDescriptor', () => {
|
|||
type: 'sum',
|
||||
},
|
||||
],
|
||||
applyForceRefresh: true,
|
||||
sourceGeoField: 'source.geo.location',
|
||||
type: 'ES_PEW_PEW',
|
||||
},
|
||||
|
@ -724,6 +730,7 @@ describe('createLayerDescriptor', () => {
|
|||
filterByMapBounds: true,
|
||||
geoField: 'client.geo.location',
|
||||
id: '12345',
|
||||
applyForceRefresh: true,
|
||||
indexPatternId: 'id',
|
||||
scalingType: 'TOP_HITS',
|
||||
sortField: '',
|
||||
|
@ -835,6 +842,7 @@ describe('createLayerDescriptor', () => {
|
|||
id: '12345',
|
||||
indexPatternId: 'id',
|
||||
scalingType: 'TOP_HITS',
|
||||
applyForceRefresh: true,
|
||||
sortField: '',
|
||||
sortOrder: 'desc',
|
||||
tooltipProperties: [
|
||||
|
@ -952,6 +960,7 @@ describe('createLayerDescriptor', () => {
|
|||
type: 'sum',
|
||||
},
|
||||
],
|
||||
applyForceRefresh: true,
|
||||
sourceGeoField: 'client.geo.location',
|
||||
type: 'ES_PEW_PEW',
|
||||
},
|
||||
|
|
|
@ -38,7 +38,6 @@ import {
|
|||
} from '../../../../common/descriptor_types';
|
||||
import { MVTSingleLayerVectorSourceConfig } from '../../sources/mvt_single_layer_vector_source/types';
|
||||
import { canSkipSourceUpdate } from '../../util/can_skip_fetch';
|
||||
import { isRefreshOnlyQuery } from '../../util/is_refresh_only_query';
|
||||
import { CustomIconAndTooltipContent } from '../layer';
|
||||
|
||||
export class TiledVectorLayer extends VectorLayer {
|
||||
|
@ -113,9 +112,11 @@ export class TiledVectorLayer extends VectorLayer {
|
|||
stopLoading,
|
||||
onLoadError,
|
||||
dataFilters,
|
||||
isForceRefresh,
|
||||
}: DataRequestContext) {
|
||||
const requestToken: symbol = Symbol(`layer-${this.getId()}-${SOURCE_DATA_REQUEST_ID}`);
|
||||
const searchFilters: VectorSourceRequestMeta = await this._getSearchFilters(
|
||||
const requestMeta: VectorSourceRequestMeta = await this._getVectorSourceRequestMeta(
|
||||
isForceRefresh,
|
||||
dataFilters,
|
||||
this.getSource(),
|
||||
this._style as IVectorStyle
|
||||
|
@ -132,7 +133,7 @@ export class TiledVectorLayer extends VectorLayer {
|
|||
extentAware: false, // spatial extent knowledge is already fully automated by tile-loading based on pan-zooming
|
||||
source: this.getSource(),
|
||||
prevDataRequest,
|
||||
nextMeta: searchFilters,
|
||||
nextRequestMeta: requestMeta,
|
||||
getUpdateDueToTimeslice: (timeslice?: Timeslice) => {
|
||||
// TODO use meta features to determine if tiles already contain features for timeslice.
|
||||
return true;
|
||||
|
@ -145,18 +146,17 @@ export class TiledVectorLayer extends VectorLayer {
|
|||
}
|
||||
}
|
||||
|
||||
startLoading(SOURCE_DATA_REQUEST_ID, requestToken, searchFilters);
|
||||
startLoading(SOURCE_DATA_REQUEST_ID, requestToken, requestMeta);
|
||||
try {
|
||||
const prevMeta = prevDataRequest ? prevDataRequest.getMeta() : undefined;
|
||||
const prevData = prevDataRequest
|
||||
? (prevDataRequest.getData() as MVTSingleLayerVectorSourceConfig)
|
||||
: undefined;
|
||||
const urlToken =
|
||||
!prevData || isRefreshOnlyQuery(prevMeta ? prevMeta.query : undefined, searchFilters.query)
|
||||
!prevData || (requestMeta.isForceRefresh && requestMeta.applyForceRefresh)
|
||||
? uuid()
|
||||
: prevData.urlToken;
|
||||
|
||||
const newUrlTemplateAndMeta = await this._source.getUrlTemplateWithMeta(searchFilters);
|
||||
const newUrlTemplateAndMeta = await this._source.getUrlTemplateWithMeta(requestMeta);
|
||||
|
||||
let urlTemplate;
|
||||
if (newUrlTemplateAndMeta.refreshTokenParamName) {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { FeatureCollection } from 'geojson';
|
||||
import type { Map as MbMap } from '@kbn/mapbox-gl';
|
||||
import type { Query } from 'src/plugins/data/common';
|
||||
import {
|
||||
EMPTY_FEATURE_COLLECTION,
|
||||
SOURCE_BOUNDS_DATA_REQUEST_ID,
|
||||
|
@ -14,9 +15,8 @@ import {
|
|||
VECTOR_SHAPE_TYPE,
|
||||
} from '../../../../common/constants';
|
||||
import {
|
||||
DataMeta,
|
||||
DataRequestMeta,
|
||||
MapExtent,
|
||||
MapQuery,
|
||||
Timeslice,
|
||||
VectorSourceRequestMeta,
|
||||
} from '../../../../common/descriptor_types';
|
||||
|
@ -77,15 +77,17 @@ export async function syncVectorSource({
|
|||
} = syncContext;
|
||||
const dataRequestId = SOURCE_DATA_REQUEST_ID;
|
||||
const requestToken = Symbol(`${layerId}-${dataRequestId}`);
|
||||
const canSkipFetch = syncContext.forceRefresh
|
||||
|
||||
const canSkipFetch = syncContext.forceRefreshDueToDrawing
|
||||
? false
|
||||
: await canSkipSourceUpdate({
|
||||
source,
|
||||
prevDataRequest,
|
||||
nextMeta: requestMeta,
|
||||
nextRequestMeta: requestMeta,
|
||||
extentAware: source.isFilterByMapBounds(),
|
||||
getUpdateDueToTimeslice,
|
||||
});
|
||||
|
||||
if (canSkipFetch) {
|
||||
return {
|
||||
refreshed: false,
|
||||
|
@ -113,11 +115,11 @@ export async function syncVectorSource({
|
|||
) {
|
||||
layerFeatureCollection.features.push(...getCentroidFeatures(layerFeatureCollection));
|
||||
}
|
||||
const responseMeta: DataMeta = meta ? { ...meta } : {};
|
||||
const responseMeta: DataRequestMeta = meta ? { ...meta } : {};
|
||||
if (requestMeta.applyGlobalTime && (await source.isTimeAware())) {
|
||||
const timesiceMaskField = await source.getTimesliceMaskFieldName();
|
||||
if (timesiceMaskField) {
|
||||
responseMeta.timesiceMaskField = timesiceMaskField;
|
||||
const timesliceMaskField = await source.getTimesliceMaskFieldName();
|
||||
if (timesliceMaskField) {
|
||||
responseMeta.timesliceMaskField = timesliceMaskField;
|
||||
}
|
||||
}
|
||||
stopLoading(dataRequestId, requestToken, layerFeatureCollection, responseMeta);
|
||||
|
@ -142,7 +144,7 @@ export async function getVectorSourceBounds({
|
|||
layerId: string;
|
||||
syncContext: DataRequestContext;
|
||||
source: IVectorSource;
|
||||
sourceQuery: MapQuery | null;
|
||||
sourceQuery: Query | null;
|
||||
}): Promise<MapExtent | null> {
|
||||
const { startLoading, stopLoading, registerCancelCallback, dataFilters } = syncContext;
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import type {
|
|||
AnyLayer as MbLayer,
|
||||
GeoJSONSource as MbGeoJSONSource,
|
||||
} from '@kbn/mapbox-gl';
|
||||
import type { Query } from 'src/plugins/data/common';
|
||||
import { Feature, FeatureCollection, GeoJsonProperties, Geometry, Position } from 'geojson';
|
||||
import _ from 'lodash';
|
||||
import { EuiIcon } from '@elastic/eui';
|
||||
|
@ -48,14 +49,13 @@ import {
|
|||
} from '../../util/mb_filter_expressions';
|
||||
import {
|
||||
DynamicStylePropertyOptions,
|
||||
MapFilters,
|
||||
MapQuery,
|
||||
DataFilters,
|
||||
StyleMetaDescriptor,
|
||||
Timeslice,
|
||||
VectorJoinSourceRequestMeta,
|
||||
VectorLayerDescriptor,
|
||||
VectorSourceRequestMeta,
|
||||
VectorStyleRequestMeta,
|
||||
VectorJoinSourceRequestMeta,
|
||||
} from '../../../../common/descriptor_types';
|
||||
import { ISource } from '../../sources/source';
|
||||
import { IVectorSource } from '../../sources/vector_source';
|
||||
|
@ -70,6 +70,7 @@ import { PropertiesMap } from '../../../../common/elasticsearch_util';
|
|||
import { ITermJoinSource } from '../../sources/term_join_source';
|
||||
import { addGeoJsonMbSource, getVectorSourceBounds, syncVectorSource } from './utils';
|
||||
import { JoinState, performInnerJoins } from './perform_inner_joins';
|
||||
import { buildVectorRequestMeta } from '../build_vector_request_meta';
|
||||
|
||||
export interface VectorLayerArguments {
|
||||
source: IVectorSource;
|
||||
|
@ -266,7 +267,7 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
|||
layerId: this.getId(),
|
||||
syncContext,
|
||||
source: this.getSource(),
|
||||
sourceQuery: this.getQuery() as MapQuery,
|
||||
sourceQuery: this.getQuery(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -332,29 +333,31 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
|||
onLoadError,
|
||||
registerCancelCallback,
|
||||
dataFilters,
|
||||
isForceRefresh,
|
||||
}: { join: InnerJoin } & DataRequestContext): Promise<JoinState> {
|
||||
const joinSource = join.getRightJoinSource();
|
||||
const sourceDataId = join.getSourceDataRequestId();
|
||||
const requestToken = Symbol(`layer-join-refresh:${this.getId()} - ${sourceDataId}`);
|
||||
const searchFilters: VectorJoinSourceRequestMeta = {
|
||||
...dataFilters,
|
||||
fieldNames: joinSource.getFieldNames(),
|
||||
sourceQuery: joinSource.getWhereQuery(),
|
||||
applyGlobalQuery: joinSource.getApplyGlobalQuery(),
|
||||
applyGlobalTime: joinSource.getApplyGlobalTime(),
|
||||
sourceMeta: joinSource.getSyncMeta(),
|
||||
};
|
||||
const prevDataRequest = this.getDataRequest(sourceDataId);
|
||||
|
||||
const joinRequestMeta: VectorJoinSourceRequestMeta = buildVectorRequestMeta(
|
||||
joinSource,
|
||||
joinSource.getFieldNames(),
|
||||
dataFilters,
|
||||
joinSource.getWhereQuery(),
|
||||
isForceRefresh
|
||||
) as VectorJoinSourceRequestMeta;
|
||||
|
||||
const prevDataRequest = this.getDataRequest(sourceDataId);
|
||||
const canSkipFetch = await canSkipSourceUpdate({
|
||||
source: joinSource,
|
||||
prevDataRequest,
|
||||
nextMeta: searchFilters,
|
||||
nextRequestMeta: joinRequestMeta,
|
||||
extentAware: false, // join-sources are term-aggs that are spatially unaware (e.g. ESTermSource/TableSource).
|
||||
getUpdateDueToTimeslice: () => {
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
if (canSkipFetch) {
|
||||
return {
|
||||
dataHasChanged: false,
|
||||
|
@ -364,10 +367,10 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
|||
}
|
||||
|
||||
try {
|
||||
startLoading(sourceDataId, requestToken, searchFilters);
|
||||
startLoading(sourceDataId, requestToken, joinRequestMeta);
|
||||
const leftSourceName = await this._source.getDisplayName();
|
||||
const propertiesMap = await joinSource.getPropertiesMap(
|
||||
searchFilters,
|
||||
joinRequestMeta,
|
||||
leftSourceName,
|
||||
join.getLeftField().getName(),
|
||||
registerCancelCallback.bind(null, requestToken)
|
||||
|
@ -396,8 +399,9 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
|||
return await Promise.all(joinSyncs);
|
||||
}
|
||||
|
||||
async _getSearchFilters(
|
||||
dataFilters: MapFilters,
|
||||
async _getVectorSourceRequestMeta(
|
||||
isForceRefresh: boolean,
|
||||
dataFilters: DataFilters,
|
||||
source: IVectorSource,
|
||||
style: IVectorStyle
|
||||
): Promise<VectorSourceRequestMeta> {
|
||||
|
@ -411,17 +415,7 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
|||
if (timesliceMaskFieldName) {
|
||||
fieldNames.push(timesliceMaskFieldName);
|
||||
}
|
||||
|
||||
const sourceQuery = this.getQuery() as MapQuery;
|
||||
return {
|
||||
...dataFilters,
|
||||
fieldNames: _.uniq(fieldNames).sort(),
|
||||
geogridPrecision: source.getGeoGridPrecision(dataFilters.zoom),
|
||||
sourceQuery: sourceQuery ? sourceQuery : undefined,
|
||||
applyGlobalQuery: source.getApplyGlobalQuery(),
|
||||
applyGlobalTime: source.getApplyGlobalTime(),
|
||||
sourceMeta: source.getSyncMeta(),
|
||||
};
|
||||
return buildVectorRequestMeta(source, fieldNames, dataFilters, this.getQuery(), isForceRefresh);
|
||||
}
|
||||
|
||||
async _syncSourceStyleMeta(
|
||||
|
@ -429,7 +423,7 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
|||
source: IVectorSource,
|
||||
style: IVectorStyle
|
||||
) {
|
||||
const sourceQuery = this.getQuery() as MapQuery;
|
||||
const sourceQuery = this.getQuery();
|
||||
return this._syncStyleMeta({
|
||||
source,
|
||||
style,
|
||||
|
@ -481,7 +475,7 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
|||
dataRequestId: string;
|
||||
dynamicStyleProps: Array<IDynamicStyleProperty<DynamicStylePropertyOptions>>;
|
||||
source: IVectorSource | ITermJoinSource;
|
||||
sourceQuery?: MapQuery;
|
||||
sourceQuery?: Query;
|
||||
style: IVectorStyle;
|
||||
} & DataRequestContext) {
|
||||
if (!source.isESSource() || dynamicStyleProps.length === 0) {
|
||||
|
@ -641,7 +635,12 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
|||
layerId: this.getId(),
|
||||
layerName: await this.getDisplayName(source),
|
||||
prevDataRequest: this.getSourceDataRequest(),
|
||||
requestMeta: await this._getSearchFilters(syncContext.dataFilters, source, style),
|
||||
requestMeta: await this._getVectorSourceRequestMeta(
|
||||
syncContext.isForceRefresh,
|
||||
syncContext.dataFilters,
|
||||
source,
|
||||
style
|
||||
),
|
||||
syncContext,
|
||||
source,
|
||||
getUpdateDueToTimeslice: (timeslice?: Timeslice) => {
|
||||
|
@ -995,9 +994,9 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
|
|||
}
|
||||
|
||||
const prevMeta = this.getSourceDataRequest()?.getMeta();
|
||||
return prevMeta !== undefined && prevMeta.timesiceMaskField !== undefined
|
||||
return prevMeta !== undefined && prevMeta.timesliceMaskField !== undefined
|
||||
? {
|
||||
timesiceMaskField: prevMeta.timesiceMaskField,
|
||||
timesliceMaskField: prevMeta.timesliceMaskField,
|
||||
timeslice,
|
||||
}
|
||||
: undefined;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { ITileLayerArguments } from '../tile_layer/tile_layer';
|
||||
import { SOURCE_TYPES } from '../../../../common/constants';
|
||||
import { MapFilters, XYZTMSSourceDescriptor } from '../../../../common/descriptor_types';
|
||||
import { DataFilters, XYZTMSSourceDescriptor } from '../../../../common/descriptor_types';
|
||||
import { ITMSSource, AbstractTMSSource } from '../../sources/tms_source';
|
||||
import { ILayer } from '../layer';
|
||||
import { VectorTileLayer } from './vector_tile_layer';
|
||||
|
@ -63,7 +63,7 @@ describe('VectorTileLayer', () => {
|
|||
onLoadError: (requestId: string, token: string, message: string) => {
|
||||
actualErrorMessage = message;
|
||||
},
|
||||
dataFilters: ({ foo: 'bar' } as unknown) as MapFilters,
|
||||
dataFilters: ({ foo: 'bar' } as unknown) as DataFilters,
|
||||
} as unknown) as DataRequestContext;
|
||||
|
||||
await layer.syncData(mockContext);
|
||||
|
|
|
@ -40,6 +40,7 @@ class TestESAggSource extends AbstractESAggSource {
|
|||
metrics,
|
||||
applyGlobalQuery: true,
|
||||
applyGlobalTime: true,
|
||||
applyForceRefresh: true,
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
|
|
@ -155,15 +155,16 @@ describe('ESGeoGridSource', () => {
|
|||
extent,
|
||||
applyGlobalQuery: true,
|
||||
applyGlobalTime: true,
|
||||
applyForceRefresh: true,
|
||||
fieldNames: [],
|
||||
buffer: extent,
|
||||
sourceQuery: {
|
||||
query: '',
|
||||
language: 'KQL',
|
||||
queryLastTriggeredAt: '2019-04-25T20:53:22.331Z',
|
||||
},
|
||||
sourceMeta: null,
|
||||
zoom: 0,
|
||||
isForceRefresh: false,
|
||||
};
|
||||
|
||||
describe('getGeoJsonWithMeta', () => {
|
||||
|
@ -315,7 +316,7 @@ describe('ESGeoGridSource', () => {
|
|||
expect(urlTemplateWithMeta.minSourceZoom).toBe(0);
|
||||
expect(urlTemplateWithMeta.maxSourceZoom).toBe(24);
|
||||
expect(urlTemplateWithMeta.urlTemplate).toEqual(
|
||||
"rootdir/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=undefined&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'',queryLastTriggeredAt:'2019-04-25T20:53:22.331Z')),'6':('0':aggs,'1':(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:bar))),geotile_grid:(bounds:!n,field:bar,precision:!n,shard_size:65535,size:65535))))))&requestType=heatmap&geoFieldType=geo_point"
|
||||
"rootdir/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=undefined&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'')),'6':('0':aggs,'1':(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:bar))),geotile_grid:(bounds:!n,field:bar,precision:!n,shard_size:65535,size:65535))))))&requestType=heatmap&geoFieldType=geo_point"
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -327,7 +328,7 @@ describe('ESGeoGridSource', () => {
|
|||
|
||||
expect(
|
||||
urlTemplateWithMeta.urlTemplate.startsWith(
|
||||
"rootdir/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=undefined&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'',queryLastTriggeredAt:'2019-04-25T20:53:22.331Z')),'6':('0':aggs,'1':(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:bar))),geotile_grid:(bounds:!n,field:bar,precision:!n,shard_size:65535,size:65535))))))&requestType=heatmap&geoFieldType=geo_point&searchSessionId=1"
|
||||
"rootdir/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=undefined&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:())),'1':('0':size,'1':0),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:())),'5':('0':query,'1':(language:KQL,query:'')),'6':('0':aggs,'1':(gridSplit:(aggs:(gridCentroid:(geo_centroid:(field:bar))),geotile_grid:(bounds:!n,field:bar,precision:!n,shard_size:65535,size:65535))))))&requestType=heatmap&geoFieldType=geo_point&searchSessionId=1"
|
||||
)
|
||||
).toBe(true);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ describe('getSourceTooltipContent', () => {
|
|||
const sourceDataRequest = new DataRequest({
|
||||
data: {},
|
||||
dataId: 'source',
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
areResultsTrimmed: false,
|
||||
areEntitiesTrimmed: false,
|
||||
entityCount: 70,
|
||||
|
@ -39,7 +39,7 @@ describe('getSourceTooltipContent', () => {
|
|||
const sourceDataRequest = new DataRequest({
|
||||
data: {},
|
||||
dataId: 'source',
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
areResultsTrimmed: true,
|
||||
areEntitiesTrimmed: true,
|
||||
entityCount: 1000,
|
||||
|
@ -58,7 +58,7 @@ describe('getSourceTooltipContent', () => {
|
|||
const sourceDataRequest = new DataRequest({
|
||||
data: {},
|
||||
dataId: 'source',
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
areResultsTrimmed: false,
|
||||
areEntitiesTrimmed: false,
|
||||
entityCount: 70,
|
||||
|
@ -77,7 +77,7 @@ describe('getSourceTooltipContent', () => {
|
|||
const sourceDataRequest = new DataRequest({
|
||||
data: {},
|
||||
dataId: 'source',
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
areResultsTrimmed: true,
|
||||
areEntitiesTrimmed: true,
|
||||
entityCount: 1000,
|
||||
|
|
|
@ -41,6 +41,7 @@ test('Should create layer descriptor', () => {
|
|||
geoField: 'myGeoField',
|
||||
id: '12345',
|
||||
indexPatternId: 'myIndexPattern',
|
||||
applyForceRefresh: true,
|
||||
scalingType: 'CLUSTERS',
|
||||
sortField: '',
|
||||
sortOrder: 'desc',
|
||||
|
|
|
@ -102,11 +102,12 @@ describe('ESSearchSource', () => {
|
|||
sourceQuery: {
|
||||
query: 'tooltipField: foobar',
|
||||
language: 'KQL',
|
||||
queryLastTriggeredAt: '2019-04-25T20:53:22.331Z',
|
||||
},
|
||||
sourceMeta: null,
|
||||
applyGlobalQuery: true,
|
||||
applyGlobalTime: true,
|
||||
applyForceRefresh: true,
|
||||
isForceRefresh: false,
|
||||
};
|
||||
|
||||
it('Should only include required props', async () => {
|
||||
|
@ -116,7 +117,7 @@ describe('ESSearchSource', () => {
|
|||
});
|
||||
const urlTemplateWithMeta = await esSearchSource.getUrlTemplateWithMeta(searchFilters);
|
||||
expect(urlTemplateWithMeta.urlTemplate).toBe(
|
||||
`rootdir/api/maps/mvt/getTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=foobar-title-*&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar',queryLastTriggeredAt:'2019-04-25T20:53:22.331Z')),'6':('0':fieldsFromSource,'1':!(tooltipField,styleField)),'7':('0':source,'1':!(tooltipField,styleField))))&geoFieldType=geo_shape`
|
||||
`rootdir/api/maps/mvt/getTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=foobar-title-*&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar')),'6':('0':fieldsFromSource,'1':!(tooltipField,styleField)),'7':('0':source,'1':!(tooltipField,styleField))))&geoFieldType=geo_shape`
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -130,7 +131,7 @@ describe('ESSearchSource', () => {
|
|||
searchSessionId: '1',
|
||||
});
|
||||
expect(urlTemplateWithMeta.urlTemplate).toBe(
|
||||
`rootdir/api/maps/mvt/getTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=foobar-title-*&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar',queryLastTriggeredAt:'2019-04-25T20:53:22.331Z')),'6':('0':fieldsFromSource,'1':!(tooltipField,styleField)),'7':('0':source,'1':!(tooltipField,styleField))))&geoFieldType=geo_shape&searchSessionId=1`
|
||||
`rootdir/api/maps/mvt/getTile/{z}/{x}/{y}.pbf?geometryFieldName=bar&index=foobar-title-*&requestBody=(foobar:ES_DSL_PLACEHOLDER,params:('0':('0':index,'1':(fields:(),title:'foobar-title-*')),'1':('0':size,'1':1000),'2':('0':filter,'1':!()),'3':('0':query),'4':('0':index,'1':(fields:(),title:'foobar-title-*')),'5':('0':query,'1':(language:KQL,query:'tooltipField: foobar')),'6':('0':fieldsFromSource,'1':!(tooltipField,styleField)),'7':('0':source,'1':!(tooltipField,styleField))))&geoFieldType=geo_shape&searchSessionId=1`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -48,7 +48,7 @@ import { DEFAULT_FILTER_BY_MAP_BOUNDS } from './constants';
|
|||
import { ESDocField } from '../../fields/es_doc_field';
|
||||
import { registerSource } from '../source_registry';
|
||||
import {
|
||||
DataMeta,
|
||||
DataRequestMeta,
|
||||
ESSearchSourceDescriptor,
|
||||
Timeslice,
|
||||
VectorSourceRequestMeta,
|
||||
|
@ -853,7 +853,7 @@ export class ESSearchSource extends AbstractESSource implements ITiledSingleLaye
|
|||
return indexPattern.timeFieldName ? indexPattern.timeFieldName : null;
|
||||
}
|
||||
|
||||
getUpdateDueToTimeslice(prevMeta: DataMeta, timeslice?: Timeslice): boolean {
|
||||
getUpdateDueToTimeslice(prevMeta: DataRequestMeta, timeslice?: Timeslice): boolean {
|
||||
if (this._isTopHits() || this._descriptor.scalingType === SCALING_TYPES.MVT) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import uuid from 'uuid/v4';
|
||||
import { Filter, IndexPatternField, IndexPattern, ISearchSource } from 'src/plugins/data/public';
|
||||
import { AbstractVectorSource, BoundsFilters } from '../vector_source';
|
||||
import type { Query } from 'src/plugins/data/common';
|
||||
import { AbstractVectorSource, BoundsRequestMeta } from '../vector_source';
|
||||
import {
|
||||
getAutocompleteService,
|
||||
getIndexPatternService,
|
||||
|
@ -26,7 +27,6 @@ import {
|
|||
AbstractSourceDescriptor,
|
||||
DynamicStylePropertyOptions,
|
||||
MapExtent,
|
||||
MapQuery,
|
||||
VectorJoinSourceRequestMeta,
|
||||
VectorSourceRequestMeta,
|
||||
} from '../../../../common/descriptor_types';
|
||||
|
@ -60,7 +60,7 @@ export interface IESSource extends IVectorSource {
|
|||
style: IVectorStyle;
|
||||
dynamicStyleProps: Array<IDynamicStyleProperty<DynamicStylePropertyOptions>>;
|
||||
registerCancelCallback: (callback: () => void) => void;
|
||||
sourceQuery?: MapQuery;
|
||||
sourceQuery?: Query;
|
||||
timeFilters: TimeRange;
|
||||
searchSessionId?: string;
|
||||
}): Promise<object>;
|
||||
|
@ -88,6 +88,8 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource
|
|||
typeof descriptor.applyGlobalQuery !== 'undefined' ? descriptor.applyGlobalQuery : true,
|
||||
applyGlobalTime:
|
||||
typeof descriptor.applyGlobalTime !== 'undefined' ? descriptor.applyGlobalTime : true,
|
||||
applyForceRefresh:
|
||||
typeof descriptor.applyForceRefresh !== 'undefined' ? descriptor.applyForceRefresh : true,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -108,11 +110,11 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource
|
|||
return this._descriptor.applyGlobalTime;
|
||||
}
|
||||
|
||||
isFieldAware(): boolean {
|
||||
return true;
|
||||
getApplyForceRefresh(): boolean {
|
||||
return this._descriptor.applyForceRefresh;
|
||||
}
|
||||
|
||||
isRefreshTimerAware(): boolean {
|
||||
isFieldAware(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -197,7 +199,7 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource
|
|||
}
|
||||
|
||||
async makeSearchSource(
|
||||
searchFilters: VectorSourceRequestMeta | VectorJoinSourceRequestMeta | BoundsFilters,
|
||||
searchFilters: VectorSourceRequestMeta | VectorJoinSourceRequestMeta | BoundsRequestMeta,
|
||||
limit: number,
|
||||
initialSearchContext?: object
|
||||
): Promise<ISearchSource> {
|
||||
|
@ -253,7 +255,7 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource
|
|||
}
|
||||
|
||||
async getBoundsForFilters(
|
||||
boundsFilters: BoundsFilters,
|
||||
boundsFilters: BoundsRequestMeta,
|
||||
registerCancelCallback: (callback: () => void) => void
|
||||
): Promise<MapExtent | null> {
|
||||
const searchSource = await this.makeSearchSource(boundsFilters, 0);
|
||||
|
@ -421,7 +423,7 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource
|
|||
style: IVectorStyle;
|
||||
dynamicStyleProps: Array<IDynamicStyleProperty<DynamicStylePropertyOptions>>;
|
||||
registerCancelCallback: (callback: () => void) => void;
|
||||
sourceQuery?: MapQuery;
|
||||
sourceQuery?: Query;
|
||||
timeFilters: TimeRange;
|
||||
searchSessionId?: string;
|
||||
}): Promise<object> {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { GeoJsonFileSource } from './geojson_file_source';
|
||||
import { BoundsFilters } from '../vector_source';
|
||||
import { BoundsRequestMeta } from '../vector_source';
|
||||
import { FIELD_ORIGIN } from '../../../../common/constants';
|
||||
|
||||
describe('GeoJsonFileSource', () => {
|
||||
|
@ -20,7 +20,7 @@ describe('GeoJsonFileSource', () => {
|
|||
it('should get null bounds', async () => {
|
||||
const geojsonFileSource = new GeoJsonFileSource({});
|
||||
expect(
|
||||
await geojsonFileSource.getBoundsForFilters(({} as unknown) as BoundsFilters, () => {})
|
||||
await geojsonFileSource.getBoundsForFilters(({} as unknown) as BoundsRequestMeta, () => {})
|
||||
).toEqual(null);
|
||||
});
|
||||
|
||||
|
@ -51,7 +51,7 @@ describe('GeoJsonFileSource', () => {
|
|||
|
||||
expect(geojsonFileSource.isBoundsAware()).toBe(true);
|
||||
expect(
|
||||
await geojsonFileSource.getBoundsForFilters(({} as unknown) as BoundsFilters, () => {})
|
||||
await geojsonFileSource.getBoundsForFilters(({} as unknown) as BoundsRequestMeta, () => {})
|
||||
).toEqual({
|
||||
maxLat: 3,
|
||||
maxLon: 2,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { Feature, FeatureCollection } from 'geojson';
|
||||
import { AbstractVectorSource, BoundsFilters, GeoJsonWithMeta } from '../vector_source';
|
||||
import { AbstractVectorSource, BoundsRequestMeta, GeoJsonWithMeta } from '../vector_source';
|
||||
import { EMPTY_FEATURE_COLLECTION, FIELD_ORIGIN, SOURCE_TYPES } from '../../../../common/constants';
|
||||
import {
|
||||
InlineFieldDescriptor,
|
||||
|
@ -103,7 +103,7 @@ export class GeoJsonFileSource extends AbstractVectorSource {
|
|||
}
|
||||
|
||||
async getBoundsForFilters(
|
||||
boundsFilters: BoundsFilters,
|
||||
boundsFilters: BoundsRequestMeta,
|
||||
registerCancelCallback: (callback: () => void) => void
|
||||
): Promise<MapExtent | null> {
|
||||
const featureCollection = (this._descriptor as GeojsonFileSourceDescriptor).__featureCollection;
|
||||
|
|
|
@ -10,7 +10,7 @@ import uuid from 'uuid/v4';
|
|||
import React from 'react';
|
||||
import { GeoJsonProperties, Geometry, Position } from 'geojson';
|
||||
import { AbstractSource, ImmutableSourceProperty, SourceEditorArgs } from '../source';
|
||||
import { BoundsFilters, GeoJsonWithMeta } from '../vector_source';
|
||||
import { BoundsRequestMeta, GeoJsonWithMeta } from '../vector_source';
|
||||
import { ITiledSingleLayerVectorSource } from '../tiled_single_layer_vector_source';
|
||||
import {
|
||||
FIELD_ORIGIN,
|
||||
|
@ -190,7 +190,7 @@ export class MVTSingleLayerVectorSource
|
|||
}
|
||||
|
||||
async getBoundsForFilters(
|
||||
boundsFilters: BoundsFilters,
|
||||
boundsFilters: BoundsRequestMeta,
|
||||
registerCancelCallback: (callback: () => void) => void
|
||||
): Promise<MapExtent | null> {
|
||||
return null;
|
||||
|
|
|
@ -16,7 +16,7 @@ import { FieldFormatter, LAYER_TYPE, MAX_ZOOM, MIN_ZOOM } from '../../../common/
|
|||
import {
|
||||
AbstractSourceDescriptor,
|
||||
Attribution,
|
||||
DataMeta,
|
||||
DataRequestMeta,
|
||||
Timeslice,
|
||||
} from '../../../common/descriptor_types';
|
||||
import { LICENSED_FEATURES } from '../../licensed_features';
|
||||
|
@ -47,7 +47,6 @@ export interface ISource {
|
|||
isFilterByMapBounds(): boolean;
|
||||
isGeoGridPrecisionAware(): boolean;
|
||||
isQueryAware(): boolean;
|
||||
isRefreshTimerAware(): boolean;
|
||||
isTimeAware(): Promise<boolean>;
|
||||
getImmutableProperties(): Promise<ImmutableSourceProperty[]>;
|
||||
getAttributionProvider(): (() => Promise<Attribution[]>) | null;
|
||||
|
@ -60,6 +59,7 @@ export interface ISource {
|
|||
getFieldNames(): string[];
|
||||
getApplyGlobalQuery(): boolean;
|
||||
getApplyGlobalTime(): boolean;
|
||||
getApplyForceRefresh(): boolean;
|
||||
getIndexPatternIds(): string[];
|
||||
getQueryableIndexPatternIds(): string[];
|
||||
getGeoGridPrecision(zoom: number): number;
|
||||
|
@ -69,7 +69,7 @@ export interface ISource {
|
|||
getMinZoom(): number;
|
||||
getMaxZoom(): number;
|
||||
getLicensedFeatures(): Promise<LICENSED_FEATURES[]>;
|
||||
getUpdateDueToTimeslice(prevMeta: DataMeta, timeslice?: Timeslice): boolean;
|
||||
getUpdateDueToTimeslice(prevMeta: DataRequestMeta, timeslice?: Timeslice): boolean;
|
||||
}
|
||||
|
||||
export class AbstractSource implements ISource {
|
||||
|
@ -115,10 +115,6 @@ export class AbstractSource implements ISource {
|
|||
return false;
|
||||
}
|
||||
|
||||
isRefreshTimerAware(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
isGeoGridPrecisionAware(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
@ -143,6 +139,10 @@ export class AbstractSource implements ISource {
|
|||
return false;
|
||||
}
|
||||
|
||||
getApplyForceRefresh(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
getIndexPatternIds(): string[] {
|
||||
return [];
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ export class AbstractSource implements ISource {
|
|||
return [];
|
||||
}
|
||||
|
||||
getUpdateDueToTimeslice(prevMeta: DataMeta, timeslice?: Timeslice): boolean {
|
||||
getUpdateDueToTimeslice(prevMeta: DataRequestMeta, timeslice?: Timeslice): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { Query } from 'src/plugins/data/common';
|
||||
import { TableSource } from './table_source';
|
||||
import { FIELD_ORIGIN } from '../../../../common/constants';
|
||||
import {
|
||||
MapFilters,
|
||||
MapQuery,
|
||||
DataFilters,
|
||||
VectorJoinSourceRequestMeta,
|
||||
VectorSourceSyncMeta,
|
||||
} from '../../../../common/descriptor_types';
|
||||
|
@ -178,12 +178,12 @@ describe('TableSource', () => {
|
|||
try {
|
||||
await tableSource.getGeoJsonWithMeta(
|
||||
'foobar',
|
||||
({} as unknown) as MapFilters & {
|
||||
({} as unknown) as DataFilters & {
|
||||
applyGlobalQuery: boolean;
|
||||
applyGlobalTime: boolean;
|
||||
fieldNames: string[];
|
||||
geogridPrecision?: number;
|
||||
sourceQuery?: MapQuery;
|
||||
sourceQuery?: Query;
|
||||
sourceMeta: VectorSourceSyncMeta;
|
||||
},
|
||||
() => {},
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
*/
|
||||
|
||||
import uuid from 'uuid';
|
||||
import type { Query } from 'src/plugins/data/common';
|
||||
import { FIELD_ORIGIN, SOURCE_TYPES, VECTOR_SHAPE_TYPE } from '../../../../common/constants';
|
||||
import {
|
||||
MapExtent,
|
||||
MapFilters,
|
||||
MapQuery,
|
||||
DataFilters,
|
||||
TableSourceDescriptor,
|
||||
VectorJoinSourceRequestMeta,
|
||||
VectorSourceSyncMeta,
|
||||
|
@ -19,10 +19,9 @@ import { Adapters } from '../../../../../../../src/plugins/inspector/common/adap
|
|||
import { ITermJoinSource } from '../term_join_source';
|
||||
import { BucketProperties, PropertiesMap } from '../../../../common/elasticsearch_util';
|
||||
import { IField } from '../../fields/field';
|
||||
import { Query } from '../../../../../../../src/plugins/data/common/query';
|
||||
import {
|
||||
AbstractVectorSource,
|
||||
BoundsFilters,
|
||||
BoundsRequestMeta,
|
||||
GeoJsonWithMeta,
|
||||
IVectorSource,
|
||||
SourceTooltipConfig,
|
||||
|
@ -156,7 +155,7 @@ export class TableSource extends AbstractVectorSource implements ITermJoinSource
|
|||
}
|
||||
|
||||
async getBoundsForFilters(
|
||||
boundsFilters: BoundsFilters,
|
||||
boundsFilters: BoundsRequestMeta,
|
||||
registerCancelCallback: (callback: () => void) => void
|
||||
): Promise<MapExtent | null> {
|
||||
return null;
|
||||
|
@ -187,12 +186,12 @@ export class TableSource extends AbstractVectorSource implements ITermJoinSource
|
|||
// Could be useful to implement, e.g. to preview raw csv data
|
||||
async getGeoJsonWithMeta(
|
||||
layerName: string,
|
||||
searchFilters: MapFilters & {
|
||||
searchFilters: DataFilters & {
|
||||
applyGlobalQuery: boolean;
|
||||
applyGlobalTime: boolean;
|
||||
fieldNames: string[];
|
||||
geogridPrecision?: number;
|
||||
sourceQuery?: MapQuery;
|
||||
sourceQuery?: Query;
|
||||
sourceMeta: VectorSourceSyncMeta;
|
||||
},
|
||||
registerCancelCallback: (callback: () => void) => void,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { Query } from 'src/plugins/data/common';
|
||||
import { FeatureCollection, GeoJsonProperties, Geometry, Position } from 'geojson';
|
||||
import { Filter, TimeRange } from 'src/plugins/data/public';
|
||||
import { VECTOR_SHAPE_TYPE } from '../../../../common/constants';
|
||||
|
@ -14,7 +15,6 @@ import { IField } from '../../fields/field';
|
|||
import {
|
||||
ESSearchSourceResponseMeta,
|
||||
MapExtent,
|
||||
MapQuery,
|
||||
Timeslice,
|
||||
VectorSourceRequestMeta,
|
||||
VectorSourceSyncMeta,
|
||||
|
@ -34,12 +34,12 @@ export interface GeoJsonWithMeta {
|
|||
meta?: GeoJsonFetchMeta;
|
||||
}
|
||||
|
||||
export interface BoundsFilters {
|
||||
export interface BoundsRequestMeta {
|
||||
applyGlobalQuery: boolean;
|
||||
applyGlobalTime: boolean;
|
||||
filters: Filter[];
|
||||
query?: MapQuery;
|
||||
sourceQuery?: MapQuery;
|
||||
query?: Query;
|
||||
sourceQuery?: Query;
|
||||
timeFilters: TimeRange;
|
||||
timeslice?: Timeslice;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ export interface BoundsFilters {
|
|||
export interface IVectorSource extends ISource {
|
||||
getTooltipProperties(properties: GeoJsonProperties): Promise<ITooltipProperty[]>;
|
||||
getBoundsForFilters(
|
||||
boundsFilters: BoundsFilters,
|
||||
layerDataFilters: BoundsRequestMeta,
|
||||
registerCancelCallback: (callback: () => void) => void
|
||||
): Promise<MapExtent | null>;
|
||||
getGeoJsonWithMeta(
|
||||
|
@ -103,7 +103,7 @@ export class AbstractVectorSource extends AbstractSource implements IVectorSourc
|
|||
}
|
||||
|
||||
async getBoundsForFilters(
|
||||
boundsFilters: BoundsFilters,
|
||||
boundsFilters: BoundsRequestMeta,
|
||||
registerCancelCallback: (callback: () => void) => void
|
||||
): Promise<MapExtent | null> {
|
||||
return null;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
import { canSkipSourceUpdate, updateDueToExtent } from './can_skip_fetch';
|
||||
import { DataRequest } from './data_request';
|
||||
import { Filter } from 'src/plugins/data/common';
|
||||
import { ISource } from '../sources/source';
|
||||
|
||||
describe('updateDueToExtent', () => {
|
||||
it('should be false when buffers are the same', async () => {
|
||||
|
@ -91,9 +93,6 @@ describe('canSkipSourceUpdate', () => {
|
|||
isTimeAware: () => {
|
||||
return false;
|
||||
},
|
||||
isRefreshTimerAware: () => {
|
||||
return false;
|
||||
},
|
||||
isFilterByMapBounds: () => {
|
||||
return false;
|
||||
},
|
||||
|
@ -107,11 +106,10 @@ describe('canSkipSourceUpdate', () => {
|
|||
return false;
|
||||
},
|
||||
};
|
||||
const prevFilters = [];
|
||||
const prevFilters: Filter[] = [];
|
||||
const prevQuery = {
|
||||
language: 'kuery',
|
||||
query: 'machine.os.keyword : "win 7"',
|
||||
queryLastTriggeredAt: '2019-04-25T20:53:22.331Z',
|
||||
};
|
||||
|
||||
describe('applyGlobalQuery is false', () => {
|
||||
|
@ -119,7 +117,7 @@ describe('canSkipSourceUpdate', () => {
|
|||
|
||||
const prevDataRequest = new DataRequest({
|
||||
dataId: SOURCE_DATA_REQUEST_ID,
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
applyGlobalQuery: prevApplyGlobalQuery,
|
||||
filters: prevFilters,
|
||||
query: prevQuery,
|
||||
|
@ -128,16 +126,16 @@ describe('canSkipSourceUpdate', () => {
|
|||
});
|
||||
|
||||
it('can skip update when filter changes', async () => {
|
||||
const nextMeta = {
|
||||
const nextRequestMeta = {
|
||||
applyGlobalQuery: prevApplyGlobalQuery,
|
||||
filters: [prevQuery],
|
||||
filters: [({} as unknown) as Filter],
|
||||
query: prevQuery,
|
||||
};
|
||||
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: queryAwareSourceMock,
|
||||
source: (queryAwareSourceMock as unknown) as ISource,
|
||||
prevDataRequest,
|
||||
nextMeta,
|
||||
nextRequestMeta,
|
||||
extentAware: queryAwareSourceMock.isFilterByMapBounds(),
|
||||
getUpdateDueToTimeslice,
|
||||
});
|
||||
|
@ -146,7 +144,7 @@ describe('canSkipSourceUpdate', () => {
|
|||
});
|
||||
|
||||
it('can skip update when query changes', async () => {
|
||||
const nextMeta = {
|
||||
const nextRequestMeta = {
|
||||
applyGlobalQuery: prevApplyGlobalQuery,
|
||||
filters: prevFilters,
|
||||
query: {
|
||||
|
@ -156,9 +154,9 @@ describe('canSkipSourceUpdate', () => {
|
|||
};
|
||||
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: queryAwareSourceMock,
|
||||
source: (queryAwareSourceMock as unknown) as ISource,
|
||||
prevDataRequest,
|
||||
nextMeta,
|
||||
nextRequestMeta,
|
||||
extentAware: queryAwareSourceMock.isFilterByMapBounds(),
|
||||
getUpdateDueToTimeslice,
|
||||
});
|
||||
|
@ -166,20 +164,19 @@ describe('canSkipSourceUpdate', () => {
|
|||
expect(canSkipUpdate).toBe(true);
|
||||
});
|
||||
|
||||
it('can not skip update when query is refreshed', async () => {
|
||||
const nextMeta = {
|
||||
it('Should not skip refresh update when applyForceRefresh is true', async () => {
|
||||
const nextRequestMeta = {
|
||||
applyGlobalQuery: prevApplyGlobalQuery,
|
||||
filters: prevFilters,
|
||||
query: {
|
||||
...prevQuery,
|
||||
queryLastTriggeredAt: 'sometime layer when Refresh button is clicked',
|
||||
},
|
||||
query: prevQuery,
|
||||
isForceRefresh: true,
|
||||
applyForceRefresh: true,
|
||||
};
|
||||
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: queryAwareSourceMock,
|
||||
source: (queryAwareSourceMock as unknown) as ISource,
|
||||
prevDataRequest,
|
||||
nextMeta,
|
||||
nextRequestMeta,
|
||||
extentAware: queryAwareSourceMock.isFilterByMapBounds(),
|
||||
getUpdateDueToTimeslice,
|
||||
});
|
||||
|
@ -187,17 +184,37 @@ describe('canSkipSourceUpdate', () => {
|
|||
expect(canSkipUpdate).toBe(false);
|
||||
});
|
||||
|
||||
it('Should skip refresh update when applyForceRefresh is false', async () => {
|
||||
const nextRequestMeta = {
|
||||
applyGlobalQuery: prevApplyGlobalQuery,
|
||||
filters: prevFilters,
|
||||
query: prevQuery,
|
||||
isForceRefresh: true,
|
||||
applyForceRefresh: false,
|
||||
};
|
||||
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: (queryAwareSourceMock as unknown) as ISource,
|
||||
prevDataRequest,
|
||||
nextRequestMeta,
|
||||
extentAware: queryAwareSourceMock.isFilterByMapBounds(),
|
||||
getUpdateDueToTimeslice,
|
||||
});
|
||||
|
||||
expect(canSkipUpdate).toBe(true);
|
||||
});
|
||||
|
||||
it('can not skip update when applyGlobalQuery changes', async () => {
|
||||
const nextMeta = {
|
||||
const nextRequestMeta = {
|
||||
applyGlobalQuery: !prevApplyGlobalQuery,
|
||||
filters: prevFilters,
|
||||
query: prevQuery,
|
||||
};
|
||||
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: queryAwareSourceMock,
|
||||
source: (queryAwareSourceMock as unknown) as ISource,
|
||||
prevDataRequest,
|
||||
nextMeta,
|
||||
nextRequestMeta,
|
||||
extentAware: queryAwareSourceMock.isFilterByMapBounds(),
|
||||
getUpdateDueToTimeslice,
|
||||
});
|
||||
|
@ -211,7 +228,7 @@ describe('canSkipSourceUpdate', () => {
|
|||
|
||||
const prevDataRequest = new DataRequest({
|
||||
dataId: SOURCE_DATA_REQUEST_ID,
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
applyGlobalQuery: prevApplyGlobalQuery,
|
||||
filters: prevFilters,
|
||||
query: prevQuery,
|
||||
|
@ -220,16 +237,16 @@ describe('canSkipSourceUpdate', () => {
|
|||
});
|
||||
|
||||
it('can not skip update when filter changes', async () => {
|
||||
const nextMeta = {
|
||||
const nextRequestMeta = {
|
||||
applyGlobalQuery: prevApplyGlobalQuery,
|
||||
filters: [prevQuery],
|
||||
filters: [({} as unknown) as Filter],
|
||||
query: prevQuery,
|
||||
};
|
||||
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: queryAwareSourceMock,
|
||||
source: (queryAwareSourceMock as unknown) as ISource,
|
||||
prevDataRequest,
|
||||
nextMeta,
|
||||
nextRequestMeta,
|
||||
extentAware: queryAwareSourceMock.isFilterByMapBounds(),
|
||||
getUpdateDueToTimeslice,
|
||||
});
|
||||
|
@ -238,7 +255,7 @@ describe('canSkipSourceUpdate', () => {
|
|||
});
|
||||
|
||||
it('can not skip update when query changes', async () => {
|
||||
const nextMeta = {
|
||||
const nextRequestMeta = {
|
||||
applyGlobalQuery: prevApplyGlobalQuery,
|
||||
filters: prevFilters,
|
||||
query: {
|
||||
|
@ -248,9 +265,9 @@ describe('canSkipSourceUpdate', () => {
|
|||
};
|
||||
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: queryAwareSourceMock,
|
||||
source: (queryAwareSourceMock as unknown) as ISource,
|
||||
prevDataRequest,
|
||||
nextMeta,
|
||||
nextRequestMeta,
|
||||
extentAware: queryAwareSourceMock.isFilterByMapBounds(),
|
||||
getUpdateDueToTimeslice,
|
||||
});
|
||||
|
@ -259,19 +276,18 @@ describe('canSkipSourceUpdate', () => {
|
|||
});
|
||||
|
||||
it('can not skip update when query is refreshed', async () => {
|
||||
const nextMeta = {
|
||||
const nextRequestMeta = {
|
||||
applyGlobalQuery: prevApplyGlobalQuery,
|
||||
filters: prevFilters,
|
||||
query: {
|
||||
...prevQuery,
|
||||
queryLastTriggeredAt: 'sometime layer when Refresh button is clicked',
|
||||
},
|
||||
query: prevQuery,
|
||||
isForceRefresh: true,
|
||||
applyForceRefresh: true,
|
||||
};
|
||||
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: queryAwareSourceMock,
|
||||
source: (queryAwareSourceMock as unknown) as ISource,
|
||||
prevDataRequest,
|
||||
nextMeta,
|
||||
nextRequestMeta,
|
||||
extentAware: queryAwareSourceMock.isFilterByMapBounds(),
|
||||
getUpdateDueToTimeslice,
|
||||
});
|
||||
|
@ -280,16 +296,16 @@ describe('canSkipSourceUpdate', () => {
|
|||
});
|
||||
|
||||
it('can not skip update when applyGlobalQuery changes', async () => {
|
||||
const nextMeta = {
|
||||
const nextRequestMeta = {
|
||||
applyGlobalQuery: !prevApplyGlobalQuery,
|
||||
filters: prevFilters,
|
||||
query: prevQuery,
|
||||
};
|
||||
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: queryAwareSourceMock,
|
||||
source: (queryAwareSourceMock as unknown) as ISource,
|
||||
prevDataRequest,
|
||||
nextMeta,
|
||||
nextRequestMeta,
|
||||
extentAware: queryAwareSourceMock.isFilterByMapBounds(),
|
||||
getUpdateDueToTimeslice,
|
||||
});
|
||||
|
@ -305,9 +321,6 @@ describe('canSkipSourceUpdate', () => {
|
|||
isTimeAware: () => {
|
||||
return true;
|
||||
},
|
||||
isRefreshTimerAware: () => {
|
||||
return false;
|
||||
},
|
||||
isFilterByMapBounds: () => {
|
||||
return false;
|
||||
},
|
||||
|
@ -326,15 +339,15 @@ describe('canSkipSourceUpdate', () => {
|
|||
describe('applyGlobalTime', () => {
|
||||
it('can not skip update when applyGlobalTime changes', async () => {
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: createSourceMock(),
|
||||
source: (createSourceMock() as unknown) as ISource,
|
||||
prevDataRequest: new DataRequest({
|
||||
dataId: SOURCE_DATA_REQUEST_ID,
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
},
|
||||
data: {},
|
||||
}),
|
||||
nextMeta: {
|
||||
nextRequestMeta: {
|
||||
applyGlobalTime: false,
|
||||
},
|
||||
extentAware: false,
|
||||
|
@ -346,15 +359,15 @@ describe('canSkipSourceUpdate', () => {
|
|||
|
||||
it('can skip update when applyGlobalTime does not change', async () => {
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: createSourceMock(),
|
||||
source: (createSourceMock() as unknown) as ISource,
|
||||
prevDataRequest: new DataRequest({
|
||||
dataId: SOURCE_DATA_REQUEST_ID,
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
},
|
||||
data: {},
|
||||
}),
|
||||
nextMeta: {
|
||||
nextRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
},
|
||||
extentAware: false,
|
||||
|
@ -368,10 +381,10 @@ describe('canSkipSourceUpdate', () => {
|
|||
describe('timeFilters', () => {
|
||||
it('can not skip update when time range changes', async () => {
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: createSourceMock(),
|
||||
source: (createSourceMock() as unknown) as ISource,
|
||||
prevDataRequest: new DataRequest({
|
||||
dataId: SOURCE_DATA_REQUEST_ID,
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
timeFilters: {
|
||||
from: 'now-15m',
|
||||
|
@ -380,7 +393,7 @@ describe('canSkipSourceUpdate', () => {
|
|||
},
|
||||
data: {},
|
||||
}),
|
||||
nextMeta: {
|
||||
nextRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
timeFilters: {
|
||||
from: 'now-7d',
|
||||
|
@ -396,10 +409,10 @@ describe('canSkipSourceUpdate', () => {
|
|||
|
||||
it('can skip update when time range does not change', async () => {
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: createSourceMock(),
|
||||
source: (createSourceMock() as unknown) as ISource,
|
||||
prevDataRequest: new DataRequest({
|
||||
dataId: SOURCE_DATA_REQUEST_ID,
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
timeFilters: {
|
||||
from: 'now-15m',
|
||||
|
@ -408,7 +421,7 @@ describe('canSkipSourceUpdate', () => {
|
|||
},
|
||||
data: {},
|
||||
}),
|
||||
nextMeta: {
|
||||
nextRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
timeFilters: {
|
||||
from: 'now-15m',
|
||||
|
@ -424,10 +437,10 @@ describe('canSkipSourceUpdate', () => {
|
|||
|
||||
it('can skip update when time range changes but applyGlobalTime is false', async () => {
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: createSourceMock(),
|
||||
source: (createSourceMock() as unknown) as ISource,
|
||||
prevDataRequest: new DataRequest({
|
||||
dataId: SOURCE_DATA_REQUEST_ID,
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
applyGlobalTime: false,
|
||||
timeFilters: {
|
||||
from: 'now-15m',
|
||||
|
@ -436,7 +449,7 @@ describe('canSkipSourceUpdate', () => {
|
|||
},
|
||||
data: {},
|
||||
}),
|
||||
nextMeta: {
|
||||
nextRequestMeta: {
|
||||
applyGlobalTime: false,
|
||||
timeFilters: {
|
||||
from: 'now-7d',
|
||||
|
@ -455,10 +468,10 @@ describe('canSkipSourceUpdate', () => {
|
|||
const mockSource = createSourceMock();
|
||||
it('can not skip update when timeslice changes (undefined => provided)', async () => {
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: mockSource,
|
||||
source: (mockSource as unknown) as ISource,
|
||||
prevDataRequest: new DataRequest({
|
||||
dataId: SOURCE_DATA_REQUEST_ID,
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
timeFilters: {
|
||||
from: 'now-7d',
|
||||
|
@ -467,7 +480,7 @@ describe('canSkipSourceUpdate', () => {
|
|||
},
|
||||
data: {},
|
||||
}),
|
||||
nextMeta: {
|
||||
nextRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
timeFilters: {
|
||||
from: 'now-7d',
|
||||
|
@ -487,10 +500,10 @@ describe('canSkipSourceUpdate', () => {
|
|||
|
||||
it('can not skip update when timeslice changes', async () => {
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: mockSource,
|
||||
source: (mockSource as unknown) as ISource,
|
||||
prevDataRequest: new DataRequest({
|
||||
dataId: SOURCE_DATA_REQUEST_ID,
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
timeFilters: {
|
||||
from: 'now-7d',
|
||||
|
@ -503,7 +516,7 @@ describe('canSkipSourceUpdate', () => {
|
|||
},
|
||||
data: {},
|
||||
}),
|
||||
nextMeta: {
|
||||
nextRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
timeFilters: {
|
||||
from: 'now-7d',
|
||||
|
@ -523,10 +536,10 @@ describe('canSkipSourceUpdate', () => {
|
|||
|
||||
it('can not skip update when timeslice changes (provided => undefined)', async () => {
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: mockSource,
|
||||
source: (mockSource as unknown) as ISource,
|
||||
prevDataRequest: new DataRequest({
|
||||
dataId: SOURCE_DATA_REQUEST_ID,
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
timeFilters: {
|
||||
from: 'now-7d',
|
||||
|
@ -539,7 +552,7 @@ describe('canSkipSourceUpdate', () => {
|
|||
},
|
||||
data: {},
|
||||
}),
|
||||
nextMeta: {
|
||||
nextRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
timeFilters: {
|
||||
from: 'now-7d',
|
||||
|
@ -555,10 +568,10 @@ describe('canSkipSourceUpdate', () => {
|
|||
|
||||
it('can skip update when timeslice does not change', async () => {
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: mockSource,
|
||||
source: (mockSource as unknown) as ISource,
|
||||
prevDataRequest: new DataRequest({
|
||||
dataId: SOURCE_DATA_REQUEST_ID,
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
timeFilters: {
|
||||
from: 'now-7d',
|
||||
|
@ -571,7 +584,7 @@ describe('canSkipSourceUpdate', () => {
|
|||
},
|
||||
data: {},
|
||||
}),
|
||||
nextMeta: {
|
||||
nextRequestMeta: {
|
||||
applyGlobalTime: true,
|
||||
timeFilters: {
|
||||
from: 'now-7d',
|
||||
|
@ -591,10 +604,10 @@ describe('canSkipSourceUpdate', () => {
|
|||
|
||||
it('can skip update when timeslice changes but applyGlobalTime is false', async () => {
|
||||
const canSkipUpdate = await canSkipSourceUpdate({
|
||||
source: mockSource,
|
||||
source: (mockSource as unknown) as ISource,
|
||||
prevDataRequest: new DataRequest({
|
||||
dataId: SOURCE_DATA_REQUEST_ID,
|
||||
dataMeta: {
|
||||
dataRequestMeta: {
|
||||
applyGlobalTime: false,
|
||||
timeFilters: {
|
||||
from: 'now-7d',
|
||||
|
@ -607,7 +620,7 @@ describe('canSkipSourceUpdate', () => {
|
|||
},
|
||||
data: {},
|
||||
}),
|
||||
nextMeta: {
|
||||
nextRequestMeta: {
|
||||
applyGlobalTime: false,
|
||||
timeFilters: {
|
||||
from: 'now-7d',
|
|
@ -8,15 +8,14 @@
|
|||
import _ from 'lodash';
|
||||
import turfBboxPolygon from '@turf/bbox-polygon';
|
||||
import turfBooleanContains from '@turf/boolean-contains';
|
||||
import { isRefreshOnlyQuery } from './is_refresh_only_query';
|
||||
import { ISource } from '../sources/source';
|
||||
import { DataMeta, Timeslice } from '../../../common/descriptor_types';
|
||||
import { DataRequestMeta, Timeslice } from '../../../common/descriptor_types';
|
||||
import { DataRequest } from './data_request';
|
||||
|
||||
const SOURCE_UPDATE_REQUIRED = true;
|
||||
const NO_SOURCE_UPDATE_REQUIRED = false;
|
||||
|
||||
export function updateDueToExtent(prevMeta: DataMeta = {}, nextMeta: DataMeta = {}) {
|
||||
export function updateDueToExtent(prevMeta: DataRequestMeta = {}, nextMeta: DataRequestMeta = {}) {
|
||||
const { buffer: previousBuffer } = prevMeta;
|
||||
const { buffer: newBuffer } = nextMeta;
|
||||
|
||||
|
@ -54,30 +53,28 @@ export function updateDueToExtent(prevMeta: DataMeta = {}, nextMeta: DataMeta =
|
|||
export async function canSkipSourceUpdate({
|
||||
source,
|
||||
prevDataRequest,
|
||||
nextMeta,
|
||||
nextRequestMeta,
|
||||
extentAware,
|
||||
getUpdateDueToTimeslice,
|
||||
}: {
|
||||
source: ISource;
|
||||
prevDataRequest: DataRequest | undefined;
|
||||
nextMeta: DataMeta;
|
||||
nextRequestMeta: DataRequestMeta;
|
||||
extentAware: boolean;
|
||||
getUpdateDueToTimeslice: (timeslice?: Timeslice) => boolean;
|
||||
}): Promise<boolean> {
|
||||
const mustForceRefresh = nextRequestMeta.isForceRefresh && nextRequestMeta.applyForceRefresh;
|
||||
if (mustForceRefresh) {
|
||||
// Cannot skip
|
||||
return false;
|
||||
}
|
||||
|
||||
const timeAware = await source.isTimeAware();
|
||||
const refreshTimerAware = await source.isRefreshTimerAware();
|
||||
const isFieldAware = source.isFieldAware();
|
||||
const isQueryAware = source.isQueryAware();
|
||||
const isGeoGridPrecisionAware = source.isGeoGridPrecisionAware();
|
||||
|
||||
if (
|
||||
!timeAware &&
|
||||
!refreshTimerAware &&
|
||||
!extentAware &&
|
||||
!isFieldAware &&
|
||||
!isQueryAware &&
|
||||
!isGeoGridPrecisionAware
|
||||
) {
|
||||
if (!timeAware && !extentAware && !isFieldAware && !isQueryAware && !isGeoGridPrecisionAware) {
|
||||
return !!prevDataRequest && prevDataRequest.hasDataOrRequestInProgress();
|
||||
}
|
||||
|
||||
|
@ -93,26 +90,18 @@ export async function canSkipSourceUpdate({
|
|||
let updateDueToTime = false;
|
||||
let updateDueToTimeslice = false;
|
||||
if (timeAware) {
|
||||
updateDueToApplyGlobalTime = prevMeta.applyGlobalTime !== nextMeta.applyGlobalTime;
|
||||
if (nextMeta.applyGlobalTime) {
|
||||
updateDueToTime = !_.isEqual(prevMeta.timeFilters, nextMeta.timeFilters);
|
||||
if (!_.isEqual(prevMeta.timeslice, nextMeta.timeslice)) {
|
||||
updateDueToTimeslice = getUpdateDueToTimeslice(nextMeta.timeslice);
|
||||
updateDueToApplyGlobalTime = prevMeta.applyGlobalTime !== nextRequestMeta.applyGlobalTime;
|
||||
if (nextRequestMeta.applyGlobalTime) {
|
||||
updateDueToTime = !_.isEqual(prevMeta.timeFilters, nextRequestMeta.timeFilters);
|
||||
if (!_.isEqual(prevMeta.timeslice, nextRequestMeta.timeslice)) {
|
||||
updateDueToTimeslice = getUpdateDueToTimeslice(nextRequestMeta.timeslice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let updateDueToRefreshTimer = false;
|
||||
if (refreshTimerAware && nextMeta.refreshTimerLastTriggeredAt) {
|
||||
updateDueToRefreshTimer = !_.isEqual(
|
||||
prevMeta.refreshTimerLastTriggeredAt,
|
||||
nextMeta.refreshTimerLastTriggeredAt
|
||||
);
|
||||
}
|
||||
|
||||
let updateDueToFields = false;
|
||||
if (isFieldAware) {
|
||||
updateDueToFields = !_.isEqual(prevMeta.fieldNames, nextMeta.fieldNames);
|
||||
updateDueToFields = !_.isEqual(prevMeta.fieldNames, nextRequestMeta.fieldNames);
|
||||
}
|
||||
|
||||
let updateDueToQuery = false;
|
||||
|
@ -120,42 +109,41 @@ export async function canSkipSourceUpdate({
|
|||
let updateDueToSourceQuery = false;
|
||||
let updateDueToApplyGlobalQuery = false;
|
||||
if (isQueryAware) {
|
||||
updateDueToApplyGlobalQuery = prevMeta.applyGlobalQuery !== nextMeta.applyGlobalQuery;
|
||||
updateDueToSourceQuery = !_.isEqual(prevMeta.sourceQuery, nextMeta.sourceQuery);
|
||||
updateDueToApplyGlobalQuery = prevMeta.applyGlobalQuery !== nextRequestMeta.applyGlobalQuery;
|
||||
updateDueToSourceQuery = !_.isEqual(prevMeta.sourceQuery, nextRequestMeta.sourceQuery);
|
||||
|
||||
if (nextMeta.applyGlobalQuery) {
|
||||
updateDueToQuery = !_.isEqual(prevMeta.query, nextMeta.query);
|
||||
updateDueToFilters = !_.isEqual(prevMeta.filters, nextMeta.filters);
|
||||
} else {
|
||||
// Global filters and query are not applied to layer search request so no re-fetch required.
|
||||
// Exception is "Refresh" query.
|
||||
updateDueToQuery = isRefreshOnlyQuery(prevMeta.query, nextMeta.query);
|
||||
if (nextRequestMeta.applyGlobalQuery) {
|
||||
updateDueToQuery = !_.isEqual(prevMeta.query, nextRequestMeta.query);
|
||||
updateDueToFilters = !_.isEqual(prevMeta.filters, nextRequestMeta.filters);
|
||||
}
|
||||
}
|
||||
|
||||
let updateDueToSearchSessionId = false;
|
||||
if (timeAware || isQueryAware) {
|
||||
updateDueToSearchSessionId = prevMeta.searchSessionId !== nextMeta.searchSessionId;
|
||||
if ((timeAware || isQueryAware) && nextRequestMeta.applyForceRefresh) {
|
||||
// If the force-refresh flag is turned off, we should ignore refreshes on the dashboard-context
|
||||
updateDueToSearchSessionId = prevMeta.searchSessionId !== nextRequestMeta.searchSessionId;
|
||||
}
|
||||
|
||||
let updateDueToPrecisionChange = false;
|
||||
let updateDueToExtentChange = false;
|
||||
|
||||
if (isGeoGridPrecisionAware) {
|
||||
updateDueToPrecisionChange = !_.isEqual(prevMeta.geogridPrecision, nextMeta.geogridPrecision);
|
||||
updateDueToPrecisionChange = !_.isEqual(
|
||||
prevMeta.geogridPrecision,
|
||||
nextRequestMeta.geogridPrecision
|
||||
);
|
||||
}
|
||||
|
||||
if (extentAware) {
|
||||
updateDueToExtentChange = updateDueToExtent(prevMeta, nextMeta);
|
||||
updateDueToExtentChange = updateDueToExtent(prevMeta, nextRequestMeta);
|
||||
}
|
||||
|
||||
const updateDueToSourceMetaChange = !_.isEqual(prevMeta.sourceMeta, nextMeta.sourceMeta);
|
||||
const updateDueToSourceMetaChange = !_.isEqual(prevMeta.sourceMeta, nextRequestMeta.sourceMeta);
|
||||
|
||||
return (
|
||||
!updateDueToApplyGlobalTime &&
|
||||
!updateDueToTime &&
|
||||
!updateDueToTimeslice &&
|
||||
!updateDueToRefreshTimer &&
|
||||
!updateDueToExtentChange &&
|
||||
!updateDueToFields &&
|
||||
!updateDueToQuery &&
|
||||
|
@ -173,7 +161,7 @@ export function canSkipStyleMetaUpdate({
|
|||
nextMeta,
|
||||
}: {
|
||||
prevDataRequest: DataRequest | undefined;
|
||||
nextMeta: DataMeta;
|
||||
nextMeta: DataRequestMeta;
|
||||
}): boolean {
|
||||
if (!prevDataRequest) {
|
||||
return false;
|
||||
|
@ -208,7 +196,7 @@ export function canSkipFormattersUpdate({
|
|||
nextMeta,
|
||||
}: {
|
||||
prevDataRequest: DataRequest | undefined;
|
||||
nextMeta: DataMeta;
|
||||
nextMeta: DataRequestMeta;
|
||||
}): boolean {
|
||||
if (!prevDataRequest) {
|
||||
return false;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
/* eslint-disable max-classes-per-file */
|
||||
|
||||
import { DataRequestDescriptor, DataMeta } from '../../../common/descriptor_types';
|
||||
import { DataRequestDescriptor, DataRequestMeta } from '../../../common/descriptor_types';
|
||||
|
||||
export class DataRequest {
|
||||
private readonly _descriptor: DataRequestDescriptor;
|
||||
|
@ -26,11 +26,11 @@ export class DataRequest {
|
|||
return !!this._descriptor.dataRequestToken;
|
||||
}
|
||||
|
||||
getMeta(): DataMeta {
|
||||
if (this._descriptor.dataMetaAtStart) {
|
||||
return this._descriptor.dataMetaAtStart;
|
||||
} else if (this._descriptor.dataMeta) {
|
||||
return this._descriptor.dataMeta;
|
||||
getMeta(): DataRequestMeta {
|
||||
if (this._descriptor.dataRequestMetaAtStart) {
|
||||
return this._descriptor.dataRequestMetaAtStart;
|
||||
} else if (this._descriptor.dataRequestMeta) {
|
||||
return this._descriptor.dataRequestMeta;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { MapQuery } from '../../../common/descriptor_types';
|
||||
|
||||
// Refresh only query is query where timestamps are different but query is the same.
|
||||
// Triggered by clicking "Refresh" button in QueryBar
|
||||
export function isRefreshOnlyQuery(
|
||||
prevQuery: MapQuery | undefined,
|
||||
newQuery: MapQuery | undefined
|
||||
): boolean {
|
||||
if (!prevQuery || !newQuery) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
prevQuery.queryLastTriggeredAt !== newQuery.queryLastTriggeredAt &&
|
||||
prevQuery.language === newQuery.language &&
|
||||
prevQuery.query === newQuery.query
|
||||
);
|
||||
}
|
|
@ -15,7 +15,7 @@ import {
|
|||
import { Timeslice } from '../../../common/descriptor_types';
|
||||
|
||||
export interface TimesliceMaskConfig {
|
||||
timesiceMaskField: string;
|
||||
timesliceMaskField: string;
|
||||
timeslice: Timeslice;
|
||||
}
|
||||
|
||||
|
@ -34,15 +34,15 @@ function getFilterExpression(
|
|||
}
|
||||
|
||||
if (timesliceMaskConfig) {
|
||||
allFilters.push(['has', timesliceMaskConfig.timesiceMaskField]);
|
||||
allFilters.push(['has', timesliceMaskConfig.timesliceMaskField]);
|
||||
allFilters.push([
|
||||
'>=',
|
||||
['get', timesliceMaskConfig.timesiceMaskField],
|
||||
['get', timesliceMaskConfig.timesliceMaskField],
|
||||
timesliceMaskConfig.timeslice.from,
|
||||
]);
|
||||
allFilters.push([
|
||||
'<',
|
||||
['get', timesliceMaskConfig.timesiceMaskField],
|
||||
['get', timesliceMaskConfig.timesliceMaskField],
|
||||
timesliceMaskConfig.timeslice.to,
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiFormRow, EuiSwitch, EuiSwitchEvent, EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
interface Props {
|
||||
applyForceRefresh: boolean;
|
||||
setApplyForceRefresh: (applyGlobalTime: boolean) => void;
|
||||
}
|
||||
|
||||
export function ForceRefreshCheckbox({ applyForceRefresh, setApplyForceRefresh }: Props) {
|
||||
const onRespondToForceRefreshChange = (event: EuiSwitchEvent) => {
|
||||
setApplyForceRefresh(event.target.checked);
|
||||
};
|
||||
|
||||
return (
|
||||
<EuiFormRow display="columnCompressedSwitch">
|
||||
<EuiToolTip
|
||||
position="top"
|
||||
content={i18n.translate('xpack.maps.filterEditor.applyForceRefreshTooltip', {
|
||||
defaultMessage: `When enabled, results are narrowed by search bar`,
|
||||
})}
|
||||
>
|
||||
<EuiSwitch
|
||||
label={i18n.translate('xpack.maps.filterEditor.applyForceRefreshLabel', {
|
||||
defaultMessage: `Apply global refresh to layer data`,
|
||||
})}
|
||||
checked={applyForceRefresh}
|
||||
onChange={onRespondToForceRefreshChange}
|
||||
data-test-subj="mapLayerPanelRespondToForceRefreshCheckbox"
|
||||
compressed
|
||||
/>
|
||||
</EuiToolTip>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
|
@ -6,7 +6,8 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiFormRow, EuiSwitch, EuiSwitchEvent } from '@elastic/eui';
|
||||
import { EuiFormRow, EuiSwitch, EuiSwitchEvent, EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
interface Props {
|
||||
applyGlobalQuery: boolean;
|
||||
|
@ -21,13 +22,20 @@ export function GlobalFilterCheckbox({ applyGlobalQuery, label, setApplyGlobalQu
|
|||
|
||||
return (
|
||||
<EuiFormRow display="columnCompressedSwitch">
|
||||
<EuiSwitch
|
||||
label={label}
|
||||
checked={applyGlobalQuery}
|
||||
onChange={onApplyGlobalQueryChange}
|
||||
data-test-subj="mapLayerPanelApplyGlobalQueryCheckbox"
|
||||
compressed
|
||||
/>
|
||||
<EuiToolTip
|
||||
position="top"
|
||||
content={i18n.translate('xpack.maps.filterEditor.applyGlobalFilterHelp', {
|
||||
defaultMessage: 'When enabled, results narrowed by global search',
|
||||
})}
|
||||
>
|
||||
<EuiSwitch
|
||||
label={label}
|
||||
checked={applyGlobalQuery}
|
||||
onChange={onApplyGlobalQueryChange}
|
||||
data-test-subj="mapLayerPanelApplyGlobalQueryCheckbox"
|
||||
compressed
|
||||
/>
|
||||
</EuiToolTip>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiFormRow, EuiSwitch, EuiSwitchEvent } from '@elastic/eui';
|
||||
|
||||
import { EuiFormRow, EuiSwitch, EuiSwitchEvent, EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
interface Props {
|
||||
applyGlobalTime: boolean;
|
||||
label: string;
|
||||
|
@ -21,13 +21,20 @@ export function GlobalTimeCheckbox({ applyGlobalTime, label, setApplyGlobalTime
|
|||
|
||||
return (
|
||||
<EuiFormRow display="columnCompressedSwitch">
|
||||
<EuiSwitch
|
||||
label={label}
|
||||
checked={applyGlobalTime}
|
||||
onChange={onApplyGlobalTimeChange}
|
||||
data-test-subj="mapLayerPanelApplyGlobalTimeCheckbox"
|
||||
compressed
|
||||
/>
|
||||
<EuiToolTip
|
||||
position="top"
|
||||
content={i18n.translate('xpack.maps.filterEditor.applyGlobalTimeHelp', {
|
||||
defaultMessage: 'When enabled, results narrowed by global time filter',
|
||||
})}
|
||||
>
|
||||
<EuiSwitch
|
||||
label={label}
|
||||
checked={applyGlobalTime}
|
||||
onChange={onApplyGlobalTimeChange}
|
||||
data-test-subj="mapLayerPanelApplyGlobalTimeCheckbox"
|
||||
compressed
|
||||
/>
|
||||
</EuiToolTip>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -15,8 +15,10 @@ import {
|
|||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiTextColor,
|
||||
EuiTextAlign,
|
||||
EuiButtonEmpty,
|
||||
EuiHorizontalRule,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
@ -27,6 +29,7 @@ import { getIndexPatternService, getData } from '../../../kibana_services';
|
|||
import { GlobalFilterCheckbox } from '../../../components/global_filter_checkbox';
|
||||
import { GlobalTimeCheckbox } from '../../../components/global_time_checkbox';
|
||||
import { ILayer } from '../../../classes/layers/layer';
|
||||
import { ForceRefreshCheckbox } from '../../../components/force_refresh_checkbox';
|
||||
|
||||
export interface Props {
|
||||
layer: ILayer;
|
||||
|
@ -113,6 +116,10 @@ export class FilterEditor extends Component<Props, State> {
|
|||
this.props.updateSourceProp(this.props.layer.getId(), 'applyGlobalTime', applyGlobalTime);
|
||||
};
|
||||
|
||||
_onRespondToForceRefreshChange = (applyForceRefresh: boolean) => {
|
||||
this.props.updateSourceProp(this.props.layer.getId(), 'applyForceRefresh', applyForceRefresh);
|
||||
};
|
||||
|
||||
_renderQueryPopover() {
|
||||
const layerQuery = this.props.layer.getQuery();
|
||||
const { SearchBar } = getData().ui;
|
||||
|
@ -153,7 +160,7 @@ export class FilterEditor extends Component<Props, State> {
|
|||
const query = this.props.layer.getQuery();
|
||||
if (!query || !query.query) {
|
||||
return (
|
||||
<EuiText size="s" textAlign="center">
|
||||
<EuiText size="s">
|
||||
<p>
|
||||
<EuiTextColor color="subdued">
|
||||
<FormattedMessage
|
||||
|
@ -169,7 +176,6 @@ export class FilterEditor extends Component<Props, State> {
|
|||
return (
|
||||
<Fragment>
|
||||
<EuiCodeBlock paddingSize="s">{query.query}</EuiCodeBlock>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
</Fragment>
|
||||
);
|
||||
|
@ -183,7 +189,7 @@ export class FilterEditor extends Component<Props, State> {
|
|||
defaultMessage: 'Edit filter',
|
||||
})
|
||||
: i18n.translate('xpack.maps.layerPanel.filterEditor.addFilterButtonLabel', {
|
||||
defaultMessage: 'Add filter',
|
||||
defaultMessage: 'Set filter',
|
||||
});
|
||||
const openButtonIcon = query && query.query ? 'pencil' : 'plusInCircleFilled';
|
||||
|
||||
|
@ -209,6 +215,7 @@ export class FilterEditor extends Component<Props, State> {
|
|||
setApplyGlobalTime={this._onApplyGlobalTimeChange}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiTitle size="xs">
|
||||
|
@ -222,12 +229,15 @@ export class FilterEditor extends Component<Props, State> {
|
|||
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
{this._renderQuery()}
|
||||
|
||||
<EuiTextAlign textAlign="center">{this._renderQueryPopover()}</EuiTextAlign>
|
||||
<EuiFlexGroup direction={'row'} wrap={false} component={'span'}>
|
||||
<EuiFlexItem grow={1}>{this._renderQueryPopover()}</EuiFlexItem>
|
||||
<EuiFlexItem grow={6}>{this._renderQuery()}</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
<EuiHorizontalRule size="full" margin="s" />
|
||||
|
||||
<GlobalFilterCheckbox
|
||||
label={i18n.translate('xpack.maps.filterEditor.applyGlobalQueryCheckboxLabel', {
|
||||
defaultMessage: `Apply global filter to layer data`,
|
||||
|
@ -237,6 +247,10 @@ export class FilterEditor extends Component<Props, State> {
|
|||
/>
|
||||
|
||||
{globalTimeCheckbox}
|
||||
<ForceRefreshCheckbox
|
||||
applyForceRefresh={this.props.layer.getSource().getApplyForceRefresh()}
|
||||
setApplyForceRefresh={this._onRespondToForceRefreshChange}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
jest.mock('../../actions', () => ({}));
|
||||
|
||||
import { DataMeta, DataRequestDescriptor } from '../../../common/descriptor_types';
|
||||
import { DataRequestMeta, DataRequestDescriptor } from '../../../common/descriptor_types';
|
||||
import {
|
||||
getDataRequest,
|
||||
setDataRequest,
|
||||
|
@ -157,7 +157,7 @@ describe('startDataRequest', () => {
|
|||
const REQUEST_TOKEN = Symbol('request');
|
||||
const DATA_META_AT_START = {
|
||||
prop1: 'value',
|
||||
} as DataMeta;
|
||||
} as DataRequestMeta;
|
||||
|
||||
test('Should return unmodified state if layer not found', () => {
|
||||
const state = ({
|
||||
|
@ -186,7 +186,7 @@ describe('startDataRequest', () => {
|
|||
__dataRequests: [
|
||||
{
|
||||
dataId: 'source',
|
||||
dataMetaAtStart: DATA_META_AT_START,
|
||||
dataRequestMetaAtStart: DATA_META_AT_START,
|
||||
dataRequestToken: REQUEST_TOKEN,
|
||||
},
|
||||
],
|
||||
|
@ -204,7 +204,7 @@ describe('startDataRequest', () => {
|
|||
__dataRequests: [
|
||||
{
|
||||
dataId: 'source',
|
||||
dataMetaAtStart: { prop1: 'old value' },
|
||||
dataRequestMetaAtStart: { prop1: 'old value' },
|
||||
dataRequestToken: Symbol('request'),
|
||||
},
|
||||
],
|
||||
|
@ -219,7 +219,7 @@ describe('startDataRequest', () => {
|
|||
__dataRequests: [
|
||||
{
|
||||
dataId: 'source',
|
||||
dataMetaAtStart: DATA_META_AT_START,
|
||||
dataRequestMetaAtStart: DATA_META_AT_START,
|
||||
dataRequestToken: REQUEST_TOKEN,
|
||||
},
|
||||
],
|
||||
|
@ -270,7 +270,7 @@ describe('stopDataRequest', () => {
|
|||
{
|
||||
dataId: 'source',
|
||||
dataRequestToken: REQUEST_TOKEN,
|
||||
dataMetaAtStart: { requestProp1: 'request' },
|
||||
dataRequestMetaAtStart: { requestProp1: 'request' },
|
||||
data: { prop1: 'old data ' },
|
||||
},
|
||||
],
|
||||
|
@ -278,7 +278,7 @@ describe('stopDataRequest', () => {
|
|||
],
|
||||
} as unknown) as MapState;
|
||||
const stateClone = _.cloneDeep(state);
|
||||
const reponseMeta = { responseProp1: 'response' } as DataMeta;
|
||||
const reponseMeta = { responseProp1: 'response' } as DataRequestMeta;
|
||||
const data = { prop1: 'new data' };
|
||||
expect(stopDataRequest(state, 'layer1', 'source', REQUEST_TOKEN, reponseMeta, data)).toEqual({
|
||||
layerList: [
|
||||
|
@ -287,9 +287,9 @@ describe('stopDataRequest', () => {
|
|||
__dataRequests: [
|
||||
{
|
||||
dataId: 'source',
|
||||
dataMeta: { requestProp1: 'request', responseProp1: 'response' },
|
||||
dataRequestMeta: { requestProp1: 'request', responseProp1: 'response' },
|
||||
data: { prop1: 'new data' },
|
||||
dataMetaAtStart: undefined,
|
||||
dataRequestMetaAtStart: undefined,
|
||||
dataRequestToken: undefined,
|
||||
},
|
||||
],
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { SOURCE_DATA_REQUEST_ID } from '../../../common/constants';
|
||||
import { findLayerById, setLayer } from './layer_utils';
|
||||
import { DataMeta, DataRequestDescriptor } from '../../../common/descriptor_types';
|
||||
import { DataRequestMeta, DataRequestDescriptor } from '../../../common/descriptor_types';
|
||||
import { MapState } from './types';
|
||||
|
||||
export function startDataRequest(
|
||||
|
@ -15,7 +15,7 @@ export function startDataRequest(
|
|||
layerId: string,
|
||||
dataRequestId: string,
|
||||
requestToken: symbol,
|
||||
requestMeta: DataMeta
|
||||
requestMeta: DataRequestMeta
|
||||
): MapState {
|
||||
const layerDescriptor = findLayerById(state, layerId);
|
||||
if (!layerDescriptor) {
|
||||
|
@ -30,7 +30,7 @@ export function startDataRequest(
|
|||
: {
|
||||
dataId: dataRequestId,
|
||||
};
|
||||
dataRequest.dataMetaAtStart = requestMeta;
|
||||
dataRequest.dataRequestMetaAtStart = requestMeta;
|
||||
dataRequest.dataRequestToken = requestToken;
|
||||
return setDataRequest(state, layerId, dataRequest);
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ export function stopDataRequest(
|
|||
layerId: string,
|
||||
dataRequestId: string,
|
||||
requestToken: symbol,
|
||||
responseMeta?: DataMeta,
|
||||
responseMeta?: DataRequestMeta,
|
||||
data?: object
|
||||
): MapState {
|
||||
const dataRequest = getDataRequest(state, layerId, dataRequestId, requestToken);
|
||||
|
@ -57,11 +57,11 @@ export function stopDataRequest(
|
|||
? setDataRequest(state, layerId, {
|
||||
...dataRequest,
|
||||
data,
|
||||
dataMeta: {
|
||||
...(dataRequest.dataMetaAtStart ? dataRequest.dataMetaAtStart : {}),
|
||||
dataRequestMeta: {
|
||||
...(dataRequest.dataRequestMetaAtStart ? dataRequest.dataRequestMetaAtStart : {}),
|
||||
...(responseMeta ? responseMeta : {}),
|
||||
},
|
||||
dataMetaAtStart: undefined,
|
||||
dataRequestMetaAtStart: undefined,
|
||||
dataRequestToken: undefined,
|
||||
})
|
||||
: state;
|
||||
|
|
|
@ -75,7 +75,6 @@ export const DEFAULT_MAP_STATE: MapState = {
|
|||
timeslice: undefined,
|
||||
query: undefined,
|
||||
filters: [],
|
||||
refreshTimerLastTriggeredAt: undefined,
|
||||
drawState: undefined,
|
||||
editState: undefined,
|
||||
},
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
/* eslint-disable @typescript-eslint/consistent-type-definitions */
|
||||
|
||||
import type { Query } from 'src/plugins/data/common';
|
||||
import {
|
||||
DrawState,
|
||||
EditState,
|
||||
|
@ -14,7 +15,6 @@ import {
|
|||
LayerDescriptor,
|
||||
MapCenter,
|
||||
MapExtent,
|
||||
MapQuery,
|
||||
Timeslice,
|
||||
TooltipState,
|
||||
} from '../../../common/descriptor_types';
|
||||
|
@ -39,9 +39,8 @@ export type MapContext = Partial<MapViewContext> & {
|
|||
};
|
||||
timeFilters?: TimeRange;
|
||||
timeslice?: Timeslice;
|
||||
query?: MapQuery;
|
||||
query?: Query;
|
||||
filters: Filter[];
|
||||
refreshTimerLastTriggeredAt?: string;
|
||||
drawState?: DrawState;
|
||||
editState?: EditState;
|
||||
searchSessionId?: string;
|
||||
|
|
|
@ -12,6 +12,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { AppLeaveAction, AppMountParameters } from 'kibana/public';
|
||||
import { Adapters } from 'src/plugins/embeddable/public';
|
||||
import { Subscription } from 'rxjs';
|
||||
import type { Query, Filter, TimeRange, IndexPattern } from 'src/plugins/data/common';
|
||||
import {
|
||||
getData,
|
||||
getCoreChrome,
|
||||
|
@ -30,10 +31,6 @@ import {
|
|||
} from '../url_state';
|
||||
import {
|
||||
esFilters,
|
||||
Filter,
|
||||
Query,
|
||||
TimeRange,
|
||||
IndexPattern,
|
||||
SavedQuery,
|
||||
QueryStateChange,
|
||||
QueryState,
|
||||
|
@ -41,7 +38,6 @@ import {
|
|||
import { MapContainer } from '../../../connected_components/map_container';
|
||||
import { getIndexPatternsFromIds } from '../../../index_pattern_util';
|
||||
import { getTopNavConfig } from '../top_nav_config';
|
||||
import { MapQuery } from '../../../../common/descriptor_types';
|
||||
import { goToSpecifiedPath } from '../../../render_app';
|
||||
import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type';
|
||||
import { getFullPath, APP_ID } from '../../../../common/constants';
|
||||
|
@ -87,7 +83,7 @@ export interface Props {
|
|||
}) => void;
|
||||
timeFilters: TimeRange;
|
||||
isSaveDisabled: boolean;
|
||||
query: MapQuery | undefined;
|
||||
query: Query | undefined;
|
||||
setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
|
||||
}
|
||||
|
||||
|
|
|
@ -402,7 +402,7 @@ export class SavedMap {
|
|||
isPaused: getTimeFilter().getRefreshInterval().pause,
|
||||
interval: getTimeFilter().getRefreshInterval().value,
|
||||
},
|
||||
query: _.omit(getQuery(state), 'queryLastTriggeredAt'),
|
||||
query: getQuery(state),
|
||||
filters: getFilters(state),
|
||||
settings: getMapSettings(state),
|
||||
});
|
||||
|
|
|
@ -58,7 +58,6 @@ describe('getDataFilters', () => {
|
|||
const mapZoom = 4;
|
||||
const timeFilters = { to: '2001-01-01', from: '2001-12-31' };
|
||||
const timeslice = undefined;
|
||||
const refreshTimerLastTriggeredAt = '2001-01-01T00:00:00';
|
||||
const query = undefined;
|
||||
const filters: Filter[] = [];
|
||||
const searchSessionId = '12345';
|
||||
|
@ -77,7 +76,6 @@ describe('getDataFilters', () => {
|
|||
mapZoom,
|
||||
timeFilters,
|
||||
timeslice,
|
||||
refreshTimerLastTriggeredAt,
|
||||
query,
|
||||
filters,
|
||||
searchSessionId,
|
||||
|
@ -94,7 +92,6 @@ describe('getDataFilters', () => {
|
|||
mapZoom,
|
||||
timeFilters,
|
||||
timeslice,
|
||||
refreshTimerLastTriggeredAt,
|
||||
query,
|
||||
filters,
|
||||
searchSessionId,
|
||||
|
|
|
@ -9,6 +9,7 @@ import { createSelector } from 'reselect';
|
|||
import { FeatureCollection } from 'geojson';
|
||||
import _ from 'lodash';
|
||||
import { Adapters } from 'src/plugins/inspector/public';
|
||||
import type { Query } from 'src/plugins/data/common';
|
||||
import { TileLayer } from '../classes/layers/tile_layer/tile_layer';
|
||||
// @ts-ignore
|
||||
import { VectorTileLayer } from '../classes/layers/vector_tile_layer/vector_tile_layer';
|
||||
|
@ -45,7 +46,6 @@ import {
|
|||
LayerDescriptor,
|
||||
MapCenter,
|
||||
MapExtent,
|
||||
MapQuery,
|
||||
TooltipState,
|
||||
VectorLayerDescriptor,
|
||||
} from '../../common/descriptor_types';
|
||||
|
@ -179,7 +179,7 @@ export const getTimeFilters = ({ map }: MapStoreState): TimeRange =>
|
|||
|
||||
export const getTimeslice = ({ map }: MapStoreState) => map.mapState.timeslice;
|
||||
|
||||
export const getQuery = ({ map }: MapStoreState): MapQuery | undefined => map.mapState.query;
|
||||
export const getQuery = ({ map }: MapStoreState): Query | undefined => map.mapState.query;
|
||||
|
||||
export const getFilters = ({ map }: MapStoreState): Filter[] => map.mapState.filters;
|
||||
|
||||
|
@ -201,9 +201,6 @@ export const getDrawState = ({ map }: MapStoreState): DrawState | undefined =>
|
|||
export const getEditState = ({ map }: MapStoreState): EditState | undefined =>
|
||||
map.mapState.editState;
|
||||
|
||||
export const getRefreshTimerLastTriggeredAt = ({ map }: MapStoreState): string | undefined =>
|
||||
map.mapState.refreshTimerLastTriggeredAt;
|
||||
|
||||
function getLayerDescriptor(state: MapStoreState, layerId: string) {
|
||||
const layerListRaw = getLayerListRaw(state);
|
||||
return layerListRaw.find((layer) => layer.id === layerId);
|
||||
|
@ -225,7 +222,6 @@ export const getDataFilters = createSelector(
|
|||
getMapZoom,
|
||||
getTimeFilters,
|
||||
getTimeslice,
|
||||
getRefreshTimerLastTriggeredAt,
|
||||
getQuery,
|
||||
getFilters,
|
||||
getSearchSessionId,
|
||||
|
@ -237,7 +233,6 @@ export const getDataFilters = createSelector(
|
|||
mapZoom,
|
||||
timeFilters,
|
||||
timeslice,
|
||||
refreshTimerLastTriggeredAt,
|
||||
query,
|
||||
filters,
|
||||
searchSessionId,
|
||||
|
@ -250,7 +245,6 @@ export const getDataFilters = createSelector(
|
|||
zoom: mapZoom,
|
||||
timeFilters,
|
||||
timeslice,
|
||||
refreshTimerLastTriggeredAt,
|
||||
query,
|
||||
filters,
|
||||
searchSessionId,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue