mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Maps] Default ES document layer scaling type to clusters and show scaling UI in the create wizard (#60668)
* [Maps] show scaling panel in ES documents create wizard * minor fix * remove unused async state * update create editor to use ScalingForm * default geo field * ts lint errors * remove old dynamic filter behavior * update jest tests * eslint * remove indexCount route Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
13baa51561
commit
dc31736dd2
13 changed files with 636 additions and 616 deletions
|
@ -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
|
||||
): void;
|
||||
|
|
14
x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.d.ts
vendored
Normal file
14
x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.d.ts
vendored
Normal file
|
@ -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;
|
||||
};
|
|
@ -0,0 +1,205 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should not render clusters option when clustering is not supported 1`] = `
|
||||
<Fragment>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
defaultMessage="Scaling"
|
||||
id="xpack.maps.esSearch.scaleTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiRadioGroup
|
||||
idSelected="LIMIT"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"id": "LIMIT",
|
||||
"label": "Limit results to 10000.",
|
||||
},
|
||||
Object {
|
||||
"id": "TOP_HITS",
|
||||
"label": "Show top hits per entity.",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiSwitch
|
||||
checked={true}
|
||||
compressed={true}
|
||||
label="Dynamically filter for data in the visible map area"
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`should render 1`] = `
|
||||
<Fragment>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
defaultMessage="Scaling"
|
||||
id="xpack.maps.esSearch.scaleTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiRadioGroup
|
||||
idSelected="LIMIT"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"id": "LIMIT",
|
||||
"label": "Limit results to 10000.",
|
||||
},
|
||||
Object {
|
||||
"id": "TOP_HITS",
|
||||
"label": "Show top hits per entity.",
|
||||
},
|
||||
Object {
|
||||
"id": "CLUSTERS",
|
||||
"label": "Show clusters when results exceed 10000.",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiSwitch
|
||||
checked={true}
|
||||
compressed={true}
|
||||
label="Dynamically filter for data in the visible map area"
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`should render top hits form when scaling type is TOP_HITS 1`] = `
|
||||
<Fragment>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
defaultMessage="Scaling"
|
||||
id="xpack.maps.esSearch.scaleTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiRadioGroup
|
||||
idSelected="TOP_HITS"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"id": "LIMIT",
|
||||
"label": "Limit results to 10000.",
|
||||
},
|
||||
Object {
|
||||
"id": "TOP_HITS",
|
||||
"label": "Show top hits per entity.",
|
||||
},
|
||||
Object {
|
||||
"id": "CLUSTERS",
|
||||
"label": "Show clusters when results exceed 10000.",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiSwitch
|
||||
checked={true}
|
||||
compressed={true}
|
||||
label="Dynamically filter for data in the visible map area"
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiHorizontalRule
|
||||
margin="xs"
|
||||
/>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="columnCompressed"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
label="Entity"
|
||||
labelType="label"
|
||||
>
|
||||
<SingleFieldSelect
|
||||
compressed={true}
|
||||
fields={Array []}
|
||||
onChange={[Function]}
|
||||
placeholder="Select entity field"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</Fragment>
|
||||
`;
|
|
@ -91,257 +91,20 @@ exports[`should enable sort order select when sort field provided 1`] = `
|
|||
size="s"
|
||||
/>
|
||||
<EuiPanel>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
defaultMessage="Scaling"
|
||||
id="xpack.maps.esSearch.scaleTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiRadioGroup
|
||||
idSelected="LIMIT"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"id": "LIMIT",
|
||||
"label": "Limit results to 10000.",
|
||||
},
|
||||
Object {
|
||||
"id": "TOP_HITS",
|
||||
"label": "Show top hits per entity.",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiSwitch
|
||||
checked={true}
|
||||
compressed={true}
|
||||
label="Dynamically filter for data in the visible map area"
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiPanel>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`should render top hits form when scaling type is TOP_HITS 1`] = `
|
||||
<Fragment>
|
||||
<EuiPanel>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
defaultMessage="Tooltip fields"
|
||||
id="xpack.maps.esSearch.tooltipsTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<TooltipSelector
|
||||
fields={null}
|
||||
<ScalingForm
|
||||
filterByMapBounds={true}
|
||||
indexPatternId="indexPattern1"
|
||||
onChange={[Function]}
|
||||
tooltipFields={Array []}
|
||||
scalingType="LIMIT"
|
||||
supportsClustering={false}
|
||||
termFields={null}
|
||||
topHitsSize={1}
|
||||
topHitsSplitField="trackId"
|
||||
/>
|
||||
</EuiPanel>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiPanel>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
defaultMessage="Sorting"
|
||||
id="xpack.maps.esSearch.sortTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="columnCompressed"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
label="Field"
|
||||
labelType="label"
|
||||
>
|
||||
<SingleFieldSelect
|
||||
compressed={true}
|
||||
fields={null}
|
||||
onChange={[Function]}
|
||||
placeholder="Select sort field"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="columnCompressed"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
label="Order"
|
||||
labelType="label"
|
||||
>
|
||||
<EuiSelect
|
||||
compressed={true}
|
||||
disabled={true}
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"text": "ascending",
|
||||
"value": "asc",
|
||||
},
|
||||
Object {
|
||||
"text": "descending",
|
||||
"value": "desc",
|
||||
},
|
||||
]
|
||||
}
|
||||
value="DESC"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiPanel>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiPanel>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
defaultMessage="Scaling"
|
||||
id="xpack.maps.esSearch.scaleTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiRadioGroup
|
||||
idSelected="TOP_HITS"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"id": "LIMIT",
|
||||
"label": "Limit results to 10000.",
|
||||
},
|
||||
Object {
|
||||
"id": "TOP_HITS",
|
||||
"label": "Show top hits per entity.",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiSwitch
|
||||
checked={true}
|
||||
compressed={true}
|
||||
label="Dynamically filter for data in the visible map area"
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiHorizontalRule
|
||||
margin="xs"
|
||||
/>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="columnCompressed"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
label="Entity"
|
||||
labelType="label"
|
||||
>
|
||||
<SingleFieldSelect
|
||||
compressed={true}
|
||||
fields={null}
|
||||
onChange={[Function]}
|
||||
placeholder="Select entity field"
|
||||
value="trackId"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="columnCompressed"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
label="Documents per entity"
|
||||
labelType="label"
|
||||
>
|
||||
<ValidatedRange
|
||||
compressed={true}
|
||||
data-test-subj="layerPanelTopHitsSize"
|
||||
max={100}
|
||||
min={1}
|
||||
onChange={[Function]}
|
||||
showInput={true}
|
||||
showLabels={true}
|
||||
showRange={true}
|
||||
step={1}
|
||||
value={1}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiPanel>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
|
@ -435,60 +198,16 @@ exports[`should render update source editor 1`] = `
|
|||
size="s"
|
||||
/>
|
||||
<EuiPanel>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
>
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
defaultMessage="Scaling"
|
||||
id="xpack.maps.esSearch.scaleTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
<ScalingForm
|
||||
filterByMapBounds={true}
|
||||
indexPatternId="indexPattern1"
|
||||
onChange={[Function]}
|
||||
scalingType="LIMIT"
|
||||
supportsClustering={false}
|
||||
termFields={null}
|
||||
topHitsSize={1}
|
||||
topHitsSplitField="trackId"
|
||||
/>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiRadioGroup
|
||||
idSelected="LIMIT"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"id": "LIMIT",
|
||||
"label": "Limit results to 10000.",
|
||||
},
|
||||
Object {
|
||||
"id": "TOP_HITS",
|
||||
"label": "Show top hits per entity.",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiSwitch
|
||||
checked={true}
|
||||
compressed={true}
|
||||
label="Dynamically filter for data in the visible map area"
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiPanel>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
|
|
|
@ -7,24 +7,17 @@
|
|||
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 {
|
||||
getIndexPatternService,
|
||||
getIndexPatternSelectComponent,
|
||||
getHttp,
|
||||
} from '../../../kibana_services';
|
||||
import { getIndexPatternService, getIndexPatternSelectComponent } from '../../../kibana_services';
|
||||
import { NoIndexPatternCallout } from '../../../components/no_index_pattern_callout';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
ES_GEO_FIELD_TYPE,
|
||||
GIS_API_PATH,
|
||||
DEFAULT_MAX_RESULT_WINDOW,
|
||||
} 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';
|
||||
import { getTermsFields } from '../../../index_pattern_util';
|
||||
|
||||
function getGeoFields(fields) {
|
||||
return fields.filter(field => {
|
||||
|
@ -34,11 +27,26 @@ 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,
|
||||
geoFields: undefined,
|
||||
|
||||
// ES search source descriptor state
|
||||
geoFieldName: undefined,
|
||||
filterByMapBounds: DEFAULT_FILTER_BY_MAP_BOUNDS,
|
||||
showFilterByBoundsSwitch: false,
|
||||
scalingType: SCALING_TYPES.CLUSTERS, // turn on clusting by default
|
||||
topHitsSplitField: undefined,
|
||||
topHitsSize: 1,
|
||||
};
|
||||
|
||||
export class CreateSourceEditor extends Component {
|
||||
|
@ -58,41 +66,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 => {
|
||||
const http = getHttp();
|
||||
const { count } = await http.fetch(`../${GIS_API_PATH}/indexCount`, {
|
||||
method: 'GET',
|
||||
credentials: 'same-origin',
|
||||
query: {
|
||||
index: indexPatternTitle,
|
||||
},
|
||||
});
|
||||
return count;
|
||||
};
|
||||
|
||||
debouncedLoad = _.debounce(async indexPatternId => {
|
||||
_debouncedLoad = _.debounce(async indexPatternId => {
|
||||
if (!indexPatternId || indexPatternId.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -105,15 +100,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;
|
||||
}
|
||||
|
@ -124,43 +110,71 @@ 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,
|
||||
geoFields,
|
||||
});
|
||||
|
||||
//make default selection
|
||||
const geoFields = getGeoFields(indexPattern.fields);
|
||||
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);
|
||||
|
||||
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 => {
|
||||
_onScalingPropChange = ({ propName, value }) => {
|
||||
this.setState(
|
||||
{
|
||||
filterByMapBounds: event.target.checked,
|
||||
[propName]: value,
|
||||
},
|
||||
this.previewLayer
|
||||
this._previewLayer
|
||||
);
|
||||
};
|
||||
|
||||
previewLayer = () => {
|
||||
const { indexPatternId, geoField, filterByMapBounds } = this.state;
|
||||
_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);
|
||||
};
|
||||
|
||||
|
@ -183,56 +197,35 @@ 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}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
||||
_renderFilterByMapBounds() {
|
||||
if (!this.state.showFilterByBoundsSwitch) {
|
||||
_renderScalingPanel() {
|
||||
if (!this.state.indexPattern || !this.state.geoFieldName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiCallOut
|
||||
title={i18n.translate('xpack.maps.source.esSearch.disableFilterByMapBoundsTitle', {
|
||||
defaultMessage: `Dynamic data filter disabled`,
|
||||
})}
|
||||
>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.source.esSearch.disableFilterByMapBoundsExplainMsg"
|
||||
defaultMessage="Index '{indexPatternTitle}' has a small number of documents and does not require dynamic filtering."
|
||||
values={{
|
||||
indexPatternTitle: this.state.indexPattern
|
||||
? this.state.indexPattern.title
|
||||
: this.state.indexPatternId,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.maps.source.esSearch.disableFilterByMapBoundsTurnOnMsg"
|
||||
defaultMessage="Turn on dynamic filtering if you expect the number of documents to increase."
|
||||
/>
|
||||
</p>
|
||||
</EuiCallOut>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiFormRow>
|
||||
<EuiSwitch
|
||||
label={i18n.translate('xpack.maps.source.esSearch.extentFilterLabel', {
|
||||
defaultMessage: `Dynamically filter for data in the visible map area`,
|
||||
})}
|
||||
checked={this.state.filterByMapBounds}
|
||||
onChange={this.onFilterByMapBoundsChange}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer size="m" />
|
||||
<ScalingForm
|
||||
filterByMapBounds={this.state.filterByMapBounds}
|
||||
indexPatternId={this.state.indexPatternId}
|
||||
onChange={this._onScalingPropChange}
|
||||
scalingType={this.state.scalingType}
|
||||
supportsClustering={isGeoFieldAggregatable(
|
||||
this.state.indexPattern,
|
||||
this.state.geoFieldName
|
||||
)}
|
||||
termFields={getTermsFields(this.state.indexPattern.fields)}
|
||||
topHitsSplitField={this.state.topHitsSplitField}
|
||||
topHitsSize={this.state.topHitsSize}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
@ -265,7 +258,7 @@ export class CreateSourceEditor extends Component {
|
|||
<IndexPatternSelect
|
||||
isDisabled={this.state.noGeoIndexPatternsExist}
|
||||
indexPatternId={this.state.indexPatternId}
|
||||
onChange={this.onIndexPatternSelect}
|
||||
onChange={this._onIndexPatternSelect}
|
||||
placeholder={i18n.translate(
|
||||
'xpack.maps.source.esSearch.selectIndexPatternPlaceholder',
|
||||
{
|
||||
|
@ -279,7 +272,7 @@ export class CreateSourceEditor extends Component {
|
|||
|
||||
{this._renderGeoSelect()}
|
||||
|
||||
{this._renderFilterByMapBounds()}
|
||||
{this._renderScalingPanel()}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
jest.mock('../../../kibana_services', () => ({}));
|
||||
|
||||
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(<ScalingForm {...defaultProps} />);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should not render clusters option when clustering is not supported', async () => {
|
||||
const component = shallow(<ScalingForm {...defaultProps} supportsClustering={false} />);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render top hits form when scaling type is TOP_HITS', async () => {
|
||||
const component = shallow(<ScalingForm {...defaultProps} scalingType={SCALING_TYPES.TOP_HITS} />);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* 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,
|
||||
EuiSpacer,
|
||||
EuiHorizontalRule,
|
||||
EuiRadioGroup,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
// @ts-ignore
|
||||
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,
|
||||
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: (args: OnSourceChangeArgs) => void;
|
||||
scalingType: SCALING_TYPES;
|
||||
supportsClustering: boolean;
|
||||
termFields: IFieldType[];
|
||||
topHitsSplitField?: string;
|
||||
topHitsSize: number;
|
||||
}
|
||||
|
||||
interface State {
|
||||
maxInnerResultWindow: number;
|
||||
maxResultWindow: number;
|
||||
}
|
||||
|
||||
export class ScalingForm extends Component<Props, State> {
|
||||
state = {
|
||||
maxInnerResultWindow: DEFAULT_MAX_INNER_RESULT_WINDOW,
|
||||
maxResultWindow: DEFAULT_MAX_RESULT_WINDOW,
|
||||
};
|
||||
_isMounted = false;
|
||||
|
||||
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: string): 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 = (
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.maps.source.esSearch.topHitsSizeLabel', {
|
||||
defaultMessage: 'Documents per entity',
|
||||
})}
|
||||
display="columnCompressed"
|
||||
>
|
||||
<ValidatedRange
|
||||
min={1}
|
||||
max={this.state.maxInnerResultWindow}
|
||||
step={1}
|
||||
value={this.props.topHitsSize}
|
||||
onChange={this._onTopHitsSizeChange}
|
||||
showLabels
|
||||
showInput
|
||||
showRange
|
||||
data-test-subj="layerPanelTopHitsSize"
|
||||
compressed
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.maps.source.esSearch.topHitsSplitFieldLabel', {
|
||||
defaultMessage: 'Entity',
|
||||
})}
|
||||
display="columnCompressed"
|
||||
>
|
||||
<SingleFieldSelect
|
||||
placeholder={i18n.translate(
|
||||
'xpack.maps.source.esSearch.topHitsSplitFieldSelectPlaceholder',
|
||||
{
|
||||
defaultMessage: 'Select entity field',
|
||||
}
|
||||
)}
|
||||
value={this.props.topHitsSplitField}
|
||||
onChange={this._onTopHitsSplitFieldChange}
|
||||
fields={this.props.termFields}
|
||||
compressed
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
||||
{sizeSlider}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
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 = (
|
||||
<EuiFormRow>
|
||||
<EuiSwitch
|
||||
label={i18n.translate('xpack.maps.source.esSearch.extentFilterLabel', {
|
||||
defaultMessage: 'Dynamically filter for data in the visible map area',
|
||||
})}
|
||||
checked={this.props.filterByMapBounds}
|
||||
onChange={this._onFilterByMapBoundsChange}
|
||||
compressed
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
||||
let scalingForm = null;
|
||||
if (this.props.scalingType === SCALING_TYPES.TOP_HITS) {
|
||||
scalingForm = (
|
||||
<Fragment>
|
||||
<EuiHorizontalRule margin="xs" />
|
||||
{this._renderTopHitsForm()}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiTitle size="xs">
|
||||
<h5>
|
||||
<FormattedMessage id="xpack.maps.esSearch.scaleTitle" defaultMessage="Scaling" />
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
<EuiFormRow>
|
||||
<EuiRadioGroup
|
||||
options={scalingOptions}
|
||||
idSelected={this.props.scalingType}
|
||||
onChange={this._onScalingTypeChange}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
||||
{filterByBoundsSwitch}
|
||||
|
||||
{scalingForm}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -6,34 +6,18 @@
|
|||
|
||||
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 { getIndexPatternService } 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 { 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 { ScalingForm } from './scaling_form';
|
||||
|
||||
export class UpdateSourceEditor extends Component {
|
||||
static propTypes = {
|
||||
|
@ -52,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 getIndexPatternService().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 {
|
||||
|
@ -133,85 +102,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 = (
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.maps.source.esSearch.topHitsSizeLabel', {
|
||||
defaultMessage: 'Documents per entity',
|
||||
})}
|
||||
display="columnCompressed"
|
||||
>
|
||||
<ValidatedRange
|
||||
min={1}
|
||||
max={this.state.maxInnerResultWindow}
|
||||
step={1}
|
||||
value={this.props.topHitsSize}
|
||||
onChange={this.onTopHitsSizeChange}
|
||||
showLabels
|
||||
showInput
|
||||
showRange
|
||||
data-test-subj="layerPanelTopHitsSize"
|
||||
compressed
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.maps.source.esSearch.topHitsSplitFieldLabel', {
|
||||
defaultMessage: 'Entity',
|
||||
})}
|
||||
display="columnCompressed"
|
||||
>
|
||||
<SingleFieldSelect
|
||||
placeholder={i18n.translate(
|
||||
'xpack.maps.source.esSearch.topHitsSplitFieldSelectPlaceholder',
|
||||
{
|
||||
defaultMessage: 'Select entity field',
|
||||
}
|
||||
)}
|
||||
value={this.props.topHitsSplitField}
|
||||
onChange={this.onTopHitsSplitFieldChange}
|
||||
fields={this.state.termFields}
|
||||
compressed
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
||||
{sizeSlider}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
_renderTooltipsPanel() {
|
||||
return (
|
||||
<EuiPanel>
|
||||
|
@ -257,7 +155,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 +184,7 @@ export class UpdateSourceEditor extends Component {
|
|||
},
|
||||
]}
|
||||
value={this.props.sortOrder}
|
||||
onChange={this.onSortOrderChange}
|
||||
onChange={this._onSortOrderChange}
|
||||
compressed
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
@ -295,78 +193,18 @@ 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 = (
|
||||
<EuiFormRow>
|
||||
<EuiSwitch
|
||||
label={i18n.translate('xpack.maps.source.esSearch.extentFilterLabel', {
|
||||
defaultMessage: 'Dynamically filter for data in the visible map area',
|
||||
})}
|
||||
checked={this.props.filterByMapBounds}
|
||||
onChange={this._onFilterByMapBoundsChange}
|
||||
compressed
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
||||
let scalingForm = null;
|
||||
if (this.props.scalingType === SCALING_TYPES.TOP_HITS) {
|
||||
scalingForm = (
|
||||
<Fragment>
|
||||
<EuiHorizontalRule margin="xs" />
|
||||
{this._renderTopHitsForm()}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiPanel>
|
||||
<EuiTitle size="xs">
|
||||
<h5>
|
||||
<FormattedMessage id="xpack.maps.esSearch.scaleTitle" defaultMessage="Scaling" />
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
<EuiFormRow>
|
||||
<EuiRadioGroup
|
||||
options={scalingOptions}
|
||||
idSelected={this.props.scalingType}
|
||||
onChange={this._onScalingTypeChange}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
||||
{filterByBoundsSwitch}
|
||||
|
||||
{scalingForm}
|
||||
<ScalingForm
|
||||
filterByMapBounds={this.props.filterByMapBounds}
|
||||
indexPatternId={this.props.indexPatternId}
|
||||
onChange={this.props.onChange}
|
||||
scalingType={this.props.scalingType}
|
||||
supportsClustering={this.state.supportsClustering}
|
||||
termFields={this.state.termFields}
|
||||
topHitsSplitField={this.props.topHitsSplitField}
|
||||
topHitsSize={this.props.topHitsSize}
|
||||
/>
|
||||
</EuiPanel>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
<UpdateSourceEditor {...defaultProps} scalingType={SCALING_TYPES.TOP_HITS} />
|
||||
);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -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}`,
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -7170,9 +7170,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": "地理空間フィールド",
|
||||
|
|
|
@ -7170,9 +7170,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": "地理空间字段",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue