Skip to content

Commit

Permalink
Merge branch 'master' into fix_existOrFail
Browse files Browse the repository at this point in the history
  • Loading branch information
pheyos committed Oct 23, 2019
2 parents b284bb9 + 6dd1b61 commit 39633a0
Show file tree
Hide file tree
Showing 48 changed files with 716 additions and 255 deletions.
6 changes: 3 additions & 3 deletions docs/maps/geojson-upload.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ for example, in visualizations and Canvas workpads.
[float]
=== Why GeoJSON?
GeoJSON is an open-standard file format for storing geospatial vector data.
Although many vector data formats are available in the GIS community,
Although many vector data formats are available in the GIS community,
GeoJSON is the most commonly used and flexible option.
[float]

Expand All @@ -18,14 +18,14 @@ Follow the instructions below to upload a GeoJSON data file, or try the
<<indexing-geojson-data-tutorial, end-to-end integrated example>>.

. Open *Elastic Maps*, and then click *Add layer*.
. Click *Upload GeoJSON vector file*.
. Click *Uploaded GeoJSON*.
+
[role="screenshot"]
image::maps/images/fu_gs_select_source_file_upload.png[]

. Use the file chooser to select a valid GeoJSON file. The file will load
a preview of the data on the map.
. Use the default *Index type* of {ref}/geo-point.html[geo_point] for point data,
. Use the default *Index type* of {ref}/geo-point.html[geo_point] for point data,
or override it and select {ref}/geo-shape.html[geo_shape].
All other shapes will default to a type of `geo_shape`.
. Leave the default *Index name* and *Index pattern* names (the name of the uploaded
Expand Down
38 changes: 19 additions & 19 deletions docs/maps/indexing-geojson-data-tutorial.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[[indexing-geojson-data-tutorial]]
== Indexing GeoJSON data tutorial

In this tutorial, you'll build a customized map that shows the flight path between
In this tutorial, you'll build a customized map that shows the flight path between
two airports, and the lightning hot spots on that route. You'll learn to:

* Import GeoJSON files into Kibana
Expand All @@ -15,15 +15,15 @@ two airports, and the lightning hot spots on that route. You'll learn to:
This tutorial requires you to download the following GeoJSON sample data files.
These files are good examples of the types
of vector data that you can upload to Kibana and index in
Elasticsearch for display in *Elastic Maps*.
Elasticsearch for display in *Elastic Maps*.

* https://raw.githubusercontent.com/elastic/examples/master/Maps/Getting%20Started%20Examples/geojson_upload_and_styling/logan_international_airport.geojson[Logan International Airport]
* https://raw.githubusercontent.com/elastic/examples/master/Maps/Getting%20Started%20Examples/geojson_upload_and_styling/bangor_international_airport.geojson[Bangor International Airport]
* https://raw.githubusercontent.com/elastic/examples/master/Maps/Getting%20Started%20Examples/geojson_upload_and_styling/lightning_detected.geojson[Lightning detected]
* https://raw.githubusercontent.com/elastic/examples/master/Maps/Getting%20Started%20Examples/geojson_upload_and_styling/original_flight_path.geojson[Original flight path]
* https://raw.githubusercontent.com/elastic/examples/master/Maps/Getting%20Started%20Examples/geojson_upload_and_styling/modified_flight_path.geojson[Modified flight path]

The data represents two real airports, two fictitious flight routes, and
The data represents two real airports, two fictitious flight routes, and
fictitious lightning reports. You don't need to use all of
these files. Feel free to work with as many files as you'd like, or use valid GeoJSON
files of your own.
Expand All @@ -47,20 +47,20 @@ image::maps/images/fu_gs_new_england_map.png[]
For each GeoJSON file you downloaded, complete the following steps:

. Below the map legend, click *Add layer*.
. From the list of layer types, click *Upload GeoJSON vector file*.
. From the list of layer types, click *Uploaded GeoJSON*.
. Using the File Picker, upload the GeoJSON file.
+
Depending on the geometry type of your features, this will
Depending on the geometry type of your features, this will
auto-populate *Index type* with either {ref}/geo-point.html[geo_point] or
{ref}/geo-shape.html[geo_shape] and *Index name* with
{ref}/geo-shape.html[geo_shape] and *Index name* with
`<file name>`.

. Click *Import file* in the lower right.
+
You'll see activity as the GeoJSON Upload utility creates a new index
and index pattern for the data set. When the process is complete, you should
receive messages that the creation of the new index and index pattern
were successful.
were successful.

. Click *Add layer* in the bottom right.

Expand All @@ -69,7 +69,7 @@ were successful.
. Once you've added all of the sample files,
<<maps-save, save your map>>.
+
At this point, you could consider the map complete,
At this point, you could consider the map complete,
but there are a few additions and tweaks that you can make to tell a
better story with your data.
+
Expand All @@ -80,34 +80,34 @@ image::maps/images/fu_gs_flight_paths.png[]
=== Add a heatmap aggregation layer

Looking at the `Lightning detected` layer, it's clear where lightning has
struck. What's less clear, is if there have been more lightning
strikes in some areas than others, in other words, where the lightning
struck. What's less clear, is if there have been more lightning
strikes in some areas than others, in other words, where the lightning
hot spots are. An advantage of having indexed
{ref}/geo-point.html[geo_point] data for the
lightning strikes is that you can perform aggregations on the data.
{ref}/geo-point.html[geo_point] data for the
lightning strikes is that you can perform aggregations on the data.

. Below the map legend, click *Add layer*.
. From the list of layer types, click *Grid aggregation*.
+
Because you indexed `lightning_detected.geojson` using the index name and
Because you indexed `lightning_detected.geojson` using the index name and
pattern `lightning_detected`, that data is available as a {ref}/geo-point.html[geo_point]
aggregation.
aggregation.

. Select `lightning_detected`.
. Click *Show as* and select `heat map`.
. Click *Add layer* to add the heat map layer
"Lightning intensity".
+
The remaining default settings are good, but there are a couple of
settings that you might want to change.
settings that you might want to change.

. Under *Source settings* > *Grid resolution*, select from the different heat map resolutions.
. Under *Source settings* > *Grid resolution*, select from the different heat map resolutions.
+
The default "Coarse" looks
good, but feel free to select a different resolution.

. Play around with the *Layer Style* >
*Color range* setting.
*Color range* setting.
+
Again the default looks good, but feel free to choose a
different color range.
Expand All @@ -125,14 +125,14 @@ image::maps/images/fu_gs_lightning_intensity.png[]
=== Organize the layers

Consider ways you might improve the appearance of the final map.
Small changes in how and when layers are shown can help tell a
Small changes in how and when layers are shown can help tell a
better story with your data. Here are a few final tweaks
you might make:

* Update layer names
* Adjust styles for each layer
* Adjust the layer order
* Decide which layers to show at different zoom levels
* Decide which layers to show at different zoom levels

When you've finished, again be sure to <<maps-save, save your work >>.

Expand Down
2 changes: 1 addition & 1 deletion docs/maps/maps-getting-started.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ and lighter shades symbolize countries with less traffic.
==== Add a vector layer from the Elastic Maps Service source

. In the map legend, click *Add layer*.
. Click the *Vector shapes* data source.
. Click the *EMS Boundaries* data source.
. From the *Layer* dropdown menu, select *World Countries*.
. Click the *Add layer* button.
. Set *Layer name* to `Total Requests by Country`.
Expand Down
44 changes: 44 additions & 0 deletions src/core/server/elasticsearch/elasticsearch_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,55 @@ Object {
undefined,
],
"ssl": Object {
"certificateAuthorities": undefined,
"verificationMode": "none",
},
}
`);
});

it('does not merge elasticsearch hosts if custom config overrides', async () => {
configService.atPath.mockReturnValueOnce(
new BehaviorSubject({
hosts: ['http://1.2.3.4', 'http://9.8.7.6'],
healthCheck: {
delay: 2000,
},
ssl: {
verificationMode: 'none',
},
} as any)
);
elasticsearchService = new ElasticsearchService(coreContext);
const setupContract = await elasticsearchService.setup(deps);
// reset all mocks called during setup phase
MockClusterClient.mockClear();

const customConfig = {
hosts: ['http://8.8.8.8'],
logQueries: true,
ssl: { certificate: 'certificate-value' },
};
setupContract.createClient('some-custom-type', customConfig);

const config = MockClusterClient.mock.calls[0][0];
expect(config).toMatchInlineSnapshot(`
Object {
"healthCheckDelay": 2000,
"hosts": Array [
"http://8.8.8.8",
],
"logQueries": true,
"requestHeadersWhitelist": Array [
undefined,
],
"ssl": Object {
"certificate": "certificate-value",
"verificationMode": "none",
},
}
`);
});
});
});

Expand Down
3 changes: 2 additions & 1 deletion src/core/server/elasticsearch/elasticsearch_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@

import { ConnectableObservable, Observable, Subscription } from 'rxjs';
import { filter, first, map, publishReplay, switchMap } from 'rxjs/operators';
import { merge } from 'lodash';

import { CoreService } from '../../types';
import { merge } from '../../utils';
import { CoreContext } from '../core_context';
import { Logger } from '../logging';
import { ClusterClient } from './cluster_client';
Expand Down
1 change: 1 addition & 0 deletions src/core/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ export * from './context';
export * from './deep_freeze';
export * from './get';
export * from './map_to_object';
export * from './merge';
export * from './pick';
export * from './url';
64 changes: 64 additions & 0 deletions src/core/utils/merge.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { merge } from './merge';

describe('merge', () => {
test('empty objects', () => expect(merge({}, {})).toEqual({}));

test('basic', () => {
expect(merge({}, { a: 1 })).toEqual({ a: 1 });
expect(merge({ a: 0 }, {})).toEqual({ a: 0 });
expect(merge({ a: 0 }, { a: 1 })).toEqual({ a: 1 });
});

test('undefined', () => {
expect(merge({ a: undefined }, { a: 1 })).toEqual({ a: 1 });
expect(merge({ a: 0 }, { a: undefined })).toEqual({ a: 0 });
expect(merge({ a: undefined }, { a: undefined })).toEqual({});
expect(merge({ a: void 0 }, { a: void 0 })).toEqual({});
});

test('null', () => {
expect(merge({ a: null }, { a: 1 })).toEqual({ a: 1 });
expect(merge({ a: 0 }, { a: null })).toEqual({ a: null });
expect(merge({ a: null }, { a: null })).toEqual({ a: null });
});

test('arrays', () => {
expect(merge({ b: [0] }, { b: [2] })).toEqual({ b: [2] });
expect(merge({ b: [0, 1] }, { b: [2] })).toEqual({ b: [2] });
expect(merge({ b: [0] }, { b: [2, 3] })).toEqual({ b: [2, 3] });
expect(merge({ b: [] }, { b: [2] })).toEqual({ b: [2] });
expect(merge({ b: [0] }, { b: [] })).toEqual({ b: [] });
});

test('nested objects', () => {
expect(merge({ top: { a: 0, b: 0 } }, { top: { a: 1, c: 1 } })).toEqual({
top: { a: 1, b: 0, c: 1 },
});
expect(merge({ top: { a: 0, b: 0 } }, { top: [0, 1] })).toEqual({ top: [0, 1] });
});

test('multiple objects', () => {
expect(merge({}, { a: 1 }, { a: 2 })).toEqual({ a: 2 });
expect(merge({ a: 0 }, {}, {})).toEqual({ a: 0 });
expect(merge({ a: 0 }, { a: 1 }, {})).toEqual({ a: 1 });
});
});
85 changes: 85 additions & 0 deletions src/core/utils/merge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/**
* Deeply merges two objects, omitting undefined values, and not deeply merging Arrays.
*
* @remarks
* Should behave identically to lodash.merge, however it will not merge Array values like lodash does.
* Any properties with `undefined` values on both objects will be ommitted from the returned object.
*/
export function merge<TBase extends Record<string, any>, TSource1 extends Record<string, any>>(
baseObj: TBase,
source1: TSource1
): TBase & TSource1;
export function merge<
TBase extends Record<string, any>,
TSource1 extends Record<string, any>,
TSource2 extends Record<string, any>
>(baseObj: TBase, overrideObj: TSource1, overrideObj2: TSource2): TBase & TSource1 & TSource2;
export function merge<
TBase extends Record<string, any>,
TSource1 extends Record<string, any>,
TSource2 extends Record<string, any>,
TSource3 extends Record<string, any>
>(
baseObj: TBase,
overrideObj: TSource1,
overrideObj2: TSource2
): TBase & TSource1 & TSource2 & TSource3;
export function merge<TReturn extends Record<string, any>>(
baseObj: Record<string, any>,
...sources: Array<Record<string, any>>
): TReturn {
const firstSource = sources[0];
if (firstSource === undefined) {
return baseObj as TReturn;
}

return sources
.slice(1)
.reduce(
(merged, nextSource) => mergeObjects(merged, nextSource),
mergeObjects(baseObj, firstSource)
) as TReturn;
}

const isMergable = (obj: any) => typeof obj === 'object' && obj !== null && !Array.isArray(obj);

const mergeObjects = <T extends Record<string, any>, U extends Record<string, any>>(
baseObj: T,
overrideObj: U
): T & U =>
[...new Set([...Object.keys(baseObj), ...Object.keys(overrideObj)])].reduce(
(merged, key) => {
const baseVal = baseObj[key];
const overrideVal = overrideObj[key];

if (isMergable(baseVal) && isMergable(overrideVal)) {
merged[key] = mergeObjects(baseVal, overrideVal);
} else if (overrideVal !== undefined) {
merged[key] = overrideVal;
} else if (baseVal !== undefined) {
merged[key] = baseVal;
}

return merged;
},
{} as any
);
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ export const visualization = () => ({
// special case in visualize, we need to render first (without executing the expression), for maps to work
if (visConfig) {
$rootScope.$apply(() => {
handlers.vis.setCurrentState({ type: visType, params: visConfig });
handlers.vis.setCurrentState({
type: visType,
params: visConfig,
title: handlers.vis.title,
});
});
}
} else {
Expand Down
Loading

0 comments on commit 39633a0

Please sign in to comment.