mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Security solution] Reinstall product documentation callout (#205975)
This commit is contained in:
parent
54436e3c1c
commit
ac4577159e
20 changed files with 460 additions and 40 deletions
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export const REACT_QUERY_KEYS = {
|
||||
GET_PRODUCT_DOC_STATUS: 'get_product_doc_status',
|
||||
INSTALL_PRODUCT_DOC: 'install_product_doc',
|
||||
};
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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 { waitFor, renderHook } from '@testing-library/react';
|
||||
import { useGetProductDocStatus } from './use_get_product_doc_status';
|
||||
import { useAssistantContext } from '../../../..';
|
||||
import { TestProviders } from '../../../mock/test_providers/test_providers';
|
||||
|
||||
jest.mock('../../../..', () => ({
|
||||
useAssistantContext: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('useGetProductDocStatus', () => {
|
||||
const mockGetStatus = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
(useAssistantContext as jest.Mock).mockReturnValue({
|
||||
productDocBase: {
|
||||
installation: {
|
||||
getStatus: mockGetStatus,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('returns loading state initially', async () => {
|
||||
mockGetStatus.mockResolvedValueOnce('status');
|
||||
const { result } = renderHook(() => useGetProductDocStatus(), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
|
||||
expect(result.current.isLoading).toBe(true);
|
||||
await waitFor(() => result.current.isSuccess);
|
||||
});
|
||||
|
||||
it('returns success state with data', async () => {
|
||||
mockGetStatus.mockResolvedValueOnce('status');
|
||||
const { result } = renderHook(() => useGetProductDocStatus(), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.status).toBe('status');
|
||||
expect(result.current.isSuccess).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns error state when query fails', async () => {
|
||||
mockGetStatus.mockRejectedValueOnce(new Error('error'));
|
||||
const { result } = renderHook(() => useGetProductDocStatus(), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.isError).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 { useQuery } from '@tanstack/react-query';
|
||||
import { REACT_QUERY_KEYS } from './const';
|
||||
import { useAssistantContext } from '../../../..';
|
||||
|
||||
export function useGetProductDocStatus() {
|
||||
const { productDocBase } = useAssistantContext();
|
||||
|
||||
const { isLoading, isError, isSuccess, isRefetching, data, refetch } = useQuery({
|
||||
queryKey: [REACT_QUERY_KEYS.GET_PRODUCT_DOC_STATUS],
|
||||
queryFn: async () => {
|
||||
return productDocBase.installation.getStatus();
|
||||
},
|
||||
keepPreviousData: false,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
return {
|
||||
status: data,
|
||||
refetch,
|
||||
isLoading,
|
||||
isRefetching,
|
||||
isSuccess,
|
||||
isError,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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 { waitFor, renderHook } from '@testing-library/react';
|
||||
import { useInstallProductDoc } from './use_install_product_doc';
|
||||
import { useAssistantContext } from '../../../..';
|
||||
import { TestProviders } from '../../../mock/test_providers/test_providers';
|
||||
|
||||
jest.mock('../../../..', () => ({
|
||||
useAssistantContext: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('useInstallProductDoc', () => {
|
||||
const mockInstall = jest.fn();
|
||||
const mockAddSuccess = jest.fn();
|
||||
const mockAddError = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
(useAssistantContext as jest.Mock).mockReturnValue({
|
||||
productDocBase: {
|
||||
installation: {
|
||||
install: mockInstall,
|
||||
},
|
||||
},
|
||||
toasts: {
|
||||
addSuccess: mockAddSuccess,
|
||||
addError: mockAddError,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('returns success state and shows success toast on successful installation', async () => {
|
||||
mockInstall.mockResolvedValueOnce({});
|
||||
const { result } = renderHook(() => useInstallProductDoc(), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
|
||||
result.current.mutate();
|
||||
await waitFor(() => result.current.isSuccess);
|
||||
|
||||
expect(mockAddSuccess).toHaveBeenCalledWith(
|
||||
'The Elastic documentation was successfully installed'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns error state and shows error toast on failed installation', async () => {
|
||||
const error = new Error('error message');
|
||||
mockInstall.mockRejectedValueOnce(error);
|
||||
const { result } = renderHook(() => useInstallProductDoc(), {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
|
||||
result.current.mutate();
|
||||
await waitFor(() => result.current.isError);
|
||||
|
||||
expect(mockAddError).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
message: 'error message',
|
||||
}),
|
||||
{ title: 'Something went wrong while installing the Elastic documentation' }
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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 { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { IHttpFetchError, ResponseErrorBody } from '@kbn/core/public';
|
||||
import type { PerformInstallResponse } from '@kbn/product-doc-base-plugin/common/http_api/installation';
|
||||
import { REACT_QUERY_KEYS } from './const';
|
||||
import { useAssistantContext } from '../../../..';
|
||||
|
||||
type ServerError = IHttpFetchError<ResponseErrorBody>;
|
||||
|
||||
export function useInstallProductDoc() {
|
||||
const { productDocBase, toasts } = useAssistantContext();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<PerformInstallResponse, ServerError, void>(
|
||||
[REACT_QUERY_KEYS.INSTALL_PRODUCT_DOC],
|
||||
() => {
|
||||
return productDocBase.installation.install();
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
toasts?.addSuccess(
|
||||
i18n.translate('xpack.elasticAssistant.kb.installProductDoc.successNotification', {
|
||||
defaultMessage: 'The Elastic documentation was successfully installed',
|
||||
})
|
||||
);
|
||||
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [REACT_QUERY_KEYS.GET_PRODUCT_DOC_STATUS],
|
||||
refetchType: 'all',
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
toasts?.addError(new Error(error.body?.message ?? error.message), {
|
||||
title: i18n.translate('xpack.elasticAssistant.kb.installProductDoc.errorNotification', {
|
||||
defaultMessage: 'Something went wrong while installing the Elastic documentation',
|
||||
}),
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { ProductDocumentationManagement } from '.';
|
||||
import * as i18n from './translations';
|
||||
import { useInstallProductDoc } from '../../api/product_docs/use_install_product_doc';
|
||||
import { useGetProductDocStatus } from '../../api/product_docs/use_get_product_doc_status';
|
||||
|
||||
jest.mock('../../api/product_docs/use_install_product_doc');
|
||||
jest.mock('../../api/product_docs/use_get_product_doc_status');
|
||||
|
||||
describe('ProductDocumentationManagement', () => {
|
||||
const mockInstallProductDoc = jest.fn().mockResolvedValue({});
|
||||
|
||||
beforeEach(() => {
|
||||
(useInstallProductDoc as jest.Mock).mockReturnValue({ mutateAsync: mockInstallProductDoc });
|
||||
(useGetProductDocStatus as jest.Mock).mockReturnValue({ status: null, isLoading: false });
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders loading spinner when status is loading', async () => {
|
||||
(useGetProductDocStatus as jest.Mock).mockReturnValue({
|
||||
status: { overall: 'not_installed' },
|
||||
isLoading: true,
|
||||
});
|
||||
render(<ProductDocumentationManagement />);
|
||||
expect(screen.getByTestId('statusLoading')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders install button when not installed', () => {
|
||||
(useGetProductDocStatus as jest.Mock).mockReturnValue({
|
||||
status: { overall: 'not_installed' },
|
||||
isLoading: false,
|
||||
});
|
||||
render(<ProductDocumentationManagement />);
|
||||
expect(screen.getByText(i18n.INSTALL)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render anything when already installed', () => {
|
||||
(useGetProductDocStatus as jest.Mock).mockReturnValue({
|
||||
status: { overall: 'installed' },
|
||||
isLoading: false,
|
||||
});
|
||||
const { container } = render(<ProductDocumentationManagement />);
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('shows installing spinner and text when installing', async () => {
|
||||
(useGetProductDocStatus as jest.Mock).mockReturnValue({
|
||||
status: { overall: 'not_installed' },
|
||||
isLoading: false,
|
||||
});
|
||||
render(<ProductDocumentationManagement />);
|
||||
fireEvent.click(screen.getByText(i18n.INSTALL));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('installing')).toBeInTheDocument();
|
||||
expect(screen.getByText(i18n.INSTALLING)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('sets installed state to true after successful installation', async () => {
|
||||
(useGetProductDocStatus as jest.Mock).mockReturnValue({
|
||||
status: { overall: 'not_installed' },
|
||||
isLoading: false,
|
||||
});
|
||||
mockInstallProductDoc.mockResolvedValueOnce({});
|
||||
render(<ProductDocumentationManagement />);
|
||||
fireEvent.click(screen.getByText(i18n.INSTALL));
|
||||
await waitFor(() => expect(screen.queryByText(i18n.INSTALL)).not.toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('sets installed state to false after failed installation', async () => {
|
||||
(useGetProductDocStatus as jest.Mock).mockReturnValue({
|
||||
status: { overall: 'not_installed' },
|
||||
isLoading: false,
|
||||
});
|
||||
mockInstallProductDoc.mockRejectedValueOnce(new Error('Installation failed'));
|
||||
render(<ProductDocumentationManagement />);
|
||||
fireEvent.click(screen.getByText(i18n.INSTALL));
|
||||
await waitFor(() => expect(screen.getByText(i18n.INSTALL)).toBeInTheDocument());
|
||||
});
|
||||
});
|
|
@ -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 {
|
||||
EuiButton,
|
||||
EuiCallOut,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiLoadingSpinner,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
import React, { useEffect, useState, useCallback, useMemo } from 'react';
|
||||
import { useInstallProductDoc } from '../../api/product_docs/use_install_product_doc';
|
||||
import { useGetProductDocStatus } from '../../api/product_docs/use_get_product_doc_status';
|
||||
import * as i18n from './translations';
|
||||
|
||||
export const ProductDocumentationManagement: React.FC = React.memo(() => {
|
||||
const [{ isInstalled, isInstalling }, setState] = useState({
|
||||
isInstalled: true,
|
||||
isInstalling: false,
|
||||
});
|
||||
|
||||
const { mutateAsync: installProductDoc } = useInstallProductDoc();
|
||||
const { status, isLoading: isStatusLoading } = useGetProductDocStatus();
|
||||
|
||||
useEffect(() => {
|
||||
if (status) {
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
isInstalled: status.overall === 'installed',
|
||||
}));
|
||||
}
|
||||
}, [status]);
|
||||
|
||||
const onClickInstall = useCallback(async () => {
|
||||
setState((prevState) => ({ ...prevState, isInstalling: true }));
|
||||
try {
|
||||
await installProductDoc();
|
||||
setState({ isInstalled: true, isInstalling: false });
|
||||
} catch {
|
||||
setState({ isInstalled: false, isInstalling: false });
|
||||
}
|
||||
}, [installProductDoc]);
|
||||
|
||||
const content = useMemo(() => {
|
||||
if (isStatusLoading) {
|
||||
return <EuiLoadingSpinner data-test-subj="statusLoading" size="m" />;
|
||||
}
|
||||
if (isInstalling) {
|
||||
return (
|
||||
<EuiFlexGroup justifyContent="flexStart" alignItems="center">
|
||||
<EuiLoadingSpinner size="m" data-test-subj="installing" />
|
||||
<EuiText size="s">{i18n.INSTALLING}</EuiText>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<EuiFlexGroup justifyContent="flexStart" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
fill
|
||||
data-test-subj="settingsTabInstallProductDocButton"
|
||||
onClick={onClickInstall}
|
||||
>
|
||||
{i18n.INSTALL}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}, [isInstalling, isStatusLoading, onClickInstall]);
|
||||
|
||||
if (isInstalled) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<EuiCallOut title={i18n.LABEL} iconType="iInCircle">
|
||||
<EuiText size="m">
|
||||
<span>{i18n.DESCRIPTION}</span>
|
||||
</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
{content}
|
||||
</EuiCallOut>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
ProductDocumentationManagement.displayName = 'ProductDocumentationManagement';
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
|
||||
export const LABEL = i18n.translate('xpack.elasticAssistant.assistant.settings.productDocLabel', {
|
||||
defaultMessage: 'Elastic documentation is not installed',
|
||||
});
|
||||
export const DESCRIPTION = i18n.translate(
|
||||
'xpack.elasticAssistant.assistant.settings.productDocDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'The Elastic Documentation has been uninstalled. Please reinstall to ensure the most accurate results from the AI Assistant.',
|
||||
}
|
||||
);
|
||||
|
||||
export const INSTALL = i18n.translate(
|
||||
'xpack.elasticAssistant.assistant.settings.installProductDocButtonLabel',
|
||||
{ defaultMessage: 'Install' }
|
||||
);
|
||||
|
||||
export const INSTALLING = i18n.translate(
|
||||
'xpack.elasticAssistant.assistant.settings.installingText',
|
||||
{ defaultMessage: 'Installing...' }
|
||||
);
|
|
@ -15,6 +15,7 @@ import useSessionStorage from 'react-use/lib/useSessionStorage';
|
|||
import type { DocLinksStart } from '@kbn/core-doc-links-browser';
|
||||
import { AssistantFeatures, defaultAssistantFeatures } from '@kbn/elastic-assistant-common';
|
||||
import { ChromeStart, NavigateToAppOptions, UserProfileService } from '@kbn/core/public';
|
||||
import type { ProductDocBasePluginStart } from '@kbn/product-doc-base-plugin/public';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { updatePromptContexts } from './helpers';
|
||||
import type {
|
||||
|
@ -78,6 +79,7 @@ export interface AssistantProviderProps {
|
|||
title?: string;
|
||||
toasts?: IToasts;
|
||||
currentAppId: string;
|
||||
productDocBase: ProductDocBasePluginStart;
|
||||
userProfileService: UserProfileService;
|
||||
chrome: ChromeStart;
|
||||
}
|
||||
|
@ -131,6 +133,7 @@ export interface UseAssistantContext {
|
|||
unRegisterPromptContext: UnRegisterPromptContext;
|
||||
currentAppId: string;
|
||||
codeBlockRef: React.MutableRefObject<(codeBlock: string) => void>;
|
||||
productDocBase: ProductDocBasePluginStart;
|
||||
userProfileService: UserProfileService;
|
||||
chrome: ChromeStart;
|
||||
}
|
||||
|
@ -153,6 +156,7 @@ export const AssistantProvider: React.FC<AssistantProviderProps> = ({
|
|||
baseConversations,
|
||||
navigateToApp,
|
||||
nameSpace = DEFAULT_ASSISTANT_NAMESPACE,
|
||||
productDocBase,
|
||||
title = DEFAULT_ASSISTANT_TITLE,
|
||||
toasts,
|
||||
currentAppId,
|
||||
|
@ -291,6 +295,7 @@ export const AssistantProvider: React.FC<AssistantProviderProps> = ({
|
|||
promptContexts,
|
||||
navigateToApp,
|
||||
nameSpace,
|
||||
productDocBase,
|
||||
registerPromptContext,
|
||||
selectedSettingsTab,
|
||||
// can be undefined from localStorage, if not defined, default to true
|
||||
|
@ -331,6 +336,7 @@ export const AssistantProvider: React.FC<AssistantProviderProps> = ({
|
|||
promptContexts,
|
||||
navigateToApp,
|
||||
nameSpace,
|
||||
productDocBase,
|
||||
registerPromptContext,
|
||||
selectedSettingsTab,
|
||||
localStorageStreaming,
|
||||
|
|
|
@ -31,6 +31,7 @@ import {
|
|||
import { css } from '@emotion/react';
|
||||
import { DataViewsContract } from '@kbn/data-views-plugin/public';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { ProductDocumentationManagement } from '../../assistant/settings/product_documentation';
|
||||
import { KnowledgeBaseTour } from '../../tour/knowledge_base';
|
||||
import { AlertsSettingsManagement } from '../../assistant/settings/alerts_settings/alerts_settings_management';
|
||||
import { useKnowledgeBaseEntries } from '../../assistant/api/knowledge_base/entries/use_knowledge_base_entries';
|
||||
|
@ -332,6 +333,7 @@ export const KnowledgeBaseSettingsManagement: React.FC<Params> = React.memo(({ d
|
|||
|
||||
return (
|
||||
<>
|
||||
<ProductDocumentationManagement />
|
||||
<EuiPanel hasShadow={false} hasBorder paddingSize="l">
|
||||
<EuiText size={'m'}>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -88,6 +88,9 @@ export const TestProvidersComponent: React.FC<Props> = ({
|
|||
navigateToApp={mockNavigateToApp}
|
||||
{...providerContext}
|
||||
currentAppId={'test'}
|
||||
productDocBase={{
|
||||
installation: { getStatus: jest.fn(), install: jest.fn(), uninstall: jest.fn() },
|
||||
}}
|
||||
userProfileService={jest.fn() as unknown as UserProfileService}
|
||||
chrome={chrome}
|
||||
>
|
||||
|
|
|
@ -37,5 +37,6 @@
|
|||
"@kbn/core-chrome-browser-mocks",
|
||||
"@kbn/core-chrome-browser",
|
||||
"@kbn/ai-assistant-icon",
|
||||
"@kbn/product-doc-base-plugin",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -88,6 +88,9 @@ const TestExternalProvidersComponent: React.FC<TestExternalProvidersProps> = ({
|
|||
http={mockHttp}
|
||||
baseConversations={{}}
|
||||
navigateToApp={mockNavigateToApp}
|
||||
productDocBase={{
|
||||
installation: { getStatus: jest.fn(), install: jest.fn(), uninstall: jest.fn() },
|
||||
}}
|
||||
currentAppId={'securitySolutionUI'}
|
||||
userProfileService={jest.fn() as unknown as UserProfileService}
|
||||
chrome={chrome}
|
||||
|
|
|
@ -59,7 +59,8 @@
|
|||
"charts",
|
||||
"entityManager",
|
||||
"inference",
|
||||
"discoverShared"
|
||||
"discoverShared",
|
||||
"productDocBase"
|
||||
],
|
||||
"optionalPlugins": [
|
||||
"encryptedSavedObjects",
|
||||
|
|
|
@ -144,6 +144,7 @@ export const AssistantProvider: FC<PropsWithChildren<unknown>> = ({ children })
|
|||
docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION },
|
||||
userProfile,
|
||||
chrome,
|
||||
productDocBase,
|
||||
} = useKibana().services;
|
||||
|
||||
let inferenceEnabled = false;
|
||||
|
@ -235,6 +236,7 @@ export const AssistantProvider: FC<PropsWithChildren<unknown>> = ({ children })
|
|||
http={http}
|
||||
inferenceEnabled={inferenceEnabled}
|
||||
navigateToApp={navigateToApp}
|
||||
productDocBase={productDocBase}
|
||||
title={ASSISTANT_TITLE}
|
||||
toasts={toasts}
|
||||
currentAppId={currentAppId ?? 'securitySolutionUI'}
|
||||
|
|
|
@ -61,6 +61,9 @@ export const MockAssistantProviderComponent: React.FC<Props> = ({
|
|||
navigateToApp={mockNavigateToApp}
|
||||
baseConversations={BASE_SECURITY_CONVERSATIONS}
|
||||
currentAppId={'test'}
|
||||
productDocBase={{
|
||||
installation: { getStatus: jest.fn(), install: jest.fn(), uninstall: jest.fn() },
|
||||
}}
|
||||
userProfileService={mockUserProfileService}
|
||||
chrome={chrome}
|
||||
>
|
||||
|
|
|
@ -12,15 +12,10 @@ import { render } from '@testing-library/react';
|
|||
import type { RuleExecutionStatus } from '../../../../../common/api/detection_engine/rule_monitoring';
|
||||
import { RuleExecutionStatusEnum } from '../../../../../common/api/detection_engine/rule_monitoring';
|
||||
import { RuleStatusFailedCallOut } from './rule_status_failed_callout';
|
||||
import { AssistantProvider } from '@kbn/elastic-assistant';
|
||||
import type { AssistantAvailability } from '@kbn/elastic-assistant';
|
||||
import { httpServiceMock } from '@kbn/core-http-browser-mocks';
|
||||
import { actionTypeRegistryMock } from '@kbn/triggers-actions-ui-plugin/public/application/action_type_registry.mock';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { BASE_SECURITY_CONVERSATIONS } from '../../../../assistant/content/conversations';
|
||||
import type { UserProfileService } from '@kbn/core-user-profile-browser';
|
||||
import { chromeServiceMock } from '@kbn/core/public/mocks';
|
||||
import { of } from 'rxjs';
|
||||
import { MockAssistantProviderComponent } from '../../../../common/mock/mock_assistant_provider';
|
||||
|
||||
jest.mock('../../../../common/lib/kibana');
|
||||
|
||||
|
@ -28,18 +23,6 @@ const TEST_ID = 'ruleStatusFailedCallOut';
|
|||
const DATE = '2022-01-27T15:03:31.176Z';
|
||||
const MESSAGE = 'This rule is attempting to query data but...';
|
||||
|
||||
const actionTypeRegistry = actionTypeRegistryMock.create();
|
||||
const mockGetComments = jest.fn(() => []);
|
||||
const mockHttp = httpServiceMock.createStartContract({ basePath: '/test' });
|
||||
const mockNavigationToApp = jest.fn();
|
||||
const mockAssistantAvailability: AssistantAvailability = {
|
||||
hasAssistantPrivilege: false,
|
||||
hasConnectorsAllPrivilege: true,
|
||||
hasConnectorsReadPrivilege: true,
|
||||
hasUpdateAIAssistantAnonymization: true,
|
||||
hasManageGlobalKnowledgeBase: true,
|
||||
isAssistantEnabled: true,
|
||||
};
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
|
@ -58,25 +41,7 @@ const ContextWrapper: FC<PropsWithChildren<unknown>> = ({ children }) => {
|
|||
chrome.getChromeStyle$.mockReturnValue(of('classic'));
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<AssistantProvider
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
assistantAvailability={mockAssistantAvailability}
|
||||
augmentMessageCodeBlocks={jest.fn()}
|
||||
basePath={'https://localhost:5601/kbn'}
|
||||
docLinks={{
|
||||
ELASTIC_WEBSITE_URL: 'https://www.elastic.co/',
|
||||
DOC_LINK_VERSION: 'current',
|
||||
}}
|
||||
getComments={mockGetComments}
|
||||
http={mockHttp}
|
||||
navigateToApp={mockNavigationToApp}
|
||||
baseConversations={BASE_SECURITY_CONVERSATIONS}
|
||||
currentAppId={'security'}
|
||||
userProfileService={jest.fn() as unknown as UserProfileService}
|
||||
chrome={chrome}
|
||||
>
|
||||
{children}
|
||||
</AssistantProvider>
|
||||
<MockAssistantProviderComponent>{children}</MockAssistantProviderComponent>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -153,6 +153,7 @@ export class PluginServices {
|
|||
customDataService,
|
||||
timelineDataService,
|
||||
topValuesPopover: new TopValuesPopoverService(),
|
||||
productDocBase: startPlugins.productDocBase,
|
||||
siemMigrations: await createSiemMigrationsService(coreStart, startPlugins),
|
||||
...(params && {
|
||||
onAppLeave: params.onAppLeave,
|
||||
|
|
|
@ -21,6 +21,7 @@ import type { Storage } from '@kbn/kibana-utils-plugin/public';
|
|||
import type { FleetStart } from '@kbn/fleet-plugin/public';
|
||||
import type { PluginStart as ListsPluginStart } from '@kbn/lists-plugin/public';
|
||||
import type { SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
||||
import type { ProductDocBasePluginStart } from '@kbn/product-doc-base-plugin/public';
|
||||
import type {
|
||||
TriggersAndActionsUIPublicPluginSetup as TriggersActionsSetup,
|
||||
TriggersAndActionsUIPublicPluginStart as TriggersActionsStart,
|
||||
|
@ -161,6 +162,7 @@ export interface StartPlugins {
|
|||
core: CoreStart;
|
||||
integrationAssistant?: IntegrationAssistantPluginStart;
|
||||
serverless?: ServerlessPluginStart;
|
||||
productDocBase: ProductDocBasePluginStart;
|
||||
}
|
||||
|
||||
export interface StartPluginsDependencies extends StartPlugins {
|
||||
|
@ -198,6 +200,7 @@ export type StartServices = CoreStart &
|
|||
topValuesPopover: TopValuesPopoverService;
|
||||
timelineDataService: DataPublicPluginStart;
|
||||
siemMigrations: SiemMigrationsService;
|
||||
productDocBase: ProductDocBasePluginStart;
|
||||
};
|
||||
|
||||
export type StartRenderServices = Pick<
|
||||
|
|
|
@ -225,7 +225,6 @@
|
|||
"@kbn/core-saved-objects-server-mocks",
|
||||
"@kbn/core-security-server-mocks",
|
||||
"@kbn/serverless",
|
||||
"@kbn/core-user-profile-browser",
|
||||
"@kbn/data-stream-adapter",
|
||||
"@kbn/core-lifecycle-server",
|
||||
"@kbn/core-user-profile-common",
|
||||
|
@ -237,6 +236,7 @@
|
|||
"@kbn/core-chrome-browser-mocks",
|
||||
"@kbn/ai-assistant-icon",
|
||||
"@kbn/llm-tasks-plugin",
|
||||
"@kbn/charts-theme"
|
||||
"@kbn/charts-theme",
|
||||
"@kbn/product-doc-base-plugin"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue