diff --git a/src/plugins/ai_assistant_management/observability/public/helpers/test_helper.tsx b/src/plugins/ai_assistant_management/observability/public/helpers/test_helper.tsx index 2e1b8e0def9b4..b03b1fd8a37d8 100644 --- a/src/plugins/ai_assistant_management/observability/public/helpers/test_helper.tsx +++ b/src/plugins/ai_assistant_management/observability/public/helpers/test_helper.tsx @@ -13,8 +13,7 @@ import { render as testLibRender } from '@testing-library/react'; import { coreMock } from '@kbn/core/public/mocks'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import translations from '@kbn/translations-plugin/translations/ja-JP.json'; - -import { mockObservabilityAIAssistantService } from '@kbn/observability-ai-assistant-plugin/public'; +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; import { RouterProvider } from '@kbn/typed-react-router-config'; import { AppContextProvider } from '../context/app_context'; import { RedirectToHomeIfUnauthorized } from '../routes/components/redirect_to_home_if_unauthorized'; @@ -62,14 +61,7 @@ export const render = (component: React.ReactNode, params?: { show: boolean }) = http: coreStart.http, application: coreStart.application, notifications: coreStart.notifications, - observabilityAIAssistant: { - service: mockObservabilityAIAssistantService, - useGenAIConnectors: () => ({ - loading: false, - selectConnector: () => {}, - reloadConnectors: () => {}, - }), - }, + observabilityAIAssistant: observabilityAIAssistantPluginMock.createStartContract(), uiSettings: coreStart.uiSettings, setBreadcrumbs: () => {}, }} diff --git a/x-pack/plugins/apm/public/components/app/error_group_details/error_sampler/error_sample_contextual_insight.tsx b/x-pack/plugins/apm/public/components/app/error_group_details/error_sampler/error_sample_contextual_insight.tsx index bf50eec3afb96..701050302da2a 100644 --- a/x-pack/plugins/apm/public/components/app/error_group_details/error_sampler/error_sample_contextual_insight.tsx +++ b/x-pack/plugins/apm/public/components/app/error_group_details/error_sampler/error_sample_contextual_insight.tsx @@ -7,12 +7,11 @@ import { EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { - useObservabilityAIAssistant, - ContextualInsight, type Message, MessageRole, } from '@kbn/observability-ai-assistant-plugin/public'; import React, { useMemo, useState } from 'react'; +import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context'; import { APMError } from '../../../../../typings/es_schemas/ui/apm_error'; import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; import { ErrorSampleDetailTabContent } from './error_sample_detail'; @@ -25,7 +24,9 @@ export function ErrorSampleContextualInsight({ error: APMError; transaction?: Transaction; }) { - const aiAssistant = useObservabilityAIAssistant(); + const { + observabilityAIAssistant: { ObservabilityAIAssistantContextualInsight }, + } = useApmPluginContext(); const [logStacktrace, setLogStacktrace] = useState(''); const [exceptionStacktrace, setExceptionStacktrace] = useState(''); @@ -72,10 +73,10 @@ ${exceptionStacktrace}` ]; }, [error, transaction, logStacktrace, exceptionStacktrace]); - return aiAssistant.isEnabled() && messages ? ( + return ObservabilityAIAssistantContextualInsight && messages ? ( <> - - + {ObservabilityAIAssistantActionMenuItem ? ( + + ) : null} ); } diff --git a/x-pack/plugins/apm/public/components/routing/app_root/index.tsx b/x-pack/plugins/apm/public/components/routing/app_root/index.tsx index 8021fe3c6c88e..85df672363ce1 100644 --- a/x-pack/plugins/apm/public/components/routing/app_root/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root/index.tsx @@ -12,7 +12,6 @@ import { } from '@kbn/kibana-react-plugin/public'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public'; import { HeaderMenuPortal, InspectorContextProvider, @@ -75,48 +74,44 @@ export function ApmAppRoot({ services={{ ...core, ...pluginsStart, storage, ...apmServices }} > - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/x-pack/plugins/exploratory_view/public/application/application.test.tsx b/x-pack/plugins/exploratory_view/public/application/application.test.tsx index 23203930616e4..a0adaca0dbded 100644 --- a/x-pack/plugins/exploratory_view/public/application/application.test.tsx +++ b/x-pack/plugins/exploratory_view/public/application/application.test.tsx @@ -13,7 +13,7 @@ import { AppMountParameters, CoreStart } from '@kbn/core/public'; import { themeServiceMock } from '@kbn/core/public/mocks'; import { ExploratoryViewPublicPluginsStart } from '../plugin'; import { renderApp } from '.'; -import { mockObservabilityAIAssistantService } from '@kbn/observability-ai-assistant-plugin/public'; +import { mockService } from '@kbn/observability-ai-assistant-plugin/public/mock'; describe('renderApp', () => { const originalConsole = global.console; @@ -43,7 +43,7 @@ describe('renderApp', () => { }, }, usageCollection: { reportUiCounter: noop }, - observabilityAIAssistant: { service: mockObservabilityAIAssistantService }, + observabilityAIAssistant: { service: mockService }, } as unknown as ExploratoryViewPublicPluginsStart; const core = { diff --git a/x-pack/plugins/exploratory_view/public/application/index.tsx b/x-pack/plugins/exploratory_view/public/application/index.tsx index c59aa090f75b7..f3189e7cf660b 100644 --- a/x-pack/plugins/exploratory_view/public/application/index.tsx +++ b/x-pack/plugins/exploratory_view/public/application/index.tsx @@ -16,7 +16,6 @@ import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-pl import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; -import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public'; import { PluginContext } from '../context/plugin_context'; import { routes } from '../routes'; import { ExploratoryViewPublicPluginsStart } from '../plugin'; @@ -68,47 +67,43 @@ export const renderApp = ({ const ApplicationUsageTrackingProvider = usageCollection?.components.ApplicationUsageTrackingProvider ?? React.Fragment; - const aiAssistantService = plugins.observabilityAIAssistant.service; - ReactDOM.render( - - + - - - - -
+ + +
+ - - - -
-
-
- - - - + + +
+
+
+
+
+
, diff --git a/x-pack/plugins/exploratory_view/public/application/types.ts b/x-pack/plugins/exploratory_view/public/application/types.ts index 7d6cc14dfe771..3cdaee088db7a 100644 --- a/x-pack/plugins/exploratory_view/public/application/types.ts +++ b/x-pack/plugins/exploratory_view/public/application/types.ts @@ -20,6 +20,7 @@ import { EmbeddableStateTransfer } from '@kbn/embeddable-plugin/public'; import { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { ObservabilityAIAssistantPluginStart } from '@kbn/observability-ai-assistant-plugin/public'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { LensPublicStart } from '@kbn/lens-plugin/public'; import { SharePluginStart } from '@kbn/share-plugin/public'; @@ -41,6 +42,7 @@ export interface ObservabilityAppServices { lens: LensPublicStart; navigation: NavigationPublicPluginStart; notifications: NotificationsStart; + observabilityAIAssistant: ObservabilityAIAssistantPluginStart; overlays: OverlayStart; savedObjectsClient: SavedObjectsStart['client']; share: SharePluginStart; diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.test.tsx index 5d43f5bd1e6df..0070517a81ca4 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.test.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.test.tsx @@ -12,6 +12,7 @@ import { sampleAttribute } from '../../configurations/test_data/sample_attribute import * as pluginHook from '../../../../../hooks/use_plugin_context'; import { TypedLensByValueInput } from '@kbn/lens-plugin/public'; import { ExpViewActionMenuContent } from './action_menu'; +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; jest.spyOn(pluginHook, 'usePluginContext').mockReturnValue({ appMountParameters: { @@ -19,6 +20,24 @@ jest.spyOn(pluginHook, 'usePluginContext').mockReturnValue({ }, } as any); +const mockObservabilityAIAssistant = observabilityAIAssistantPluginMock.createStartContract(); + +jest.mock('../../hooks/use_kibana', () => { + const originalModule = jest.requireActual('../../hooks/use_kibana'); + return { + ...originalModule, + useKibana: () => { + const { services } = originalModule.useKibana(); + return { + services: { + ...services, + observabilityAIAssistant: mockObservabilityAIAssistant, + }, + }; + }, + }; +}); + describe('Action Menu', function () { afterAll(() => { jest.clearAllMocks(); diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.tsx index f8e86388131aa..f0e387a1554df 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.tsx @@ -9,14 +9,9 @@ import React, { useState } from 'react'; import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { LensEmbeddableInput, TypedLensByValueInput } from '@kbn/lens-plugin/public'; -import { - ObservabilityAIAssistantActionMenuItem, - useObservabilityAIAssistantOptional, -} from '@kbn/observability-ai-assistant-plugin/public'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; import { EmbedAction } from '../../header/embed_action'; -import { ObservabilityAppServices } from '../../../../../application/types'; import { AddToCaseAction } from '../../header/add_to_case_action'; +import { useKibana } from '../../hooks/use_kibana'; export function ExpViewActionMenuContent({ timeRange, @@ -25,16 +20,16 @@ export function ExpViewActionMenuContent({ timeRange?: { from: string; to: string }; lensAttributes: TypedLensByValueInput['attributes'] | null; }) { - const kServices = useKibana().services; - - const { lens, isDev } = kServices; + const { + lens, + isDev, + observabilityAIAssistant: { ObservabilityAIAssistantActionMenuItem }, + } = useKibana().services; const [isSaveOpen, setIsSaveOpen] = useState(false); const LensSaveModalComponent = lens.SaveModalComponent; - const service = useObservabilityAIAssistantOptional(); - return ( <>
- {service?.isEnabled() ? ( + {ObservabilityAIAssistantActionMenuItem ? ( diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.test.tsx index 83cae3e8b4ebb..e8b01b10316c3 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.test.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.test.tsx @@ -12,6 +12,7 @@ import { ExploratoryView } from './exploratory_view'; import * as obsvDataViews from '../../../utils/observability_data_views/observability_data_views'; import * as pluginHook from '../../../hooks/use_plugin_context'; import { createStubIndexPattern } from '@kbn/data-plugin/common/stubs'; +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; jest.spyOn(pluginHook, 'usePluginContext').mockReturnValue({ appMountParameters: { @@ -19,6 +20,24 @@ jest.spyOn(pluginHook, 'usePluginContext').mockReturnValue({ }, } as any); +const mockObservabilityAIAssistant = observabilityAIAssistantPluginMock.createStartContract(); + +jest.mock('./hooks/use_kibana', () => { + const originalModule = jest.requireActual('./hooks/use_kibana'); + return { + ...originalModule, + useKibana: () => { + const { services } = originalModule.useKibana(); + return { + services: { + ...services, + observabilityAIAssistant: mockObservabilityAIAssistant, + }, + }; + }, + }; +}); + describe('ExploratoryView', () => { mockAppDataView(); diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.tsx index a67618cf5f93c..9b5fadb9c1bf8 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/exploratory_view.tsx @@ -16,9 +16,8 @@ import { EuiFlexItem, } from '@elastic/eui'; import { PanelDirection } from '@elastic/eui/src/components/resizable_container/types'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; import { TypedLensByValueInput } from '@kbn/lens-plugin/public'; -import { ExploratoryViewPublicPluginsStart } from '../../../plugin'; +import { useKibana } from './hooks/use_kibana'; import { useSeriesStorage } from './hooks/use_series_storage'; import { useLensAttributes } from './hooks/use_lens_attributes'; import { useAppDataViewContext } from './hooks/use_app_data_view'; @@ -38,7 +37,7 @@ export function ExploratoryView({ }) { const { services: { lens }, - } = useKibana(); + } = useKibana(); const seriesBuilderRef = useRef(null); const wrapperRef = useRef(null); diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/hooks/use_kibana.ts b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/hooks/use_kibana.ts new file mode 100644 index 0000000000000..57c0c731d4245 --- /dev/null +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/hooks/use_kibana.ts @@ -0,0 +1,20 @@ +/* + * 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 { CoreStart } from '@kbn/core/public'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { ExploratoryViewPublicPluginsStart } from '../../../../plugin'; + +export type StartServices = CoreStart & + ExploratoryViewPublicPluginsStart & + AdditionalServices & { + isDev: boolean; + }; +const useTypedKibana = () => + useKibana>(); + +export { useTypedKibana as useKibana }; diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/index.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/index.tsx index 152593abaf06a..392420ee547f8 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/index.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/index.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { useHistory } from 'react-router-dom'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; + import { createKbnUrlStateStorage, withNotifyOnErrors, @@ -17,7 +17,7 @@ import { import { TypedLensByValueInput } from '@kbn/lens-plugin/public'; import { useBreadcrumbs, useTrackPageview } from '@kbn/observability-shared-plugin/public'; import { ExploratoryView } from './exploratory_view'; -import { ExploratoryViewPublicPluginsStart } from '../../../plugin'; +import { useKibana } from './hooks/use_kibana'; import { DataViewContextProvider } from './hooks/use_app_data_view'; import { UrlStorageContextProvider } from './hooks/use_series_storage'; import { RefreshButton } from './header/refresh_button'; @@ -39,7 +39,7 @@ export function ExploratoryViewPage({ }: ExploratoryViewPageProps) { const { services: { uiSettings, notifications, observabilityShared }, - } = useKibana(); + } = useKibana(); const history = useHistory(); diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/lens_embeddable.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/lens_embeddable.tsx index 6ec631403b229..2613d39e79391 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/lens_embeddable.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/lens_embeddable.tsx @@ -9,10 +9,9 @@ import { i18n } from '@kbn/i18n'; import React, { Dispatch, SetStateAction, useCallback, useState } from 'react'; import styled from 'styled-components'; import { LensEmbeddableInput, TypedLensByValueInput } from '@kbn/lens-plugin/public'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; import { useUiTracker } from '@kbn/observability-shared-plugin/public'; import { useSeriesStorage } from './hooks/use_series_storage'; -import { ExploratoryViewPublicPluginsStart } from '../../../plugin'; +import { useKibana } from './hooks/use_kibana'; import { useExpViewTimeRange } from './hooks/use_time_range'; import { parseRelativeDate } from './components/date_range_picker'; import { trackTelemetryOnLoad } from './utils/telemetry'; @@ -30,7 +29,7 @@ export function LensEmbeddable(props: Props) { const { lensAttributes, setChartTimeRangeContext } = props; const { services: { lens, notifications }, - } = useKibana(); + } = useKibana(); const LensComponent = lens?.EmbeddableComponent; const LensSaveModalComponent = lens?.SaveModalComponent; diff --git a/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/components/log_rate_analysis.tsx b/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/components/log_rate_analysis.tsx index a8ebb5c884b6b..c1f9231a3a1a9 100644 --- a/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/components/log_rate_analysis.tsx +++ b/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/components/log_rate_analysis.tsx @@ -19,12 +19,7 @@ import { import { LogRateAnalysisContent, type LogRateAnalysisResultsData } from '@kbn/aiops-plugin/public'; import { Rule } from '@kbn/alerting-plugin/common'; import { TopAlert } from '@kbn/observability-plugin/public'; -import { - ContextualInsight, - useObservabilityAIAssistant, - type Message, - MessageRole, -} from '@kbn/observability-ai-assistant-plugin/public'; +import { type Message, MessageRole } from '@kbn/observability-ai-assistant-plugin/public'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { i18n } from '@kbn/i18n'; import { ALERT_END } from '@kbn/rule-data-utils'; @@ -54,7 +49,11 @@ interface SignificantFieldValue { export const LogRateAnalysis: FC = ({ rule, alert }) => { const { services } = useKibanaContextForPlugin(); - const { dataViews, logsShared } = services; + const { + dataViews, + logsShared, + observabilityAIAssistant: { ObservabilityAIAssistantContextualInsight }, + } = services; const [dataView, setDataView] = useState(); const [esSearchQuery, setEsSearchQuery] = useState(); const [logRateAnalysisParams, setLogRateAnalysisParams] = useState< @@ -180,8 +179,6 @@ export const LogRateAnalysis: FC = ({ r ); }; - const aiAssistant = useObservabilityAIAssistant(); - const messages = useMemo(() => { const hasLogRateAnalysisParams = logRateAnalysisParams && logRateAnalysisParams.significantFieldValues?.length > 0; @@ -290,9 +287,12 @@ export const LogRateAnalysis: FC = ({ r - {aiAssistant.isEnabled() && messages ? ( + {ObservabilityAIAssistantContextualInsight && messages ? ( - + ) : null} diff --git a/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/index.tsx b/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/index.tsx index 05b8c53f9ded9..0f94a1d528c13 100644 --- a/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/index.tsx +++ b/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/index.tsx @@ -20,7 +20,6 @@ import { EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; import { get, identity } from 'lodash'; -import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public'; import { useLogView } from '@kbn/logs-shared-plugin/public'; import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; import { @@ -44,10 +43,7 @@ const AlertDetailsAppSection = ({ alert, setAlertSummaryFields, }: AlertDetailsAppSectionProps) => { - const { - logsShared, - observabilityAIAssistant: { service: observabilityAIAssistantService }, - } = useKibanaContextForPlugin().services; + const { logsShared } = useKibanaContextForPlugin().services; const theme = useTheme(); const timeRange = getPaddedAlertTimeRange(alert.fields[ALERT_START]!, alert.fields[ALERT_END]); const alertEnd = alert.fields[ALERT_END] ? moment(alert.fields[ALERT_END]).valueOf() : undefined; @@ -245,14 +241,12 @@ const AlertDetailsAppSection = ({ }; return ( - - - {getLogRatioChart()} - {getLogCountChart()} - {getLogRateAnalysisSection()} - {getLogsHistoryChart()} - - + + {getLogRatioChart()} + {getLogCountChart()} + {getLogRateAnalysisSection()} + {getLogsHistoryChart()} + ); }; diff --git a/x-pack/plugins/infra/public/apps/common_providers.tsx b/x-pack/plugins/infra/public/apps/common_providers.tsx index 67c13bad48c96..158e0b95293e9 100644 --- a/x-pack/plugins/infra/public/apps/common_providers.tsx +++ b/x-pack/plugins/infra/public/apps/common_providers.tsx @@ -9,10 +9,7 @@ import { AppMountParameters, CoreStart } from '@kbn/core/public'; import React from 'react'; import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; -import { - ObservabilityAIAssistantProvider, - ObservabilityAIAssistantPluginStart, -} from '@kbn/observability-ai-assistant-plugin/public'; +import type { ObservabilityAIAssistantPluginStart } from '@kbn/observability-ai-assistant-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { NavigationWarningPromptProvider } from '@kbn/observability-shared-plugin/public'; import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; @@ -44,11 +41,9 @@ export const CommonInfraProviders: React.FC<{ - - - {children} - - + + {children} + diff --git a/x-pack/plugins/infra/public/components/asset_details/__stories__/decorator.tsx b/x-pack/plugins/infra/public/components/asset_details/__stories__/decorator.tsx index e55a70978a748..f1ec2d43aa86f 100644 --- a/x-pack/plugins/infra/public/components/asset_details/__stories__/decorator.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/__stories__/decorator.tsx @@ -28,8 +28,6 @@ import type { AlertSummaryWidgetProps } from '@kbn/triggers-actions-ui-plugin/pu import { defaultLogViewAttributes } from '@kbn/logs-shared-plugin/common'; import { DataView, DataViewField } from '@kbn/data-views-plugin/common'; import { MemoryRouter } from 'react-router-dom'; -import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public'; -import { ObservabilityAIAssistantService } from '@kbn/observability-ai-assistant-plugin/public/types'; import { PluginConfigProvider } from '../../../containers/plugin_config_context'; import type { PluginKibanaContextValue } from '../../../hooks/use_kibana'; import { SourceProvider } from '../../../containers/metrics_source'; @@ -199,20 +197,7 @@ export const DecorateWithKibanaContext: DecoratorFn = (story) => { - true, - callApi: () => {}, - getCurrentUser: () => {}, - getLicense: () => {}, - getLicenseManagementLocator: () => {}, - start: {}, - } as unknown as ObservabilityAIAssistantService - } - > - {story()} - + {story()} diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/process_row.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/process_row.tsx index a874e071e6c23..c6f98c6d1422c 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/process_row.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/process_row.tsx @@ -23,12 +23,8 @@ import { } from '@elastic/eui'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import useToggle from 'react-use/lib/useToggle'; -import { - useObservabilityAIAssistant, - type Message, - MessageRole, - ContextualInsight, -} from '@kbn/observability-ai-assistant-plugin/public'; +import { type Message, MessageRole } from '@kbn/observability-ai-assistant-plugin/public'; +import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; import { Process } from './types'; import { ProcessRowCharts } from './process_row_charts'; @@ -38,7 +34,10 @@ interface Props { supportAIAssistant?: boolean; } export const ContextualInsightProcessRow = ({ command }: { command: string }) => { - const aiAssistant = useObservabilityAIAssistant(); + const { + observabilityAIAssistant: { ObservabilityAIAssistantContextualInsight }, + } = useKibanaContextForPlugin().services; + const explainProcessMessages = useMemo(() => { if (!command) { return undefined; @@ -98,11 +97,11 @@ export const ContextualInsightProcessRow = ({ command }: { command: string }) => }, [command]); return ( <> - {aiAssistant.isEnabled() && explainProcessMessages ? ( + {ObservabilityAIAssistantContextualInsight && explainProcessMessages ? ( - diff --git a/x-pack/plugins/infra/public/pages/logs/page_content.tsx b/x-pack/plugins/infra/public/pages/logs/page_content.tsx index ca6c281a47309..39868c74797d4 100644 --- a/x-pack/plugins/infra/public/pages/logs/page_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/page_content.tsx @@ -11,9 +11,9 @@ import React, { useContext } from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { HeaderMenuPortal, useLinkProps } from '@kbn/observability-shared-plugin/public'; -import { ObservabilityAIAssistantActionMenuItem } from '@kbn/observability-ai-assistant-plugin/public'; import { LazyAlertDropdownWrapper } from '../../alerting/log_threshold'; import { HelpCenterContent } from '../../components/help_center_content'; +import { useKibanaContextForPlugin } from '../../hooks/use_kibana'; import { useReadOnlyBadge } from '../../hooks/use_readonly_badge'; import { HeaderActionMenuContext } from '../../utils/header_action_menu_provider'; import { RedirectWithQueryParams } from '../../utils/redirect_with_query_params'; @@ -26,11 +26,15 @@ import { StateMachinePlayground } from '../../observability_logs/xstate_helpers' import { NotFoundPage } from '../404'; export const LogsPageContent: React.FunctionComponent = () => { - const enableDeveloperRoutes = isDevMode(); const uiCapabilities = useKibana().services.application?.capabilities; const { setHeaderActionMenu, theme$ } = useContext(HeaderActionMenuContext); - const kibana = useKibana(); + const { + application: { getUrlForApp }, + observabilityAIAssistant: { ObservabilityAIAssistantActionMenuItem }, + } = useKibanaContextForPlugin().services; + + const enableDeveloperRoutes = isDevMode(); useReadOnlyBadge(!uiCapabilities?.logs?.save); @@ -76,13 +80,15 @@ export const LogsPageContent: React.FunctionComponent = () => { {ADD_DATA_LABEL} - + {ObservabilityAIAssistantActionMenuItem ? ( + + ) : null} )} diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index 46f2f1c124767..e617edcebf965 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -13,8 +13,8 @@ import { Routes, Route } from '@kbn/shared-ux-router'; import { EuiErrorBoundary, EuiHeaderLinks, EuiHeaderLink } from '@elastic/eui'; import { useKibana, useUiSetting } from '@kbn/kibana-react-plugin/public'; import { HeaderMenuPortal, useLinkProps } from '@kbn/observability-shared-plugin/public'; -import { ObservabilityAIAssistantActionMenuItem } from '@kbn/observability-ai-assistant-plugin/public'; import { enableInfrastructureHostsView } from '@kbn/observability-plugin/common'; +import { useKibanaContextForPlugin } from '../../hooks/use_kibana'; import { MetricsSourceConfigurationProperties } from '../../../common/metrics_sources'; import { HelpCenterContent } from '../../components/help_center_content'; import { useReadOnlyBadge } from '../../hooks/use_readonly_badge'; @@ -44,6 +44,9 @@ const ADD_DATA_LABEL = i18n.translate('xpack.infra.metricsHeaderAddDataButtonLab }); export const InfrastructurePage = () => { + const { + observabilityAIAssistant: { ObservabilityAIAssistantActionMenuItem }, + } = useKibanaContextForPlugin().services; const config = usePluginConfig(); const uiCapabilities = useKibana().services.application?.capabilities; const { setHeaderActionMenu, theme$ } = useContext(HeaderActionMenuContext); @@ -95,7 +98,9 @@ export const InfrastructurePage = () => { > {ADD_DATA_LABEL} - + {ObservabilityAIAssistantActionMenuItem ? ( + + ) : null} )} diff --git a/x-pack/plugins/logs_shared/public/components/log_ai_assistant/index.tsx b/x-pack/plugins/logs_shared/public/components/log_ai_assistant/index.tsx index 0bfb9f516209c..78b696388e165 100644 --- a/x-pack/plugins/logs_shared/public/components/log_ai_assistant/index.tsx +++ b/x-pack/plugins/logs_shared/public/components/log_ai_assistant/index.tsx @@ -4,25 +4,18 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { ComponentType } from 'react'; -import { Optional } from '@kbn/utility-types'; +import { ObservabilityAIAssistantPluginStart } from '@kbn/observability-ai-assistant-plugin/public'; +import React from 'react'; import { dynamic } from '../../../common/dynamic'; -import type { LogAIAssistantDeps } from './log_ai_assistant'; export const LogAIAssistant = dynamic(() => import('./log_ai_assistant')); -interface LogAIAssistantFactoryDeps { - observabilityAIAssistant: LogAIAssistantDeps['observabilityAIAssistant']; -} - -export type LogAIAssistantComponent = ComponentType< - Optional ->; - export function createLogAIAssistant({ - observabilityAIAssistant: aiAssistantService, -}: LogAIAssistantFactoryDeps): LogAIAssistantComponent { - return ({ observabilityAIAssistant = aiAssistantService, ...props }) => ( + observabilityAIAssistant, +}: { + observabilityAIAssistant: ObservabilityAIAssistantPluginStart; +}) { + return ({ ...props }) => ( ); } diff --git a/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.tsx b/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.tsx index 8a8c755d70ff7..79adfde85540e 100644 --- a/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.tsx +++ b/x-pack/plugins/logs_shared/public/components/log_ai_assistant/log_ai_assistant.tsx @@ -8,12 +8,9 @@ import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { - ContextualInsight, type Message, - ObservabilityAIAssistantPluginStart, MessageRole, - ObservabilityAIAssistantProvider, - useObservabilityAIAssistant, + type ObservabilityAIAssistantPluginStart, } from '@kbn/observability-ai-assistant-plugin/public'; import { LogEntryField } from '../../../common'; import { explainLogMessageTitle, similarLogMessagesTitle } from './translations'; @@ -23,16 +20,14 @@ export interface LogAIAssistantDocument { } export interface LogAIAssistantProps { + observabilityAIAssistant: ObservabilityAIAssistantPluginStart; doc: LogAIAssistantDocument | undefined; } -export interface LogAIAssistantDeps extends LogAIAssistantProps { - observabilityAIAssistant: ObservabilityAIAssistantPluginStart['service']; -} - -export const LogAIAssistant = withProviders(({ doc }: LogAIAssistantProps) => { - const aiAssistant = useObservabilityAIAssistant(); - +export const LogAIAssistant = ({ + doc, + observabilityAIAssistant: { ObservabilityAIAssistantContextualInsight }, +}: LogAIAssistantProps) => { const explainLogMessageMessages = useMemo(() => { if (!doc) { return undefined; @@ -75,18 +70,18 @@ export const LogAIAssistant = withProviders(({ doc }: LogAIAssistantProps) => { return ( - {aiAssistant.isEnabled() && explainLogMessageMessages ? ( + {ObservabilityAIAssistantContextualInsight && explainLogMessageMessages ? ( - ) : null} - {aiAssistant.isEnabled() && similarLogMessageMessages ? ( + {ObservabilityAIAssistantContextualInsight && similarLogMessageMessages ? ( - { ) : null} ); -}); +}; // eslint-disable-next-line import/no-default-export export default LogAIAssistant; - -function withProviders(Component: React.FunctionComponent) { - return function ComponentWithProviders({ - observabilityAIAssistant: observabilityAIAssistantService, - ...props - }: LogAIAssistantDeps) { - return ( - - - - ); - }; -} diff --git a/x-pack/plugins/logs_shared/public/components/logging/log_entry_flyout/log_entry_flyout.tsx b/x-pack/plugins/logs_shared/public/components/logging/log_entry_flyout/log_entry_flyout.tsx index 2c5913d282e1d..aca2638a6120c 100644 --- a/x-pack/plugins/logs_shared/public/components/logging/log_entry_flyout/log_entry_flyout.tsx +++ b/x-pack/plugins/logs_shared/public/components/logging/log_entry_flyout/log_entry_flyout.tsx @@ -100,12 +100,6 @@ export const LogEntryFlyout = ({ onSetFieldFilter, logViewReference, }: LogEntryFlyoutProps) => { - const { - services: { - observabilityAIAssistant: { service: observabilityAIAssistantService }, - }, - } = useKibanaContextForPlugin(); - const { cancelRequest: cancelLogEntryRequest, errors: logEntryErrors, @@ -119,6 +113,8 @@ export const LogEntryFlyout = ({ logEntryId, }); + const { observabilityAIAssistant } = useKibanaContextForPlugin().services; + useEffect(() => { if (logViewReference && logEntryId) { fetchLogEntry(); @@ -186,10 +182,7 @@ export const LogEntryFlyout = ({ > - + diff --git a/x-pack/plugins/logs_shared/public/plugin.ts b/x-pack/plugins/logs_shared/public/plugin.ts index 372ca2c124bcc..092e95570db7f 100644 --- a/x-pack/plugins/logs_shared/public/plugin.ts +++ b/x-pack/plugins/logs_shared/public/plugin.ts @@ -33,9 +33,7 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { search: data.search, }); - const LogAIAssistant = createLogAIAssistant({ - observabilityAIAssistant: observabilityAIAssistant.service, - }); + const LogAIAssistant = createLogAIAssistant({ observabilityAIAssistant }); return { logViews, diff --git a/x-pack/plugins/logs_shared/public/types.ts b/x-pack/plugins/logs_shared/public/types.ts index c0379c6fc21fb..2a2e9c1cf742d 100644 --- a/x-pack/plugins/logs_shared/public/types.ts +++ b/x-pack/plugins/logs_shared/public/types.ts @@ -17,7 +17,7 @@ import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { ObservabilityAIAssistantPluginStart } from '@kbn/observability-ai-assistant-plugin/public'; import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import { LogAIAssistantComponent } from './components/log_ai_assistant'; +import type { LogAIAssistantProps } from './components/log_ai_assistant/log_ai_assistant'; // import type { OsqueryPluginStart } from '../../osquery/public'; import { LogViewsServiceSetup, LogViewsServiceStart } from './services/log_views'; @@ -28,7 +28,7 @@ export interface LogsSharedClientSetupExports { export interface LogsSharedClientStartExports { logViews: LogViewsServiceStart; - LogAIAssistant: LogAIAssistantComponent; + LogAIAssistant: (props: Omit) => JSX.Element; } // eslint-disable-next-line @typescript-eslint/no-empty-interface diff --git a/x-pack/plugins/observability/public/application/application.test.tsx b/x-pack/plugins/observability/public/application/application.test.tsx index 3b385fee702f5..5b01eb93b788b 100644 --- a/x-pack/plugins/observability/public/application/application.test.tsx +++ b/x-pack/plugins/observability/public/application/application.test.tsx @@ -15,7 +15,7 @@ import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; import { ConfigSchema, ObservabilityPublicPluginsStart } from '../plugin'; import { createObservabilityRuleTypeRegistryMock } from '../rules/observability_rule_type_registry_mock'; import { renderApp } from '.'; -import { mockObservabilityAIAssistantService } from '@kbn/observability-ai-assistant-plugin/public'; +import { mockService } from '@kbn/observability-ai-assistant-plugin/public/mock'; describe('renderApp', () => { const originalConsole = global.console; @@ -51,7 +51,7 @@ describe('renderApp', () => { }, }, usageCollection: { reportUiCounter: noop }, - observabilityAIAssistant: { service: mockObservabilityAIAssistantService }, + observabilityAIAssistant: { service: mockService }, } as unknown as ObservabilityPublicPluginsStart; const core = { diff --git a/x-pack/plugins/observability/public/application/index.tsx b/x-pack/plugins/observability/public/application/index.tsx index 5eb3fa65849cd..7081005487fc3 100644 --- a/x-pack/plugins/observability/public/application/index.tsx +++ b/x-pack/plugins/observability/public/application/index.tsx @@ -19,7 +19,6 @@ import { KibanaThemeProvider } from '@kbn/react-kibana-context-theme'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; -import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public'; import { PluginContext } from '../context/plugin_context/plugin_context'; import { ConfigSchema, ObservabilityPublicPluginsStart } from '../plugin'; import { routes } from '../routes/routes'; @@ -101,32 +100,30 @@ export const renderApp = ({ isServerless, }} > - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/x-pack/plugins/observability/public/context/plugin_context/plugin_context.tsx b/x-pack/plugins/observability/public/context/plugin_context/plugin_context.tsx index d9ae99760a7ad..11d2b05fc235b 100644 --- a/x-pack/plugins/observability/public/context/plugin_context/plugin_context.tsx +++ b/x-pack/plugins/observability/public/context/plugin_context/plugin_context.tsx @@ -5,11 +5,11 @@ * 2.0. */ -import { AppMountParameters } from '@kbn/core/public'; import { createContext } from 'react'; +import type { AppMountParameters } from '@kbn/core/public'; import type { LazyObservabilityPageTemplateProps } from '@kbn/observability-shared-plugin/public'; -import { ObservabilityRuleTypeRegistry } from '../../rules/create_observability_rule_type_registry'; -import { ConfigSchema } from '../../plugin'; +import type { ObservabilityRuleTypeRegistry } from '../../rules/create_observability_rule_type_registry'; +import type { ConfigSchema } from '../../plugin'; export interface PluginContextValue { config: ConfigSchema; diff --git a/x-pack/plugins/observability/public/pages/alert_details/alert_details.test.tsx b/x-pack/plugins/observability/public/pages/alert_details/alert_details.test.tsx index f2a7a4d72d66f..9d537453d4ead 100644 --- a/x-pack/plugins/observability/public/pages/alert_details/alert_details.test.tsx +++ b/x-pack/plugins/observability/public/pages/alert_details/alert_details.test.tsx @@ -13,6 +13,9 @@ import { casesPluginMock } from '@kbn/cases-plugin/public/mocks'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import * as useUiSettingHook from '@kbn/kibana-react-plugin/public/ui_settings/use_ui_setting'; import { useBreadcrumbs } from '@kbn/observability-shared-plugin/public'; +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; +import { ruleTypeRegistryMock } from '@kbn/triggers-actions-ui-plugin/public/application/rule_type_registry.mock'; +import { RuleTypeModel, ValidationResult } from '@kbn/triggers-actions-ui-plugin/public'; import { Subset } from '../../typings'; import { render } from '../../utils/test_helper'; @@ -22,8 +25,6 @@ import { useFetchAlertDetail } from '../../hooks/use_fetch_alert_detail'; import { AlertDetails } from './alert_details'; import { ConfigSchema } from '../../plugin'; import { alert, alertWithNoData } from './mock/alert'; -import { ruleTypeRegistryMock } from '@kbn/triggers-actions-ui-plugin/public/application/rule_type_registry.mock'; -import { RuleTypeModel, ValidationResult } from '@kbn/triggers-actions-ui-plugin/public'; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -45,17 +46,20 @@ const ruleTypeRegistry = ruleTypeRegistryMock.create(); const useKibanaMock = useKibana as jest.Mock; +const mockObservabilityAIAssistant = observabilityAIAssistantPluginMock.createStartContract(); + const mockKibana = () => { useKibanaMock.mockReturnValue({ services: { ...kibanaStartMock.startContract(), - theme: {}, cases: casesPluginMock.createStartContract(), http: { basePath: { prepend: jest.fn(), }, }, + observabilityAIAssistant: mockObservabilityAIAssistant, + theme: {}, triggersActionsUi: { ruleTypeRegistry, }, diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts.test.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts.test.tsx index cf59af003a788..8977e9ae3e4f0 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts.test.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts.test.tsx @@ -15,6 +15,7 @@ import { RUNNING_MAINTENANCE_WINDOW_1 } from '@kbn/alerts-ui-shared/src/maintena import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { MAINTENANCE_WINDOW_FEATURE_ID } from '@kbn/alerting-plugin/common/maintenance_window'; +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; import { ObservabilityPublicPluginsStart } from '../../plugin'; import { AlertsPage } from './alerts'; @@ -35,10 +36,19 @@ mockUseKibanaReturnValue.services.application.capabilities = { }, }; +const mockObservabilityAIAssistant = observabilityAIAssistantPluginMock.createStartContract(); + jest.mock('../../utils/kibana_react', () => ({ __esModule: true, - useKibana: jest.fn(() => mockUseKibanaReturnValue), + useKibana: jest.fn(() => ({ + ...mockUseKibanaReturnValue, + services: { + ...mockUseKibanaReturnValue.services, + observabilityAIAssistant: mockObservabilityAIAssistant, + }, + })), })); + jest.mock('@kbn/kibana-react-plugin/public', () => ({ __esModule: true, useKibana: jest.fn(() => mockUseKibanaReturnValue), diff --git a/x-pack/plugins/observability/public/pages/alerts/components/alert_actions.test.tsx b/x-pack/plugins/observability/public/pages/alerts/components/alert_actions.test.tsx index b8e216ded52fb..ab7080e1d6d60 100644 --- a/x-pack/plugins/observability/public/pages/alerts/components/alert_actions.test.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/components/alert_actions.test.tsx @@ -4,11 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import React from 'react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { act } from '@testing-library/react-hooks'; -import { kibanaStartMock } from '../../../utils/kibana_react.mock'; -import React from 'react'; import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; +import { kibanaStartMock } from '../../../utils/kibana_react.mock'; +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; import { AlertActions, ObservabilityAlertActionsProps } from './alert_actions'; import { inventoryThresholdAlertEs } from '../../../rules/fixtures/example_alerts'; import { RULE_DETAILS_PAGE_ID } from '../../rule_details/constants'; @@ -42,6 +43,9 @@ mockUseKibanaReturnValue.services.cases.hooks.useCasesAddToExistingCaseModal.moc mockUseKibanaReturnValue.services.cases.helpers.canUseCases.mockReturnValue(allCasesPermissions()); +const { ObservabilityAIAssistantActionMenuItem, ObservabilityAIAssistantContextualInsight } = + observabilityAIAssistantPluginMock.createStartContract(); + jest.mock('../../../utils/kibana_react', () => ({ __esModule: true, useKibana: jest.fn(() => mockUseKibanaReturnValue), @@ -72,6 +76,8 @@ jest.spyOn(pluginContext, 'usePluginContext').mockImplementation(() => ({ plugins: {} as ObservabilityPublicPluginsStart, observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(), ObservabilityPageTemplate: KibanaPageTemplate, + ObservabilityAIAssistantActionMenuItem, + ObservabilityAIAssistantContextualInsight, })); describe('ObservabilityActions component', () => { diff --git a/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu.tsx b/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu.tsx index 111acb054e163..b57c512565fc1 100644 --- a/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu.tsx +++ b/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu.tsx @@ -8,22 +8,22 @@ import { EuiHeaderLink, EuiHeaderLinks } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { - ObservabilityAIAssistantActionMenuItem, - useObservabilityAIAssistantOptional, -} from '@kbn/observability-ai-assistant-plugin/public'; + import { useKibana } from '../../../../utils/kibana_react'; import { usePluginContext } from '../../../../hooks/use_plugin_context'; import HeaderMenuPortal from './header_menu_portal'; export function HeaderMenu(): React.ReactElement | null { - const { http, theme } = useKibana().services; + const { + http, + theme, + observabilityAIAssistant: { ObservabilityAIAssistantActionMenuItem }, + } = useKibana().services; + const { appMountParameters: { setHeaderActionMenu }, } = usePluginContext(); - const aiAssistant = useObservabilityAIAssistantOptional(); - return ( @@ -34,7 +34,7 @@ export function HeaderMenu(): React.ReactElement | null { > {addDataLinkText} - {aiAssistant?.isEnabled() ? : null} + {ObservabilityAIAssistantActionMenuItem ? : null} ); diff --git a/x-pack/plugins/observability/public/pages/overview/components/sections/apm/apm_section.test.tsx b/x-pack/plugins/observability/public/pages/overview/components/sections/apm/apm_section.test.tsx index 23d3af1167b99..b5befe3c3083d 100644 --- a/x-pack/plugins/observability/public/pages/overview/components/sections/apm/apm_section.test.tsx +++ b/x-pack/plugins/observability/public/pages/overview/components/sections/apm/apm_section.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import * as fetcherHook from '@kbn/observability-shared-plugin/public/hooks/use_fetcher'; +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; import { render, data as dataMock } from '../../../../../utils/test_helper'; import { CoreStart } from '@kbn/core/public'; import { ConfigSchema, ObservabilityPublicPluginsStart } from '../../../../../plugin'; @@ -27,6 +28,9 @@ jest.mock('react-router-dom', () => ({ useHistory: jest.fn(), })); +const { ObservabilityAIAssistantActionMenuItem, ObservabilityAIAssistantContextualInsight } = + observabilityAIAssistantPluginMock.createStartContract(); + describe('APMSection', () => { const bucketSize = { intervalString: '60s', bucketSize: 60, dateFormat: 'YYYY-MM-DD HH:mm' }; @@ -61,6 +65,8 @@ describe('APMSection', () => { plugins: {} as ObservabilityPublicPluginsStart, observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(), ObservabilityPageTemplate: KibanaPageTemplate, + ObservabilityAIAssistantActionMenuItem, + ObservabilityAIAssistantContextualInsight, })); }); diff --git a/x-pack/plugins/observability/public/pages/rules/rules.test.tsx b/x-pack/plugins/observability/public/pages/rules/rules.test.tsx index 6f18d308780ad..904578fe75a03 100644 --- a/x-pack/plugins/observability/public/pages/rules/rules.test.tsx +++ b/x-pack/plugins/observability/public/pages/rules/rules.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { CoreStart } from '@kbn/core/public'; +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { ObservabilityPublicPluginsStart } from '../../plugin'; import { RulesPage } from './rules'; @@ -19,10 +20,17 @@ import { AppMountParameters } from '@kbn/core/public'; import { ALERTS_FEATURE_ID } from '@kbn/alerting-plugin/common'; const mockUseKibanaReturnValue = kibanaStartMock.startContract(); +const mockObservabilityAIAssistant = observabilityAIAssistantPluginMock.createStartContract(); jest.mock('../../utils/kibana_react', () => ({ __esModule: true, - useKibana: jest.fn(() => mockUseKibanaReturnValue), + useKibana: jest.fn(() => ({ + ...mockUseKibanaReturnValue, + services: { + ...mockUseKibanaReturnValue.services, + observabilityAIAssistant: mockObservabilityAIAssistant, + }, + })), })); jest.mock('@kbn/observability-shared-plugin/public'); diff --git a/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx b/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx index 5a06bbd9bf2db..22691aaa2b49c 100644 --- a/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx +++ b/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { fireEvent, screen, waitFor } from '@testing-library/react'; import type { Capabilities } from '@kbn/core/public'; +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; import { useKibana } from '../../utils/kibana_react'; import { useParams, useLocation } from 'react-router-dom'; @@ -84,6 +85,7 @@ const mockKibana = () => { addError: jest.fn(), }, }, + observabilityAIAssistant: observabilityAIAssistantPluginMock.createStartContract(), share: { url: { locators: { diff --git a/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.test.tsx b/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.test.tsx index 8d4d45a08d709..5a90e43ab0c03 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.test.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.test.tsx @@ -9,6 +9,7 @@ import { fireEvent, waitFor, cleanup } from '@testing-library/react'; import { createBrowserHistory } from 'history'; import React from 'react'; import Router from 'react-router-dom'; +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; import { paths } from '../../../common/locators/paths'; import { buildSlo } from '../../data/slo/slo'; @@ -103,6 +104,7 @@ const mockKibana = () => { addSuccess: mockAddSuccess, }, }, + observabilityAIAssistant: observabilityAIAssistantPluginMock.createStartContract(), storage: { get: () => {}, }, diff --git a/x-pack/plugins/observability/public/pages/slos/slos.test.tsx b/x-pack/plugins/observability/public/pages/slos/slos.test.tsx index 1f28e822b96f9..61e6190b79956 100644 --- a/x-pack/plugins/observability/public/pages/slos/slos.test.tsx +++ b/x-pack/plugins/observability/public/pages/slos/slos.test.tsx @@ -7,7 +7,7 @@ import { act, fireEvent, screen, waitFor } from '@testing-library/react'; import React from 'react'; - +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; @@ -90,6 +90,7 @@ const mockKibana = () => { addError: mockAddError, }, }, + observabilityAIAssistant: observabilityAIAssistantPluginMock.createStartContract(), share: { url: { locators: { diff --git a/x-pack/plugins/observability/public/pages/slos_welcome/slos_welcome.test.tsx b/x-pack/plugins/observability/public/pages/slos_welcome/slos_welcome.test.tsx index a6b4f671d306c..8290ecc2988be 100644 --- a/x-pack/plugins/observability/public/pages/slos_welcome/slos_welcome.test.tsx +++ b/x-pack/plugins/observability/public/pages/slos_welcome/slos_welcome.test.tsx @@ -17,6 +17,7 @@ import { SlosWelcomePage } from './slos_welcome'; import { emptySloList, sloList } from '../../data/slo/slo'; import { useCapabilities } from '../../hooks/slo/use_capabilities'; import { paths } from '../../../common/locators/paths'; +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; jest.mock('@kbn/observability-shared-plugin/public'); jest.mock('../../utils/kibana_react'); @@ -33,16 +34,19 @@ const useGlobalDiagnosisMock = useFetchSloGlobalDiagnosis as jest.Mock; const mockNavigate = jest.fn(); +const mockObservabilityAIAssistant = observabilityAIAssistantPluginMock.createStartContract(); + const mockKibana = () => { useKibanaMock.mockReturnValue({ services: { - theme: {}, application: { navigateToUrl: mockNavigate }, + theme: {}, http: { basePath: { prepend: (url: string) => url, }, }, + observabilityAIAssistant: mockObservabilityAIAssistant, }, }); }; diff --git a/x-pack/plugins/observability/public/utils/test_helper.tsx b/x-pack/plugins/observability/public/utils/test_helper.tsx index 9428f887ed93c..61fb7bbade53f 100644 --- a/x-pack/plugins/observability/public/utils/test_helper.tsx +++ b/x-pack/plugins/observability/public/utils/test_helper.tsx @@ -62,6 +62,7 @@ export const render = (component: React.ReactNode, config: Subset exploratoryView: { createExploratoryViewUrl: jest.fn(), getAppDataView: jest.fn(), + // eslint-disable-next-line @kbn/i18n/strings_should_be_translated_with_i18n ExploratoryViewEmbeddable: () =>
Embeddable exploratory view
, }, }} diff --git a/x-pack/plugins/observability_ai_assistant/public/application.tsx b/x-pack/plugins/observability_ai_assistant/public/application.tsx index 15ed0243bd921..10e5403bba436 100644 --- a/x-pack/plugins/observability_ai_assistant/public/application.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/application.tsx @@ -20,6 +20,8 @@ import type { ObservabilityAIAssistantService, } from './types'; +// This is the Conversation application. + export function Application({ coreStart, history, @@ -36,6 +38,7 @@ export function Application({ const theme = useMemo(() => { return { theme$ }; }, [theme$]); + return ( diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/welcome_message.test.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/welcome_message.test.tsx index ce18f0fb0878d..56dd52c417a3b 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/welcome_message.test.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/welcome_message.test.tsx @@ -97,17 +97,23 @@ const render = (component: React.ReactElement) => { return rtlRender({component}); }; -describe('Welcome Message', () => { - beforeEach(() => { - useKibanaMock.mockReturnValue({ - services: { - application: { navigateToApp, capabilities: {} }, - http: { basePath: { prepend: jest.fn((path: string) => `/${path}`) } }, +const defaultMockServices = { + services: { + application: { navigateToApp, capabilities: {} }, + http: { basePath: { prepend: jest.fn((path: string) => `/${path}`) } }, + plugins: { + start: { triggersActionsUi: { getAddConnectorFlyout: () => , }, }, - }); + }, + }, +}; + +describe('Welcome Message', () => { + beforeEach(() => { + useKibanaMock.mockReturnValue(defaultMockServices); }); describe('when no connectors are available', () => { @@ -159,8 +165,14 @@ describe('Welcome Message', () => { }, }, }, - triggersActionsUi: { - getAddConnectorFlyout: () => , + plugins: { + start: { + triggersActionsUi: { + getAddConnectorFlyout: () => ( + + ), + }, + }, }, }, }); diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/welcome_message.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/welcome_message.tsx index afd9cbdf0e76e..bae4cf0d5a92e 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/welcome_message.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/welcome_message.tsx @@ -45,7 +45,11 @@ export function WelcomeMessage({ const { application: { navigateToApp, capabilities }, - triggersActionsUi: { getAddConnectorFlyout: ConnectorFlyout }, + plugins: { + start: { + triggersActionsUi: { getAddConnectorFlyout: ConnectorFlyout }, + }, + }, } = useKibana().services; const [connectorFlyoutOpen, setConnectorFlyoutOpen] = useState(false); diff --git a/x-pack/plugins/observability_ai_assistant/public/components/insight/insight.tsx b/x-pack/plugins/observability_ai_assistant/public/components/insight/insight.tsx index 4ae3c685a4c97..bfe01db7fb49f 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/insight/insight.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/insight/insight.tsx @@ -122,15 +122,13 @@ function ChatContent({ ); } -export function Insight({ - messages, - title, - dataTestSubj, -}: { +export interface InsightProps { messages: Message[]; title: string; dataTestSubj?: string; -}) { +} + +export function Insight({ messages, title, dataTestSubj }: InsightProps) { const [hasOpened, setHasOpened] = useState(false); const connectors = useGenAIConnectors(); diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_kibana.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_kibana.ts index 0362415d7a232..af2a06e010552 100644 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_kibana.ts +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_kibana.ts @@ -9,10 +9,9 @@ import { useKibana } from '@kbn/kibana-react-plugin/public'; import type { CoreStart } from '@kbn/core/public'; import type { ObservabilityAIAssistantPluginStartDependencies } from '../types'; -export type StartServices = CoreStart & - ObservabilityAIAssistantPluginStartDependencies & { - plugins: { start: ObservabilityAIAssistantPluginStartDependencies }; - } & TAdditionalServices & {}; +export type StartServices = CoreStart & { + plugins: { start: ObservabilityAIAssistantPluginStartDependencies }; +} & TAdditionalServices & {}; const useTypedKibana = () => useKibana>(); diff --git a/x-pack/plugins/observability_ai_assistant/public/index.ts b/x-pack/plugins/observability_ai_assistant/public/index.ts index fb77855d8898f..a5e33a8433861 100644 --- a/x-pack/plugins/observability_ai_assistant/public/index.ts +++ b/x-pack/plugins/observability_ai_assistant/public/index.ts @@ -5,8 +5,6 @@ * 2.0. */ import type { PluginInitializer, PluginInitializerContext } from '@kbn/core/public'; -import { lazy } from 'react'; -import { withSuspense } from '@kbn/shared-ux-utility'; import { ObservabilityAIAssistantPlugin } from './plugin'; import type { ObservabilityAIAssistantPluginSetup, @@ -16,21 +14,6 @@ import type { ConfigSchema, ObservabilityAIAssistantService, } from './types'; -export { mockService as mockObservabilityAIAssistantService } from './utils/storybook_decorator'; - -export const ContextualInsight = withSuspense( - lazy(() => import('./components/insight/insight').then((m) => ({ default: m.Insight }))) -); - -export const ObservabilityAIAssistantActionMenuItem = withSuspense( - lazy(() => - import('./components/action_menu_item/action_menu_item').then((m) => ({ - default: m.ObservabilityAIAssistantActionMenuItem, - })) - ) -); - -export { ObservabilityAIAssistantProvider } from './context/observability_ai_assistant_provider'; export type { ObservabilityAIAssistantPluginSetup, @@ -38,11 +21,6 @@ export type { ObservabilityAIAssistantService, }; -export { - useObservabilityAIAssistant, - useObservabilityAIAssistantOptional, -} from './hooks/use_observability_ai_assistant'; - export type { Conversation, Message, KnowledgeBaseEntry } from '../common'; export { MessageRole, KnowledgeBaseEntryRole } from '../common'; diff --git a/x-pack/plugins/observability_ai_assistant/public/mock.tsx b/x-pack/plugins/observability_ai_assistant/public/mock.tsx new file mode 100644 index 0000000000000..54dbd1d06c610 --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/public/mock.tsx @@ -0,0 +1,97 @@ +/* + * 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 React from 'react'; +import { Observable } from 'rxjs'; +import { i18n } from '@kbn/i18n'; +import { AuthenticatedUser } from '@kbn/security-plugin-types-common'; +import { SharePluginStart } from '@kbn/share-plugin/public'; +import { StreamingChatResponseEvent } from '../common/conversation_complete'; +import { ObservabilityAIAssistantAPIClient } from './api'; +import type { + ObservabilityAIAssistantChatService, + ObservabilityAIAssistantPluginSetup, + ObservabilityAIAssistantPluginStart, + ObservabilityAIAssistantService, + PendingMessage, +} from './types'; +import { buildFunctionElasticsearch, buildFunctionServiceSummary } from './utils/builders'; + +export const mockChatService: ObservabilityAIAssistantChatService = { + analytics: { + optIn: () => {}, + reportEvent: () => {}, + telemetryCounter$: new Observable(), + }, + chat: (options) => new Observable(), + complete: (options) => new Observable(), + getContexts: () => [], + getFunctions: () => [buildFunctionElasticsearch(), buildFunctionServiceSummary()], + renderFunction: (name) => ( +
+ {i18n.translate('xpack.observabilityAiAssistant.chatService.div.helloLabel', { + defaultMessage: 'Hello', + })} + {name} +
+ ), + hasFunction: () => true, + hasRenderFunction: () => true, +}; + +export const mockService: ObservabilityAIAssistantService = { + isEnabled: () => true, + start: async () => { + return mockChatService; + }, + callApi: {} as ObservabilityAIAssistantAPIClient, + getCurrentUser: async (): Promise => ({ + username: 'user', + roles: [], + enabled: true, + authentication_realm: { name: 'foo', type: '' }, + lookup_realm: { name: 'foo', type: '' }, + authentication_provider: { name: '', type: '' }, + authentication_type: '', + elastic_cloud_user: false, + }), + getLicense: () => new Observable(), + getLicenseManagementLocator: () => + ({ + url: {}, + navigate: () => {}, + } as unknown as SharePluginStart), + register: () => {}, +}; + +function createSetupContract(): ObservabilityAIAssistantPluginSetup { + return {}; +} + +function createStartContract(): ObservabilityAIAssistantPluginStart { + return { + service: mockService, + + ObservabilityAIAssistantActionMenuItem: (() => ( + // eslint-disable-next-line @kbn/i18n/strings_should_be_translated_with_i18n +
Im a button
+ )) as unknown as ObservabilityAIAssistantPluginStart['ObservabilityAIAssistantActionMenuItem'], + ObservabilityAIAssistantContextualInsight: ( + // eslint-disable-next-line @kbn/i18n/strings_should_be_translated_with_i18n +
I give insight
+ ) as unknown as ObservabilityAIAssistantPluginStart['ObservabilityAIAssistantContextualInsight'], + useGenAIConnectors: () => ({ + loading: false, + selectConnector: () => {}, + reloadConnectors: () => {}, + }), + }; +} + +export const observabilityAIAssistantPluginMock = { + createSetupContract, + createStartContract, +}; diff --git a/x-pack/plugins/observability_ai_assistant/public/plugin.tsx b/x-pack/plugins/observability_ai_assistant/public/plugin.tsx index 64a1f4ae8d2fa..5ee13a1c5b6e8 100644 --- a/x-pack/plugins/observability_ai_assistant/public/plugin.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/plugin.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; +import React, { ComponentType, lazy, Ref } from 'react'; import ReactDOM from 'react-dom'; import { AppNavLinkStatus, @@ -17,6 +17,8 @@ import { } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import type { Logger } from '@kbn/logging'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { withSuspense } from '@kbn/shared-ux-utility'; import { createService } from './service/create_service'; import { useGenAIConnectorsWithoutContext } from './hooks/use_genai_connectors'; import type { @@ -28,6 +30,7 @@ import type { ObservabilityAIAssistantService, } from './types'; import { registerTelemetryEventTypes } from './analytics'; +import { ObservabilityAIAssistantProvider } from './context/observability_ai_assistant_provider'; export class ObservabilityAIAssistantPlugin implements @@ -117,9 +120,54 @@ export class ObservabilityAIAssistantPlugin }); }); + const withProviders =

( + Component: ComponentType

, + services: Omit & { + plugins: { start: ObservabilityAIAssistantPluginStartDependencies }; + } + ) => + React.forwardRef((props: P, ref: Ref) => ( + + + + + + )); + + const services = { + ...coreStart, + plugins: { + start: pluginsStart, + }, + }; + + const isEnabled = service.isEnabled(); + return { service, useGenAIConnectors: () => useGenAIConnectorsWithoutContext(service), + ObservabilityAIAssistantContextualInsight: isEnabled + ? withSuspense( + withProviders( + lazy(() => + import('./components/insight/insight').then((m) => ({ default: m.Insight })) + ), + services + ) + ) + : null, + ObservabilityAIAssistantActionMenuItem: isEnabled + ? withSuspense( + withProviders( + lazy(() => + import('./components/action_menu_item/action_menu_item').then((m) => ({ + default: m.ObservabilityAIAssistantActionMenuItem, + })) + ), + services + ) + ) + : null, }; } } diff --git a/x-pack/plugins/observability_ai_assistant/public/types.ts b/x-pack/plugins/observability_ai_assistant/public/types.ts index a664638365eaf..3c53243ffd48f 100644 --- a/x-pack/plugins/observability_ai_assistant/public/types.ts +++ b/x-pack/plugins/observability_ai_assistant/public/types.ts @@ -28,6 +28,8 @@ import type { } from '@kbn/data-views-plugin/public'; import type { LicensingPluginStart, ILicense } from '@kbn/licensing-plugin/public'; import type { SharePluginStart } from '@kbn/share-plugin/public'; +import { ForwardRefExoticComponent, RefAttributes } from 'react'; +import { WithSuspenseExtendedDeps } from '@kbn/shared-ux-utility'; import type { ContextDefinition, FunctionDefinition, @@ -38,6 +40,7 @@ import type { ObservabilityAIAssistantAPIClient } from './api'; import type { PendingMessage } from '../common/types'; import type { StreamingChatResponseEvent } from '../common/conversation_complete'; import type { UseGenAIConnectorsResult } from './hooks/use_genai_connectors'; +import type { InsightProps } from './components/insight/insight'; /* eslint-disable @typescript-eslint/no-empty-interface*/ @@ -92,12 +95,10 @@ export type ChatRegistrationRenderFunction = ({}: { registerRenderFunction: RegisterRenderFunctionDefinition; }) => Promise; -export interface ObservabilityAIAssistantPluginStart { - service: ObservabilityAIAssistantService; - useGenAIConnectors: () => UseGenAIConnectorsResult; -} +export interface ConfigSchema {} + +export type { PendingMessage }; -export interface ObservabilityAIAssistantPluginSetup {} export interface ObservabilityAIAssistantPluginSetupDependencies { dataViews: DataViewsPublicPluginSetup; features: FeaturesPluginSetup; @@ -106,6 +107,7 @@ export interface ObservabilityAIAssistantPluginSetupDependencies { security: SecurityPluginSetup; triggersActionsUi: TriggersAndActionsUIPublicPluginSetup; } + export interface ObservabilityAIAssistantPluginStartDependencies { dataViews: DataViewsPublicPluginStart; features: FeaturesPluginStart; @@ -117,6 +119,14 @@ export interface ObservabilityAIAssistantPluginStartDependencies { triggersActionsUi: TriggersAndActionsUIPublicPluginStart; } -export interface ConfigSchema {} +export interface ObservabilityAIAssistantPluginSetup {} -export type { PendingMessage }; +export interface ObservabilityAIAssistantPluginStart { + service: ObservabilityAIAssistantService; + ObservabilityAIAssistantContextualInsight: React.ForwardRefExoticComponent | null; + ObservabilityAIAssistantActionMenuItem: ForwardRefExoticComponent< + Pick & WithSuspenseExtendedDeps, 'css' | 'key' | 'analytics'> & + RefAttributes<{}> + > | null; + useGenAIConnectors: () => UseGenAIConnectorsResult; +} diff --git a/x-pack/plugins/observability_ai_assistant/public/utils/storybook_decorator.tsx b/x-pack/plugins/observability_ai_assistant/public/utils/storybook_decorator.tsx index 04a30ce53059d..0914bedbf82f2 100644 --- a/x-pack/plugins/observability_ai_assistant/public/utils/storybook_decorator.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/utils/storybook_decorator.tsx @@ -4,69 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { i18n } from '@kbn/i18n'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import type { AuthenticatedUser } from '@kbn/security-plugin/common'; -import type { SharePluginStart } from '@kbn/share-plugin/public'; import React, { ComponentType } from 'react'; -import { Observable } from 'rxjs'; -import type { StreamingChatResponseEvent } from '../../common/conversation_complete'; -import { ObservabilityAIAssistantAPIClient } from '../api'; import { ObservabilityAIAssistantChatServiceProvider } from '../context/observability_ai_assistant_chat_service_provider'; import { ObservabilityAIAssistantProvider } from '../context/observability_ai_assistant_provider'; -import type { - ObservabilityAIAssistantChatService, - ObservabilityAIAssistantService, - PendingMessage, -} from '../types'; -import { buildFunctionElasticsearch, buildFunctionServiceSummary } from './builders'; - -const chatService: ObservabilityAIAssistantChatService = { - analytics: { - optIn: () => {}, - reportEvent: () => {}, - telemetryCounter$: new Observable(), - }, - chat: (options) => new Observable(), - complete: (options) => new Observable(), - getContexts: () => [], - getFunctions: () => [buildFunctionElasticsearch(), buildFunctionServiceSummary()], - renderFunction: (name) => ( -

- {i18n.translate('xpack.observabilityAiAssistant.chatService.div.helloLabel', { - defaultMessage: 'Hello', - })} - {name} -
- ), - hasFunction: () => true, - hasRenderFunction: () => true, -}; - -export const mockService: ObservabilityAIAssistantService = { - isEnabled: () => true, - start: async () => { - return chatService; - }, - callApi: {} as ObservabilityAIAssistantAPIClient, - getCurrentUser: async (): Promise => ({ - username: 'user', - roles: [], - enabled: true, - authentication_realm: { name: 'foo', type: '' }, - lookup_realm: { name: 'foo', type: '' }, - authentication_provider: { name: '', type: '' }, - authentication_type: '', - elastic_cloud_user: false, - }), - getLicense: () => new Observable(), - getLicenseManagementLocator: () => - ({ - url: {}, - navigate: () => {}, - } as unknown as SharePluginStart), - register: () => {}, -}; +// eslint-disable-next-line @kbn/imports/no_boundary_crossing +import { mockChatService, mockService } from '../mock'; export function KibanaReactStorybookDecorator(Story: ComponentType) { return ( @@ -83,7 +26,7 @@ export function KibanaReactStorybookDecorator(Story: ComponentType) { }} > - + diff --git a/x-pack/plugins/observability_ai_assistant/tsconfig.json b/x-pack/plugins/observability_ai_assistant/tsconfig.json index fdac7a82d4df2..28b5b68b07b34 100644 --- a/x-pack/plugins/observability_ai_assistant/tsconfig.json +++ b/x-pack/plugins/observability_ai_assistant/tsconfig.json @@ -53,7 +53,8 @@ "@kbn/tooling-log", "@kbn/babel-register", "@kbn/dev-cli-runner", - "@kbn/core-analytics-browser" + "@kbn/core-analytics-browser", + "@kbn/security-plugin-types-common" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/profiling/public/app.tsx b/x-pack/plugins/profiling/public/app.tsx index 2d5dd828c18b0..e91c2eef4ec72 100644 --- a/x-pack/plugins/profiling/public/app.tsx +++ b/x-pack/plugins/profiling/public/app.tsx @@ -13,7 +13,6 @@ import { RouteRenderer, RouterProvider } from '@kbn/typed-react-router-config'; import React, { useMemo } from 'react'; import ReactDOM from 'react-dom'; import { HeaderMenuPortal } from '@kbn/observability-shared-plugin/public'; -import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public'; import { CheckSetup } from './components/check_setup'; import { ProfilingDependenciesContextProvider } from './components/contexts/profiling_dependencies/profiling_dependencies_context'; import { RouteBreadcrumbsContextProvider } from './components/contexts/route_breadcrumbs_context'; @@ -84,35 +83,33 @@ function App({ - - - - - - - - - <> - - - - - - - - - - - - - - - - - + + + + + + + + <> + + + + + + + + + + + + + + + + diff --git a/x-pack/plugins/profiling/public/components/frame_information_window/frame_information_ai_assistant.tsx b/x-pack/plugins/profiling/public/components/frame_information_window/frame_information_ai_assistant.tsx index 9175115432f81..b82d8e2693a18 100644 --- a/x-pack/plugins/profiling/public/components/frame_information_window/frame_information_ai_assistant.tsx +++ b/x-pack/plugins/profiling/public/components/frame_information_window/frame_information_ai_assistant.tsx @@ -5,22 +5,20 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; -import { - ContextualInsight, - Message, - MessageRole, - useObservabilityAIAssistant, -} from '@kbn/observability-ai-assistant-plugin/public'; import React, { useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import { Message, MessageRole } from '@kbn/observability-ai-assistant-plugin/public'; import { Frame } from '.'; +import { useProfilingDependencies } from '../contexts/profiling_dependencies/use_profiling_dependencies'; interface Props { frame?: Frame; } export function FrameInformationAIAssistant({ frame }: Props) { - const aiAssistant = useObservabilityAIAssistant(); + const { + observabilityAIAssistant: { ObservabilityAIAssistantContextualInsight }, + } = useProfilingDependencies().start; const promptMessages = useMemo(() => { if (frame?.functionName && frame.exeFileName) { @@ -91,8 +89,8 @@ export function FrameInformationAIAssistant({ frame }: Props) { return ( <> - {aiAssistant.isEnabled() && promptMessages ? ( - - + {ObservabilityAIAssistantActionMenuItem ? : null} ); } diff --git a/x-pack/plugins/profiling/public/embeddables/profiling_embeddable_provider.tsx b/x-pack/plugins/profiling/public/embeddables/profiling_embeddable_provider.tsx index 15e4af7bedb94..52000e4783620 100644 --- a/x-pack/plugins/profiling/public/embeddables/profiling_embeddable_provider.tsx +++ b/x-pack/plugins/profiling/public/embeddables/profiling_embeddable_provider.tsx @@ -6,7 +6,6 @@ */ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public'; import React, { ReactChild, useMemo } from 'react'; import { CoreSetup, CoreStart } from '@kbn/core/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; @@ -53,11 +52,7 @@ export function ProfilingEmbeddableProvider({ deps, children }: Props) { - - {children} - + {children} diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/header/action_menu_content.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/header/action_menu_content.tsx index a123f4be95382..c9a0118815eca 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/header/action_menu_content.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/header/action_menu_content.tsx @@ -11,10 +11,9 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { useHistory, useRouteMatch } from 'react-router-dom'; import { createExploratoryViewUrl } from '@kbn/exploratory-view-plugin/public'; -import { ObservabilityAIAssistantActionMenuItem } from '@kbn/observability-ai-assistant-plugin/public'; import { LastRefreshed } from '../components/last_refreshed'; import { AutoRefreshButton } from '../components/auto_refresh_button'; -import { useSyntheticsSettingsContext } from '../../../contexts'; +import { useSyntheticsSettingsContext, useSyntheticsStartPlugins } from '../../../contexts'; import { useGetUrlParams } from '../../../hooks'; import { MONITOR_ROUTE, SETTINGS_ROUTE } from '../../../../../../common/constants'; import { stringifyUrlParams } from '../../../utils/url_params'; @@ -32,6 +31,9 @@ const ANALYZE_MESSAGE = i18n.translate('xpack.synthetics.analyzeDataButtonLabel. export function ActionMenuContent(): React.ReactElement { const { basePath } = useSyntheticsSettingsContext(); + + const { observabilityAIAssistant: { ObservabilityAIAssistantActionMenuItem } = {} } = + useSyntheticsStartPlugins(); const params = useGetUrlParams(); const { dateRangeStart, dateRangeEnd } = params; const history = useHistory(); @@ -104,7 +106,9 @@ export function ActionMenuContent(): React.ReactElement { - + {ObservabilityAIAssistantActionMenuItem && ObservabilityAIAssistantActionMenuItem ? ( + + ) : null} ); } diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/synthetics_app.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/synthetics_app.tsx index 89bffbe6dfd73..3bd3407dcb3c1 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/synthetics_app.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/synthetics_app.tsx @@ -14,7 +14,6 @@ import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-pl import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import { InspectorContextProvider } from '@kbn/observability-shared-plugin/public'; -import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public'; import { SyntheticsDataViewContextProvider } from './contexts/synthetics_data_view_context'; import { SyntheticsAppProps } from './contexts'; @@ -91,6 +90,7 @@ const Application = (props: SyntheticsAppProps) => { triggersActionsUi: startPlugins.triggersActionsUi, observability: startPlugins.observability, observabilityShared: startPlugins.observabilityShared, + observabilityAIAssistant: startPlugins.observabilityAIAssistant, exploratoryView: startPlugins.exploratoryView, cases: startPlugins.cases, spaces: startPlugins.spaces, @@ -98,35 +98,31 @@ const Application = (props: SyntheticsAppProps) => { }} > - - - - - - - -
- - - - - - - -
-
-
-
-
-
-
-
+ + + + + + +
+ + + + + + + +
+
+
+
+
+
+
diff --git a/x-pack/plugins/uptime/public/legacy_uptime/app/uptime_app.tsx b/x-pack/plugins/uptime/public/legacy_uptime/app/uptime_app.tsx index a87180eb0a932..0dd752ab2ff64 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/app/uptime_app.tsx +++ b/x-pack/plugins/uptime/public/legacy_uptime/app/uptime_app.tsx @@ -15,7 +15,6 @@ import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-pl import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import { InspectorContextProvider } from '@kbn/observability-shared-plugin/public'; -import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public'; import { ClientPluginsSetup, ClientPluginsStart } from '../../plugin'; import { UMUpdateBadge } from '../lib/lib'; import { @@ -127,37 +126,33 @@ const Application = (props: UptimeAppProps) => { cases: startPlugins.cases, }} > - - - - - - - - -
- - - - - - - -
-
-
-
-
-
-
-
-
+ + + + + + + +
+ + + + + + + +
+
+
+
+
+
+
+
diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/common/header/action_menu_content.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/common/header/action_menu_content.tsx index d6a37ea9bd4ee..58756b4a5669a 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/common/header/action_menu_content.tsx +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/common/header/action_menu_content.tsx @@ -13,7 +13,7 @@ import { useHistory, useRouteMatch } from 'react-router-dom'; import { useSelector } from 'react-redux'; import { createExploratoryViewUrl } from '@kbn/exploratory-view-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { ObservabilityAIAssistantActionMenuItem } from '@kbn/observability-ai-assistant-plugin/public'; + import { stringifyUrlParams } from '../../../lib/helper/url_params/stringify_url_params'; import { useUptimeSettingsContext } from '../../../contexts/uptime_settings_context'; import { useGetUrlParams } from '../../../hooks'; @@ -22,6 +22,7 @@ import { MONITOR_ROUTE, SETTINGS_ROUTE } from '../../../../../common/constants'; import { InspectorHeaderLink } from './inspector_header_link'; import { monitorStatusSelector } from '../../../state/selectors'; import { ManageMonitorsBtn } from './manage_monitors_btn'; +import { useUptimeStartPlugins } from '../../../contexts/uptime_startup_plugins_context'; const ADD_DATA_LABEL = i18n.translate('xpack.uptime.addDataButtonLabel', { defaultMessage: 'Add data', @@ -38,7 +39,10 @@ const ANALYZE_MESSAGE = i18n.translate('xpack.uptime.analyzeDataButtonLabel.mess export function ActionMenuContent(): React.ReactElement { const kibana = useKibana(); + const { basePath } = useUptimeSettingsContext(); + const { observabilityAIAssistant: { ObservabilityAIAssistantActionMenuItem } = {} } = + useUptimeStartPlugins(); const params = useGetUrlParams(); const { dateRangeStart, dateRangeEnd } = params; const history = useHistory(); @@ -117,7 +121,7 @@ export function ActionMenuContent(): React.ReactElement { {ADD_DATA_LABEL} - + {ObservabilityAIAssistantActionMenuItem ? : null} ); } diff --git a/x-pack/plugins/ux/public/application/application.test.tsx b/x-pack/plugins/ux/public/application/application.test.tsx index 33a2ef66b9c70..bcac3494f5376 100644 --- a/x-pack/plugins/ux/public/application/application.test.tsx +++ b/x-pack/plugins/ux/public/application/application.test.tsx @@ -8,11 +8,12 @@ import React from 'react'; import { EuiErrorBoundary } from '@elastic/eui'; import { mount } from 'enzyme'; +import { createObservabilityRuleTypeRegistryMock } from '@kbn/observability-plugin/public'; +import { observabilityAIAssistantPluginMock } from '@kbn/observability-ai-assistant-plugin/public/mock'; import { UXAppRoot } from './ux_app'; import { RumHome } from '../components/app/rum_dashboard/rum_home'; import { coreMock } from '@kbn/core/public/mocks'; -import { createObservabilityRuleTypeRegistryMock } from '@kbn/observability-plugin/public'; import { merge } from 'lodash'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; @@ -36,6 +37,9 @@ jest.mock('@kbn/kibana-react-plugin/public', () => { }; }); +const mockAIAssistantPlugin = + observabilityAIAssistantPluginMock.createStartContract(); + const mockPlugin = { data: { query: { @@ -43,6 +47,7 @@ const mockPlugin = { }, }, observability: {}, + observabilityAIAssistant: mockAIAssistantPlugin, }; const mockEmbeddable = embeddablePluginMock.createStartContract(); @@ -67,9 +72,7 @@ const mockCorePlugins = { ), }, }, - observabilityAIAssistant: { - service: {}, - }, + observabilityAIAssistant: mockAIAssistantPlugin, data: { query: { timefilter: { @@ -127,6 +130,7 @@ export const mockApmPluginContextValue = { core: mockCore, plugins: mockPlugin, observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(), + observabilityAIAssistant: mockAIAssistantPlugin, corePlugins: mockCorePlugins, deps: {}, }; diff --git a/x-pack/plugins/ux/public/application/ux_app.tsx b/x-pack/plugins/ux/public/application/ux_app.tsx index 9eb0b7f2f967b..aae803dec162a 100644 --- a/x-pack/plugins/ux/public/application/ux_app.tsx +++ b/x-pack/plugins/ux/public/application/ux_app.tsx @@ -33,7 +33,6 @@ import { InspectorContextProvider, useBreadcrumbs, } from '@kbn/observability-shared-plugin/public'; -import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public'; import { CsmSharedContextProvider } from '../components/app/rum_dashboard/csm_shared_context'; import { DASHBOARD_LABEL, @@ -147,6 +146,7 @@ export function UXAppRoot({ inspector, observability, observabilityShared, + observabilityAIAssistant, embeddable, exploratoryView, data, @@ -154,47 +154,43 @@ export function UXAppRoot({ lens, }} > - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/x-pack/plugins/ux/public/components/app/rum_dashboard/action_menu/index.tsx b/x-pack/plugins/ux/public/components/app/rum_dashboard/action_menu/index.tsx index fc6a636abba50..da0cc4f8cfc7e 100644 --- a/x-pack/plugins/ux/public/components/app/rum_dashboard/action_menu/index.tsx +++ b/x-pack/plugins/ux/public/components/app/rum_dashboard/action_menu/index.tsx @@ -14,7 +14,6 @@ import { createExploratoryViewUrl, } from '@kbn/exploratory-view-plugin/public'; import { AppMountParameters } from '@kbn/core/public'; -import { ObservabilityAIAssistantActionMenuItem } from '@kbn/observability-ai-assistant-plugin/public'; import { useLegacyUrlParams } from '../../../../context/url_params_context/use_url_params'; import { SERVICE_NAME } from '../../../../../common/elasticsearch_fieldnames'; import { UxInspectorHeaderLink } from './inpector_link'; @@ -39,7 +38,12 @@ export function UXActionMenu({ appMountParameters: AppMountParameters; isDev: boolean; }) { - const { http, application } = useKibanaServices(); + const { + http, + application, + observabilityAIAssistant: { ObservabilityAIAssistantActionMenuItem }, + } = useKibanaServices(); + const { urlParams } = useLegacyUrlParams(); const { rangeTo, rangeFrom, serviceName } = urlParams; @@ -88,7 +92,9 @@ export function UXActionMenu({ })} - + {ObservabilityAIAssistantActionMenuItem ? ( + + ) : null} );