Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Maps] geo line source #76572

Merged
merged 29 commits into from
Dec 3, 2020
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9762345
[Maps] geo line source
nreese Sep 2, 2020
060e44a
update editor with metrics
nreese Sep 3, 2020
c4788cd
show track name in tooltip
nreese Sep 3, 2020
a203cf0
fix styling by category
nreese Sep 3, 2020
a1895c0
avoid killing ES, limit to 100 tracks
nreese Sep 3, 2020
fa9f66e
better source tooltip message
nreese Sep 3, 2020
335d440
merge with master
nreese Sep 14, 2020
c365867
merge with master
nreese Nov 2, 2020
dccc802
fix imports
nreese Nov 2, 2020
bce45df
increase max tracks
nreese Nov 2, 2020
77dee60
Merge branch 'master' into geo_line
kibanamachine Nov 30, 2020
1cb8aae
use tracks icon
nreese Nov 30, 2020
891a60b
tslint
nreese Nov 30, 2020
96ac781
Making layer wizard select tooltip flex
miukimiu Nov 30, 2020
02f492b
tslint and jest snapshot updates
nreese Nov 30, 2020
4c415cc
clean up
nreese Nov 30, 2020
15f7799
Merge branch 'master' into geo_line
kibanamachine Dec 1, 2020
5bb7212
add trimmed property to tooltip
nreese Dec 1, 2020
4427613
change complete label to 'track is complete'
nreese Dec 1, 2020
4485f93
show incomplete data icon if tracks are trimmed
nreese Dec 1, 2020
5da8cdb
add jest test for getSourceTooltipContent
nreese Dec 1, 2020
7bbfa54
clean up areResultsTrimmed logic
nreese Dec 1, 2020
c0c72f8
split request into 2 fetches
nreese Dec 2, 2020
b7e6390
Merge branch 'master' into geo_line
kibanamachine Dec 2, 2020
d932913
Merge branch 'master' of github.com:elastic/kibana into geo_line
nreese Dec 3, 2020
e7c9032
review feedback
nreese Dec 3, 2020
11d5701
do not allow selecting split field as sort field
nreese Dec 3, 2020
7364c8c
reduce number of tracks to 250
nreese Dec 3, 2020
2bc733d
tslint
nreese Dec 3, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions x-pack/plugins/maps/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export enum SOURCE_TYPES {
EMS_TMS = 'EMS_TMS',
EMS_FILE = 'EMS_FILE',
ES_GEO_GRID = 'ES_GEO_GRID',
ES_GEO_LINE = 'ES_GEO_LINE',
ES_SEARCH = 'ES_SEARCH',
ES_PEW_PEW = 'ES_PEW_PEW',
ES_TERM_SOURCE = 'ES_TERM_SOURCE',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ export type ESGeoGridSourceDescriptor = AbstractESAggSourceDescriptor & {
resolution: GRID_RESOLUTION;
};

export type ESGeoLineSourceDescriptor = AbstractESAggSourceDescriptor & {
splitField: string;
sortField: string;
};

export type ESSearchSourceDescriptor = AbstractESSourceDescriptor & {
geoField: string;
filterByMapBounds?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export type LayerWizard = {
categories: LAYER_WIZARD_CATEGORY[];
checkVisibility?: () => Promise<boolean>;
description: string;
disabledReason?: string;
icon: string | FunctionComponent<any>;
getIsDisabled?: () => boolean;
nreese marked this conversation as resolved.
Show resolved Hide resolved
prerequisiteSteps?: Array<{ id: string; label: string }>;
renderWizard(renderWizardArguments: RenderWizardArguments): ReactElement<any>;
title: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { uploadLayerWizardConfig } from './file_upload_wizard';
import { esDocumentsLayerWizardConfig } from '../sources/es_search_source';
// @ts-ignore
import { clustersLayerWizardConfig, heatmapLayerWizardConfig } from '../sources/es_geo_grid_source';
import { geoLineLayerWizardConfig } from '../sources/es_geo_line_source';
// @ts-ignore
import { point2PointLayerWizardConfig } from '../sources/es_pew_pew_source';
// @ts-ignore
Expand Down Expand Up @@ -45,6 +46,7 @@ export function registerLayerWizards() {
registerLayerWizard(clustersLayerWizardConfig);
// @ts-ignore
registerLayerWizard(heatmapLayerWizardConfig);
registerLayerWizard(geoLineLayerWizardConfig);
// @ts-ignore
registerLayerWizard(point2PointLayerWizardConfig);
// @ts-ignore
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* 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 { convertToGeoJson } from './convert_to_geojson';

const esResponse = {
aggregations: {
entitySplit: {
buckets: [
{
key: 'ios',
doc_count: 1,
path: {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [
[-95.339639, 41.584389],
[-95.339639, 41.0],
],
},
properties: {
complete: true,
},
},
},
{
key: 'osx',
doc_count: 1,
path: {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [
[-97.902775, 48.940572],
[-97.902775, 48.0],
],
},
properties: {
complete: true,
},
},
},
],
},
},
};

it('Should convert elasticsearch aggregation response into feature collection', () => {
const geoJson = convertToGeoJson(esResponse, 'machine.os.keyword');
expect(geoJson.featureCollection.features.length).toBe(2);
expect(geoJson.featureCollection.features[0]).toEqual({
geometry: {
coordinates: [
[-95.339639, 41.584389],
[-95.339639, 41.0],
],
type: 'LineString',
},
id: 'ios',
properties: {
complete: true,
doc_count: 1,
['machine.os.keyword']: 'ios',
},
type: 'Feature',
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* 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 { Feature } from 'geojson';
import { extractPropertiesFromBucket } from '../../../../common/elasticsearch_util';

const KEYS_TO_IGNORE = ['key', 'path'];

export function convertToGeoJson(esResponse: any, entitySplitFieldName: string) {
const features = [];

const buckets = _.get(esResponse, 'aggregations.entitySplit.buckets', []);
buckets.forEach((bucket: any) => {
const feature = bucket.path as Feature;
feature.id = bucket.key;
feature.properties = {
[entitySplitFieldName]: bucket.key,
...feature.properties,
...extractPropertiesFromBucket(bucket, KEYS_TO_IGNORE),
};
features.push(feature);
});

return {
featureCollection: {
type: 'FeatureCollection',
features,
},
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* 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 React, { Component } from 'react';

import { IndexPattern } from 'src/plugins/data/public';
import { i18n } from '@kbn/i18n';
import { EuiFormRow, EuiPanel } from '@elastic/eui';
import { SingleFieldSelect } from '../../../components/single_field_select';
import { GeoIndexPatternSelect } from '../../../components/geo_index_pattern_select';
import { ESGeoLineSourceDescriptor } from '../../../../common/descriptor_types';

import { getGeoPointFields } from '../../../index_pattern_util';
import { indexPatterns } from '../../../../../../../src/plugins/data/public';
import { GeoLineForm } from './geo_line_form';

interface Props {
onSourceConfigChange: (sourceConfig: Partial<ESGeoLineSourceDescriptor>) => void;
}

interface State {
indexPattern: IndexPattern | null;
geoField: string;
splitField: string;
sortField: string;
}

export class CreateSourceEditor extends Component<Props, State> {
state: State = {
indexPattern: null,
geoField: '',
splitField: '',
sortField: '',
};

_onIndexPatternSelect = (indexPattern: IndexPattern) => {
const pointFields = getGeoPointFields(indexPattern.fields);
this.setState(
{
indexPattern,
geoField: pointFields.length ? pointFields[0].name : '',
sortField: indexPattern.timeFieldName ? indexPattern.timeFieldName : '',
},
this.previewLayer
);
};

_onGeoFieldSelect = (geoField) => {
this.setState(
{
geoField,
},
this.previewLayer
);
};

_onSplitFieldSelect = (newValue) => {
this.setState(
{
splitField: newValue,
},
this.previewLayer
);
};

_onSortFieldSelect = (newValue) => {
this.setState(
{
sortField: newValue,
},
this.previewLayer
);
};

previewLayer = () => {
const { indexPattern, geoField, splitField, sortField } = this.state;

const sourceConfig =
indexPattern && geoField && splitField && sortField
? { indexPatternId: indexPattern.id, geoField, splitField, sortField }
: null;
this.props.onSourceConfigChange(sourceConfig);
};

_renderGeoSelect() {
if (!this.state.indexPattern) {
return null;
}

return (
<EuiFormRow
label={i18n.translate('xpack.maps.source.esGeoLine.geofieldLabel', {
defaultMessage: 'Geospatial field',
})}
>
<SingleFieldSelect
placeholder={i18n.translate('xpack.maps.source.esGeoLine.geofieldPlaceholder', {
defaultMessage: 'Select geo field',
})}
value={this.state.geoField}
onChange={this._onGeoFieldSelect}
fields={getGeoPointFields(this.state.indexPattern.fields)}
/>
</EuiFormRow>
);
}

_renderGeoLineForm() {
if (!this.state.indexPattern || !this.state.geoField) {
return null;
}

return (
<GeoLineForm
indexPattern={this.state.indexPattern}
onSortFieldChange={this._onSortFieldSelect}
onSplitFieldChange={this._onSplitFieldSelect}
sortField={this.state.sortField}
splitField={this.state.splitField}
/>
);
}

render() {
return (
<EuiPanel>
<GeoIndexPatternSelect
value={this.state.indexPattern ? this.state.indexPattern.id : ''}
onChange={this._onIndexPatternSelect}
isGeoPointsOnly={true}
/>
{this._renderGeoSelect()}
{this._renderGeoLineForm()}
</EuiPanel>
);
}
}
Loading