mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Security AI Assistant] Conversation migration bugs (#181512)
Fixed duplication conversations and actionTypeId for removed connectors: <img width="2030" alt="Screenshot 2024-04-23 at 8 17 16 AM" src="e85a894a
-c9ae-4691-95ba-24f37931f47e"> <img width="2253" alt="Screenshot 2024-04-23 at 8 03 44 AM" src="c8040605
-b994-424e-bf52-652f30057d31">
This commit is contained in:
parent
7895df6ee2
commit
f0e4a97219
4 changed files with 74 additions and 42 deletions
|
@ -12,8 +12,10 @@ import {
|
|||
ApiConfig,
|
||||
Replacements,
|
||||
API_VERSIONS,
|
||||
ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_FIND,
|
||||
} from '@kbn/elastic-assistant-common';
|
||||
import { Conversation, ClientMessage } from '../../../assistant_context/types';
|
||||
import { FetchConversationsResponse } from './use_fetch_current_user_conversations';
|
||||
|
||||
export interface GetConversationByIdParams {
|
||||
http: HttpSetup;
|
||||
|
@ -58,6 +60,44 @@ export const getConversationById = async ({
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* API call for getting all user conversations.
|
||||
*
|
||||
* @param {Object} options - The options object.
|
||||
* @param {HttpSetup} options.http - HttpSetup
|
||||
* @param {IToasts} [options.toasts] - IToasts
|
||||
* @param {AbortSignal} [options.signal] - AbortSignal
|
||||
*
|
||||
* @returns {Promise<FetchConversationsResponse>}
|
||||
*/
|
||||
export const getUserConversations = async ({
|
||||
http,
|
||||
signal,
|
||||
toasts,
|
||||
}: {
|
||||
http: HttpSetup;
|
||||
toasts?: IToasts;
|
||||
signal?: AbortSignal | undefined;
|
||||
}) => {
|
||||
try {
|
||||
return await http.fetch<FetchConversationsResponse>(
|
||||
ELASTIC_AI_ASSISTANT_CONVERSATIONS_URL_FIND,
|
||||
{
|
||||
method: 'GET',
|
||||
version: API_VERSIONS.public.v1,
|
||||
signal,
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
toasts?.addError(error.body && error.body.message ? new Error(error.body.message) : error, {
|
||||
title: i18n.translate('xpack.elasticAssistant.conversations.getUserConversationsError', {
|
||||
defaultMessage: 'Error fetching conversations',
|
||||
}),
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export interface PostConversationParams {
|
||||
http: HttpSetup;
|
||||
conversation: Partial<Conversation>;
|
||||
|
|
|
@ -159,3 +159,4 @@ export { getConversationById } from './impl/assistant/api/conversations/conversa
|
|||
export { mergeBaseWithPersistedConversations } from './impl/assistant/helpers';
|
||||
|
||||
export { UpgradeButtons } from './impl/upgrade/upgrade_buttons';
|
||||
export { getUserConversations } from './impl/assistant/api';
|
||||
|
|
|
@ -158,7 +158,6 @@ describe('createConversations', () => {
|
|||
await act(async () => {
|
||||
const { waitForNextUpdate } = renderHook(() =>
|
||||
createConversations(
|
||||
[],
|
||||
coreMock.createStart().notifications,
|
||||
http,
|
||||
mockStorage as unknown as Storage
|
||||
|
@ -181,7 +180,6 @@ describe('createConversations', () => {
|
|||
await act(async () => {
|
||||
const { waitForNextUpdate } = renderHook(() =>
|
||||
createConversations(
|
||||
[],
|
||||
coreMock.createStart().notifications,
|
||||
http,
|
||||
mockStorage as unknown as Storage
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { parse } from '@kbn/datemath';
|
||||
import type { Storage } from '@kbn/kibana-utils-plugin/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -13,15 +13,14 @@ import type { Conversation } from '@kbn/elastic-assistant';
|
|||
import {
|
||||
AssistantProvider as ElasticAssistantProvider,
|
||||
bulkUpdateConversations,
|
||||
mergeBaseWithPersistedConversations,
|
||||
useFetchCurrentUserConversations,
|
||||
getUserConversations,
|
||||
} from '@kbn/elastic-assistant';
|
||||
|
||||
import type { FetchConversationsResponse } from '@kbn/elastic-assistant/impl/assistant/api';
|
||||
import { once } from 'lodash/fp';
|
||||
import type { HttpSetup } from '@kbn/core-http-browser';
|
||||
import type { Message } from '@kbn/elastic-assistant-common';
|
||||
import { loadAllActions as loadConnectors } from '@kbn/triggers-actions-ui-plugin/public/common/constants';
|
||||
import { APP_ID } from '../../common';
|
||||
import { useBasePath, useKibana } from '../common/lib/kibana';
|
||||
import { useAssistantTelemetry } from './use_assistant_telemetry';
|
||||
import { getComments } from './get_comments';
|
||||
|
@ -46,22 +45,15 @@ const LOCAL_CONVERSATIONS_MIGRATION_STATUS_TOAST_TITLE = i18n.translate(
|
|||
);
|
||||
|
||||
export const createConversations = async (
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
conversationsData: Record<string, any>,
|
||||
notifications: NotificationsStart,
|
||||
http: HttpSetup,
|
||||
storage: Storage
|
||||
) => {
|
||||
// migrate conversations with messages from the local storage
|
||||
// won't happen next time
|
||||
const conversations = storage.get(`securitySolution.${LOCAL_STORAGE_KEY}`);
|
||||
const conversations = storage.get(`${APP_ID}.${LOCAL_STORAGE_KEY}`);
|
||||
|
||||
if (
|
||||
conversationsData &&
|
||||
Object.keys(conversationsData).length === 0 &&
|
||||
conversations &&
|
||||
Object.keys(conversations).length > 0
|
||||
) {
|
||||
if (conversations && Object.keys(conversations).length > 0) {
|
||||
const conversationsToCreate = Object.values(conversations).filter(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(c: any) => c.messages && c.messages.length > 0
|
||||
|
@ -87,10 +79,14 @@ export const createConversations = async (
|
|||
const selectedConnector = (connectors ?? []).find(
|
||||
(connector) => connector.id === c.apiConfig.connectorId
|
||||
);
|
||||
c.apiConfig = {
|
||||
...c.apiConfig,
|
||||
actionTypeId: selectedConnector?.actionTypeId,
|
||||
};
|
||||
if (selectedConnector) {
|
||||
c.apiConfig = {
|
||||
...c.apiConfig,
|
||||
actionTypeId: selectedConnector.actionTypeId,
|
||||
};
|
||||
} else {
|
||||
c.apiConfig = undefined;
|
||||
}
|
||||
}
|
||||
res[c.id] = {
|
||||
...c,
|
||||
|
@ -104,7 +100,7 @@ export const createConversations = async (
|
|||
notifications.toasts
|
||||
);
|
||||
if (bulkResult && bulkResult.success) {
|
||||
storage.remove(`securitySolution.${LOCAL_STORAGE_KEY}`);
|
||||
storage.remove(`${APP_ID}.${LOCAL_STORAGE_KEY}`);
|
||||
notifications.toasts?.addSuccess({
|
||||
iconType: 'check',
|
||||
title: LOCAL_CONVERSATIONS_MIGRATION_STATUS_TOAST_TITLE,
|
||||
|
@ -132,30 +128,27 @@ export const AssistantProvider: React.FC = ({ children }) => {
|
|||
const assistantAvailability = useAssistantAvailability();
|
||||
const assistantTelemetry = useAssistantTelemetry();
|
||||
|
||||
const migrateConversationsFromLocalStorage = once(
|
||||
(conversationsData: Record<string, Conversation>) =>
|
||||
createConversations(conversationsData, notifications, http, storage)
|
||||
);
|
||||
const onFetchedConversations = useCallback(
|
||||
(conversationsData: FetchConversationsResponse): Record<string, Conversation> => {
|
||||
const mergedData = mergeBaseWithPersistedConversations({}, conversationsData);
|
||||
if (assistantAvailability.isAssistantEnabled && assistantAvailability.hasAssistantPrivilege) {
|
||||
migrateConversationsFromLocalStorage(mergedData);
|
||||
useEffect(() => {
|
||||
const migrateConversationsFromLocalStorage = once(async () => {
|
||||
const res = await getUserConversations({
|
||||
http,
|
||||
});
|
||||
if (
|
||||
assistantAvailability.isAssistantEnabled &&
|
||||
assistantAvailability.hasAssistantPrivilege &&
|
||||
res.total === 0
|
||||
) {
|
||||
await createConversations(notifications, http, storage);
|
||||
}
|
||||
return mergedData;
|
||||
},
|
||||
[
|
||||
assistantAvailability.hasAssistantPrivilege,
|
||||
assistantAvailability.isAssistantEnabled,
|
||||
migrateConversationsFromLocalStorage,
|
||||
]
|
||||
);
|
||||
useFetchCurrentUserConversations({
|
||||
});
|
||||
migrateConversationsFromLocalStorage();
|
||||
}, [
|
||||
assistantAvailability.hasAssistantPrivilege,
|
||||
assistantAvailability.isAssistantEnabled,
|
||||
http,
|
||||
onFetch: onFetchedConversations,
|
||||
isAssistantEnabled:
|
||||
assistantAvailability.isAssistantEnabled && assistantAvailability.hasAssistantPrivilege,
|
||||
});
|
||||
notifications,
|
||||
storage,
|
||||
]);
|
||||
|
||||
const { signalIndexName } = useSignalIndex();
|
||||
const alertsIndexPattern = signalIndexName ?? undefined;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue