merge with master (#61097)

This commit is contained in:
Nathan Reese 2020-03-24 12:09:48 -06:00 committed by GitHub
parent 96d235fc9e
commit f680edc443
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 141 additions and 53 deletions

View file

@ -5,25 +5,41 @@
*/
/* eslint-disable @typescript-eslint/consistent-type-definitions */
import { Query } from './map_descriptor';
type Extent = {
maxLat: number;
maxLon: number;
minLat: number;
minLon: number;
};
// Global map state passed to every layer.
export type MapFilters = {
buffer: unknown;
extent: unknown;
buffer: Extent; // extent with additional buffer
extent: Extent; // map viewport
filters: unknown[];
query: unknown;
query: Query;
refreshTimerLastTriggeredAt: string;
timeFilters: unknown;
zoom: number;
};
export type VectorLayerRequestMeta = MapFilters & {
export type VectorSourceRequestMeta = MapFilters & {
applyGlobalQuery: boolean;
fieldNames: string[];
geogridPrecision: number;
sourceQuery: unknown;
sourceQuery: Query;
sourceMeta: unknown;
};
export type VectorStyleRequestMeta = MapFilters & {
dynamicStyleFields: string[];
isTimeAware: boolean;
sourceQuery: Query;
timeFilters: unknown;
};
export type ESSearchSourceResponseMeta = {
areResultsTrimmed?: boolean;
sourceType?: string;
@ -35,7 +51,9 @@ export type ESSearchSourceResponseMeta = {
};
// Partial because objects are justified downstream in constructors
export type DataMeta = Partial<VectorLayerRequestMeta> & Partial<ESSearchSourceResponseMeta>;
export type DataMeta = Partial<VectorSourceRequestMeta> &
Partial<VectorStyleRequestMeta> &
Partial<ESSearchSourceResponseMeta>;
export type DataRequestDescriptor = {
dataId: string;

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
/* eslint-disable @typescript-eslint/consistent-type-definitions */
export type Query = {
language: string;
query: string;
queryLastTriggeredAt: string;
};

View file

@ -23,7 +23,6 @@ import {
FIELD_ORIGIN,
} from '../../common/constants';
import { ESGeoGridSource } from './sources/es_geo_grid_source/es_geo_grid_source';
// @ts-ignore
import { canSkipSourceUpdate } from './util/can_skip_fetch';
import { IVectorLayer, VectorLayerArguments } from './vector_layer';
import { IESSource } from './sources/es_source';

View file

@ -7,7 +7,7 @@
import { AbstractVectorSource } from './vector_source';
import { IVectorSource } from './vector_source';
import { IndexPattern, SearchSource } from '../../../../../../../src/plugins/data/public';
import { VectorLayerRequestMeta } from '../../../common/data_request_descriptor_types';
import { VectorSourceRequestMeta } from '../../../common/data_request_descriptor_types';
export interface IESSource extends IVectorSource {
getId(): string;
@ -16,7 +16,7 @@ export interface IESSource extends IVectorSource {
getGeoFieldName(): string;
getMaxResultWindow(): Promise<number>;
makeSearchSource(
searchFilters: VectorLayerRequestMeta,
searchFilters: VectorSourceRequestMeta,
limit: number,
initialSearchContext?: object
): Promise<SearchSource>;
@ -29,7 +29,7 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource
getGeoFieldName(): string;
getMaxResultWindow(): Promise<number>;
makeSearchSource(
searchFilters: VectorLayerRequestMeta,
searchFilters: VectorSourceRequestMeta,
limit: number,
initialSearchContext?: object
): Promise<SearchSource>;

View file

@ -9,15 +9,28 @@ import { ILayer } from '../layer';
export interface ISource {
createDefaultLayer(): ILayer;
getDisplayName(): Promise<string>;
destroy(): void;
getDisplayName(): Promise<string>;
getInspectorAdapters(): object;
isFieldAware(): boolean;
isFilterByMapBounds(): boolean;
isGeoGridPrecisionAware(): boolean;
isQueryAware(): boolean;
isRefreshTimerAware(): Promise<boolean>;
isTimeAware(): Promise<boolean>;
}
export class AbstractSource implements ISource {
constructor(sourceDescriptor: AbstractSourceDescriptor, inspectorAdapters: object);
destroy(): void;
createDefaultLayer(): ILayer;
getDisplayName(): Promise<string>;
destroy(): void;
getInspectorAdapters(): object;
isFieldAware(): boolean;
isFilterByMapBounds(): boolean;
isGeoGridPrecisionAware(): boolean;
isQueryAware(): boolean;
isRefreshTimerAware(): Promise<boolean>;
isTimeAware(): Promise<boolean>;
}

View file

@ -5,6 +5,7 @@
*/
/* eslint-disable @typescript-eslint/consistent-type-definitions */
import { FeatureCollection } from 'geojson';
import { AbstractSource, ISource } from './source';
import { IField } from '../fields/field';
import { ESSearchSourceResponseMeta } from '../../../common/data_request_descriptor_types';
@ -12,7 +13,7 @@ import { ESSearchSourceResponseMeta } from '../../../common/data_request_descrip
export type GeoJsonFetchMeta = ESSearchSourceResponseMeta;
export type GeoJsonWithMeta = {
data: unknown; // geojson feature collection
data: FeatureCollection;
meta?: GeoJsonFetchMeta;
};

View file

@ -7,7 +7,7 @@
import { TileLayer } from './tile_layer';
import { EMS_XYZ } from '../../common/constants';
import { XYZTMSSourceDescriptor } from '../../common/descriptor_types';
import { ITMSSource } from './sources/tms_source';
import { ITMSSource, AbstractTMSSource } from './sources/tms_source';
import { ILayer } from './layer';
const sourceDescriptor: XYZTMSSourceDescriptor = {
@ -16,9 +16,10 @@ const sourceDescriptor: XYZTMSSourceDescriptor = {
id: 'foobar',
};
class MockTileSource implements ITMSSource {
class MockTileSource extends AbstractTMSSource implements ITMSSource {
private readonly _descriptor: XYZTMSSourceDescriptor;
constructor(descriptor: XYZTMSSourceDescriptor) {
super(descriptor, {});
this._descriptor = descriptor;
}
createDefaultLayer(): ILayer {
@ -32,14 +33,6 @@ class MockTileSource implements ITMSSource {
async getUrlTemplate(): Promise<string> {
return 'template/{x}/{y}/{z}.png';
}
destroy(): void {
// no-op
}
getInspectorAdapters(): object {
return {};
}
}
describe('TileLayer', () => {

View file

@ -6,19 +6,25 @@
import { assignFeatureIds } from './assign_feature_ids';
import { FEATURE_ID_PROPERTY_NAME } from '../../../common/constants';
import { FeatureCollection, Feature, Point } from 'geojson';
const featureId = 'myFeature1';
const geometry: Point = {
type: 'Point',
coordinates: [0, 0],
};
const defaultFeature: Feature = {
type: 'Feature',
geometry,
properties: {},
};
test('should provide unique id when feature.id is not provided', () => {
const featureCollection = {
features: [
{
properties: {},
},
{
properties: {},
},
],
const featureCollection: FeatureCollection = {
type: 'FeatureCollection',
features: [{ ...defaultFeature }, { ...defaultFeature }],
};
const updatedFeatureCollection = assignFeatureIds(featureCollection);
@ -26,16 +32,18 @@ test('should provide unique id when feature.id is not provided', () => {
const feature2 = updatedFeatureCollection.features[1];
expect(typeof feature1.id).toBe('number');
expect(typeof feature2.id).toBe('number');
// @ts-ignore
expect(feature1.id).toBe(feature1.properties[FEATURE_ID_PROPERTY_NAME]);
expect(feature1.id).not.toBe(feature2.id);
});
test('should preserve feature id when provided', () => {
const featureCollection = {
const featureCollection: FeatureCollection = {
type: 'FeatureCollection',
features: [
{
...defaultFeature,
id: featureId,
properties: {},
},
],
};
@ -43,16 +51,19 @@ test('should preserve feature id when provided', () => {
const updatedFeatureCollection = assignFeatureIds(featureCollection);
const feature1 = updatedFeatureCollection.features[0];
expect(typeof feature1.id).toBe('number');
// @ts-ignore
expect(feature1.id).not.toBe(feature1.properties[FEATURE_ID_PROPERTY_NAME]);
// @ts-ignore
expect(feature1.properties[FEATURE_ID_PROPERTY_NAME]).toBe(featureId);
});
test('should preserve feature id for falsy value', () => {
const featureCollection = {
const featureCollection: FeatureCollection = {
type: 'FeatureCollection',
features: [
{
...defaultFeature,
id: 0,
properties: {},
},
],
};
@ -60,15 +71,19 @@ test('should preserve feature id for falsy value', () => {
const updatedFeatureCollection = assignFeatureIds(featureCollection);
const feature1 = updatedFeatureCollection.features[0];
expect(typeof feature1.id).toBe('number');
// @ts-ignore
expect(feature1.id).not.toBe(feature1.properties[FEATURE_ID_PROPERTY_NAME]);
// @ts-ignore
expect(feature1.properties[FEATURE_ID_PROPERTY_NAME]).toBe(0);
});
test('should not modify original feature properties', () => {
const featureProperties = {};
const featureCollection = {
const featureCollection: FeatureCollection = {
type: 'FeatureCollection',
features: [
{
...defaultFeature,
id: featureId,
properties: featureProperties,
},
@ -77,6 +92,7 @@ test('should not modify original feature properties', () => {
const updatedFeatureCollection = assignFeatureIds(featureCollection);
const feature1 = updatedFeatureCollection.features[0];
// @ts-ignore
expect(feature1.properties[FEATURE_ID_PROPERTY_NAME]).toBe(featureId);
expect(featureProperties).not.toHaveProperty(FEATURE_ID_PROPERTY_NAME);
});

View file

@ -5,17 +5,18 @@
*/
import _ from 'lodash';
import { FeatureCollection, Feature } from 'geojson';
import { FEATURE_ID_PROPERTY_NAME } from '../../../common/constants';
let idCounter = 0;
function generateNumericalId() {
function generateNumericalId(): number {
const newId = idCounter < Number.MAX_SAFE_INTEGER ? idCounter : 0;
idCounter = newId + 1;
return newId;
}
export function assignFeatureIds(featureCollection) {
export function assignFeatureIds(featureCollection: FeatureCollection): FeatureCollection {
// wrt https://github.com/elastic/kibana/issues/39317
// In constrained resource environments, mapbox-gl may throw a stackoverflow error due to hitting the browser's recursion limit. This crashes Kibana.
// This error is thrown in mapbox-gl's quicksort implementation, when it is sorting all the features by id.
@ -32,7 +33,7 @@ export function assignFeatureIds(featureCollection) {
}
const randomizedIds = _.shuffle(ids);
const features = [];
const features: Feature[] = [];
for (let i = 0; i < featureCollection.features.length; i++) {
const numericId = randomizedIds[i];
const feature = featureCollection.features[i];

View file

@ -4,14 +4,22 @@
* you may not use this file except in compliance with the Elastic License.
*/
import _ from 'lodash';
// @ts-ignore
import turf from 'turf';
import turfBooleanContains from '@turf/boolean-contains';
import { isRefreshOnlyQuery } from './is_refresh_only_query';
import { ISource } from '../sources/source';
import { DataMeta } from '../../../common/data_request_descriptor_types';
import { DataRequest } from './data_request';
const SOURCE_UPDATE_REQUIRED = true;
const NO_SOURCE_UPDATE_REQUIRED = false;
export function updateDueToExtent(source, prevMeta = {}, nextMeta = {}) {
export function updateDueToExtent(
source: ISource,
prevMeta: DataMeta = {},
nextMeta: DataMeta = {}
) {
const extentAware = source.isFilterByMapBounds();
if (!extentAware) {
return NO_SOURCE_UPDATE_REQUIRED;
@ -20,7 +28,7 @@ export function updateDueToExtent(source, prevMeta = {}, nextMeta = {}) {
const { buffer: previousBuffer } = prevMeta;
const { buffer: newBuffer } = nextMeta;
if (!previousBuffer) {
if (!previousBuffer || !previousBuffer || !newBuffer) {
return SOURCE_UPDATE_REQUIRED;
}
@ -51,7 +59,15 @@ export function updateDueToExtent(source, prevMeta = {}, nextMeta = {}) {
: SOURCE_UPDATE_REQUIRED;
}
export async function canSkipSourceUpdate({ source, prevDataRequest, nextMeta }) {
export async function canSkipSourceUpdate({
source,
prevDataRequest,
nextMeta,
}: {
source: ISource;
prevDataRequest: DataRequest | undefined;
nextMeta: DataMeta;
}): Promise<boolean> {
const timeAware = await source.isTimeAware();
const refreshTimerAware = await source.isRefreshTimerAware();
const extentAware = source.isFilterByMapBounds();
@ -67,7 +83,7 @@ export async function canSkipSourceUpdate({ source, prevDataRequest, nextMeta })
!isQueryAware &&
!isGeoGridPrecisionAware
) {
return prevDataRequest && prevDataRequest.hasDataOrRequestInProgress();
return !!prevDataRequest && prevDataRequest.hasDataOrRequestInProgress();
}
if (!prevDataRequest) {
@ -136,7 +152,13 @@ export async function canSkipSourceUpdate({ source, prevDataRequest, nextMeta })
);
}
export function canSkipStyleMetaUpdate({ prevDataRequest, nextMeta }) {
export function canSkipStyleMetaUpdate({
prevDataRequest,
nextMeta,
}: {
prevDataRequest: DataRequest | undefined;
nextMeta: DataMeta;
}): boolean {
if (!prevDataRequest) {
return false;
}
@ -159,7 +181,13 @@ export function canSkipStyleMetaUpdate({ prevDataRequest, nextMeta }) {
);
}
export function canSkipFormattersUpdate({ prevDataRequest, nextMeta }) {
export function canSkipFormattersUpdate({
prevDataRequest,
nextMeta,
}: {
prevDataRequest: DataRequest | undefined;
nextMeta: DataMeta;
}): boolean {
if (!prevDataRequest) {
return false;
}

View file

@ -4,9 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { Query } from '../../../common/map_descriptor';
// 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, newQuery) {
export function isRefreshOnlyQuery(
prevQuery: Query | undefined,
newQuery: Query | undefined
): boolean {
if (!prevQuery || !newQuery) {
return false;
}

View file

@ -34,14 +34,14 @@ const POINT_MB_FILTER = [
const VISIBLE_POINT_MB_FILTER = [...VISIBILITY_FILTER_CLAUSE, POINT_MB_FILTER];
export function getFillFilterExpression(hasJoins) {
export function getFillFilterExpression(hasJoins: boolean): unknown[] {
return hasJoins ? VISIBLE_CLOSED_SHAPE_MB_FILTER : CLOSED_SHAPE_MB_FILTER;
}
export function getLineFilterExpression(hasJoins) {
export function getLineFilterExpression(hasJoins: boolean): unknown[] {
return hasJoins ? VISIBLE_ALL_SHAPE_MB_FILTER : ALL_SHAPE_MB_FILTER;
}
export function getPointFilterExpression(hasJoins) {
export function getPointFilterExpression(hasJoins: boolean): unknown[] {
return hasJoins ? VISIBLE_POINT_MB_FILTER : POINT_MB_FILTER;
}

View file

@ -8,7 +8,7 @@
import { AbstractLayer } from './layer';
import { IVectorSource } from './sources/vector_source';
import { VectorLayerDescriptor } from '../../common/descriptor_types';
import { MapFilters, VectorLayerRequestMeta } from '../../common/data_request_descriptor_types';
import { MapFilters, VectorSourceRequestMeta } from '../../common/data_request_descriptor_types';
import { ILayer } from './layer';
import { IJoin } from './joins/join';
import { IVectorStyle } from './styles/vector/vector_style';
@ -45,6 +45,6 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer {
dataFilters: MapFilters,
source: IVectorSource,
style: IVectorStyle
): VectorLayerRequestMeta;
): VectorSourceRequestMeta;
_syncData(syncContext: SyncContext, source: IVectorSource, style: IVectorStyle): Promise<void>;
}

View file

@ -59,6 +59,7 @@
"@types/elasticsearch": "^5.0.33",
"@types/fancy-log": "^1.3.1",
"@types/file-saver": "^2.0.0",
"@types/geojson": "7946.0.7",
"@types/getos": "^3.0.0",
"@types/git-url-parse": "^9.0.0",
"@types/glob": "^7.1.1",

View file

@ -5175,7 +5175,7 @@
dependencies:
"@types/jquery" "*"
"@types/geojson@*":
"@types/geojson@*", "@types/geojson@7946.0.7":
version "7946.0.7"
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad"
integrity sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==