Skip to content

Commit

Permalink
[Maps] Blended layer that switches between documents and clusters (#5…
Browse files Browse the repository at this point in the history
…7879)

* [Maps] Blended layer that switches between documents and clusters

* change layer type when scalingType changes

* getSource

* use cluster source when count exceeds value

* ensure doc source stays in editor

* start creating cluster style

* pass all parts of style descriptor

* get toggling between sources working

* derive cluster style from document style

* remove references to METRIC_TYPE

* fix import

* start typescripting blended_vector_layer

* more typescript work

* last of the TS errors

* add migration to convert useTopTerm to scalingType

* clean up

* remove MapSavedObject work since its in a seperate PR now

* fix EsSearchSource update editor jest test

* fix map_selector jest test

* move mutable state out of BlendedVectorLayer

* one more change for removing mutable BlendedVectorLayer state

* integrate newly merged MapSavedObjectAttributes type

* review feedback

* use data request for fetching feature count

* add functional test

* fix functional test

* review feedback

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
nreese and elasticmachine committed Mar 18, 2020
1 parent 0a80a4b commit 7e085ea
Show file tree
Hide file tree
Showing 49 changed files with 1,214 additions and 284 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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 */

// Global map state passed to every layer.
export type MapFilters = {
buffer: unknown;
extent: unknown;
filters: unknown[];
query: unknown;
refreshTimerLastTriggeredAt: string;
timeFilters: unknown;
zoom: number;
};

export type VectorLayerRequestMeta = MapFilters & {
applyGlobalQuery: boolean;
fieldNames: string[];
geogridPrecision: number;
sourceQuery: unknown;
sourceMeta: unknown;
};

export type ESSearchSourceResponseMeta = {
areResultsTrimmed?: boolean;
sourceType?: string;

// top hits meta
areEntitiesTrimmed?: boolean;
entityCount?: number;
totalEntities?: number;
};

// Partial because objects are justified downstream in constructors
export type DataMeta = Partial<VectorLayerRequestMeta> & Partial<ESSearchSourceResponseMeta>;

export type DataRequestDescriptor = {
dataId: string;
dataMetaAtStart?: DataMeta;
dataRequestToken?: symbol;
data?: object;
dataMeta?: DataMeta;
};
13 changes: 3 additions & 10 deletions x-pack/legacy/plugins/maps/common/descriptor_types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
*/
/* eslint-disable @typescript-eslint/consistent-type-definitions */

import { AGG_TYPE, GRID_RESOLUTION, RENDER_AS, SORT_ORDER } from './constants';
import { DataRequestDescriptor } from './data_request_descriptor_types';
import { AGG_TYPE, GRID_RESOLUTION, RENDER_AS, SORT_ORDER, SCALING_TYPES } from './constants';

