Skip to content

Commit

Permalink
Fix issue where Dashboard panel targeting deleted saved search could …
Browse files Browse the repository at this point in the history
…not be removed
  • Loading branch information
davismcphee committed Oct 25, 2023
1 parent 310ae23 commit 276d190
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -747,11 +747,7 @@ export class SavedSearchEmbeddable
}
}

public getSavedSearch(): SavedSearch {
if (!this.savedSearch) {
throw new Error('Saved search not defined');
}

public getSavedSearch(): SavedSearch | undefined {
return this.savedSearch;
}

Expand Down
2 changes: 1 addition & 1 deletion src/plugins/discover/public/embeddable/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface SearchOutput extends EmbeddableOutput {
}

export interface ISearchEmbeddable extends IEmbeddable<SearchInput, SearchOutput> {
getSavedSearch(): SavedSearch;
getSavedSearch(): SavedSearch | undefined;
hasTimeRange(): boolean;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe('view saved search action', () => {
expect(discoverServiceMock.locator.navigate).toHaveBeenCalledWith(
getDiscoverLocatorParams({
input: embeddable.getInput(),
savedSearch: embeddable.getSavedSearch(),
savedSearch: embeddable.getSavedSearch()!,
})
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ export class ViewSavedSearchAction implements Action<ViewSearchContext> {

async execute(context: ActionExecutionContext<ViewSearchContext>): Promise<void> {
const embeddable = context.embeddable as SavedSearchEmbeddable;
const savedSearch = embeddable.getSavedSearch();
if (!savedSearch) {
return;
}
const locatorParams = getDiscoverLocatorParams({
input: embeddable.getInput(),
savedSearch: embeddable.getSavedSearch(),
savedSearch,
});
await this.locator.navigate(locatorParams);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export class ReportingCsvPanelAction implements ActionDefinition<ActionContext>
}

const savedSearch = embeddable.getSavedSearch();
const query = savedSearch.searchSource.getField('query');
const query = savedSearch?.searchSource.getField('query');

// using isOfAggregateQueryType(query) added increased the bundle size over the configured limit of 55.7KB
if (query && Boolean(query && 'sql' in query)) {
Expand All @@ -121,11 +121,12 @@ export class ReportingCsvPanelAction implements ActionDefinition<ActionContext>
throw new IncompatibleActionError();
}

if (this.isDownloading) {
const savedSearch = embeddable.getSavedSearch();

if (!savedSearch || this.isDownloading) {
return;
}

const savedSearch = embeddable.getSavedSearch();
const { columns, getSearchSource } = await this.getSharingData(savedSearch);

const immediateJobParams = this.apiClient.getDecoratedJobParams({
Expand Down
1 change: 1 addition & 0 deletions x-pack/test/functional/apps/discover/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./visualize_field'));
loadTestFile(require.resolve('./value_suggestions'));
loadTestFile(require.resolve('./value_suggestions_non_timebased'));
loadTestFile(require.resolve('./saved_search_embeddable'));
});
}
109 changes: 109 additions & 0 deletions x-pack/test/functional/apps/discover/saved_search_embeddable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* 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 expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';

export default function ({ getService, getPageObjects }: FtrProviderContext) {
const browser = getService('browser');
const dataGrid = getService('dataGrid');
const dashboardAddPanel = getService('dashboardAddPanel');
const dashboardPanelActions = getService('dashboardPanelActions');
const filterBar = getService('filterBar');
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');
const testSubjects = getService('testSubjects');
const PageObjects = getPageObjects(['common', 'dashboard', 'header', 'timePicker', 'discover']);

describe('discover saved search embeddable', () => {
before(async () => {
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional');
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/dashboard/current/data');
await kibanaServer.savedObjects.cleanStandardList();
await kibanaServer.importExport.load(
'test/functional/fixtures/kbn_archiver/dashboard/current/kibana'
);
await kibanaServer.uiSettings.replace({
defaultIndex: '0bf35f60-3dc9-11e8-8660-4d65aa086b3c',
});
await PageObjects.common.setTime({
from: 'Sep 22, 2015 @ 00:00:00.000',
to: 'Sep 23, 2015 @ 00:00:00.000',
});
});

after(async () => {
await kibanaServer.savedObjects.cleanStandardList();
await PageObjects.common.unsetTime();
});

beforeEach(async () => {
await PageObjects.dashboard.navigateToApp();
await filterBar.ensureFieldEditorModalIsClosed();
await PageObjects.dashboard.gotoDashboardLandingPage();
await PageObjects.dashboard.clickNewDashboard();
});

const addSearchEmbeddableToDashboard = async (title = 'Rendering-Test:-saved-search') => {
await dashboardAddPanel.addSavedSearch(title);
await PageObjects.header.waitUntilLoadingHasFinished();
await PageObjects.dashboard.waitForRenderComplete();
const rows = await dataGrid.getDocTableRows();
expect(rows.length).to.be.above(0);
};

const refreshDashboardPage = async (requireRenderComplete = false) => {
await browser.refresh();
await PageObjects.header.waitUntilLoadingHasFinished();
if (requireRenderComplete) {
await PageObjects.dashboard.waitForRenderComplete();
}
};

it('should allow removing the dashboard panel after the underlying saved search has been deleted', async () => {
const searchTitle = 'TempSearch';
const searchId = '90943e30-9a47-11e8-b64d-95841ca0b247';
await kibanaServer.savedObjects.create({
type: 'search',
id: searchId,
overwrite: false,
attributes: {
title: searchTitle,
description: '',
columns: ['agent', 'bytes', 'clientip'],
sort: [['@timestamp', 'desc']],
kibanaSavedObjectMeta: {
searchSourceJSON:
'{"highlightAll":true,"version":true,"query":{"language":"lucene","query":""},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}',
},
},
references: [
{
id: '0bf35f60-3dc9-11e8-8660-4d65aa086b3c',
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
type: 'index-pattern',
},
],
});
await addSearchEmbeddableToDashboard(searchTitle);
await PageObjects.dashboard.saveDashboard('Dashboard with deleted saved search', {
waitDialogIsClosed: true,
exitFromEditMode: false,
});
await kibanaServer.savedObjects.delete({
type: 'search',
id: searchId,
});
await refreshDashboardPage();
await testSubjects.existOrFail('embeddableError');
const panels = await PageObjects.dashboard.getDashboardPanels();
await dashboardPanelActions.removePanel(panels[0]);
await PageObjects.header.waitUntilLoadingHasFinished();
await testSubjects.missingOrFail('embeddableError');
});
});
}

0 comments on commit 276d190

Please sign in to comment.