Skip to content

Commit

Permalink
[8.16] [Security Assistant] Move security AI assistant button into gl…
Browse files Browse the repository at this point in the history
…obal nav bar (#203060) (#205886)

# Backport

This will backport the following commits from `main` to `8.16`:
- [[Security Assistant] Move security AI assistant button into global
nav bar (#203060)](#203060)

<!--- Backport version: 8.9.8 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Kenneth
Kreindler","email":"42113355+KDKHD@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-01-08T10:03:54Z","message":"[Security
Assistant] Move security AI assistant button into global nav bar
(#203060)\n\n## Summary\r\n\r\nMore changes are needed within the
observability and search solution to\r\nclose the issue
fully.\r\n\r\nSummarise your PR. If it involves visual changes include a
screenshot or\r\ngif.\r\n\r\nMove the security AI assistant button from
the solution header bar into\r\nthe global nav bar. This is part of the
AI assistant unification\r\ninitiative.\r\n\r\n### How to Test\r\n-
Start kibana\r\n- Go to one of the security solution pages (e.g. attack
discovery)\r\n- AI assistant button should be in the global nav bar.
Clicking it opens\r\nthe assistant.\r\n\r\n- The button can also be
tested for security serverless deployment. It\r\nshould look like the
screenshot bellow.\r\n\r\n### Checklist\r\n\r\nCheck the PR satisfies
following conditions. \r\n\r\nReviewers should verify this PR satisfies
this list as well.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [x] This was
checked for breaking HTTP API changes, and any breaking\r\nchanges have
been approved by the breaking-change committee.
The\r\n`release_note:breaking` label should be applied in these
situations.\r\n- [x] [Flaky
Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\r\nused on any tests changed\r\n- [x] The PR description includes
the appropriate Release Notes section,\r\nand the correct
`release_note:*` label is applied per
the\r\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n###
Identify risks\r\n\r\nDoes this PR introduce any risks? For example,
consider risks like hard\r\nto test bugs, performance regression,
potential of data loss.\r\n\r\nDescribe the risk, its severity, and
mitigation for each identified\r\nrisk. Invite stakeholders and evaluate
how to proceed before merging.\r\n\r\n- [ ] [See some
risk\r\nexamples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)\r\n-
[ ]
...\r\n\r\nClassic:\r\n\r\n![image](https://github.com/user-attachments/assets/b2a9c982-bc54-42f4-ab59-6f0c99d4d899)\r\n\r\n![image](https://github.com/user-attachments/assets/1ae36af0-5d1a-4519-844a-563074646ddf)\r\n\r\nServerless:\r\n\r\n![image](https://github.com/user-attachments/assets/345280df-0e70-4203-b0d8-48ad11753f74)\r\n\r\n![image](https://github.com/user-attachments/assets/7425c886-4528-4987-a00a-48bdc71728c7)\r\n\r\nOld:\r\n<img
width=\"1728\"
alt=\"image\"\r\nsrc=\"https://github.com/user-attachments/assets/5ef568c6-2d31-47da-8f5f-87dfdf10cb5c\">\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"06cf554981845fa2e1d9505952e559568d3e0479","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:prev-major","Feature:Security
Assistant","Team:Security Generative
AI"],"number":203060,"url":"https://github.com/elastic/kibana/pull/203060","mergeCommit":{"message":"[Security
Assistant] Move security AI assistant button into global nav bar
(#203060)\n\n## Summary\r\n\r\nMore changes are needed within the
observability and search solution to\r\nclose the issue
fully.\r\n\r\nSummarise your PR. If it involves visual changes include a
screenshot or\r\ngif.\r\n\r\nMove the security AI assistant button from
the solution header bar into\r\nthe global nav bar. This is part of the
AI assistant unification\r\ninitiative.\r\n\r\n### How to Test\r\n-
Start kibana\r\n- Go to one of the security solution pages (e.g. attack
discovery)\r\n- AI assistant button should be in the global nav bar.
Clicking it opens\r\nthe assistant.\r\n\r\n- The button can also be
tested for security serverless deployment. It\r\nshould look like the
screenshot bellow.\r\n\r\n### Checklist\r\n\r\nCheck the PR satisfies
following conditions. \r\n\r\nReviewers should verify this PR satisfies
this list as well.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [x] This was
checked for breaking HTTP API changes, and any breaking\r\nchanges have
been approved by the breaking-change committee.
The\r\n`release_note:breaking` label should be applied in these
situations.\r\n- [x] [Flaky
Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\r\nused on any tests changed\r\n- [x] The PR description includes
the appropriate Release Notes section,\r\nand the correct
`release_note:*` label is applied per
the\r\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n###
Identify risks\r\n\r\nDoes this PR introduce any risks? For example,
consider risks like hard\r\nto test bugs, performance regression,
potential of data loss.\r\n\r\nDescribe the risk, its severity, and
mitigation for each identified\r\nrisk. Invite stakeholders and evaluate
how to proceed before merging.\r\n\r\n- [ ] [See some
risk\r\nexamples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)\r\n-
[ ]
...\r\n\r\nClassic:\r\n\r\n![image](https://github.com/user-attachments/assets/b2a9c982-bc54-42f4-ab59-6f0c99d4d899)\r\n\r\n![image](https://github.com/user-attachments/assets/1ae36af0-5d1a-4519-844a-563074646ddf)\r\n\r\nServerless:\r\n\r\n![image](https://github.com/user-attachments/assets/345280df-0e70-4203-b0d8-48ad11753f74)\r\n\r\n![image](https://github.com/user-attachments/assets/7425c886-4528-4987-a00a-48bdc71728c7)\r\n\r\nOld:\r\n<img
width=\"1728\"
alt=\"image\"\r\nsrc=\"https://github.com/user-attachments/assets/5ef568c6-2d31-47da-8f5f-87dfdf10cb5c\">\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"06cf554981845fa2e1d9505952e559568d3e0479"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","labelRegex":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/203060","number":203060,"mergeCommit":{"message":"[Security
Assistant] Move security AI assistant button into global nav bar
(#203060)\n\n## Summary\r\n\r\nMore changes are needed within the
observability and search solution to\r\nclose the issue
fully.\r\n\r\nSummarise your PR. If it involves visual changes include a
screenshot or\r\ngif.\r\n\r\nMove the security AI assistant button from
the solution header bar into\r\nthe global nav bar. This is part of the
AI assistant unification\r\ninitiative.\r\n\r\n### How to Test\r\n-
Start kibana\r\n- Go to one of the security solution pages (e.g. attack
discovery)\r\n- AI assistant button should be in the global nav bar.
Clicking it opens\r\nthe assistant.\r\n\r\n- The button can also be
tested for security serverless deployment. It\r\nshould look like the
screenshot bellow.\r\n\r\n### Checklist\r\n\r\nCheck the PR satisfies
following conditions. \r\n\r\nReviewers should verify this PR satisfies
this list as well.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [x] This was
checked for breaking HTTP API changes, and any breaking\r\nchanges have
been approved by the breaking-change committee.
The\r\n`release_note:breaking` label should be applied in these
situations.\r\n- [x] [Flaky
Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\r\nused on any tests changed\r\n- [x] The PR description includes
the appropriate Release Notes section,\r\nand the correct
`release_note:*` label is applied per
the\r\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n###
Identify risks\r\n\r\nDoes this PR introduce any risks? For example,
consider risks like hard\r\nto test bugs, performance regression,
potential of data loss.\r\n\r\nDescribe the risk, its severity, and
mitigation for each identified\r\nrisk. Invite stakeholders and evaluate
how to proceed before merging.\r\n\r\n- [ ] [See some
risk\r\nexamples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)\r\n-
[ ]
...\r\n\r\nClassic:\r\n\r\n![image](https://github.com/user-attachments/assets/b2a9c982-bc54-42f4-ab59-6f0c99d4d899)\r\n\r\n![image](https://github.com/user-attachments/assets/1ae36af0-5d1a-4519-844a-563074646ddf)\r\n\r\nServerless:\r\n\r\n![image](https://github.com/user-attachments/assets/345280df-0e70-4203-b0d8-48ad11753f74)\r\n\r\n![image](https://github.com/user-attachments/assets/7425c886-4528-4987-a00a-48bdc71728c7)\r\n\r\nOld:\r\n<img
width=\"1728\"
alt=\"image\"\r\nsrc=\"https://github.com/user-attachments/assets/5ef568c6-2d31-47da-8f5f-87dfdf10cb5c\">\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"06cf554981845fa2e1d9505952e559568d3e0479"}}]}]
BACKPORT-->

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
KDKHD and kibanamachine authored Jan 9, 2025
1 parent 1b08f7a commit 56aebad
Show file tree
Hide file tree
Showing 24 changed files with 400 additions and 163 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { DEFAULT_CONVERSATION_TITLE } from '../../use_conversation/translations'
import { TestProviders } from '../../../mock/test_providers/test_providers';
import { WELCOME_CONVERSATION } from '../../use_conversation/sample_conversations';
import { PromptResponse } from '@kbn/elastic-assistant-common';
import { chromeServiceMock } from '@kbn/core-chrome-browser-mocks';
import { of } from 'rxjs';

const BASE_CONVERSATION: Conversation = {
...WELCOME_CONVERSATION,
Expand All @@ -36,6 +38,13 @@ const mockUseAssistantContext = {
setConversations: jest.fn(),
setAllSystemPrompts: jest.fn(),
allSystemPrompts: mockSystemPrompts,
chrome: {
getChromeStyle$: jest.fn(() => of('classic')),
navControls: chromeServiceMock.createStartContract().navControls,
},
assistantAvailability: {
hasAssistantPrivilege: true,
},
};

jest.mock('../../../assistant_context', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { QuickPromptSettings } from './quick_prompt_settings';
import { TestProviders } from '../../../mock/test_providers/test_providers';
import { MOCK_QUICK_PROMPTS } from '../../../mock/quick_prompt';
import { mockPromptContexts } from '../../../mock/prompt_context';
import { chromeServiceMock } from '@kbn/core-chrome-browser-mocks';
import { of } from 'rxjs';

const onSelectedQuickPromptChange = jest.fn();
const setPromptsBulkActions = jest.fn();
Expand All @@ -28,6 +30,13 @@ const testProps = {
};
const mockContext = {
basePromptContexts: MOCK_QUICK_PROMPTS,
chrome: {
getChromeStyle$: jest.fn(() => of('classic')),
navControls: chromeServiceMock.createStartContract().navControls,
},
assistantAvailability: {
hasAssistantPrivilege: true,
},
};

jest.mock('../../../assistant_context', () => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { TestProviders } from '../../mock/test_providers/test_providers';
import { MOCK_QUICK_PROMPTS } from '../../mock/quick_prompt';
import { QUICK_PROMPTS_TAB } from '../settings/const';
import { QuickPrompts } from './quick_prompts';
import { of } from 'rxjs';
import { chromeServiceMock } from '@kbn/core-chrome-browser-mocks';

const setInput = jest.fn();
const setIsSettingsModalVisible = jest.fn();
Expand All @@ -26,6 +28,13 @@ const mockUseAssistantContext = {
setSelectedSettingsTab,
promptContexts: {},
allQuickPrompts: MOCK_QUICK_PROMPTS,
chrome: {
getChromeStyle$: jest.fn(() => of('classic')),
navControls: chromeServiceMock.createStartContract().navControls,
},
assistantAvailability: {
hasAssistantPrivilege: true,
},
};

const testTitle = 'SPL_QUERY_CONVERSION_TITLE';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* 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 { render } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
import { AssistantNavLink } from './assistant_nav_link';
import { chromeServiceMock } from '@kbn/core-chrome-browser-mocks';
import { ChromeNavControl } from '@kbn/core/public';
import { createHtmlPortalNode, OutPortal } from 'react-reverse-portal';
import { of } from 'rxjs';
import { useAssistantContext } from '.';

const MockNavigationBar = OutPortal;

const mockShowAssistantOverlay = jest.fn();
const mockNavControls = chromeServiceMock.createStartContract().navControls;
const mockGetChromeStyle = jest.fn();

const mockAssistantContext = {
chrome: {
getChromeStyle$: mockGetChromeStyle,
navControls: mockNavControls,
},
showAssistantOverlay: mockShowAssistantOverlay,
assistantAvailability: {
hasAssistantPrivilege: true,
},
};

jest.mock('.', () => {
return {
...jest.requireActual('.'),
useAssistantContext: jest.fn(),
};
});

describe('AssistantNavLink', () => {
beforeEach(() => {
jest.clearAllMocks();
mockGetChromeStyle.mockReturnValue(of('classic'));
(useAssistantContext as jest.Mock).mockReturnValue({
...mockAssistantContext,
});
});

it('should register link in nav bar', () => {
render(<AssistantNavLink />);
expect(mockNavControls.registerRight).toHaveBeenCalledTimes(1);
});

it('button has transparent background in project navigation', () => {
const { result: portalNode } = renderHook(() =>
React.useMemo(() => createHtmlPortalNode(), [])
);

mockGetChromeStyle.mockReturnValue(of('project'));

mockNavControls.registerRight.mockImplementation((chromeNavControl: ChromeNavControl) => {
chromeNavControl.mount(portalNode.current.element);
});

const { queryByTestId } = render(
<>
<MockNavigationBar node={portalNode.current} />
<AssistantNavLink />
</>
);
expect(queryByTestId('assistantNavLink')).not.toHaveStyle(
'background-color: rgb(204, 228, 245)'
);
});

it('button has opaque background in classic navigation', () => {
const { result: portalNode } = renderHook(() =>
React.useMemo(() => createHtmlPortalNode(), [])
);

mockGetChromeStyle.mockReturnValue(of('classic'));

mockNavControls.registerRight.mockImplementation((chromeNavControl: ChromeNavControl) => {
chromeNavControl.mount(portalNode.current.element);
});

const { queryByTestId } = render(
<>
<MockNavigationBar node={portalNode.current} />
<AssistantNavLink />
</>
);
expect(queryByTestId('assistantNavLink')).toHaveStyle('background-color: rgb(204, 228, 245)');
});

it('should render the header link text', () => {
const { result: portalNode } = renderHook(() =>
React.useMemo(() => createHtmlPortalNode(), [])
);

mockNavControls.registerRight.mockImplementation((chromeNavControl: ChromeNavControl) => {
chromeNavControl.mount(portalNode.current.element);
});

const { queryByText, queryByTestId } = render(
<>
<MockNavigationBar node={portalNode.current} />
<AssistantNavLink />
</>
);
expect(queryByTestId('assistantNavLink')).toBeInTheDocument();
expect(queryByText('AI Assistant')).toBeInTheDocument();
});

it('should not render the header link if not authorized', () => {
const { result: portalNode } = renderHook(() =>
React.useMemo(() => createHtmlPortalNode(), [])
);

mockNavControls.registerRight.mockImplementation((chromeNavControl: ChromeNavControl) => {
chromeNavControl.mount(portalNode.current.element);
});

(useAssistantContext as jest.Mock).mockReturnValue({
...mockAssistantContext,
assistantAvailability: {
hasAssistantPrivilege: false,
},
});

const { queryByText, queryByTestId } = render(
<>
<MockNavigationBar node={portalNode.current} />
<AssistantNavLink />
</>
);
expect(queryByTestId('assistantNavLink')).not.toBeInTheDocument();
expect(queryByText('AI Assistant')).not.toBeInTheDocument();
});

it('should call the assistant overlay to show on click', () => {
const { result: portalNode } = renderHook(() =>
React.useMemo(() => createHtmlPortalNode(), [])
);

mockNavControls.registerRight.mockImplementation((chromeNavControl: ChromeNavControl) => {
chromeNavControl.mount(portalNode.current.element);
});

const { queryByTestId } = render(
<>
<MockNavigationBar node={portalNode.current} />
<AssistantNavLink />
</>
);
queryByTestId('assistantNavLink')?.click();
expect(mockShowAssistantOverlay).toHaveBeenCalledTimes(1);
expect(mockShowAssistantOverlay).toHaveBeenCalledWith({ showOverlay: true });
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* 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 type { FC } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
import { createHtmlPortalNode, OutPortal, InPortal } from 'react-reverse-portal';
import { EuiToolTip, EuiButton, EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { ChromeStyle } from '@kbn/core-chrome-browser';
import { useAssistantContext } from '.';
import { AssistantAvatar } from '../assistant/assistant_avatar/assistant_avatar';

const isMac = navigator.platform.toLowerCase().indexOf('mac') >= 0;

const TOOLTIP_CONTENT = i18n.translate(
'xpack.elasticAssistant.assistantContext.assistantNavLinkShortcutTooltip',
{
values: { keyboardShortcut: isMac ? '⌘ ;' : 'Ctrl ;' },
defaultMessage: 'Keyboard shortcut {keyboardShortcut}',
}
);
const LINK_LABEL = i18n.translate('xpack.elasticAssistant.assistantContext.assistantNavLink', {
defaultMessage: 'AI Assistant',
});

export const AssistantNavLink: FC = () => {
const { chrome, showAssistantOverlay, assistantAvailability, currentAppId } =
useAssistantContext();
const portalNode = React.useMemo(() => createHtmlPortalNode(), []);
const [chromeStyle, setChromeStyle] = useState<ChromeStyle | undefined>(undefined);

// useObserverable would change the order of re-renders that are tested against closely.
useEffect(() => {
const s = chrome.getChromeStyle$().subscribe(setChromeStyle);
return () => s.unsubscribe();
}, [chrome]);

useEffect(() => {
const registerPortalNode = () => {
chrome.navControls.registerRight({
mount: (element: HTMLElement) => {
ReactDOM.render(<OutPortal node={portalNode} />, element);
return () => ReactDOM.unmountComponentAtNode(element);
},
// right before the user profile
order: 1001,
});
};

if (
assistantAvailability.hasAssistantPrivilege &&
chromeStyle &&
currentAppId !== 'management'
) {
registerPortalNode();
}
}, [chrome, portalNode, assistantAvailability.hasAssistantPrivilege, chromeStyle, currentAppId]);

const showOverlay = useCallback(
() => showAssistantOverlay({ showOverlay: true }),
[showAssistantOverlay]
);

if (!assistantAvailability.hasAssistantPrivilege || !chromeStyle) {
return null;
}

const EuiButtonBasicOrEmpty = chromeStyle === 'project' ? EuiButtonEmpty : EuiButton;

return (
<InPortal node={portalNode}>
<EuiToolTip content={TOOLTIP_CONTENT}>
<EuiButtonBasicOrEmpty
onClick={showOverlay}
color="primary"
size="s"
data-test-subj="assistantNavLink"
>
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<AssistantAvatar size="xs" />
</EuiFlexItem>
<EuiFlexItem grow={false}>{LINK_LABEL}</EuiFlexItem>
</EuiFlexGroup>
</EuiButtonBasicOrEmpty>
</EuiToolTip>
</InPortal>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/publ
import { useLocalStorage, useSessionStorage } from 'react-use';
import type { DocLinksStart } from '@kbn/core-doc-links-browser';
import { AssistantFeatures, defaultAssistantFeatures } from '@kbn/elastic-assistant-common';
import { NavigateToAppOptions, UserProfileService } from '@kbn/core/public';
import { ChromeStart, NavigateToAppOptions, UserProfileService } from '@kbn/core/public';
import { useQuery } from '@tanstack/react-query';
import { updatePromptContexts } from './helpers';
import type {
Expand Down Expand Up @@ -42,6 +42,7 @@ import {
import { useCapabilities } from '../assistant/api/capabilities/use_capabilities';
import { WELCOME_CONVERSATION_TITLE } from '../assistant/use_conversation/translations';
import { SettingsTabs } from '../assistant/settings/types';
import { AssistantNavLink } from './assistant_nav_link';

export interface ShowAssistantOverlayProps {
showOverlay: boolean;
Expand Down Expand Up @@ -76,6 +77,7 @@ export interface AssistantProviderProps {
toasts?: IToasts;
currentAppId: string;
userProfileService: UserProfileService;
chrome: ChromeStart;
}

export interface UserAvatar {
Expand Down Expand Up @@ -127,6 +129,7 @@ export interface UseAssistantContext {
currentAppId: string;
codeBlockRef: React.MutableRefObject<(codeBlock: string) => void>;
userProfileService: UserProfileService;
chrome: ChromeStart;
}

const AssistantContext = React.createContext<UseAssistantContext | undefined>(undefined);
Expand All @@ -150,6 +153,7 @@ export const AssistantProvider: React.FC<AssistantProviderProps> = ({
toasts,
currentAppId,
userProfileService,
chrome,
}) => {
/**
* Session storage for traceOptions, including APM URL and LangSmith Project/API Key
Expand Down Expand Up @@ -302,6 +306,7 @@ export const AssistantProvider: React.FC<AssistantProviderProps> = ({
currentAppId,
codeBlockRef,
userProfileService,
chrome,
}),
[
actionTypeRegistry,
Expand Down Expand Up @@ -337,10 +342,16 @@ export const AssistantProvider: React.FC<AssistantProviderProps> = ({
currentAppId,
codeBlockRef,
userProfileService,
chrome,
]
);

return <AssistantContext.Provider value={value}>{children}</AssistantContext.Provider>;
return (
<AssistantContext.Provider value={value}>
<AssistantNavLink />
{children}
</AssistantContext.Provider>
);
};

export const useAssistantContext = () => {
Expand Down
Loading

0 comments on commit 56aebad

Please # to comment.