[Maps] move apply global filter settting from layer to source (#50523)

* [Maps] move apply global filter settting from layer to source

* add checkbox to join UI

* update edit UI for grid and pew-pew source

* add migrations

* update docs

* remove setting of applyGlobalQuery from geojson upload

* upgrade SIEM layer descriptors

* fix jest tests and api integration tests

* fix functional tests

* fix functional test

* i18n

* review feedback

* doc re-wording

* i18n fixes
This commit is contained in:
Nathan Reese 2019-11-18 13:59:27 -07:00 committed by GitHub
parent e5ef8788bd
commit e2dc9213ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 343 additions and 143 deletions

View file

@ -14,7 +14,7 @@ You can create a layer that requests data from {es} from the following:
** Grid aggregation source
** <<terms-join>>. The search context is applied to both the terms join and the vector source when the vector source is provided by Elasticsearch documents.
** <<terms-join>>
* <<heatmap-layer>> with Grid aggregation source
@ -87,8 +87,11 @@ The most common cause for empty layers are searches for a field that exists in o
[[maps-disable-search-for-layer]]
==== Disable search for layer
To prevent the global search bar from applying search context to a layer, clear the *Apply global filter to layer* checkbox in Layer settings.
Disabling the search context applies to the layer source and all <<terms-join, term joins>> configured for the layer.
You can prevent the search bar from applying search context to a layer by configuring the following:
* In *Source settings*, clear the *Apply global filter to source* checkbox to turn off the global search context for the layer source.
* In *Term joins*, clear the *Apply global filter to join* checkbox to turn off the global search context for the <<terms-join, term join>>.
[float]
[[maps-add-index-search]]

View file

@ -59,6 +59,9 @@ export const SOURCE_DATA_ID_ORIGIN = 'source';
export const GEOJSON_FILE = 'GEOJSON_FILE';
export const MIN_ZOOM = 0;
export const MAX_ZOOM = 24;
export const DECIMAL_DEGREES_PRECISION = 5; // meters precision
export const ZOOM_PRECISION = 2;
export const ES_SIZE_LIMIT = 10000;

View file

@ -0,0 +1,51 @@
/*
* 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 _ from 'lodash';
import {
ES_GEO_GRID,
ES_PEW_PEW,
ES_SEARCH,
} from '../constants';
function isEsSource(layerDescriptor) {
const sourceType = _.get(layerDescriptor, 'sourceDescriptor.type');
return [ES_GEO_GRID, ES_PEW_PEW, ES_SEARCH].includes(sourceType);
}
// Migration to move applyGlobalQuery from layer to sources.
// Moving to source to provide user the granularity needed to apply global filter per source.
export function moveApplyGlobalQueryToSources({ attributes }) {
if (!attributes.layerListJSON) {
return attributes;
}
const layerList = JSON.parse(attributes.layerListJSON);
layerList.forEach((layerDescriptor) => {
const applyGlobalQuery = _.get(layerDescriptor, 'applyGlobalQuery', true);
delete layerDescriptor.applyGlobalQuery;
if (isEsSource(layerDescriptor)) {
layerDescriptor.sourceDescriptor.applyGlobalQuery = applyGlobalQuery;
}
if (_.has(layerDescriptor, 'joins')) {
layerDescriptor.joins.forEach(joinDescriptor => {
if (_.has(joinDescriptor, 'right')) {
// joinDescriptor.right is ES_TERM_SOURCE source descriptor
joinDescriptor.right.applyGlobalQuery = applyGlobalQuery;
}
});
}
});
return {
...attributes,
layerListJSON: JSON.stringify(layerList),
};
}

View file

@ -0,0 +1,109 @@
/*
* 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 max-len: 0 */
import { moveApplyGlobalQueryToSources } from './move_apply_global_query';
describe('moveApplyGlobalQueryToSources', () => {
test('Should handle missing layerListJSON attribute', () => {
const attributes = {
title: 'my map',
};
expect(moveApplyGlobalQueryToSources({ attributes })).toEqual({
title: 'my map',
});
});
test('Should ignore layers without ES sources', () => {
const layerListJSON = JSON.stringify([
{
type: 'TILE',
sourceDescriptor: {
type: 'EMS_TMS'
}
}
]);
const attributes = {
title: 'my map',
layerListJSON
};
expect(moveApplyGlobalQueryToSources({ attributes })).toEqual({
title: 'my map',
layerListJSON,
});
});
test('Should move applyGlobalQuery from layer to source', () => {
const layerListJSON = JSON.stringify([
{
type: 'HEATMAP',
applyGlobalQuery: false,
sourceDescriptor: {
type: 'ES_GEO_GRID'
}
}
]);
const attributes = {
title: 'my map',
layerListJSON
};
expect(moveApplyGlobalQueryToSources({ attributes })).toEqual({
title: 'my map',
layerListJSON: '[{\"type\":\"HEATMAP\",\"sourceDescriptor\":{\"type\":\"ES_GEO_GRID\",\"applyGlobalQuery\":false}}]',
});
});
test('Should move applyGlobalQuery from layer to join', () => {
const layerListJSON = JSON.stringify([
{
type: 'VECTOR',
applyGlobalQuery: false,
sourceDescriptor: {
type: 'EMS_FILE'
},
joins: [
{
right: {}
}
]
}
]);
const attributes = {
title: 'my map',
layerListJSON
};
expect(moveApplyGlobalQueryToSources({ attributes })).toEqual({
title: 'my map',
layerListJSON: '[{\"type\":\"VECTOR\",\"sourceDescriptor\":{\"type\":\"EMS_FILE\"},\"joins\":[{\"right\":{\"applyGlobalQuery\":false}}]}]',
});
});
test('Should set applyGlobalQuery to true sources when no value is provided in layer', () => {
const layerListJSON = JSON.stringify([
{
type: 'VECTOR',
sourceDescriptor: {
type: 'ES_GEO_GRID'
},
joins: [
{
right: {}
}
]
}
]);
const attributes = {
title: 'my map',
layerListJSON
};
expect(moveApplyGlobalQueryToSources({ attributes })).toEqual({
title: 'my map',
layerListJSON: '[{\"type\":\"VECTOR\",\"sourceDescriptor\":{\"type\":\"ES_GEO_GRID\",\"applyGlobalQuery\":true},\"joins\":[{\"right\":{\"applyGlobalQuery\":true}}]}]',
});
});
});

View file

@ -7,6 +7,7 @@
import { extractReferences } from './common/migrations/references';
import { emsRasterTileToEmsVectorTile } from './common/migrations/ems_raster_tile_to_ems_vector_tile';
import { topHitsTimeToSort } from './common/migrations/top_hits_time_to_sort';
import { moveApplyGlobalQueryToSources } from './common/migrations/move_apply_global_query';
export const migrations = {
'map': {
@ -30,6 +31,14 @@ export const migrations = {
'7.5.0': (doc) => {
const attributes = topHitsTimeToSort(doc);
return {
...doc,
attributes,
};
},
'7.6.0': (doc) => {
const attributes = moveApplyGlobalQueryToSources(doc);
return {
...doc,
attributes,

View file

@ -634,19 +634,6 @@ export function setLayerQuery(id, query) {
};
}
export function setLayerApplyGlobalQuery(id, applyGlobalQuery) {
return (dispatch) => {
dispatch({
type: UPDATE_LAYER_PROP,
id,
propName: 'applyGlobalQuery',
newValue: applyGlobalQuery,
});
dispatch(syncDataForLayer(id));
};
}
export function removeSelectedLayer() {
return (dispatch, getState) => {
const state = getState();

View file

@ -45,7 +45,6 @@ describe('kibana.yml configured with map.tilemap.url', () => {
alpha: 1,
__dataRequests: [],
id: layers[0].id,
applyGlobalQuery: true,
label: null,
maxZoom: 24,
minZoom: 0,
@ -87,7 +86,6 @@ describe('EMS is enabled', () => {
alpha: 1,
__dataRequests: [],
id: layers[0].id,
applyGlobalQuery: true,
label: null,
maxZoom: 24,
minZoom: 0,

View file

@ -0,0 +1,33 @@
/*
* 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 from 'react';
import { EuiFormRow, EuiSwitch } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
const label = i18n.translate('xpack.maps.layerPanel.applyGlobalQueryCheckboxLabel', {
defaultMessage: `Apply global filter to source`,
});
export function GlobalFilterCheckbox({ applyGlobalQuery, customLabel, setApplyGlobalQuery }) {
const onApplyGlobalQueryChange = event => {
setApplyGlobalQuery(event.target.checked);
};
return (
<EuiFormRow
display="columnCompressedSwitch"
>
<EuiSwitch
label={customLabel ? customLabel : label}
checked={applyGlobalQuery}
onChange={onApplyGlobalQueryChange}
data-test-subj="mapLayerPanelApplyGlobalQueryCheckbox"
compressed
/>
</EuiFormRow>
);
}

View file

@ -43,7 +43,8 @@ export class FilterEditor extends Component {
}
_loadIndexPatterns = async () => {
const indexPatternIds = this.props.layer.getIndexPatternIds();
// Filter only effects source so only load source indices.
const indexPatternIds = this.props.layer.getSource().getIndexPatternIds();
const indexPatterns = [];
const getIndexPatternPromises = indexPatternIds.map(async indexPatternId => {
try {

View file

@ -15,6 +15,7 @@ import { i18n } from '@kbn/i18n';
import { JoinExpression } from './join_expression';
import { MetricsExpression } from './metrics_expression';
import { WhereExpression } from './where_expression';
import { GlobalFilterCheckbox } from '../../../../components/global_filter_checkbox';
import {
indexPatternService,
@ -168,6 +169,16 @@ export class Join extends Component {
});
}
_onApplyGlobalQueryChange = applyGlobalQuery => {
this.props.onChange({
leftField: this.props.join.leftField,
right: {
...this.props.join.right,
applyGlobalQuery,
},
});
}
render() {
const {
join,
@ -184,6 +195,7 @@ export class Join extends Component {
const isJoinConfigComplete = join.leftField && right.indexPatternId && right.term;
let metricsExpression;
let globalFilterCheckbox;
if (isJoinConfigComplete) {
metricsExpression = (
<EuiFlexItem grow={false}>
@ -194,6 +206,15 @@ export class Join extends Component {
/>
</EuiFlexItem>
);
globalFilterCheckbox = (
<GlobalFilterCheckbox
applyGlobalQuery={right.applyGlobalQuery}
setApplyGlobalQuery={this._onApplyGlobalQueryChange}
customLabel={i18n.translate('xpack.maps.layerPanel.join.applyGlobalQueryCheckboxLabel', {
defaultMessage: `Apply global filter to join`,
})}
/>
);
}
let whereExpression;
@ -234,6 +255,8 @@ export class Join extends Component {
{whereExpression}
{globalFilterCheckbox}
<EuiButtonIcon
className="mapJoinItem__delete"
iconType="trash"

View file

@ -58,7 +58,8 @@ export function JoinEditor({ joins, layer, onChange }) {
...joins,
{
right: {
id: uuid()
id: uuid(),
applyGlobalQuery: true,
}
}
]);

View file

@ -12,19 +12,16 @@ import {
updateLayerMaxZoom,
updateLayerMinZoom,
updateLayerAlpha,
setLayerApplyGlobalQuery,
} from '../../../actions/map_actions';
function mapStateToProps(state = {}) {
const selectedLayer = getSelectedLayer(state);
return {
alpha: selectedLayer.getAlpha(),
applyGlobalQuery: selectedLayer.getApplyGlobalQuery(),
label: selectedLayer.getLabel(),
layerId: selectedLayer.getId(),
maxZoom: selectedLayer.getMaxZoom(),
minZoom: selectedLayer.getMinZoom(),
layer: selectedLayer
};
}
@ -34,9 +31,6 @@ function mapDispatchToProps(dispatch) {
updateMinZoom: (id, minZoom) => dispatch(updateLayerMinZoom(id, minZoom)),
updateMaxZoom: (id, maxZoom) => dispatch(updateLayerMaxZoom(id, maxZoom)),
updateAlpha: (id, alpha) => dispatch(updateLayerAlpha(id, alpha)),
setLayerApplyGlobalQuery: (layerId, applyGlobalQuery) => {
dispatch(setLayerApplyGlobalQuery(layerId, applyGlobalQuery));
}
};
}

View file

@ -12,17 +12,13 @@ import {
EuiFormRow,
EuiFieldText,
EuiSpacer,
EuiSwitch,
EuiToolTip,
} from '@elastic/eui';
import { ValidatedRange } from '../../../components/validated_range';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { ValidatedDualRange } from 'ui/validated_range';
const MIN_ZOOM = 0;
const MAX_ZOOM = 24;
import { MAX_ZOOM, MIN_ZOOM } from '../../../../common/constants';
export function LayerSettings(props) {
const onLabelChange = event => {
@ -37,14 +33,9 @@ export function LayerSettings(props) {
const onAlphaChange = alpha => {
const alphaDecimal = alpha / 100;
props.updateAlpha(props.layerId, alphaDecimal);
};
const onApplyGlobalQueryChange = event => {
props.setLayerApplyGlobalQuery(props.layerId, event.target.checked);
};
const renderZoomSliders = () => {
return (
<ValidatedDualRange
@ -109,45 +100,6 @@ export function LayerSettings(props) {
);
};
const renderApplyGlobalQueryCheckbox = () => {
const layerSupportsGlobalQuery = props.layer.getIndexPatternIds().length;
const applyGlobalQueryCheckbox = (
<EuiFormRow
label={i18n.translate('xpack.maps.layerPanel.settingsPanel.layerGlobalFilterLabel', {
defaultMessage: 'Global filter',
})}
display="columnCompressedSwitch"
>
<EuiSwitch
label={i18n.translate('xpack.maps.layerPanel.applyGlobalQueryCheckboxLabel', {
defaultMessage: `Apply to layer`,
})}
checked={layerSupportsGlobalQuery ? props.applyGlobalQuery : false}
onChange={onApplyGlobalQueryChange}
disabled={!layerSupportsGlobalQuery}
data-test-subj="mapLayerPanelApplyGlobalQueryCheckbox"
compressed
/>
</EuiFormRow>
);
if (layerSupportsGlobalQuery) {
return applyGlobalQueryCheckbox;
}
return (
<EuiToolTip
position="top"
content={i18n.translate('xpack.maps.layerPanel.applyGlobalQueryCheckbox.disableTooltip', {
defaultMessage: `Layer does not support filtering.`,
})}
>
{applyGlobalQueryCheckbox}
</EuiToolTip>
);
};
return (
<Fragment>
<EuiPanel>
@ -164,7 +116,6 @@ export function LayerSettings(props) {
{renderLabel()}
{renderZoomSliders()}
{renderAlphaSlider()}
{renderApplyGlobalQueryCheckbox()}
</EuiPanel>
<EuiSpacer size="s" />

View file

@ -18,6 +18,7 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { MAX_ZOOM, MIN_ZOOM } from '../../../../common/constants';
function getViewString(lat, lon, zoom) {
return `${lat},${lon},${zoom}`;
@ -117,8 +118,8 @@ export class SetViewControl extends Component {
const { isInvalid: isZoomInvalid, component: zoomFormRow } = this._renderNumberFormRow({
value: this.state.zoom,
min: 0,
max: 24,
min: MIN_ZOOM,
max: MAX_ZOOM,
onChange: this._onZoomChange,
label: i18n.translate('xpack.maps.setViewControl.zoomLabel', {
defaultMessage: 'Zoom',

View file

@ -90,6 +90,10 @@ export class InnerJoin {
return this._rightSource.getIndexPatternIds();
}
getQueryableIndexPatternIds() {
return this._rightSource.getQueryableIndexPatternIds();
}
getWhereQuery() {
return this._rightSource.getWhereQuery();
}

View file

@ -10,8 +10,10 @@ import turf from 'turf';
import turfBooleanContains from '@turf/boolean-contains';
import { DataRequest } from './util/data_request';
import {
MAX_ZOOM,
MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER,
SOURCE_DATA_ID_ORIGIN
MIN_ZOOM,
SOURCE_DATA_ID_ORIGIN,
} from '../../common/constants';
import uuid from 'uuid/v4';
import { copyPersistentState } from '../reducers/util';
@ -44,11 +46,10 @@ export class AbstractLayer {
layerDescriptor.__dataRequests = _.get(options, '__dataRequests', []);
layerDescriptor.id = _.get(options, 'id', uuid());
layerDescriptor.label = options.label && options.label.length > 0 ? options.label : null;
layerDescriptor.minZoom = _.get(options, 'minZoom', 0);
layerDescriptor.maxZoom = _.get(options, 'maxZoom', 24);
layerDescriptor.minZoom = _.get(options, 'minZoom', MIN_ZOOM);
layerDescriptor.maxZoom = _.get(options, 'maxZoom', MAX_ZOOM);
layerDescriptor.alpha = _.get(options, 'alpha', 0.75);
layerDescriptor.visible = _.get(options, 'visible', true);
layerDescriptor.applyGlobalQuery = _.get(options, 'applyGlobalQuery', true);
layerDescriptor.style = _.get(options, 'style', {});
return layerDescriptor;
@ -231,10 +232,6 @@ export class AbstractLayer {
return this._descriptor.query;
}
getApplyGlobalQuery() {
return this._descriptor.applyGlobalQuery;
}
getZoomConfig() {
return {
minZoom: this._descriptor.minZoom,
@ -383,14 +380,10 @@ export class AbstractLayer {
}
getIndexPatternIds() {
return [];
return [];
}
getQueryableIndexPatternIds() {
if (this.getApplyGlobalQuery()) {
return this.getIndexPatternIds();
}
return [];
}

View file

@ -1,7 +0,0 @@
/*
* 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.
*/
export const DEFAULT_APPLY_GLOBAL_QUERY = false;

View file

@ -15,9 +15,6 @@ import { ClientFileCreateSourceEditor } from './create_client_file_source_editor
import { ESSearchSource } from '../es_search_source';
import uuid from 'uuid/v4';
import _ from 'lodash';
import {
DEFAULT_APPLY_GLOBAL_QUERY
} from './constants';
import { i18n } from '@kbn/i18n';
export class GeojsonFileSource extends AbstractVectorSource {
@ -31,9 +28,6 @@ export class GeojsonFileSource extends AbstractVectorSource {
});
static icon = 'importAction';
static isIndexingSource = true;
static layerDefaults = {
applyGlobalQuery: DEFAULT_APPLY_GLOBAL_QUERY
}
static createDescriptor(geoJson, name) {
// Wrap feature as feature collection if needed
@ -96,7 +90,7 @@ export class GeojsonFileSource extends AbstractVectorSource {
geoField,
filterByMapBounds
}, inspectorAdapters);
addAndViewSource(source, this.layerDefaults);
addAndViewSource(source);
importSuccessHandler(indexResponses);
}
};

View file

@ -85,6 +85,7 @@ export class ESGeoGridSource extends AbstractESAggSource {
metrics={this._descriptor.metrics}
renderAs={this._descriptor.requestType}
resolution={this._descriptor.resolution}
applyGlobalQuery={this._descriptor.applyGlobalQuery}
/>
);
}

View file

@ -14,6 +14,7 @@ import { ResolutionEditor } from './resolution_editor';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiSpacer, EuiTitle } from '@elastic/eui';
import { GlobalFilterCheckbox } from '../../../components/global_filter_checkbox';
export class UpdateSourceEditor extends Component {
state = {
@ -62,6 +63,10 @@ export class UpdateSourceEditor extends Component {
this.props.onChange({ propName: 'resolution', value: e });
};
_onApplyGlobalQueryChange = applyGlobalQuery => {
this.props.onChange({ propName: 'applyGlobalQuery', value: applyGlobalQuery });
};
_renderMetricsEditor() {
const metricsFilter =
this.props.renderAs === RENDER_AS.HEATMAP
@ -95,7 +100,13 @@ export class UpdateSourceEditor extends Component {
<Fragment>
<ResolutionEditor resolution={this.props.resolution} onChange={this._onResolutionChange} />
<EuiSpacer size="m" />
{this._renderMetricsEditor()}
<GlobalFilterCheckbox
applyGlobalQuery={this.props.applyGlobalQuery}
setApplyGlobalQuery={this._onApplyGlobalQueryChange}
/>
</Fragment>
);
}

View file

@ -68,6 +68,7 @@ export class ESPewPewSource extends AbstractESAggSource {
indexPatternId={this._descriptor.indexPatternId}
onChange={onChange}
metrics={this._descriptor.metrics}
applyGlobalQuery={this._descriptor.applyGlobalQuery}
/>
);
}

View file

@ -11,6 +11,7 @@ import { indexPatternService } from '../../../kibana_services';
import { i18n } from '@kbn/i18n';
import { EuiTitle, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { GlobalFilterCheckbox } from '../../../components/global_filter_checkbox';
export class UpdateSourceEditor extends Component {
state = {
@ -55,6 +56,10 @@ export class UpdateSourceEditor extends Component {
this.props.onChange({ propName: 'metrics', value: metrics });
};
_onApplyGlobalQueryChange = applyGlobalQuery => {
this.props.onChange({ propName: 'applyGlobalQuery', value: applyGlobalQuery });
};
render() {
return (
<>
@ -70,6 +75,10 @@ export class UpdateSourceEditor extends Component {
metrics={this.props.metrics}
onChange={this._onMetricsChange}
/>
<GlobalFilterCheckbox
applyGlobalQuery={this.props.applyGlobalQuery}
setApplyGlobalQuery={this._onApplyGlobalQueryChange}
/>
</>
);
}

View file

@ -96,6 +96,9 @@ exports[`should enable sort order select when sort field provided 1`] = `
onChange={[Function]}
/>
</EuiFormRow>
<GlobalFilterCheckbox
setApplyGlobalQuery={[Function]}
/>
</Fragment>
`;
@ -234,6 +237,9 @@ exports[`should render top hits form when useTopHits is true 1`] = `
onChange={[Function]}
/>
</EuiFormRow>
<GlobalFilterCheckbox
setApplyGlobalQuery={[Function]}
/>
</Fragment>
`;
@ -332,5 +338,8 @@ exports[`should render update source editor 1`] = `
onChange={[Function]}
/>
</EuiFormRow>
<GlobalFilterCheckbox
setApplyGlobalQuery={[Function]}
/>
</Fragment>
`;

View file

@ -55,6 +55,7 @@ export class ESSearchSource extends AbstractESSource {
constructor(descriptor, inspectorAdapters) {
super({
...descriptor,
id: descriptor.id,
type: ESSearchSource.type,
indexPatternId: descriptor.indexPatternId,
@ -81,6 +82,7 @@ export class ESSearchSource extends AbstractESSource {
useTopHits={this._descriptor.useTopHits}
topHitsSplitField={this._descriptor.topHitsSplitField}
topHitsSize={this._descriptor.topHitsSize}
applyGlobalQuery={this._descriptor.applyGlobalQuery}
/>
);
}

View file

@ -15,6 +15,7 @@ import {
} from '@elastic/eui';
import { SingleFieldSelect } from '../../../components/single_field_select';
import { TooltipSelector } from '../../../components/tooltip_selector';
import { GlobalFilterCheckbox } from '../../../components/global_filter_checkbox';
import { indexPatternService } from '../../../kibana_services';
import { i18n } from '@kbn/i18n';
@ -106,6 +107,10 @@ export class UpdateSourceEditor extends Component {
this.props.onChange({ propName: 'topHitsSize', value: size });
};
_onApplyGlobalQueryChange = applyGlobalQuery => {
this.props.onChange({ propName: 'applyGlobalQuery', value: applyGlobalQuery });
};
renderTopHitsForm() {
if (!this.props.useTopHits) {
return null;
@ -236,6 +241,11 @@ export class UpdateSourceEditor extends Component {
/>
</EuiFormRow>
<GlobalFilterCheckbox
applyGlobalQuery={this.props.applyGlobalQuery}
setApplyGlobalQuery={this._onApplyGlobalQueryChange}
/>
</Fragment>
);
}

View file

@ -24,6 +24,13 @@ export class AbstractESSource extends AbstractVectorSource {
static icon = 'logoElasticsearch';
constructor(descriptor, inspectorAdapters) {
super({
...descriptor,
applyGlobalQuery: _.get(descriptor, 'applyGlobalQuery', true),
}, inspectorAdapters);
}
isFieldAware() {
return true;
}
@ -40,6 +47,13 @@ export class AbstractESSource extends AbstractVectorSource {
return [this._descriptor.indexPatternId];
}
getQueryableIndexPatternIds() {
if (this.getApplyGlobalQuery()) {
return [this._descriptor.indexPatternId];
}
return [];
}
supportsElasticsearchFilters() {
return true;
}
@ -55,7 +69,6 @@ export class AbstractESSource extends AbstractVectorSource {
return clonedDescriptor;
}
async _runEsQuery(requestName, searchSource, registerCancelCallback, requestDescription) {
const abortController = new AbortController();
registerCancelCallback(() => abortController.abort());

View file

@ -95,8 +95,16 @@ export class AbstractSource {
return null;
}
getApplyGlobalQuery() {
return !!this._descriptor.applyGlobalQuery;
}
getIndexPatternIds() {
return [];
return [];
}
getQueryableIndexPatternIds() {
return [];
}
getGeoGridPrecision() {

View file

@ -292,6 +292,14 @@ export class VectorLayer extends AbstractLayer {
return indexPatternIds;
}
getQueryableIndexPatternIds() {
const indexPatternIds = this._source.getQueryableIndexPatternIds();
this.getValidJoins().forEach(join => {
indexPatternIds.push(...join.getQueryableIndexPatternIds());
});
return indexPatternIds;
}
_findDataRequestForSource(sourceDataId) {
return this._dataRequests.find(dataRequest => dataRequest.getDataId() === sourceDataId);
}
@ -389,7 +397,7 @@ export class VectorLayer extends AbstractLayer {
...dataFilters,
fieldNames: joinSource.getFieldNames(),
sourceQuery: joinSource.getWhereQuery(),
applyGlobalQuery: this.getApplyGlobalQuery(),
applyGlobalQuery: joinSource.getApplyGlobalQuery(),
};
const canSkip = await this._canSkipSourceUpdate(joinSource, sourceDataId, searchFilters);
if (canSkip) {
@ -452,7 +460,7 @@ export class VectorLayer extends AbstractLayer {
fieldNames: _.uniq(fieldNames).sort(),
geogridPrecision: this._source.getGeoGridPrecision(dataFilters.zoom),
sourceQuery: this.getQuery(),
applyGlobalQuery: this.getApplyGlobalQuery(),
applyGlobalQuery: this._source.getApplyGlobalQuery(),
sourceMeta: this._source.getSyncMeta(),
};
}

View file

@ -14,6 +14,7 @@ export const mockSourceLayer = {
sourceDescriptor: {
id: 'uuid.v4()',
type: 'ES_SEARCH',
applyGlobalQuery: true,
geoField: 'source.geo.location',
filterByMapBounds: false,
tooltipProperties: [
@ -56,7 +57,6 @@ export const mockSourceLayer = {
maxZoom: 24,
alpha: 1,
visible: true,
applyGlobalQuery: true,
type: 'VECTOR',
query: { query: '', language: 'kuery' },
joins: [],
@ -66,6 +66,7 @@ export const mockDestinationLayer = {
sourceDescriptor: {
id: 'uuid.v4()',
type: 'ES_SEARCH',
applyGlobalQuery: true,
geoField: 'destination.geo.location',
filterByMapBounds: true,
tooltipProperties: [
@ -108,7 +109,6 @@ export const mockDestinationLayer = {
maxZoom: 24,
alpha: 1,
visible: true,
applyGlobalQuery: true,
type: 'VECTOR',
query: { query: '', language: 'kuery' },
};
@ -116,6 +116,7 @@ export const mockDestinationLayer = {
export const mockLineLayer = {
sourceDescriptor: {
type: 'ES_PEW_PEW',
applyGlobalQuery: true,
id: 'uuid.v4()',
indexPatternId: '8c7323ac-97ad-4b53-ac0a-40f8f691a918',
sourceGeoField: 'source.geo.location',
@ -164,7 +165,6 @@ export const mockLineLayer = {
maxZoom: 24,
alpha: 0.5,
visible: true,
applyGlobalQuery: true,
type: 'VECTOR',
query: { query: '', language: 'kuery' },
};
@ -178,7 +178,6 @@ export const mockLayerList = [
maxZoom: 24,
alpha: 1,
visible: true,
applyGlobalQuery: true,
style: null,
type: 'VECTOR_TILE',
},
@ -196,7 +195,6 @@ export const mockLayerListDouble = [
maxZoom: 24,
alpha: 1,
visible: true,
applyGlobalQuery: true,
style: null,
type: 'VECTOR_TILE',
},

View file

@ -50,7 +50,6 @@ export const getLayerList = (indexPatternIds: IndexPatternMapping[]) => {
maxZoom: 24,
alpha: 1,
visible: true,
applyGlobalQuery: true,
style: null,
type: 'VECTOR_TILE',
},
@ -76,6 +75,7 @@ export const getSourceLayer = (indexPatternTitle: string, indexPatternId: string
sourceDescriptor: {
id: uuid.v4(),
type: 'ES_SEARCH',
applyGlobalQuery: true,
geoField: 'source.geo.location',
filterByMapBounds: false,
tooltipProperties: Object.keys(sourceFieldMappings),
@ -112,7 +112,6 @@ export const getSourceLayer = (indexPatternTitle: string, indexPatternId: string
maxZoom: 24,
alpha: 1,
visible: true,
applyGlobalQuery: true,
type: 'VECTOR',
query: { query: '', language: 'kuery' },
joins: [],
@ -129,6 +128,7 @@ export const getDestinationLayer = (indexPatternTitle: string, indexPatternId: s
sourceDescriptor: {
id: uuid.v4(),
type: 'ES_SEARCH',
applyGlobalQuery: true,
geoField: 'destination.geo.location',
filterByMapBounds: true,
tooltipProperties: Object.keys(destinationFieldMappings),
@ -165,7 +165,6 @@ export const getDestinationLayer = (indexPatternTitle: string, indexPatternId: s
maxZoom: 24,
alpha: 1,
visible: true,
applyGlobalQuery: true,
type: 'VECTOR',
query: { query: '', language: 'kuery' },
});
@ -180,6 +179,7 @@ export const getDestinationLayer = (indexPatternTitle: string, indexPatternId: s
export const getLineLayer = (indexPatternTitle: string, indexPatternId: string) => ({
sourceDescriptor: {
type: 'ES_PEW_PEW',
applyGlobalQuery: true,
id: uuid.v4(),
indexPatternId,
sourceGeoField: 'source.geo.location',
@ -228,7 +228,6 @@ export const getLineLayer = (indexPatternTitle: string, indexPatternId: string)
maxZoom: 24,
alpha: 0.5,
visible: true,
applyGlobalQuery: true,
type: 'VECTOR',
query: { query: '', language: 'kuery' },
});

View file

@ -6445,7 +6445,6 @@
"xpack.maps.layerControl.tocEntry.hideDetailsButtonTitle": "レイヤー詳細を非表示",
"xpack.maps.layerControl.tocEntry.showDetailsButtonAriaLabel": "レイヤー詳細を表示",
"xpack.maps.layerControl.tocEntry.showDetailsButtonTitle": "レイヤー詳細を表示",
"xpack.maps.layerPanel.applyGlobalQueryCheckbox.disableTooltip": "レイヤーはフィルタリングをサポートしていません。",
"xpack.maps.layerPanel.applyGlobalQueryCheckboxLabel": "レイヤーにグローバルフィルターを適用",
"xpack.maps.layerPanel.filterEditor.addFilterButtonLabel": "フィルターを追加します",
"xpack.maps.layerPanel.filterEditor.editFilterButtonLabel": "フィルターを編集",
@ -6701,7 +6700,6 @@
"xpack.maps.tooltip.toolsControl.cancelDrawButtonLabel": "キャンセル",
"xpack.maps.xyztmssource.attributionLink": "属性テキストにはリンクが必要です",
"xpack.maps.xyztmssource.attributionText": "属性 URL にはテキストが必要です",
"xpack.maps.layerPanel.settingsPanel.layerGlobalFilterLabel": "グローバルフィルター",
"xpack.maps.layerPanel.settingsPanel.percentageLabel": "%",
"xpack.maps.layerPanel.settingsPanel.visibleZoom": "ズームレベル",
"xpack.maps.source.esSearch.sortFieldSelectPlaceholder": "ソートフィールドを選択",

View file

@ -6447,7 +6447,6 @@
"xpack.maps.layerControl.tocEntry.hideDetailsButtonTitle": "隐藏图层详情",
"xpack.maps.layerControl.tocEntry.showDetailsButtonAriaLabel": "显示图层详情",
"xpack.maps.layerControl.tocEntry.showDetailsButtonTitle": "显示图层详情",
"xpack.maps.layerPanel.applyGlobalQueryCheckbox.disableTooltip": "图层不支持筛选",
"xpack.maps.layerPanel.applyGlobalQueryCheckboxLabel": "将全局筛选应用到图层",
"xpack.maps.layerPanel.filterEditor.addFilterButtonLabel": "添加筛选",
"xpack.maps.layerPanel.filterEditor.editFilterButtonLabel": "编辑筛选",
@ -6703,7 +6702,6 @@
"xpack.maps.tooltip.toolsControl.cancelDrawButtonLabel": "取消",
"xpack.maps.xyztmssource.attributionLink": "属性文本必须附带链接",
"xpack.maps.xyztmssource.attributionText": "属性 url 必须附带文本",
"xpack.maps.layerPanel.settingsPanel.layerGlobalFilterLabel": "全局筛选",
"xpack.maps.layerPanel.settingsPanel.percentageLabel": "%",
"xpack.maps.layerPanel.settingsPanel.visibleZoom": "缩放级别",
"xpack.maps.source.esSearch.sortFieldSelectPlaceholder": "选择排序字段",

View file

@ -42,7 +42,7 @@ export default function ({ getService }) {
type: 'index-pattern'
}
]);
expect(resp.body.migrationVersion).to.eql({ map: '7.5.0' });
expect(resp.body.migrationVersion).to.eql({ map: '7.6.0' });
expect(resp.body.attributes.layerListJSON.includes('indexPatternRefName')).to.be(true);
});
});

View file

@ -40,7 +40,7 @@ export default function ({ getPageObjects, getService }) {
it('should pass index patterns to container', async () => {
const indexPatterns = await filterBar.getIndexPatterns();
expect(indexPatterns).to.equal('geo_shapes*,meta_for_geo_shapes*,logstash-*');
expect(indexPatterns).to.equal('meta_for_geo_shapes*,logstash-*');
});
it('should populate inspector with requests for map embeddable', async () => {

View file

@ -111,14 +111,15 @@ export default function ({ getPageObjects, getService }) {
describe('query bar', () => {
before(async () => {
await PageObjects.maps.setAndSubmitQuery('prop1 < 10 or _index : "geo_shapes*"');
await PageObjects.maps.setAndSubmitQuery('prop1 < 10');
});
afterEach(async () => {
after(async () => {
await inspector.close();
await PageObjects.maps.setAndSubmitQuery('');
});
it('should apply query to join request', async () => {
it('should not apply query to source and apply query to join', async () => {
await PageObjects.maps.openInspectorRequest('meta_for_geo_shapes*.shape_name');
const requestStats = await inspector.getTableData();
const totalHits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits (total)');
@ -128,20 +129,6 @@ export default function ({ getPageObjects, getService }) {
const indexPatternName = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Index pattern');
expect(indexPatternName).to.equal('meta_for_geo_shapes*');
});
it('should not apply query to join request when apply global query is disabled', async () => {
await PageObjects.maps.openLayerPanel('geo_shapes*');
await PageObjects.maps.disableApplyGlobalQuery();
await PageObjects.maps.openInspectorRequest('meta_for_geo_shapes*.shape_name');
const requestStats = await inspector.getTableData();
const totalHits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits (total)');
expect(totalHits).to.equal('6');
const hits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits');
expect(hits).to.equal('0'); // aggregation requests do not return any documents
const indexPatternName = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Index pattern');
expect(indexPatternName).to.equal('meta_for_geo_shapes*');
});
});
describe('where clause', () => {

View file

@ -411,7 +411,7 @@
"type": "envelope"
},
"description": "",
"layerListJSON": "[{\"id\":\"0hmz5\",\"label\":\"EMS base layer (road_map)\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"n1t6f\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"62eca1fc-fe42-11e8-8eb2-f2801f1b9fd1\",\"type\":\"ES_SEARCH\",\"geoField\":\"geometry\",\"limit\":2048,\"filterByMapBounds\":false,\"showTooltip\":true,\"tooltipProperties\":[\"name\"],\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"max(prop1) group by meta_for_geo_shapes*.shape_name\",\"name\":\"__kbnjoin__max_of_prop1_groupby_meta_for_geo_shapes*.shape_name\",\"origin\":\"join\"},\"color\":\"Blues\"}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\",\"joins\":[{\"leftField\":\"name\",\"right\":{\"id\":\"855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"indexPatternTitle\":\"meta_for_geo_shapes*\",\"term\":\"shape_name\",\"metrics\":[{\"type\":\"max\",\"field\":\"prop1\"}],\"indexPatternRefName\":\"layer_1_join_0_index_pattern\"}}]}]",
"layerListJSON" : "[{\"id\":\"0hmz5\",\"label\":\"EMS base layer (road_map)\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"VECTOR_TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"n1t6f\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"62eca1fc-fe42-11e8-8eb2-f2801f1b9fd1\",\"type\":\"ES_SEARCH\",\"geoField\":\"geometry\",\"limit\":2048,\"filterByMapBounds\":false,\"showTooltip\":true,\"tooltipProperties\":[\"name\"],\"applyGlobalQuery\":false,\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"max(prop1) group by meta_for_geo_shapes*.shape_name\",\"name\":\"__kbnjoin__max_of_prop1_groupby_meta_for_geo_shapes*.shape_name\",\"origin\":\"join\"},\"color\":\"Blues\"}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\",\"joins\":[{\"leftField\":\"name\",\"right\":{\"id\":\"855ccb86-fe42-11e8-8eb2-f2801f1b9fd1\",\"indexPatternTitle\":\"meta_for_geo_shapes*\",\"term\":\"shape_name\",\"metrics\":[{\"type\":\"max\",\"field\":\"prop1\"}],\"applyGlobalQuery\":true,\"indexPatternRefName\":\"layer_1_join_0_index_pattern\"}}]}]",
"mapStateJSON": "{\"zoom\":3.02,\"center\":{\"lon\":77.33426,\"lat\":-0.04647},\"timeFilters\":{\"from\":\"now-17m\",\"to\":\"now\",\"mode\":\"quick\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":1000}}",
"title": "join example",
"uiStateJSON": "{\"isLayerTOCOpen\":true,\"openTOCDetails\":[\"n1t6f\"]}"
@ -430,7 +430,7 @@
}
],
"migrationVersion" : {
"map" : "7.2.0"
"map" : "7.6.0"
}
}
}