diff --git a/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/profile.tsx b/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/profile.tsx index 6b705b00c1ba1..f9cba1592dc30 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/profile.tsx +++ b/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/profile.tsx @@ -58,7 +58,15 @@ export const exampleDataSourceProfileProvider: DataSourceProfileProvider = { return { title: `Record #${recordId}`, docViewsRegistry: (registry) => { - registry.enableById('doc_view_logs_overview'); + registry.add({ + id: 'doc_view_example', + title: 'Example', + order: 0, + component: () => ( +
Example Doc View
+ ), + }); + return prevValue.docViewsRegistry(registry); }, }; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/profile.ts b/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/profile.ts index 303efa103e327..9739430e08000 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/profile.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/profile.ts @@ -13,14 +13,14 @@ export const exampleDocumentProfileProvider: DocumentProfileProvider = { profileId: 'example-document-profile', profile: {}, resolve: (params) => { - if (getFieldValue(params.record, 'data_stream.type') !== 'logs') { + if (getFieldValue(params.record, 'data_stream.type') !== 'example') { return { isMatch: false }; } return { isMatch: true, context: { - type: DocumentType.Log, + type: DocumentType.Default, }, }; }, diff --git a/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/accessors/get_doc_viewer.tsx b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/accessors/get_doc_viewer.tsx new file mode 100644 index 0000000000000..c83155c4d3a49 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/accessors/get_doc_viewer.tsx @@ -0,0 +1,33 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import { UnifiedDocViewerLogsOverview } from '@kbn/unified-doc-viewer-plugin/public'; +import React from 'react'; +import type { DocumentProfileProvider } from '../../../profiles'; + +export const getDocViewer: DocumentProfileProvider['profile']['getDocViewer'] = + (prev) => (params) => { + const prevDocViewer = prev(params); + + return { + ...prevDocViewer, + docViewsRegistry: (registry) => { + registry.add({ + id: 'doc_view_logs_overview', + title: i18n.translate('discover.docViews.logsOverview.title', { + defaultMessage: 'Log overview', + }), + order: 0, + component: (props) => , + }); + + return prevDocViewer.docViewsRegistry(registry); + }, + }; + }; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/accessors/index.ts b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/accessors/index.ts new file mode 100644 index 0000000000000..781ad51343123 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/accessors/index.ts @@ -0,0 +1,9 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { getDocViewer } from './get_doc_viewer'; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.test.ts b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.test.ts index 6514eb699e553..a188dd4584508 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.test.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.test.ts @@ -7,6 +7,7 @@ */ import { buildDataTableRecord } from '@kbn/discover-utils'; +import { DocViewsRegistry } from '@kbn/unified-doc-viewer'; import { DocumentType } from '../../profiles'; import { createContextAwarenessMocks } from '../../__mocks__'; import { createLogDocumentProfileProvider } from './profile'; @@ -65,6 +66,32 @@ describe('logDocumentProfileProvider', () => { }) ).toEqual(RESOLUTION_MISMATCH); }); + + describe('getDocViewer', () => { + it('adds a log overview doc view to the registry', () => { + const getDocViewer = logDocumentProfileProvider.profile.getDocViewer!(() => ({ + title: 'test title', + docViewsRegistry: (registry) => registry, + })); + const docViewer = getDocViewer({ + record: buildDataTableRecord({}), + }); + const registry = new DocViewsRegistry(); + + expect(docViewer.title).toBe('test title'); + expect(registry.getAll()).toHaveLength(0); + docViewer.docViewsRegistry(registry); + expect(registry.getAll()).toHaveLength(1); + expect(registry.getAll()[0]).toEqual( + expect.objectContaining({ + id: 'doc_view_logs_overview', + title: 'Log overview', + order: 0, + component: expect.any(Function), + }) + ); + }); + }); }); const buildMockRecord = (index: string, fields: Record = {}) => diff --git a/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.ts b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.tsx similarity index 95% rename from src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.ts rename to src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.tsx index 2d03c9e35398a..bf7276f1d39b8 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/log_document_profile/profile.tsx @@ -9,12 +9,15 @@ import { DataTableRecord } from '@kbn/discover-utils'; import { DocumentProfileProvider, DocumentType } from '../../profiles'; import { ProfileProviderServices } from '../profile_provider_services'; +import { getDocViewer } from './accessors'; export const createLogDocumentProfileProvider = ( services: ProfileProviderServices ): DocumentProfileProvider => ({ profileId: 'log-document-profile', - profile: {}, + profile: { + getDocViewer, + }, resolve: ({ record }) => { const isLogRecord = getIsLogRecord(record, services.logsContextService.isLogsIndexPattern); diff --git a/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.test.ts b/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.test.ts index c58726ecc1c11..df437d1547cc5 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.test.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.test.ts @@ -68,7 +68,7 @@ describe('registerProfileProviders', () => { const documentContext = documentProfileServiceMock.resolve({ record: { id: 'test', - flattened: { 'data_stream.type': 'logs' }, + flattened: { 'data_stream.type': 'example' }, raw: {}, }, }); @@ -100,7 +100,7 @@ describe('registerProfileProviders', () => { const documentContext = documentProfileServiceMock.resolve({ record: { id: 'test', - flattened: { 'data_stream.type': 'logs' }, + flattened: { 'data_stream.type': 'example' }, raw: {}, }, }); diff --git a/src/plugins/unified_doc_viewer/kibana.jsonc b/src/plugins/unified_doc_viewer/kibana.jsonc index e2febffda4df6..56ea8951e3a2d 100644 --- a/src/plugins/unified_doc_viewer/kibana.jsonc +++ b/src/plugins/unified_doc_viewer/kibana.jsonc @@ -8,7 +8,7 @@ "server": false, "browser": true, "requiredBundles": ["kibanaUtils"], - "requiredPlugins": ["data", "discoverShared", "fieldFormats", "share"], + "requiredPlugins": ["data", "fieldFormats", "share"], "optionalPlugins": ["fieldsMetadata"] } } diff --git a/src/plugins/unified_doc_viewer/public/__mocks__/services.ts b/src/plugins/unified_doc_viewer/public/__mocks__/services.ts index 29ae5f2981a6e..5e7222f261532 100644 --- a/src/plugins/unified_doc_viewer/public/__mocks__/services.ts +++ b/src/plugins/unified_doc_viewer/public/__mocks__/services.ts @@ -8,7 +8,6 @@ import { analyticsServiceMock } from '@kbn/core-analytics-browser-mocks'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; -import { discoverSharedPluginMock } from '@kbn/discover-shared-plugin/public/mocks'; import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks'; import { fieldsMetadataPluginPublicMock } from '@kbn/fields-metadata-plugin/public/mocks'; import { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks'; @@ -24,7 +23,6 @@ export const mockUnifiedDocViewer: jest.Mocked = { export const mockUnifiedDocViewerServices: jest.Mocked = { analytics: analyticsServiceMock.createAnalyticsServiceStart(), data: dataPluginMock.createStartContract(), - discoverShared: discoverSharedPluginMock.createStartContract(), fieldFormats: fieldFormatsMock, fieldsMetadata: fieldsMetadataPluginPublicMock.createStartContract(), storage: new Storage(localStorage), diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/index.ts b/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/index.ts index 69f01c944ad25..99416ee140231 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/index.ts +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/index.ts @@ -5,6 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ + import { LogsOverview } from './logs_overview'; // Required for usage in React.lazy diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview.tsx index b46570f4f0d37..73bcf21dab30c 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview.tsx @@ -10,13 +10,17 @@ import React from 'react'; import { DocViewRenderProps } from '@kbn/unified-doc-viewer/types'; import { getLogDocumentOverview } from '@kbn/discover-utils'; import { EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; +import { ObservabilityLogsAIAssistantFeatureRenderDeps } from '@kbn/discover-shared-plugin/public'; import { LogsOverviewHeader } from './logs_overview_header'; import { LogsOverviewHighlights } from './logs_overview_highlights'; import { FieldActionsProvider } from '../../hooks/use_field_actions'; import { getUnifiedDocViewerServices } from '../../plugin'; -import { LogsOverviewAIAssistant } from './logs_overview_ai_assistant'; import { LogsOverviewDegradedFields } from './logs_overview_degraded_fields'; +export type LogsOverviewProps = DocViewRenderProps & { + renderAIAssistant?: (deps: ObservabilityLogsAIAssistantFeatureRenderDeps) => JSX.Element; +}; + export function LogsOverview({ columns, dataView, @@ -24,9 +28,11 @@ export function LogsOverview({ filter, onAddColumn, onRemoveColumn, -}: DocViewRenderProps) { + renderAIAssistant, +}: LogsOverviewProps) { const { fieldFormats } = getUnifiedDocViewerServices(); const parsedDoc = getLogDocumentOverview(hit, { dataView, fieldFormats }); + const LogsOverviewAIAssistant = renderAIAssistant; return ( - + {LogsOverviewAIAssistant && } ); } diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview_ai_assistant.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview_ai_assistant.tsx deleted file mode 100644 index 0e2627a1054fd..0000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview_ai_assistant.tsx +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { DataTableRecord } from '@kbn/discover-utils'; -import { getUnifiedDocViewerServices } from '../../plugin'; - -export function LogsOverviewAIAssistant({ doc }: { doc: DataTableRecord }) { - const { discoverShared } = getUnifiedDocViewerServices(); - - const logsAIAssistantFeature = discoverShared.features.registry.getById( - 'observability-logs-ai-assistant' - ); - - if (!logsAIAssistantFeature) { - return null; - } - - return logsAIAssistantFeature.render({ doc }); -} diff --git a/src/plugins/unified_doc_viewer/public/components/lazy_doc_viewer_logs_overview.tsx b/src/plugins/unified_doc_viewer/public/components/lazy_doc_viewer_logs_overview.tsx new file mode 100644 index 0000000000000..8da9e9b3cb722 --- /dev/null +++ b/src/plugins/unified_doc_viewer/public/components/lazy_doc_viewer_logs_overview.tsx @@ -0,0 +1,19 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { EuiDelayRender, EuiSkeletonText } from '@elastic/eui'; +import { dynamic } from '@kbn/shared-ux-utility'; + +export const UnifiedDocViewerLogsOverview = dynamic(() => import('./doc_viewer_logs_overview'), { + fallback: ( + + + + ), +}); diff --git a/src/plugins/unified_doc_viewer/public/index.tsx b/src/plugins/unified_doc_viewer/public/index.tsx index b594d8f06c42f..6c5f1d59991c6 100644 --- a/src/plugins/unified_doc_viewer/public/index.tsx +++ b/src/plugins/unified_doc_viewer/public/index.tsx @@ -29,4 +29,7 @@ export { useEsDocSearch } from './hooks'; export { UnifiedDocViewer } from './components/lazy_doc_viewer'; export { UnifiedDocViewerFlyout } from './components/lazy_doc_viewer_flyout'; +export type { LogsOverviewProps as UnifiedDocViewerLogsOverviewProps } from './components/doc_viewer_logs_overview/logs_overview'; +export { UnifiedDocViewerLogsOverview } from './components/lazy_doc_viewer_logs_overview'; + export const plugin = () => new UnifiedDocViewerPublicPlugin(); diff --git a/src/plugins/unified_doc_viewer/public/plugin.tsx b/src/plugins/unified_doc_viewer/public/plugin.tsx index 9c4d7117c37dd..e8a23342e7976 100644 --- a/src/plugins/unified_doc_viewer/public/plugin.tsx +++ b/src/plugins/unified_doc_viewer/public/plugin.tsx @@ -17,7 +17,6 @@ import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import { CoreStart } from '@kbn/core/public'; import { dynamic } from '@kbn/shared-ux-utility'; -import { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public'; import { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; import { SharePluginStart } from '@kbn/share-plugin/public'; import type { UnifiedDocViewerServices } from './types'; @@ -31,9 +30,6 @@ const fallback = ( ); -const LazyDocViewerLogsOverview = dynamic(() => import('./components/doc_viewer_logs_overview'), { - fallback, -}); const LazyDocViewerLegacyTable = dynamic(() => import('./components/doc_viewer_table/legacy'), { fallback, }); @@ -50,7 +46,6 @@ export interface UnifiedDocViewerStart { export interface UnifiedDocViewerStartDeps { data: DataPublicPluginStart; - discoverShared: DiscoverSharedPublicStart; fieldFormats: FieldFormatsStart; fieldsMetadata: FieldsMetadataPublicStart; share: SharePluginStart; @@ -62,18 +57,6 @@ export class UnifiedDocViewerPublicPlugin private docViewsRegistry = new DocViewsRegistry(); public setup(core: CoreSetup) { - this.docViewsRegistry.add({ - id: 'doc_view_logs_overview', - title: i18n.translate('unifiedDocViewer.docViews.logsOverview.title', { - defaultMessage: 'Overview', - }), - order: 0, - enabled: false, // Disabled doc view by default, can be programmatically enabled using the DocViewsRegistry.prototype.enableById method. - component: (props) => { - return ; - }, - }); - this.docViewsRegistry.add({ id: 'doc_view_table', title: i18n.translate('unifiedDocViewer.docViews.table.tableTitle', { @@ -123,7 +106,7 @@ export class UnifiedDocViewerPublicPlugin public start(core: CoreStart, deps: UnifiedDocViewerStartDeps) { const { analytics, uiSettings } = core; - const { data, discoverShared, fieldFormats, fieldsMetadata, share } = deps; + const { data, fieldFormats, fieldsMetadata, share } = deps; const storage = new Storage(localStorage); const unifiedDocViewer = { registry: this.docViewsRegistry, @@ -131,7 +114,6 @@ export class UnifiedDocViewerPublicPlugin const services = { analytics, data, - discoverShared, fieldFormats, fieldsMetadata, storage, diff --git a/src/plugins/unified_doc_viewer/public/types.ts b/src/plugins/unified_doc_viewer/public/types.ts index e471fa87b85c1..9266328306aaf 100644 --- a/src/plugins/unified_doc_viewer/public/types.ts +++ b/src/plugins/unified_doc_viewer/public/types.ts @@ -11,7 +11,6 @@ export type { UnifiedDocViewerSetup, UnifiedDocViewerStart } from './plugin'; import type { AnalyticsServiceStart } from '@kbn/core-analytics-browser'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; -import type { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; import type { Storage } from '@kbn/kibana-utils-plugin/public'; @@ -22,7 +21,6 @@ import type { UnifiedDocViewerStart } from './plugin'; export interface UnifiedDocViewerServices { analytics: AnalyticsServiceStart; data: DataPublicPluginStart; - discoverShared: DiscoverSharedPublicStart; fieldFormats: FieldFormatsStart; fieldsMetadata: FieldsMetadataPublicStart; storage: Storage; diff --git a/test/accessibility/apps/discover.ts b/test/accessibility/apps/discover.ts index abdfe096efab2..ef92ee78f0899 100644 --- a/test/accessibility/apps/discover.ts +++ b/test/accessibility/apps/discover.ts @@ -122,8 +122,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // adding a11y tests for the new data grid it('a11y test on single document view', async () => { - await testSubjects.click('docTableExpandToggleColumn'); - await PageObjects.discover.clickDocViewerTab('doc_view_table'); + await dataGrid.clickRowToggle(); await a11y.testAppSnapshot(); }); diff --git a/test/functional/apps/dashboard/group1/url_field_formatter.ts b/test/functional/apps/dashboard/group1/url_field_formatter.ts index b408e0aed14d6..1cc49998770bf 100644 --- a/test/functional/apps/dashboard/group1/url_field_formatter.ts +++ b/test/functional/apps/dashboard/group1/url_field_formatter.ts @@ -25,6 +25,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const deployment = getService('deployment'); const retry = getService('retry'); const security = getService('security'); + const dataGrid = getService('dataGrid'); const checkUrl = async (fieldValue: string) => { const windowHandlers = await browser.getAllWindowHandles(); @@ -79,7 +80,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await common.setTime({ from, to }); await common.navigateToApp('discover'); await discover.selectIndexPattern('logstash-*'); - await testSubjects.click('docTableExpandToggleColumn'); + await dataGrid.clickRowToggle(); await retry.waitForWithTimeout(`${fieldName} is visible`, 30000, async () => { return await testSubjects.isDisplayed(`tableDocViewRow-${fieldName}-value`); }); @@ -87,8 +88,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { `[data-test-subj="tableDocViewRow-${fieldName}-value"] a` ); const fieldValue = await fieldLink.getVisibleText(); - await fieldLink.click(); await retry.try(async () => { + await fieldLink.click(); await checkUrl(fieldValue); }); }); diff --git a/test/functional/apps/discover/context_awareness/_data_source_profile.ts b/test/functional/apps/discover/context_awareness/_data_source_profile.ts index f3f7e35d7030b..594e6dee5dd78 100644 --- a/test/functional/apps/discover/context_awareness/_data_source_profile.ts +++ b/test/functional/apps/discover/context_awareness/_data_source_profile.ts @@ -73,7 +73,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataGrid.clickRowToggle({ rowIndex: 0 }); await testSubjects.existOrFail('docViewerTab-doc_view_table'); await testSubjects.existOrFail('docViewerTab-doc_view_source'); - await testSubjects.missingOrFail('docViewerTab-doc_view_logs_overview'); + await testSubjects.missingOrFail('docViewerTab-doc_view_example'); expect(await testSubjects.getVisibleText('docViewerRowDetailsTitle')).to.be('Result'); }); @@ -89,7 +89,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataGrid.clickRowToggle({ rowIndex: 0 }); await testSubjects.existOrFail('docViewerTab-doc_view_table'); await testSubjects.existOrFail('docViewerTab-doc_view_source'); - await testSubjects.existOrFail('docViewerTab-doc_view_logs_overview'); + await testSubjects.existOrFail('docViewerTab-doc_view_example'); expect(await testSubjects.getVisibleText('docViewerRowDetailsTitle')).to.be('Record #0'); }); }); @@ -136,7 +136,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataGrid.clickRowToggle({ rowIndex: 0 }); await testSubjects.existOrFail('docViewerTab-doc_view_table'); await testSubjects.existOrFail('docViewerTab-doc_view_source'); - await testSubjects.missingOrFail('docViewerTab-doc_view_logs_overview'); + await testSubjects.missingOrFail('docViewerTab-doc_view_example'); expect(await testSubjects.getVisibleText('docViewerRowDetailsTitle')).to.be('Document'); }); @@ -147,7 +147,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataGrid.clickRowToggle({ rowIndex: 0 }); await testSubjects.existOrFail('docViewerTab-doc_view_table'); await testSubjects.existOrFail('docViewerTab-doc_view_source'); - await testSubjects.existOrFail('docViewerTab-doc_view_logs_overview'); + await testSubjects.existOrFail('docViewerTab-doc_view_example'); expect(await testSubjects.getVisibleText('docViewerRowDetailsTitle')).to.be( 'Record #my-example-logs::XdQFDpABfGznVC1bCHLo::' ); diff --git a/test/functional/apps/discover/context_awareness/extensions/_get_doc_viewer.ts b/test/functional/apps/discover/context_awareness/extensions/_get_doc_viewer.ts new file mode 100644 index 0000000000000..7f60f92cf6191 --- /dev/null +++ b/test/functional/apps/discover/context_awareness/extensions/_get_doc_viewer.ts @@ -0,0 +1,73 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import kbnRison from '@kbn/rison'; +import type { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'discover']); + const testSubjects = getService('testSubjects'); + const dataViews = getService('dataViews'); + const dataGrid = getService('dataGrid'); + + describe('extension getDocViewer', () => { + describe('ES|QL mode', () => { + it('should render logs overview tab for logs data source', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { esql: 'from my-example-logs | sort @timestamp desc' }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataGrid.clickRowToggle(); + await testSubjects.existOrFail('docViewerTab-doc_view_table'); + await testSubjects.existOrFail('docViewerTab-doc_view_logs_overview'); + await dataGrid.clickDocViewerTab('doc_view_logs_overview'); + await testSubjects.existOrFail('unifiedDocViewLogsOverviewHeader'); + }); + + it('should not render logs overview tab for non-logs data source', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { esql: 'from my-example-metrics | sort @timestamp desc' }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataGrid.clickRowToggle(); + await testSubjects.existOrFail('docViewerTab-doc_view_table'); + await testSubjects.missingOrFail('docViewerTab-doc_view_logs_overview'); + }); + }); + + describe('data view mode', () => { + it('should render logs overview tab for logs data source', async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-logs'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataGrid.clickRowToggle(); + await testSubjects.existOrFail('docViewerTab-doc_view_table'); + await testSubjects.existOrFail('docViewerTab-doc_view_logs_overview'); + await dataGrid.clickDocViewerTab('doc_view_logs_overview'); + await testSubjects.existOrFail('unifiedDocViewLogsOverviewHeader'); + }); + + it('should not render logs overview tab for non-logs data source', async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-metrics'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataGrid.clickRowToggle(); + await testSubjects.existOrFail('docViewerTab-doc_view_table'); + await testSubjects.missingOrFail('docViewerTab-doc_view_logs_overview'); + }); + }); + }); +} diff --git a/test/functional/apps/discover/context_awareness/index.ts b/test/functional/apps/discover/context_awareness/index.ts index 5ea6bc9ea0e26..b642bcbce7476 100644 --- a/test/functional/apps/discover/context_awareness/index.ts +++ b/test/functional/apps/discover/context_awareness/index.ts @@ -36,5 +36,6 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid loadTestFile(require.resolve('./_root_profile')); loadTestFile(require.resolve('./_data_source_profile')); loadTestFile(require.resolve('./extensions/_get_row_indicator_provider')); + loadTestFile(require.resolve('./extensions/_get_doc_viewer')); }); } diff --git a/test/functional/apps/discover/group2_data_grid1/_data_grid_doc_table.ts b/test/functional/apps/discover/group2_data_grid1/_data_grid_doc_table.ts index 050900047c489..5d96a3d3fb321 100644 --- a/test/functional/apps/discover/group2_data_grid1/_data_grid_doc_table.ts +++ b/test/functional/apps/discover/group2_data_grid1/_data_grid_doc_table.ts @@ -10,7 +10,6 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { - const find = getService('find'); const dataGrid = getService('dataGrid'); const log = getService('log'); const retry = getService('retry'); @@ -95,10 +94,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); log.debug(`expanded document id: ${expandDocId}`); - await dataGrid.clickRowToggle(); - await find.clickByCssSelectorWhenNotDisabledWithoutRetry( - '#kbn_doc_viewer_tab_doc_view_source' - ); + await dataGrid.clickRowToggle({ defaultTabId: 'doc_view_source' }); await retry.waitForWithTimeout( 'document id in flyout matching the expanded document id', @@ -139,10 +135,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); log.debug(`expanded document id: ${expandDocId}`); - await dataGrid.clickRowToggle(); - await find.clickByCssSelectorWhenNotDisabledWithoutRetry( - '#kbn_doc_viewer_tab_doc_view_source' - ); + await dataGrid.clickRowToggle({ defaultTabId: 'doc_view_source' }); await retry.waitForWithTimeout( 'document id in flyout matching the expanded document id', diff --git a/test/functional/fixtures/kbn_archiver/discover/context_awareness.json b/test/functional/fixtures/kbn_archiver/discover/context_awareness.json index 5232a109e5799..a4a086afc11ce 100644 --- a/test/functional/fixtures/kbn_archiver/discover/context_awareness.json +++ b/test/functional/fixtures/kbn_archiver/discover/context_awareness.json @@ -46,4 +46,29 @@ "updated_at": "2024-06-12T22:23:21.331Z", "updated_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", "version": "WzEwLDFd" +} + +{ + "attributes": { + "allowHidden": false, + "fieldAttrs": "{}", + "fieldFormatMap": "{}", + "fields": "[]", + "name": "my-example-metrics", + "runtimeFieldMap": "{}", + "sourceFilters": "[]", + "timeFieldName": "@timestamp", + "title": "my-example-metrics" + }, + "coreMigrationVersion": "8.8.0", + "created_at": "2024-06-12T22:23:31.331Z", + "created_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "id": "795df528-add1-491a-8e25-72a862c4bf3b", + "managed": false, + "references": [], + "type": "index-pattern", + "typeMigrationVersion": "8.0.0", + "updated_at": "2024-06-12T22:23:21.331Z", + "updated_by": "u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0", + "version": "WzEwLDFc" } \ No newline at end of file diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index 25bbd3900513e..81f4bad5b5b1e 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -431,12 +431,12 @@ export class DiscoverPageObject extends FtrService { return await this.testSubjects.find('discoverDocTableFooter'); } - public async isShowingDocViewer() { - return await this.testSubjects.exists('kbnDocViewer'); + public isShowingDocViewer() { + return this.dataGrid.isShowingDocViewer(); } - public async clickDocViewerTab(id: string) { - return await this.find.clickByCssSelector(`#kbn_doc_viewer_tab_${id}`); + public clickDocViewerTab(id: string) { + return this.dataGrid.clickDocViewerTab(id); } public async expectSourceViewerToExist() { diff --git a/test/functional/services/data_grid.ts b/test/functional/services/data_grid.ts index caa7f5c6b02a2..7df0c5f49bf00 100644 --- a/test/functional/services/data_grid.ts +++ b/test/functional/services/data_grid.ts @@ -302,7 +302,10 @@ export class DataGridService extends FtrService { } public async clickRowToggle( - options: SelectOptions = { isAnchorRow: false, rowIndex: 0 } + { defaultTabId, ...options }: SelectOptions & { defaultTabId?: string } = { + isAnchorRow: false, + rowIndex: 0, + } ): Promise { const testSubj = options.isAnchorRow ? 'docTableExpandToggleColumnAnchor' @@ -321,11 +324,24 @@ export class DataGridService extends FtrService { }); if (toggle) { - await toggle.scrollIntoViewIfNecessary(); - await toggle.click(); + await this.retry.waitFor('doc viewer to open', async () => { + await toggle!.scrollIntoViewIfNecessary(); + await toggle!.click(); + return this.isShowingDocViewer(); + }); } else { throw new Error('Unable to find row toggle element'); } + + await this.clickDocViewerTab(defaultTabId ?? 'doc_view_table'); + } + + public async isShowingDocViewer() { + return await this.testSubjects.exists('kbnDocViewer'); + } + + public async clickDocViewerTab(id: string) { + return await this.find.clickByCssSelector(`#kbn_doc_viewer_tab_${id}`); } public async getDetailsRows(): Promise { diff --git a/x-pack/plugins/observability_solution/logs_explorer/kibana.jsonc b/x-pack/plugins/observability_solution/logs_explorer/kibana.jsonc index b19d2ad0b4e07..60127ebf28f51 100644 --- a/x-pack/plugins/observability_solution/logs_explorer/kibana.jsonc +++ b/x-pack/plugins/observability_solution/logs_explorer/kibana.jsonc @@ -19,6 +19,8 @@ "navigation", "share", "unifiedSearch", + "unifiedDocViewer", + "discoverShared", ], "optionalPlugins": [], "requiredBundles": ["controls","embeddable","fleet", "kibanaReact", "kibanaUtils"], diff --git a/x-pack/plugins/observability_solution/logs_explorer/public/customizations/logs_explorer_profile.tsx b/x-pack/plugins/observability_solution/logs_explorer/public/customizations/logs_explorer_profile.tsx index 42a3838311a98..7b193f4aafff8 100644 --- a/x-pack/plugins/observability_solution/logs_explorer/public/customizations/logs_explorer_profile.tsx +++ b/x-pack/plugins/observability_solution/logs_explorer/public/customizations/logs_explorer_profile.tsx @@ -11,6 +11,7 @@ import type { CustomizationCallback } from '@kbn/discover-plugin/public'; import { i18n } from '@kbn/i18n'; import { waitFor } from 'xstate/lib/waitFor'; import { dynamic } from '@kbn/shared-ux-utility'; +import { UnifiedDocViewerLogsOverview } from '@kbn/unified-doc-viewer-plugin/public'; import type { LogsExplorerController } from '../controller'; import type { LogsExplorerStartDeps } from '../types'; import { useKibanaContextForPluginProvider } from '../utils/use_kibana'; @@ -130,7 +131,23 @@ export const createLogsExplorerProfileCustomizations = }, }, docViewsRegistry: (registry) => { - registry.enableById('doc_view_logs_overview'); + const logsAIAssistantFeature = plugins.discoverShared.features.registry.getById( + 'observability-logs-ai-assistant' + ); + + registry.add({ + id: 'doc_view_logs_overview', + title: i18n.translate('xpack.logsExplorer.docViews.logsOverview.title', { + defaultMessage: 'Overview', + }), + order: 0, + component: (props) => ( + + ), + }); return registry; }, diff --git a/x-pack/plugins/observability_solution/logs_explorer/public/types.ts b/x-pack/plugins/observability_solution/logs_explorer/public/types.ts index cdd8feea3128c..6e4c5fdd4c66b 100644 --- a/x-pack/plugins/observability_solution/logs_explorer/public/types.ts +++ b/x-pack/plugins/observability_solution/logs_explorer/public/types.ts @@ -12,6 +12,7 @@ import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/publi import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; +import type { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public'; import type { LogsExplorerLocators } from '../common/locators'; import type { LogsExplorerProps } from './components/logs_explorer'; import type { CreateLogsExplorerController } from './controller'; @@ -37,4 +38,5 @@ export interface LogsExplorerStartDeps { navigation: NavigationPublicPluginStart; share: SharePluginStart; unifiedSearch: UnifiedSearchPublicPluginStart; + discoverShared: DiscoverSharedPublicStart; } diff --git a/x-pack/plugins/observability_solution/logs_explorer/tsconfig.json b/x-pack/plugins/observability_solution/logs_explorer/tsconfig.json index b3f8c978a67b4..230fe1987f0ff 100644 --- a/x-pack/plugins/observability_solution/logs_explorer/tsconfig.json +++ b/x-pack/plugins/observability_solution/logs_explorer/tsconfig.json @@ -45,6 +45,8 @@ "@kbn/xstate-utils", "@kbn/esql-utils", "@kbn/data-view-utils", + "@kbn/unified-doc-viewer-plugin", + "@kbn/discover-shared-plugin", ], "exclude": [ "target/**/*" diff --git a/x-pack/test/functional/apps/discover/feature_controls/discover_security.ts b/x-pack/test/functional/apps/discover/feature_controls/discover_security.ts index bfd732622b785..2d6b56c6d375f 100644 --- a/x-pack/test/functional/apps/discover/feature_controls/discover_security.ts +++ b/x-pack/test/functional/apps/discover/feature_controls/discover_security.ts @@ -17,7 +17,6 @@ export default function (ctx: FtrProviderContext) { const esArchiver = getService('esArchiver'); const esSupertest = getService('esSupertest'); const dataGrid = getService('dataGrid'); - const find = getService('find'); const indexPatterns = getService('indexPatterns'); const retry = getService('retry'); const monacoEditor = getService('monacoEditor'); @@ -524,9 +523,7 @@ export default function (ctx: FtrProviderContext) { ); // check the JSON tab - await find.clickByCssSelectorWhenNotDisabledWithoutRetry( - '#kbn_doc_viewer_tab_doc_view_source' - ); + await dataGrid.clickDocViewerTab('doc_view_source'); await retry.waitForWithTimeout( 'index in flyout JSON tab is matching the logstash index', 5000, diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/_data_source_profile.ts b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/_data_source_profile.ts index 9ce2e79d8f586..38942bf87a3cf 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/_data_source_profile.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/_data_source_profile.ts @@ -68,7 +68,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataGrid.clickRowToggle({ rowIndex: 0 }); await testSubjects.existOrFail('docViewerTab-doc_view_table'); await testSubjects.existOrFail('docViewerTab-doc_view_source'); - await testSubjects.missingOrFail('docViewerTab-doc_view_logs_overview'); + await testSubjects.missingOrFail('docViewerTab-doc_view_example'); expect(await testSubjects.getVisibleText('docViewerRowDetailsTitle')).to.be('Result'); }); @@ -84,7 +84,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataGrid.clickRowToggle({ rowIndex: 0 }); await testSubjects.existOrFail('docViewerTab-doc_view_table'); await testSubjects.existOrFail('docViewerTab-doc_view_source'); - await testSubjects.existOrFail('docViewerTab-doc_view_logs_overview'); + await testSubjects.existOrFail('docViewerTab-doc_view_example'); expect(await testSubjects.getVisibleText('docViewerRowDetailsTitle')).to.be('Record #0'); }); }); @@ -127,7 +127,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataGrid.clickRowToggle({ rowIndex: 0 }); await testSubjects.existOrFail('docViewerTab-doc_view_table'); await testSubjects.existOrFail('docViewerTab-doc_view_source'); - await testSubjects.missingOrFail('docViewerTab-doc_view_logs_overview'); + await testSubjects.missingOrFail('docViewerTab-doc_view_example'); expect(await testSubjects.getVisibleText('docViewerRowDetailsTitle')).to.be('Document'); }); @@ -138,7 +138,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataGrid.clickRowToggle({ rowIndex: 0 }); await testSubjects.existOrFail('docViewerTab-doc_view_table'); await testSubjects.existOrFail('docViewerTab-doc_view_source'); - await testSubjects.existOrFail('docViewerTab-doc_view_logs_overview'); + await testSubjects.existOrFail('docViewerTab-doc_view_example'); expect(await testSubjects.getVisibleText('docViewerRowDetailsTitle')).to.be( 'Record #my-example-logs::XdQFDpABfGznVC1bCHLo::' ); diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_doc_viewer.ts b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_doc_viewer.ts new file mode 100644 index 0000000000000..d9ee508161d92 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_doc_viewer.ts @@ -0,0 +1,72 @@ +/* + * 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 kbnRison from '@kbn/rison'; +import type { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'discover']); + const testSubjects = getService('testSubjects'); + const dataViews = getService('dataViews'); + const dataGrid = getService('dataGrid'); + + describe('extension getDocViewer', () => { + describe('ES|QL mode', () => { + it('should render logs overview tab for logs data source', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { esql: 'from my-example-logs | sort @timestamp desc' }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataGrid.clickRowToggle(); + await testSubjects.existOrFail('docViewerTab-doc_view_table'); + await testSubjects.existOrFail('docViewerTab-doc_view_logs_overview'); + await dataGrid.clickDocViewerTab('doc_view_logs_overview'); + await testSubjects.existOrFail('unifiedDocViewLogsOverviewHeader'); + }); + + it('should not render logs overview tab for non-logs data source', async () => { + const state = kbnRison.encode({ + dataSource: { type: 'esql' }, + query: { esql: 'from my-example-metrics | sort @timestamp desc' }, + }); + await PageObjects.common.navigateToApp('discover', { + hash: `/?_a=${state}`, + }); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataGrid.clickRowToggle(); + await testSubjects.existOrFail('docViewerTab-doc_view_table'); + await testSubjects.missingOrFail('docViewerTab-doc_view_logs_overview'); + }); + }); + + describe('data view mode', () => { + it('should render logs overview tab for logs data source', async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-logs'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataGrid.clickRowToggle(); + await testSubjects.existOrFail('docViewerTab-doc_view_table'); + await testSubjects.existOrFail('docViewerTab-doc_view_logs_overview'); + await dataGrid.clickDocViewerTab('doc_view_logs_overview'); + await testSubjects.existOrFail('unifiedDocViewLogsOverviewHeader'); + }); + + it('should not render logs overview tab for non-logs data source', async () => { + await PageObjects.common.navigateToApp('discover'); + await dataViews.switchTo('my-example-metrics'); + await PageObjects.discover.waitUntilSearchingHasFinished(); + await dataGrid.clickRowToggle(); + await testSubjects.existOrFail('docViewerTab-doc_view_table'); + await testSubjects.missingOrFail('docViewerTab-doc_view_logs_overview'); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts index 3fddfdaf3ef7a..4e52a62bc6f54 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/index.ts @@ -37,5 +37,6 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid loadTestFile(require.resolve('./_root_profile')); loadTestFile(require.resolve('./_data_source_profile')); loadTestFile(require.resolve('./extensions/_get_row_indicator_provider')); + loadTestFile(require.resolve('./extensions/_get_doc_viewer')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_table.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_table.ts index fafd9b72c50db..2bbbd8353c0ff 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_table.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group2/_data_grid_doc_table.ts @@ -9,7 +9,6 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { - const find = getService('find'); const dataGrid = getService('dataGrid'); const log = getService('log'); const retry = getService('retry'); @@ -96,10 +95,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); log.debug(`expanded document id: ${expandDocId}`); - await dataGrid.clickRowToggle(); - await find.clickByCssSelectorWhenNotDisabledWithoutRetry( - '#kbn_doc_viewer_tab_doc_view_source' - ); + await dataGrid.clickRowToggle({ defaultTabId: 'doc_view_source' }); await retry.waitForWithTimeout( 'document id in flyout matching the expanded document id', @@ -140,10 +136,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); log.debug(`expanded document id: ${expandDocId}`); - await dataGrid.clickRowToggle(); - await find.clickByCssSelectorWhenNotDisabledWithoutRetry( - '#kbn_doc_viewer_tab_doc_view_source' - ); + await dataGrid.clickRowToggle({ defaultTabId: 'doc_view_source' }); await retry.waitForWithTimeout( 'document id in flyout matching the expanded document id',