Skip to content

Commit

Permalink
[Maps] filter dashboard by map extent (elastic#99860) (elastic#100690)
Browse files Browse the repository at this point in the history
* [Maps] filter dashboard by map extent

* clean up

* remove warning from filter pill

* tslint

* API doc updates, i18n fixes, tslint

* only show context menu option in edit mode

* add functional test

* review feedback

* do not use search session when filtering by map bounds

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

Co-authored-by: Nathan Reese <reese.nathan@gmail.com>
  • Loading branch information
kibanamachine and nreese authored May 26, 2021
1 parent a4921f3 commit 2028d54
Show file tree
Hide file tree
Showing 20 changed files with 394 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) &gt; [ApplyGlobalFilterActionContext](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md) &gt; [controlledBy](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.controlledby.md)

## ApplyGlobalFilterActionContext.controlledBy property

<b>Signature:</b>

```typescript
controlledBy?: string;
```
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface ApplyGlobalFilterActionContext

| Property | Type | Description |
| --- | --- | --- |
| [controlledBy](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.controlledby.md) | <code>string</code> | |
| [embeddable](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.embeddable.md) | <code>unknown</code> | |
| [filters](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.filters.md) | <code>Filter[]</code> | |
| [timeFieldName](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.timefieldname.md) | <code>string</code> | |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ esFilters: {
disabled: boolean;
controlledBy?: string | undefined;
index?: string | undefined;
isMultiIndex?: boolean | undefined;
type?: string | undefined;
key?: string | undefined;
params?: any;
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data/common/es_query/filters/meta_filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export type FilterMeta = {
controlledBy?: string;
// index and type are optional only because when you create a new filter, there are no defaults
index?: string;
isMultiIndex?: boolean;
type?: string;
key?: string;
params?: any;
Expand Down
14 changes: 13 additions & 1 deletion src/plugins/data/public/actions/apply_filter_action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export interface ApplyGlobalFilterActionContext {
// Need to make this unknown to prevent circular dependencies.
// Apps using this property will need to cast to `IEmbeddable`.
embeddable?: unknown;
// controlledBy is an optional key in filter.meta that identifies the owner of a filter
// Pass controlledBy to cleanup an existing filter(s) owned by embeddable prior to adding new filters
controlledBy?: string;
}

async function isCompatible(context: ApplyGlobalFilterActionContext) {
Expand All @@ -42,7 +45,7 @@ export function createFilterAction(
});
},
isCompatible,
execute: async ({ filters, timeFieldName }: ApplyGlobalFilterActionContext) => {
execute: async ({ filters, timeFieldName, controlledBy }: ApplyGlobalFilterActionContext) => {
if (!filters) {
throw new Error('Applying a filter requires a filter');
}
Expand Down Expand Up @@ -85,6 +88,15 @@ export function createFilterAction(
selectedFilters = await filterSelectionPromise;
}

// remove existing filters for control prior to adding new filtes for control
if (controlledBy) {
filterManager.getFilters().forEach((filter) => {
if (filter.meta.controlledBy === controlledBy) {
filterManager.removeFilter(filter);
}
});
}

if (timeFieldName) {
const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter(
timeFieldName,
Expand Down
7 changes: 5 additions & 2 deletions src/plugins/data/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,8 @@ export const APPLY_FILTER_TRIGGER = "FILTER_TRIGGER";
//
// @public (undocumented)
export interface ApplyGlobalFilterActionContext {
// (undocumented)
controlledBy?: string;
// (undocumented)
embeddable?: unknown;
// (undocumented)
Expand Down Expand Up @@ -763,6 +765,7 @@ export const esFilters: {
disabled: boolean;
controlledBy?: string | undefined;
index?: string | undefined;
isMultiIndex?: boolean | undefined;
type?: string | undefined;
key?: string | undefined;
params?: any;
Expand Down Expand Up @@ -2699,8 +2702,8 @@ export interface WaitUntilNextSessionCompletesOptions {
// src/plugins/data/common/es_query/filters/exists_filter.ts:19:3 - (ae-forgotten-export) The symbol "ExistsFilterMeta" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/es_query/filters/exists_filter.ts:20:3 - (ae-forgotten-export) The symbol "FilterExistsProperty" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/es_query/filters/match_all_filter.ts:17:3 - (ae-forgotten-export) The symbol "MatchAllFilterMeta" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/es_query/filters/meta_filter.ts:42:3 - (ae-forgotten-export) The symbol "FilterState" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/es_query/filters/meta_filter.ts:43:3 - (ae-forgotten-export) The symbol "FilterMeta" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/es_query/filters/meta_filter.ts:43:3 - (ae-forgotten-export) The symbol "FilterState" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/es_query/filters/meta_filter.ts:44:3 - (ae-forgotten-export) The symbol "FilterMeta" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/es_query/filters/phrase_filter.ts:22:3 - (ae-forgotten-export) The symbol "PhraseFilterMeta" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/es_query/filters/phrases_filter.ts:20:3 - (ae-forgotten-export) The symbol "PhrasesFilterMeta" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:65:5 - (ae-forgotten-export) The symbol "FormatFieldFn" needs to be exported by the entry point index.d.ts
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/data/public/ui/filter_bar/filter_item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ export function FilterItem(props: FilterItemProps) {
message: '',
status: FILTER_ITEM_OK,
};

if (filter.meta?.isMultiIndex) {
return label;
}

if (indexPatternExists === false) {
label.status = FILTER_ITEM_ERROR;
label.title = props.intl.formatMessage({
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/data/server/server.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1519,8 +1519,8 @@ export function usageProvider(core: CoreSetup_2): SearchUsage;

// Warnings were encountered during analysis:
//
// src/plugins/data/common/es_query/filters/meta_filter.ts:42:3 - (ae-forgotten-export) The symbol "FilterState" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/es_query/filters/meta_filter.ts:43:3 - (ae-forgotten-export) The symbol "FilterMeta" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/es_query/filters/meta_filter.ts:43:3 - (ae-forgotten-export) The symbol "FilterState" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/es_query/filters/meta_filter.ts:44:3 - (ae-forgotten-export) The symbol "FilterMeta" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:52:45 - (ae-forgotten-export) The symbol "IndexPatternFieldMap" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:65:5 - (ae-forgotten-export) The symbol "FormatFieldFn" needs to be exported by the entry point index.d.ts
// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:138:7 - (ae-forgotten-export) The symbol "FieldAttrSet" needs to be exported by the entry point index.d.ts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ describe('createExtentFilter', () => {
minLat: 35,
minLon: -89,
};
const filter = createExtentFilter(mapExtent, geoFieldName);
const filter = createExtentFilter(mapExtent, [geoFieldName]);
expect(filter.geo_bounding_box).toEqual({
location: {
top_left: [-89, 39],
Expand All @@ -412,7 +412,7 @@ describe('createExtentFilter', () => {
minLat: -100,
minLon: -190,
};
const filter = createExtentFilter(mapExtent, geoFieldName);
const filter = createExtentFilter(mapExtent, [geoFieldName]);
expect(filter.geo_bounding_box).toEqual({
location: {
top_left: [-180, 89],
Expand All @@ -428,7 +428,7 @@ describe('createExtentFilter', () => {
minLat: 35,
minLon: 100,
};
const filter = createExtentFilter(mapExtent, geoFieldName);
const filter = createExtentFilter(mapExtent, [geoFieldName]);
const leftLon = filter.geo_bounding_box.location.top_left[0];
const rightLon = filter.geo_bounding_box.location.bottom_right[0];
expect(leftLon).toBeGreaterThan(rightLon);
Expand All @@ -447,7 +447,7 @@ describe('createExtentFilter', () => {
minLat: 35,
minLon: -200,
};
const filter = createExtentFilter(mapExtent, geoFieldName);
const filter = createExtentFilter(mapExtent, [geoFieldName]);
const leftLon = filter.geo_bounding_box.location.top_left[0];
const rightLon = filter.geo_bounding_box.location.bottom_right[0];
expect(leftLon).toBeGreaterThan(rightLon);
Expand All @@ -466,7 +466,7 @@ describe('createExtentFilter', () => {
minLat: 35,
minLon: -191,
};
const filter = createExtentFilter(mapExtent, geoFieldName);
const filter = createExtentFilter(mapExtent, [geoFieldName]);
expect(filter.geo_bounding_box).toEqual({
location: {
top_left: [-180, 39],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,18 +349,49 @@ export function makeESBbox({ maxLat, maxLon, minLat, minLon }: MapExtent): ESBBo
return esBbox;
}

export function createExtentFilter(mapExtent: MapExtent, geoFieldName: string): GeoFilter {
return {
geo_bounding_box: {
[geoFieldName]: makeESBbox(mapExtent),
},
meta: {
alias: null,
disabled: false,
negate: false,
key: geoFieldName,
},
};
export function createExtentFilter(mapExtent: MapExtent, geoFieldNames: string[]): GeoFilter {
const esBbox = makeESBbox(mapExtent);
return geoFieldNames.length === 1
? {
geo_bounding_box: {
[geoFieldNames[0]]: esBbox,
},
meta: {
alias: null,
disabled: false,
negate: false,
key: geoFieldNames[0],
},
}
: {
query: {
bool: {
should: geoFieldNames.map((geoFieldName) => {
return {
bool: {
must: [
{
exists: {
field: geoFieldName,
},
},
{
geo_bounding_box: {
[geoFieldName]: esBbox,
},
},
],
},
};
}),
},
},
meta: {
alias: null,
disabled: false,
negate: false,
},
};
}

export function createSpatialFilterWithGeometry({
Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/maps/public/classes/layers/layer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { DataRequestContext } from '../../actions';
import { IStyle } from '../styles/style';
import { getJoinAggKey } from '../../../common/get_agg_key';
import { LICENSED_FEATURES } from '../../licensed_features';
import { IESSource } from '../sources/es_source';

export interface ILayer {
getBounds(dataRequestContext: DataRequestContext): Promise<MapExtent | null>;
Expand Down Expand Up @@ -101,6 +102,7 @@ export interface ILayer {
getLicensedFeatures(): Promise<LICENSED_FEATURES[]>;
getCustomIconAndTooltipContent(): CustomIconAndTooltipContent;
getDescriptor(): LayerDescriptor;
getGeoFieldNames(): string[];
}

export type CustomIconAndTooltipContent = {
Expand Down Expand Up @@ -513,4 +515,9 @@ export class AbstractLayer implements ILayer {
async getLicensedFeatures(): Promise<LICENSED_FEATURES[]> {
return [];
}

getGeoFieldNames(): string[] {
const source = this.getSource();
return source.isESSource() ? [(source as IESSource).getGeoFieldName()] : [];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource
typeof searchFilters.geogridPrecision === 'number'
? expandToTileBoundaries(searchFilters.buffer, searchFilters.geogridPrecision)
: searchFilters.buffer;
const extentFilter = createExtentFilter(buffer, geoField.name);
const extentFilter = createExtentFilter(buffer, [geoField.name]);

allFilters.push(extentFilter);
}
Expand Down
Loading

0 comments on commit 2028d54

Please sign in to comment.