export type AbstractSourceDescriptor = {
id?: string;
Expand Down Expand Up @@ -49,7 +50,7 @@ export type ESSearchSourceDescriptor = AbstractESSourceDescriptor & {
tooltipProperties?: string[];
sortField?: string;
sortOrder?: SORT_ORDER;
useTopHits?: boolean;
scalingType: SCALING_TYPES;
topHitsSplitField?: string;
topHitsSize?: number;
};
Expand Down Expand Up @@ -93,14 +94,6 @@ export type JoinDescriptor = {
right: ESTermSourceDescriptor;
};

export type DataRequestDescriptor = {
dataId: string;
dataMetaAtStart: object;
dataRequestToken: symbol;
data: object;
dataMeta: object;
};

export type LayerDescriptor = {
__dataRequests?: DataRequestDescriptor[];
__isInErrorState?: boolean;
Expand Down
74 changes: 74 additions & 0 deletions x-pack/legacy/plugins/maps/common/migrations/scaling_type.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* 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.
*/

import { migrateUseTopHitsToScalingType } from './scaling_type';

describe('migrateUseTopHitsToScalingType', () => {
test('Should handle missing layerListJSON attribute', () => {
const attributes = {
title: 'my map',
};
expect(migrateUseTopHitsToScalingType({ attributes })).toEqual({
title: 'my map',
});
});

test('Should migrate useTopHits: true to scalingType TOP_HITS for ES documents sources', () => {
const layerListJSON = JSON.stringify([
{
sourceDescriptor: {
type: 'ES_SEARCH',
useTopHits: true,
},
},
]);
const attributes = {
title: 'my map',
layerListJSON,
};
expect(migrateUseTopHitsToScalingType({ attributes })).toEqual({
title: 'my map',
layerListJSON: '[{"sourceDescriptor":{"type":"ES_SEARCH","scalingType":"TOP_HITS"}}]',
});
});

test('Should migrate useTopHits: false to scalingType LIMIT for ES documents sources', () => {
const layerListJSON = JSON.stringify([
{
sourceDescriptor: {
type: 'ES_SEARCH',
useTopHits: false,
},
},
]);
const attributes = {
title: 'my map',
layerListJSON,
};
expect(migrateUseTopHitsToScalingType({ attributes })).toEqual({
title: 'my map',
layerListJSON: '[{"sourceDescriptor":{"type":"ES_SEARCH","scalingType":"LIMIT"}}]',
});
});

test('Should set scalingType to LIMIT when useTopHits is not set', () => {
const layerListJSON = JSON.stringify([
{
sourceDescriptor: {
type: 'ES_SEARCH',
},
},
]);
const attributes = {
title: 'my map',
layerListJSON,
};
expect(migrateUseTopHitsToScalingType({ attributes })).toEqual({
title: 'my map',
layerListJSON: '[{"sourceDescriptor":{"type":"ES_SEARCH","scalingType":"LIMIT"}}]',
});
});
});
43 changes: 43 additions & 0 deletions x-pack/legacy/plugins/maps/common/migrations/scaling_type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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.
*/

import _ from 'lodash';
import { ES_SEARCH, SCALING_TYPES } from '../constants';
import { LayerDescriptor, ESSearchSourceDescriptor } from '../descriptor_types';
import { MapSavedObjectAttributes } from '../../../../../plugins/maps/common/map_saved_object_type';

function isEsDocumentSource(layerDescriptor: LayerDescriptor) {
const sourceType = _.get(layerDescriptor, 'sourceDescriptor.type');
return sourceType === ES_SEARCH;
}

export function migrateUseTopHitsToScalingType({
attributes,
}: {
attributes: MapSavedObjectAttributes;
}): MapSavedObjectAttributes {
if (!attributes || !attributes.layerListJSON) {
return attributes;
}

const layerList: LayerDescriptor[] = JSON.parse(attributes.layerListJSON);
layerList.forEach((layerDescriptor: LayerDescriptor) => {
if (isEsDocumentSource(layerDescriptor)) {
const sourceDescriptor = layerDescriptor.sourceDescriptor as ESSearchSourceDescriptor;
sourceDescriptor.scalingType = _.get(layerDescriptor, 'sourceDescriptor.useTopHits', false)
? SCALING_TYPES.TOP_HITS
: SCALING_TYPES.LIMIT;
// @ts-ignore useTopHits no longer in type definition but that does not mean its not in live data
// hence the entire point of this method
delete sourceDescriptor.useTopHits;
}
});

return {
...attributes,
layerListJSON: JSON.stringify(layerList),
};
}
6 changes: 4 additions & 2 deletions x-pack/legacy/plugins/maps/migrations.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { topHitsTimeToSort } from './common/migrations/top_hits_time_to_sort';
import { moveApplyGlobalQueryToSources } from './common/migrations/move_apply_global_query';
import { addFieldMetaOptions } from './common/migrations/add_field_meta_options';
import { migrateSymbolStyleDescriptor } from './common/migrations/migrate_symbol_style_descriptor';
import { migrateUseTopHitsToScalingType } from './common/migrations/scaling_type';

export const migrations = {
map: {
Expand Down Expand Up @@ -48,11 +49,12 @@ export const migrations = {
};
},
'7.7.0': doc => {
const attributes = migrateSymbolStyleDescriptor(doc);
const attributesPhase1 = migrateSymbolStyleDescriptor(doc);
const attributesPhase2 = migrateUseTopHitsToScalingType({ attributes: attributesPhase1 });

return {
...doc,
attributes,
attributes: attributesPhase2,
};
},
},
Expand Down
18 changes: 18 additions & 0 deletions x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* 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 */

import { DataMeta, MapFilters } from '../../common/data_request_descriptor_types';

export type SyncContext = {
startLoading(dataId: string, requestToken: symbol, meta: DataMeta): void;
stopLoading(dataId: string, requestToken: symbol, data: unknown, meta: DataMeta): void;
onLoadError(dataId: string, requestToken: symbol, errorMessage: string): void;
updateSourceData(newData: unknown): void;
isRequestStillActive(dataId: string, requestToken: symbol): boolean;
registerCancelCallback(requestToken: symbol, callback: () => void): void;
dataFilters: MapFilters;
};
3 changes: 2 additions & 1 deletion x-pack/legacy/plugins/maps/public/actions/map_actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -649,13 +649,14 @@ export function onDataLoadError(layerId, dataId, requestToken, errorMessage) {
};
}

export function updateSourceProp(layerId, propName, value) {
export function updateSourceProp(layerId, propName, value, newLayerType) {
return async dispatch => {
dispatch({
type: UPDATE_SOURCE_PROP,
layerId,
propName,
value,
newLayerType,
});
await dispatch(clearMissingStyleProperties(layerId));
dispatch(syncDataForLayer(layerId));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import {
EuiTextColor,
EuiTextAlign,
EuiButtonEmpty,
EuiFormRow,
EuiSwitch,
} from '@elastic/eui';

import { FormattedMessage } from '@kbn/i18n/react';
Expand Down Expand Up @@ -80,14 +78,6 @@ export class FilterEditor extends Component {
this._close();
};

_onFilterByMapBoundsChange = event => {
this.props.updateSourceProp(
this.props.layer.getId(),
'filterByMapBounds',
event.target.checked
);
};

_onApplyGlobalQueryChange = applyGlobalQuery => {
this.props.updateSourceProp(this.props.layer.getId(), 'applyGlobalQuery', applyGlobalQuery);
};
Expand Down Expand Up @@ -182,22 +172,6 @@ export class FilterEditor extends Component {
}

render() {
let filterByBoundsSwitch;
if (this.props.layer.getSource().isFilterByMapBoundsConfigurable()) {
filterByBoundsSwitch = (
<EuiFormRow display="rowCompressed">
<EuiSwitch
label={i18n.translate('xpack.maps.filterEditor.extentFilterLabel', {
defaultMessage: 'Dynamically filter for data in the visible map area',
})}
checked={this.props.layer.getSource().isFilterByMapBounds()}
onChange={this._onFilterByMapBoundsChange}
compressed
/>
</EuiFormRow>
);
}

return (
<Fragment>
<EuiTitle size="xs">
Expand All @@ -217,8 +191,6 @@ export class FilterEditor extends Component {

<EuiSpacer size="m" />

{filterByBoundsSwitch}

<GlobalFilterCheckbox
label={i18n.translate('xpack.maps.filterEditor.applyGlobalQueryCheckboxLabel', {
defaultMessage: `Apply global filter to layer data`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ function mapDispatchToProps(dispatch) {
fitToBounds: layerId => {
dispatch(fitToLayerExtent(layerId));
},
updateSourceProp: (id, propName, value) => dispatch(updateSourceProp(id, propName, value)),
updateSourceProp: (id, propName, value, newLayerType) =>
dispatch(updateSourceProp(id, propName, value, newLayerType)),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ export class LayerPanel extends React.Component {
}
}

_onSourceChange = ({ propName, value }) => {
this.props.updateSourceProp(this.props.selectedLayer.getId(), propName, value);
_onSourceChange = ({ propName, value, newLayerType }) => {
this.props.updateSourceProp(this.props.selectedLayer.getId(), propName, value, newLayerType);
};

_renderFilterSection() {
Expand Down
Loading

0 comments on commit 7e085ea

Please sign in to comment.