From 14e4da8de3f53366b3fb3f2a813f53492d8e6ea3 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Fri, 15 Feb 2019 11:32:18 -0700 Subject: [PATCH] [6.7] Share global filters & queries with coordinate maps vis. (#30595) (#31273) --- .../public/coordinate_maps_visualization.js | 41 +------- .../loader/embedded_visualize_handler.ts | 11 +++ src/ui/public/visualize/loader/utils/index.ts | 20 ++++ .../loader/utils/query_geohash_bounds.ts | 98 +++++++++++++++++++ test/functional/apps/visualize/_tile_map.js | 23 ++++- .../translations/translations/zh-CN.json | 1 - 6 files changed, 152 insertions(+), 42 deletions(-) create mode 100644 src/ui/public/visualize/loader/utils/index.ts create mode 100644 src/ui/public/visualize/loader/utils/query_geohash_bounds.ts diff --git a/src/legacy/core_plugins/tile_map/public/coordinate_maps_visualization.js b/src/legacy/core_plugins/tile_map/public/coordinate_maps_visualization.js index 91e67e370f2ff..b1efb35bae3d0 100644 --- a/src/legacy/core_plugins/tile_map/public/coordinate_maps_visualization.js +++ b/src/legacy/core_plugins/tile_map/public/coordinate_maps_visualization.js @@ -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'; diff --git a/src/ui/public/visualize/loader/embedded_visualize_handler.ts b/src/ui/public/visualize/loader/embedded_visualize_handler.ts index 5f9da460beb79..57f66b2d0adea 100644 --- a/src/ui/public/visualize/loader/embedded_visualize_handler.ts +++ b/src/ui/public/visualize/loader/embedded_visualize_handler.ts @@ -37,6 +37,7 @@ import { VisualizeDataLoader } from './visualize_data_loader'; import { DataAdapter, RequestAdapter } from '../../inspector/adapters'; import { VisSavedObject, VisualizeLoaderParams, VisualizeUpdateParams } from './types'; +import { queryGeohashBounds } from './utils'; interface EmbeddedVisualizeHandlerParams extends VisualizeLoaderParams { Private: IPrivate; @@ -142,6 +143,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 = new VisualizeDataLoader(vis, Private); this.renderCompleteHelper = new RenderCompleteHelper(element); this.inspectorAdapters = this.getActiveInspectorAdapters(); diff --git a/src/ui/public/visualize/loader/utils/index.ts b/src/ui/public/visualize/loader/utils/index.ts new file mode 100644 index 0000000000000..df07c72686dea --- /dev/null +++ b/src/ui/public/visualize/loader/utils/index.ts @@ -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'; diff --git a/src/ui/public/visualize/loader/utils/query_geohash_bounds.ts b/src/ui/public/visualize/loader/utils/query_geohash_bounds.ts new file mode 100644 index 0000000000000..860a3a2689c9c --- /dev/null +++ b/src/ui/public/visualize/loader/utils/query_geohash_bounds.ts @@ -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; + } + } +} diff --git a/test/functional/apps/visualize/_tile_map.js b/test/functional/apps/visualize/_tile_map.js index a66e6c3941742..ab5401931c94e 100644 --- a/test/functional/apps/visualize/_tile_map.js +++ b/test/functional/apps/visualize/_tile_map.js @@ -24,9 +24,10 @@ 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', 'header', 'settings']); + const PageObjects = getPageObjects(['common', 'discover', 'visualize', 'header', 'settings']); describe('tile map visualize app', function () { @@ -167,6 +168,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 PageObjects.discover.removeAllFilters(); + compareTableData(data, expectedPrecision2DataTable); + }); + it('Newly saved visualization retains map bounds', async () => { const vizName1 = 'Visualization TileMap'; diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 0f8e142114f39..4a425032e3cbe 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2486,7 +2486,6 @@ "tagCloud.visParams.showLabelToggleLabel": "显示标签", "tagCloud.visParams.textScaleLabel": "文本比例", "tileMap.baseMapsVisualization.childShouldImplementMethodErrorMessage": "子函数应实现此方法以响应数据更新", - "tileMap.coordinateMapsVisualization.unableToGetBoundErrorTitle": "无法获取边界", "tileMap.geohashLayer.mapTitle": "{mapType} 地图类型无法识别", "tileMap.tooltipFormatter.latitudeLabel": "纬度", "tileMap.tooltipFormatter.longitudeLabel": "经度",