[8.17] [Discover] [Embeddable] Fix Discover session embeddable drilldown (#211678) (#212142)

# Backport

This will backport the following commits from `main` to `8.17`:
- [[Discover] [Embeddable] Fix Discover session embeddable drilldown
(#211678)](https://github.com/elastic/kibana/pull/211678)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Davis
McPhee","email":"davis.mcphee@elastic.co"},"sourceCommit":{"committedDate":"2025-02-21T17:26:22Z","message":"[Discover]
[Embeddable] Fix Discover session embeddable drilldown (#211678)\n\n##
Summary\n\nThis PR re-adds drilldown support to the Discover session
embeddable\nafter it was accidentally removed during the refactoring in
#180536\n(related PR where drilldowns / dynamic actions were
refactored:\n#178896). A new functional test has also been added to
prevent future\nregressions.\n\nFixes #211677.\n\n### Checklist\n\n- [ ]
Any text added follows [EUI's
writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\nsentence case text and includes
[i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n-
[
]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas
added for features that require explanation or tutorials\n- [ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [ ] If a plugin
configuration key changed, check if it needs to be\nallowlisted in the
cloud and added to the
[docker\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\n-
[ ] This was checked for breaking HTTP API changes, and any
breaking\nchanges have been approved by the breaking-change committee.
The\n`release_note:breaking` label should be applied in these
situations.\n- [ ] [Flaky
Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\nused on any tests changed\n- [ ] The PR description includes the
appropriate Release Notes section,\nand the correct `release_note:*`
label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n---------\n\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\nCo-authored-by:
Matthias Wilhelm
<matthias.wilhelm@elastic.co>","sha":"257971d4c0f99c0da56b9b817cff731977f8891f","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:Discover","release_note:fix","Team:DataDiscovery","backport:prev-major","v9.1.0"],"title":"[Discover]
[Embeddable] Fix Discover session embeddable
drilldown","number":211678,"url":"https://github.com/elastic/kibana/pull/211678","mergeCommit":{"message":"[Discover]
[Embeddable] Fix Discover session embeddable drilldown (#211678)\n\n##
Summary\n\nThis PR re-adds drilldown support to the Discover session
embeddable\nafter it was accidentally removed during the refactoring in
#180536\n(related PR where drilldowns / dynamic actions were
refactored:\n#178896). A new functional test has also been added to
prevent future\nregressions.\n\nFixes #211677.\n\n### Checklist\n\n- [ ]
Any text added follows [EUI's
writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\nsentence case text and includes
[i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n-
[
]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas
added for features that require explanation or tutorials\n- [ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [ ] If a plugin
configuration key changed, check if it needs to be\nallowlisted in the
cloud and added to the
[docker\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\n-
[ ] This was checked for breaking HTTP API changes, and any
breaking\nchanges have been approved by the breaking-change committee.
The\n`release_note:breaking` label should be applied in these
situations.\n- [ ] [Flaky
Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\nused on any tests changed\n- [ ] The PR description includes the
appropriate Release Notes section,\nand the correct `release_note:*`
label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n---------\n\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\nCo-authored-by:
Matthias Wilhelm
<matthias.wilhelm@elastic.co>","sha":"257971d4c0f99c0da56b9b817cff731977f8891f"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/211678","number":211678,"mergeCommit":{"message":"[Discover]
[Embeddable] Fix Discover session embeddable drilldown (#211678)\n\n##
Summary\n\nThis PR re-adds drilldown support to the Discover session
embeddable\nafter it was accidentally removed during the refactoring in
#180536\n(related PR where drilldowns / dynamic actions were
refactored:\n#178896). A new functional test has also been added to
prevent future\nregressions.\n\nFixes #211677.\n\n### Checklist\n\n- [ ]
Any text added follows [EUI's
writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\nsentence case text and includes
[i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n-
[
]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas
added for features that require explanation or tutorials\n- [ ] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [ ] If a plugin
configuration key changed, check if it needs to be\nallowlisted in the
cloud and added to the
[docker\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\n-
[ ] This was checked for breaking HTTP API changes, and any
breaking\nchanges have been approved by the breaking-change committee.
The\n`release_note:breaking` label should be applied in these
situations.\n- [ ] [Flaky
Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\nused on any tests changed\n- [ ] The PR description includes the
appropriate Release Notes section,\nand the correct `release_note:*`
label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n---------\n\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\nCo-authored-by:
Matthias Wilhelm
<matthias.wilhelm@elastic.co>","sha":"257971d4c0f99c0da56b9b817cff731977f8891f"}}]}]
BACKPORT-->
This commit is contained in:
Davis McPhee 2025-02-21 17:13:03 -04:00 committed by GitHub
parent 5ec051eb89
commit f9f26752de
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 107 additions and 14 deletions

View file

@ -48,6 +48,7 @@
"aiops",
"fieldsMetadata",
"logsDataAccess",
"embeddableEnhanced"
],
"requiredBundles": [
"kibanaUtils",

View file

@ -60,6 +60,7 @@ import type { DataVisualizerPluginStart } from '@kbn/data-visualizer-plugin/publ
import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public';
import { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public';
import { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public';
import type { EmbeddableEnhancedPluginStart } from '@kbn/embeddable-enhanced-plugin/public';
import type { DiscoverStartPlugins } from './types';
import type { DiscoverContextAppLocator } from './application/context/services/locator';
import type { DiscoverSingleDocLocator } from './application/doc/locator';
@ -137,6 +138,7 @@ export interface DiscoverServices {
ebtManager: DiscoverEBTManager;
fieldsMetadata?: FieldsMetadataPublicStart;
logsDataAccess?: LogsDataAccessPluginStart;
embeddableEnhanced?: EmbeddableEnhancedPluginStart;
}
export const buildServices = memoize(
@ -229,6 +231,7 @@ export const buildServices = memoize(
ebtManager,
fieldsMetadata: plugins.fieldsMetadata,
logsDataAccess: plugins.logsDataAccess,
embeddableEnhanced: plugins.embeddableEnhanced,
};
}
);

View file

@ -7,8 +7,9 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { SavedSearchAttributes } from '@kbn/saved-search-plugin/common';
import type { SavedSearchAttributes } from '@kbn/saved-search-plugin/common';
import type { Trigger } from '@kbn/ui-actions-plugin/public';
import type { SearchEmbeddableSerializedState } from './types';
export { SEARCH_EMBEDDABLE_TYPE } from '@kbn/discover-utils';
@ -37,9 +38,10 @@ export const EDITABLE_SAVED_SEARCH_KEYS: Readonly<Array<keyof SavedSearchAttribu
] as const;
/** This constant refers to the dashboard panel specific state */
export const EDITABLE_PANEL_KEYS = [
export const EDITABLE_PANEL_KEYS: Readonly<Array<keyof SearchEmbeddableSerializedState>> = [
'title', // panel title
'description', // panel description
'timeRange', // panel custom time range
'hidePanelTitles', // panel hidden title
'enhancements', // panel enhancements (e.g. drilldowns)
] as const;

View file

@ -20,6 +20,7 @@ import { i18n } from '@kbn/i18n';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import {
FetchContext,
getUnchangingComparator,
initializeTimeRange,
initializeTitles,
useBatchedPublishingSubjects,
@ -93,6 +94,13 @@ export const getSearchEmbeddableFactory = ({
/** Build API */
const { titlesApi, titleComparators, serializeTitles } = initializeTitles(initialState);
const timeRange = initializeTimeRange(initialState);
const dynamicActionsApi =
discoverServices.embeddableEnhanced?.initializeReactEmbeddableDynamicActions(
uuid,
() => titlesApi.panelTitle.getValue(),
initialState
);
const maybeStopDynamicActions = dynamicActionsApi?.startDynamicActions();
const searchEmbeddable = await initializeSearchEmbeddableApi(initialState, {
discoverServices,
});
@ -118,6 +126,7 @@ export const getSearchEmbeddableFactory = ({
...titlesApi,
...searchEmbeddable.api,
...timeRange.api,
...dynamicActionsApi?.dynamicActionsApi,
...initializeEditApi({
uuid,
parentApi,
@ -187,14 +196,23 @@ export const getSearchEmbeddableFactory = ({
savedSearch: searchEmbeddable.api.savedSearch$.getValue(),
serializeTitles,
serializeTimeRange: timeRange.serialize,
serializeDynamicActions: dynamicActionsApi?.serializeDynamicActions,
savedObjectId: savedObjectId$.getValue(),
discoverServices,
}),
getInspectorAdapters: () => searchEmbeddable.stateManager.inspectorAdapters.getValue(),
supportedTriggers: () => {
// No triggers are supported, but this is still required to pass the drilldown
// compatibilty check and ensure top-level drilldowns (e.g. URL) work as expected
return [];
},
},
{
...titleComparators,
...timeRange.comparators,
...(dynamicActionsApi?.dynamicActionsComparator ?? {
enhancements: getUnchangingComparator(),
}),
...searchEmbeddable.comparators,
savedObjectId: [savedObjectId$, (value) => savedObjectId$.next(value)],
savedObjectTitle: [defaultPanelTitle$, (value) => defaultPanelTitle$.next(value)],
@ -217,6 +235,7 @@ export const getSearchEmbeddableFactory = ({
return () => {
searchEmbeddable.cleanup();
unsubscribeFromFetch();
maybeStopDynamicActions?.stopDynamicActions();
};
}, []);

View file

@ -7,13 +7,14 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { DataTableRecord } from '@kbn/discover-utils/types';
import type { DataTableRecord } from '@kbn/discover-utils/types';
import type { DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public';
import { HasInspectorAdapters } from '@kbn/inspector-plugin/public';
import {
import type { HasInspectorAdapters } from '@kbn/inspector-plugin/public';
import type {
EmbeddableApiContext,
HasEditCapabilities,
HasInPlaceLibraryTransforms,
HasSupportedTriggers,
PublishesBlockingError,
PublishesDataLoading,
PublishesDataViews,
@ -24,13 +25,15 @@ import {
SerializedTimeRange,
SerializedTitles,
} from '@kbn/presentation-publishing';
import {
import type {
SavedSearch,
SavedSearchAttributes,
SerializableSavedSearch,
} from '@kbn/saved-search-plugin/common/types';
import { DataTableColumnsMeta } from '@kbn/unified-data-table';
import { BehaviorSubject } from 'rxjs';
import type { DataTableColumnsMeta } from '@kbn/unified-data-table';
import type { BehaviorSubject } from 'rxjs';
import type { DynamicActionsSerializedState } from '@kbn/embeddable-enhanced-plugin/public/plugin';
import type { HasDynamicActions } from '@kbn/embeddable-enhanced-plugin/public';
import { EDITABLE_SAVED_SEARCH_KEYS } from './constants';
export type SearchEmbeddableState = Pick<
@ -63,6 +66,7 @@ export type SearchEmbeddableSerializedAttributes = Omit<
export type SearchEmbeddableSerializedState = SerializedTitles &
SerializedTimeRange &
Partial<DynamicActionsSerializedState> &
Partial<Pick<SavedSearchAttributes, (typeof EDITABLE_SAVED_SEARCH_KEYS)[number]>> & {
// by value
attributes?: SavedSearchAttributes & { references: SavedSearch['references'] };
@ -72,7 +76,8 @@ export type SearchEmbeddableSerializedState = SerializedTitles &
export type SearchEmbeddableRuntimeState = SearchEmbeddableSerializedAttributes &
SerializedTitles &
SerializedTimeRange & {
SerializedTimeRange &
Partial<DynamicActionsSerializedState> & {
savedObjectTitle?: string;
savedObjectId?: string;
savedObjectDescription?: string;
@ -93,7 +98,9 @@ export type SearchEmbeddableApi = DefaultEmbeddableApi<
HasInPlaceLibraryTransforms &
HasTimeRange &
HasInspectorAdapters &
Partial<HasEditCapabilities & PublishesSavedObjectId>;
Partial<HasEditCapabilities & PublishesSavedObjectId> &
HasDynamicActions &
HasSupportedTriggers;
export interface PublishesSavedSearch {
savedSearch$: PublishingSubject<SavedSearch>;

View file

@ -121,6 +121,7 @@ describe('Serialization utils', () => {
savedSearch,
serializeTitles: jest.fn(),
serializeTimeRange: jest.fn(),
serializeDynamicActions: jest.fn(),
discoverServices: discoverServiceMock,
});
@ -159,6 +160,7 @@ describe('Serialization utils', () => {
savedSearch,
serializeTitles: jest.fn(),
serializeTimeRange: jest.fn(),
serializeDynamicActions: jest.fn(),
savedObjectId: 'test-id',
discoverServices: discoverServiceMock,
});
@ -178,6 +180,7 @@ describe('Serialization utils', () => {
savedSearch: { ...savedSearch, sampleSize: 500, sort: [['order_date', 'asc']] },
serializeTitles: jest.fn(),
serializeTimeRange: jest.fn(),
serializeDynamicActions: jest.fn(),
savedObjectId: 'test-id',
discoverServices: discoverServiceMock,
});

View file

@ -20,6 +20,7 @@ import {
} from '@kbn/saved-search-plugin/common';
import { SavedSearchUnwrapResult } from '@kbn/saved-search-plugin/public';
import type { DynamicActionsSerializedState } from '@kbn/embeddable-enhanced-plugin/public/plugin';
import { extract, inject } from '../../../common/embeddable/search_inject_extract';
import { DiscoverServices } from '../../build_services';
import {
@ -77,6 +78,7 @@ export const serializeState = async ({
savedSearch,
serializeTitles,
serializeTimeRange,
serializeDynamicActions,
savedObjectId,
discoverServices,
}: {
@ -85,6 +87,7 @@ export const serializeState = async ({
savedSearch: SavedSearch;
serializeTitles: () => SerializedTitles;
serializeTimeRange: () => SerializedTimeRange;
serializeDynamicActions: (() => DynamicActionsSerializedState) | undefined;
savedObjectId?: string;
discoverServices: DiscoverServices;
}): Promise<SerializedPanelState<SearchEmbeddableSerializedState>> => {
@ -110,6 +113,7 @@ export const serializeState = async ({
// Serialize the current dashboard state into the panel state **without** updating the saved object
...serializeTitles(),
...serializeTimeRange(),
...serializeDynamicActions?.(),
...overwriteState,
},
// No references to extract for by-reference embeddable since all references are stored with by-reference saved object

View file

@ -43,6 +43,7 @@ import type { DataVisualizerPluginStart } from '@kbn/data-visualizer-plugin/publ
import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public';
import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public';
import { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public';
import type { EmbeddableEnhancedPluginStart } from '@kbn/embeddable-enhanced-plugin/public';
import { DiscoverAppLocator } from '../common';
import { DiscoverCustomizationContext } from './customizations';
import { type DiscoverContainerProps } from './components/discover_container';
@ -174,4 +175,5 @@ export interface DiscoverStartPlugins {
unifiedSearch: UnifiedSearchPublicPluginStart;
urlForwarding: UrlForwardingStart;
usageCollection?: UsageCollectionSetup;
embeddableEnhanced?: EmbeddableEnhancedPluginStart;
}

View file

@ -99,7 +99,8 @@
"@kbn/core-lifecycle-browser",
"@kbn/discover-contextual-components",
"@kbn/esql-ast",
"@kbn/discover-shared-plugin"
"@kbn/discover-shared-plugin",
"@kbn/embeddable-enhanced-plugin"
],
"exclude": [
"target/**/*"

View file

@ -78,7 +78,11 @@ export function DashboardDrilldownsManageProvider({ getService }: FtrProviderCon
}: {
drilldownName: string;
destinationURLTemplate: string;
trigger: 'VALUE_CLICK_TRIGGER' | 'SELECT_RANGE_TRIGGER' | 'IMAGE_CLICK_TRIGGER';
trigger:
| 'VALUE_CLICK_TRIGGER'
| 'SELECT_RANGE_TRIGGER'
| 'IMAGE_CLICK_TRIGGER'
| 'CONTEXT_MENU_TRIGGER';
}) {
await this.fillInDrilldownName(drilldownName);
await this.selectTriggerIfNeeded(trigger);
@ -94,7 +98,11 @@ export function DashboardDrilldownsManageProvider({ getService }: FtrProviderCon
}
async selectTriggerIfNeeded(
trigger: 'VALUE_CLICK_TRIGGER' | 'SELECT_RANGE_TRIGGER' | 'IMAGE_CLICK_TRIGGER'
trigger:
| 'VALUE_CLICK_TRIGGER'
| 'SELECT_RANGE_TRIGGER'
| 'IMAGE_CLICK_TRIGGER'
| 'CONTEXT_MENU_TRIGGER'
) {
if (await testSubjects.exists(`triggerPicker`)) {
const container = await testSubjects.find(`triggerPicker-${trigger}`);

View file

@ -13,11 +13,20 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const dataGrid = getService('dataGrid');
const dashboardAddPanel = getService('dashboardAddPanel');
const dashboardPanelActions = getService('dashboardPanelActions');
const dashboardDrilldownPanelActions = getService('dashboardDrilldownPanelActions');
const dashboardDrilldownsManage = getService('dashboardDrilldownsManage');
const filterBar = getService('filterBar');
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');
const testSubjects = getService('testSubjects');
const { common, dashboard, header } = getPageObjects(['common', 'dashboard', 'header']);
const find = getService('find');
const queryBar = getService('queryBar');
const { common, dashboard, header, discover } = getPageObjects([
'common',
'dashboard',
'header',
'discover',
]);
describe('discover saved search embeddable', () => {
before(async () => {
@ -106,5 +115,39 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await header.waitUntilLoadingHasFinished();
await testSubjects.missingOrFail('embeddableError');
});
it('should support URL drilldown', async () => {
await addSearchEmbeddableToDashboard();
await dashboardDrilldownPanelActions.clickCreateDrilldown();
const drilldownName = 'URL drilldown';
const urlTemplate =
"{{kibanaUrl}}/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:'{{context.panel.timeRange.from}}',to:'{{context.panel.timeRange.to}}'))" +
"&_a=(columns:!(_source),filters:{{rison context.panel.filters}},index:'{{context.panel.indexPatternId}}',interval:auto," +
"query:(language:{{context.panel.query.language}},query:'clientip:239.190.189.77'),sort:!())";
await testSubjects.click('actionFactoryItem-URL_DRILLDOWN');
await dashboardDrilldownsManage.fillInDashboardToURLDrilldownWizard({
drilldownName,
destinationURLTemplate: urlTemplate,
trigger: 'CONTEXT_MENU_TRIGGER',
});
await testSubjects.click('urlDrilldownAdditionalOptions');
await testSubjects.click('urlDrilldownOpenInNewTab');
await dashboardDrilldownsManage.saveChanges();
await dashboard.saveDashboard('Dashboard with URL drilldown', {
saveAsNew: true,
waitDialogIsClosed: true,
exitFromEditMode: true,
});
await browser.refresh();
await header.waitUntilLoadingHasFinished();
await dashboard.waitForRenderComplete();
await dashboardPanelActions.openContextMenu();
await find.clickByLinkText(drilldownName);
await discover.waitForDiscoverAppOnScreen();
await header.waitUntilLoadingHasFinished();
await discover.waitForDocTableLoadingComplete();
expect(await queryBar.getQueryString()).to.be('clientip:239.190.189.77');
expect(await discover.getHitCount()).to.be('6');
});
});
}