[Maps] fix Filters applied to map visualization not preserved when added to dashboard (#138188)

* [Maps] fix Tool tip with large field list exceeds browser screen and cannot be accessed or dismissed

* add min-width to mapFeatureTooltip__propertyLabel

* [Maps] fix Filters applied to map visualization not preserved when added to dashboard

* clean up

* [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix'

* clean-up

* publish query and filter to container

* [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix'

* fix checks

* tslint and add to bounds filter

* functional test

* review feedback

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2022-08-16 14:09:38 -06:00 committed by GitHub
parent cb8cf84720
commit 7303ef8991
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 111 additions and 15 deletions

View file

@ -21,8 +21,12 @@ export type Timeslice = {
export type DataFilters = {
buffer?: MapExtent; // extent with additional buffer
extent?: MapExtent; // map viewport
filters: Filter[];
query?: Query;
filters: Filter[]; // search bar filters
query?: Query; // search bar query
embeddableSearchContext?: {
query?: Query;
filters: Filter[];
};
searchSessionId?: string;
timeFilters: TimeRange;
timeslice?: Timeslice;

View file

@ -30,6 +30,7 @@ export const SET_LAYER_STYLE_META = 'SET_LAYER_STYLE_META';
export const UPDATE_SOURCE_PROP = 'UPDATE_SOURCE_PROP';
export const SET_MOUSE_COORDINATES = 'SET_MOUSE_COORDINATES';
export const CLEAR_MOUSE_COORDINATES = 'CLEAR_MOUSE_COORDINATES';
export const SET_EMBEDDABLE_SEARCH_CONTEXT = 'SET_EMBEDDABLE_SEARCH_CONTEXT';
export const SET_GOTO = 'SET_GOTO';
export const CLEAR_GOTO = 'CLEAR_GOTO';
export const TRACK_CURRENT_LAYER_STATE = 'TRACK_CURRENT_LAYER_STATE';

View file

@ -43,6 +43,7 @@ import {
MAP_EXTENT_CHANGED,
MAP_READY,
ROLLBACK_MAP_SETTINGS,
SET_EMBEDDABLE_SEARCH_CONTEXT,
SET_GOTO,
SET_MAP_INIT_ERROR,
SET_MAP_SETTINGS,
@ -340,6 +341,19 @@ export function setQuery({
};
}
export function setEmbeddableSearchContext({
query,
filters,
}: {
filters: Filter[];
query?: Query;
}) {
return {
type: SET_EMBEDDABLE_SEARCH_CONTEXT,
embeddableSearchContext: { filters, query },
};
}
export function updateDrawState(drawState: DrawState | null) {
return (dispatch: Dispatch) => {
if (drawState !== null) {

View file

@ -39,6 +39,7 @@ export async function syncBoundsData({
query: dataFilters.query,
timeFilters: dataFilters.timeFilters,
timeslice: dataFilters.timeslice,
embeddableSearchContext: dataFilters.embeddableSearchContext,
filters: dataFilters.filters,
joinKeyFilter: dataFilters.joinKeyFilter,
applyGlobalQuery: source.getApplyGlobalQuery(),

View file

@ -262,12 +262,27 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource
searchSource.setField('query', searchFilters.query);
}
const parents = [];
if (searchFilters.sourceQuery && !isFeatureEditorOpenForLayer) {
const layerSearchSource = searchService.searchSource.createEmpty();
layerSearchSource.setField('index', indexPattern);
layerSearchSource.setField('query', searchFilters.sourceQuery);
searchSource.setParent(layerSearchSource);
parents.push(layerSearchSource);
}
if (searchFilters.embeddableSearchContext && !isFeatureEditorOpenForLayer) {
const embeddableSearchSource = searchService.searchSource.createEmpty();
embeddableSearchSource.setField('index', indexPattern);
embeddableSearchSource.setField('query', searchFilters.embeddableSearchContext.query);
embeddableSearchSource.setField('filter', searchFilters.embeddableSearchContext.filters);
parents.push(embeddableSearchSource);
}
if (parents.length === 1) {
searchSource.setParent(parents[0]);
} else if (parents.length === 2) {
parents[1].setParent(parents[0]);
searchSource.setParent(parents[1]);
}
return searchSource;

View file

@ -53,6 +53,10 @@ export interface BoundsRequestMeta {
applyGlobalTime: boolean;
filters: Filter[];
query?: Query;
embeddableSearchContext?: {
query?: Query;
filters: Filter[];
};
sourceQuery?: Query;
timeFilters: TimeRange;
timeslice?: Timeslice;

View file

@ -36,6 +36,7 @@ import {
setReadOnly,
updateLayerById,
setGotoWithCenter,
setEmbeddableSearchContext,
} from '../actions';
import { getIsLayerTOCOpen, getOpenTOCDetails } from '../selectors/ui_selectors';
import {
@ -48,6 +49,7 @@ import {
import {
areLayersLoaded,
getGeoFieldNames,
getEmbeddableSearchContext,
getLayerList,
getGoto,
getMapCenter,
@ -194,6 +196,21 @@ export class MapEmbeddable
forceRefresh: false,
});
const mapStateJSON = this._savedMap.getAttributes().mapStateJSON;
if (mapStateJSON) {
try {
const mapState = JSON.parse(mapStateJSON);
store.dispatch(
setEmbeddableSearchContext({
filters: mapState.filters ? mapState.filters : [],
query: mapState.query,
})
);
} catch (e) {
// ignore malformed mapStateJSON, not a critical error for viewing map - map will just use defaults
}
}
this._unsubscribeFromStore = store.subscribe(() => {
this._handleStoreChanges();
});
@ -249,20 +266,18 @@ export class MapEmbeddable
return this._isInitialized ? this._savedMap.getAttributes().description : '';
}
/**
* TODO: Implement this function once https://github.com/elastic/kibana/issues/91282 is resolved
* @returns []
*/
public async getFilters() {
return [];
const embeddableSearchContext = getEmbeddableSearchContext(
this._savedMap.getStore().getState()
);
return embeddableSearchContext ? embeddableSearchContext.filters : [];
}
/**
* TODO: Implement this function once https://github.com/elastic/kibana/issues/91282 is resolved
* @returns undefined
*/
public async getQuery() {
return undefined;
const embeddableSearchContext = getEmbeddableSearchContext(
this._savedMap.getStore().getState()
);
return embeddableSearchContext?.query;
}
public supportedTriggers(): string[] {

View file

@ -21,6 +21,7 @@ import {
MAP_EXTENT_CHANGED,
MAP_READY,
MAP_DESTROYED,
SET_EMBEDDABLE_SEARCH_CONTEXT,
SET_QUERY,
UPDATE_LAYER,
UPDATE_LAYER_PROP,
@ -313,6 +314,14 @@ export function map(state: MapState = DEFAULT_MAP_STATE, action: Record<string,
visible: !action.hiddenLayerIds.includes(layer.id),
})),
};
case SET_EMBEDDABLE_SEARCH_CONTEXT:
return {
...state,
mapState: {
...state.mapState,
embeddableSearchContext: action.embeddableSearchContext,
},
};
default:
return state;
}

View file

@ -41,6 +41,10 @@ export type MapContext = Partial<MapViewContext> & {
timeslice?: Timeslice;
query?: Query;
filters: Filter[];
embeddableSearchContext?: {
query?: Query;
filters: Filter[];
};
drawState?: DrawState;
editState?: EditState;
searchSessionId?: string;

View file

@ -57,6 +57,7 @@ describe('getDataFilters', () => {
const timeFilters = { to: '2001-01-01', from: '2001-12-31' };
const timeslice = undefined;
const query = undefined;
const embeddableSearchContext = undefined;
const filters: Filter[] = [];
const searchSessionId = '12345';
const searchSessionMapBuffer = {
@ -76,6 +77,7 @@ describe('getDataFilters', () => {
timeslice,
query,
filters,
embeddableSearchContext,
searchSessionId,
searchSessionMapBuffer,
isReadOnly
@ -92,6 +94,7 @@ describe('getDataFilters', () => {
timeslice,
query,
filters,
embeddableSearchContext,
searchSessionId,
undefined,
isReadOnly

View file

@ -198,6 +198,9 @@ export const getQuery = ({ map }: MapStoreState): Query | undefined => map.mapSt
export const getFilters = ({ map }: MapStoreState): Filter[] => map.mapState.filters;
export const getEmbeddableSearchContext = ({ map }: MapStoreState) =>
map.mapState.embeddableSearchContext;
export const getSearchSessionId = ({ map }: MapStoreState): string | undefined =>
map.mapState.searchSessionId;
@ -239,6 +242,7 @@ export const getDataFilters = createSelector(
getTimeslice,
getQuery,
getFilters,
getEmbeddableSearchContext,
getSearchSessionId,
getSearchSessionMapBuffer,
getIsReadOnly,
@ -250,6 +254,7 @@ export const getDataFilters = createSelector(
timeslice,
query,
filters,
embeddableSearchContext,
searchSessionId,
searchSessionMapBuffer,
isReadOnly
@ -262,6 +267,7 @@ export const getDataFilters = createSelector(
timeslice,
query,
filters,
embeddableSearchContext,
searchSessionId,
isReadOnly,
};

View file

@ -17,6 +17,7 @@ export default function ({ getPageObjects, getService }) {
const browser = getService('browser');
const retry = getService('retry');
const security = getService('security');
const testSubjects = getService('testSubjects');
describe('embed in dashboard', () => {
before(async () => {
@ -25,7 +26,8 @@ export default function ({ getPageObjects, getService }) {
'test_logstash_reader',
'geoshape_data_reader',
'meta_for_geoshape_data_reader',
'global_dashboard_read',
'global_dashboard_all',
'global_maps_all',
],
{ skipBrowserRefresh: true }
);
@ -121,6 +123,24 @@ export default function ({ getPageObjects, getService }) {
expect(joinResponse.aggregations.join.buckets.length).to.equal(1);
});
it('should apply embeddable query and filters to panel', async () => {
// clear filters from previous test
await filterBar.removeAllFilters();
await PageObjects.dashboard.switchToEditMode();
await dashboardPanelActions.editPanelByTitle('geo grid vector grid example');
await PageObjects.maps.waitForLayersToLoad();
await filterBar.addFilter('machine.os', 'is', 'ios');
await PageObjects.maps.waitForLayersToLoad();
await testSubjects.click('mapSaveAndReturnButton');
const { rawResponse: gridResponse } = await PageObjects.maps.getResponseFromDashboardPanel(
'geo grid vector grid example'
);
expect(gridResponse.aggregations.gridSplit.buckets.length).to.equal(2);
});
it('should re-fetch query when "refresh" is clicked', async () => {
await dashboardPanelActions.openInspectorByTitle('geo grid vector grid example');
const beforeQueryRefreshTimestamp = await getRequestTimestamp();