Skip to content

Commit

Permalink
[7.15] [Lens] fix filters not being cleaned
Browse files Browse the repository at this point in the history
  • Loading branch information
mbondyra committed Oct 15, 2021
1 parent d18687f commit 42586cc
Show file tree
Hide file tree
Showing 9 changed files with 360 additions and 31 deletions.
15 changes: 7 additions & 8 deletions x-pack/plugins/lens/public/app_plugin/mounter.tsx
Expand Up @@ -167,13 +167,6 @@ export async function mountApp(
? historyLocationState.payload
: undefined;

// Clear app-specific filters when navigating to Lens. Necessary because Lens
// can be loaded without a full page refresh. If the user navigates to Lens from Discover
// we keep the filters
if (!initialContext) {
data.query.filterManager.setAppFilters([]);
}

if (embeddableEditorIncomingState?.searchSessionId) {
data.search.session.continue(embeddableEditorIncomingState.searchSessionId);
}
Expand Down Expand Up @@ -202,7 +195,13 @@ export async function mountApp(
trackUiEvent('loaded');
const initialInput = getInitialInput(props.id, props.editByValue);

lensStore.dispatch(loadInitial({ redirectCallback, initialInput, emptyState }));
// Clear app-specific filters when navigating to Lens. Necessary because Lens
// can be loaded without a full page refresh. If the user navigates to Lens from Discover
// we keep the filters
if (!initialContext) {
data.query.filterManager.setAppFilters([]);
}
lensStore.dispatch(loadInitial({ redirectCallback, initialInput }));

return (
<Provider store={lensStore}>
Expand Down
Expand Up @@ -23,8 +23,7 @@ export const initMiddleware = (storeDeps: LensStoreDeps) => (store: MiddlewareAP
store,
storeDeps,
action.payload.redirectCallback,
action.payload.initialInput,
action.payload.emptyState
action.payload.initialInput
);
} else if (lensSlice.actions.navigateAway.match(action)) {
return unsubscribeFromExternalContext();
Expand Down
Expand Up @@ -15,8 +15,6 @@ import {
import { act } from 'react-dom/test-utils';
import { loadInitial } from './load_initial';
import { LensEmbeddableInput } from '../../embeddable';
import { getPreloadedState } from '../lens_slice';
import { LensAppState } from '..';

const defaultSavedObjectId = '1234';
const preloadedState = {
Expand Down Expand Up @@ -167,10 +165,9 @@ describe('Mounter', () => {
}),
});

const emptyState = getPreloadedState(storeDeps) as LensAppState;
services.attributeService.unwrapAttributes = jest.fn();
await act(async () => {
await loadInitial(lensStore, storeDeps, jest.fn(), undefined, emptyState);
await loadInitial(lensStore, storeDeps, jest.fn(), undefined);
});

expect(lensStore.getState()).toEqual({
Expand Down
Expand Up @@ -6,13 +6,13 @@
*/

import { MiddlewareAPI } from '@reduxjs/toolkit';
import { isEqual } from 'lodash';
import { i18n } from '@kbn/i18n';
import { LensAppState, setState } from '..';
import { setState } from '..';
import { updateLayer, updateVisualizationState, LensStoreDeps } from '..';
import { LensEmbeddableInput, LensByReferenceInput } from '../../embeddable/embeddable';
import { getInitialDatasourceId } from '../../utils';
import { initializeDatasources } from '../../editor_frame_service/editor_frame';
import { getPreloadedState } from '../lens_slice';
import { generateId } from '../../id_generator';
import {
getVisualizeFieldSuggestions,
Expand Down Expand Up @@ -55,17 +55,23 @@ export const getPersisted = async ({

export function loadInitial(
store: MiddlewareAPI,
{
storeDeps: LensStoreDeps,
redirectCallback: (savedObjectId?: string) => void,
initialInput?: LensEmbeddableInput
) {
const {
lensServices,
datasourceMap,
visualizationMap,
embeddableEditorIncomingState,
initialContext,
}: LensStoreDeps,
redirectCallback: (savedObjectId?: string) => void,
initialInput?: LensEmbeddableInput,
emptyState?: LensAppState
) {
visualizationMap,
} = storeDeps;
const {
resolvedDateRange,
searchSessionId,
isLinkedToOriginatingApp,
...emptyState
} = getPreloadedState(storeDeps);
const { getState, dispatch } = store;
const { attributeService, notifications, data, dashboardFeatureFlag } = lensServices;
const { persistedDoc } = getState().lens;
Expand Down Expand Up @@ -115,11 +121,11 @@ export function loadInitial(
switchToSuggestion(dispatch, selectedSuggestion, 'SWITCH_VISUALIZATION');
}
}

const activeDatasourceId = getInitialDatasourceId(datasourceMap);
const visualization = getState().lens.visualization;
const activeVisualization =
visualization.activeId && visualizationMap[visualization.activeId];

if (visualization.state === null && activeVisualization) {
const newLayerId = generateId();

Expand Down Expand Up @@ -158,10 +164,9 @@ export function loadInitial(
initialInput.savedObjectId
);
}
const filters = injectFilterReferences(doc.state.filters, doc.references);
// Don't overwrite any pinned filters
data.query.filterManager.setAppFilters(
injectFilterReferences(doc.state.filters, doc.references)
);
data.query.filterManager.setAppFilters(filters);

const docDatasourceStates = Object.entries(doc.state.datasourceStates).reduce(
(stateMap, [datasourceId, datasourceState]) => ({
Expand Down Expand Up @@ -190,6 +195,8 @@ export function loadInitial(

dispatch(
setState({
isSaveable: true,
filters,
query: doc.state.query,
searchSessionId:
dashboardFeatureFlag.allowByValueEmbeddables &&
Expand All @@ -198,7 +205,7 @@ export function loadInitial(
currentSessionId
? currentSessionId
: data.search.session.start(),
...(!isEqual(persistedDoc, doc) ? { persistedDoc: doc } : null),
persistedDoc: doc,
activeDatasourceId,
visualization: {
activeId: doc.visualizationType,
Expand Down
5 changes: 3 additions & 2 deletions x-pack/plugins/lens/public/state_management/lens_slice.ts
Expand Up @@ -48,9 +48,11 @@ export const getPreloadedState = ({
const state = {
...initialState,
isLoading: true,
query: data.query.queryString.getQuery(),
// Do not use app-specific filters from previous app,
// only if Lens was opened with the intention to visualize a field (e.g. coming from Discover)
query: !initialContext
? data.query.queryString.getDefaultQuery()
: data.query.queryString.getQuery(),
filters: !initialContext
? data.query.filterManager.getGlobalFilters()
: data.query.filterManager.getFilters(),
Expand Down Expand Up @@ -300,7 +302,6 @@ export const lensSlice = createSlice({
payload: PayloadAction<{
initialInput?: LensEmbeddableInput;
redirectCallback: (savedObjectId?: string) => void;
emptyState: LensAppState;
}>
) => state,
},
Expand Down
7 changes: 7 additions & 0 deletions x-pack/test/functional/apps/lens/index.ts
Expand Up @@ -11,18 +11,25 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) {
const browser = getService('browser');
const log = getService('log');
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');

describe('lens app', () => {
before(async () => {
log.debug('Starting lens before method');
await browser.setWindowSize(1280, 800);
await esArchiver.load('x-pack/test/functional/es_archives/logstash_functional');
await esArchiver.load('x-pack/test/functional/es_archives/lens/basic');
await kibanaServer.importExport.load(
'x-pack/test/functional/fixtures/kbn_archiver/lens/default'
);
});

after(async () => {
await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional');
await esArchiver.unload('x-pack/test/functional/es_archives/lens/basic');
await kibanaServer.importExport.unload(
'x-pack/test/functional/fixtures/kbn_archiver/lens/default'
);
});

describe('', function () {
Expand Down
127 changes: 126 additions & 1 deletion x-pack/test/functional/apps/lens/persistent_context.ts
Expand Up @@ -9,11 +9,20 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';

export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['visualize', 'lens', 'header', 'timePicker']);
const PageObjects = getPageObjects([
'visualize',
'lens',
'header',
'timePicker',
'common',
'navigationalSearch',
]);
const browser = getService('browser');
const filterBar = getService('filterBar');
const appsMenu = getService('appsMenu');
const security = getService('security');
const listingTable = getService('listingTable');
const queryBar = getService('queryBar');

describe('lens query context', () => {
before(async () => {
Expand All @@ -27,6 +36,122 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await security.testUser.restoreDefaults();
});

describe('Navigation search', () => {
describe('when opening from empty visualization to existing one', () => {
before(async () => {
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickVisType('lens');
await PageObjects.lens.goToTimeRange();
await PageObjects.navigationalSearch.focus();
await PageObjects.navigationalSearch.searchFor('type:lens lnsTableVis');
await PageObjects.navigationalSearch.clickOnOption(0);
await PageObjects.lens.waitForWorkspaceWithVisualization();
});
it('filters, time and query reflect the visualization state', async () => {
expect(await PageObjects.lens.getDatatableHeaderText(1)).to.equal(
'404 › Median of bytes'
);
expect(await PageObjects.lens.getDatatableHeaderText(2)).to.equal(
'503 › Median of bytes'
);
expect(await PageObjects.lens.getDatatableCellText(0, 0)).to.eql('TG');
expect(await PageObjects.lens.getDatatableCellText(0, 1)).to.eql('9,931');
});
it('preserves time range', async () => {
const timePickerValues = await PageObjects.timePicker.getTimeConfigAsAbsoluteTimes();
expect(timePickerValues.start).to.eql(PageObjects.timePicker.defaultStartTime);
expect(timePickerValues.end).to.eql(PageObjects.timePicker.defaultEndTime);
// data is correct and top nav is correct
});
it('loads filters', async () => {
const filterCount = await filterBar.getFilterCount();
expect(filterCount).to.equal(1);
});
it('loads query', async () => {
const query = await queryBar.getQueryString();
expect(query).to.equal('extension.raw : "jpg" or extension.raw : "gif" ');
});
});
describe('when opening from existing visualization to empty one', () => {
before(async () => {
await PageObjects.visualize.gotoVisualizationLandingPage();
await listingTable.searchForItemWithName('lnsTableVis');
await PageObjects.lens.clickVisualizeListItemTitle('lnsTableVis');
await PageObjects.lens.goToTimeRange();
await PageObjects.navigationalSearch.focus();
await PageObjects.navigationalSearch.searchFor('type:application lens');
await PageObjects.navigationalSearch.clickOnOption(0);
await PageObjects.lens.waitForEmptyWorkspace();
await PageObjects.lens.switchToVisualization('lnsMetric');
await PageObjects.lens.dragFieldToWorkspace('@timestamp');
});
it('preserves time range', async () => {
// fill the navigation search and select empty
// see the time
const timePickerValues = await PageObjects.timePicker.getTimeConfigAsAbsoluteTimes();
expect(timePickerValues.start).to.eql(PageObjects.timePicker.defaultStartTime);
expect(timePickerValues.end).to.eql(PageObjects.timePicker.defaultEndTime);
});
it('cleans filters', async () => {
const filterCount = await filterBar.getFilterCount();
expect(filterCount).to.equal(0);
});
it('cleans query', async () => {
const query = await queryBar.getQueryString();
expect(query).to.equal('');
});
it('filters, time and query reflect the visualization state', async () => {
await PageObjects.lens.assertMetric('Unique count of @timestamp', '14,181');
});
});
});

describe('Switching in Visualize App', () => {
it('when moving from existing to empty workspace, preserves time range, cleans filters and query', async () => {
// go to existing vis
await PageObjects.visualize.gotoVisualizationLandingPage();
await listingTable.searchForItemWithName('lnsTableVis');
await PageObjects.lens.clickVisualizeListItemTitle('lnsTableVis');
await PageObjects.lens.goToTimeRange();
// go to empty vis
await PageObjects.lens.goToListingPageViaBreadcrumbs();
await PageObjects.visualize.clickNewVisualization();
await PageObjects.visualize.waitForGroupsSelectPage();
await PageObjects.visualize.clickVisType('lens');
await PageObjects.lens.waitForEmptyWorkspace();
await PageObjects.lens.switchToVisualization('lnsMetric');
await PageObjects.lens.dragFieldToWorkspace('@timestamp');

const timePickerValues = await PageObjects.timePicker.getTimeConfigAsAbsoluteTimes();
expect(timePickerValues.start).to.eql(PageObjects.timePicker.defaultStartTime);
expect(timePickerValues.end).to.eql(PageObjects.timePicker.defaultEndTime);
const filterCount = await filterBar.getFilterCount();
expect(filterCount).to.equal(0);
const query = await queryBar.getQueryString();
expect(query).to.equal('');
await PageObjects.lens.assertMetric('Unique count of @timestamp', '14,181');
});
it('when moving from empty to existing workspace, preserves time range and loads filters and query', async () => {
// go to existing vis
await PageObjects.lens.goToListingPageViaBreadcrumbs();
await listingTable.searchForItemWithName('lnsTableVis');
await PageObjects.lens.clickVisualizeListItemTitle('lnsTableVis');

expect(await PageObjects.lens.getDatatableHeaderText(1)).to.equal('404 › Median of bytes');
expect(await PageObjects.lens.getDatatableHeaderText(2)).to.equal('503 › Median of bytes');
expect(await PageObjects.lens.getDatatableCellText(0, 0)).to.eql('TG');
expect(await PageObjects.lens.getDatatableCellText(0, 1)).to.eql('9,931');

const timePickerValues = await PageObjects.timePicker.getTimeConfigAsAbsoluteTimes();
expect(timePickerValues.start).to.eql(PageObjects.timePicker.defaultStartTime);
expect(timePickerValues.end).to.eql(PageObjects.timePicker.defaultEndTime);
const filterCount = await filterBar.getFilterCount();
expect(filterCount).to.equal(1);
const query = await queryBar.getQueryString();
expect(query).to.equal('extension.raw : "jpg" or extension.raw : "gif" ');
});
});

it('should carry over time range and pinned filters to discover', async () => {
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickVisType('lens');
Expand Down

0 comments on commit 42586cc

Please sign in to comment.