diff --git a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx
index cb02e3b736663..456f10d89dc89 100644
--- a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx
+++ b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx
@@ -19,7 +19,7 @@ import { dataViewWithTimefieldMock } from '../../__mocks__/data_view_with_timefi
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import type { DataView } from '@kbn/data-views-plugin/public';
import type { DataTableRecord, EsHitRecord } from '@kbn/discover-utils/types';
-import { buildDataTableRecord } from '@kbn/discover-utils';
+import { buildDataTableRecord, buildDataTableRecordList } from '@kbn/discover-utils';
import { act } from 'react-dom/test-utils';
import { ReactWrapper } from 'enzyme';
import { setUnifiedDocViewerServices } from '@kbn/unified-doc-viewer-plugin/public/plugin';
@@ -64,19 +64,8 @@ const waitNextUpdate = async (component: ReactWrapper) => {
};
describe('Discover flyout', function () {
- const mountComponent = async ({
- dataView,
- hits,
- hitIndex,
- query,
- }: {
- dataView?: DataView;
- hits?: DataTableRecord[];
- hitIndex?: number;
- query?: Query | AggregateQuery;
- }) => {
- const onClose = jest.fn();
- const services = {
+ const getServices = () => {
+ return {
...discoverServiceMock,
filterManager: createFilterManagerMock(),
addBasePath: (path: string) => `/base${path}`,
@@ -92,22 +81,35 @@ describe('Discover flyout', function () {
addSuccess: jest.fn(),
},
} as unknown as DiscoverServices;
+ };
+
+ const mountComponent = async ({
+ dataView,
+ records,
+ expandedHit,
+ query,
+ services = getServices(),
+ }: {
+ dataView?: DataView;
+ records?: DataTableRecord[];
+ expandedHit?: EsHitRecord;
+ query?: Query | AggregateQuery;
+ services?: DiscoverServices;
+ }) => {
+ const onClose = jest.fn();
setUnifiedDocViewerServices(mockUnifiedDocViewerServices);
- const hit = buildDataTableRecord(
- hitIndex ? esHitsMock[hitIndex] : (esHitsMock[0] as EsHitRecord),
- dataViewMock
- );
+ const currentRecords =
+ records ||
+ esHitsMock.map((entry: EsHitRecord) => buildDataTableRecord(entry, dataView || dataViewMock));
const props = {
columns: ['date'],
dataView: dataView || dataViewMock,
- hit,
- hits:
- hits ||
- esHitsMock.map((entry: EsHitRecord) =>
- buildDataTableRecord(entry, dataView || dataViewMock)
- ),
+ hit: expandedHit
+ ? buildDataTableRecord(expandedHit, dataView || dataViewMock)
+ : currentRecords[0],
+ hits: currentRecords,
query,
onAddColumn: jest.fn(),
onClose,
@@ -131,6 +133,7 @@ describe('Discover flyout', function () {
beforeEach(() => {
mockFlyoutCustomization.actions.defaultActions = undefined;
mockFlyoutCustomization.Content = undefined;
+ mockFlyoutCustomization.title = undefined;
jest.clearAllMocks();
(useDiscoverCustomization as jest.Mock).mockImplementation(() => mockFlyoutCustomization);
@@ -163,14 +166,14 @@ describe('Discover flyout', function () {
});
it('displays no document navigation when there are 0 docs available', async () => {
- const { component } = await mountComponent({ hits: [] });
+ const { component } = await mountComponent({ records: [], expandedHit: esHitsMock[0] });
const docNav = findTestSubject(component, 'dscDocNavigation');
expect(docNav.length).toBeFalsy();
});
it('displays no document navigation when the expanded doc is not part of the given docs', async () => {
// scenario: you've expanded a doc, and in the next request differed docs where fetched
- const hits = [
+ const records = [
{
_index: 'new',
_id: '1',
@@ -186,7 +189,7 @@ describe('Discover flyout', function () {
_source: { date: '2020-20-01T12:12:12.124', name: 'test2', extension: 'jpg' },
},
].map((hit) => buildDataTableRecord(hit, dataViewMock));
- const { component } = await mountComponent({ hits });
+ const { component } = await mountComponent({ records, expandedHit: esHitsMock[0] });
const docNav = findTestSubject(component, 'dscDocNavigation');
expect(docNav.length).toBeFalsy();
});
@@ -208,14 +211,18 @@ describe('Discover flyout', function () {
it('doesnt allow you to navigate to the next doc, if expanded doc is the last', async () => {
// scenario: you've expanded a doc, and in the next request differed docs where fetched
- const { component, props } = await mountComponent({ hitIndex: esHitsMock.length - 1 });
+ const { component, props } = await mountComponent({
+ expandedHit: esHitsMock[esHitsMock.length - 1],
+ });
findTestSubject(component, 'pagination-button-next').simulate('click');
expect(props.setExpandedDoc).toHaveBeenCalledTimes(0);
});
it('allows you to navigate to the previous doc, if expanded doc is the last', async () => {
// scenario: you've expanded a doc, and in the next request differed docs where fetched
- const { component, props } = await mountComponent({ hitIndex: esHitsMock.length - 1 });
+ const { component, props } = await mountComponent({
+ expandedHit: esHitsMock[esHitsMock.length - 1],
+ });
findTestSubject(component, 'pagination-button-previous').simulate('click');
expect(props.setExpandedDoc).toHaveBeenCalledTimes(1);
expect(props.setExpandedDoc.mock.calls[0][0].raw._id).toBe('4');
@@ -470,5 +477,37 @@ describe('Discover flyout', function () {
expect(props.onFilter).toHaveBeenCalled();
});
});
+
+ describe('context awareness', () => {
+ it('should render flyout per the defined document profile', async () => {
+ const services = getServices();
+ const hits = [
+ {
+ _index: 'new',
+ _id: '1',
+ _score: 1,
+ _type: '_doc',
+ _source: { date: '2020-20-01T12:12:12.123', message: 'test1', bytes: 20 },
+ },
+ {
+ _index: 'new',
+ _id: '2',
+ _score: 1,
+ _type: '_doc',
+ _source: { date: '2020-20-01T12:12:12.124', name: 'test2', extension: 'jpg' },
+ },
+ ];
+ const records = buildDataTableRecordList({
+ records: hits as EsHitRecord[],
+ dataView: dataViewMock,
+ processRecord: (record) => services.profilesManager.resolveDocumentProfile({ record }),
+ });
+ const { component } = await mountComponent({ records, services });
+ const title = findTestSubject(component, 'docTableRowDetailsTitle');
+ expect(title.text()).toBe('Document #new::1::');
+ const content = findTestSubject(component, 'kbnDocViewer');
+ expect(content.text()).toBe('Mock tab');
+ });
+ });
});
});
diff --git a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx
index d6273d7669391..891ae384bd41a 100644
--- a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx
+++ b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx
@@ -31,12 +31,14 @@ import { Filter, Query, AggregateQuery, isOfAggregateQueryType } from '@kbn/es-q
import type { DataTableRecord } from '@kbn/discover-utils/types';
import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types';
import type { DataTableColumnsMeta } from '@kbn/unified-data-table';
+import type { DocViewsRegistry } from '@kbn/unified-doc-viewer';
import { UnifiedDocViewer } from '@kbn/unified-doc-viewer-plugin/public';
import useLocalStorage from 'react-use/lib/useLocalStorage';
import { useDiscoverServices } from '../../hooks/use_discover_services';
import { useFlyoutActions } from './use_flyout_actions';
import { useDiscoverCustomization } from '../../customizations';
import { DiscoverGridFlyoutActions } from './discover_grid_flyout_actions';
+import { useProfileAccessor } from '../../context_awareness';
export interface DiscoverGridFlyoutProps {
savedSearchId?: string;
@@ -161,6 +163,29 @@ export function DiscoverGridFlyout({
[onRemoveColumn, services.toastNotifications]
);
+ const defaultFlyoutTitle = isEsqlQuery
+ ? i18n.translate('discover.grid.tableRow.docViewerEsqlDetailHeading', {
+ defaultMessage: 'Result',
+ })
+ : i18n.translate('discover.grid.tableRow.docViewerDetailHeading', {
+ defaultMessage: 'Document',
+ });
+
+ const getDocViewerAccessor = useProfileAccessor('getDocViewer', {
+ record: actualHit,
+ });
+ const docViewer = useMemo(() => {
+ const getDocViewer = getDocViewerAccessor(() => ({
+ title: flyoutCustomization?.title ?? defaultFlyoutTitle,
+ docViewsRegistry: (registry: DocViewsRegistry) =>
+ typeof flyoutCustomization?.docViewsRegistry === 'function'
+ ? flyoutCustomization.docViewsRegistry(registry)
+ : registry,
+ }));
+
+ return getDocViewer({ record: actualHit });
+ }, [defaultFlyoutTitle, flyoutCustomization, getDocViewerAccessor, actualHit]);
+
const renderDefaultContent = useCallback(
() => (
),
[
@@ -185,7 +210,7 @@ export function DiscoverGridFlyout({
isEsqlQuery,
onFilter,
removeColumn,
- flyoutCustomization?.docViewsRegistry,
+ docViewer.docViewsRegistry,
]
);
@@ -208,15 +233,6 @@ export function DiscoverGridFlyout({
renderDefaultContent()
);
- const defaultFlyoutTitle = isEsqlQuery
- ? i18n.translate('discover.grid.tableRow.docViewerEsqlDetailHeading', {
- defaultMessage: 'Result',
- })
- : i18n.translate('discover.grid.tableRow.docViewerDetailHeading', {
- defaultMessage: 'Document',
- });
- const flyoutTitle = flyoutCustomization?.title ?? defaultFlyoutTitle;
-
return (
- {flyoutTitle}
+ {docViewer.title}
{activePage !== -1 && (
diff --git a/src/plugins/discover/public/context_awareness/__mocks__/index.ts b/src/plugins/discover/public/context_awareness/__mocks__/index.ts
index 0f8beed5d955f..b493ff43bfbca 100644
--- a/src/plugins/discover/public/context_awareness/__mocks__/index.ts
+++ b/src/plugins/discover/public/context_awareness/__mocks__/index.ts
@@ -61,6 +61,24 @@ export const createContextAwarenessMocks = () => {
...prev(),
rootProfile: () => 'document-profile',
})),
+ getDocViewer: (prev) => (params) => {
+ const recordId = params.record.id;
+ const prevValue = prev(params);
+ return {
+ title: `${prevValue.title} #${recordId}`,
+ docViewsRegistry: (registry) => {
+ registry.add({
+ id: 'doc_view_mock',
+ title: 'Mock tab',
+ order: 10,
+ component: () => {
+ return null;
+ },
+ });
+ return prevValue.docViewsRegistry(registry);
+ },
+ };
+ },
} as DocumentProfileProvider['profile'],
resolve: jest.fn(() => ({
isMatch: true,
diff --git a/src/plugins/discover/public/context_awareness/types.ts b/src/plugins/discover/public/context_awareness/types.ts
index b612b2ce29907..4bc75e6e1727d 100644
--- a/src/plugins/discover/public/context_awareness/types.ts
+++ b/src/plugins/discover/public/context_awareness/types.ts
@@ -7,7 +7,19 @@
*/
import type { CustomCellRenderer } from '@kbn/unified-data-table';
+import type { DocViewsRegistry } from '@kbn/unified-doc-viewer';
+import type { DataTableRecord } from '@kbn/discover-utils';
+
+export interface DocViewerExtension {
+ title: string;
+ docViewsRegistry: (prevRegistry: DocViewsRegistry) => DocViewsRegistry;
+}
+
+export interface DocViewerExtensionParams {
+ record: DataTableRecord;
+}
export interface Profile {
getCellRenderers: () => CustomCellRenderer;
+ getDocViewer: (params: DocViewerExtensionParams) => DocViewerExtension;
}