Share global filters & queries with coordinate maps vis. (#30595)

This commit is contained in:
Luke Elmers 2019-02-15 08:43:05 -07:00 committed by GitHub
parent 3cc064f6d0
commit 09a6c9dcd0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 151 additions and 41 deletions

View file

@ -18,11 +18,9 @@
*/
import _ from 'lodash';
import { i18n } from '@kbn/i18n';
import { GeohashLayer } from './geohash_layer';
import { BaseMapsVisualizationProvider } from './base_maps_visualization';
import { TileMapTooltipFormatterProvider } from './editors/_tooltip_formatter';
import { toastNotifications } from 'ui/notify';
export function CoordinateMapsVisualizationProvider(Notifier, Private) {
const BaseMapsVisualization = Private(BaseMapsVisualizationProvider);
@ -37,7 +35,6 @@ export function CoordinateMapsVisualizationProvider(Notifier, Private) {
this._notify = new Notifier({ location: 'Coordinate Map' });
}
async _makeKibanaMap() {
await super._makeKibanaMap();
@ -161,7 +158,6 @@ export function CoordinateMapsVisualizationProvider(Notifier, Private) {
}
_getGeohashOptions() {
const newParams = this._getMapsParams();
const metricAgg = this._getMetricAgg();
const boundTooltipFormatter = tooltipFormatter.bind(null, this.vis.getAggConfig(), metricAgg);
@ -172,7 +168,7 @@ export function CoordinateMapsVisualizationProvider(Notifier, Private) {
tooltipFormatter: this._geoJsonFeatureCollectionAndMeta ? boundTooltipFormatter : null,
mapType: newParams.mapType,
isFilteredByCollar: this._isFilteredByCollar(),
fetchBounds: this.getGeohashBounds.bind(this),
fetchBounds: () => this.vis.API.getGeohashBounds(), // TODO: Remove this (elastic/kibana#30593)
colorRamp: newParams.colorSchema,
heatmap: {
heatClusterSize: newParams.heatClusterSize
@ -196,47 +192,12 @@ export function CoordinateMapsVisualizationProvider(Notifier, Private) {
this.vis.updateState();
}
async getGeohashBounds() {
const agg = this._getGeoHashAgg();
if (agg) {
const searchSource = this.vis.searchSource.createChild();
searchSource.setField('size', 0);
searchSource.setField('aggs', () => {
const geoBoundsAgg = this.vis.getAggConfig().createAggConfig({
type: 'geo_bounds',
enabled: true,
params: {
field: agg.getField()
},
schema: 'metric',
}, { addToAggConfigs: false });
return {
'1': geoBoundsAgg.toDsl()
};
});
let esResp;
try {
esResp = await searchSource.fetch();
} catch(error) {
toastNotifications.addDanger({
title: i18n.translate('tileMap.coordinateMapsVisualization.unableToGetBoundErrorTitle', {
defaultMessage: 'Unable to get bounds',
}),
text: `${error.message}`,
});
return;
}
return _.get(esResp, 'aggregations.1.bounds');
}
}
_getGeoHashAgg() {
return this.vis.getAggConfig().find((agg) => {
return _.get(agg, 'type.dslName') === 'geohash_grid';
});
}
_getMetricAgg() {
return this.vis.getAggConfig().find((agg) => {
return agg.type.type === 'metrics';

View file

@ -44,6 +44,7 @@ import {
VisualizeLoaderParams,
VisualizeUpdateParams,
} from './types';
import { queryGeohashBounds } from './utils';
interface EmbeddedVisualizeHandlerParams extends VisualizeLoaderParams {
Private: IPrivate;
@ -157,6 +158,16 @@ export class EmbeddedVisualizeHandler {
timefilter.on('autoRefreshFetch', this.reload);
}
// This is a hack to give maps visualizations access to data in the
// globalState, since they can no longer access it via searchSource.
// TODO: Remove this as a part of elastic/kibana#30593
this.vis.API.getGeohashBounds = () => {
return queryGeohashBounds(this.vis, {
filters: this.dataLoaderParams.filters,
query: this.dataLoaderParams.query,
});
};
this.dataLoader = EmbeddedVisualizeHandler.__ENABLE_PIPELINE_DATA_LOADER__
? new PipelineDataLoader(vis)
: new VisualizeDataLoader(vis, Private);

View file

@ -0,0 +1,20 @@
/*
* 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.
*/
export { queryGeohashBounds } from './query_geohash_bounds';

View file

@ -0,0 +1,98 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { get } from 'lodash';
import { toastNotifications } from 'ui/notify';
import { AggConfig } from 'ui/vis';
import { Vis } from '../../../vis';
import { Filters, Query } from '../types';
interface QueryGeohashBoundsParams {
filters?: Filters;
query?: Query;
}
/**
* Coordinate map visualization needs to be able to query for the latest geohash
* bounds when a user clicks the "fit to data" map icon, which requires knowing
* about global filters & queries. This logic has been extracted here so we can
* keep `searchSource` out of the vis, but ultimately we need to design a
* long-term solution for situations like this.
*
* TODO: Remove this as a part of elastic/kibana#30593
*/
export async function queryGeohashBounds(vis: Vis, params: QueryGeohashBoundsParams) {
const agg = vis.getAggConfig().find((a: AggConfig) => {
return get(a, 'type.dslName') === 'geohash_grid';
});
if (agg) {
const searchSource = vis.searchSource.createChild();
searchSource.setField('size', 0);
searchSource.setField('aggs', () => {
const geoBoundsAgg = vis.getAggConfig().createAggConfig(
{
type: 'geo_bounds',
enabled: true,
params: {
field: agg.getField(),
},
schema: 'metric',
},
{
addToAggConfigs: false,
}
);
return {
'1': geoBoundsAgg.toDsl(),
};
});
const { filters, query } = params;
if (filters) {
searchSource.setField('filter', () => {
const activeFilters = [...filters];
const indexPattern = agg.getIndexPattern();
const useTimeFilter = !!indexPattern.timeFieldName;
if (useTimeFilter) {
activeFilters.push(vis.API.timeFilter.createFilter(indexPattern));
}
return activeFilters;
});
}
if (query) {
searchSource.setField('query', query);
}
try {
const esResp = await searchSource.fetch();
return get(esResp, 'aggregations.1.bounds');
} catch (error) {
toastNotifications.addDanger({
title: i18n.translate('common.ui.visualize.queryGeohashBounds.unableToGetBoundErrorTitle', {
defaultMessage: 'Unable to get bounds',
}),
text: `${error.message}`,
});
return;
}
}
}

View file

@ -24,6 +24,7 @@ export default function ({ getService, getPageObjects }) {
const retry = getService('retry');
const inspector = getService('inspector');
const find = getService('find');
const filterBar = getService('filterBar');
const testSubjects = getService('testSubjects');
const browser = getService('browser');
const PageObjects = getPageObjects(['common', 'visualize', 'timePicker', 'settings']);
@ -165,6 +166,26 @@ export default function ({ getService, getPageObjects }) {
compareTableData(data, expectedPrecision2DataTable);
});
it('Fit data bounds works with pinned filter data', async () => {
const expectedPrecision2DataTable = [
['-', 'f05', '1', { lat: 45, lon: -85 }],
['-', 'dpr', '1', { lat: 40, lon: -79 }],
['-', '9qh', '1', { lat: 33, lon: -118 }],
];
await filterBar.addFilter('bytes', 'is between', '19980', '19990');
await filterBar.toggleFilterPinned('bytes');
await PageObjects.visualize.zoomAllTheWayOut();
await PageObjects.visualize.clickMapFitDataBounds();
await inspector.open();
const data = await inspector.getTableData();
await inspector.close();
await filterBar.removeAllFilters();
compareTableData(data, expectedPrecision2DataTable);
});
it('Newly saved visualization retains map bounds', async () => {
const vizName1 = 'Visualization TileMap';

View file

@ -2412,7 +2412,6 @@
"tagCloud.visParams.showLabelToggleLabel": "显示标签",
"tagCloud.visParams.textScaleLabel": "文本比例",
"tileMap.baseMapsVisualization.childShouldImplementMethodErrorMessage": "子函数应实现此方法以响应数据更新",
"tileMap.coordinateMapsVisualization.unableToGetBoundErrorTitle": "无法获取边界",
"tileMap.geohashLayer.mapTitle": "{mapType} 地图类型无法识别",
"tileMap.tooltipFormatter.latitudeLabel": "纬度",
"tileMap.tooltipFormatter.longitudeLabel": "经度",