[maps] clean-up filter by map bounds action (#136045)

* [maps] clean-up filter by map bounds action

* modal

* [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix'

* update docs

* fix warning in generated filter pill

* fix functional test

* fix jest test

* review feedback

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2022-07-13 07:51:23 -06:00 committed by GitHub
parent e0b6517ae5
commit 63335d8e37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 284 additions and 122 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 708 KiB

View file

@ -81,22 +81,17 @@ Create filters from your map to focus in on just the data you want. *Maps* provi
[float]
[[maps-map-extent-filter]]
==== Filter dashboard by map extent
==== Filter dashboard by map bounds
A map extent shows uniform data across all panels.
As you pan and zoom your map, all panels will update to only include data that is visible in your map.
To filter your dashboard by your map bounds as you pan and zoom your map:
To enable filtering your dashboard by map extent:
* Open the main menu, and then click *Dashboard*.
* Select your dashboard from the list or click *Create dashboard*.
* If your dashboard does not have a map, add a map panel.
* Click the gear icon image:maps/images/gear_icon.png[gear icon] to open the map panel menu.
* Select *More* to view all panel options.
* Select *Enable filter by map extent*.
[role="screenshot"]
image::maps/images/enable_filter_by_map_extent.png[]
. Open the main menu, and then click *Dashboard*.
. Select your dashboard from the list or click *Create dashboard*.
. If your dashboard does not have a map, add a map panel.
. Click the gear icon image:maps/images/gear_icon.png[gear icon] to open the map panel menu.
. Select *More* to view all panel options.
. Select *Filter dashboard by map bounds*.
. Select the checkbox for your map panel.
[float]
[[maps-spatial-filters]]

View file

@ -30,6 +30,7 @@ describe('createExtentFilter', () => {
disabled: false,
key: 'location',
negate: false,
type: 'spatial_filter',
},
query: {
bool: {
@ -66,6 +67,7 @@ describe('createExtentFilter', () => {
disabled: false,
key: 'location',
negate: false,
type: 'spatial_filter',
},
query: {
bool: {
@ -102,6 +104,7 @@ describe('createExtentFilter', () => {
disabled: false,
key: 'location',
negate: false,
type: 'spatial_filter',
},
query: {
bool: {
@ -138,6 +141,7 @@ describe('createExtentFilter', () => {
disabled: false,
key: 'location',
negate: false,
type: 'spatial_filter',
},
query: {
bool: {
@ -174,6 +178,7 @@ describe('createExtentFilter', () => {
disabled: false,
key: 'location',
negate: false,
type: 'spatial_filter',
},
query: {
bool: {
@ -210,6 +215,7 @@ describe('createExtentFilter', () => {
disabled: false,
isMultiIndex: true,
negate: false,
type: 'spatial_filter',
},
query: {
bool: {

View file

@ -89,6 +89,7 @@ export function createExtentFilter(mapExtent: MapExtent, geoFieldNames: string[]
}
const meta: FilterMeta = {
type: SPATIAL_FILTER_TYPE,
alias: null,
disabled: false,
negate: false,

View file

@ -224,6 +224,7 @@ describe('ESGeoGridSource', () => {
disabled: false,
key: 'bar',
negate: false,
type: 'spatial_filter',
},
query: {
bool: {

View file

@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { getGeoFieldsLabel } from './get_geo_fields_label';
test('single field', () => {
expect(getGeoFieldsLabel(['location'])).toEqual('location');
});
test('two fields', () => {
expect(getGeoFieldsLabel(['location', 'secondLocation'])).toEqual('location and secondLocation');
});
test('three or more fields', () => {
expect(getGeoFieldsLabel(['location', 'secondLocation', 'thirdLocation'])).toEqual(
'location, secondLocation, and thirdLocation'
);
});

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
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
export function getGeoFieldsLabel(geoFieldNames: string[]) {
if (geoFieldNames.length === 0) {
return '';
}
if (geoFieldNames.length === 1) {
return geoFieldNames[0];
}
const connector = i18n.translate('xpack.maps.embeddable.geoFieldsConnector', {
defaultMessage: ' and ',
});
if (geoFieldNames.length === 2) {
return geoFieldNames[0] + connector + geoFieldNames[1];
}
return (
geoFieldNames.slice(0, geoFieldNames.length - 1).join(', ') +
',' +
connector +
geoFieldNames[geoFieldNames.length - 1]
);
}

View file

@ -82,8 +82,8 @@ import { getIndexPatternsFromIds } from '../index_pattern_util';
import { getMapAttributeService } from '../map_attribute_service';
import { isUrlDrilldown, toValueClickDataFormat } from '../trigger_actions/trigger_utils';
import { waitUntilTimeLayersLoad$ } from '../routes/map_page/map_app/wait_until_time_layers_load';
import { synchronizeMovement } from './synchronize_movement';
import { getFilterByMapExtent } from '../trigger_actions/filter_by_map_extent_action';
import { mapEmbeddablesSingleton } from './map_embeddables_singleton';
import { getGeoFieldsLabel } from './get_geo_fields_label';
import {
MapByValueInput,
@ -112,7 +112,6 @@ export class MapEmbeddable
private _savedMap: SavedMap;
private _renderTooltipContent?: RenderToolTipContent;
private _subscription: Subscription;
private _prevFilterByMapExtent: boolean;
private _prevIsRestore: boolean = false;
private _prevMapExtent?: MapExtent;
private _prevTimeRange?: TimeRange;
@ -144,7 +143,6 @@ export class MapEmbeddable
this._initializeSaveMap();
this._subscription = this.getUpdated$().subscribe(() => this.onUpdate());
this._controlledBy = `mapEmbeddablePanel${this.id}`;
this._prevFilterByMapExtent = getFilterByMapExtent(this.input);
}
public reportsEmbeddableLoad() {
@ -278,16 +276,6 @@ export class MapEmbeddable
}
onUpdate() {
const filterByMapExtent = getFilterByMapExtent(this.input);
if (this._prevFilterByMapExtent !== filterByMapExtent) {
this._prevFilterByMapExtent = filterByMapExtent;
if (filterByMapExtent) {
this.setMapExtentFilter();
} else {
this.clearMapExtentFilter();
}
}
if (
!_.isEqual(this.input.timeRange, this._prevTimeRange) ||
!_.isEqual(this.input.query, this._prevQuery) ||
@ -321,8 +309,12 @@ export class MapEmbeddable
: this.input.isMovementSynchronized;
};
_getIsFilterByMapExtent = () => {
return this.input.filterByMapExtent === undefined ? false : this.input.filterByMapExtent;
};
_gotoSynchronizedLocation() {
const syncedLocation = synchronizeMovement.getLocation();
const syncedLocation = mapEmbeddablesSingleton.getLocation();
if (syncedLocation) {
// set map to synchronized view
this._mapSyncHandler(syncedLocation.lat, syncedLocation.lon, syncedLocation.zoom);
@ -334,7 +326,7 @@ export class MapEmbeddable
// Use goto because un-rendered map will not have accurate mapCenter and mapZoom.
const goto = getGoto(this._savedMap.getStore().getState());
if (goto && goto.center) {
synchronizeMovement.setLocation(
mapEmbeddablesSingleton.setLocation(
this.input.id,
goto.center.lat,
goto.center.lon,
@ -347,12 +339,12 @@ export class MapEmbeddable
// Initialize synchronized view to map's view
const center = getMapCenter(this._savedMap.getStore().getState());
const zoom = getMapZoom(this._savedMap.getStore().getState());
synchronizeMovement.setLocation(this.input.id, center.lat, center.lon, zoom);
mapEmbeddablesSingleton.setLocation(this.input.id, center.lat, center.lon, zoom);
}
_propogateMapMovement = (lat: number, lon: number, zoom: number) => {
if (this._getIsMovementSynchronized()) {
synchronizeMovement.setLocation(this.input.id, lat, lon, zoom);
mapEmbeddablesSingleton.setLocation(this.input.id, lat, lon, zoom);
}
};
@ -418,7 +410,7 @@ export class MapEmbeddable
return;
}
synchronizeMovement.register(this.input.id, {
mapEmbeddablesSingleton.register(this.input.id, {
getTitle: () => {
const output = this.getOutput();
if (output.title) {
@ -442,6 +434,18 @@ export class MapEmbeddable
this._savedMap.getStore().dispatch(setMapSettings({ autoFitToDataBounds: true }));
}
},
getIsFilterByMapExtent: this._getIsFilterByMapExtent,
setIsFilterByMapExtent: (isFilterByMapExtent: boolean) => {
this.updateInput({ filterByMapExtent: isFilterByMapExtent });
if (isFilterByMapExtent) {
this._setMapExtentFilter();
} else {
this._clearMapExtentFilter();
}
},
getGeoFieldNames: () => {
return getGeoFieldNames(this._savedMap.getStore().getState());
},
});
if (this._getIsMovementSynchronized()) {
this._gotoSynchronizedLocation();
@ -568,14 +572,21 @@ export class MapEmbeddable
} as ActionExecutionContext;
};
setMapExtentFilter() {
const state = this._savedMap.getStore().getState();
const mapExtent = getMapExtent(state);
const geoFieldNames = getGeoFieldNames(state);
const center = getMapCenter(state);
const zoom = getMapZoom(state);
// Timing bug for dashboard with multiple maps with synchronized movement and filter by map extent enabled
// When moving map with filterByMapExtent:false, previous map extent filter(s) does not get removed
// Cuased by syncDashboardContainerInput applyContainerChangesToState.
// 1) _setMapExtentFilter executes ACTION_GLOBAL_APPLY_FILTER action,
// removing previous map extent filter and adding new map extent filter
// 2) applyContainerChangesToState then re-adds stale input.filters (which contains previous map extent filter)
// Add debounce to fix timing issue.
// 1) applyContainerChangesToState now runs first and does its thing
// 2) _setMapExtentFilter executes ACTION_GLOBAL_APPLY_FILTER action,
// removing previous map extent filter and adding new map extent filter
_setMapExtentFilter = _.debounce(() => {
const mapExtent = getMapExtent(this._savedMap.getStore().getState());
const geoFieldNames = mapEmbeddablesSingleton.getGeoFieldNames();
if (center === undefined || mapExtent === undefined || geoFieldNames.length === 0) {
if (mapExtent === undefined || geoFieldNames.length === 0) {
return;
}
@ -584,12 +595,8 @@ export class MapEmbeddable
const mapExtentFilter = createExtentFilter(mapExtent, geoFieldNames);
mapExtentFilter.meta.controlledBy = this._controlledBy;
mapExtentFilter.meta.alias = i18n.translate('xpack.maps.embeddable.boundsFilterLabel', {
defaultMessage: 'Map bounds at center: {lat}, {lon}, zoom: {zoom}',
values: {
lat: center.lat,
lon: center.lon,
zoom,
},
defaultMessage: '{geoFieldsLabel} within map bounds',
values: { geoFieldsLabel: getGeoFieldsLabel(geoFieldNames) },
});
const executeContext = {
@ -602,9 +609,9 @@ export class MapEmbeddable
throw new Error('Unable to apply map extent filter, could not locate action');
}
action.execute(executeContext);
}
}, 100);
clearMapExtentFilter() {
_clearMapExtentFilter() {
this._prevMapExtent = undefined;
const executeContext = {
...this.getActionContext(),
@ -620,7 +627,7 @@ export class MapEmbeddable
destroy() {
super.destroy();
synchronizeMovement.unregister(this.input.id);
mapEmbeddablesSingleton.unregister(this.input.id);
this._isActive = false;
if (this._unsubscribeFromStore) {
this._unsubscribeFromStore();
@ -665,8 +672,8 @@ export class MapEmbeddable
}
const mapExtent = getMapExtent(this._savedMap.getStore().getState());
if (getFilterByMapExtent(this.input) && !_.isEqual(this._prevMapExtent, mapExtent)) {
this.setMapExtentFilter();
if (this._getIsFilterByMapExtent() && !_.isEqual(this._prevMapExtent, mapExtent)) {
this._setMapExtentFilter();
}
const center = getMapCenter(this._savedMap.getStore().getState());

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import _ from 'lodash';
import { MapCenterAndZoom } from '../../common/descriptor_types';
interface MapPanel {
@ -12,6 +13,9 @@ interface MapPanel {
onLocationChange(lat: number, lon: number, zoom: number): void;
getIsMovementSynchronized(): boolean;
setIsMovementSynchronized(IsMovementSynchronized: boolean): void;
getIsFilterByMapExtent(): boolean;
setIsFilterByMapExtent(isFilterByMapExtent: boolean): void;
getGeoFieldNames(): string[];
}
const registry: Record<string, MapPanel> = {};
@ -19,7 +23,14 @@ let location: MapCenterAndZoom | undefined;
let primaryPanelId: string | undefined;
let primaryPanelTimeoutId: ReturnType<typeof setTimeout> | undefined;
export const synchronizeMovement = {
export const mapEmbeddablesSingleton = {
getGeoFieldNames() {
const geoFieldNames: string[] = [];
Object.values(registry).forEach((mapPanel) => {
geoFieldNames.push(...mapPanel.getGeoFieldNames());
});
return _.uniq(geoFieldNames);
},
getLocation() {
return location;
},

View file

@ -1,55 +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
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import { Embeddable, EmbeddableInput, ViewMode } from '@kbn/embeddable-plugin/public';
import { createAction } from '@kbn/ui-actions-plugin/public';
import { MAP_SAVED_OBJECT_TYPE } from '../../common/constants';
export const FILTER_BY_MAP_EXTENT = 'FILTER_BY_MAP_EXTENT';
interface FilterByMapExtentInput extends EmbeddableInput {
filterByMapExtent: boolean;
}
interface FilterByMapExtentActionContext {
embeddable: Embeddable<FilterByMapExtentInput>;
}
export function getFilterByMapExtent(input: { filterByMapExtent?: boolean }) {
return input.filterByMapExtent === undefined ? false : input.filterByMapExtent;
}
export const filterByMapExtentAction = createAction<FilterByMapExtentActionContext>({
id: FILTER_BY_MAP_EXTENT,
type: FILTER_BY_MAP_EXTENT,
order: 20,
getDisplayName: ({ embeddable }: FilterByMapExtentActionContext) => {
return getFilterByMapExtent(embeddable.getInput())
? i18n.translate('xpack.maps.filterByMapExtentMenuItem.disableDisplayName', {
defaultMessage: 'Disable filter by map extent',
})
: i18n.translate('xpack.maps.filterByMapExtentMenuItem.enableDisplayName', {
defaultMessage: 'Enable filter by map extent',
});
},
getIconType: () => {
return 'filter';
},
isCompatible: async ({ embeddable }: FilterByMapExtentActionContext) => {
return (
embeddable.type === MAP_SAVED_OBJECT_TYPE &&
embeddable.getInput().viewMode === ViewMode.EDIT &&
!embeddable.getInput().disableTriggers
);
},
execute: async ({ embeddable }: FilterByMapExtentActionContext) => {
embeddable.updateInput({
filterByMapExtent: !getFilterByMapExtent(embeddable.getInput()),
});
},
});

View file

@ -0,0 +1,73 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { i18n } from '@kbn/i18n';
import { Embeddable, EmbeddableInput } from '@kbn/embeddable-plugin/public';
import { createReactOverlays } from '@kbn/kibana-react-plugin/public';
import { createAction } from '@kbn/ui-actions-plugin/public';
import { MAP_SAVED_OBJECT_TYPE } from '../../common/constants';
import { getCore } from '../kibana_services';
export const FILTER_BY_MAP_EXTENT = 'FILTER_BY_MAP_EXTENT';
interface FilterByMapExtentInput extends EmbeddableInput {
filterByMapExtent: boolean;
}
interface FilterByMapExtentActionContext {
embeddable: Embeddable<FilterByMapExtentInput>;
}
function getContainerLabel(embeddable: Embeddable<FilterByMapExtentInput>) {
return embeddable.parent?.type === 'dashboard'
? i18n.translate('xpack.maps.filterByMapExtentMenuItem.dashboardLabel', {
defaultMessage: 'dashboard',
})
: i18n.translate('xpack.maps.filterByMapExtentMenuItem.pageLabel', {
defaultMessage: 'page',
});
}
function getDisplayName(embeddable: Embeddable<FilterByMapExtentInput>) {
return i18n.translate('xpack.maps.filterByMapExtentMenuItem.displayName', {
defaultMessage: 'Filter {containerLabel} by map bounds',
values: { containerLabel: getContainerLabel(embeddable) },
});
}
export const filterByMapExtentAction = createAction<FilterByMapExtentActionContext>({
id: FILTER_BY_MAP_EXTENT,
type: FILTER_BY_MAP_EXTENT,
order: 20,
getDisplayName: (context: FilterByMapExtentActionContext) => {
return getDisplayName(context.embeddable);
},
getDisplayNameTooltip: (context: FilterByMapExtentActionContext) => {
return i18n.translate('xpack.maps.filterByMapExtentMenuItem.displayNameTooltip', {
defaultMessage:
'As you zoom and pan the map, the {containerLabel} updates to display only the data visible in the map bounds.',
values: { containerLabel: getContainerLabel(context.embeddable) },
});
},
getIconType: () => {
return 'filter';
},
isCompatible: async ({ embeddable }: FilterByMapExtentActionContext) => {
return embeddable.type === MAP_SAVED_OBJECT_TYPE && !embeddable.getInput().disableTriggers;
},
execute: async (context: FilterByMapExtentActionContext) => {
const { FilterByMapExtentModal } = await import('./filter_by_map_extent_modal');
const { openModal } = createReactOverlays(getCore());
const modalSession = openModal(
<FilterByMapExtentModal
onClose={() => modalSession.close()}
title={getDisplayName(context.embeddable)}
/>
);
},
});

View file

@ -0,0 +1,66 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { Component, Fragment } from 'react';
import {
EuiFormRow,
EuiModalHeader,
EuiModalBody,
EuiModalHeaderTitle,
EuiSwitch,
EuiSwitchEvent,
} from '@elastic/eui';
import { mapEmbeddablesSingleton } from '../embeddable/map_embeddables_singleton';
interface Props {
onClose: () => void;
title: string;
}
export class FilterByMapExtentModal extends Component<Props> {
_renderSwitches() {
return mapEmbeddablesSingleton.getMapPanels().map((mapPanel) => {
return (
<EuiFormRow display="columnCompressedSwitch" key={mapPanel.id}>
<EuiSwitch
label={mapPanel.getTitle()}
checked={mapPanel.getIsFilterByMapExtent()}
onChange={(event: EuiSwitchEvent) => {
const isChecked = event.target.checked;
mapPanel.setIsFilterByMapExtent(isChecked);
// only a single map can create map bound filter at a time
// disable all other map panels from creating map bound filter
if (isChecked) {
mapEmbeddablesSingleton.getMapPanels().forEach((it) => {
if (it.id !== mapPanel.id && it.getIsFilterByMapExtent()) {
it.setIsFilterByMapExtent(false);
}
});
}
this.forceUpdate();
}}
compressed
data-test-subj={`filterByMapExtentSwitch${mapPanel.id}`}
/>
</EuiFormRow>
);
});
}
render() {
return (
<Fragment>
<EuiModalHeader>
<EuiModalHeaderTitle>{this.props.title}</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>{this._renderSwitches()}</EuiModalBody>
</Fragment>
);
}
}

View file

@ -39,8 +39,8 @@ export const synchronizeMovementAction = createAction<SynchronizeMovementActionC
return 'crosshairs';
},
isCompatible: async ({ embeddable }: SynchronizeMovementActionContext) => {
const { synchronizeMovement } = await import('../embeddable/synchronize_movement');
if (!synchronizeMovement.hasMultipleMaps()) {
const { mapEmbeddablesSingleton } = await import('../embeddable/map_embeddables_singleton');
if (!mapEmbeddablesSingleton.hasMultipleMaps()) {
return false;
}

View file

@ -15,7 +15,7 @@ import {
EuiSwitch,
EuiSwitchEvent,
} from '@elastic/eui';
import { synchronizeMovement } from '../embeddable/synchronize_movement';
import { mapEmbeddablesSingleton } from '../embeddable/map_embeddables_singleton';
interface Props {
onClose: () => void;
@ -23,7 +23,7 @@ interface Props {
export class SynchronizeMovementModal extends Component<Props> {
_renderSwitches() {
const mapPanels = synchronizeMovement.getMapPanels();
const mapPanels = mapEmbeddablesSingleton.getMapPanels();
const synchronizedPanels = mapPanels.filter((mapPanel) => {
return mapPanel.getIsMovementSynchronized();

View file

@ -17409,7 +17409,6 @@
"xpack.maps.drawTooltip.lineInstructions": "Cliquez pour commencer la ligne. Cliquez pour ajouter le vertex. Double-cliquez pour terminer.",
"xpack.maps.drawTooltip.pointInstructions": "Cliquez pour créer un point.",
"xpack.maps.drawTooltip.polygonInstructions": "Cliquez pour commencer la forme. Cliquez pour ajouter le vertex. Double-cliquez pour terminer.",
"xpack.maps.embeddable.boundsFilterLabel": "Limites de carte au centre : {lat}, {lon}, zoom : {zoom}",
"xpack.maps.embeddableDisplayName": "carte",
"xpack.maps.emsFileSelect.selectPlaceholder": "Sélectionner les limites EMS",
"xpack.maps.emsSource.tooltipsTitle": "Champs d'infobulle",
@ -17439,8 +17438,6 @@
"xpack.maps.fileUploadWizard.disabledDesc": "Impossible de charger les fichiers, vous ne disposez pas du privilège Kibana de gestion des vues de données.",
"xpack.maps.fileUploadWizard.title": "Charger le fichier",
"xpack.maps.fileUploadWizard.uploadLabel": "Importation du fichier",
"xpack.maps.filterByMapExtentMenuItem.disableDisplayName": "Désactiver le filtre par étendue de carte",
"xpack.maps.filterByMapExtentMenuItem.enableDisplayName": "Activer le filtre par étendue de carte",
"xpack.maps.filterEditor.applyForceRefreshLabel": "Appliquer une actualisation globale aux données de calque",
"xpack.maps.filterEditor.applyForceRefreshTooltip": "Lorsque cette option est activée, le calque récupère à nouveau les données au moment de lactualisation automatique ainsi que chaque fois que le bouton \"Actualiser\" est sélectionné.",
"xpack.maps.filterEditor.applyGlobalFilterHelp": "Lorsque cette option est activée, les résultats sont affinés par recherche globale.",

View file

@ -17399,7 +17399,6 @@
"xpack.maps.drawTooltip.lineInstructions": "クリックして行を開始します。クリックして頂点を追加します。ダブルクリックして終了します。",
"xpack.maps.drawTooltip.pointInstructions": "クリックして点を作成します。",
"xpack.maps.drawTooltip.polygonInstructions": "クリックしてシェイプを開始します。クリックして頂点を追加します。ダブルクリックして終了します。",
"xpack.maps.embeddable.boundsFilterLabel": "中央のマップの境界:{lat}、{lon}、ズーム:{zoom}",
"xpack.maps.embeddableDisplayName": "マップ",
"xpack.maps.emsFileSelect.selectPlaceholder": "EMS境界を選択",
"xpack.maps.emsSource.tooltipsTitle": "ツールチップフィールド",
@ -17429,8 +17428,6 @@
"xpack.maps.fileUploadWizard.disabledDesc": "ファイルをアップロードできません。Kibana「データビュー管理」権限がありません。",
"xpack.maps.fileUploadWizard.title": "ファイルをアップロード",
"xpack.maps.fileUploadWizard.uploadLabel": "ファイルをインポートしています",
"xpack.maps.filterByMapExtentMenuItem.disableDisplayName": "マップ範囲でのフィルターを無効にする",
"xpack.maps.filterByMapExtentMenuItem.enableDisplayName": "マップ範囲でのフィルターを有効にする",
"xpack.maps.filterEditor.applyForceRefreshLabel": "レイヤーデータにグローバル更新を適用",
"xpack.maps.filterEditor.applyForceRefreshTooltip": "有効にすると、自動更新が実行されるときと、[更新]をクリックしたときに、レイヤーでデータが再取り込みされます。",
"xpack.maps.filterEditor.applyGlobalFilterHelp": "有効にすると、結果がグローバル検索で絞り込まれます",

View file

@ -17417,7 +17417,6 @@
"xpack.maps.drawTooltip.lineInstructions": "单击以开始绘制线条。单击以添加顶点。双击以完成。",
"xpack.maps.drawTooltip.pointInstructions": "单击以创建点。",
"xpack.maps.drawTooltip.polygonInstructions": "单击以开始绘制形状。单击以添加顶点。双击以完成。",
"xpack.maps.embeddable.boundsFilterLabel": "位于中心的地图边界:{lat}, {lon},缩放:{zoom}",
"xpack.maps.embeddableDisplayName": "地图",
"xpack.maps.emsFileSelect.selectPlaceholder": "选择 EMS 边界",
"xpack.maps.emsSource.tooltipsTitle": "工具提示字段",
@ -17447,8 +17446,6 @@
"xpack.maps.fileUploadWizard.disabledDesc": "无法上传文件,您缺少对“数据视图管理”的 Kibana 权限。",
"xpack.maps.fileUploadWizard.title": "上传文件",
"xpack.maps.fileUploadWizard.uploadLabel": "正在导入文件",
"xpack.maps.filterByMapExtentMenuItem.disableDisplayName": "按地图范围禁用筛选",
"xpack.maps.filterByMapExtentMenuItem.enableDisplayName": "按地图范围启用筛选",
"xpack.maps.filterEditor.applyForceRefreshLabel": "将全局刷新应用于图层数据",
"xpack.maps.filterEditor.applyForceRefreshTooltip": "启用后,图层将在触发自动刷新和单击“刷新”时重新提取数据。",
"xpack.maps.filterEditor.applyGlobalFilterHelp": "启用后,全局搜索会缩减结果",

View file

@ -8,6 +8,7 @@
export default function ({ getPageObjects, getService }) {
const PageObjects = getPageObjects(['common', 'dashboard', 'header', 'lens', 'maps']);
const browser = getService('browser');
const testSubjects = getService('testSubjects');
const dashboardPanelActions = getService('dashboardPanelActions');
const security = getService('security');
@ -35,7 +36,12 @@ export default function ({ getPageObjects, getService }) {
it('should filter dashboard by map extent when "filter by map extent" is enabled', async () => {
const mapPanelHeader = await dashboardPanelActions.getPanelHeading('document example');
await dashboardPanelActions.openContextMenuMorePanel(mapPanelHeader);
await await testSubjects.click('embeddablePanelAction-FILTER_BY_MAP_EXTENT');
await testSubjects.click('embeddablePanelAction-FILTER_BY_MAP_EXTENT');
await testSubjects.setEuiSwitch(
'filterByMapExtentSwitch24ade730-afe4-42b6-919a-c4e0a98c94f2',
'check'
);
await browser.pressKeys(browser.keys.ESCAPE);
await PageObjects.header.waitUntilLoadingHasFinished();
await PageObjects.lens.assertMetric('Count of records', '1');
@ -50,7 +56,12 @@ export default function ({ getPageObjects, getService }) {
it('should remove map extent filter dashboard when "filter by map extent" is disabled', async () => {
const mapPanelHeader = await dashboardPanelActions.getPanelHeading('document example');
await dashboardPanelActions.openContextMenuMorePanel(mapPanelHeader);
await await testSubjects.click('embeddablePanelAction-FILTER_BY_MAP_EXTENT');
await testSubjects.click('embeddablePanelAction-FILTER_BY_MAP_EXTENT');
await testSubjects.setEuiSwitch(
'filterByMapExtentSwitch24ade730-afe4-42b6-919a-c4e0a98c94f2',
'uncheck'
);
await browser.pressKeys(browser.keys.ESCAPE);
await PageObjects.header.waitUntilLoadingHasFinished();
await PageObjects.lens.assertMetric('Count of records', '6');
});