From 5b4f4afb44142049e9de2d02887d299663a88e61 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Thu, 5 Sep 2024 10:59:35 +0200 Subject: [PATCH] [AI Assistant] Prevent Ai Assistant nav control load for any page (#192066) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📓 Summary Closes #191601 The AI Assistant nav control is currently loaded only for Observability pages. However, during its registration step in the `observabilityAIAssistantApp`, the whole async chunk leaked into any page even when unnecessary since the control was not shown. The cause was a visibility condition applied too late in the react rendering process. Lifting the control condition higher in the tree prevents the whole chunk from being loaded for any page, but only for those enabled in observability. This refactor const of a total **~93%** reduction in the impact of the AI Assistant code for pages that won't need it. Also, even if the bundle file was not excessively big, this refactor brings a nice **~33%** on the initial `observabilityAiAssistantApp.plugin.js` bundle file. | **AIAssistantApp impact on Kibana** | |--------| | **Before** Screenshot 2024-09-04 at 11 25 40 | | **After** Screenshot 2024-09-04 at 11 29 11 | **Demo** 🎥 https://github.com/user-attachments/assets/5faa4c77-52c5-40e8-8d39-78952504fede --------- Co-authored-by: Marco Antonio Ghiani Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../public/components/nav_control/index.tsx | 36 ++++++++++++++---- .../nav_control/lazy_nav_control.tsx | 38 +++++++++++++++++-- .../public/hooks/is_nav_control_visible.tsx | 21 +++++----- .../public/plugin.tsx | 12 ++---- .../tsconfig.json | 1 + 5 files changed, 77 insertions(+), 31 deletions(-) diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/index.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/index.tsx index b70d5dbade35b..66a66ecc07dc0 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/index.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/index.tsx @@ -11,14 +11,40 @@ import { css } from '@emotion/react'; import { v4 } from 'uuid'; import useObservable from 'react-use/lib/useObservable'; import { i18n } from '@kbn/i18n'; +import { CoreStart } from '@kbn/core-lifecycle-browser'; import { useObservabilityAIAssistantAppService } from '../../hooks/use_observability_ai_assistant_app_service'; import { ChatFlyout } from '../chat/chat_flyout'; import { useKibana } from '../../hooks/use_kibana'; -import { useIsNavControlVisible } from '../../hooks/is_nav_control_visible'; import { useTheme } from '../../hooks/use_theme'; import { useNavControlScreenContext } from '../../hooks/use_nav_control_screen_context'; +import { SharedProviders } from '../../utils/shared_providers'; +import { ObservabilityAIAssistantAppService } from '../../service/create_app_service'; +import { ObservabilityAIAssistantAppPluginStartDependencies } from '../../types'; + +interface NavControlWithProviderDeps { + appService: ObservabilityAIAssistantAppService; + coreStart: CoreStart; + pluginsStart: ObservabilityAIAssistantAppPluginStartDependencies; +} + +export const NavControlWithProvider = ({ + appService, + coreStart, + pluginsStart, +}: NavControlWithProviderDeps) => { + return ( + + + + ); +}; -export function NavControl({}: {}) { +export function NavControl() { const service = useObservabilityAIAssistantAppService(); const { @@ -63,8 +89,6 @@ export function NavControl({}: {}) { const keyRef = useRef(v4()); - const { isVisible } = useIsNavControlVisible(); - useEffect(() => { const conversationSubscription = service.conversations.predefinedConversation$.subscribe(() => { keyRef.current = v4(); @@ -108,10 +132,6 @@ export function NavControl({}: {}) { }; }, [service.conversations]); - if (!isVisible) { - return null; - } - return ( <> diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/lazy_nav_control.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/lazy_nav_control.tsx index 77086a9bf73aa..bed86909af417 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/lazy_nav_control.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/components/nav_control/lazy_nav_control.tsx @@ -5,9 +5,39 @@ * 2.0. */ -import { withSuspense } from '@kbn/shared-ux-utility'; -import { lazy } from 'react'; +import { dynamic } from '@kbn/shared-ux-utility'; +import React from 'react'; +import { CoreStart } from '@kbn/core-lifecycle-browser'; +import { useIsNavControlVisible } from '../../hooks/is_nav_control_visible'; +import { ObservabilityAIAssistantAppService } from '../../service/create_app_service'; +import { ObservabilityAIAssistantAppPluginStartDependencies } from '../../types'; -export const LazyNavControl = withSuspense( - lazy(() => import('.').then((m) => ({ default: m.NavControl }))) +const LazyNavControlWithProvider = dynamic(() => + import('.').then((m) => ({ default: m.NavControlWithProvider })) ); + +interface NavControlInitiatorProps { + appService: ObservabilityAIAssistantAppService; + coreStart: CoreStart; + pluginsStart: ObservabilityAIAssistantAppPluginStartDependencies; +} + +export const NavControlInitiator = ({ + appService, + coreStart, + pluginsStart, +}: NavControlInitiatorProps) => { + const { isVisible } = useIsNavControlVisible({ coreStart, pluginsStart }); + + if (!isVisible) { + return null; + } + + return ( + + ); +}; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/is_nav_control_visible.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/is_nav_control_visible.tsx index c8386991eebbf..f82de790e05c2 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/is_nav_control_visible.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/is_nav_control_visible.tsx @@ -7,9 +7,14 @@ import { useEffect, useState } from 'react'; import { combineLatest } from 'rxjs'; -import { DEFAULT_APP_CATEGORIES, type PublicAppInfo } from '@kbn/core/public'; +import { CoreStart, DEFAULT_APP_CATEGORIES, type PublicAppInfo } from '@kbn/core/public'; import { AIAssistantType } from '@kbn/ai-assistant-management-plugin/public'; -import { useKibana } from './use_kibana'; +import { ObservabilityAIAssistantAppPluginStartDependencies } from '../types'; + +interface UseIsNavControlVisibleProps { + coreStart: CoreStart; + pluginsStart: ObservabilityAIAssistantAppPluginStartDependencies; +} function getVisibility( appId: string | undefined, @@ -30,17 +35,11 @@ function getVisibility( return categoryId === DEFAULT_APP_CATEGORIES.observability.id; } -export function useIsNavControlVisible() { +export function useIsNavControlVisible({ coreStart, pluginsStart }: UseIsNavControlVisibleProps) { const [isVisible, setIsVisible] = useState(false); - const { - services: { - application: { currentAppId$, applications$ }, - plugins: { - start: { aiAssistantManagementSelection }, - }, - }, - } = useKibana(); + const { currentAppId$, applications$ } = coreStart.application; + const { aiAssistantManagementSelection } = pluginsStart; useEffect(() => { const appSubscription = combineLatest([ diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/plugin.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/plugin.tsx index 466cde6747990..9817cc65362d6 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/plugin.tsx @@ -24,9 +24,8 @@ import type { ObservabilityAIAssistantAppPublicStart, } from './types'; import { createAppService, ObservabilityAIAssistantAppService } from './service/create_app_service'; -import { SharedProviders } from './utils/shared_providers'; -import { LazyNavControl } from './components/nav_control/lazy_nav_control'; import { getObsAIAssistantConnectorType } from './rule_connector'; +import { NavControlInitiator } from './components/nav_control/lazy_nav_control'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ConfigSchema {} @@ -108,14 +107,11 @@ export class ObservabilityAIAssistantAppPlugin coreStart.chrome.navControls.registerRight({ mount: (element) => { ReactDOM.render( - - - , + />, element, () => {} ); diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/tsconfig.json b/x-pack/plugins/observability_solution/observability_ai_assistant_app/tsconfig.json index bc92d37d3cd70..55d965c9c37e3 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/tsconfig.json @@ -71,6 +71,7 @@ "@kbn/observability-plugin", "@kbn/esql-datagrid", "@kbn/alerting-comparators", + "@kbn/core-lifecycle-browser", "@kbn/inference-plugin" ], "exclude": ["target/**/*"]