mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Maps] fix choropleth map with applyGlobalQuery set to false still creates filter for source. (#108999) (#109915)
* [Maps] fix choropleth map with applyGlobalQuery set to false still creates filter for source. * cleanup functional test * eslint * fix functional test * add inidication in tooltip when field is join key * copy updates * update jest test * eslint Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Nathan Reese <reese.nathan@gmail.com>
This commit is contained in:
parent
5e3572ef51
commit
7b0adb268c
11 changed files with 168 additions and 31 deletions
|
@ -62,7 +62,13 @@ export class CountAggField implements IESAggField {
|
|||
async createTooltipProperty(value: string | string[] | undefined): Promise<ITooltipProperty> {
|
||||
const indexPattern = await this._source.getIndexPattern();
|
||||
const tooltipProperty = new TooltipProperty(this.getName(), await this.getLabel(), value);
|
||||
return new ESAggTooltipProperty(tooltipProperty, indexPattern, this, this._getAggType());
|
||||
return new ESAggTooltipProperty(
|
||||
tooltipProperty,
|
||||
indexPattern,
|
||||
this,
|
||||
this._getAggType(),
|
||||
this._source.getApplyGlobalQuery()
|
||||
);
|
||||
}
|
||||
|
||||
getValueAggDsl(indexPattern: IndexPattern): unknown | null {
|
||||
|
|
|
@ -53,7 +53,12 @@ export class ESDocField extends AbstractField implements IField {
|
|||
async createTooltipProperty(value: string | string[] | undefined): Promise<ITooltipProperty> {
|
||||
const indexPattern = await this._source.getIndexPattern();
|
||||
const tooltipProperty = new TooltipProperty(this.getName(), await this.getLabel(), value);
|
||||
return new ESTooltipProperty(tooltipProperty, indexPattern, this as IField);
|
||||
return new ESTooltipProperty(
|
||||
tooltipProperty,
|
||||
indexPattern,
|
||||
this as IField,
|
||||
this._source.getApplyGlobalQuery()
|
||||
);
|
||||
}
|
||||
|
||||
async getDataType(): Promise<string> {
|
||||
|
|
|
@ -75,7 +75,6 @@ export interface IVectorSource extends ISource {
|
|||
defaultFields: Record<string, Record<string, string>>
|
||||
): Promise<void>;
|
||||
deleteFeature(featureId: string): Promise<void>;
|
||||
isFilterByMapBounds(): boolean;
|
||||
}
|
||||
|
||||
export class AbstractVectorSource extends AbstractSource implements IVectorSource {
|
||||
|
|
|
@ -18,13 +18,14 @@ export class ESAggTooltipProperty extends ESTooltipProperty {
|
|||
tooltipProperty: ITooltipProperty,
|
||||
indexPattern: IndexPattern,
|
||||
field: IField,
|
||||
aggType: AGG_TYPE
|
||||
aggType: AGG_TYPE,
|
||||
applyGlobalQuery: boolean
|
||||
) {
|
||||
super(tooltipProperty, indexPattern, field);
|
||||
super(tooltipProperty, indexPattern, field, applyGlobalQuery);
|
||||
this._aggType = aggType;
|
||||
}
|
||||
|
||||
isFilterable(): boolean {
|
||||
return this._aggType === AGG_TYPE.TERMS;
|
||||
return this._aggType === AGG_TYPE.TERMS ? super.isFilterable() : false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,9 @@ import { FIELD_ORIGIN } from '../../../common/constants';
|
|||
|
||||
class MockField extends AbstractField {}
|
||||
|
||||
const APPLY_GLOBAL_QUERY = true;
|
||||
const DO_NOT_APPLY_GLOBAL_QUERY = false;
|
||||
|
||||
const indexPatternField = {
|
||||
name: 'machine.os',
|
||||
type: 'string',
|
||||
|
@ -29,11 +32,33 @@ const featurePropertyField = new MockField({
|
|||
origin: FIELD_ORIGIN.SOURCE,
|
||||
});
|
||||
|
||||
const nonFilterableIndexPatternField = {
|
||||
name: 'location',
|
||||
type: 'geo_point',
|
||||
esTypes: ['geo_point'],
|
||||
count: 0,
|
||||
scripted: false,
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
readFromDocValues: false,
|
||||
} as IFieldType;
|
||||
|
||||
const nonFilterableFeaturePropertyField = new MockField({
|
||||
fieldName: 'location',
|
||||
origin: FIELD_ORIGIN.SOURCE,
|
||||
});
|
||||
|
||||
const indexPattern = {
|
||||
id: 'indexPatternId',
|
||||
fields: {
|
||||
getByName: (name: string): IFieldType | null => {
|
||||
return name === 'machine.os' ? indexPatternField : null;
|
||||
if (name === 'machine.os') {
|
||||
return indexPatternField;
|
||||
}
|
||||
if (name === 'location') {
|
||||
return nonFilterableIndexPatternField;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
},
|
||||
title: 'my index pattern',
|
||||
|
@ -52,7 +77,8 @@ describe('getESFilters', () => {
|
|||
'my value'
|
||||
),
|
||||
indexPattern,
|
||||
notFoundFeaturePropertyField
|
||||
notFoundFeaturePropertyField,
|
||||
APPLY_GLOBAL_QUERY
|
||||
);
|
||||
expect(await esTooltipProperty.getESFilters()).toEqual([]);
|
||||
});
|
||||
|
@ -65,7 +91,8 @@ describe('getESFilters', () => {
|
|||
'my value'
|
||||
),
|
||||
indexPattern,
|
||||
featurePropertyField
|
||||
featurePropertyField,
|
||||
APPLY_GLOBAL_QUERY
|
||||
);
|
||||
expect(await esTooltipProperty.getESFilters()).toEqual([
|
||||
{
|
||||
|
@ -89,7 +116,8 @@ describe('getESFilters', () => {
|
|||
undefined
|
||||
),
|
||||
indexPattern,
|
||||
featurePropertyField
|
||||
featurePropertyField,
|
||||
APPLY_GLOBAL_QUERY
|
||||
);
|
||||
expect(await esTooltipProperty.getESFilters()).toEqual([
|
||||
{
|
||||
|
@ -103,4 +131,62 @@ describe('getESFilters', () => {
|
|||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('Should return empty array when applyGlobalQuery is false', async () => {
|
||||
const esTooltipProperty = new ESTooltipProperty(
|
||||
new TooltipProperty(
|
||||
featurePropertyField.getName(),
|
||||
await featurePropertyField.getLabel(),
|
||||
'my value'
|
||||
),
|
||||
indexPattern,
|
||||
featurePropertyField,
|
||||
DO_NOT_APPLY_GLOBAL_QUERY
|
||||
);
|
||||
expect(await esTooltipProperty.getESFilters()).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isFilterable', () => {
|
||||
test('Should by true when field is filterable and apply global query is true', async () => {
|
||||
const esTooltipProperty = new ESTooltipProperty(
|
||||
new TooltipProperty(
|
||||
featurePropertyField.getName(),
|
||||
await featurePropertyField.getLabel(),
|
||||
'my value'
|
||||
),
|
||||
indexPattern,
|
||||
featurePropertyField,
|
||||
APPLY_GLOBAL_QUERY
|
||||
);
|
||||
expect(esTooltipProperty.isFilterable()).toBe(true);
|
||||
});
|
||||
|
||||
test('Should by false when field is not filterable and apply global query is true', async () => {
|
||||
const esTooltipProperty = new ESTooltipProperty(
|
||||
new TooltipProperty(
|
||||
nonFilterableFeaturePropertyField.getName(),
|
||||
await nonFilterableFeaturePropertyField.getLabel(),
|
||||
'my value'
|
||||
),
|
||||
indexPattern,
|
||||
nonFilterableFeaturePropertyField,
|
||||
APPLY_GLOBAL_QUERY
|
||||
);
|
||||
expect(esTooltipProperty.isFilterable()).toBe(false);
|
||||
});
|
||||
|
||||
test('Should by false when field is filterable and apply global query is false', async () => {
|
||||
const esTooltipProperty = new ESTooltipProperty(
|
||||
new TooltipProperty(
|
||||
featurePropertyField.getName(),
|
||||
await featurePropertyField.getLabel(),
|
||||
'my value'
|
||||
),
|
||||
indexPattern,
|
||||
featurePropertyField,
|
||||
DO_NOT_APPLY_GLOBAL_QUERY
|
||||
);
|
||||
expect(esTooltipProperty.isFilterable()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,18 +19,25 @@ export class ESTooltipProperty implements ITooltipProperty {
|
|||
private readonly _tooltipProperty: ITooltipProperty;
|
||||
private readonly _indexPattern: IndexPattern;
|
||||
private readonly _field: IField;
|
||||
private readonly _applyGlobalQuery: boolean;
|
||||
|
||||
constructor(tooltipProperty: ITooltipProperty, indexPattern: IndexPattern, field: IField) {
|
||||
constructor(
|
||||
tooltipProperty: ITooltipProperty,
|
||||
indexPattern: IndexPattern,
|
||||
field: IField,
|
||||
applyGlobalQuery: boolean
|
||||
) {
|
||||
this._tooltipProperty = tooltipProperty;
|
||||
this._indexPattern = indexPattern;
|
||||
this._field = field;
|
||||
this._applyGlobalQuery = applyGlobalQuery;
|
||||
}
|
||||
|
||||
getPropertyKey(): string {
|
||||
return this._tooltipProperty.getPropertyKey();
|
||||
}
|
||||
|
||||
getPropertyName(): string {
|
||||
getPropertyName() {
|
||||
return this._tooltipProperty.getPropertyName();
|
||||
}
|
||||
|
||||
|
@ -65,6 +72,10 @@ export class ESTooltipProperty implements ITooltipProperty {
|
|||
}
|
||||
|
||||
isFilterable(): boolean {
|
||||
if (!this._applyGlobalQuery) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const indexPatternField = this._getIndexPatternField();
|
||||
return (
|
||||
!!indexPatternField &&
|
||||
|
@ -76,6 +87,10 @@ export class ESTooltipProperty implements ITooltipProperty {
|
|||
}
|
||||
|
||||
async getESFilters(): Promise<Filter[]> {
|
||||
if (!this._applyGlobalQuery) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const indexPatternField = this._getIndexPatternField();
|
||||
if (!indexPatternField) {
|
||||
return [];
|
||||
|
|
|
@ -5,17 +5,20 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { ReactNode } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiIcon, EuiToolTip } from '@elastic/eui';
|
||||
import { ITooltipProperty } from './tooltip_property';
|
||||
import { InnerJoin } from '../joins/inner_join';
|
||||
import { Filter } from '../../../../../../src/plugins/data/public';
|
||||
|
||||
export class JoinTooltipProperty implements ITooltipProperty {
|
||||
private readonly _tooltipProperty: ITooltipProperty;
|
||||
private readonly _leftInnerJoins: InnerJoin[];
|
||||
private readonly _innerJoins: InnerJoin[];
|
||||
|
||||
constructor(tooltipProperty: ITooltipProperty, leftInnerJoins: InnerJoin[]) {
|
||||
constructor(tooltipProperty: ITooltipProperty, innerJoins: InnerJoin[]) {
|
||||
this._tooltipProperty = tooltipProperty;
|
||||
this._leftInnerJoins = leftInnerJoins;
|
||||
this._innerJoins = innerJoins;
|
||||
}
|
||||
|
||||
isFilterable(): boolean {
|
||||
|
@ -26,8 +29,28 @@ export class JoinTooltipProperty implements ITooltipProperty {
|
|||
return this._tooltipProperty.getPropertyKey();
|
||||
}
|
||||
|
||||
getPropertyName(): string {
|
||||
return this._tooltipProperty.getPropertyName();
|
||||
getPropertyName(): ReactNode {
|
||||
const content = i18n.translate('xpack.maps.tooltip.joinPropertyTooltipContent', {
|
||||
defaultMessage: `Shared key '{leftFieldName}' is joined with {rightSources}`,
|
||||
values: {
|
||||
leftFieldName: this._tooltipProperty.getPropertyName() as string,
|
||||
rightSources: this._innerJoins
|
||||
.map((innerJoin) => {
|
||||
const rightSource = innerJoin.getRightJoinSource();
|
||||
const termField = rightSource.getTermField();
|
||||
return `'${termField.getName()}'`;
|
||||
})
|
||||
.join(','),
|
||||
},
|
||||
});
|
||||
return (
|
||||
<>
|
||||
{this._tooltipProperty.getPropertyName()}
|
||||
<EuiToolTip position="bottom" content={content}>
|
||||
<EuiIcon type="link" />
|
||||
</EuiToolTip>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
getRawValue(): string | string[] | undefined {
|
||||
|
@ -40,13 +63,11 @@ export class JoinTooltipProperty implements ITooltipProperty {
|
|||
|
||||
async getESFilters(): Promise<Filter[]> {
|
||||
const esFilters = [];
|
||||
if (this._tooltipProperty.isFilterable()) {
|
||||
const filters = await this._tooltipProperty.getESFilters();
|
||||
esFilters.push(...filters);
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._leftInnerJoins.length; i++) {
|
||||
const rightSource = this._leftInnerJoins[i].getRightJoinSource();
|
||||
// only create filters for right sources.
|
||||
// do not create filters for left source.
|
||||
for (let i = 0; i < this._innerJoins.length; i++) {
|
||||
const rightSource = this._innerJoins[i].getRightJoinSource();
|
||||
const termField = rightSource.getTermField();
|
||||
try {
|
||||
const esTooltipProperty = await termField.createTooltipProperty(
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { ReactNode } from 'react';
|
||||
import { GeoJsonProperties, Geometry } from 'geojson';
|
||||
import { Filter } from 'src/plugins/data/public';
|
||||
import { ActionExecutionContext, Action } from 'src/plugins/ui_actions/public';
|
||||
|
@ -14,7 +15,7 @@ import type { TooltipFeature } from '../../../../../plugins/maps/common/descript
|
|||
|
||||
export interface ITooltipProperty {
|
||||
getPropertyKey(): string;
|
||||
getPropertyName(): string;
|
||||
getPropertyName(): string | ReactNode;
|
||||
getHtmlDisplayValue(): string;
|
||||
getRawValue(): string | string[] | undefined;
|
||||
isFilterable(): boolean;
|
||||
|
|
|
@ -31,6 +31,10 @@ class MockTooltipProperty {
|
|||
return this._value;
|
||||
}
|
||||
|
||||
getPropertyKey() {
|
||||
return this._key;
|
||||
}
|
||||
|
||||
getPropertyName() {
|
||||
return this._key;
|
||||
}
|
||||
|
|
|
@ -329,10 +329,11 @@ export class FeatureProperties extends Component<Props, State> {
|
|||
}
|
||||
|
||||
const rows = this.state.properties.map((tooltipProperty) => {
|
||||
const label = tooltipProperty.getPropertyName();
|
||||
return (
|
||||
<tr key={label} className="mapFeatureTooltip_row">
|
||||
<td className="eui-textOverflowWrap mapFeatureTooltip__propertyLabel">{label}</td>
|
||||
<tr key={tooltipProperty.getPropertyKey()} className="mapFeatureTooltip_row">
|
||||
<td className="eui-textOverflowWrap mapFeatureTooltip__propertyLabel">
|
||||
{tooltipProperty.getPropertyName()}
|
||||
</td>
|
||||
<td
|
||||
className="eui-textOverflowWrap"
|
||||
/*
|
||||
|
|
|
@ -53,11 +53,9 @@ export default function ({ getPageObjects, getService }) {
|
|||
|
||||
it('should create filters when create filter button is clicked', async () => {
|
||||
await testSubjects.click('mapTooltipCreateFilterButton');
|
||||
await testSubjects.click('applyFiltersPopoverButton');
|
||||
|
||||
// TODO: Fix me #64861
|
||||
// const hasSourceFilter = await filterBar.hasFilter('name', 'charlie');
|
||||
// expect(hasSourceFilter).to.be(true);
|
||||
const numFilters = await filterBar.getFilterCount();
|
||||
expect(numFilters).to.be(1);
|
||||
|
||||
const hasJoinFilter = await filterBar.hasFilter('runtime_shape_name', 'charlie');
|
||||
expect(hasJoinFilter).to.be(true);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue