Skip to content

Commit

Permalink
[AI Assistant] Prevent Ai Assistant nav control load for any page (el…
Browse files Browse the repository at this point in the history
…astic#192066)

## 📓 Summary

Closes elastic#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** <img width="2276" alt="Screenshot 2024-09-04 at 11 25 40"
src="https://github.com/user-attachments/assets/0f728c82-c667-4489-9d04-18e9c1ce158e">
|
| **After** <img width="2272" alt="Screenshot 2024-09-04 at 11 29 11"
src="https://github.com/user-attachments/assets/513e6eab-10bd-4919-9a33-16eb3983fa27">
|

**Demo** 🎥


https://github.com/user-attachments/assets/5faa4c77-52c5-40e8-8d39-78952504fede

---------

Co-authored-by: Marco Antonio Ghiani <[email protected]>
Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
3 people authored Sep 5, 2024
1 parent 8be089b commit 5b4f4af
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<SharedProviders
coreStart={coreStart}
pluginsStart={pluginsStart}
service={appService}
theme$={coreStart.theme.theme$}
>
<NavControl />
</SharedProviders>
);
};

export function NavControl({}: {}) {
export function NavControl() {
const service = useObservabilityAIAssistantAppService();

const {
Expand Down Expand Up @@ -63,8 +89,6 @@ export function NavControl({}: {}) {

const keyRef = useRef(v4());

const { isVisible } = useIsNavControlVisible();

useEffect(() => {
const conversationSubscription = service.conversations.predefinedConversation$.subscribe(() => {
keyRef.current = v4();
Expand Down Expand Up @@ -108,10 +132,6 @@ export function NavControl({}: {}) {
};
}, [service.conversations]);

if (!isVisible) {
return null;
}

return (
<>
<EuiToolTip content={buttonLabel}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<LazyNavControlWithProvider
appService={appService}
coreStart={coreStart}
pluginsStart={pluginsStart}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Expand Down Expand Up @@ -108,14 +107,11 @@ export class ObservabilityAIAssistantAppPlugin
coreStart.chrome.navControls.registerRight({
mount: (element) => {
ReactDOM.render(
<SharedProviders
<NavControlInitiator
appService={appService}
coreStart={coreStart}
pluginsStart={pluginsStart}
service={appService}
theme$={coreStart.theme.theme$}
>
<LazyNavControl />
</SharedProviders>,
/>,
element,
() => {}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"@kbn/observability-plugin",
"@kbn/esql-datagrid",
"@kbn/alerting-comparators",
"@kbn/core-lifecycle-browser",
"@kbn/inference-plugin"
],
"exclude": ["target/**/*"]
Expand Down

0 comments on commit 5b4f4af

Please sign in to comment.