From 56b1c3ae96e59f4b1c1562d10fdbc9273bf71ed3 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 18 Mar 2020 16:00:30 -0600 Subject: [PATCH 01/10] [Maps] show scaling panel in ES documents create wizard --- .../maps/public/actions/map_actions.d.ts | 8 + .../layer_panel/view.d.ts | 14 ++ .../es_search_source/scaling_panel.tsx | 232 ++++++++++++++++++ .../es_search_source/update_source_editor.js | 182 ++------------ 4 files changed, 270 insertions(+), 166 deletions(-) create mode 100644 x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.d.ts create mode 100644 x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_panel.tsx diff --git a/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts b/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts index 418f2880c1077..f1bd6b8f85b57 100644 --- a/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts +++ b/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts @@ -5,6 +5,7 @@ */ /* eslint-disable @typescript-eslint/consistent-type-definitions */ +import { LAYER_TYPE } from '../../common/constants'; import { DataMeta, MapFilters } from '../../common/data_request_descriptor_types'; export type SyncContext = { @@ -16,3 +17,10 @@ export type SyncContext = { registerCancelCallback(requestToken: symbol, callback: () => void): void; dataFilters: MapFilters; }; + +export function updateSourceProp( + layerId: string, + propName: string, + value: unknown, + newLayerType?: LAYER_TYPE +); diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.d.ts b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.d.ts new file mode 100644 index 0000000000000..6d1d076c723ad --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.d.ts @@ -0,0 +1,14 @@ +/* + * 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 { LAYER_TYPE } from '../../../common/constants'; + +export type OnSourceChangeArgs = { + propName: string; + value: unknown; + newLayerType?: LAYER_TYPE; +}; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_panel.tsx b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_panel.tsx new file mode 100644 index 0000000000000..d625fc3cd4ee6 --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_panel.tsx @@ -0,0 +1,232 @@ +/* + * 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, { Fragment, Component } from 'react'; +import { + EuiFormRow, + EuiSwitch, + EuiSwitchEvent, + EuiTitle, + EuiPanel, + EuiSpacer, + EuiHorizontalRule, + EuiRadioGroup, +} from '@elastic/eui'; +// @ ts-ignore +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { SingleFieldSelect } from '../../../components/single_field_select'; + +// @ts-ignore +import { indexPatternService } from '../../../kibana_services'; +// @ts-ignore +import { getTermsFields, getSourceFields } from '../../../index_pattern_util'; +// @ts-ignore +import { ValidatedRange } from '../../../components/validated_range'; +import { + DEFAULT_MAX_INNER_RESULT_WINDOW, + DEFAULT_MAX_RESULT_WINDOW, + SORT_ORDER, + SCALING_TYPES, + LAYER_TYPE, +} from '../../../../common/constants'; +// @ts-ignore +import { loadIndexSettings } from './load_index_settings'; +import { IFieldType } from '../../../../../../../../src/plugins/data/public'; +import { OnSourceChangeArgs } from '../../../connected_components/layer_panel/view'; + +interface Props { + filterByMapBounds: boolean; + indexPatternId: string; + onChange: (OnSourceChangeArgs) => void; + scalingType: SCALING_TYPES; + supportsClustering: boolean; + termFields: IFieldType[]; + topHitsSplitField?: string; + topHitsSize: number; +} + +interface State { + maxInnerResultWindow: number; + maxResultWindow: number; +} + +export class ScalingPanel extends Component { + private _isMounted: boolean; + state = { + maxInnerResultWindow: DEFAULT_MAX_INNER_RESULT_WINDOW, + maxResultWindow: DEFAULT_MAX_RESULT_WINDOW, + }; + + componentDidMount() { + this._isMounted = true; + this.loadIndexSettings(); + } + + componentWillUnmount() { + this._isMounted = false; + } + + async loadIndexSettings() { + try { + const indexPattern = await indexPatternService.get(this.props.indexPatternId); + const { maxInnerResultWindow, maxResultWindow } = await loadIndexSettings(indexPattern.title); + if (this._isMounted) { + this.setState({ maxInnerResultWindow, maxResultWindow }); + } + } catch (err) { + return; + } + } + + _onScalingTypeChange = (optionId: SCALING_TYPES): void => { + const layerType = + optionId === SCALING_TYPES.CLUSTERS ? LAYER_TYPE.BLENDED_VECTOR : LAYER_TYPE.VECTOR; + this.props.onChange({ propName: 'scalingType', value: optionId, newLayerType: layerType }); + }; + + _onFilterByMapBoundsChange = (event: EuiSwitchEvent) => { + this.props.onChange({ propName: 'filterByMapBounds', value: event.target.checked }); + }; + + _onTopHitsSplitFieldChange = (topHitsSplitField: string) => { + this.props.onChange({ propName: 'topHitsSplitField', value: topHitsSplitField }); + }; + + _onTopHitsSizeChange = (size: number) => { + this.props.onChange({ propName: 'topHitsSize', value: size }); + }; + + _renderTopHitsForm() { + let sizeSlider; + if (this.props.topHitsSplitField) { + sizeSlider = ( + + + + ); + } + + return ( + + + + + + {sizeSlider} + + ); + } + + render() { + const scalingOptions = [ + { + id: SCALING_TYPES.LIMIT, + label: i18n.translate('xpack.maps.source.esSearch.limitScalingLabel', { + defaultMessage: 'Limit results to {maxResultWindow}.', + values: { maxResultWindow: this.state.maxResultWindow }, + }), + }, + { + id: SCALING_TYPES.TOP_HITS, + label: i18n.translate('xpack.maps.source.esSearch.useTopHitsLabel', { + defaultMessage: 'Show top hits per entity.', + }), + }, + ]; + if (this.props.supportsClustering) { + scalingOptions.push({ + id: SCALING_TYPES.CLUSTERS, + label: i18n.translate('xpack.maps.source.esSearch.clusterScalingLabel', { + defaultMessage: 'Show clusters when results exceed {maxResultWindow}.', + values: { maxResultWindow: this.state.maxResultWindow }, + }), + }); + } + + let filterByBoundsSwitch; + if (this.props.scalingType !== SCALING_TYPES.CLUSTERS) { + filterByBoundsSwitch = ( + + + + ); + } + + let scalingForm = null; + if (this.props.scalingType === SCALING_TYPES.TOP_HITS) { + scalingForm = ( + + + {this._renderTopHitsForm()} + + ); + } + + return ( + + +
+ +
+
+ + + + + + + + {filterByBoundsSwitch} + + {scalingForm} +
+ ); + } +} diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js index b85cca113cf98..daa5d900afeb4 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js @@ -6,34 +6,23 @@ import React, { Fragment, Component } from 'react'; import PropTypes from 'prop-types'; -import { - EuiFormRow, - EuiSwitch, - EuiSelect, - EuiTitle, - EuiPanel, - EuiSpacer, - EuiHorizontalRule, - EuiRadioGroup, -} from '@elastic/eui'; +import { EuiFormRow, EuiSelect, EuiTitle, EuiPanel, EuiSpacer } from '@elastic/eui'; import { SingleFieldSelect } from '../../../components/single_field_select'; import { TooltipSelector } from '../../../components/tooltip_selector'; import { indexPatternService } from '../../../kibana_services'; import { i18n } from '@kbn/i18n'; import { getTermsFields, getSourceFields } from '../../../index_pattern_util'; -import { ValidatedRange } from '../../../components/validated_range'; import { DEFAULT_MAX_INNER_RESULT_WINDOW, DEFAULT_MAX_RESULT_WINDOW, SORT_ORDER, - SCALING_TYPES, - LAYER_TYPE, } from '../../../../common/constants'; import { ESDocField } from '../../fields/es_doc_field'; import { FormattedMessage } from '@kbn/i18n/react'; import { loadIndexSettings } from './load_index_settings'; import { indexPatterns } from '../../../../../../../../src/plugins/data/public'; +import { ScalingPanel } from './scaling_panel'; export class UpdateSourceEditor extends Component { static propTypes = { @@ -133,85 +122,14 @@ export class UpdateSourceEditor extends Component { this.props.onChange({ propName: 'tooltipProperties', value: propertyNames }); }; - _onScalingTypeChange = optionId => { - const layerType = - optionId === SCALING_TYPES.CLUSTERS ? LAYER_TYPE.BLENDED_VECTOR : LAYER_TYPE.VECTOR; - this.props.onChange({ propName: 'scalingType', value: optionId, newLayerType: layerType }); - }; - - _onFilterByMapBoundsChange = event => { - this.props.onChange({ propName: 'filterByMapBounds', value: event.target.checked }); - }; - - onTopHitsSplitFieldChange = topHitsSplitField => { - this.props.onChange({ propName: 'topHitsSplitField', value: topHitsSplitField }); - }; - - onSortFieldChange = sortField => { + _onSortFieldChange = sortField => { this.props.onChange({ propName: 'sortField', value: sortField }); }; - onSortOrderChange = e => { + _onSortOrderChange = e => { this.props.onChange({ propName: 'sortOrder', value: e.target.value }); }; - onTopHitsSizeChange = size => { - this.props.onChange({ propName: 'topHitsSize', value: size }); - }; - - _renderTopHitsForm() { - let sizeSlider; - if (this.props.topHitsSplitField) { - sizeSlider = ( - - - - ); - } - - return ( - - - - - - {sizeSlider} - - ); - } - _renderTooltipsPanel() { return ( @@ -257,7 +175,7 @@ export class UpdateSourceEditor extends Component { defaultMessage: 'Select sort field', })} value={this.props.sortField} - onChange={this.onSortFieldChange} + onChange={this._onSortFieldChange} fields={this.state.sortFields} compressed /> @@ -286,7 +204,7 @@ export class UpdateSourceEditor extends Component { }, ]} value={this.props.sortOrder} - onChange={this.onSortOrderChange} + onChange={this._onSortOrderChange} compressed /> @@ -294,83 +212,6 @@ export class UpdateSourceEditor extends Component { ); } - _renderScalingPanel() { - const scalingOptions = [ - { - id: SCALING_TYPES.LIMIT, - label: i18n.translate('xpack.maps.source.esSearch.limitScalingLabel', { - defaultMessage: 'Limit results to {maxResultWindow}.', - values: { maxResultWindow: this.state.maxResultWindow }, - }), - }, - { - id: SCALING_TYPES.TOP_HITS, - label: i18n.translate('xpack.maps.source.esSearch.useTopHitsLabel', { - defaultMessage: 'Show top hits per entity.', - }), - }, - ]; - if (this.state.supportsClustering) { - scalingOptions.push({ - id: SCALING_TYPES.CLUSTERS, - label: i18n.translate('xpack.maps.source.esSearch.clusterScalingLabel', { - defaultMessage: 'Show clusters when results exceed {maxResultWindow}.', - values: { maxResultWindow: this.state.maxResultWindow }, - }), - }); - } - - let filterByBoundsSwitch; - if (this.props.scalingType !== SCALING_TYPES.CLUSTERS) { - filterByBoundsSwitch = ( - - - - ); - } - - let scalingForm = null; - if (this.props.scalingType === SCALING_TYPES.TOP_HITS) { - scalingForm = ( - - - {this._renderTopHitsForm()} - - ); - } - - return ( - - -
- -
-
- - - - - - - - {filterByBoundsSwitch} - - {scalingForm} -
- ); - } - render() { return ( @@ -380,7 +221,16 @@ export class UpdateSourceEditor extends Component { {this._renderSortPanel()} - {this._renderScalingPanel()} + ); From 1a685d75de79f56da191525dd737a001544a0a0b Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 18 Mar 2020 16:02:08 -0600 Subject: [PATCH 02/10] minor fix --- .../public/layers/sources/es_search_source/scaling_panel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_panel.tsx b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_panel.tsx index d625fc3cd4ee6..4bcbee528ea5f 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_panel.tsx +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_panel.tsx @@ -15,9 +15,9 @@ import { EuiHorizontalRule, EuiRadioGroup, } from '@elastic/eui'; -// @ ts-ignore import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +// @ts-ignore import { SingleFieldSelect } from '../../../components/single_field_select'; // @ts-ignore From 6c0c1142bd35fd64ed8d4d60925a6f9ffaa3581e Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 19 Mar 2020 06:32:12 -0600 Subject: [PATCH 03/10] remove unused async state --- .../es_search_source/update_source_editor.js | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js index daa5d900afeb4..d3a8e572428a7 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js @@ -13,14 +13,9 @@ import { TooltipSelector } from '../../../components/tooltip_selector'; import { indexPatternService } from '../../../kibana_services'; import { i18n } from '@kbn/i18n'; import { getTermsFields, getSourceFields } from '../../../index_pattern_util'; -import { - DEFAULT_MAX_INNER_RESULT_WINDOW, - DEFAULT_MAX_RESULT_WINDOW, - SORT_ORDER, -} from '../../../../common/constants'; +import { SORT_ORDER } from '../../../../common/constants'; import { ESDocField } from '../../fields/es_doc_field'; import { FormattedMessage } from '@kbn/i18n/react'; -import { loadIndexSettings } from './load_index_settings'; import { indexPatterns } from '../../../../../../../../src/plugins/data/public'; import { ScalingPanel } from './scaling_panel'; @@ -41,33 +36,18 @@ export class UpdateSourceEditor extends Component { sourceFields: null, termFields: null, sortFields: null, - maxInnerResultWindow: DEFAULT_MAX_INNER_RESULT_WINDOW, - maxResultWindow: DEFAULT_MAX_RESULT_WINDOW, supportsClustering: false, }; componentDidMount() { this._isMounted = true; this.loadFields(); - this.loadIndexSettings(); } componentWillUnmount() { this._isMounted = false; } - async loadIndexSettings() { - try { - const indexPattern = await indexPatternService.get(this.props.indexPatternId); - const { maxInnerResultWindow, maxResultWindow } = await loadIndexSettings(indexPattern.title); - if (this._isMounted) { - this.setState({ maxInnerResultWindow, maxResultWindow }); - } - } catch (err) { - return; - } - } - async loadFields() { let indexPattern; try { From 7145df72316839ef298a601e5f579800083d76a8 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 19 Mar 2020 12:16:42 -0600 Subject: [PATCH 04/10] update create editor to use ScalingForm --- .../es_search_source/create_source_editor.js | 134 ++++++++++++++---- .../{scaling_panel.tsx => scaling_form.tsx} | 7 +- .../es_search_source/update_source_editor.js | 28 ++-- 3 files changed, 127 insertions(+), 42 deletions(-) rename x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/{scaling_panel.tsx => scaling_form.tsx} (98%) diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js index b7b63ce8082bc..8b2887e47269b 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js @@ -19,9 +19,12 @@ import { ES_GEO_FIELD_TYPE, GIS_API_PATH, DEFAULT_MAX_RESULT_WINDOW, + SCALING_TYPES, } from '../../../../common/constants'; import { DEFAULT_FILTER_BY_MAP_BOUNDS } from './constants'; import { indexPatterns } from '../../../../../../../../src/plugins/data/public'; +import { ScalingForm } from './scaling_form'; +import { getTermsFields } from '../../../index_pattern_util'; import { npStart } from 'ui/new_platform'; const { IndexPatternSelect } = npStart.plugins.data.ui; @@ -34,11 +37,28 @@ function getGeoFields(fields) { ); }); } + +function isGeoFieldAggregatable(indexPattern, geoFieldName) { + if (!indexPattern) { + return false; + } + + const geoField = indexPattern.fields.getByName(geoFieldName); + return geoField && geoField.aggregatable; +} + const RESET_INDEX_PATTERN_STATE = { indexPattern: undefined, - geoField: undefined, - filterByMapBounds: DEFAULT_FILTER_BY_MAP_BOUNDS, + geoFieldName: undefined, showFilterByBoundsSwitch: false, + showScalingPanel: false, + geoFields: undefined, + + // ES search source descriptor state + filterByMapBounds: DEFAULT_FILTER_BY_MAP_BOUNDS, + scalingType: SCALING_TYPES.CLUSTERS, // turn on clusting by default + topHitsSplitField: undefined, + topHitsSize: 1, }; export class CreateSourceEditor extends Component { @@ -58,29 +78,28 @@ export class CreateSourceEditor extends Component { componentDidMount() { this._isMounted = true; - this.loadIndexPattern(this.state.indexPatternId); } - onIndexPatternSelect = indexPatternId => { + _onIndexPatternSelect = indexPatternId => { this.setState( { indexPatternId, }, - this.loadIndexPattern(indexPatternId) + this._loadIndexPattern(indexPatternId) ); }; - loadIndexPattern = indexPatternId => { + _loadIndexPattern = indexPatternId => { this.setState( { isLoadingIndexPattern: true, ...RESET_INDEX_PATTERN_STATE, }, - this.debouncedLoad.bind(null, indexPatternId) + this._debouncedLoad.bind(null, indexPatternId) ); }; - loadIndexDocCount = async indexPatternTitle => { + _loadIndexDocCount = async indexPatternTitle => { const { count } = await kfetch({ pathname: `../${GIS_API_PATH}/indexCount`, query: { @@ -90,7 +109,7 @@ export class CreateSourceEditor extends Component { return count; }; - debouncedLoad = _.debounce(async indexPatternId => { + _debouncedLoad = _.debounce(async indexPatternId => { if (!indexPatternId || indexPatternId.length === 0) { return; } @@ -105,7 +124,7 @@ export class CreateSourceEditor extends Component { let indexHasSmallDocCount = false; try { - const indexDocCount = await this.loadIndexDocCount(indexPattern.title); + const indexDocCount = await this._loadIndexDocCount(indexPattern.title); indexHasSmallDocCount = indexDocCount <= DEFAULT_MAX_RESULT_WINDOW; } catch (error) { // retrieving index count is a nice to have and is not essential @@ -122,43 +141,77 @@ export class CreateSourceEditor extends Component { return; } + const geoFields = getGeoFields(indexPattern.fields); this.setState({ isLoadingIndexPattern: false, indexPattern: indexPattern, filterByMapBounds: !indexHasSmallDocCount, // Turn off filterByMapBounds when index contains a limited number of documents showFilterByBoundsSwitch: indexHasSmallDocCount, + showScalingPanel: !indexHasSmallDocCount, + geoFields, }); - //make default selection - const geoFields = getGeoFields(indexPattern.fields); + // make default selection if (geoFields[0]) { - this.onGeoFieldSelect(geoFields[0].name); + this._onGeoFieldSelect(geoFields[0].name); } }, 300); - onGeoFieldSelect = geoField => { + _onGeoFieldSelect = geoFieldName => { + // Respect previous scaling type selection unless newly selected geo field does not support clustering. + const scalingType = + this.state.scalingType === SCALING_TYPES.CLUSTERS && + !isGeoFieldAggregatable(this.state.indexPattern, geoFieldName) + ? SCALING_TYPES.LIMIT + : this.state.scalingType; this.setState( { - geoField, + geoFieldName, + scalingType, }, - this.previewLayer + this._previewLayer ); }; - onFilterByMapBoundsChange = event => { + _onFilterByMapBoundsChange = event => { this.setState( { filterByMapBounds: event.target.checked, }, - this.previewLayer + this._previewLayer ); }; - previewLayer = () => { - const { indexPatternId, geoField, filterByMapBounds } = this.state; + _onScalingPropChange = ({ propName, value }) => { + this.setState( + { + [propName]: value, + }, + this._previewLayer + ); + }; + + _previewLayer = () => { + const { + indexPatternId, + geoFieldName, + filterByMapBounds, + scalingType, + topHitsSplitField, + topHitsSize, + } = this.state; const sourceConfig = - indexPatternId && geoField ? { indexPatternId, geoField, filterByMapBounds } : null; + indexPatternId && geoFieldName + ? { + indexPatternId, + geoField: geoFieldName, + filterByMapBounds, + scalingType, + topHitsSplitField, + topHitsSize, + } + : null; this.props.onSourceConfigChange(sourceConfig); }; @@ -181,11 +234,9 @@ export class CreateSourceEditor extends Component { placeholder={i18n.translate('xpack.maps.source.esSearch.selectLabel', { defaultMessage: 'Select geo field', })} - value={this.state.geoField} - onChange={this.onGeoFieldSelect} - fields={ - this.state.indexPattern ? getGeoFields(this.state.indexPattern.fields) : undefined - } + value={this.state.geoFieldName} + onChange={this._onGeoFieldSelect} + fields={this.state.geoFields} /> ); @@ -228,13 +279,38 @@ export class CreateSourceEditor extends Component { defaultMessage: `Dynamically filter for data in the visible map area`, })} checked={this.state.filterByMapBounds} - onChange={this.onFilterByMapBoundsChange} + onChange={this._onFilterByMapBoundsChange} /> ); } + _renderScalingPanel() { + if (!this.state.indexPattern || !this.state.geoFieldName || !this.state.showScalingPanel) { + return null; + } + + return ( + + + + + ); + } + _renderNoIndexPatternWarning() { if (!this.state.noGeoIndexPatternsExist) { return null; @@ -261,7 +337,7 @@ export class CreateSourceEditor extends Component { ); diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_panel.tsx b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_form.tsx similarity index 98% rename from x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_panel.tsx rename to x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_form.tsx index 4bcbee528ea5f..6dc92836e2aba 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_panel.tsx +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_form.tsx @@ -10,7 +10,6 @@ import { EuiSwitch, EuiSwitchEvent, EuiTitle, - EuiPanel, EuiSpacer, EuiHorizontalRule, EuiRadioGroup, @@ -54,7 +53,7 @@ interface State { maxResultWindow: number; } -export class ScalingPanel extends Component { +export class ScalingForm extends Component { private _isMounted: boolean; state = { maxInnerResultWindow: DEFAULT_MAX_INNER_RESULT_WINDOW, @@ -206,7 +205,7 @@ export class ScalingPanel extends Component { } return ( - +
@@ -226,7 +225,7 @@ export class ScalingPanel extends Component { {filterByBoundsSwitch} {scalingForm} - + ); } } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js index d3a8e572428a7..9277939292ebd 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js @@ -17,7 +17,7 @@ import { SORT_ORDER } from '../../../../common/constants'; import { ESDocField } from '../../fields/es_doc_field'; import { FormattedMessage } from '@kbn/i18n/react'; import { indexPatterns } from '../../../../../../../../src/plugins/data/public'; -import { ScalingPanel } from './scaling_panel'; +import { ScalingForm } from './scaling_form'; export class UpdateSourceEditor extends Component { static propTypes = { @@ -192,16 +192,10 @@ export class UpdateSourceEditor extends Component { ); } - render() { + _renderScalingPanel() { return ( - - {this._renderTooltipsPanel()} - - - {this._renderSortPanel()} - - - + + + ); + } + + render() { + return ( + + {this._renderTooltipsPanel()} + + + {this._renderSortPanel()} + + + {this._renderScalingPanel()} ); From f6cdad80d4145ea71fb3c2df8114cce5f2124525 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 19 Mar 2020 12:22:53 -0600 Subject: [PATCH 05/10] default geo field --- .../sources/es_search_source/create_source_editor.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js index 8b2887e47269b..8f6416b66e104 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js @@ -151,9 +151,15 @@ export class CreateSourceEditor extends Component { geoFields, }); - // make default selection - if (geoFields[0]) { - this._onGeoFieldSelect(geoFields[0].name); + if (geoFields.length) { + // make default selection, prefer aggregatable field over the first available + const firstAggregatableGeoField = geoFields.find(geoField => { + return geoField.aggregatable; + }); + const defaultGeoFieldName = firstAggregatableGeoField + ? firstAggregatableGeoField + : geoFields[0]; + this._onGeoFieldSelect(defaultGeoFieldName.name); } }, 300); From 7f394ab2715502e1425bf575eda09df345bbc51f Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 19 Mar 2020 12:35:50 -0600 Subject: [PATCH 06/10] ts lint errors --- .../plugins/maps/public/actions/map_actions.d.ts | 2 +- .../sources/es_search_source/scaling_form.tsx | 9 ++++----- x-pack/plugins/maps/common/constants.ts | 14 +++++++------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts b/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts index f1bd6b8f85b57..3a61d5affd861 100644 --- a/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts +++ b/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts @@ -23,4 +23,4 @@ export function updateSourceProp( propName: string, value: unknown, newLayerType?: LAYER_TYPE -); +): void; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_form.tsx b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_form.tsx index 6dc92836e2aba..c5950f1132974 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_form.tsx +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_form.tsx @@ -28,7 +28,6 @@ import { ValidatedRange } from '../../../components/validated_range'; import { DEFAULT_MAX_INNER_RESULT_WINDOW, DEFAULT_MAX_RESULT_WINDOW, - SORT_ORDER, SCALING_TYPES, LAYER_TYPE, } from '../../../../common/constants'; @@ -40,7 +39,7 @@ import { OnSourceChangeArgs } from '../../../connected_components/layer_panel/vi interface Props { filterByMapBounds: boolean; indexPatternId: string; - onChange: (OnSourceChangeArgs) => void; + onChange: (args: OnSourceChangeArgs) => void; scalingType: SCALING_TYPES; supportsClustering: boolean; termFields: IFieldType[]; @@ -54,11 +53,11 @@ interface State { } export class ScalingForm extends Component { - private _isMounted: boolean; state = { maxInnerResultWindow: DEFAULT_MAX_INNER_RESULT_WINDOW, maxResultWindow: DEFAULT_MAX_RESULT_WINDOW, }; + _isMounted = false; componentDidMount() { this._isMounted = true; @@ -81,7 +80,7 @@ export class ScalingForm extends Component { } } - _onScalingTypeChange = (optionId: SCALING_TYPES): void => { + _onScalingTypeChange = (optionId: string): void => { const layerType = optionId === SCALING_TYPES.CLUSTERS ? LAYER_TYPE.BLENDED_VECTOR : LAYER_TYPE.VECTOR; this.props.onChange({ propName: 'scalingType', value: optionId, newLayerType: layerType }); @@ -142,7 +141,7 @@ export class ScalingForm extends Component { )} value={this.props.topHitsSplitField} onChange={this._onTopHitsSplitFieldChange} - fields={this.state.termFields} + fields={this.props.termFields} compressed /> diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index 3b1513f4bb95d..2e49549e2c441 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -43,13 +43,13 @@ export function createMapPath(id: string) { return `${MAP_BASE_URL}/${id}`; } -export const LAYER_TYPE = { - TILE: 'TILE', - VECTOR: 'VECTOR', - VECTOR_TILE: 'VECTOR_TILE', - HEATMAP: 'HEATMAP', - BLENDED_VECTOR: 'BLENDED_VECTOR', -}; +export enum LAYER_TYPE { + TILE = 'TILE', + VECTOR = 'VECTOR', + VECTOR_TILE = 'VECTOR_TILE', + HEATMAP = 'HEATMAP', + BLENDED_VECTOR = 'BLENDED_VECTOR', +} export enum SORT_ORDER { ASC = 'asc', From cc53048af21403b6367153d51ed21c88a0fb1a17 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 19 Mar 2020 15:45:16 -0600 Subject: [PATCH 07/10] remove old dynamic filter behavior --- .../es_search_source/create_source_editor.js | 94 +------------------ .../translations/translations/ja-JP.json | 3 - .../translations/translations/zh-CN.json | 3 - 3 files changed, 4 insertions(+), 96 deletions(-) diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js index 8f6416b66e104..e663fa21ada8a 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js @@ -7,20 +7,13 @@ import _ from 'lodash'; import React, { Fragment, Component } from 'react'; import PropTypes from 'prop-types'; -import { EuiFormRow, EuiSpacer, EuiSwitch, EuiCallOut } from '@elastic/eui'; +import { EuiFormRow, EuiSpacer } from '@elastic/eui'; import { SingleFieldSelect } from '../../../components/single_field_select'; import { indexPatternService } from '../../../kibana_services'; import { NoIndexPatternCallout } from '../../../components/no_index_pattern_callout'; -import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { kfetch } from 'ui/kfetch'; -import { - ES_GEO_FIELD_TYPE, - GIS_API_PATH, - DEFAULT_MAX_RESULT_WINDOW, - SCALING_TYPES, -} from '../../../../common/constants'; +import { ES_GEO_FIELD_TYPE, SCALING_TYPES } from '../../../../common/constants'; import { DEFAULT_FILTER_BY_MAP_BOUNDS } from './constants'; import { indexPatterns } from '../../../../../../../../src/plugins/data/public'; import { ScalingForm } from './scaling_form'; @@ -49,12 +42,10 @@ function isGeoFieldAggregatable(indexPattern, geoFieldName) { const RESET_INDEX_PATTERN_STATE = { indexPattern: undefined, - geoFieldName: undefined, - showFilterByBoundsSwitch: false, - showScalingPanel: false, geoFields: undefined, // ES search source descriptor state + geoFieldName: undefined, filterByMapBounds: DEFAULT_FILTER_BY_MAP_BOUNDS, scalingType: SCALING_TYPES.CLUSTERS, // turn on clusting by default topHitsSplitField: undefined, @@ -99,16 +90,6 @@ export class CreateSourceEditor extends Component { ); }; - _loadIndexDocCount = async indexPatternTitle => { - const { count } = await kfetch({ - pathname: `../${GIS_API_PATH}/indexCount`, - query: { - index: indexPatternTitle, - }, - }); - return count; - }; - _debouncedLoad = _.debounce(async indexPatternId => { if (!indexPatternId || indexPatternId.length === 0) { return; @@ -122,15 +103,6 @@ export class CreateSourceEditor extends Component { return; } - let indexHasSmallDocCount = false; - try { - const indexDocCount = await this._loadIndexDocCount(indexPattern.title); - indexHasSmallDocCount = indexDocCount <= DEFAULT_MAX_RESULT_WINDOW; - } catch (error) { - // retrieving index count is a nice to have and is not essential - // do not interrupt user flow if unable to retrieve count - } - if (!this._isMounted) { return; } @@ -145,9 +117,6 @@ export class CreateSourceEditor extends Component { this.setState({ isLoadingIndexPattern: false, indexPattern: indexPattern, - filterByMapBounds: !indexHasSmallDocCount, // Turn off filterByMapBounds when index contains a limited number of documents - showFilterByBoundsSwitch: indexHasSmallDocCount, - showScalingPanel: !indexHasSmallDocCount, geoFields, }); @@ -179,15 +148,6 @@ export class CreateSourceEditor extends Component { ); }; - _onFilterByMapBoundsChange = event => { - this.setState( - { - filterByMapBounds: event.target.checked, - }, - this._previewLayer - ); - }; - _onScalingPropChange = ({ propName, value }) => { this.setState( { @@ -248,52 +208,8 @@ export class CreateSourceEditor extends Component { ); } - _renderFilterByMapBounds() { - if (!this.state.showFilterByBoundsSwitch) { - return null; - } - - return ( - - -

- -

-

- -

-
- - - - -
- ); - } - _renderScalingPanel() { - if (!this.state.indexPattern || !this.state.geoFieldName || !this.state.showScalingPanel) { + if (!this.state.indexPattern || !this.state.geoFieldName) { return null; } @@ -358,8 +274,6 @@ export class CreateSourceEditor extends Component { {this._renderGeoSelect()} {this._renderScalingPanel()} - - {this._renderFilterByMapBounds()}
); } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 86a6f958cf258..d849a0cff4a23 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -7247,9 +7247,6 @@ "xpack.maps.source.esGridDescription": "それぞれのグリッド付きセルのメトリックでグリッドにグループ分けされた地理空間データです。", "xpack.maps.source.esGridTitle": "グリッド集約", "xpack.maps.source.esSearch.convertToGeoJsonErrorMsg": "検索への応答を geoJson 機能コレクションに変換できません。エラー: {errorMsg}", - "xpack.maps.source.esSearch.disableFilterByMapBoundsExplainMsg": "インデックス「{indexPatternTitle}」はドキュメント数が少なく、ダイナミックフィルターが必要ありません。", - "xpack.maps.source.esSearch.disableFilterByMapBoundsTitle": "ダイナミックデータフィルターは無効です", - "xpack.maps.source.esSearch.disableFilterByMapBoundsTurnOnMsg": "ドキュメント数が増えると思われる場合はダイナミックフィルターをオンにしてください。", "xpack.maps.source.esSearch.extentFilterLabel": "マップの表示範囲でデータを動的にフィルタリング", "xpack.maps.source.esSearch.geofieldLabel": "地理空間フィールド", "xpack.maps.source.esSearch.geoFieldLabel": "地理空間フィールド", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index c580eb533feb9..ded573e404710 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7247,9 +7247,6 @@ "xpack.maps.source.esGridDescription": "地理空间数据在网格中进行分组,每个网格单元格都具有指标", "xpack.maps.source.esGridTitle": "网格聚合", "xpack.maps.source.esSearch.convertToGeoJsonErrorMsg": "无法将搜索响应转换成 geoJson 功能集合,错误:{errorMsg}", - "xpack.maps.source.esSearch.disableFilterByMapBoundsExplainMsg": "索引“{indexPatternTitle}”具有很少数量的文档,不需要动态筛选。", - "xpack.maps.source.esSearch.disableFilterByMapBoundsTitle": "动态数据筛选已禁用", - "xpack.maps.source.esSearch.disableFilterByMapBoundsTurnOnMsg": "如果预期文档数量会增加,请打开动态筛选。", "xpack.maps.source.esSearch.extentFilterLabel": "在可见地图区域中动态筛留数据", "xpack.maps.source.esSearch.geofieldLabel": "地理空间字段", "xpack.maps.source.esSearch.geoFieldLabel": "地理空间字段", From 2c0ced4292dd1482bdf35efc7012d0af6b66c111 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 19 Mar 2020 18:35:16 -0600 Subject: [PATCH 08/10] update jest tests --- .../__snapshots__/scaling_form.test.tsx.snap | 205 ++++++++++++ .../update_source_editor.test.js.snap | 315 +----------------- .../es_search_source/scaling_form.test.tsx | 47 +++ .../update_source_editor.test.js | 8 - 4 files changed, 269 insertions(+), 306 deletions(-) create mode 100644 x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/scaling_form.test.tsx.snap create mode 100644 x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/scaling_form.test.tsx diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/scaling_form.test.tsx.snap b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/scaling_form.test.tsx.snap new file mode 100644 index 0000000000000..967225d6f0fdc --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/scaling_form.test.tsx.snap @@ -0,0 +1,205 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should not render clusters option when clustering is not supported 1`] = ` + + +
+ +
+
+ + + + + + + +
+`; + +exports[`should render 1`] = ` + + +
+ +
+
+ + + + + + + +
+`; + +exports[`should render top hits form when scaling type is TOP_HITS 1`] = ` + + +
+ +
+
+ + + + + + + + + + + +
+`; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/update_source_editor.test.js.snap b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/update_source_editor.test.js.snap index c94f305773f35..0cb7f67fb9c92 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/update_source_editor.test.js.snap +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/update_source_editor.test.js.snap @@ -91,253 +91,16 @@ exports[`should enable sort order select when sort field provided 1`] = ` size="s" /> - -
- -
-
- - - - - - - -
- - -`; - -exports[`should render top hits form when scaling type is TOP_HITS 1`] = ` - - - -
- -
-
- - -
- - - -
- -
-
- - - - - - - -
- - - -
- -
-
- - - - - - - - - - - - - -
- -
- -
-
- - - - - - -
({})); + +jest.mock('./load_index_settings', () => ({ + loadIndexSettings: async () => { + return { maxInnerResultWindow: 100, maxResultWindow: 10000 }; + }, +})); + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { ScalingForm } from './scaling_form'; +import { SCALING_TYPES } from '../../../../common/constants'; + +const defaultProps = { + filterByMapBounds: true, + indexPatternId: 'myIndexPattern', + onChange: () => {}, + scalingType: SCALING_TYPES.LIMIT, + supportsClustering: true, + termFields: [], + topHitsSize: 1, +}; + +test('should render', async () => { + const component = shallow(); + + expect(component).toMatchSnapshot(); +}); + +test('should not render clusters option when clustering is not supported', async () => { + const component = shallow(); + + expect(component).toMatchSnapshot(); +}); + +test('should render top hits form when scaling type is TOP_HITS', async () => { + const component = shallow(); + + expect(component).toMatchSnapshot(); +}); diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.test.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.test.js index e8a845c4b1669..65a91ce03994a 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.test.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.test.js @@ -40,11 +40,3 @@ test('should enable sort order select when sort field provided', async () => { expect(component).toMatchSnapshot(); }); - -test('should render top hits form when scaling type is TOP_HITS', async () => { - const component = shallow( - - ); - - expect(component).toMatchSnapshot(); -}); From cd762f71d97a61be1f611373e4025f4bae0e4adb Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Fri, 20 Mar 2020 14:26:14 -0600 Subject: [PATCH 09/10] eslint --- .../layers/sources/es_search_source/create_source_editor.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js index cb9eb2d2b36c0..73bea574ace28 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/create_source_editor.js @@ -10,10 +10,7 @@ import PropTypes from 'prop-types'; import { EuiFormRow, EuiSpacer } from '@elastic/eui'; import { SingleFieldSelect } from '../../../components/single_field_select'; -import { - getIndexPatternService, - getIndexPatternSelectComponent, -} from '../../../kibana_services'; +import { getIndexPatternService, getIndexPatternSelectComponent } from '../../../kibana_services'; import { NoIndexPatternCallout } from '../../../components/no_index_pattern_callout'; import { i18n } from '@kbn/i18n'; import { ES_GEO_FIELD_TYPE, SCALING_TYPES } from '../../../../common/constants'; From c4569a88e7d891199a157f3fc1bb94764b85ab9a Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 23 Mar 2020 09:00:11 -0600 Subject: [PATCH 10/10] remove indexCount route --- x-pack/legacy/plugins/maps/server/routes.js | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/x-pack/legacy/plugins/maps/server/routes.js b/x-pack/legacy/plugins/maps/server/routes.js index 7ca659148449f..6aacfdc41aeea 100644 --- a/x-pack/legacy/plugins/maps/server/routes.js +++ b/x-pack/legacy/plugins/maps/server/routes.js @@ -409,26 +409,6 @@ export function initRoutes(server, licenseUid) { }, }); - server.route({ - method: 'GET', - path: `${ROOT}/indexCount`, - handler: async (request, h) => { - const { server, query } = request; - - if (!query.index) { - return h.response().code(400); - } - - const { callWithRequest } = server.plugins.elasticsearch.getCluster('data'); - try { - const { count } = await callWithRequest(request, 'count', { index: query.index }); - return { count }; - } catch (error) { - return h.response().code(400); - } - }, - }); - server.route({ method: 'GET', path: `/${INDEX_SETTINGS_API_PATH}`,