From c316c0aa39ed55c7176cd4c1be25cdc3c1a73005 Mon Sep 17 00:00:00 2001
From: Angela Chuang
Date: Mon, 3 Jun 2024 18:46:33 +0100
Subject: [PATCH 01/37] connectors tab
---
.../ai_assistant_selection_page.tsx | 85 +++++---
.../assistant/settings/assistant_settings.tsx | 14 +-
.../assistant_settings_management.tsx | 33 ++--
.../impl/assistant/settings/translations.ts | 14 ++
.../impl/assistant_context/index.tsx | 20 +-
.../connector_row_actions.tsx | 58 ++++++
.../connector_settings/index.tsx | 182 ++++++++++++++++++
.../connectorland/connector_setup/index.tsx | 7 +-
.../impl/connectorland/translations.ts | 35 ++++
.../public/assistant/provider.tsx | 4 +-
10 files changed, 402 insertions(+), 50 deletions(-)
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/connector_row_actions.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx
diff --git a/src/plugins/ai_assistant_management/selection/public/routes/components/ai_assistant_selection_page.tsx b/src/plugins/ai_assistant_management/selection/public/routes/components/ai_assistant_selection_page.tsx
index 62687625db86d..5a494bdb3b257 100644
--- a/src/plugins/ai_assistant_management/selection/public/routes/components/ai_assistant_selection_page.tsx
+++ b/src/plugins/ai_assistant_management/selection/public/routes/components/ai_assistant_selection_page.tsx
@@ -9,6 +9,7 @@
import React, { useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import {
+ EuiButton,
EuiCallOut,
EuiCard,
EuiFlexGrid,
@@ -86,32 +87,48 @@ export function AiAssistantSelectionPage() {
>
) : null}
-
+ {i18n.translate(
+ 'aiAssistantManagementSelection.aiAssistantSelectionPage.obsAssistant.documentationLinkDescription',
+ { defaultMessage: 'For more info, see our' }
+ )}{' '}
+
+ {i18n.translate(
+ 'aiAssistantManagementSelection.aiAssistantSettingsPage.obsAssistant.documentationLinkLabel',
+ { defaultMessage: 'Documentation' }
+ )}
+
+
+
+ navigateToApp('management', {
+ path: 'kibana/observabilityAiAssistantManagement',
+ })
+ }
>
{i18n.translate(
- 'aiAssistantManagementSelection.aiAssistantSettingsPage.obsAssistant.documentationLinkLabel',
- { defaultMessage: 'Documentation' }
+ 'aiAssistantManagementSelection.aiAssistantSelectionPage.obsAssistant.manageSettingsButtonLabel',
+ { defaultMessage: 'Manage Settings' }
)}
-
+
}
display="plain"
hasBorder
- icon={}
+ icon={}
isDisabled={!observabilityAIAssistantEnabled}
- layout="horizontal"
title={i18n.translate(
'aiAssistantManagementSelection.aiAssistantSelectionPage.observabilityLabel',
{ defaultMessage: 'Elastic AI Assistant for Observability' }
)}
titleSize="xs"
- onClick={() =>
- navigateToApp('management', { path: 'kibana/observabilityAiAssistantManagement' })
- }
/>
@@ -135,32 +152,46 @@ export function AiAssistantSelectionPage() {
>
) : null}
-
+ {i18n.translate(
+ 'aiAssistantManagementSelection.aiAssistantSelectionPage.securityAssistant.documentationLinkDescription',
+ { defaultMessage: 'For more info, see our' }
+ )}{' '}
+
+ {i18n.translate(
+ 'aiAssistantManagementSelection.aiAssistantSettingsPage.securityAssistant.documentationLinkLabel',
+ { defaultMessage: 'Documentation' }
+ )}
+
+
+
+ navigateToApp('management', { path: 'kibana/securityAiAssistantManagement' })
+ }
>
{i18n.translate(
- 'aiAssistantManagementSelection.aiAssistantSettingsPage.securityAssistant.documentationLinkLabel',
- { defaultMessage: 'Documentation' }
+ 'aiAssistantManagementSelection.aiAssistantSelectionPage.securityAssistant.manageSettingsButtonLabel',
+ { defaultMessage: 'Manage Settings' }
)}
-
+
}
display="plain"
hasBorder
- icon={}
+ icon={}
isDisabled={!securityAIAssistantEnabled}
- layout="horizontal"
title={i18n.translate(
'aiAssistantManagementSelection.aiAssistantSelectionPage.securityLabel',
- { defaultMessage: 'Elastic AI Assistant for Security' }
+ { defaultMessage: 'Elastic AI for Security' }
)}
titleSize="xs"
- onClick={() =>
- navigateToApp('management', { path: 'kibana/securityAiAssistantManagement' })
- }
/>
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.tsx
index f83e6c0d72ee6..999d511d570ec 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.tsx
@@ -44,6 +44,7 @@ const StyledEuiModal = styled(EuiModal)`
height: 575px;
`;
+export const CONNECTORS_TAB = 'CONNECTORS_TAB' as const;
export const CONVERSATIONS_TAB = 'CONVERSATION_TAB' as const;
export const QUICK_PROMPTS_TAB = 'QUICK_PROMPTS_TAB' as const;
export const SYSTEM_PROMPTS_TAB = 'SYSTEM_PROMPTS_TAB' as const;
@@ -51,13 +52,18 @@ export const ANONYMIZATION_TAB = 'ANONYMIZATION_TAB' as const;
export const KNOWLEDGE_BASE_TAB = 'KNOWLEDGE_BASE_TAB' as const;
export const EVALUATION_TAB = 'EVALUATION_TAB' as const;
-export type SettingsTabs =
+export type BaseSettingsTabs =
| typeof CONVERSATIONS_TAB
| typeof QUICK_PROMPTS_TAB
| typeof SYSTEM_PROMPTS_TAB
| typeof ANONYMIZATION_TAB
| typeof KNOWLEDGE_BASE_TAB
| typeof EVALUATION_TAB;
+
+export type AdditionalSettingsTabs = typeof CONNECTORS_TAB;
+
+export type SettingsTabs = BaseSettingsTabs | AdditionalSettingsTabs;
+
interface Props {
defaultConnector?: AIConnector;
onClose: (
@@ -93,6 +99,12 @@ export const AssistantSettings: React.FC = React.memo(
setSelectedSettingsTab,
} = useAssistantContext();
+ useEffect(() => {
+ if (selectedSettingsTab == null) {
+ setSelectedSettingsTab(CONVERSATIONS_TAB);
+ }
+ }, [selectedSettingsTab, setSelectedSettingsTab]);
+
const { data: anonymizationFields, refetch: refetchAnonymizationFieldsResults } =
useFetchAnonymizationFields();
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
index 79a050b11bb27..f9b335b84b03f 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
@@ -9,7 +9,6 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
EuiButton,
EuiButtonEmpty,
- EuiIcon,
EuiFlexItem,
EuiPageTemplate,
EuiFlexGroup,
@@ -31,7 +30,9 @@ import {
import { useLoadConnectors } from '../../connectorland/use_load_connectors';
import { getDefaultConnector } from '../helpers';
import { useFetchAnonymizationFields } from '../api/anonymization_fields/use_fetch_anonymization_fields';
+import { ConnectorsSettings } from '../../connectorland/connector_settings';
+export const CONNECTORS_TAB = 'CONNECTORS_TAB' as const;
export const CONVERSATIONS_TAB = 'CONVERSATION_TAB' as const;
export const QUICK_PROMPTS_TAB = 'QUICK_PROMPTS_TAB' as const;
export const SYSTEM_PROMPTS_TAB = 'SYSTEM_PROMPTS_TAB' as const;
@@ -39,13 +40,6 @@ export const ANONYMIZATION_TAB = 'ANONYMIZATION_TAB' as const;
export const KNOWLEDGE_BASE_TAB = 'KNOWLEDGE_BASE_TAB' as const;
export const EVALUATION_TAB = 'EVALUATION_TAB' as const;
-export type SettingsTabs =
- | typeof CONVERSATIONS_TAB
- | typeof QUICK_PROMPTS_TAB
- | typeof SYSTEM_PROMPTS_TAB
- | typeof ANONYMIZATION_TAB
- | typeof KNOWLEDGE_BASE_TAB
- | typeof EVALUATION_TAB;
interface Props {
conversations: Record;
selectedConversation: Conversation;
@@ -125,6 +119,12 @@ export const AssistantSettingsManagement: React.FC = React.memo(
}
}, [conversationSettings, selectedConversation]);
+ useEffect(() => {
+ if (selectedSettingsTab == null) {
+ setSelectedSettingsTab(CONNECTORS_TAB);
+ }
+ }, [selectedSettingsTab, setSelectedSettingsTab]);
+
// Quick Prompt Selection State
const [selectedQuickPrompt, setSelectedQuickPrompt] = useState();
const onHandleSelectedQuickPromptChange = useCallback((quickPrompt?: QuickPrompt) => {
@@ -173,37 +173,35 @@ export const AssistantSettingsManagement: React.FC = React.memo(
const tabsConfig = useMemo(
() => [
+ {
+ id: CONNECTORS_TAB,
+ label: i18n.CONNECTORS_MENU_ITEM,
+ },
{
id: CONVERSATIONS_TAB,
label: i18n.CONVERSATIONS_MENU_ITEM,
- prepend: ,
},
{
id: QUICK_PROMPTS_TAB,
label: i18n.QUICK_PROMPTS_MENU_ITEM,
- prepend: ,
},
{
id: SYSTEM_PROMPTS_TAB,
label: i18n.SYSTEM_PROMPTS_MENU_ITEM,
- prepend: ,
},
{
id: ANONYMIZATION_TAB,
label: i18n.ANONYMIZATION_MENU_ITEM,
- prepend: ,
},
{
id: KNOWLEDGE_BASE_TAB,
label: i18n.KNOWLEDGE_BASE_MENU_ITEM,
- prepend: ,
},
...(modelEvaluatorEnabled
? [
{
id: EVALUATION_TAB,
label: i18n.EVALUATION_MENU_ITEM,
- prepend: ,
},
]
: []),
@@ -235,7 +233,11 @@ export const AssistantSettingsManagement: React.FC = React.memo(
return (
<>
-
+
= React.memo(
padding-right: 0;
`}
>
+ {selectedSettingsTab === CONNECTORS_TAB && }
{selectedSettingsTab === CONVERSATIONS_TAB && (
;
children: React.ReactNode;
+ getAddConnectorFlyout: TriggersAndActionsUIPublicPluginStart['getAddConnectorFlyout'];
+ getEditConnectorFlyout: TriggersAndActionsUIPublicPluginStart['getEditConnectorFlyout'];
getComments: (commentArgs: {
abortStream: () => void;
currentConversation?: Conversation;
@@ -112,6 +117,7 @@ export interface UseAssistantContext {
baseQuickPrompts: QuickPrompt[];
baseSystemPrompts: Prompt[];
baseConversations: Record;
+ getEditConnectorFlyout: TriggersAndActionsUIPublicPluginStart['getEditConnectorFlyout'];
getComments: (commentArgs: {
abortStream: () => void;
currentConversation?: Conversation;
@@ -130,7 +136,7 @@ export interface UseAssistantContext {
promptContexts: Record;
nameSpace: string;
registerPromptContext: RegisterPromptContext;
- selectedSettingsTab: SettingsTabs;
+ selectedSettingsTab: SettingsTabs | null;
setAllQuickPrompts: React.Dispatch>;
setAllSystemPrompts: React.Dispatch>;
setAssistantStreamingEnabled: React.Dispatch>;
@@ -164,6 +170,8 @@ export const AssistantProvider: React.FC = ({
baseQuickPrompts = [],
baseSystemPrompts = BASE_SYSTEM_PROMPTS,
children,
+ getAddConnectorFlyout,
+ getEditConnectorFlyout,
getComments,
http,
baseConversations,
@@ -264,7 +272,7 @@ export const AssistantProvider: React.FC = ({
/**
* Settings State
*/
- const [selectedSettingsTab, setSelectedSettingsTab] = useState(CONVERSATIONS_TAB);
+ const [selectedSettingsTab, setSelectedSettingsTab] = useState(null);
const getLastConversationId = useCallback(
// if a conversationId has been provided, use that
@@ -293,6 +301,8 @@ export const AssistantProvider: React.FC = ({
baseQuickPrompts,
baseSystemPrompts,
docLinks,
+ getAddConnectorFlyout,
+ getEditConnectorFlyout,
getComments,
http,
knowledgeBase: { ...DEFAULT_KNOWLEDGE_BASE_SETTINGS, ...localStorageKnowledgeBase },
@@ -332,6 +342,8 @@ export const AssistantProvider: React.FC = ({
baseQuickPrompts,
baseSystemPrompts,
docLinks,
+ getAddConnectorFlyout,
+ getEditConnectorFlyout,
getComments,
http,
localStorageKnowledgeBase,
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/connector_row_actions.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/connector_row_actions.tsx
new file mode 100644
index 0000000000000..c6f73840ac09f
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/connector_row_actions.tsx
@@ -0,0 +1,58 @@
+/*
+ * 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 { EuiButtonEmpty, EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiPopover } from '@elastic/eui';
+import React, { useCallback, useState } from 'react';
+import { AIConnector } from '../connector_selector';
+
+import { DELETE_CONNECTOR_BUTTON, EDIT_CONNECTOR_BUTTON } from '../translations';
+
+interface Props {
+ connector: AIConnector;
+ onClickEditConnector: (connector: AIConnector) => void;
+}
+
+const ConnectorRowActionsComponent: React.FC = ({ connector, onClickEditConnector }) => {
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+
+ const closePopover = useCallback(() => setIsPopoverOpen(false), []);
+ const handleEditConnector = useCallback(() => {
+ closePopover();
+ onClickEditConnector(connector);
+ }, [closePopover, onClickEditConnector, connector]);
+
+ const onButtonClick = useCallback(() => setIsPopoverOpen((prevState) => !prevState), []);
+ return (
+
+ }
+ isOpen={isPopoverOpen}
+ closePopover={closePopover}
+ anchorPosition="downLeft"
+ >
+
+
+
+ {EDIT_CONNECTOR_BUTTON}
+
+
+
+ {DELETE_CONNECTOR_BUTTON}
+
+
+
+ );
+};
+
+export const ConnectorRowActions = React.memo(ConnectorRowActionsComponent);
+ConnectorRowActions.displayName = 'ConnectorRowActions';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx
new file mode 100644
index 0000000000000..fb2d36911c4c2
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx
@@ -0,0 +1,182 @@
+/*
+ * 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 {
+ EuiBadge,
+ EuiButton,
+ EuiButtonEmpty,
+ EuiCallOut,
+ EuiInMemoryTable,
+ EuiSearchBarProps,
+ EuiSkeletonText,
+} from '@elastic/eui';
+import React, { useCallback, useMemo, useState } from 'react';
+import { useAssistantContext } from '../../assistant_context';
+import { AIConnector } from '../connector_selector';
+import { useLoadConnectors } from '../use_load_connectors';
+import {
+ CREATE_CONNECTOR_BUTTON,
+ MISSING_READ_CONNECTORS_CALLOUT_TITLE,
+ REFRESH_CONNECTORS_BUTTON,
+} from '../translations';
+import { ConnectorRowActions } from './connector_row_actions';
+
+export interface Props {}
+
+const emptyConnectors = [] as AIConnector[];
+
+const ConnectorsSettingsComponent: React.FC = () => {
+ const { http, assistantAvailability, getEditConnectorFlyout } = useAssistantContext();
+ const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false);
+
+ const onCloseEditFlyout = useCallback(() => {
+ setEditFlyoutVisibility(false);
+ }, []);
+ const [editedConnectorItem, setEditedConnectorItem] = useState(null);
+
+ const {
+ data: aiConnectors,
+ refetch: refetchConnectors,
+ isFetchedAfterMount: areConnectorsFetched,
+ } = useLoadConnectors({ http });
+
+ const [query, setQuery] = useState('');
+
+ const handleOnChange: EuiSearchBarProps['onChange'] = ({ queryText, error }) => {
+ if (!error) {
+ setQuery(queryText);
+ }
+ };
+
+ const handleRefetchConnectors = useCallback(() => {
+ refetchConnectors();
+ }, [refetchConnectors]);
+
+ const onClickEditConnector = useCallback((connector: AIConnector) => {
+ setEditedConnectorItem(connector);
+ setEditFlyoutVisibility(true);
+ }, []);
+
+ const columns = [
+ {
+ name: 'Connector name',
+ truncateText: false,
+ mobileOptions: {
+ show: true,
+ },
+ render: (connector: AIConnector) => (
+ onClickEditConnector(connector)}>
+ {connector.name}
+
+ ),
+ },
+ {
+ field: 'apiProvider',
+ name: 'Type',
+ truncateText: false,
+ mobileOptions: {
+ show: true,
+ },
+ render: (apiProvider: AIConnector['apiProvider']) => (
+ {apiProvider}
+ ),
+ },
+ {
+ name: 'Actions',
+ actions: [
+ {
+ name: 'Action',
+ icon: 'boxesHorizontal',
+ render: (connector: AIConnector) => {
+ return (
+
+ );
+ },
+ },
+ ],
+ },
+ ];
+
+ const search: EuiSearchBarProps = {
+ query,
+ onChange: handleOnChange,
+ box: {
+ schema: true,
+ placeholder: 'Search for connectors',
+ },
+ toolsRight: [
+
+ {REFRESH_CONNECTORS_BUTTON}
+ ,
+
+ {CREATE_CONNECTOR_BUTTON}
+ ,
+ ],
+ };
+
+ const onConnectorUpdated = useCallback(
+ async (updatedConnector) => {
+ setEditedConnectorItem(updatedConnector);
+ refetchConnectors();
+ },
+ [refetchConnectors, setEditedConnectorItem]
+ );
+
+ const ConnectorEditFlyout = useMemo(
+ () =>
+ editedConnectorItem && editFlyoutVisible
+ ? getEditConnectorFlyout({
+ connector: editedConnectorItem,
+ onClose: onCloseEditFlyout,
+ onConnectorUpdated,
+ })
+ : null,
+ [
+ editFlyoutVisible,
+ editedConnectorItem,
+ getEditConnectorFlyout,
+ onCloseEditFlyout,
+ onConnectorUpdated,
+ ]
+ );
+
+ if (!assistantAvailability.hasConnectorsReadPrivilege) {
+ return (
+
+ );
+ }
+
+ return areConnectorsFetched ? (
+ <>
+
+ {ConnectorEditFlyout}
+ >
+ ) : (
+
+ );
+};
+
+export const ConnectorsSettings = React.memo(ConnectorsSettingsComponent);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_setup/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_setup/index.tsx
index ab552656fc57f..81166bbf90fa1 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_setup/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_setup/index.tsx
@@ -35,7 +35,7 @@ export interface ConnectorSetupProps {
conversation?: Conversation;
isFlyoutMode?: boolean;
onSetupComplete?: () => void;
- onConversationUpdate: ({ cId, cTitle }: { cId: string; cTitle: string }) => Promise;
+ onConversationUpdate?: ({ cId, cTitle }: { cId: string; cTitle: string }) => Promise;
updateConversationsOnSaveConnector?: boolean;
}
@@ -198,7 +198,10 @@ export const useConnectorSetup = ({
});
if (updatedConversation) {
- onConversationUpdate({ cId: updatedConversation.id, cTitle: updatedConversation.title });
+ onConversationUpdate?.({
+ cId: updatedConversation.id,
+ cTitle: updatedConversation.title,
+ });
refetchConnectors?.();
setIsConnectorModalVisible(false);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
index 4381da8486497..424c7ce893726 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
@@ -149,3 +149,38 @@ export const MISSING_CONNECTOR_CONVERSATION_SETTINGS_LINK = i18n.translate(
defaultMessage: 'Conversation Settings',
}
);
+
+export const CREATE_CONNECTOR_BUTTON = i18n.translate(
+ 'xpack.elasticAssistant.assistant.connectors.createConnectorButton',
+ {
+ defaultMessage: 'Connector',
+ }
+);
+
+export const REFRESH_CONNECTORS_BUTTON = i18n.translate(
+ 'xpack.elasticAssistant.assistant.connectors.refreshConnectorsButton',
+ {
+ defaultMessage: 'Refresh',
+ }
+);
+
+export const EDIT_CONNECTOR_BUTTON = i18n.translate(
+ 'xpack.elasticAssistant.assistant.connectors.editConnectorButton',
+ {
+ defaultMessage: 'Edit',
+ }
+);
+
+export const DELETE_CONNECTOR_BUTTON = i18n.translate(
+ 'xpack.elasticAssistant.assistant.connectors.deleteConnectorButton',
+ {
+ defaultMessage: 'Delete',
+ }
+);
+
+export const MISSING_READ_CONNECTORS_CALLOUT_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.connectors.connectorMissingCallout.missingReadConnectorsCalloutTitle',
+ {
+ defaultMessage: 'Missing Read Connectors Privileges',
+ }
+);
diff --git a/x-pack/plugins/security_solution/public/assistant/provider.tsx b/x-pack/plugins/security_solution/public/assistant/provider.tsx
index 8516ec455aac0..3a4a9004c81f0 100644
--- a/x-pack/plugins/security_solution/public/assistant/provider.tsx
+++ b/x-pack/plugins/security_solution/public/assistant/provider.tsx
@@ -120,7 +120,7 @@ export const AssistantProvider: FC> = ({ children })
http,
notifications,
storage,
- triggersActionsUi: { actionTypeRegistry },
+ triggersActionsUi: { actionTypeRegistry, getAddConnectorFlyout, getEditConnectorFlyout },
docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION },
} = useKibana().services;
const basePath = useBasePath();
@@ -168,6 +168,8 @@ export const AssistantProvider: FC> = ({ children })
baseQuickPrompts={BASE_SECURITY_QUICK_PROMPTS} // to server and plugin start
baseSystemPrompts={BASE_SECURITY_SYSTEM_PROMPTS} // to server and plugin start
baseConversations={baseConversations}
+ getAddConnectorFlyout={getAddConnectorFlyout}
+ getEditConnectorFlyout={getEditConnectorFlyout}
getComments={getComments}
http={http}
title={ASSISTANT_TITLE}
From f6a81d43e00a49545d76291a60ecfb3580801737 Mon Sep 17 00:00:00 2001
From: Angela Chuang
Date: Tue, 4 Jun 2024 17:42:51 +0100
Subject: [PATCH 02/37] connectors tab
---
.../impl/assistant_context/index.tsx | 5 +
.../connector_row_actions.tsx | 22 +-
.../delete_confirmation_modal.tsx | 8 +
.../connector_settings/index.tsx | 193 +++++++++++++++---
.../connectorland/connector_settings/types.ts | 13 ++
.../impl/connectorland/helpers.tsx | 26 +++
.../impl/connectorland/translations.ts | 42 ++++
.../public/assistant/provider.tsx | 8 +-
.../components/delete_modal_confirmation.tsx | 30 +--
.../common/get_delete_modal_confirmation.tsx | 29 +++
.../triggers_actions_ui/public/mocks.ts | 7 +
.../triggers_actions_ui/public/plugin.ts | 13 ++
12 files changed, 348 insertions(+), 48 deletions(-)
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/delete_confirmation_modal.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/types.ts
create mode 100644 x-pack/plugins/triggers_actions_ui/public/common/get_delete_modal_confirmation.tsx
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx
index d55651689b5b1..96800a1001cfa 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx
@@ -72,6 +72,7 @@ export interface AssistantProviderProps {
docLinks: Omit;
children: React.ReactNode;
getAddConnectorFlyout: TriggersAndActionsUIPublicPluginStart['getAddConnectorFlyout'];
+ getDeleteConnectorModalConfirmation: TriggersAndActionsUIPublicPluginStart['getDeleteConnectorModalConfirmation'];
getEditConnectorFlyout: TriggersAndActionsUIPublicPluginStart['getEditConnectorFlyout'];
getComments: (commentArgs: {
abortStream: () => void;
@@ -130,6 +131,7 @@ export interface UseAssistantContext {
setIsStreaming: (isStreaming: boolean) => void;
isFlyoutMode: boolean;
}) => EuiCommentProps[];
+ getDeleteConnectorModalConfirmation: TriggersAndActionsUIPublicPluginStart['getDeleteConnectorModalConfirmation'];
http: HttpSetup;
knowledgeBase: KnowledgeBaseConfig;
getLastConversationId: (conversationTitle?: string) => string;
@@ -171,6 +173,7 @@ export const AssistantProvider: React.FC = ({
baseSystemPrompts = BASE_SYSTEM_PROMPTS,
children,
getAddConnectorFlyout,
+ getDeleteConnectorModalConfirmation,
getEditConnectorFlyout,
getComments,
http,
@@ -303,6 +306,7 @@ export const AssistantProvider: React.FC = ({
docLinks,
getAddConnectorFlyout,
getEditConnectorFlyout,
+ getDeleteConnectorModalConfirmation,
getComments,
http,
knowledgeBase: { ...DEFAULT_KNOWLEDGE_BASE_SETTINGS, ...localStorageKnowledgeBase },
@@ -344,6 +348,7 @@ export const AssistantProvider: React.FC = ({
docLinks,
getAddConnectorFlyout,
getEditConnectorFlyout,
+ getDeleteConnectorModalConfirmation,
getComments,
http,
localStorageKnowledgeBase,
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/connector_row_actions.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/connector_row_actions.tsx
index c6f73840ac09f..4b5acec308dea 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/connector_row_actions.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/connector_row_actions.tsx
@@ -7,16 +7,21 @@
import { EuiButtonEmpty, EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiPopover } from '@elastic/eui';
import React, { useCallback, useState } from 'react';
-import { AIConnector } from '../connector_selector';
+import { ActionConnectorTableItem } from './types';
import { DELETE_CONNECTOR_BUTTON, EDIT_CONNECTOR_BUTTON } from '../translations';
interface Props {
- connector: AIConnector;
- onClickEditConnector: (connector: AIConnector) => void;
+ connector: ActionConnectorTableItem;
+ onClickEditConnector: (connector: ActionConnectorTableItem) => void;
+ onClickDeleteConnector: (connector: ActionConnectorTableItem) => void;
}
-const ConnectorRowActionsComponent: React.FC = ({ connector, onClickEditConnector }) => {
+const ConnectorRowActionsComponent: React.FC = ({
+ connector,
+ onClickEditConnector,
+ onClickDeleteConnector,
+}) => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const closePopover = useCallback(() => setIsPopoverOpen(false), []);
@@ -25,6 +30,11 @@ const ConnectorRowActionsComponent: React.FC = ({ connector, onClickEditC
onClickEditConnector(connector);
}, [closePopover, onClickEditConnector, connector]);
+ const handleDeleteConnector = useCallback(() => {
+ closePopover();
+ onClickDeleteConnector(connector);
+ }, [closePopover, onClickDeleteConnector, connector]);
+
const onButtonClick = useCallback(() => setIsPopoverOpen((prevState) => !prevState), []);
return (
= ({ connector, onClickEditC
- {DELETE_CONNECTOR_BUTTON}
+
+ {DELETE_CONNECTOR_BUTTON}
+
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/delete_confirmation_modal.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/delete_confirmation_modal.tsx
new file mode 100644
index 0000000000000..9b1a3ffb5175a
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/delete_confirmation_modal.tsx
@@ -0,0 +1,8 @@
+/*
+ * 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.
+ */
+
+
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx
index fb2d36911c4c2..ebf843171d04c 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx
@@ -10,40 +10,106 @@ import {
EuiButton,
EuiButtonEmpty,
EuiCallOut,
+ EuiFlexGroup,
+ EuiFlexItem,
EuiInMemoryTable,
EuiSearchBarProps,
EuiSkeletonText,
} from '@elastic/eui';
-import React, { useCallback, useMemo, useState } from 'react';
+import React, { Suspense, useCallback, useMemo, useState } from 'react';
+import { ActionConnector, ActionType } from '@kbn/triggers-actions-ui-plugin/public';
+import { getConnectorCompatibility } from '@kbn/actions-plugin/common';
import { useAssistantContext } from '../../assistant_context';
import { AIConnector } from '../connector_selector';
+
import { useLoadConnectors } from '../use_load_connectors';
import {
+ CONNECTORS_TABLE_COLUMN_ACTIONS,
+ CONNECTORS_TABLE_COLUMN_ACTION_TYPE,
+ CONNECTORS_TABLE_COLUMN_COMPATIBILITY,
+ CONNECTORS_TABLE_COLUMN_NAME,
CREATE_CONNECTOR_BUTTON,
+ DELETE_CONNECTOR_CONFIRMATION_MULTIPLE_TITLE,
+ DELETE_CONNECTOR_CONFIRMATION_SINGLE_TITLE,
MISSING_READ_CONNECTORS_CALLOUT_TITLE,
REFRESH_CONNECTORS_BUTTON,
} from '../translations';
import { ConnectorRowActions } from './connector_row_actions';
+import { useLoadActionTypes } from '../use_load_action_types';
+import { AddConnectorModal } from '../add_connector_modal';
+import { ActionConnectorTableItem } from './types';
+import { deleteActions } from '../helpers';
-export interface Props {}
+const emptyConnectors = [] as ActionConnectorTableItem[];
-const emptyConnectors = [] as AIConnector[];
+const ConnectorsSettingsComponent: React.FC = () => {
+ const {
+ actionTypeRegistry,
+ http,
+ assistantAvailability,
+ getEditConnectorFlyout,
+ getDeleteConnectorModalConfirmation,
+ } = useAssistantContext();
-const ConnectorsSettingsComponent: React.FC = () => {
- const { http, assistantAvailability, getEditConnectorFlyout } = useAssistantContext();
+ const {
+ data: aiConnectors,
+ refetch: refetchConnectors,
+ isFetchedAfterMount: areConnectorsFetched,
+ } = useLoadConnectors({ http });
+ const { data: actionTypes } = useLoadActionTypes({ http });
+
+ const aiConnectorTableItems: ActionConnectorTableItem[] | undefined = areConnectorsFetched
+ ? (aiConnectors ?? []).map((action) => {
+ const currentActionType = actionTypes?.find(
+ (actionType) => actionType.id === action.actionTypeId
+ );
+ return {
+ ...action,
+ actionType: currentActionType?.name ?? action.actionTypeId,
+ compatibility: currentActionType
+ ? getConnectorCompatibility(currentActionType.supportedFeatureIds)
+ : [],
+ };
+ })
+ : undefined;
+
+ // Edit Connector
const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false);
- const onCloseEditFlyout = useCallback(() => {
+ const handleCloseEditFlyout = useCallback(() => {
setEditFlyoutVisibility(false);
}, []);
const [editedConnectorItem, setEditedConnectorItem] = useState(null);
- const {
- data: aiConnectors,
- refetch: refetchConnectors,
- isFetchedAfterMount: areConnectorsFetched,
- } = useLoadConnectors({ http });
+ // Add Connector
+ const [isAddConnectorModalVisible, setIsAddConnectorModalVisible] = useState(false);
+
+ const [selectedActionType, setSelectedActionType] = useState(null);
+
+ const onSaveConnector = useCallback(
+ (connector: ActionConnector) => {
+ // onConnectorSelectionChange({
+ // ...connector,
+ // });
+ refetchConnectors?.();
+ // setAddModalVisibility(false);
+ },
+ [refetchConnectors]
+ );
+
+ const handleAddConnector = useCallback(() => {
+ handleCloseEditFlyout();
+ setIsAddConnectorModalVisible(true);
+ }, [handleCloseEditFlyout]);
+
+ const onClickEditConnector = useCallback((connector: ActionConnectorTableItem) => {
+ setIsAddConnectorModalVisible(false);
+ setEditedConnectorItem(connector);
+ setEditFlyoutVisibility(true);
+ }, []);
+
+ // search
const [query, setQuery] = useState('');
const handleOnChange: EuiSearchBarProps['onChange'] = ({ queryText, error }) => {
@@ -52,50 +118,99 @@ const ConnectorsSettingsComponent: React.FC = () => {
}
};
+ // refetch
+
const handleRefetchConnectors = useCallback(() => {
refetchConnectors();
}, [refetchConnectors]);
- const onClickEditConnector = useCallback((connector: AIConnector) => {
- setEditedConnectorItem(connector);
- setEditFlyoutVisibility(true);
+ // delete
+
+ const [connectorsToDelete, setConnectorsToDelete] = useState([]);
+
+ const onClickDeleteConnector = useCallback((connector: ActionConnectorTableItem) => {
+ const itemIds = [connector.id];
+ setConnectorsToDelete(itemIds);
}, []);
+ const DeleteConnectorModalConfirmation = getDeleteConnectorModalConfirmation({
+ idsToDelete: connectorsToDelete,
+ apiDeleteCall: deleteActions,
+ onDeleted: (deleted: string[]) => {
+ refetchConnectors();
+ },
+ onCancel: () => {
+ setConnectorsToDelete([]);
+ },
+ onErrors: () => {
+ setConnectorsToDelete([]);
+ },
+ singleTitle: DELETE_CONNECTOR_CONFIRMATION_SINGLE_TITLE,
+ multipleTitle: DELETE_CONNECTOR_CONFIRMATION_MULTIPLE_TITLE,
+ setIsLoadingState: () => {},
+ });
+
const columns = [
{
- name: 'Connector name',
+ name: CONNECTORS_TABLE_COLUMN_NAME,
truncateText: false,
mobileOptions: {
show: true,
},
- render: (connector: AIConnector) => (
+ render: (connector: ActionConnectorTableItem) => (
onClickEditConnector(connector)}>
{connector.name}
),
},
{
- field: 'apiProvider',
- name: 'Type',
+ field: 'actionType',
+ name: CONNECTORS_TABLE_COLUMN_ACTION_TYPE,
truncateText: false,
mobileOptions: {
show: true,
},
- render: (apiProvider: AIConnector['apiProvider']) => (
- {apiProvider}
- ),
+ render: (actionType: ActionConnectorTableItem['actionType']) =>
+ actionType ? {actionType} : null,
+ },
+ {
+ name: CONNECTORS_TABLE_COLUMN_COMPATIBILITY,
+ sortable: false,
+ truncateText: true,
+ mobileOptions: {
+ show: true,
+ },
+ render: (tableItem: ActionConnectorTableItem) => {
+ return (
+
+ {tableItem?.compatibility?.map((compatibilityItem: string) => (
+
+
+ {compatibilityItem}
+
+
+ ))}
+
+ );
+ },
},
{
- name: 'Actions',
+ name: CONNECTORS_TABLE_COLUMN_ACTIONS,
actions: [
{
- name: 'Action',
+ name: CONNECTORS_TABLE_COLUMN_ACTIONS,
icon: 'boxesHorizontal',
- render: (connector: AIConnector) => {
+ render: (connector: ActionConnectorTableItem) => {
return (
);
},
@@ -120,7 +235,12 @@ const ConnectorsSettingsComponent: React.FC = () => {
>
{REFRESH_CONNECTORS_BUTTON}
,
-
+
{CREATE_CONNECTOR_BUTTON}
,
],
@@ -130,8 +250,9 @@ const ConnectorsSettingsComponent: React.FC = () => {
async (updatedConnector) => {
setEditedConnectorItem(updatedConnector);
refetchConnectors();
+ handleCloseEditFlyout();
},
- [refetchConnectors, setEditedConnectorItem]
+ [handleCloseEditFlyout, refetchConnectors]
);
const ConnectorEditFlyout = useMemo(
@@ -139,7 +260,7 @@ const ConnectorsSettingsComponent: React.FC = () => {
editedConnectorItem && editFlyoutVisible
? getEditConnectorFlyout({
connector: editedConnectorItem,
- onClose: onCloseEditFlyout,
+ onClose: handleCloseEditFlyout,
onConnectorUpdated,
})
: null,
@@ -147,7 +268,7 @@ const ConnectorsSettingsComponent: React.FC = () => {
editFlyoutVisible,
editedConnectorItem,
getEditConnectorFlyout,
- onCloseEditFlyout,
+ handleCloseEditFlyout,
onConnectorUpdated,
]
);
@@ -166,13 +287,27 @@ const ConnectorsSettingsComponent: React.FC = () => {
return areConnectorsFetched ? (
<>
+ {DeleteConnectorModalConfirmation}
{ConnectorEditFlyout}
+ {isAddConnectorModalVisible && (
+ // Crashing management app otherwise
+
+ setIsAddConnectorModalVisible(false)}
+ onSaveConnector={onSaveConnector}
+ onSelectActionType={(actionType: ActionType) => setSelectedActionType(actionType)}
+ selectedActionType={selectedActionType}
+ />
+
+ )}
>
) : (
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/types.ts b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/types.ts
new file mode 100644
index 0000000000000..ba613134b90ec
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/types.ts
@@ -0,0 +1,13 @@
+/*
+ * 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 { AIConnector } from '../connector_selector';
+
+export type ActionConnectorTableItem = AIConnector & {
+ actionType: string;
+ compatibility: string[];
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx
index c8b17de9906a3..e401db2f07a20 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx
@@ -8,6 +8,8 @@
import type { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public';
import { ActionConnectorProps } from '@kbn/triggers-actions-ui-plugin/public/types';
import { ActionTypeModel } from '@kbn/triggers-actions-ui-plugin/public';
+import { HttpSetup } from '@kbn/core/public';
+import { BASE_ACTION_API_PATH } from '@kbn/actions-plugin/common';
// aligns with OpenAiProviderType from '@kbn/stack-connectors-plugin/common/openai/types'
enum OpenAiProviderType {
@@ -54,3 +56,27 @@ const getAzureApiVersionParameter = (url: string): string | undefined => {
const urlSearchParams = new URLSearchParams(new URL(url).search);
return urlSearchParams.get('api-version') ?? undefined;
};
+
+export async function deleteActions({
+ ids,
+ http,
+}: {
+ ids: string[];
+ http: HttpSetup;
+}): Promise<{ successes: string[]; errors: string[] }> {
+ const successes: string[] = [];
+ const errors: string[] = [];
+ await Promise.all(
+ ids.map((id) =>
+ http.delete(`${BASE_ACTION_API_PATH}/connector/${encodeURIComponent(id)}`)
+ )
+ ).then(
+ function (fulfilled) {
+ successes.push(...fulfilled);
+ },
+ function (rejected) {
+ errors.push(...rejected);
+ }
+ );
+ return { successes, errors };
+}
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
index 424c7ce893726..1c53d9a015881 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
@@ -184,3 +184,45 @@ export const MISSING_READ_CONNECTORS_CALLOUT_TITLE = i18n.translate(
defaultMessage: 'Missing Read Connectors Privileges',
}
);
+
+export const CONNECTORS_TABLE_COLUMN_NAME = i18n.translate(
+ 'xpack.elasticAssistant.assistant.connectors.table.column.Name',
+ {
+ defaultMessage: 'Connector name',
+ }
+);
+
+export const CONNECTORS_TABLE_COLUMN_ACTION_TYPE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.connectors.table.column.type',
+ {
+ defaultMessage: 'Type',
+ }
+);
+
+export const CONNECTORS_TABLE_COLUMN_COMPATIBILITY = i18n.translate(
+ 'xpack.elasticAssistant.assistant.connectors.table.column.compatibility',
+ {
+ defaultMessage: 'Compatibility',
+ }
+);
+
+export const CONNECTORS_TABLE_COLUMN_ACTIONS = i18n.translate(
+ 'xpack.elasticAssistant.assistant.connectors.table.column.actions',
+ {
+ defaultMessage: 'Actions',
+ }
+);
+
+export const DELETE_CONNECTOR_CONFIRMATION_SINGLE_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.connectors.deleteConnectorConfirmation.singleTitle',
+ {
+ defaultMessage: 'connector',
+ }
+);
+
+export const DELETE_CONNECTOR_CONFIRMATION_MULTIPLE_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.connectors.deleteConnectorConfirmation.multipleTitle',
+ {
+ defaultMessage: 'connectors',
+ }
+);
diff --git a/x-pack/plugins/security_solution/public/assistant/provider.tsx b/x-pack/plugins/security_solution/public/assistant/provider.tsx
index 3a4a9004c81f0..16d9df5847a2a 100644
--- a/x-pack/plugins/security_solution/public/assistant/provider.tsx
+++ b/x-pack/plugins/security_solution/public/assistant/provider.tsx
@@ -120,7 +120,12 @@ export const AssistantProvider: FC> = ({ children })
http,
notifications,
storage,
- triggersActionsUi: { actionTypeRegistry, getAddConnectorFlyout, getEditConnectorFlyout },
+ triggersActionsUi: {
+ actionTypeRegistry,
+ getAddConnectorFlyout,
+ getDeleteConnectorModalConfirmation,
+ getEditConnectorFlyout,
+ },
docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION },
} = useKibana().services;
const basePath = useBasePath();
@@ -169,6 +174,7 @@ export const AssistantProvider: FC> = ({ children })
baseSystemPrompts={BASE_SECURITY_SYSTEM_PROMPTS} // to server and plugin start
baseConversations={baseConversations}
getAddConnectorFlyout={getAddConnectorFlyout}
+ getDeleteConnectorModalConfirmation={getDeleteConnectorModalConfirmation}
getEditConnectorFlyout={getEditConnectorFlyout}
getComments={getComments}
http={http}
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/delete_modal_confirmation.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/delete_modal_confirmation.tsx
index a0334c6ff7694..f8a777cda589a 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/delete_modal_confirmation.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/delete_modal_confirmation.tsx
@@ -17,18 +17,7 @@ import {
CANCEL_BUTTON_TEXT,
} from '../sections/rules_list/translations';
-export const DeleteModalConfirmation = ({
- idsToDelete,
- apiDeleteCall,
- onDeleted,
- onCancel,
- onErrors,
- singleTitle,
- multipleTitle,
- showWarningText,
- warningText,
- setIsLoadingState,
-}: {
+export interface DeleteModalConfirmationProps {
idsToDelete: string[];
apiDeleteCall: ({
ids,
@@ -45,7 +34,20 @@ export const DeleteModalConfirmation = ({
setIsLoadingState: (isLoading: boolean) => void;
showWarningText?: boolean;
warningText?: string;
-}) => {
+}
+
+export const DeleteModalConfirmation = ({
+ idsToDelete,
+ apiDeleteCall,
+ onDeleted,
+ onCancel,
+ onErrors,
+ singleTitle,
+ multipleTitle,
+ showWarningText,
+ warningText,
+ setIsLoadingState,
+}: DeleteModalConfirmationProps) => {
const [deleteModalFlyoutVisible, setDeleteModalVisibility] = useState(false);
useEffect(() => {
@@ -102,3 +104,5 @@ export const DeleteModalConfirmation = ({
);
};
+// eslint-disable-next-line import/no-default-export
+export { DeleteModalConfirmation as default };
diff --git a/x-pack/plugins/triggers_actions_ui/public/common/get_delete_modal_confirmation.tsx b/x-pack/plugins/triggers_actions_ui/public/common/get_delete_modal_confirmation.tsx
new file mode 100644
index 0000000000000..2e78b09db431b
--- /dev/null
+++ b/x-pack/plugins/triggers_actions_ui/public/common/get_delete_modal_confirmation.tsx
@@ -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 { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import React from 'react';
+import {
+ DeleteModalConfirmation,
+ DeleteModalConfirmationProps,
+} from '../application/components/delete_modal_confirmation';
+import { ConnectorProvider } from '../application/context/connector_context';
+import { ConnectorServices } from '../types';
+
+const queryClient = new QueryClient();
+
+export const getDeleteConnectorModalConfirmationLazy = (
+ props: DeleteModalConfirmationProps & { connectorServices: ConnectorServices }
+) => {
+ return (
+
+
+
+
+
+ );
+};
diff --git a/x-pack/plugins/triggers_actions_ui/public/mocks.ts b/x-pack/plugins/triggers_actions_ui/public/mocks.ts
index 5224a2e0d505f..a4d8451b5994d 100644
--- a/x-pack/plugins/triggers_actions_ui/public/mocks.ts
+++ b/x-pack/plugins/triggers_actions_ui/public/mocks.ts
@@ -52,6 +52,8 @@ import { getRulesSettingsLinkLazy } from './common/get_rules_settings_link';
import { AlertTableConfigRegistry } from './application/alert_table_config_registry';
import { AlertActionsProps } from './types';
import { AlertSummaryWidgetDependencies } from './application/sections/alert_summary_widget/types';
+import { getDeleteConnectorModalConfirmationLazy } from './common/get_delete_modal_confirmation';
+import { DeleteModalConfirmationProps } from './application/components/delete_modal_confirmation';
function createStartMock(): TriggersAndActionsUIPublicPluginStart {
const actionTypeRegistry = new TypeRegistry();
@@ -85,6 +87,11 @@ function createStartMock(): TriggersAndActionsUIPublicPluginStart {
connectorServices,
});
},
+ getDeleteConnectorModalConfirmation: (
+ props: Omit
+ ) => {
+ return getDeleteConnectorModalConfirmationLazy({ ...props, connectorServices });
+ },
getAddRuleFlyout: (props) => {
return getAddRuleFlyoutLazy({
...props,
diff --git a/x-pack/plugins/triggers_actions_ui/public/plugin.ts b/x-pack/plugins/triggers_actions_ui/public/plugin.ts
index 829e0bf364562..51ab5f7423a93 100644
--- a/x-pack/plugins/triggers_actions_ui/public/plugin.ts
+++ b/x-pack/plugins/triggers_actions_ui/public/plugin.ts
@@ -98,6 +98,8 @@ import { getRulesSettingsLinkLazy } from './common/get_rules_settings_link';
import { getGlobalRuleEventLogListLazy } from './common/get_global_rule_event_log_list';
import { AlertTableConfigRegistry } from './application/alert_table_config_registry';
import { AlertSummaryWidgetDependencies } from './application/sections/alert_summary_widget/types';
+import { DeleteModalConfirmationProps } from './application/components/delete_modal_confirmation';
+import { getDeleteConnectorModalConfirmationLazy } from './common/get_delete_modal_confirmation';
export interface TriggersAndActionsUIPublicPluginSetup {
actionTypeRegistry: TypeRegistry;
@@ -120,6 +122,9 @@ export interface TriggersAndActionsUIPublicPluginStart {
getEditConnectorFlyout: (
props: Omit
) => ReactElement;
+ getDeleteConnectorModalConfirmation: (
+ props: Omit
+ ) => ReactElement;
getAddRuleFlyout: <
Params extends RuleTypeParams = RuleTypeParams,
MetaData extends RuleTypeMetaData = RuleTypeMetaData
@@ -489,6 +494,14 @@ export class Plugin
connectorServices: this.connectorServices!,
});
},
+ getDeleteConnectorModalConfirmation: (
+ props: Omit
+ ) => {
+ return getDeleteConnectorModalConfirmationLazy({
+ ...props,
+ connectorServices: this.connectorServices!,
+ });
+ },
getAddRuleFlyout: (props) => {
return getAddRuleFlyoutLazy({
...props,
From 0f053ba6cfb63456c690eaef2ddaa80d530152fb Mon Sep 17 00:00:00 2001
From: Angela Chuang
Date: Thu, 6 Jun 2024 21:31:15 +0100
Subject: [PATCH 03/37] conversation tab
---
.../common/components/formatted_date.tsx | 19 ++
.../common/components/row_actions.tsx} | 36 +-
.../assistant/common/hooks/use_settings.ts | 29 ++
.../common/hooks/use_table_search.ts} | 2 -
.../conversation_selector_settings/index.tsx | 6 +-
.../conversation_selector_settings/types.ts | 12 +
.../use_conversation_selector_settings.tsx | 55 +++
.../conversation_settings.tsx | 174 ++--------
.../conversation_streaming_switch.tsx | 59 ++++
.../use_connector_selector.ts | 100 ++++++
.../use_conversation_deleted.tsx | 50 +++
.../use_select_system_prompt.tsx | 93 ++++++
.../index.tsx | 313 ++++++++++++++++++
.../translations.ts | 43 +++
.../index.tsx | 28 ++
.../assistant_settings_management.tsx | 44 +--
.../assistant/settings/use_handle_save.tsx | 53 +++
.../impl/assistant/types.ts | 1 +
.../impl/assistant_context/index.tsx | 6 +
.../connector_settings/index.tsx | 238 ++++---------
.../use_connector_table.tsx | 187 +++++++++++
.../impl/connectorland/helpers.tsx | 26 +-
.../impl/connectorland/translations.ts | 7 +
.../impl/content/prompts/system/index.tsx | 4 +
.../content/prompts/system/translations.ts | 14 +
.../public/assistant/provider.tsx | 2 +
.../stack_management/management_settings.tsx | 2 -
27 files changed, 1222 insertions(+), 381 deletions(-)
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/formatted_date.tsx
rename x-pack/packages/kbn-elastic-assistant/impl/{connectorland/connector_settings/connector_row_actions.tsx => assistant/common/components/row_actions.tsx} (65%)
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_settings.ts
rename x-pack/packages/kbn-elastic-assistant/impl/{connectorland/connector_settings/delete_confirmation_modal.tsx => assistant/common/hooks/use_table_search.ts} (99%)
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/types.ts
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_streaming_switch.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_connector_selector.ts
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_conversation_deleted.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_select_system_prompt.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/translations.ts
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_handle_save.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/use_connector_table.tsx
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/formatted_date.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/formatted_date.tsx
new file mode 100644
index 0000000000000..c641290bc3895
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/formatted_date.tsx
@@ -0,0 +1,19 @@
+/*
+ * 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 moment from 'moment';
+import React from 'react';
+import { useDateFormat, useTimeZone } from '../hooks/use_settings';
+
+export const FormattedDate = React.memo<{ dateFormat?: string; value: Date }>(
+ /* eslint-disable-next-line react-hooks/rules-of-hooks */
+ ({ value, dateFormat = useDateFormat() }) => (
+ <>{moment.tz(value, useTimeZone()).format(dateFormat)}>
+ )
+);
+
+FormattedDate.displayName = 'FormattedDate';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/connector_row_actions.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/row_actions.tsx
similarity index 65%
rename from x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/connector_row_actions.tsx
rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/row_actions.tsx
index 4b5acec308dea..97360feaebc3c 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/connector_row_actions.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/row_actions.tsx
@@ -7,33 +7,33 @@
import { EuiButtonEmpty, EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiPopover } from '@elastic/eui';
import React, { useCallback, useState } from 'react';
-import { ActionConnectorTableItem } from './types';
-import { DELETE_CONNECTOR_BUTTON, EDIT_CONNECTOR_BUTTON } from '../translations';
+import {
+ DELETE_CONNECTOR_BUTTON,
+ EDIT_CONNECTOR_BUTTON,
+} from '../../../connectorland/translations';
-interface Props {
- connector: ActionConnectorTableItem;
- onClickEditConnector: (connector: ActionConnectorTableItem) => void;
- onClickDeleteConnector: (connector: ActionConnectorTableItem) => void;
+interface Props {
+ rowItem: T;
+ onEdit: (rowItem: T) => void;
+ onDelete: (rowItem: T) => void;
}
-const ConnectorRowActionsComponent: React.FC = ({
- connector,
- onClickEditConnector,
- onClickDeleteConnector,
-}) => {
+type RowActionsComponentType = (props: Props) => JSX.Element;
+
+const RowActionsComponent = ({ rowItem, onEdit, onDelete }: Props) => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const closePopover = useCallback(() => setIsPopoverOpen(false), []);
const handleEditConnector = useCallback(() => {
closePopover();
- onClickEditConnector(connector);
- }, [closePopover, onClickEditConnector, connector]);
+ onEdit(rowItem);
+ }, [closePopover, onEdit, rowItem]);
const handleDeleteConnector = useCallback(() => {
closePopover();
- onClickDeleteConnector(connector);
- }, [closePopover, onClickDeleteConnector, connector]);
+ onDelete(rowItem);
+ }, [closePopover, onDelete, rowItem]);
const onButtonClick = useCallback(() => setIsPopoverOpen((prevState) => !prevState), []);
return (
@@ -42,7 +42,7 @@ const ConnectorRowActionsComponent: React.FC = ({
}
@@ -66,5 +66,5 @@ const ConnectorRowActionsComponent: React.FC = ({
);
};
-export const ConnectorRowActions = React.memo(ConnectorRowActionsComponent);
-ConnectorRowActions.displayName = 'ConnectorRowActions';
+// casting to correctly infer the param of onEdit and onDelete when reusing this component
+export const RowActions = React.memo(RowActionsComponent) as RowActionsComponentType;
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_settings.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_settings.ts
new file mode 100644
index 0000000000000..aa9b70963580f
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_settings.ts
@@ -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 moment from 'moment';
+import { useAssistantContext } from '../../../assistant_context';
+
+export const DEFAULT_DATE_FORMAT_TZ = 'dateFormat:tz' as const;
+export const DEFAULT_DATE_FORMAT = 'dateFormat' as const;
+
+export const useUiSetting = (key: string, defaultValue?: T): T => {
+ const { settings } = useAssistantContext();
+
+ if (!settings) {
+ throw new TypeError('uiSettings service not available in kibana-react context.');
+ }
+
+ return settings.client.get(key, defaultValue);
+};
+
+export const useDateFormat = (): string => useUiSetting(DEFAULT_DATE_FORMAT);
+
+export const useTimeZone = (): string => {
+ const timeZone = useUiSetting(DEFAULT_DATE_FORMAT_TZ);
+ return timeZone === 'Browser' ? moment.tz.guess() : timeZone;
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/delete_confirmation_modal.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_table_search.ts
similarity index 99%
rename from x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/delete_confirmation_modal.tsx
rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_table_search.ts
index 9b1a3ffb5175a..1fec1c76430eb 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/delete_confirmation_modal.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_table_search.ts
@@ -4,5 +4,3 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
-
-
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/index.tsx
index 286be81f531f3..f4b8f9a79412f 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/index.tsx
@@ -8,7 +8,6 @@
import {
EuiButtonIcon,
EuiComboBox,
- EuiComboBoxOptionOption,
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
@@ -21,6 +20,7 @@ import { css } from '@emotion/react';
import { Conversation } from '../../../..';
import * as i18n from '../conversation_selector/translations';
import { SystemPromptSelectorOption } from '../../prompt_editor/system_prompt/system_prompt_modal/system_prompt_selector/system_prompt_selector';
+import { ConversationSelectorSettingsOption } from './types';
interface Props {
conversations: Record;
@@ -49,10 +49,6 @@ const getNextConversationTitle = (
: conversationTitles[conversationTitles.indexOf(selectedConversationTitle) + 1];
};
-export type ConversationSelectorSettingsOption = EuiComboBoxOptionOption<{
- isDefault: boolean;
-}>;
-
/**
* A disconnected variant of the ConversationSelector component that allows for
* modifiable settings without persistence. Also changes some styling and removes
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/types.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/types.ts
new file mode 100644
index 0000000000000..548149ffe0c7b
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/types.ts
@@ -0,0 +1,12 @@
+/*
+ * 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 { EuiComboBoxOptionOption } from '@elastic/eui';
+
+export type ConversationSelectorSettingsOption = EuiComboBoxOptionOption<{
+ isDefault: boolean;
+}>;
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx
new file mode 100644
index 0000000000000..98f47e4e8ddcd
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx
@@ -0,0 +1,55 @@
+/*
+ * 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 { useMemo } from 'react';
+import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public';
+import { Conversation } from '../../../assistant_context/types';
+import { AIConnector } from '../../../connectorland/connector_selector';
+import { getConnectorTypeTitle } from '../../../connectorland/helpers';
+import { Prompt } from '../../../..';
+
+const emptyConversations = {};
+
+export interface UseConversationSelectorSettingsProps {
+ allSystemPrompts: Prompt[];
+ actionTypeRegistry: ActionTypeRegistryContract;
+ connectors: AIConnector[] | undefined;
+ conversations: Record;
+}
+
+export type ConversationTableItem = Conversation & {
+ actionType?: string | null;
+ systemPrompt?: string;
+};
+
+export const useConversationSelectorSettings = ({
+ allSystemPrompts,
+ actionTypeRegistry,
+ connectors,
+ conversations = emptyConversations,
+}: UseConversationSelectorSettingsProps) => {
+ const conversationOptions = useMemo(() => {
+ return Object.values(conversations).map((conversation) => {
+ const connector: AIConnector | undefined = connectors?.find(
+ (c) => c.id === conversation.apiConfig?.connectorId
+ );
+
+ const actionType = getConnectorTypeTitle(connector, actionTypeRegistry);
+ const systemPrompt = allSystemPrompts.find(
+ ({ id }) => id === conversation.apiConfig?.defaultSystemPromptId
+ );
+
+ return {
+ ...conversation,
+ actionType,
+ systemPrompt: systemPrompt?.label ?? systemPrompt?.name,
+ };
+ });
+ }, [allSystemPrompts, actionTypeRegistry, connectors, conversations]);
+
+ return conversationOptions;
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx
index 179ff7524bd88..8ea90eaf41d66 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx
@@ -33,6 +33,9 @@ import { getDefaultSystemPrompt } from '../../use_conversation/helpers';
import { useLoadConnectors } from '../../../connectorland/use_load_connectors';
import { getGenAiConfig } from '../../../connectorland/helpers';
import { ConversationsBulkActions } from '../../api';
+import { useSelectSystemPrompt } from './use_select_system_prompt';
+import { useConnectorSelector } from './use_connector_selector';
+import { useConversationDeleted } from './use_conversation_deleted';
export interface ConversationSettingsProps {
actionTypeRegistry: ActionTypeRegistryContract;
@@ -76,22 +79,10 @@ export const ConversationSettings: React.FC = React.m
return getDefaultSystemPrompt({ allSystemPrompts, conversation: undefined });
}, [allSystemPrompts]);
- const selectedSystemPrompt = useMemo(() => {
- return getDefaultSystemPrompt({ allSystemPrompts, conversation: selectedConversation });
- }, [allSystemPrompts, selectedConversation]);
-
const { data: connectors, isSuccess: areConnectorsFetched } = useLoadConnectors({
http,
});
- const selectedConversationId = useMemo(
- () =>
- selectedConversation?.id === ''
- ? selectedConversation.title
- : (selectedConversation?.id as string),
- [selectedConversation]
- );
-
// Conversation callbacks
// When top level conversation selection changes
const onConversationSelectionChange = useCallback(
@@ -152,83 +143,21 @@ export const ConversationSettings: React.FC = React.m
]
);
- const onConversationDeleted = useCallback(
- (conversationTitle: string) => {
- const conversationId =
- Object.values(conversationSettings).find((c) => c.title === conversationTitle)?.id ?? '';
- const updatedConversationSettings = { ...conversationSettings };
- delete updatedConversationSettings[conversationId];
- setConversationSettings(updatedConversationSettings);
-
- setConversationsSettingsBulkActions({
- ...conversationsSettingsBulkActions,
- delete: {
- ids: [...(conversationsSettingsBulkActions.delete?.ids ?? []), conversationId],
- },
- });
- },
- [
- conversationSettings,
- conversationsSettingsBulkActions,
- setConversationSettings,
- setConversationsSettingsBulkActions,
- ]
- );
+ const onConversationDeleted = useConversationDeleted({
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ });
- const handleOnSystemPromptSelectionChange = useCallback(
- (systemPromptId?: string | undefined) => {
- if (selectedConversation != null && selectedConversation.apiConfig) {
- const updatedConversation = {
- ...selectedConversation,
- apiConfig: {
- ...selectedConversation.apiConfig,
- defaultSystemPromptId: systemPromptId,
- },
- };
- setConversationSettings({
- ...conversationSettings,
- [updatedConversation.id]: updatedConversation,
- });
- if (selectedConversation.id !== '') {
- setConversationsSettingsBulkActions({
- ...conversationsSettingsBulkActions,
- update: {
- ...(conversationsSettingsBulkActions.update ?? {}),
- [updatedConversation.id]: {
- ...updatedConversation,
- ...(conversationsSettingsBulkActions.update
- ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
- : {}),
- apiConfig: {
- ...updatedConversation.apiConfig,
- ...((conversationsSettingsBulkActions.update
- ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
- : {}
- ).apiConfig ?? {}),
- defaultSystemPromptId: systemPromptId,
- },
- },
- },
- });
- } else {
- setConversationsSettingsBulkActions({
- ...conversationsSettingsBulkActions,
- create: {
- ...(conversationsSettingsBulkActions.create ?? {}),
- [updatedConversation.id]: updatedConversation,
- },
- });
- }
- }
- },
- [
- conversationSettings,
- conversationsSettingsBulkActions,
- selectedConversation,
- setConversationSettings,
- setConversationsSettingsBulkActions,
- ]
- );
+ const { selectedSystemPrompt, handleOnSystemPromptSelectionChange } = useSelectSystemPrompt({
+ allSystemPrompts,
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ selectedConversation,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ });
const selectedConnector = useMemo(() => {
const selectedConnectorId = selectedConversation?.apiConfig?.connectorId;
@@ -243,68 +172,13 @@ export const ConversationSettings: React.FC = React.m
[selectedConversation?.apiConfig?.provider]
);
- const handleOnConnectorSelectionChange = useCallback(
- (connector) => {
- if (selectedConversation != null) {
- const config = getGenAiConfig(connector);
- const updatedConversation = {
- ...selectedConversation,
- apiConfig: {
- ...selectedConversation.apiConfig,
- connectorId: connector.id,
- actionTypeId: connector.actionTypeId,
- provider: config?.apiProvider,
- model: config?.defaultModel,
- },
- };
- setConversationSettings({
- ...conversationSettings,
- [selectedConversationId]: updatedConversation,
- });
- if (selectedConversation.id !== '') {
- setConversationsSettingsBulkActions({
- ...conversationsSettingsBulkActions,
- update: {
- ...(conversationsSettingsBulkActions.update ?? {}),
- [updatedConversation.id]: {
- ...updatedConversation,
- ...(conversationsSettingsBulkActions.update
- ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
- : {}),
- apiConfig: {
- ...updatedConversation.apiConfig,
- ...((conversationsSettingsBulkActions.update
- ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
- : {}
- ).apiConfig ?? {}),
- connectorId: connector?.id,
- actionTypeId: connector?.actionTypeId,
- provider: config?.apiProvider,
- model: config?.defaultModel,
- },
- },
- },
- });
- } else {
- setConversationsSettingsBulkActions({
- ...conversationsSettingsBulkActions,
- create: {
- ...(conversationsSettingsBulkActions.create ?? {}),
- [updatedConversation.id]: updatedConversation,
- },
- });
- }
- }
- },
- [
- conversationSettings,
- conversationsSettingsBulkActions,
- selectedConversation,
- selectedConversationId,
- setConversationSettings,
- setConversationsSettingsBulkActions,
- ]
- );
+ const handleOnConnectorSelectionChange = useConnectorSelector({
+ selectedConversation,
+ setConversationSettings,
+ conversationSettings,
+ setConversationsSettingsBulkActions,
+ conversationsSettingsBulkActions,
+ });
const selectedModel = useMemo(() => {
const connectorModel = getGenAiConfig(selectedConnector)?.defaultModel;
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_streaming_switch.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_streaming_switch.tsx
new file mode 100644
index 0000000000000..c302716595b9d
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_streaming_switch.tsx
@@ -0,0 +1,59 @@
+/*
+ * 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 { EuiFormRow, EuiSwitch, EuiText, useEuiTheme } from '@elastic/eui';
+import { css } from '@emotion/react';
+import React from 'react';
+import { STREAMING_TITLE, STREAMING_HELP_TEXT_TITLE } from './translations';
+
+interface Props {
+ assistantStreamingEnabled: boolean;
+ setAssistantStreamingEnabled: React.Dispatch>;
+ compressed?: boolean;
+}
+
+const ConversationStreamingSwitchComponent: React.FC = ({
+ assistantStreamingEnabled,
+ compressed,
+ setAssistantStreamingEnabled,
+}) => {
+ const { euiTheme } = useEuiTheme();
+
+ return (
+
+ {STREAMING_TITLE}
+
+ }
+ >
+ {STREAMING_HELP_TEXT_TITLE}}
+ checked={assistantStreamingEnabled}
+ onChange={(e) => setAssistantStreamingEnabled(e.target.checked)}
+ compressed={compressed}
+ />
+
+ );
+};
+
+export const ConversationStreamingSwitch = React.memo(ConversationStreamingSwitchComponent);
+
+ConversationStreamingSwitch.displayName = 'ConversationStreamingSwitch';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_connector_selector.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_connector_selector.ts
new file mode 100644
index 0000000000000..e295452ceaa6a
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_connector_selector.ts
@@ -0,0 +1,100 @@
+/*
+ * 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 { useCallback, useMemo } from 'react';
+import { Conversation, ConversationsBulkActions } from '../../../..';
+import { getGenAiConfig } from '../../../connectorland/helpers';
+
+interface Props {
+ selectedConversation?: Conversation;
+ setConversationSettings: React.Dispatch>>;
+ conversationSettings: Record;
+ setConversationsSettingsBulkActions: React.Dispatch<
+ React.SetStateAction
+ >;
+ conversationsSettingsBulkActions: ConversationsBulkActions;
+}
+
+export const useConnectorSelector = ({
+ selectedConversation,
+ setConversationSettings,
+ conversationSettings,
+ setConversationsSettingsBulkActions,
+ conversationsSettingsBulkActions,
+}: Props) => {
+ const selectedConversationId = useMemo(
+ () =>
+ selectedConversation?.id === ''
+ ? selectedConversation.title
+ : (selectedConversation?.id as string),
+ [selectedConversation]
+ );
+ const handleOnConnectorSelectionChange = useCallback(
+ (connector) => {
+ if (selectedConversation != null) {
+ const config = getGenAiConfig(connector);
+ const updatedConversation = {
+ ...selectedConversation,
+ apiConfig: {
+ ...selectedConversation.apiConfig,
+ connectorId: connector.id,
+ actionTypeId: connector.actionTypeId,
+ provider: config?.apiProvider,
+ model: config?.defaultModel,
+ },
+ };
+ setConversationSettings({
+ ...conversationSettings,
+ [selectedConversationId]: updatedConversation,
+ });
+ if (selectedConversation.id !== '') {
+ setConversationsSettingsBulkActions({
+ ...conversationsSettingsBulkActions,
+ update: {
+ ...(conversationsSettingsBulkActions.update ?? {}),
+ [updatedConversation.id]: {
+ ...updatedConversation,
+ ...(conversationsSettingsBulkActions.update
+ ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
+ : {}),
+ apiConfig: {
+ ...updatedConversation.apiConfig,
+ ...((conversationsSettingsBulkActions.update
+ ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
+ : {}
+ ).apiConfig ?? {}),
+ connectorId: connector?.id,
+ actionTypeId: connector?.actionTypeId,
+ provider: config?.apiProvider,
+ model: config?.defaultModel,
+ },
+ },
+ },
+ });
+ } else {
+ setConversationsSettingsBulkActions({
+ ...conversationsSettingsBulkActions,
+ create: {
+ ...(conversationsSettingsBulkActions.create ?? {}),
+ [updatedConversation.id]: updatedConversation,
+ },
+ });
+ }
+ }
+ },
+ [
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ selectedConversation,
+ selectedConversationId,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ ]
+ );
+
+ return handleOnConnectorSelectionChange;
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_conversation_deleted.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_conversation_deleted.tsx
new file mode 100644
index 0000000000000..855f08d588e48
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_conversation_deleted.tsx
@@ -0,0 +1,50 @@
+/*
+ * 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 { useCallback } from 'react';
+import { Conversation, ConversationsBulkActions } from '../../../..';
+
+interface Props {
+ conversationSettings: Record;
+ conversationsSettingsBulkActions: ConversationsBulkActions;
+ setConversationSettings: React.Dispatch>>;
+ setConversationsSettingsBulkActions: React.Dispatch<
+ React.SetStateAction
+ >;
+}
+
+export const useConversationDeleted = ({
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+}: Props) => {
+ const onConversationDeleted = useCallback(
+ (conversationTitle: string) => {
+ const conversationId =
+ Object.values(conversationSettings).find((c) => c.title === conversationTitle)?.id ?? '';
+ const updatedConversationSettings = { ...conversationSettings };
+ delete updatedConversationSettings[conversationId];
+ setConversationSettings(updatedConversationSettings);
+
+ setConversationsSettingsBulkActions({
+ ...conversationsSettingsBulkActions,
+ delete: {
+ ids: [...(conversationsSettingsBulkActions.delete?.ids ?? []), conversationId],
+ },
+ });
+ },
+ [
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ ]
+ );
+
+ return onConversationDeleted;
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_select_system_prompt.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_select_system_prompt.tsx
new file mode 100644
index 0000000000000..10dd08656d4c1
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_select_system_prompt.tsx
@@ -0,0 +1,93 @@
+/*
+ * 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 { useCallback, useMemo } from 'react';
+import { Conversation, Prompt } from '../../../..';
+import { ConversationsBulkActions } from '../../api';
+import { getDefaultSystemPrompt } from '../../use_conversation/helpers';
+
+interface Props {
+ allSystemPrompts: Prompt[];
+ conversationSettings: Record;
+ conversationsSettingsBulkActions: ConversationsBulkActions;
+ selectedConversation?: Conversation;
+ setConversationSettings: React.Dispatch>>;
+ setConversationsSettingsBulkActions: React.Dispatch<
+ React.SetStateAction
+ >;
+}
+export const useSelectSystemPrompt = ({
+ allSystemPrompts,
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ selectedConversation,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+}: Props) => {
+ const selectedSystemPrompt = useMemo(() => {
+ return getDefaultSystemPrompt({ allSystemPrompts, conversation: selectedConversation });
+ }, [allSystemPrompts, selectedConversation]);
+ const handleOnSystemPromptSelectionChange = useCallback(
+ (systemPromptId?: string | undefined) => {
+ if (selectedConversation != null && selectedConversation.apiConfig) {
+ const updatedConversation = {
+ ...selectedConversation,
+ apiConfig: {
+ ...selectedConversation.apiConfig,
+ defaultSystemPromptId: systemPromptId,
+ },
+ };
+ setConversationSettings({
+ ...conversationSettings,
+ [updatedConversation.id]: updatedConversation,
+ });
+ if (selectedConversation.id !== '') {
+ setConversationsSettingsBulkActions({
+ ...conversationsSettingsBulkActions,
+ update: {
+ ...(conversationsSettingsBulkActions.update ?? {}),
+ [updatedConversation.id]: {
+ ...updatedConversation,
+ ...(conversationsSettingsBulkActions.update
+ ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
+ : {}),
+ apiConfig: {
+ ...updatedConversation.apiConfig,
+ ...((conversationsSettingsBulkActions.update
+ ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
+ : {}
+ ).apiConfig ?? {}),
+ defaultSystemPromptId: systemPromptId,
+ },
+ },
+ },
+ });
+ } else {
+ setConversationsSettingsBulkActions({
+ ...conversationsSettingsBulkActions,
+ create: {
+ ...(conversationsSettingsBulkActions.create ?? {}),
+ [updatedConversation.id]: updatedConversation,
+ },
+ });
+ }
+ }
+ },
+ [
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ selectedConversation,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ ]
+ );
+
+ return {
+ selectedSystemPrompt,
+ handleOnSystemPromptSelectionChange,
+ };
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
new file mode 100644
index 0000000000000..001f1c26cf790
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
@@ -0,0 +1,313 @@
+/*
+ * 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 {
+ EuiInMemoryTable,
+ EuiPanel,
+ EuiSpacer,
+ EuiBadge,
+ EuiLink,
+ EuiFlyout,
+ EuiFlyoutHeader,
+ EuiFlyoutBody,
+ EuiFormRow,
+ EuiBasicTableColumn,
+ EuiTitle,
+ EuiFlyoutFooter,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiButtonEmpty,
+ EuiButton,
+} from '@elastic/eui';
+import React, { useCallback, useMemo, useState } from 'react';
+
+import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public';
+import { FormattedMessage } from '@kbn/i18n-react';
+import { noop } from 'lodash/fp';
+import { Conversation } from '../../../assistant_context/types';
+import {
+ ConversationTableItem,
+ useConversationSelectorSettings,
+} from '../conversation_selector_settings/use_conversation_selector_settings';
+import { ConversationStreamingSwitch } from '../conversation_settings/conversation_streaming_switch';
+import { AIConnector, ConnectorSelector } from '../../../connectorland/connector_selector';
+import { FormattedDate } from '../../common/components/formatted_date';
+import { RowActions } from '../../common/components/row_actions';
+import {
+ CONVERSATIONS_TABLE_COLUMN_ACTIONS,
+ CONVERSATIONS_TABLE_COLUMN_CONNECTOR,
+ CONVERSATIONS_TABLE_COLUMN_SYSTEM_PROMPT,
+ CONVERSATIONS_TABLE_COLUMN_TYPE,
+ CONVERSATIONS_TABLE_COLUMN_UPDATED_AT,
+} from './translations';
+import { SelectSystemPrompt } from '../../prompt_editor/system_prompt/select_system_prompt';
+import {
+ CONNECTOR_TITLE,
+ SETTINGS_PROMPT_HELP_TEXT_TITLE,
+ SETTINGS_PROMPT_TITLE,
+} from '../conversation_settings/translations';
+import { Prompt } from '../../types';
+import { useSelectSystemPrompt } from '../conversation_settings/use_select_system_prompt';
+import { useConnectorSelector } from '../conversation_settings/use_connector_selector';
+import { ConversationsBulkActions } from '../../api';
+import { useAssistantContext } from '../../../assistant_context';
+import { CANCEL, SAVE } from '../../settings/translations';
+import { useConversationDeleted } from '../conversation_settings/use_conversation_deleted';
+
+interface Props {
+ actionTypeRegistry: ActionTypeRegistryContract;
+ allSystemPrompts: Prompt[];
+ areConnectorsFetched: boolean;
+ assistantStreamingEnabled: boolean;
+ connectors: AIConnector[] | undefined;
+ conversations: Record;
+ conversationSettings: Record;
+ conversationsSettingsBulkActions: ConversationsBulkActions;
+ handleSave: () => void;
+ isDisabled?: boolean;
+ isFlyoutMode: boolean;
+ resetSettings: () => void;
+ setAssistantStreamingEnabled: React.Dispatch>;
+ setConversationSettings: React.Dispatch>>;
+ setConversationsSettingsBulkActions: React.Dispatch<
+ React.SetStateAction
+ >;
+}
+
+const ConversationSettingsManagementComponent: React.FC = ({
+ actionTypeRegistry,
+ allSystemPrompts,
+ areConnectorsFetched,
+ assistantStreamingEnabled,
+ connectors,
+ conversations,
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ handleSave,
+ isDisabled,
+ isFlyoutMode,
+ resetSettings,
+ setAssistantStreamingEnabled,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+}) => {
+ const { http } = useAssistantContext();
+ const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false);
+ const [selectedConversation, setSelectedConversation] = useState<
+ ConversationTableItem | undefined
+ >(undefined);
+
+ const selectedConnector = useMemo(() => {
+ const selectedConnectorId = selectedConversation?.apiConfig?.connectorId;
+ if (areConnectorsFetched) {
+ return connectors?.find((c) => c.id === selectedConnectorId);
+ }
+ return undefined;
+ }, [areConnectorsFetched, connectors, selectedConversation?.apiConfig?.connectorId]);
+
+ const selectedConversationTitle = selectedConversation?.title ?? '';
+
+ const handleConversationEdited = useCallback((rowItem: ConversationTableItem) => {
+ setEditFlyoutVisibility(true);
+ setSelectedConversation(rowItem);
+ }, []);
+
+ const onConversationDeleted = useConversationDeleted({
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ });
+
+ const handleConversationDeleted = useCallback(() => {
+ onConversationDeleted(selectedConversationTitle);
+ }, [onConversationDeleted, selectedConversationTitle]);
+
+ const conversationOptions = useConversationSelectorSettings({
+ allSystemPrompts,
+ actionTypeRegistry,
+ connectors,
+ conversations,
+ });
+
+ const { selectedSystemPrompt, handleOnSystemPromptSelectionChange } = useSelectSystemPrompt({
+ allSystemPrompts,
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ selectedConversation,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ });
+
+ const handleOnConnectorSelectionChange = useConnectorSelector({
+ selectedConversation,
+ setConversationSettings,
+ conversationSettings,
+ setConversationsSettingsBulkActions,
+ conversationsSettingsBulkActions,
+ });
+
+ const columns: Array> = [
+ {
+ name: CONVERSATIONS_TABLE_COLUMN_TYPE,
+ render: (conversation: ConversationTableItem) => (
+ handleConversationEdited(conversation)}>
+ {conversation.title}
+
+ ),
+ },
+ {
+ field: 'systemPrompt',
+ name: CONVERSATIONS_TABLE_COLUMN_SYSTEM_PROMPT,
+ render: (systemPrompt: ConversationTableItem['systemPrompt']) =>
+ systemPrompt ? {systemPrompt} : null,
+ },
+ {
+ field: 'actionType',
+ name: CONVERSATIONS_TABLE_COLUMN_CONNECTOR,
+ render: (actionType: ConversationTableItem['actionType']) =>
+ actionType ? {actionType} : null,
+ },
+ {
+ field: 'updatedAt',
+ name: CONVERSATIONS_TABLE_COLUMN_UPDATED_AT,
+ render: (updatedAt: ConversationTableItem['updatedAt']) =>
+ updatedAt ? (
+
+
+
+ ) : null,
+ },
+ {
+ name: CONVERSATIONS_TABLE_COLUMN_ACTIONS,
+ actions: [
+ {
+ name: CONVERSATIONS_TABLE_COLUMN_ACTIONS,
+ render: (conversation: ConversationTableItem) => {
+ return (
+
+ rowItem={conversation}
+ onEdit={handleConversationEdited}
+ onDelete={handleConversationDeleted}
+ />
+ );
+ },
+ },
+ ],
+ },
+ ];
+
+ const onCancelClick = useCallback(() => {
+ setEditFlyoutVisibility(false);
+ resetSettings();
+ }, [resetSettings]);
+
+ const onSaveClick = useCallback(() => {
+ handleSave();
+ setEditFlyoutVisibility(false);
+ }, [handleSave]);
+ return (
+ <>
+
+
+
+
+
+ {editFlyoutVisible && (
+ setEditFlyoutVisibility(false)}>
+
+
+ {selectedConversationTitle}
+
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+
+
+ {CANCEL}
+
+
+
+
+ {SAVE}
+
+
+
+
+
+ )}
+ >
+ );
+};
+
+export const ConversationSettingsManagement = React.memo(ConversationSettingsManagementComponent);
+
+ConversationSettingsManagement.displayName = 'ConversationSettingsManagement';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/translations.ts
new file mode 100644
index 0000000000000..d28f1705de5ab
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/translations.ts
@@ -0,0 +1,43 @@
+/*
+ * 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 CONVERSATIONS_TABLE_COLUMN_TYPE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.conversationSettings.column.type',
+ {
+ defaultMessage: 'Conversation Type',
+ }
+);
+
+export const CONVERSATIONS_TABLE_COLUMN_SYSTEM_PROMPT = i18n.translate(
+ 'xpack.elasticAssistant.assistant.conversationSettings.column.systemPrompt',
+ {
+ defaultMessage: 'Title',
+ }
+);
+
+export const CONVERSATIONS_TABLE_COLUMN_CONNECTOR = i18n.translate(
+ 'xpack.elasticAssistant.assistant.conversationSettings.column.connector',
+ {
+ defaultMessage: 'Connector',
+ }
+);
+
+export const CONVERSATIONS_TABLE_COLUMN_UPDATED_AT = i18n.translate(
+ 'xpack.elasticAssistant.assistant.conversationSettings.column.updatedAt',
+ {
+ defaultMessage: 'Date updated',
+ }
+);
+
+export const CONVERSATIONS_TABLE_COLUMN_ACTIONS = i18n.translate(
+ 'xpack.elasticAssistant.assistant.conversationSettings.column.actions',
+ {
+ defaultMessage: 'Actions',
+ }
+);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
new file mode 100644
index 0000000000000..9ddd43d8d90df
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
@@ -0,0 +1,28 @@
+/*
+ * 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 { EuiInMemoryTable } from '@elastic/eui';
+import { QuickPrompt } from '../types';
+
+interface Props {
+ quickPrompts: QuickPrompt[];
+}
+const QuickPromptSettingsManagementComponent = ({quickPrompts}: Props) => {
+ cosnt columns = [
+ {
+ field: 'title',
+ name: 'Title',
+ }
+ ];
+ return (
+
+
+
+ );
+};
+
+export const QuickPromptSettingsManagement = QuickPromptSettingsManagementComponent;
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
index f9b335b84b03f..0a526b18aeb87 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
@@ -21,7 +21,6 @@ import { useAssistantContext } from '../../assistant_context';
import { useSettingsUpdater } from './use_settings_updater/use_settings_updater';
import {
AnonymizationSettings,
- ConversationSettings,
EvaluationSettings,
KnowledgeBaseSettings,
QuickPromptSettings,
@@ -31,6 +30,7 @@ import { useLoadConnectors } from '../../connectorland/use_load_connectors';
import { getDefaultConnector } from '../helpers';
import { useFetchAnonymizationFields } from '../api/anonymization_fields/use_fetch_anonymization_fields';
import { ConnectorsSettings } from '../../connectorland/connector_settings';
+import { ConversationSettingsManagement } from '../conversations/converstaion_settings_management';
export const CONNECTORS_TAB = 'CONNECTORS_TAB' as const;
export const CONVERSATIONS_TAB = 'CONVERSATION_TAB' as const;
@@ -70,7 +70,11 @@ export const AssistantSettingsManagement: React.FC = React.memo(
const { data: anonymizationFields } = useFetchAnonymizationFields();
// Connector details
- const { data: connectors } = useLoadConnectors({
+ const {
+ data: connectors,
+ refetch: refetchConnectors,
+ isFetchedAfterMount: areConnectorsFetched,
+ } = useLoadConnectors({
http,
});
const defaultConnector = useMemo(() => getDefaultConnector(connectors), [connectors]);
@@ -109,10 +113,6 @@ export const AssistantSettingsManagement: React.FC = React.memo(
}
);
- const onHandleSelectedConversationChange = useCallback((conversation?: Conversation) => {
- setSelectedConversation(conversation);
- }, []);
-
useEffect(() => {
if (selectedConversation != null) {
setSelectedConversation(conversationSettings[selectedConversation.title]);
@@ -245,25 +245,31 @@ export const AssistantSettingsManagement: React.FC = React.memo(
padding-right: 0;
`}
>
- {selectedSettingsTab === CONNECTORS_TAB && }
+ {selectedSettingsTab === CONNECTORS_TAB && (
+
+ )}
{selectedSettingsTab === CONVERSATIONS_TAB && (
-
)}
{selectedSettingsTab === QUICK_PROMPTS_TAB && (
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_handle_save.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_handle_save.tsx
new file mode 100644
index 0000000000000..63f937f2fdf7a
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_handle_save.tsx
@@ -0,0 +1,53 @@
+/*
+ * 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 { useCallback } from 'react';
+import { IToasts } from '@kbn/core/public';
+import { Conversation } from '../../..';
+import { SETTINGS_UPDATED_TOAST_TITLE } from './translations';
+
+interface Props {
+ conversationSettings: Record;
+ defaultSelectedConversation: Conversation;
+ setSelectedConversationId: React.Dispatch>;
+ saveSettings: () => void;
+ setHasPendingChanges: React.Dispatch>;
+ toasts: IToasts | undefined;
+}
+export const useHandleSave = ({
+ conversationSettings,
+ defaultSelectedConversation,
+ setSelectedConversationId,
+ saveSettings,
+ setHasPendingChanges,
+ toasts,
+}: Props) => {
+ const handleSave = useCallback(() => {
+ // If the selected conversation is deleted, we need to select a new conversation to prevent a crash creating a conversation that already exists
+ const isSelectedConversationDeleted =
+ conversationSettings[defaultSelectedConversation.title] == null;
+ const newSelectedConversationId: string | undefined = Object.keys(conversationSettings)[0];
+ if (isSelectedConversationDeleted && newSelectedConversationId != null) {
+ setSelectedConversationId(conversationSettings[newSelectedConversationId].title);
+ }
+ saveSettings();
+ toasts?.addSuccess({
+ iconType: 'check',
+ title: SETTINGS_UPDATED_TOAST_TITLE,
+ });
+ setHasPendingChanges(false);
+ }, [
+ conversationSettings,
+ defaultSelectedConversation.title,
+ saveSettings,
+ setHasPendingChanges,
+ setSelectedConversationId,
+ toasts,
+ ]);
+
+ return handleSave;
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/types.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/types.ts
index 8b80b87584d35..91ee3468a12d9 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/types.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/types.ts
@@ -15,6 +15,7 @@ export interface Prompt {
isDefault?: boolean; // TODO: Should be renamed to isImmutable as this flag is used to prevent users from deleting prompts
isNewConversationDefault?: boolean;
isFlyoutMode?: boolean;
+ label?: string;
}
export interface KnowledgeBaseConfig {
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx
index 96800a1001cfa..a9a949073a4f2 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx
@@ -17,6 +17,7 @@ import {
import { useLocalStorage, useSessionStorage } from 'react-use';
import type { DocLinksStart } from '@kbn/core-doc-links-browser';
import { AssistantFeatures, defaultAssistantFeatures } from '@kbn/elastic-assistant-common';
+import { SettingsStart } from '@kbn/core-ui-settings-browser';
import { updatePromptContexts } from './helpers';
import type {
PromptContext,
@@ -89,6 +90,7 @@ export interface AssistantProviderProps {
http: HttpSetup;
baseConversations: Record;
nameSpace?: string;
+ settings: SettingsStart;
title?: string;
toasts?: IToasts;
}
@@ -147,6 +149,7 @@ export interface UseAssistantContext {
setSelectedSettingsTab: React.Dispatch>;
setShowAssistantOverlay: (showAssistantOverlay: ShowAssistantOverlay) => void;
showAssistantOverlay: ShowAssistantOverlay;
+ settings: SettingsStart;
setTraceOptions: (traceOptions: {
apmUrl: string;
langSmithProject: string;
@@ -179,6 +182,7 @@ export const AssistantProvider: React.FC = ({
http,
baseConversations,
nameSpace = DEFAULT_ASSISTANT_NAMESPACE,
+ settings,
title = DEFAULT_ASSISTANT_TITLE,
toasts,
}) => {
@@ -322,6 +326,7 @@ export const AssistantProvider: React.FC = ({
setKnowledgeBase: setLocalStorageKnowledgeBase,
setSelectedSettingsTab,
setShowAssistantOverlay,
+ settings,
setTraceOptions: setSessionStorageTraceOptions,
showAssistantOverlay,
title,
@@ -361,6 +366,7 @@ export const AssistantProvider: React.FC = ({
setLocalStorageQuickPrompts,
setLocalStorageSystemPrompts,
setLocalStorageKnowledgeBase,
+ settings,
setSessionStorageTraceOptions,
showAssistantOverlay,
title,
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx
index ebf843171d04c..9a2b4824a3ba0 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx
@@ -5,44 +5,40 @@
* 2.0.
*/
-import {
- EuiBadge,
- EuiButton,
- EuiButtonEmpty,
- EuiCallOut,
- EuiFlexGroup,
- EuiFlexItem,
- EuiInMemoryTable,
- EuiSearchBarProps,
- EuiSkeletonText,
-} from '@elastic/eui';
+import { EuiCallOut, EuiInMemoryTable, EuiPanel, EuiSkeletonText } from '@elastic/eui';
import React, { Suspense, useCallback, useMemo, useState } from 'react';
-import { ActionConnector, ActionType } from '@kbn/triggers-actions-ui-plugin/public';
-import { getConnectorCompatibility } from '@kbn/actions-plugin/common';
+import { ActionType } from '@kbn/triggers-actions-ui-plugin/public';
+import type { IHttpFetchError } from '@kbn/core-http-browser';
+
+import { UseQueryResult } from '@tanstack/react-query';
import { useAssistantContext } from '../../assistant_context';
import { AIConnector } from '../connector_selector';
-import { useLoadConnectors } from '../use_load_connectors';
import {
- CONNECTORS_TABLE_COLUMN_ACTIONS,
- CONNECTORS_TABLE_COLUMN_ACTION_TYPE,
- CONNECTORS_TABLE_COLUMN_COMPATIBILITY,
- CONNECTORS_TABLE_COLUMN_NAME,
- CREATE_CONNECTOR_BUTTON,
DELETE_CONNECTOR_CONFIRMATION_MULTIPLE_TITLE,
DELETE_CONNECTOR_CONFIRMATION_SINGLE_TITLE,
MISSING_READ_CONNECTORS_CALLOUT_TITLE,
- REFRESH_CONNECTORS_BUTTON,
} from '../translations';
-import { ConnectorRowActions } from './connector_row_actions';
+
import { useLoadActionTypes } from '../use_load_action_types';
import { AddConnectorModal } from '../add_connector_modal';
import { ActionConnectorTableItem } from './types';
import { deleteActions } from '../helpers';
+import { useConnectorTable } from './use_connector_table';
+
+interface Props {
+ connectors: AIConnector[] | undefined;
+ refetchConnectors: UseQueryResult['refetch'];
+ areConnectorsFetched: boolean;
+}
const emptyConnectors = [] as ActionConnectorTableItem[];
-const ConnectorsSettingsComponent: React.FC = () => {
+const ConnectorsSettingsComponent: React.FC = ({
+ connectors: aiConnectors,
+ refetchConnectors,
+ areConnectorsFetched,
+}) => {
const {
actionTypeRegistry,
http,
@@ -51,28 +47,8 @@ const ConnectorsSettingsComponent: React.FC = () => {
getDeleteConnectorModalConfirmation,
} = useAssistantContext();
- const {
- data: aiConnectors,
- refetch: refetchConnectors,
- isFetchedAfterMount: areConnectorsFetched,
- } = useLoadConnectors({ http });
const { data: actionTypes } = useLoadActionTypes({ http });
- const aiConnectorTableItems: ActionConnectorTableItem[] | undefined = areConnectorsFetched
- ? (aiConnectors ?? []).map((action) => {
- const currentActionType = actionTypes?.find(
- (actionType) => actionType.id === action.actionTypeId
- );
- return {
- ...action,
- actionType: currentActionType?.name ?? action.actionTypeId,
- compatibility: currentActionType
- ? getConnectorCompatibility(currentActionType.supportedFeatureIds)
- : [],
- };
- })
- : undefined;
-
// Edit Connector
const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false);
@@ -87,164 +63,50 @@ const ConnectorsSettingsComponent: React.FC = () => {
const [selectedActionType, setSelectedActionType] = useState(null);
- const onSaveConnector = useCallback(
- (connector: ActionConnector) => {
- // onConnectorSelectionChange({
- // ...connector,
- // });
- refetchConnectors?.();
- // setAddModalVisibility(false);
- },
- [refetchConnectors]
- );
+ const onSaveConnector = useCallback(() => {
+ refetchConnectors?.();
+ }, [refetchConnectors]);
const handleAddConnector = useCallback(() => {
handleCloseEditFlyout();
setIsAddConnectorModalVisible(true);
}, [handleCloseEditFlyout]);
- const onClickEditConnector = useCallback((connector: ActionConnectorTableItem) => {
+ const onEditConnector = useCallback((connector: ActionConnectorTableItem) => {
setIsAddConnectorModalVisible(false);
setEditedConnectorItem(connector);
setEditFlyoutVisibility(true);
}, []);
- // search
- const [query, setQuery] = useState('');
-
- const handleOnChange: EuiSearchBarProps['onChange'] = ({ queryText, error }) => {
- if (!error) {
- setQuery(queryText);
- }
- };
-
- // refetch
-
- const handleRefetchConnectors = useCallback(() => {
- refetchConnectors();
- }, [refetchConnectors]);
-
// delete
const [connectorsToDelete, setConnectorsToDelete] = useState([]);
- const onClickDeleteConnector = useCallback((connector: ActionConnectorTableItem) => {
+ const onDeleteConnector = useCallback((connector: ActionConnectorTableItem) => {
const itemIds = [connector.id];
setConnectorsToDelete(itemIds);
}, []);
- const DeleteConnectorModalConfirmation = getDeleteConnectorModalConfirmation({
- idsToDelete: connectorsToDelete,
- apiDeleteCall: deleteActions,
- onDeleted: (deleted: string[]) => {
- refetchConnectors();
- },
- onCancel: () => {
- setConnectorsToDelete([]);
- },
- onErrors: () => {
- setConnectorsToDelete([]);
- },
- singleTitle: DELETE_CONNECTOR_CONFIRMATION_SINGLE_TITLE,
- multipleTitle: DELETE_CONNECTOR_CONFIRMATION_MULTIPLE_TITLE,
- setIsLoadingState: () => {},
- });
-
- const columns = [
- {
- name: CONNECTORS_TABLE_COLUMN_NAME,
- truncateText: false,
- mobileOptions: {
- show: true,
- },
- render: (connector: ActionConnectorTableItem) => (
- onClickEditConnector(connector)}>
- {connector.name}
-
- ),
- },
- {
- field: 'actionType',
- name: CONNECTORS_TABLE_COLUMN_ACTION_TYPE,
- truncateText: false,
- mobileOptions: {
- show: true,
- },
- render: (actionType: ActionConnectorTableItem['actionType']) =>
- actionType ? {actionType} : null,
- },
- {
- name: CONNECTORS_TABLE_COLUMN_COMPATIBILITY,
- sortable: false,
- truncateText: true,
- mobileOptions: {
- show: true,
- },
- render: (tableItem: ActionConnectorTableItem) => {
- return (
-
- {tableItem?.compatibility?.map((compatibilityItem: string) => (
-
-
- {compatibilityItem}
-
-
- ))}
-
- );
- },
- },
- {
- name: CONNECTORS_TABLE_COLUMN_ACTIONS,
- actions: [
- {
- name: CONNECTORS_TABLE_COLUMN_ACTIONS,
- icon: 'boxesHorizontal',
- render: (connector: ActionConnectorTableItem) => {
- return (
-
- );
- },
+ const DeleteConnectorModalConfirmation = useMemo(
+ () =>
+ getDeleteConnectorModalConfirmation({
+ idsToDelete: connectorsToDelete,
+ apiDeleteCall: deleteActions,
+ onDeleted: (deleted: string[]) => {
+ refetchConnectors();
},
- ],
- },
- ];
-
- const search: EuiSearchBarProps = {
- query,
- onChange: handleOnChange,
- box: {
- schema: true,
- placeholder: 'Search for connectors',
- },
- toolsRight: [
-
- {REFRESH_CONNECTORS_BUTTON}
- ,
-
- {CREATE_CONNECTOR_BUTTON}
- ,
- ],
- };
+ onCancel: () => {
+ setConnectorsToDelete([]);
+ },
+ onErrors: () => {
+ setConnectorsToDelete([]);
+ },
+ singleTitle: DELETE_CONNECTOR_CONFIRMATION_SINGLE_TITLE,
+ multipleTitle: DELETE_CONNECTOR_CONFIRMATION_MULTIPLE_TITLE,
+ setIsLoadingState: () => {},
+ }),
+ [connectorsToDelete, getDeleteConnectorModalConfirmation, refetchConnectors]
+ );
const onConnectorUpdated = useCallback(
async (updatedConnector) => {
@@ -273,6 +135,18 @@ const ConnectorsSettingsComponent: React.FC = () => {
]
);
+ const { search, columns, aiConnectorTableItems } = useConnectorTable({
+ actionTypes,
+ actionTypeRegistry,
+ aiConnectors,
+ areConnectorsFetched,
+ hasConnectorsAllPrivilege: assistantAvailability.hasConnectorsAllPrivilege,
+ refetchConnectors,
+ handleAddConnector,
+ onEditConnector,
+ onDeleteConnector,
+ });
+
if (!assistantAvailability.hasConnectorsReadPrivilege) {
return (
{
}
return areConnectorsFetched ? (
- <>
+
{DeleteConnectorModalConfirmation}
{
/>
)}
- >
+
) : (
);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/use_connector_table.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/use_connector_table.tsx
new file mode 100644
index 0000000000000..9ea7412e598da
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/use_connector_table.tsx
@@ -0,0 +1,187 @@
+/*
+ * 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 {
+ EuiBadge,
+ EuiBasicTableColumn,
+ EuiButton,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiLink,
+ EuiSearchBarProps,
+} from '@elastic/eui';
+import React, { useState, useMemo } from 'react';
+import { ActionType, ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public';
+import { getConnectorCompatibility } from '@kbn/actions-plugin/common';
+import { RowActions } from '../../assistant/common/components/row_actions';
+import { AIConnector } from '../connector_selector';
+import { getActionTypeTitle, getGenAiConfig } from '../helpers';
+import {
+ CONNECTORS_TABLE_COLUMN_ACTIONS,
+ CONNECTORS_TABLE_COLUMN_ACTION_TYPE,
+ CONNECTORS_TABLE_COLUMN_COMPATIBILITY,
+ CONNECTORS_TABLE_COLUMN_NAME,
+ CREATE_CONNECTOR_BUTTON,
+ PRECONFIGURED_CONNECTOR,
+ REFRESH_CONNECTORS_BUTTON,
+ SEARCH_CONNECTOR_PLACEHOLDER,
+} from '../translations';
+import { ActionConnectorTableItem } from './types';
+
+interface Props {
+ actionTypes: ActionType[] | undefined;
+ actionTypeRegistry: ActionTypeRegistryContract;
+ aiConnectors: AIConnector[] | undefined;
+ areConnectorsFetched: boolean;
+ hasConnectorsAllPrivilege: boolean;
+ refetchConnectors: () => void;
+ handleAddConnector: () => void;
+ onEditConnector: (connector: ActionConnectorTableItem) => void;
+ onDeleteConnector: (connector: ActionConnectorTableItem) => void;
+}
+export const useConnectorTable = ({
+ actionTypes,
+ actionTypeRegistry,
+ aiConnectors,
+ areConnectorsFetched,
+ hasConnectorsAllPrivilege,
+ refetchConnectors,
+ handleAddConnector,
+ onEditConnector,
+ onDeleteConnector,
+}: Props) => {
+ const [query, setQuery] = useState('');
+
+ const handleOnChange: EuiSearchBarProps['onChange'] = ({ queryText, error }) => {
+ if (!error) {
+ setQuery(queryText);
+ }
+ };
+
+ const search: EuiSearchBarProps = useMemo(
+ () => ({
+ query,
+ onChange: handleOnChange,
+ box: {
+ schema: true,
+ placeholder: SEARCH_CONNECTOR_PLACEHOLDER,
+ },
+ toolsRight: [
+
+ {REFRESH_CONNECTORS_BUTTON}
+ ,
+
+ {CREATE_CONNECTOR_BUTTON}
+ ,
+ ],
+ }),
+ [areConnectorsFetched, hasConnectorsAllPrivilege, handleAddConnector, refetchConnectors, query]
+ );
+
+ const columns: Array> = useMemo(
+ () => [
+ {
+ name: CONNECTORS_TABLE_COLUMN_NAME,
+ truncateText: false,
+ mobileOptions: {
+ show: true,
+ },
+ render: (connector: ActionConnectorTableItem) => (
+ onEditConnector(connector)}>{connector.name}
+ ),
+ },
+ {
+ field: 'actionType',
+ name: CONNECTORS_TABLE_COLUMN_ACTION_TYPE,
+ truncateText: false,
+ mobileOptions: {
+ show: true,
+ },
+ render: (actionType: ActionConnectorTableItem['actionType']) =>
+ actionType ? {actionType} : null,
+ },
+ {
+ name: CONNECTORS_TABLE_COLUMN_COMPATIBILITY,
+ truncateText: true,
+ mobileOptions: {
+ show: true,
+ },
+ render: (tableItem: ActionConnectorTableItem) => {
+ return (
+
+ {tableItem?.compatibility?.map((compatibilityItem: string) => (
+
+
+ {compatibilityItem}
+
+
+ ))}
+
+ );
+ },
+ },
+ {
+ name: CONNECTORS_TABLE_COLUMN_ACTIONS,
+ actions: [
+ {
+ name: CONNECTORS_TABLE_COLUMN_ACTIONS,
+ render: (connector: ActionConnectorTableItem) => {
+ return (
+
+ rowItem={connector}
+ onEdit={onEditConnector}
+ onDelete={onDeleteConnector}
+ />
+ );
+ },
+ },
+ ],
+ },
+ ],
+ [onDeleteConnector, onEditConnector]
+ );
+
+ const aiConnectorTableItems: ActionConnectorTableItem[] | undefined = areConnectorsFetched
+ ? (aiConnectors ?? []).map((connector) => {
+ const currentActionType = actionTypes?.find(
+ (actionType) => actionType.id === connector.actionTypeId
+ );
+
+ const connectorTypeTitle =
+ getGenAiConfig(connector)?.apiProvider ??
+ getActionTypeTitle(actionTypeRegistry.get(connector.actionTypeId));
+ const actionType = connector.isPreconfigured ? PRECONFIGURED_CONNECTOR : connectorTypeTitle;
+ return {
+ ...connector,
+ actionType,
+ compatibility: currentActionType
+ ? getConnectorCompatibility(currentActionType.supportedFeatureIds)
+ : [],
+ };
+ })
+ : undefined;
+
+ return { search, columns, aiConnectorTableItems };
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx
index e401db2f07a20..d1e2b01007f67 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx
@@ -5,11 +5,15 @@
* 2.0.
*/
-import type { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public';
-import { ActionConnectorProps } from '@kbn/triggers-actions-ui-plugin/public/types';
-import { ActionTypeModel } from '@kbn/triggers-actions-ui-plugin/public';
+import type {
+ ActionConnector,
+ ActionTypeModel,
+ ActionTypeRegistryContract,
+} from '@kbn/triggers-actions-ui-plugin/public';
import { HttpSetup } from '@kbn/core/public';
import { BASE_ACTION_API_PATH } from '@kbn/actions-plugin/common';
+import { ActionConnectorProps } from '@kbn/triggers-actions-ui-plugin/public/types';
+import { PRECONFIGURED_CONNECTOR } from './translations';
// aligns with OpenAiProviderType from '@kbn/stack-connectors-plugin/common/openai/types'
enum OpenAiProviderType {
@@ -57,6 +61,22 @@ const getAzureApiVersionParameter = (url: string): string | undefined => {
return urlSearchParams.get('api-version') ?? undefined;
};
+export const getConnectorTypeTitle = (
+ connector: ActionConnector | undefined,
+ actionTypeRegistry: ActionTypeRegistryContract
+) => {
+ if (!connector) {
+ return null;
+ }
+ const connectorTypeTitle =
+ getGenAiConfig(connector)?.apiProvider ??
+ getActionTypeTitle(actionTypeRegistry.get(connector.actionTypeId));
+
+ const actionType = connector.isPreconfigured ? PRECONFIGURED_CONNECTOR : connectorTypeTitle;
+
+ return actionType;
+};
+
export async function deleteActions({
ids,
http,
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
index 1c53d9a015881..a12ebd61129e3 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
@@ -226,3 +226,10 @@ export const DELETE_CONNECTOR_CONFIRMATION_MULTIPLE_TITLE = i18n.translate(
defaultMessage: 'connectors',
}
);
+
+export const SEARCH_CONNECTOR_PLACEHOLDER = i18n.translate(
+ 'xpack.elasticAssistant.assistant.connectors.searchConnectorPlaceholder',
+ {
+ defaultMessage: 'Search for connectors',
+ }
+);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/index.tsx
index e2034cc62c33a..a73fbf4854ef1 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/index.tsx
@@ -7,8 +7,10 @@
import { Prompt } from '../../../..';
import {
+ DEFAULT_SYSTEM_PROMPT_LABEL,
DEFAULT_SYSTEM_PROMPT_NAME,
DEFAULT_SYSTEM_PROMPT_NON_I18N,
+ SUPERHERO_SYSTEM_PROMPT_LABEL,
SUPERHERO_SYSTEM_PROMPT_NAME,
SUPERHERO_SYSTEM_PROMPT_NON_I18N,
} from './translations';
@@ -22,11 +24,13 @@ export const BASE_SYSTEM_PROMPTS: Prompt[] = [
content: DEFAULT_SYSTEM_PROMPT_NON_I18N,
name: DEFAULT_SYSTEM_PROMPT_NAME,
promptType: 'system',
+ label: DEFAULT_SYSTEM_PROMPT_LABEL,
},
{
id: 'CB9FA555-B59F-4F71-AFF9-8A891AC5BC28',
content: SUPERHERO_SYSTEM_PROMPT_NON_I18N,
name: SUPERHERO_SYSTEM_PROMPT_NAME,
promptType: 'system',
+ label: SUPERHERO_SYSTEM_PROMPT_LABEL,
},
];
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/translations.ts
index eecc3b6dea246..8ce92919de1cb 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/translations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/translations.ts
@@ -39,6 +39,13 @@ export const DEFAULT_SYSTEM_PROMPT_NAME = i18n.translate(
}
);
+export const DEFAULT_SYSTEM_PROMPT_LABEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.content.prompts.system.defaultSystemPromptLabel',
+ {
+ defaultMessage: 'Default',
+ }
+);
+
export const SUPERHERO_SYSTEM_PROMPT_NON_I18N = `${YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT} ${IF_YOU_DONT_KNOW_THE_ANSWER}
${SUPERHERO_PERSONALITY}`;
@@ -49,6 +56,13 @@ export const SUPERHERO_SYSTEM_PROMPT_NAME = i18n.translate(
}
);
+export const SUPERHERO_SYSTEM_PROMPT_LABEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.content.prompts.system.superheroSystemPromptLabel',
+ {
+ defaultMessage: 'Enhanced',
+ }
+);
+
export const SYSTEM_PROMPT_CONTEXT_NON_I18N = (context: string) => {
return `CONTEXT:\n"""\n${context}\n"""`;
};
diff --git a/x-pack/plugins/security_solution/public/assistant/provider.tsx b/x-pack/plugins/security_solution/public/assistant/provider.tsx
index 16d9df5847a2a..106078f792d08 100644
--- a/x-pack/plugins/security_solution/public/assistant/provider.tsx
+++ b/x-pack/plugins/security_solution/public/assistant/provider.tsx
@@ -119,6 +119,7 @@ export const AssistantProvider: FC> = ({ children })
const {
http,
notifications,
+ settings,
storage,
triggersActionsUi: {
actionTypeRegistry,
@@ -178,6 +179,7 @@ export const AssistantProvider: FC> = ({ children })
getEditConnectorFlyout={getEditConnectorFlyout}
getComments={getComments}
http={http}
+ settings={settings}
title={ASSISTANT_TITLE}
toasts={toasts}
>
diff --git a/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx b/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx
index 7282e5e85e437..d7d4c180442ba 100644
--- a/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx
+++ b/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx
@@ -37,11 +37,9 @@ export const ManagementSettings = React.memo(() => {
onFetch: onFetchedConversations,
isAssistantEnabled,
});
-
const [selectedConversationId, setSelectedConversationId] = useState(
WELCOME_CONVERSATION_TITLE
);
-
const { getDefaultConversation } = useConversation();
const currentConversation = useMemo(
From 889ef91b487bc8afe6a8bc3afb2928c4205811ec Mon Sep 17 00:00:00 2001
From: Angela Chuang
Date: Mon, 17 Jun 2024 14:37:28 +0100
Subject: [PATCH 04/37] add prompts
---
.../use_fetch_current_user_conversations.ts | 1 +
.../flyout/index.tsx | 78 ++++
.../flyout/translations.ts | 22 +
.../flyout/use_flyout_modal_visibility.ts | 26 ++
.../row_actions.tsx | 41 +-
.../common/components/formatted_date.tsx | 19 -
.../assistant/common/hooks/use_settings.ts | 29 --
.../common/hooks/use_table_search.ts | 6 -
.../use_conversation_selector_settings.tsx | 15 +-
.../conversation_settings.tsx | 184 +--------
.../conversation_settings_editor.tsx | 267 ++++++++++++
.../use_select_system_prompt.tsx | 93 -----
.../index.tsx | 382 ++++++++----------
.../translations.ts | 9 +-
.../system_prompt_editor.tsx | 338 ++++++++++++++++
.../system_prompt_settings.tsx | 328 +--------------
.../system_prompt_modal/translations.ts | 14 -
.../system_prompt_modal/types.ts | 23 ++
.../index.tsx | 221 ++++++++++
.../translations.ts | 58 +++
.../quick_prompt_editor.tsx | 217 ++++++++++
.../quick_prompt_settings.tsx | 203 +---------
.../helpers.ts | 31 ++
.../index.tsx | 174 +++++++-
.../translations.ts | 65 +++
.../assistant_settings_management.tsx | 76 ++--
.../impl/assistant/settings/translations.ts | 7 +
.../impl/assistant_context/index.tsx | 31 +-
.../connector_settings/index.tsx | 191 ---------
.../connectorland/connector_settings/types.ts | 13 -
.../use_connector_table.tsx | 187 ---------
.../connector_settings_management/index.tsx | 57 +++
.../translations.ts | 30 ++
.../impl/connectorland/helpers.tsx | 27 +-
.../impl/connectorland/translations.ts | 56 ---
.../index.tsx | 78 ++++
.../settings/anonymization_settings/index.tsx | 44 +-
.../use_anonymization_list_update.tsx | 66 +++
.../context_editor/index.tsx | 4 +-
.../stats/allowed_stat/index.tsx | 14 +-
.../stats/anonymized_stat/index.tsx | 14 +-
.../stats/available_stat/index.tsx | 13 +-
.../stats/constants.ts | 1 +
.../data_anonymization_editor/stats/index.tsx | 16 +-
.../public/assistant/provider.tsx | 14 +-
.../stack_management/management_settings.tsx | 3 +-
46 files changed, 2110 insertions(+), 1676 deletions(-)
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/index.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/translations.ts
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/use_flyout_modal_visibility.ts
rename x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/{ => assisttant_settings_management}/row_actions.tsx (66%)
delete mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/formatted_date.tsx
delete mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_settings.ts
delete mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_table_search.ts
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx
delete mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_select_system_prompt.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_editor.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/types.ts
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/translations.ts
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/quick_prompt_editor.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/helpers.ts
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/translations.ts
delete mode 100644 x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx
delete mode 100644 x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/types.ts
delete mode 100644 x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/use_connector_table.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/index.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/translations.ts
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonomization_settings_management/index.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/use_anonymization_list_update.tsx
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.ts
index 58be08317d40c..08cbbeaef20a4 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.ts
@@ -26,6 +26,7 @@ export interface UseFetchCurrentUserConversationsParams {
signal?: AbortSignal | undefined;
refetchOnWindowFocus?: boolean;
isAssistantEnabled: boolean;
+ query?: { page: number; perPage: number };
}
/**
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/index.tsx
new file mode 100644
index 0000000000000..d82dc77f7a505
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/index.tsx
@@ -0,0 +1,78 @@
+/*
+ * 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,
+ EuiButtonEmpty,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFlyout,
+ EuiFlyoutBody,
+ EuiFlyoutFooter,
+ EuiFlyoutHeader,
+ EuiTitle,
+} from '@elastic/eui';
+import React from 'react';
+import * as i18n from './translations';
+
+interface Props {
+ children: React.ReactNode;
+ title: string;
+ flyoutVisible: boolean;
+ onClose: () => void;
+ onSaveCancelled: () => void;
+ onSaveConfirmed: () => void;
+}
+
+const FlyoutComponent: React.FC = ({
+ title,
+ flyoutVisible,
+ children,
+ onClose,
+ onSaveCancelled,
+ onSaveConfirmed,
+}) => {
+ return flyoutVisible ? (
+
+
+
+ {title}
+
+
+ {children}
+
+
+
+
+ {i18n.FLYOUT_CANCEL_BUTTON_TITLE}
+
+
+
+
+ {i18n.FLYOUT_SAVE_BUTTON_TITLE}
+
+
+
+
+
+ ) : null;
+};
+
+export const Flyout = React.memo(FlyoutComponent);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/translations.ts
new file mode 100644
index 0000000000000..f25348cd8b5d6
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/translations.ts
@@ -0,0 +1,22 @@
+/*
+ * 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 FLYOUT_SAVE_BUTTON_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.flyout.saveButtonTitle',
+ {
+ defaultMessage: 'Save',
+ }
+);
+
+export const FLYOUT_CANCEL_BUTTON_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.flyout.cancelButtonTitle',
+ {
+ defaultMessage: 'Cancel',
+ }
+);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/use_flyout_modal_visibility.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/use_flyout_modal_visibility.ts
new file mode 100644
index 0000000000000..01291b6f77252
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/use_flyout_modal_visibility.ts
@@ -0,0 +1,26 @@
+/*
+ * 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 { useState } from 'react';
+
+export const useFlyoutModalVisibility = () => {
+ const [isFlyoutOpen, setIsFlyoutOpen] = useState(false);
+
+ const openFlyout = () => {
+ setIsFlyoutOpen(true);
+ };
+
+ const closeFlyout = () => {
+ setIsFlyoutOpen(false);
+ };
+
+ return {
+ isFlyoutOpen,
+ openFlyout,
+ closeFlyout,
+ };
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/row_actions.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/row_actions.tsx
similarity index 66%
rename from x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/row_actions.tsx
rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/row_actions.tsx
index 97360feaebc3c..7eeaf07f930d2 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/row_actions.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/row_actions.tsx
@@ -11,32 +11,33 @@ import React, { useCallback, useState } from 'react';
import {
DELETE_CONNECTOR_BUTTON,
EDIT_CONNECTOR_BUTTON,
-} from '../../../connectorland/translations';
+} from '../../../../connectorland/translations';
interface Props {
rowItem: T;
- onEdit: (rowItem: T) => void;
- onDelete: (rowItem: T) => void;
+ onEdit?: (rowItem: T) => void;
+ onDelete?: (rowItem: T) => void;
+ disabled?: boolean;
}
type RowActionsComponentType = (props: Props) => JSX.Element;
-const RowActionsComponent = ({ rowItem, onEdit, onDelete }: Props) => {
+const RowActionsComponent = ({ disabled, rowItem, onEdit, onDelete }: Props) => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const closePopover = useCallback(() => setIsPopoverOpen(false), []);
const handleEditConnector = useCallback(() => {
closePopover();
- onEdit(rowItem);
+ onEdit?.(rowItem);
}, [closePopover, onEdit, rowItem]);
const handleDeleteConnector = useCallback(() => {
closePopover();
- onDelete(rowItem);
+ onDelete?.(rowItem);
}, [closePopover, onDelete, rowItem]);
const onButtonClick = useCallback(() => setIsPopoverOpen((prevState) => !prevState), []);
- return (
+ return onEdit || onDelete ? (
({ rowItem, onEdit, onDelete }: Props) => {
anchorPosition="downLeft"
>
-
-
- {EDIT_CONNECTOR_BUTTON}
-
-
-
-
- {DELETE_CONNECTOR_BUTTON}
-
-
+ {onEdit != null && (
+
+
+ {EDIT_CONNECTOR_BUTTON}
+
+
+ )}
+ {onDelete != null && (
+
+
+ {DELETE_CONNECTOR_BUTTON}
+
+
+ )}
- );
+ ) : null;
};
// casting to correctly infer the param of onEdit and onDelete when reusing this component
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/formatted_date.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/formatted_date.tsx
deleted file mode 100644
index c641290bc3895..0000000000000
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/formatted_date.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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 moment from 'moment';
-import React from 'react';
-import { useDateFormat, useTimeZone } from '../hooks/use_settings';
-
-export const FormattedDate = React.memo<{ dateFormat?: string; value: Date }>(
- /* eslint-disable-next-line react-hooks/rules-of-hooks */
- ({ value, dateFormat = useDateFormat() }) => (
- <>{moment.tz(value, useTimeZone()).format(dateFormat)}>
- )
-);
-
-FormattedDate.displayName = 'FormattedDate';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_settings.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_settings.ts
deleted file mode 100644
index aa9b70963580f..0000000000000
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_settings.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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 moment from 'moment';
-import { useAssistantContext } from '../../../assistant_context';
-
-export const DEFAULT_DATE_FORMAT_TZ = 'dateFormat:tz' as const;
-export const DEFAULT_DATE_FORMAT = 'dateFormat' as const;
-
-export const useUiSetting = (key: string, defaultValue?: T): T => {
- const { settings } = useAssistantContext();
-
- if (!settings) {
- throw new TypeError('uiSettings service not available in kibana-react context.');
- }
-
- return settings.client.get(key, defaultValue);
-};
-
-export const useDateFormat = (): string => useUiSetting(DEFAULT_DATE_FORMAT);
-
-export const useTimeZone = (): string => {
- const timeZone = useUiSetting(DEFAULT_DATE_FORMAT_TZ);
- return timeZone === 'Browser' ? moment.tz.guess() : timeZone;
-};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_table_search.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_table_search.ts
deleted file mode 100644
index 1fec1c76430eb..0000000000000
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/hooks/use_table_search.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-/*
- * 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.
- */
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx
index 98f47e4e8ddcd..9a60f19209200 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx
@@ -11,6 +11,7 @@ import { Conversation } from '../../../assistant_context/types';
import { AIConnector } from '../../../connectorland/connector_selector';
import { getConnectorTypeTitle } from '../../../connectorland/helpers';
import { Prompt } from '../../../..';
+import { getDefaultSystemPrompt } from '../../use_conversation/helpers';
const emptyConversations = {};
@@ -26,7 +27,7 @@ export type ConversationTableItem = Conversation & {
systemPrompt?: string;
};
-export const useConversationSelectorSettings = ({
+export const useConversationsList = ({
allSystemPrompts,
actionTypeRegistry,
connectors,
@@ -39,14 +40,22 @@ export const useConversationSelectorSettings = ({
);
const actionType = getConnectorTypeTitle(connector, actionTypeRegistry);
- const systemPrompt = allSystemPrompts.find(
+ const systemPrompt: Prompt | undefined = allSystemPrompts.find(
({ id }) => id === conversation.apiConfig?.defaultSystemPromptId
);
+ const defaultSystemPrompt = getDefaultSystemPrompt({
+ allSystemPrompts,
+ conversation,
+ });
return {
...conversation,
actionType,
- systemPrompt: systemPrompt?.label ?? systemPrompt?.name,
+ systemPrompt:
+ systemPrompt?.label ??
+ systemPrompt?.name ??
+ defaultSystemPrompt?.label ??
+ defaultSystemPrompt?.name,
};
});
}, [allSystemPrompts, actionTypeRegistry, connectors, conversations]);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx
index 8ea90eaf41d66..9c89fc27302bc 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx
@@ -6,36 +6,29 @@
*/
import {
- EuiFormRow,
- EuiLink,
EuiTitle,
EuiText,
EuiHorizontalRule,
EuiSpacer,
+ EuiFormRow,
EuiSwitch,
} from '@elastic/eui';
import React, { useCallback, useMemo } from 'react';
import { HttpSetup } from '@kbn/core-http-browser';
-import { FormattedMessage } from '@kbn/i18n-react';
-import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/public/common';
-import { noop } from 'lodash/fp';
+
import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public';
import { Conversation, Prompt } from '../../../..';
import * as i18n from './translations';
-import * as i18nModel from '../../../connectorland/models/model_selector/translations';
-import { AIConnector, ConnectorSelector } from '../../../connectorland/connector_selector';
-import { SelectSystemPrompt } from '../../prompt_editor/system_prompt/select_system_prompt';
-import { ModelSelector } from '../../../connectorland/models/model_selector/model_selector';
+import { AIConnector } from '../../../connectorland/connector_selector';
+
import { ConversationSelectorSettings } from '../conversation_selector_settings';
import { getDefaultSystemPrompt } from '../../use_conversation/helpers';
-import { useLoadConnectors } from '../../../connectorland/use_load_connectors';
-import { getGenAiConfig } from '../../../connectorland/helpers';
+
import { ConversationsBulkActions } from '../../api';
-import { useSelectSystemPrompt } from './use_select_system_prompt';
-import { useConnectorSelector } from './use_connector_selector';
import { useConversationDeleted } from './use_conversation_deleted';
+import { ConversationSettingsEditor } from './conversation_settings_editor';
export interface ConversationSettingsProps {
actionTypeRegistry: ActionTypeRegistryContract;
@@ -79,10 +72,6 @@ export const ConversationSettings: React.FC = React.m
return getDefaultSystemPrompt({ allSystemPrompts, conversation: undefined });
}, [allSystemPrompts]);
- const { data: connectors, isSuccess: areConnectorsFetched } = useLoadConnectors({
- http,
- });
-
// Conversation callbacks
// When top level conversation selection changes
const onConversationSelectionChange = useCallback(
@@ -150,96 +139,6 @@ export const ConversationSettings: React.FC = React.m
setConversationsSettingsBulkActions,
});
- const { selectedSystemPrompt, handleOnSystemPromptSelectionChange } = useSelectSystemPrompt({
- allSystemPrompts,
- conversationSettings,
- conversationsSettingsBulkActions,
- selectedConversation,
- setConversationSettings,
- setConversationsSettingsBulkActions,
- });
-
- const selectedConnector = useMemo(() => {
- const selectedConnectorId = selectedConversation?.apiConfig?.connectorId;
- if (areConnectorsFetched) {
- return connectors?.find((c) => c.id === selectedConnectorId);
- }
- return undefined;
- }, [areConnectorsFetched, connectors, selectedConversation?.apiConfig?.connectorId]);
-
- const selectedProvider = useMemo(
- () => selectedConversation?.apiConfig?.provider,
- [selectedConversation?.apiConfig?.provider]
- );
-
- const handleOnConnectorSelectionChange = useConnectorSelector({
- selectedConversation,
- setConversationSettings,
- conversationSettings,
- setConversationsSettingsBulkActions,
- conversationsSettingsBulkActions,
- });
-
- const selectedModel = useMemo(() => {
- const connectorModel = getGenAiConfig(selectedConnector)?.defaultModel;
- // Prefer conversation configuration over connector default
- return selectedConversation?.apiConfig?.model ?? connectorModel;
- }, [selectedConnector, selectedConversation?.apiConfig?.model]);
-
- const handleOnModelSelectionChange = useCallback(
- (model?: string) => {
- if (selectedConversation != null && selectedConversation.apiConfig) {
- const updatedConversation = {
- ...selectedConversation,
- apiConfig: {
- ...selectedConversation.apiConfig,
- model,
- },
- };
- setConversationSettings({
- ...conversationSettings,
- [updatedConversation.id]: updatedConversation,
- });
- if (selectedConversation.id !== '') {
- setConversationsSettingsBulkActions({
- ...conversationsSettingsBulkActions,
- update: {
- ...(conversationsSettingsBulkActions.update ?? {}),
- [updatedConversation.id]: {
- ...updatedConversation,
- ...(conversationsSettingsBulkActions.update
- ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
- : {}),
- apiConfig: {
- ...updatedConversation.apiConfig,
- ...((conversationsSettingsBulkActions.update
- ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
- : {}
- ).apiConfig ?? {}),
- model,
- },
- },
- },
- });
- } else {
- setConversationsSettingsBulkActions({
- ...conversationsSettingsBulkActions,
- create: {
- ...(conversationsSettingsBulkActions.create ?? {}),
- [updatedConversation.id]: updatedConversation,
- },
- });
- }
- }
- },
- [
- conversationSettings,
- conversationsSettingsBulkActions,
- selectedConversation,
- setConversationSettings,
- setConversationsSettingsBulkActions,
- ]
- );
return (
<>
@@ -256,67 +155,18 @@ export const ConversationSettings: React.FC = React.m
onConversationSelectionChange={onConversationSelectionChange}
/>
-
-
-
-
-
-
-
- }
- >
-
-
+
- {selectedConnector?.isPreconfigured === false &&
- selectedProvider === OpenAiProviderType.OpenAi && (
-
-
-
- )}
{i18n.SETTINGS_ALL_TITLE}
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx
new file mode 100644
index 0000000000000..691ad911be3a5
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx
@@ -0,0 +1,267 @@
+/*
+ * 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 { EuiFormRow, EuiLink } from '@elastic/eui';
+import React, { useCallback, useMemo } from 'react';
+
+import { HttpSetup } from '@kbn/core-http-browser';
+import { FormattedMessage } from '@kbn/i18n-react';
+import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/public/common';
+import { noop } from 'lodash/fp';
+import { Conversation, Prompt } from '../../../..';
+import * as i18n from './translations';
+import * as i18nModel from '../../../connectorland/models/model_selector/translations';
+
+import { ConnectorSelector } from '../../../connectorland/connector_selector';
+import { SelectSystemPrompt } from '../../prompt_editor/system_prompt/select_system_prompt';
+import { ModelSelector } from '../../../connectorland/models/model_selector/model_selector';
+import { useLoadConnectors } from '../../../connectorland/use_load_connectors';
+import { getGenAiConfig } from '../../../connectorland/helpers';
+import { ConversationsBulkActions } from '../../api';
+import { useConnectorSelector } from './use_connector_selector';
+import { getDefaultSystemPrompt } from '../../use_conversation/helpers';
+
+export interface ConversationSettingsEditorProps {
+ allSystemPrompts: Prompt[];
+ conversationSettings: Record;
+ conversationsSettingsBulkActions: ConversationsBulkActions;
+ http: HttpSetup;
+ isDisabled?: boolean;
+ isFlyoutMode: boolean;
+ selectedConversation?: Conversation;
+ setConversationSettings: React.Dispatch>>;
+ setConversationsSettingsBulkActions: React.Dispatch<
+ React.SetStateAction
+ >;
+}
+
+/**
+ * Settings for adding/removing conversation and configuring default system prompt and connector.
+ */
+export const ConversationSettingsEditor: React.FC = React.memo(
+ ({
+ allSystemPrompts,
+ selectedConversation,
+ conversationSettings,
+ http,
+ isDisabled = false,
+ isFlyoutMode,
+ setConversationSettings,
+ conversationsSettingsBulkActions,
+ setConversationsSettingsBulkActions,
+ }) => {
+ const { data: connectors, isSuccess: areConnectorsFetched } = useLoadConnectors({
+ http,
+ });
+
+ const selectedSystemPrompt = useMemo(() => {
+ return getDefaultSystemPrompt({ allSystemPrompts, conversation: selectedConversation });
+ }, [allSystemPrompts, selectedConversation]);
+ const handleOnSystemPromptSelectionChange = useCallback(
+ (systemPromptId?: string | undefined) => {
+ if (selectedConversation != null && selectedConversation.apiConfig) {
+ const updatedConversation = {
+ ...selectedConversation,
+ apiConfig: {
+ ...selectedConversation.apiConfig,
+ defaultSystemPromptId: systemPromptId,
+ },
+ };
+ setConversationSettings({
+ ...conversationSettings,
+ [updatedConversation.id]: updatedConversation,
+ });
+ if (selectedConversation.id !== '') {
+ setConversationsSettingsBulkActions({
+ ...conversationsSettingsBulkActions,
+ update: {
+ ...(conversationsSettingsBulkActions.update ?? {}),
+ [updatedConversation.id]: {
+ ...updatedConversation,
+ ...(conversationsSettingsBulkActions.update
+ ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
+ : {}),
+ apiConfig: {
+ ...updatedConversation.apiConfig,
+ ...((conversationsSettingsBulkActions.update
+ ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
+ : {}
+ ).apiConfig ?? {}),
+ defaultSystemPromptId: systemPromptId,
+ },
+ },
+ },
+ });
+ } else {
+ setConversationsSettingsBulkActions({
+ ...conversationsSettingsBulkActions,
+ create: {
+ ...(conversationsSettingsBulkActions.create ?? {}),
+ [updatedConversation.id]: updatedConversation,
+ },
+ });
+ }
+ }
+ },
+ [
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ selectedConversation,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ ]
+ );
+
+ const selectedConnector = useMemo(() => {
+ const selectedConnectorId = selectedConversation?.apiConfig?.connectorId;
+ if (areConnectorsFetched) {
+ return connectors?.find((c) => c.id === selectedConnectorId);
+ }
+ return undefined;
+ }, [areConnectorsFetched, connectors, selectedConversation?.apiConfig?.connectorId]);
+
+ const selectedProvider = useMemo(
+ () => selectedConversation?.apiConfig?.provider,
+ [selectedConversation?.apiConfig?.provider]
+ );
+
+ const handleOnConnectorSelectionChange = useConnectorSelector({
+ selectedConversation,
+ setConversationSettings,
+ conversationSettings,
+ setConversationsSettingsBulkActions,
+ conversationsSettingsBulkActions,
+ });
+
+ const selectedModel = useMemo(() => {
+ const connectorModel = getGenAiConfig(selectedConnector)?.defaultModel;
+ // Prefer conversation configuration over connector default
+ return selectedConversation?.apiConfig?.model ?? connectorModel;
+ }, [selectedConnector, selectedConversation?.apiConfig?.model]);
+
+ const handleOnModelSelectionChange = useCallback(
+ (model?: string) => {
+ if (selectedConversation != null && selectedConversation.apiConfig) {
+ const updatedConversation = {
+ ...selectedConversation,
+ apiConfig: {
+ ...selectedConversation.apiConfig,
+ model,
+ },
+ };
+ setConversationSettings({
+ ...conversationSettings,
+ [updatedConversation.id]: updatedConversation,
+ });
+ if (selectedConversation.id !== '') {
+ setConversationsSettingsBulkActions({
+ ...conversationsSettingsBulkActions,
+ update: {
+ ...(conversationsSettingsBulkActions.update ?? {}),
+ [updatedConversation.id]: {
+ ...updatedConversation,
+ ...(conversationsSettingsBulkActions.update
+ ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
+ : {}),
+ apiConfig: {
+ ...updatedConversation.apiConfig,
+ ...((conversationsSettingsBulkActions.update
+ ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
+ : {}
+ ).apiConfig ?? {}),
+ model,
+ },
+ },
+ },
+ });
+ } else {
+ setConversationsSettingsBulkActions({
+ ...conversationsSettingsBulkActions,
+ create: {
+ ...(conversationsSettingsBulkActions.create ?? {}),
+ [updatedConversation.id]: updatedConversation,
+ },
+ });
+ }
+ }
+ },
+ [
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ selectedConversation,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ ]
+ );
+ return (
+ <>
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+ {selectedConnector?.isPreconfigured === false &&
+ selectedProvider === OpenAiProviderType.OpenAi && (
+
+
+
+ )}
+ >
+ );
+ }
+);
+ConversationSettingsEditor.displayName = 'ConversationSettingsEditor';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_select_system_prompt.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_select_system_prompt.tsx
deleted file mode 100644
index 10dd08656d4c1..0000000000000
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_select_system_prompt.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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 { useCallback, useMemo } from 'react';
-import { Conversation, Prompt } from '../../../..';
-import { ConversationsBulkActions } from '../../api';
-import { getDefaultSystemPrompt } from '../../use_conversation/helpers';
-
-interface Props {
- allSystemPrompts: Prompt[];
- conversationSettings: Record;
- conversationsSettingsBulkActions: ConversationsBulkActions;
- selectedConversation?: Conversation;
- setConversationSettings: React.Dispatch>>;
- setConversationsSettingsBulkActions: React.Dispatch<
- React.SetStateAction
- >;
-}
-export const useSelectSystemPrompt = ({
- allSystemPrompts,
- conversationSettings,
- conversationsSettingsBulkActions,
- selectedConversation,
- setConversationSettings,
- setConversationsSettingsBulkActions,
-}: Props) => {
- const selectedSystemPrompt = useMemo(() => {
- return getDefaultSystemPrompt({ allSystemPrompts, conversation: selectedConversation });
- }, [allSystemPrompts, selectedConversation]);
- const handleOnSystemPromptSelectionChange = useCallback(
- (systemPromptId?: string | undefined) => {
- if (selectedConversation != null && selectedConversation.apiConfig) {
- const updatedConversation = {
- ...selectedConversation,
- apiConfig: {
- ...selectedConversation.apiConfig,
- defaultSystemPromptId: systemPromptId,
- },
- };
- setConversationSettings({
- ...conversationSettings,
- [updatedConversation.id]: updatedConversation,
- });
- if (selectedConversation.id !== '') {
- setConversationsSettingsBulkActions({
- ...conversationsSettingsBulkActions,
- update: {
- ...(conversationsSettingsBulkActions.update ?? {}),
- [updatedConversation.id]: {
- ...updatedConversation,
- ...(conversationsSettingsBulkActions.update
- ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
- : {}),
- apiConfig: {
- ...updatedConversation.apiConfig,
- ...((conversationsSettingsBulkActions.update
- ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
- : {}
- ).apiConfig ?? {}),
- defaultSystemPromptId: systemPromptId,
- },
- },
- },
- });
- } else {
- setConversationsSettingsBulkActions({
- ...conversationsSettingsBulkActions,
- create: {
- ...(conversationsSettingsBulkActions.create ?? {}),
- [updatedConversation.id]: updatedConversation,
- },
- });
- }
- }
- },
- [
- conversationSettings,
- conversationsSettingsBulkActions,
- selectedConversation,
- setConversationSettings,
- setConversationsSettingsBulkActions,
- ]
- );
-
- return {
- selectedSystemPrompt,
- handleOnSystemPromptSelectionChange,
- };
-};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
index 001f1c26cf790..fb3b618ea9c8b 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
@@ -6,210 +6,212 @@
*/
import {
- EuiInMemoryTable,
EuiPanel,
EuiSpacer,
EuiBadge,
EuiLink,
- EuiFlyout,
- EuiFlyoutHeader,
- EuiFlyoutBody,
- EuiFormRow,
EuiBasicTableColumn,
- EuiTitle,
- EuiFlyoutFooter,
- EuiFlexGroup,
- EuiFlexItem,
- EuiButtonEmpty,
- EuiButton,
+ EuiConfirmModal,
+ EuiInMemoryTable,
} from '@elastic/eui';
import React, { useCallback, useMemo, useState } from 'react';
import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public';
-import { FormattedMessage } from '@kbn/i18n-react';
-import { noop } from 'lodash/fp';
+import { FormattedDate } from '@kbn/i18n-react';
import { Conversation } from '../../../assistant_context/types';
import {
ConversationTableItem,
- useConversationSelectorSettings,
+ useConversationsList,
} from '../conversation_selector_settings/use_conversation_selector_settings';
import { ConversationStreamingSwitch } from '../conversation_settings/conversation_streaming_switch';
-import { AIConnector, ConnectorSelector } from '../../../connectorland/connector_selector';
-import { FormattedDate } from '../../common/components/formatted_date';
-import { RowActions } from '../../common/components/row_actions';
-import {
- CONVERSATIONS_TABLE_COLUMN_ACTIONS,
- CONVERSATIONS_TABLE_COLUMN_CONNECTOR,
- CONVERSATIONS_TABLE_COLUMN_SYSTEM_PROMPT,
- CONVERSATIONS_TABLE_COLUMN_TYPE,
- CONVERSATIONS_TABLE_COLUMN_UPDATED_AT,
-} from './translations';
-import { SelectSystemPrompt } from '../../prompt_editor/system_prompt/select_system_prompt';
-import {
- CONNECTOR_TITLE,
- SETTINGS_PROMPT_HELP_TEXT_TITLE,
- SETTINGS_PROMPT_TITLE,
-} from '../conversation_settings/translations';
+import { AIConnector } from '../../../connectorland/connector_selector';
+import { RowActions } from '../../common/components/assisttant_settings_management/row_actions';
+import * as i18n from './translations';
+
import { Prompt } from '../../types';
-import { useSelectSystemPrompt } from '../conversation_settings/use_select_system_prompt';
-import { useConnectorSelector } from '../conversation_settings/use_connector_selector';
import { ConversationsBulkActions } from '../../api';
import { useAssistantContext } from '../../../assistant_context';
-import { CANCEL, SAVE } from '../../settings/translations';
import { useConversationDeleted } from '../conversation_settings/use_conversation_deleted';
+import { useFlyoutModalVisibility } from '../../common/components/assisttant_settings_management/flyout/use_flyout_modal_visibility';
+import { Flyout } from '../../common/components/assisttant_settings_management/flyout';
+import { CANCEL, DELETE } from '../../settings/translations';
+import { ConversationSettingsEditor } from '../conversation_settings/conversation_settings_editor';
interface Props {
actionTypeRegistry: ActionTypeRegistryContract;
allSystemPrompts: Prompt[];
- areConnectorsFetched: boolean;
assistantStreamingEnabled: boolean;
connectors: AIConnector[] | undefined;
conversations: Record;
- conversationSettings: Record;
conversationsSettingsBulkActions: ConversationsBulkActions;
handleSave: () => void;
isDisabled?: boolean;
isFlyoutMode: boolean;
+ refetchConversations: () => void;
resetSettings: () => void;
setAssistantStreamingEnabled: React.Dispatch>;
setConversationSettings: React.Dispatch>>;
setConversationsSettingsBulkActions: React.Dispatch<
React.SetStateAction
>;
+ selectedConversation: Conversation | undefined;
+ onSelectedConversationChange: (conversation?: Conversation) => void;
}
const ConversationSettingsManagementComponent: React.FC = ({
actionTypeRegistry,
allSystemPrompts,
- areConnectorsFetched,
assistantStreamingEnabled,
connectors,
conversations,
- conversationSettings,
conversationsSettingsBulkActions,
handleSave,
isDisabled,
isFlyoutMode,
+ onSelectedConversationChange,
+ refetchConversations,
resetSettings,
+ selectedConversation,
setAssistantStreamingEnabled,
setConversationSettings,
setConversationsSettingsBulkActions,
}) => {
const { http } = useAssistantContext();
- const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false);
- const [selectedConversation, setSelectedConversation] = useState<
- ConversationTableItem | undefined
- >(undefined);
+ const {
+ isFlyoutOpen: editFlyoutVisible,
+ openFlyout: openEditFlyout,
+ closeFlyout: closeEditFlyout,
+ } = useFlyoutModalVisibility();
+ const [deleteConversation, setDeleteConversation] = useState();
- const selectedConnector = useMemo(() => {
- const selectedConnectorId = selectedConversation?.apiConfig?.connectorId;
- if (areConnectorsFetched) {
- return connectors?.find((c) => c.id === selectedConnectorId);
- }
- return undefined;
- }, [areConnectorsFetched, connectors, selectedConversation?.apiConfig?.connectorId]);
+ const {
+ isFlyoutOpen: deleteConfirmModalVisibility,
+ openFlyout: openConfirmModal,
+ closeFlyout: closeConfirmModal,
+ } = useFlyoutModalVisibility();
- const selectedConversationTitle = selectedConversation?.title ?? '';
-
- const handleConversationEdited = useCallback((rowItem: ConversationTableItem) => {
- setEditFlyoutVisibility(true);
- setSelectedConversation(rowItem);
- }, []);
+ const onEditActionClicked = useCallback(
+ (rowItem: ConversationTableItem) => {
+ openEditFlyout();
+ onSelectedConversationChange(rowItem);
+ },
+ [onSelectedConversationChange, openEditFlyout]
+ );
const onConversationDeleted = useConversationDeleted({
- conversationSettings,
+ conversationSettings: conversations,
conversationsSettingsBulkActions,
setConversationSettings,
setConversationsSettingsBulkActions,
});
- const handleConversationDeleted = useCallback(() => {
- onConversationDeleted(selectedConversationTitle);
- }, [onConversationDeleted, selectedConversationTitle]);
+ const onDeleteActionClicked = useCallback(
+ (rowItem: ConversationTableItem) => {
+ setDeleteConversation(rowItem);
+ closeEditFlyout();
+ openConfirmModal();
+ },
+ [closeEditFlyout, openConfirmModal]
+ );
- const conversationOptions = useConversationSelectorSettings({
+ const onDeleteConfirmed = useCallback(() => {
+ if (!deleteConversation) return;
+ onConversationDeleted(deleteConversation.title);
+ closeConfirmModal();
+ refetchConversations();
+ }, [deleteConversation, onConversationDeleted, closeConfirmModal, refetchConversations]);
+
+ const onDeleteCancelled = useCallback(() => {
+ setDeleteConversation(null);
+ closeConfirmModal();
+ resetSettings();
+ }, [closeConfirmModal, resetSettings]);
+
+ const conversationOptions = useConversationsList({
allSystemPrompts,
actionTypeRegistry,
connectors,
conversations,
});
- const { selectedSystemPrompt, handleOnSystemPromptSelectionChange } = useSelectSystemPrompt({
- allSystemPrompts,
- conversationSettings,
- conversationsSettingsBulkActions,
- selectedConversation,
- setConversationSettings,
- setConversationsSettingsBulkActions,
- });
+ const onEditFlyoutClosed = useCallback(() => {
+ closeEditFlyout();
+ resetSettings();
+ }, [closeEditFlyout, resetSettings]);
- const handleOnConnectorSelectionChange = useConnectorSelector({
- selectedConversation,
- setConversationSettings,
- conversationSettings,
- setConversationsSettingsBulkActions,
- conversationsSettingsBulkActions,
- });
+ const onEditFlyoutSaved = useCallback(() => {
+ handleSave();
+ closeEditFlyout();
+ refetchConversations();
+ }, [closeEditFlyout, handleSave, refetchConversations]);
- const columns: Array> = [
- {
- name: CONVERSATIONS_TABLE_COLUMN_TYPE,
- render: (conversation: ConversationTableItem) => (
- handleConversationEdited(conversation)}>
- {conversation.title}
-
- ),
- },
- {
- field: 'systemPrompt',
- name: CONVERSATIONS_TABLE_COLUMN_SYSTEM_PROMPT,
- render: (systemPrompt: ConversationTableItem['systemPrompt']) =>
- systemPrompt ? {systemPrompt} : null,
- },
- {
- field: 'actionType',
- name: CONVERSATIONS_TABLE_COLUMN_CONNECTOR,
- render: (actionType: ConversationTableItem['actionType']) =>
- actionType ? {actionType} : null,
- },
- {
- field: 'updatedAt',
- name: CONVERSATIONS_TABLE_COLUMN_UPDATED_AT,
- render: (updatedAt: ConversationTableItem['updatedAt']) =>
- updatedAt ? (
-
-
-
- ) : null,
- },
- {
- name: CONVERSATIONS_TABLE_COLUMN_ACTIONS,
- actions: [
- {
- name: CONVERSATIONS_TABLE_COLUMN_ACTIONS,
- render: (conversation: ConversationTableItem) => {
- return (
-
- rowItem={conversation}
- onEdit={handleConversationEdited}
- onDelete={handleConversationDeleted}
+ const columns: Array> = useMemo(
+ () => [
+ {
+ name: i18n.CONVERSATIONS_TABLE_COLUMN_TYPE,
+ render: (conversation: ConversationTableItem) => (
+ onEditActionClicked(conversation)}>{conversation.title}
+ ),
+ },
+ {
+ field: 'systemPrompt',
+ name: i18n.CONVERSATIONS_TABLE_COLUMN_SYSTEM_PROMPT,
+ render: (systemPrompt: ConversationTableItem['systemPrompt']) =>
+ systemPrompt ? {systemPrompt} : null,
+ },
+ {
+ field: 'actionType',
+ name: i18n.CONVERSATIONS_TABLE_COLUMN_CONNECTOR,
+ render: (actionType: ConversationTableItem['actionType']) =>
+ actionType ? {actionType} : null,
+ },
+ {
+ field: 'updatedAt',
+ name: i18n.CONVERSATIONS_TABLE_COLUMN_UPDATED_AT,
+ render: (updatedAt: ConversationTableItem['updatedAt']) =>
+ updatedAt ? (
+
+
- );
+
+ ) : null,
+ },
+ {
+ name: i18n.CONVERSATIONS_TABLE_COLUMN_ACTIONS,
+ actions: [
+ {
+ name: i18n.CONVERSATIONS_TABLE_COLUMN_ACTIONS,
+ render: (conversation: ConversationTableItem) => {
+ return (
+
+ rowItem={conversation}
+ onEdit={onEditActionClicked}
+ onDelete={onDeleteActionClicked}
+ />
+ );
+ },
},
- },
- ],
- },
- ];
+ ],
+ },
+ ],
+ [onDeleteActionClicked, onEditActionClicked]
+ );
- const onCancelClick = useCallback(() => {
- setEditFlyoutVisibility(false);
- resetSettings();
- }, [resetSettings]);
+ const sorting = useMemo(
+ () => ({
+ sort: {
+ field: 'updatedAt',
+ direction: 'desc' as const,
+ },
+ }),
+ []
+ );
- const onSaveClick = useCallback(() => {
- handleSave();
- setEditFlyoutVisibility(false);
- }, [handleSave]);
return (
<>
@@ -219,90 +221,48 @@ const ConversationSettingsManagementComponent: React.FC = ({
compressed={false}
/>
-
+
{editFlyoutVisible && (
- setEditFlyoutVisibility(false)}>
-
-
- {selectedConversationTitle}
-
-
-
-
-
-
-
-
-
- }
- >
-
-
-
-
-
-
-
- {CANCEL}
-
-
-
-
- {SAVE}
-
-
-
-
-
+
+
+
+ )}
+ {deleteConfirmModalVisibility && deleteConversation?.title && (
+
+
+
)}
>
);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/translations.ts
index d28f1705de5ab..783e641640b9c 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/translations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/translations.ts
@@ -17,7 +17,7 @@ export const CONVERSATIONS_TABLE_COLUMN_TYPE = i18n.translate(
export const CONVERSATIONS_TABLE_COLUMN_SYSTEM_PROMPT = i18n.translate(
'xpack.elasticAssistant.assistant.conversationSettings.column.systemPrompt',
{
- defaultMessage: 'Title',
+ defaultMessage: 'System prompt',
}
);
@@ -41,3 +41,10 @@ export const CONVERSATIONS_TABLE_COLUMN_ACTIONS = i18n.translate(
defaultMessage: 'Actions',
}
);
+
+export const DELETE_CONVERSATION_CONFIRMATION_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.conversationSettings.deleteConfirmation.title',
+ {
+ defaultMessage: 'conversation',
+ }
+);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_editor.tsx
new file mode 100644
index 0000000000000..5f19726b1497a
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_editor.tsx
@@ -0,0 +1,338 @@
+/*
+ * 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, { useCallback, useMemo } from 'react';
+import {
+ EuiFormRow,
+ EuiTextArea,
+ EuiCheckbox,
+ EuiIcon,
+ EuiFlexGroup,
+ EuiFlexItem,
+} from '@elastic/eui';
+
+import { keyBy } from 'lodash/fp';
+
+import { css } from '@emotion/react';
+import { ApiConfig } from '@kbn/elastic-assistant-common';
+import { AIConnector } from '../../../../connectorland/connector_selector';
+import { Conversation, Prompt } from '../../../../..';
+import * as i18n from './translations';
+import { ConversationMultiSelector } from './conversation_multi_selector/conversation_multi_selector';
+import { SystemPromptSelector } from './system_prompt_selector/system_prompt_selector';
+import { TEST_IDS } from '../../../constants';
+import { ConversationsBulkActions } from '../../../api';
+import { getSelectedConversations } from '../../../quick_prompts/quick_prompt_settings_management.tsx/helpers';
+
+interface Props {
+ conversationSettings: Record;
+ conversationsSettingsBulkActions: ConversationsBulkActions;
+ onSelectedSystemPromptChange: (systemPrompt?: Prompt) => void;
+ selectedSystemPrompt: Prompt | undefined;
+ setUpdatedSystemPromptSettings: React.Dispatch>;
+ setConversationSettings: React.Dispatch>>;
+ systemPromptSettings: Prompt[];
+ setConversationsSettingsBulkActions: React.Dispatch<
+ React.SetStateAction
+ >;
+ defaultConnector?: AIConnector;
+}
+
+/**
+ * Settings for adding/removing system prompts. Configure name, prompt and default conversations.
+ */
+export const SystemPromptEditorComponent: React.FC = ({
+ conversationSettings,
+ onSelectedSystemPromptChange,
+ selectedSystemPrompt,
+ setUpdatedSystemPromptSettings,
+ setConversationSettings,
+ systemPromptSettings,
+ conversationsSettingsBulkActions,
+ setConversationsSettingsBulkActions,
+ defaultConnector,
+}) => {
+ // Prompt
+ const promptContent = useMemo(
+ () => selectedSystemPrompt?.content ?? '',
+ [selectedSystemPrompt?.content]
+ );
+
+ const handlePromptContentChange = useCallback(
+ (e: React.ChangeEvent) => {
+ if (selectedSystemPrompt != null) {
+ setUpdatedSystemPromptSettings((prev): Prompt[] => {
+ const alreadyExists = prev.some((sp) => sp.id === selectedSystemPrompt.id);
+
+ if (alreadyExists) {
+ return prev.map((sp): Prompt => {
+ if (sp.id === selectedSystemPrompt.id) {
+ return {
+ ...sp,
+ content: e.target.value,
+ };
+ }
+ return sp;
+ });
+ }
+
+ return prev;
+ });
+ }
+ },
+ [selectedSystemPrompt, setUpdatedSystemPromptSettings]
+ );
+
+ // Conversations this system prompt should be a default for
+ const conversationOptions = useMemo(
+ () => Object.values(conversationSettings),
+ [conversationSettings]
+ );
+ const selectedConversations = useMemo(() => {
+ return selectedSystemPrompt != null
+ ? getSelectedConversations(conversationSettings, selectedSystemPrompt.id)
+ : [];
+ }, [conversationSettings, selectedSystemPrompt]);
+
+ const handleConversationSelectionChange = useCallback(
+ (currentPromptConversations: Conversation[]) => {
+ const currentPromptConversationTitles = currentPromptConversations.map(
+ (convo) => convo.title
+ );
+ const getDefaultSystemPromptId = (convo: Conversation) =>
+ currentPromptConversationTitles.includes(convo.title)
+ ? selectedSystemPrompt?.id
+ : convo.apiConfig && convo.apiConfig.defaultSystemPromptId === selectedSystemPrompt?.id
+ ? // remove the default System Prompt if it is assigned to a conversation
+ // but that conversation is not in the currentPromptConversationList
+ // This means conversation was removed in the current transaction
+ undefined
+ : // leave it as it is .. if that conversation was neither added nor removed.
+ convo.apiConfig?.defaultSystemPromptId;
+
+ if (selectedSystemPrompt != null) {
+ setConversationSettings((prev) =>
+ keyBy(
+ 'title',
+ /*
+ * updatedConversationWithPrompts calculates the present of prompt for
+ * each conversation. Based on the values of selected conversation, it goes
+ * through each conversation adds/removed the selected prompt on each conversation.
+ *
+ * */
+ Object.values(prev).map((convo) => ({
+ ...convo,
+ ...(convo.apiConfig
+ ? {
+ apiConfig: {
+ ...convo.apiConfig,
+ defaultSystemPromptId: getDefaultSystemPromptId(convo),
+ },
+ }
+ : {
+ apiConfig: {
+ defaultSystemPromptId: getDefaultSystemPromptId(convo),
+ connectorId: defaultConnector?.id ?? '',
+ actionTypeId: defaultConnector?.actionTypeId ?? '',
+ },
+ }),
+ }))
+ )
+ );
+
+ let updatedConversationsSettingsBulkActions = { ...conversationsSettingsBulkActions };
+ Object.values(conversationSettings).forEach((convo) => {
+ const getApiConfig = (): ApiConfig | {} => {
+ if (convo.apiConfig) {
+ return {
+ apiConfig: {
+ ...convo.apiConfig,
+ defaultSystemPromptId: getDefaultSystemPromptId(convo),
+ },
+ };
+ }
+ return {};
+ };
+ const createOperation =
+ convo.id === ''
+ ? {
+ create: {
+ ...(updatedConversationsSettingsBulkActions.create ?? {}),
+ [convo.id]: {
+ ...convo,
+ ...(convo.apiConfig
+ ? {
+ apiConfig: {
+ ...convo.apiConfig,
+ defaultSystemPromptId: getDefaultSystemPromptId(convo),
+ },
+ }
+ : {}),
+ },
+ },
+ }
+ : {};
+
+ const updateOperation =
+ convo.id !== ''
+ ? {
+ update: {
+ ...(updatedConversationsSettingsBulkActions.update ?? {}),
+ [convo.id]: {
+ ...(updatedConversationsSettingsBulkActions.update
+ ? updatedConversationsSettingsBulkActions.update[convo.id] ?? {}
+ : {}),
+ ...getApiConfig(),
+ },
+ },
+ }
+ : {};
+
+ updatedConversationsSettingsBulkActions = {
+ ...updatedConversationsSettingsBulkActions,
+ ...createOperation,
+ ...updateOperation,
+ };
+ });
+ setConversationsSettingsBulkActions(updatedConversationsSettingsBulkActions);
+ }
+ },
+ [
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ defaultConnector?.actionTypeId,
+ defaultConnector?.id,
+ selectedSystemPrompt,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ ]
+ );
+
+ // Whether this system prompt should be the default for new conversations
+ const isNewConversationDefault = useMemo(
+ () => selectedSystemPrompt?.isNewConversationDefault ?? false,
+ [selectedSystemPrompt?.isNewConversationDefault]
+ );
+
+ const handleNewConversationDefaultChange = useCallback(
+ (e) => {
+ const isChecked = e.target.checked;
+
+ if (selectedSystemPrompt != null) {
+ setUpdatedSystemPromptSettings((prev) => {
+ return prev.map((pp) => {
+ return {
+ ...pp,
+ isNewConversationDefault: selectedSystemPrompt.id === pp.id && isChecked,
+ };
+ });
+ });
+ }
+ },
+ [selectedSystemPrompt, setUpdatedSystemPromptSettings]
+ );
+
+ // When top level system prompt selection changes
+ const onSystemPromptSelectionChange = useCallback(
+ (systemPrompt?: Prompt | string) => {
+ const isNew = typeof systemPrompt === 'string';
+ const newSelectedSystemPrompt: Prompt | undefined = isNew
+ ? {
+ id: systemPrompt ?? '',
+ content: '',
+ name: systemPrompt ?? '',
+ promptType: 'system',
+ }
+ : systemPrompt;
+
+ if (newSelectedSystemPrompt != null) {
+ setUpdatedSystemPromptSettings((prev) => {
+ const alreadyExists = prev.some((sp) => sp.id === newSelectedSystemPrompt.id);
+
+ if (!alreadyExists) {
+ return [...prev, newSelectedSystemPrompt];
+ }
+
+ return prev;
+ });
+ }
+
+ onSelectedSystemPromptChange(newSelectedSystemPrompt);
+ },
+ [onSelectedSystemPromptChange, setUpdatedSystemPromptSettings]
+ );
+
+ const onSystemPromptDeleted = useCallback(
+ (id: string) => {
+ setUpdatedSystemPromptSettings((prev) => prev.filter((sp) => sp.id !== id));
+ },
+ [setUpdatedSystemPromptSettings]
+ );
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ {i18n.SYSTEM_PROMPT_DEFAULT_NEW_CONVERSATION}
+
+
+
+
+ }
+ checked={isNewConversationDefault}
+ onChange={handleNewConversationDefaultChange}
+ compressed
+ />
+
+ >
+ );
+};
+
+export const SystemPromptEditor = React.memo(SystemPromptEditorComponent);
+
+SystemPromptEditor.displayName = 'SystemPromptEditor';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_settings.tsx
index defe0d90e8c8c..c228cc7df49c6 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_settings.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_settings.tsx
@@ -5,50 +5,17 @@
* 2.0.
*/
-import React, { useCallback, useMemo } from 'react';
-import {
- EuiFormRow,
- EuiTextArea,
- EuiCheckbox,
- EuiIcon,
- EuiFlexGroup,
- EuiFlexItem,
- EuiTitle,
- EuiText,
- EuiHorizontalRule,
- EuiSpacer,
-} from '@elastic/eui';
+import React from 'react';
+import { EuiTitle, EuiText, EuiHorizontalRule, EuiSpacer } from '@elastic/eui';
-import { keyBy } from 'lodash/fp';
-
-import { css } from '@emotion/react';
-import { ApiConfig } from '@kbn/elastic-assistant-common';
-import { AIConnector } from '../../../../connectorland/connector_selector';
-import { Conversation, Prompt } from '../../../../..';
import * as i18n from './translations';
-import { ConversationMultiSelector } from './conversation_multi_selector/conversation_multi_selector';
-import { SystemPromptSelector } from './system_prompt_selector/system_prompt_selector';
-import { TEST_IDS } from '../../../constants';
-import { ConversationsBulkActions } from '../../../api';
-
-interface Props {
- conversationSettings: Record;
- conversationsSettingsBulkActions: ConversationsBulkActions;
- onSelectedSystemPromptChange: (systemPrompt?: Prompt) => void;
- selectedSystemPrompt: Prompt | undefined;
- setUpdatedSystemPromptSettings: React.Dispatch>;
- setConversationSettings: React.Dispatch>>;
- systemPromptSettings: Prompt[];
- setConversationsSettingsBulkActions: React.Dispatch<
- React.SetStateAction
- >;
- defaultConnector?: AIConnector;
-}
+import { SystemPromptEditor } from './system_prompt_editor';
+import { SystemPromptSettingsProps } from './types';
/**
* Settings for adding/removing system prompts. Configure name, prompt and default conversations.
*/
-export const SystemPromptSettings: React.FC = React.memo(
+export const SystemPromptSettings: React.FC = React.memo(
({
conversationSettings,
onSelectedSystemPromptChange,
@@ -60,226 +27,6 @@ export const SystemPromptSettings: React.FC = React.memo(
setConversationsSettingsBulkActions,
defaultConnector,
}) => {
- // Prompt
- const promptContent = useMemo(
- () => selectedSystemPrompt?.content ?? '',
- [selectedSystemPrompt?.content]
- );
-
- const handlePromptContentChange = useCallback(
- (e: React.ChangeEvent) => {
- if (selectedSystemPrompt != null) {
- setUpdatedSystemPromptSettings((prev): Prompt[] => {
- const alreadyExists = prev.some((sp) => sp.id === selectedSystemPrompt.id);
-
- if (alreadyExists) {
- return prev.map((sp): Prompt => {
- if (sp.id === selectedSystemPrompt.id) {
- return {
- ...sp,
- content: e.target.value,
- };
- }
- return sp;
- });
- }
-
- return prev;
- });
- }
- },
- [selectedSystemPrompt, setUpdatedSystemPromptSettings]
- );
-
- // Conversations this system prompt should be a default for
- const conversationOptions = useMemo(
- () => Object.values(conversationSettings),
- [conversationSettings]
- );
- const selectedConversations = useMemo(() => {
- return selectedSystemPrompt != null
- ? Object.values(conversationSettings).filter(
- (conversation) =>
- conversation.apiConfig?.defaultSystemPromptId === selectedSystemPrompt.id
- )
- : [];
- }, [conversationSettings, selectedSystemPrompt]);
-
- const handleConversationSelectionChange = useCallback(
- (currentPromptConversations: Conversation[]) => {
- const currentPromptConversationTitles = currentPromptConversations.map(
- (convo) => convo.title
- );
- const getDefaultSystemPromptId = (convo: Conversation) =>
- currentPromptConversationTitles.includes(convo.title)
- ? selectedSystemPrompt?.id
- : convo.apiConfig && convo.apiConfig.defaultSystemPromptId === selectedSystemPrompt?.id
- ? // remove the default System Prompt if it is assigned to a conversation
- // but that conversation is not in the currentPromptConversationList
- // This means conversation was removed in the current transaction
- undefined
- : // leave it as it is .. if that conversation was neither added nor removed.
- convo.apiConfig?.defaultSystemPromptId;
-
- if (selectedSystemPrompt != null) {
- setConversationSettings((prev) =>
- keyBy(
- 'title',
- /*
- * updatedConversationWithPrompts calculates the present of prompt for
- * each conversation. Based on the values of selected conversation, it goes
- * through each conversation adds/removed the selected prompt on each conversation.
- *
- * */
- Object.values(prev).map((convo) => ({
- ...convo,
- ...(convo.apiConfig
- ? {
- apiConfig: {
- ...convo.apiConfig,
- defaultSystemPromptId: getDefaultSystemPromptId(convo),
- },
- }
- : {
- apiConfig: {
- defaultSystemPromptId: getDefaultSystemPromptId(convo),
- connectorId: defaultConnector?.id ?? '',
- actionTypeId: defaultConnector?.actionTypeId ?? '',
- },
- }),
- }))
- )
- );
-
- let updatedConversationsSettingsBulkActions = { ...conversationsSettingsBulkActions };
- Object.values(conversationSettings).forEach((convo) => {
- const getApiConfig = (): ApiConfig | {} => {
- if (convo.apiConfig) {
- return {
- apiConfig: {
- ...convo.apiConfig,
- defaultSystemPromptId: getDefaultSystemPromptId(convo),
- },
- };
- }
- return {};
- };
- const createOperation =
- convo.id === ''
- ? {
- create: {
- ...(updatedConversationsSettingsBulkActions.create ?? {}),
- [convo.id]: {
- ...convo,
- ...(convo.apiConfig
- ? {
- apiConfig: {
- ...convo.apiConfig,
- defaultSystemPromptId: getDefaultSystemPromptId(convo),
- },
- }
- : {}),
- },
- },
- }
- : {};
-
- const updateOperation =
- convo.id !== ''
- ? {
- update: {
- ...(updatedConversationsSettingsBulkActions.update ?? {}),
- [convo.id]: {
- ...(updatedConversationsSettingsBulkActions.update
- ? updatedConversationsSettingsBulkActions.update[convo.id] ?? {}
- : {}),
- ...getApiConfig(),
- },
- },
- }
- : {};
-
- updatedConversationsSettingsBulkActions = {
- ...updatedConversationsSettingsBulkActions,
- ...createOperation,
- ...updateOperation,
- };
- });
- setConversationsSettingsBulkActions(updatedConversationsSettingsBulkActions);
- }
- },
- [
- conversationSettings,
- conversationsSettingsBulkActions,
- defaultConnector?.actionTypeId,
- defaultConnector?.id,
- selectedSystemPrompt,
- setConversationSettings,
- setConversationsSettingsBulkActions,
- ]
- );
-
- // Whether this system prompt should be the default for new conversations
- const isNewConversationDefault = useMemo(
- () => selectedSystemPrompt?.isNewConversationDefault ?? false,
- [selectedSystemPrompt?.isNewConversationDefault]
- );
-
- const handleNewConversationDefaultChange = useCallback(
- (e) => {
- const isChecked = e.target.checked;
-
- if (selectedSystemPrompt != null) {
- setUpdatedSystemPromptSettings((prev) => {
- return prev.map((pp) => {
- return {
- ...pp,
- isNewConversationDefault: selectedSystemPrompt.id === pp.id && isChecked,
- };
- });
- });
- }
- },
- [selectedSystemPrompt, setUpdatedSystemPromptSettings]
- );
-
- // When top level system prompt selection changes
- const onSystemPromptSelectionChange = useCallback(
- (systemPrompt?: Prompt | string) => {
- const isNew = typeof systemPrompt === 'string';
- const newSelectedSystemPrompt: Prompt | undefined = isNew
- ? {
- id: systemPrompt ?? '',
- content: '',
- name: systemPrompt ?? '',
- promptType: 'system',
- }
- : systemPrompt;
-
- if (newSelectedSystemPrompt != null) {
- setUpdatedSystemPromptSettings((prev) => {
- const alreadyExists = prev.some((sp) => sp.id === newSelectedSystemPrompt.id);
-
- if (!alreadyExists) {
- return [...prev, newSelectedSystemPrompt];
- }
-
- return prev;
- });
- }
-
- onSelectedSystemPromptChange(newSelectedSystemPrompt);
- },
- [onSelectedSystemPromptChange, setUpdatedSystemPromptSettings]
- );
-
- const onSystemPromptDeleted = useCallback(
- (id: string) => {
- setUpdatedSystemPromptSettings((prev) => prev.filter((sp) => sp.id !== id));
- },
- [setUpdatedSystemPromptSettings]
- );
-
return (
<>
@@ -289,60 +36,17 @@ export const SystemPromptSettings: React.FC = React.memo(
{i18n.SETTINGS_DESCRIPTION}
-
-
-
-
-
-
-
-
-
-
-
-
- {i18n.SYSTEM_PROMPT_DEFAULT_NEW_CONVERSATION}
-
-
-
-
- }
- checked={isNewConversationDefault}
- onChange={handleNewConversationDefaultChange}
- compressed
- />
-
+
>
);
}
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/translations.ts
index 06544b98a68bd..c9cd7bde54797 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/translations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/translations.ts
@@ -68,17 +68,3 @@ export const SYSTEM_PROMPT_DEFAULT_CONVERSATIONS_HELP_TEXT = i18n.translate(
defaultMessage: 'Conversations that should use this System Prompt by default',
}
);
-
-export const CANCEL = i18n.translate(
- 'xpack.elasticAssistant.assistant.promptEditor.systemPrompt.slCancelButtonTitle',
- {
- defaultMessage: 'Cancel',
- }
-);
-
-export const SAVE = i18n.translate(
- 'xpack.elasticAssistant.assistant.promptEditor.systemPrompt.slSaveButtonTitle',
- {
- defaultMessage: 'Save',
- }
-);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/types.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/types.ts
new file mode 100644
index 0000000000000..4fa30c39436e9
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/types.ts
@@ -0,0 +1,23 @@
+/*
+ * 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 { AIConnector } from '../../../../connectorland/connector_selector';
+import { Conversation, Prompt } from '../../../../..';
+import { ConversationsBulkActions } from '../../../api';
+
+export interface SystemPromptSettingsProps {
+ conversationSettings: Record;
+ conversationsSettingsBulkActions: ConversationsBulkActions;
+ onSelectedSystemPromptChange: (systemPrompt?: Prompt) => void;
+ selectedSystemPrompt: Prompt | undefined;
+ setUpdatedSystemPromptSettings: React.Dispatch>;
+ setConversationSettings: React.Dispatch>>;
+ systemPromptSettings: Prompt[];
+ setConversationsSettingsBulkActions: React.Dispatch<
+ React.SetStateAction
+ >;
+ defaultConnector?: AIConnector;
+}
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx
new file mode 100644
index 0000000000000..28cf547b15e7e
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx
@@ -0,0 +1,221 @@
+/*
+ * 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 {
+ EuiInMemoryTable,
+ EuiPanel,
+ EuiConfirmModal,
+ EuiButton,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiLink,
+ EuiBadge,
+} from '@elastic/eui';
+import React, { useCallback, useMemo, useState } from 'react';
+import { Conversation, ConversationsBulkActions } from '../../../../..';
+import { AIConnector } from '../../../../connectorland/connector_selector';
+import { Flyout } from '../../../common/components/assisttant_settings_management/flyout';
+import { useFlyoutModalVisibility } from '../../../common/components/assisttant_settings_management/flyout/use_flyout_modal_visibility';
+import { RowActions } from '../../../common/components/assisttant_settings_management/row_actions';
+import { getSystemPromptsList } from '../../../quick_prompts/quick_prompt_settings_management.tsx/helpers';
+import { CANCEL, DELETE } from '../../../settings/translations';
+import { Prompt } from '../../../types';
+import { SystemPromptEditor } from '../system_prompt_modal/system_prompt_editor';
+import { SETTINGS_TITLE } from '../system_prompt_modal/translations';
+import * as i18n from './translations';
+
+interface Props {
+ conversations: Record;
+ conversationSettings: Record;
+ conversationsSettingsBulkActions: ConversationsBulkActions;
+ onSelectedSystemPromptChange: (systemPrompt?: Prompt) => void;
+ selectedSystemPrompt: Prompt | undefined;
+ setUpdatedSystemPromptSettings: React.Dispatch>;
+ setConversationSettings: React.Dispatch>>;
+ systemPromptSettings: Prompt[];
+ setConversationsSettingsBulkActions: React.Dispatch<
+ React.SetStateAction
+ >;
+ defaultConnector?: AIConnector;
+ handleSave: () => void;
+ resetSettings: () => void;
+}
+
+const SystemPromptSettingsManagementComponent = ({
+ conversations,
+ conversationSettings,
+ onSelectedSystemPromptChange,
+ setUpdatedSystemPromptSettings,
+ setConversationSettings,
+ selectedSystemPrompt,
+ systemPromptSettings,
+ conversationsSettingsBulkActions,
+ setConversationsSettingsBulkActions,
+ defaultConnector,
+ handleSave,
+ resetSettings,
+}: Props) => {
+ const { isFlyoutOpen: editFlyoutVisible, openFlyout, closeFlyout } = useFlyoutModalVisibility();
+ const {
+ isFlyoutOpen: deleteConfirmModalVisibility,
+ openFlyout: openConfirmModal,
+ closeFlyout: closeConfirmModal,
+ } = useFlyoutModalVisibility();
+ const [deletedPrompt, setDeletedPrompt] = useState();
+
+ const onCreate = useCallback(() => {
+ onSelectedSystemPromptChange({
+ id: '',
+ content: '',
+ name: '',
+ promptType: 'system',
+ });
+ openFlyout();
+ }, [onSelectedSystemPromptChange, openFlyout]);
+
+ const onEditActionClicked = useCallback(
+ (prompt: Prompt) => {
+ onSelectedSystemPromptChange(prompt);
+ openFlyout();
+ },
+ [onSelectedSystemPromptChange, openFlyout]
+ );
+
+ const onDeleteActionClicked = useCallback(
+ (prompt: Prompt) => {
+ setDeletedPrompt(prompt);
+ openConfirmModal();
+ },
+ [openConfirmModal]
+ );
+
+ const onDeleteCancelled = useCallback(() => {
+ setDeletedPrompt(null);
+ closeConfirmModal();
+ }, [closeConfirmModal]);
+
+ const onDeleteConfirmed = useCallback(() => {
+ setUpdatedSystemPromptSettings((prev) => prev.filter((sp) => sp.id !== deletedPrompt?.id));
+ handleSave();
+ closeConfirmModal();
+ }, [closeConfirmModal, deletedPrompt?.id, handleSave, setUpdatedSystemPromptSettings]);
+
+ const onSaveCancelled = useCallback(() => {
+ onSelectedSystemPromptChange();
+ closeFlyout();
+ resetSettings();
+ }, [onSelectedSystemPromptChange, closeFlyout, resetSettings]);
+
+ const onSaveConfirmed = useCallback(() => {
+ handleSave();
+ onSelectedSystemPromptChange();
+ closeFlyout();
+ }, [closeFlyout, handleSave, onSelectedSystemPromptChange]);
+
+ const columns = useMemo(
+ () => [
+ {
+ name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_NAME,
+ render: (prompt: Prompt) =>
+ prompt?.name ? (
+ onEditActionClicked(prompt)}>{prompt?.name}
+ ) : null,
+ },
+ {
+ field: 'defaultConversations',
+ name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_DEFAULT_CONVERSATIONS,
+ render: (defaultConversations: string[]) =>
+ defaultConversations.map((c, idx) => (
+
+ {c}
+
+ )),
+ },
+ {
+ field: 'createdAt',
+ name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_CREATED_ON,
+ },
+ {
+ name: 'Actions',
+ render: (prompt: Prompt) => {
+ return (
+
+ rowItem={prompt}
+ onEdit={onEditActionClicked}
+ onDelete={onDeleteActionClicked}
+ />
+ );
+ },
+ },
+ ],
+ [onEditActionClicked, onDeleteActionClicked]
+ );
+
+ const confirmationTitle = useMemo(
+ () =>
+ deletedPrompt?.name
+ ? i18n.DELETE_SYSTEM_PROMPT_MODAL_TITLE(deletedPrompt?.name)
+ : i18n.DELETE_SYSTEM_PROMPT_MODAL_DEFAULT_TITLE,
+ [deletedPrompt?.name]
+ );
+
+ const systemPromptListItems = useMemo(
+ () => getSystemPromptsList(systemPromptSettings, conversations),
+ [systemPromptSettings, conversations]
+ );
+ return (
+ <>
+
+
+
+
+ {SETTINGS_TITLE}
+
+
+
+
+
+
+
+
+
+ {deleteConfirmModalVisibility && deletedPrompt?.name && (
+
+ {i18n.DELETE_SYSTEM_PROMPT_MODAL_DESCRIPTION}
+
+ )}
+ >
+ );
+};
+
+export const SystemPromptSettingsManagement = React.memo(SystemPromptSettingsManagementComponent);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/translations.ts
new file mode 100644
index 0000000000000..b1ff676486954
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/translations.ts
@@ -0,0 +1,58 @@
+/*
+ * 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 SYSTEM_PROMPTS_TABLE_COLUMN_NAME = i18n.translate(
+ 'xpack.elasticAssistant.assistant.promptsTable.systemPromptsTableColumnName',
+ {
+ defaultMessage: 'Name',
+ }
+);
+
+export const SYSTEM_PROMPTS_TABLE_COLUMN_DEFAULT_CONVERSATIONS = i18n.translate(
+ 'xpack.elasticAssistant.assistant.promptsTable.systemPromptsTableColumnDefaultConversations',
+ {
+ defaultMessage: 'Default conversations',
+ }
+);
+
+export const SYSTEM_PROMPTS_TABLE_COLUMN_CREATED_ON = i18n.translate(
+ 'xpack.elasticAssistant.assistant.promptsTable.systemPromptsTableColumnCreatedOn',
+ {
+ defaultMessage: 'Created on',
+ }
+);
+
+export const SYSTEM_PROMPTS_TABLE_COLUMN_ACTIONS = i18n.translate(
+ 'xpack.elasticAssistant.assistant.promptsTable.systemPromptsTableColumnActions',
+ {
+ defaultMessage: 'Actions',
+ }
+);
+
+export const DELETE_SYSTEM_PROMPT_MODAL_TITLE = (prompt: string) =>
+ i18n.translate(
+ 'xpack.elasticAssistant.assistant.promptEditor.modal.deleteSystemPromptConfirmationTitle',
+ {
+ values: { prompt },
+ defaultMessage: 'Delete "{prompt}"?',
+ }
+ );
+
+export const DELETE_SYSTEM_PROMPT_MODAL_DEFAULT_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.promptEditor.modal.deleteSystemPromptConfirmationDefaultTitle',
+ {
+ defaultMessage: 'Delete system prompt?',
+ }
+);
+
+export const DELETE_SYSTEM_PROMPT_MODAL_DESCRIPTION = i18n.translate(
+ 'xpack.elasticAssistant.assistant.promptEditor.modal.deleteSystemPromptConfirmationMessage',
+ {
+ defaultMessage: 'You cannot recover the prompt once deleted',
+ }
+);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/quick_prompt_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/quick_prompt_editor.tsx
new file mode 100644
index 0000000000000..8a7e90a0f890b
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/quick_prompt_editor.tsx
@@ -0,0 +1,217 @@
+/*
+ * 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, { memo, useCallback, useMemo } from 'react';
+import { EuiFormRow, EuiColorPicker, EuiTextArea } from '@elastic/eui';
+
+import { EuiSetColorMethod } from '@elastic/eui/src/services/color_picker/color_picker';
+import { css } from '@emotion/react';
+import { PromptContextTemplate } from '../../../..';
+import * as i18n from './translations';
+import { QuickPrompt } from '../types';
+import { QuickPromptSelector } from '../quick_prompt_selector/quick_prompt_selector';
+import { PromptContextSelector } from '../prompt_context_selector/prompt_context_selector';
+import { useAssistantContext } from '../../../assistant_context';
+
+const DEFAULT_COLOR = '#D36086';
+
+interface Props {
+ onSelectedQuickPromptChange: (quickPrompt?: QuickPrompt) => void;
+ quickPromptSettings: QuickPrompt[];
+ selectedQuickPrompt: QuickPrompt | undefined;
+ setUpdatedQuickPromptSettings: React.Dispatch>;
+}
+
+const QuickPromptSettingsEditorComponent = ({
+ onSelectedQuickPromptChange,
+ quickPromptSettings,
+ selectedQuickPrompt,
+ setUpdatedQuickPromptSettings,
+}: Props) => {
+ const { basePromptContexts } = useAssistantContext();
+
+ // Prompt
+ const prompt = useMemo(() => selectedQuickPrompt?.prompt ?? '', [selectedQuickPrompt?.prompt]);
+
+ const handlePromptChange = useCallback(
+ (e: React.ChangeEvent) => {
+ if (selectedQuickPrompt != null) {
+ setUpdatedQuickPromptSettings((prev) => {
+ const alreadyExists = prev.some((qp) => qp.title === selectedQuickPrompt.title);
+
+ if (alreadyExists) {
+ return prev.map((qp) => {
+ if (qp.title === selectedQuickPrompt.title) {
+ return {
+ ...qp,
+ prompt: e.target.value,
+ };
+ }
+ return qp;
+ });
+ }
+
+ return prev;
+ });
+ }
+ },
+ [selectedQuickPrompt, setUpdatedQuickPromptSettings]
+ );
+
+ // Color
+ const selectedColor = useMemo(
+ () => selectedQuickPrompt?.color ?? DEFAULT_COLOR,
+ [selectedQuickPrompt?.color]
+ );
+
+ const handleColorChange = useCallback(
+ (color, { hex, isValid }) => {
+ if (selectedQuickPrompt != null) {
+ setUpdatedQuickPromptSettings((prev) => {
+ const alreadyExists = prev.some((qp) => qp.title === selectedQuickPrompt.title);
+
+ if (alreadyExists) {
+ return prev.map((qp) => {
+ if (qp.title === selectedQuickPrompt.title) {
+ return {
+ ...qp,
+ color,
+ };
+ }
+ return qp;
+ });
+ }
+ return prev;
+ });
+ }
+ },
+ [selectedQuickPrompt, setUpdatedQuickPromptSettings]
+ );
+
+ // Prompt Contexts
+ const selectedPromptContexts = useMemo(
+ () =>
+ basePromptContexts.filter((bpc) =>
+ selectedQuickPrompt?.categories?.some((cat) => bpc?.category === cat)
+ ) ?? [],
+ [basePromptContexts, selectedQuickPrompt?.categories]
+ );
+
+ const onPromptContextSelectionChange = useCallback(
+ (pc: PromptContextTemplate[]) => {
+ if (selectedQuickPrompt != null) {
+ setUpdatedQuickPromptSettings((prev) => {
+ const alreadyExists = prev.some((qp) => qp.title === selectedQuickPrompt.title);
+
+ if (alreadyExists) {
+ return prev.map((qp) => {
+ if (qp.title === selectedQuickPrompt.title) {
+ return {
+ ...qp,
+ categories: pc.map((p) => p.category),
+ };
+ }
+ return qp;
+ });
+ }
+ return prev;
+ });
+ }
+ },
+ [selectedQuickPrompt, setUpdatedQuickPromptSettings]
+ );
+
+ // When top level quick prompt selection changes
+ const onQuickPromptSelectionChange = useCallback(
+ (quickPrompt?: QuickPrompt | string) => {
+ const isNew = typeof quickPrompt === 'string';
+ const newSelectedQuickPrompt: QuickPrompt | undefined = isNew
+ ? {
+ title: quickPrompt ?? '',
+ prompt: '',
+ color: DEFAULT_COLOR,
+ categories: [],
+ }
+ : quickPrompt;
+
+ if (newSelectedQuickPrompt != null) {
+ setUpdatedQuickPromptSettings((prev) => {
+ const alreadyExists = prev.some((qp) => qp.title === newSelectedQuickPrompt.title);
+
+ if (!alreadyExists) {
+ return [...prev, newSelectedQuickPrompt];
+ }
+
+ return prev;
+ });
+ }
+
+ onSelectedQuickPromptChange(newSelectedQuickPrompt);
+ },
+ [onSelectedQuickPromptChange, setUpdatedQuickPromptSettings]
+ );
+
+ const onQuickPromptDeleted = useCallback(
+ (title: string) => {
+ setUpdatedQuickPromptSettings((prev) => prev.filter((qp) => qp.title !== title));
+ },
+ [setUpdatedQuickPromptSettings]
+ );
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+export const QuickPromptSettingsEditor = memo(QuickPromptSettingsEditorComponent);
+
+QuickPromptSettingsEditor.displayName = 'QuickPromptSettingsEditor';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/quick_prompt_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/quick_prompt_settings.tsx
index 38bbb0e6899be..4b8b6a8f8039d 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/quick_prompt_settings.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/quick_prompt_settings.tsx
@@ -5,27 +5,12 @@
* 2.0.
*/
-import React, { useCallback, useMemo } from 'react';
-import {
- EuiFormRow,
- EuiColorPicker,
- EuiTextArea,
- EuiTitle,
- EuiText,
- EuiHorizontalRule,
- EuiSpacer,
-} from '@elastic/eui';
+import React from 'react';
+import { EuiTitle, EuiText, EuiHorizontalRule, EuiSpacer } from '@elastic/eui';
-import { EuiSetColorMethod } from '@elastic/eui/src/services/color_picker/color_picker';
-import { css } from '@emotion/react';
-import { PromptContextTemplate } from '../../../..';
import * as i18n from './translations';
import { QuickPrompt } from '../types';
-import { QuickPromptSelector } from '../quick_prompt_selector/quick_prompt_selector';
-import { PromptContextSelector } from '../prompt_context_selector/prompt_context_selector';
-import { useAssistantContext } from '../../../assistant_context';
-
-const DEFAULT_COLOR = '#D36086';
+import { QuickPromptSettingsEditor } from './quick_prompt_editor';
interface Props {
onSelectedQuickPromptChange: (quickPrompt?: QuickPrompt) => void;
@@ -44,136 +29,6 @@ export const QuickPromptSettings: React.FC = React.memo(
selectedQuickPrompt,
setUpdatedQuickPromptSettings,
}) => {
- const { basePromptContexts } = useAssistantContext();
-
- // Prompt
- const prompt = useMemo(() => selectedQuickPrompt?.prompt ?? '', [selectedQuickPrompt?.prompt]);
-
- const handlePromptChange = useCallback(
- (e: React.ChangeEvent) => {
- if (selectedQuickPrompt != null) {
- setUpdatedQuickPromptSettings((prev) => {
- const alreadyExists = prev.some((qp) => qp.title === selectedQuickPrompt.title);
-
- if (alreadyExists) {
- return prev.map((qp) => {
- if (qp.title === selectedQuickPrompt.title) {
- return {
- ...qp,
- prompt: e.target.value,
- };
- }
- return qp;
- });
- }
-
- return prev;
- });
- }
- },
- [selectedQuickPrompt, setUpdatedQuickPromptSettings]
- );
-
- // Color
- const selectedColor = useMemo(
- () => selectedQuickPrompt?.color ?? DEFAULT_COLOR,
- [selectedQuickPrompt?.color]
- );
-
- const handleColorChange = useCallback(
- (color, { hex, isValid }) => {
- if (selectedQuickPrompt != null) {
- setUpdatedQuickPromptSettings((prev) => {
- const alreadyExists = prev.some((qp) => qp.title === selectedQuickPrompt.title);
-
- if (alreadyExists) {
- return prev.map((qp) => {
- if (qp.title === selectedQuickPrompt.title) {
- return {
- ...qp,
- color,
- };
- }
- return qp;
- });
- }
- return prev;
- });
- }
- },
- [selectedQuickPrompt, setUpdatedQuickPromptSettings]
- );
-
- // Prompt Contexts
- const selectedPromptContexts = useMemo(
- () =>
- basePromptContexts.filter((bpc) =>
- selectedQuickPrompt?.categories?.some((cat) => bpc?.category === cat)
- ) ?? [],
- [basePromptContexts, selectedQuickPrompt?.categories]
- );
-
- const onPromptContextSelectionChange = useCallback(
- (pc: PromptContextTemplate[]) => {
- if (selectedQuickPrompt != null) {
- setUpdatedQuickPromptSettings((prev) => {
- const alreadyExists = prev.some((qp) => qp.title === selectedQuickPrompt.title);
-
- if (alreadyExists) {
- return prev.map((qp) => {
- if (qp.title === selectedQuickPrompt.title) {
- return {
- ...qp,
- categories: pc.map((p) => p.category),
- };
- }
- return qp;
- });
- }
- return prev;
- });
- }
- },
- [selectedQuickPrompt, setUpdatedQuickPromptSettings]
- );
-
- // When top level quick prompt selection changes
- const onQuickPromptSelectionChange = useCallback(
- (quickPrompt?: QuickPrompt | string) => {
- const isNew = typeof quickPrompt === 'string';
- const newSelectedQuickPrompt: QuickPrompt | undefined = isNew
- ? {
- title: quickPrompt ?? '',
- prompt: '',
- color: DEFAULT_COLOR,
- categories: [],
- }
- : quickPrompt;
-
- if (newSelectedQuickPrompt != null) {
- setUpdatedQuickPromptSettings((prev) => {
- const alreadyExists = prev.some((qp) => qp.title === newSelectedQuickPrompt.title);
-
- if (!alreadyExists) {
- return [...prev, newSelectedQuickPrompt];
- }
-
- return prev;
- });
- }
-
- onSelectedQuickPromptChange(newSelectedQuickPrompt);
- },
- [onSelectedQuickPromptChange, setUpdatedQuickPromptSettings]
- );
-
- const onQuickPromptDeleted = useCallback(
- (title: string) => {
- setUpdatedQuickPromptSettings((prev) => prev.filter((qp) => qp.title !== title));
- },
- [setUpdatedQuickPromptSettings]
- );
-
return (
<>
@@ -183,52 +38,12 @@ export const QuickPromptSettings: React.FC = React.memo(
{i18n.SETTINGS_DESCRIPTION}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
>
);
}
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/helpers.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/helpers.ts
new file mode 100644
index 0000000000000..294527b5d8191
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/helpers.ts
@@ -0,0 +1,31 @@
+/*
+ * 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 { Conversation } from '../../../..';
+import { Prompt } from '../../types';
+
+export const getSelectedConversations = (
+ conversationSettings: Record,
+ systemPromptId: string
+) =>
+ Object.values(conversationSettings).filter(
+ (conversation) => conversation.apiConfig?.defaultSystemPromptId === systemPromptId
+ );
+
+export const getSystemPromptsList = (
+ systemPromptSettings: Prompt[],
+ conversationSettings: Record
+): Array => {
+ return systemPromptSettings.map((systemPrompt) => {
+ return {
+ ...systemPrompt,
+ defaultConversations: getSelectedConversations(conversationSettings, systemPrompt.id).map(
+ ({ title }) => title
+ ),
+ };
+ });
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
index 9ddd43d8d90df..01bdf5fd749b0 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
@@ -4,24 +4,172 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
-import React from 'react';
-import { EuiInMemoryTable } from '@elastic/eui';
+import React, { useCallback, useMemo, useState } from 'react';
+import {
+ EuiBasicTableColumn,
+ EuiButton,
+ EuiConfirmModal,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiInMemoryTable,
+ EuiLink,
+ EuiPanel,
+} from '@elastic/eui';
import { QuickPrompt } from '../types';
+import { RowActions } from '../../common/components/assisttant_settings_management/row_actions';
+import { QuickPromptSettingsEditor } from '../quick_prompt_settings/quick_prompt_editor';
+import * as i18n from './translations';
+import { useFlyoutModalVisibility } from '../../common/components/assisttant_settings_management/flyout/use_flyout_modal_visibility';
+import { Flyout } from '../../common/components/assisttant_settings_management/flyout';
+import { CANCEL, DELETE } from '../../settings/translations';
interface Props {
- quickPrompts: QuickPrompt[];
+ onSelectedQuickPromptChange: (quickPrompt?: QuickPrompt) => void;
+ quickPromptSettings: QuickPrompt[];
+ selectedQuickPrompt: QuickPrompt | undefined;
+ setUpdatedQuickPromptSettings: React.Dispatch>;
+ handleSave: () => void;
+ resetSettings: () => void;
}
-const QuickPromptSettingsManagementComponent = ({quickPrompts}: Props) => {
- cosnt columns = [
- {
- field: 'title',
- name: 'Title',
- }
- ];
+const QuickPromptSettingsManagementComponent = ({
+ onSelectedQuickPromptChange,
+ quickPromptSettings,
+ selectedQuickPrompt,
+ setUpdatedQuickPromptSettings,
+ handleSave,
+ resetSettings,
+}: Props) => {
+ const { isFlyoutOpen: editFlyoutVisible, openFlyout, closeFlyout } = useFlyoutModalVisibility();
+ const [deletedQuickPrompt, setDeletedQuickPrompt] = useState();
+ const {
+ isFlyoutOpen: deleteConfirmModalVisibility,
+ openFlyout: openConfirmModal,
+ closeFlyout: closeConfirmModal,
+ } = useFlyoutModalVisibility();
+
+ const onEditActionClicked = useCallback(
+ (prompt: QuickPrompt) => {
+ onSelectedQuickPromptChange(prompt);
+ openFlyout();
+ },
+ [onSelectedQuickPromptChange, openFlyout]
+ );
+
+ const onDeleteActionClicked = useCallback(
+ (prompt: QuickPrompt) => {
+ setDeletedQuickPrompt(prompt);
+ openConfirmModal();
+ },
+ [openConfirmModal]
+ );
+
+ const onDeleteCancelled = useCallback(() => {
+ setDeletedQuickPrompt(null);
+ closeConfirmModal();
+ }, [closeConfirmModal]);
+
+ const onDeleteConfirmed = useCallback(() => {
+ setUpdatedQuickPromptSettings((prev) =>
+ prev.filter((p) => p.title !== deletedQuickPrompt?.title)
+ );
+ handleSave();
+ closeConfirmModal();
+ }, [closeConfirmModal, deletedQuickPrompt?.title, handleSave, setUpdatedQuickPromptSettings]);
+
+ const onCreate = useCallback(() => {
+ onSelectedQuickPromptChange();
+ openFlyout();
+ }, [onSelectedQuickPromptChange, openFlyout]);
+
+ const onCancel = useCallback(() => {
+ onSelectedQuickPromptChange();
+ closeFlyout();
+ resetSettings();
+ }, [closeFlyout, onSelectedQuickPromptChange, resetSettings]);
+
+ const onSave = useCallback(() => {
+ handleSave();
+ onSelectedQuickPromptChange();
+ closeFlyout();
+ }, [closeFlyout, handleSave, onSelectedQuickPromptChange]);
+
+ const columns: Array> = useMemo(
+ () => [
+ {
+ name: i18n.QUICK_PROMPTS_TABLE_COLUMN_NAME,
+ render: (prompt: QuickPrompt) =>
+ prompt?.title ? (
+ onEditActionClicked(prompt)}>{prompt?.title}
+ ) : null,
+ },
+ {
+ field: 'createdAt',
+ name: i18n.QUICK_PROMPTS_TABLE_COLUMN_CREATED_AT,
+ },
+ {
+ name: i18n.QUICK_PROMPTS_TABLE_COLUMN_ACTIONS,
+ render: (prompt: QuickPrompt) => {
+ return (
+
+ rowItem={prompt}
+ onDelete={onDeleteActionClicked}
+ onEdit={onEditActionClicked}
+ />
+ );
+ },
+ },
+ ],
+ [onDeleteActionClicked, onEditActionClicked]
+ );
+
+ const confirmationTitle = useMemo(
+ () =>
+ deletedQuickPrompt?.title
+ ? i18n.DELETE_QUICK_PROMPT_MODAL_TITLE(deletedQuickPrompt.title)
+ : i18n.DELETE_QUICK_PROMPT_MODAL_DEFAULT_TITLE,
+ [deletedQuickPrompt?.title]
+ );
return (
-
-
-
+ <>
+
+
+
+
+ {i18n.QUICK_PROMPTS_TABLE_CREATE_BUTTON_TITLE}
+
+
+
+
+
+
+
+
+ {deleteConfirmModalVisibility && deletedQuickPrompt && (
+
+ {i18n.DELETE_QUICK_PROMPT_MODAL_DESCRIPTION}
+
+ )}
+ >
);
};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/translations.ts
new file mode 100644
index 0000000000000..be24863d2aec1
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/translations.ts
@@ -0,0 +1,65 @@
+/*
+ * 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 QUICK_PROMPTS_TABLE_COLUMN_NAME = i18n.translate(
+ 'xpack.elasticAssistant.assistant.quickPromptsTable.quickPromptsTableColumnName',
+ {
+ defaultMessage: 'Name',
+ }
+);
+
+export const QUICK_PROMPTS_TABLE_COLUMN_CREATED_AT = i18n.translate(
+ 'xpack.elasticAssistant.assistant.quickPromptsTable.quickPromptsTableColumnCreatedAt',
+ {
+ defaultMessage: 'Created at',
+ }
+);
+
+export const QUICK_PROMPTS_TABLE_COLUMN_ACTIONS = i18n.translate(
+ 'xpack.elasticAssistant.assistant.quickPromptsTable.quickPromptsTableColumnActions',
+ {
+ defaultMessage: 'Actions',
+ }
+);
+
+export const QUICK_PROMPTS_TABLE_CREATE_BUTTON_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.quickPromptsTable.createButtonTitle',
+ {
+ defaultMessage: 'Quick Prompt',
+ }
+);
+
+export const QUICK_PROMPT_EDIT_FLYOUT_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.quickPromptEditFlyout.title',
+ {
+ defaultMessage: 'Quick Prompt',
+ }
+);
+
+export const DELETE_QUICK_PROMPT_MODAL_TITLE = (prompt: string) =>
+ i18n.translate(
+ 'xpack.elasticAssistant.assistant.quickPromptsTable.modal.deleteQuickPromptConfirmationTitle',
+ {
+ values: { prompt },
+ defaultMessage: 'Delete "{prompt}"?',
+ }
+ );
+
+export const DELETE_QUICK_PROMPT_MODAL_DEFAULT_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.quickPromptsTable.modal.deleteQuickPromptConfirmationDefaultTitle',
+ {
+ defaultMessage: 'Delete quick prompt?',
+ }
+);
+
+export const DELETE_QUICK_PROMPT_MODAL_DESCRIPTION = i18n.translate(
+ 'xpack.elasticAssistant.assistant.quickPromptsTable.modal.deleteQuickPromptConfirmationMessage',
+ {
+ defaultMessage: 'You cannot recover the prompt once deleted',
+ }
+);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
index 0a526b18aeb87..2664f01805bf7 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
@@ -6,31 +6,22 @@
*/
import React, { useCallback, useEffect, useMemo, useState } from 'react';
-import {
- EuiButton,
- EuiButtonEmpty,
- EuiFlexItem,
- EuiPageTemplate,
- EuiFlexGroup,
-} from '@elastic/eui';
+import { EuiPageTemplate } from '@elastic/eui';
import { css } from '@emotion/react';
import { Conversation, Prompt, QuickPrompt } from '../../..';
import * as i18n from './translations';
import { useAssistantContext } from '../../assistant_context';
import { useSettingsUpdater } from './use_settings_updater/use_settings_updater';
-import {
- AnonymizationSettings,
- EvaluationSettings,
- KnowledgeBaseSettings,
- QuickPromptSettings,
- SystemPromptSettings,
-} from '.';
+import { EvaluationSettings, KnowledgeBaseSettings } from '.';
import { useLoadConnectors } from '../../connectorland/use_load_connectors';
import { getDefaultConnector } from '../helpers';
import { useFetchAnonymizationFields } from '../api/anonymization_fields/use_fetch_anonymization_fields';
-import { ConnectorsSettings } from '../../connectorland/connector_settings';
+import { ConnectorsSettingsManagement } from '../../connectorland/connector_settings_management';
import { ConversationSettingsManagement } from '../conversations/converstaion_settings_management';
+import { QuickPromptSettingsManagement } from '../quick_prompts/quick_prompt_settings_management.tsx';
+import { SystemPromptSettingsManagement } from '../prompt_editor/system_prompt/system_prompt_settings_management';
+import { AnonymizationSettingsManagement } from '../../data_anonymization/settings/anonomization_settings_management';
export const CONNECTORS_TAB = 'CONNECTORS_TAB' as const;
export const CONVERSATIONS_TAB = 'CONVERSATION_TAB' as const;
@@ -45,6 +36,7 @@ interface Props {
selectedConversation: Conversation;
setSelectedConversationId: React.Dispatch>;
isFlyoutMode: boolean;
+ refetchConversations: () => void;
}
/**
@@ -57,11 +49,13 @@ export const AssistantSettingsManagement: React.FC = React.memo(
setSelectedConversationId,
conversations,
isFlyoutMode,
+ refetchConversations,
}) => {
const {
actionTypeRegistry,
assistantFeatures: { assistantModelEvaluation: modelEvaluatorEnabled },
http,
+ navigateToApp,
selectedSettingsTab,
setSelectedSettingsTab,
toasts,
@@ -70,11 +64,7 @@ export const AssistantSettingsManagement: React.FC = React.memo(
const { data: anonymizationFields } = useFetchAnonymizationFields();
// Connector details
- const {
- data: connectors,
- refetch: refetchConnectors,
- isFetchedAfterMount: areConnectorsFetched,
- } = useLoadConnectors({
+ const { data: connectors } = useLoadConnectors({
http,
});
const defaultConnector = useMemo(() => getDefaultConnector(connectors), [connectors]);
@@ -113,6 +103,10 @@ export const AssistantSettingsManagement: React.FC = React.memo(
}
);
+ const onHandleSelectedConversationChange = useCallback((conversation?: Conversation) => {
+ setSelectedConversation(conversation);
+ }, []);
+
useEffect(() => {
if (selectedConversation != null) {
setSelectedConversation(conversationSettings[selectedConversation.title]);
@@ -246,57 +240,59 @@ export const AssistantSettingsManagement: React.FC = React.memo(
`}
>
{selectedSettingsTab === CONNECTORS_TAB && (
-
+
)}
{selectedSettingsTab === CONVERSATIONS_TAB && (
- )}
- {selectedSettingsTab === QUICK_PROMPTS_TAB && (
-
)}
{selectedSettingsTab === SYSTEM_PROMPTS_TAB && (
-
+ )}
+ {selectedSettingsTab === QUICK_PROMPTS_TAB && (
+
)}
{selectedSettingsTab === ANONYMIZATION_TAB && (
- = React.memo(
)}
{selectedSettingsTab === EVALUATION_TAB && }
- {hasPendingChanges && (
+ {/* {hasPendingChanges && (
@@ -340,7 +336,7 @@ export const AssistantSettingsManagement: React.FC = React.memo(
- )}
+ )} */}
>
);
}
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/translations.ts
index 6acd07beb7772..a8c2c85941176 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/translations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/translations.ts
@@ -104,3 +104,10 @@ export const SAVE = i18n.translate(
defaultMessage: 'Save',
}
);
+
+export const DELETE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.promptEditor.systemPrompt.slDeleteButtonTitle',
+ {
+ defaultMessage: 'Delete',
+ }
+);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx
index a9a949073a4f2..68a1e426be7a0 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx
@@ -10,14 +10,11 @@ import type { HttpSetup } from '@kbn/core-http-browser';
import { omit } from 'lodash/fp';
import React, { useCallback, useMemo, useState } from 'react';
import type { IToasts } from '@kbn/core-notifications-browser';
-import {
- ActionTypeRegistryContract,
- TriggersAndActionsUIPublicPluginStart,
-} from '@kbn/triggers-actions-ui-plugin/public';
+import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public';
import { useLocalStorage, useSessionStorage } from 'react-use';
import type { DocLinksStart } from '@kbn/core-doc-links-browser';
import { AssistantFeatures, defaultAssistantFeatures } from '@kbn/elastic-assistant-common';
-import { SettingsStart } from '@kbn/core-ui-settings-browser';
+import { NavigateToAppOptions } from '@kbn/core/public';
import { updatePromptContexts } from './helpers';
import type {
PromptContext,
@@ -72,9 +69,6 @@ export interface AssistantProviderProps {
baseSystemPrompts?: Prompt[];
docLinks: Omit;
children: React.ReactNode;
- getAddConnectorFlyout: TriggersAndActionsUIPublicPluginStart['getAddConnectorFlyout'];
- getDeleteConnectorModalConfirmation: TriggersAndActionsUIPublicPluginStart['getDeleteConnectorModalConfirmation'];
- getEditConnectorFlyout: TriggersAndActionsUIPublicPluginStart['getEditConnectorFlyout'];
getComments: (commentArgs: {
abortStream: () => void;
currentConversation?: Conversation;
@@ -90,7 +84,7 @@ export interface AssistantProviderProps {
http: HttpSetup;
baseConversations: Record;
nameSpace?: string;
- settings: SettingsStart;
+ navigateToApp: (appId: string, options?: NavigateToAppOptions | undefined) => Promise;
title?: string;
toasts?: IToasts;
}
@@ -120,7 +114,6 @@ export interface UseAssistantContext {
baseQuickPrompts: QuickPrompt[];
baseSystemPrompts: Prompt[];
baseConversations: Record;
- getEditConnectorFlyout: TriggersAndActionsUIPublicPluginStart['getEditConnectorFlyout'];
getComments: (commentArgs: {
abortStream: () => void;
currentConversation?: Conversation;
@@ -133,11 +126,11 @@ export interface UseAssistantContext {
setIsStreaming: (isStreaming: boolean) => void;
isFlyoutMode: boolean;
}) => EuiCommentProps[];
- getDeleteConnectorModalConfirmation: TriggersAndActionsUIPublicPluginStart['getDeleteConnectorModalConfirmation'];
http: HttpSetup;
knowledgeBase: KnowledgeBaseConfig;
getLastConversationId: (conversationTitle?: string) => string;
promptContexts: Record;
+ navigateToApp: (appId: string, options?: NavigateToAppOptions | undefined) => Promise;
nameSpace: string;
registerPromptContext: RegisterPromptContext;
selectedSettingsTab: SettingsTabs | null;
@@ -149,7 +142,6 @@ export interface UseAssistantContext {
setSelectedSettingsTab: React.Dispatch>;
setShowAssistantOverlay: (showAssistantOverlay: ShowAssistantOverlay) => void;
showAssistantOverlay: ShowAssistantOverlay;
- settings: SettingsStart;
setTraceOptions: (traceOptions: {
apmUrl: string;
langSmithProject: string;
@@ -175,14 +167,11 @@ export const AssistantProvider: React.FC = ({
baseQuickPrompts = [],
baseSystemPrompts = BASE_SYSTEM_PROMPTS,
children,
- getAddConnectorFlyout,
- getDeleteConnectorModalConfirmation,
- getEditConnectorFlyout,
getComments,
http,
baseConversations,
+ navigateToApp,
nameSpace = DEFAULT_ASSISTANT_NAMESPACE,
- settings,
title = DEFAULT_ASSISTANT_TITLE,
toasts,
}) => {
@@ -308,13 +297,11 @@ export const AssistantProvider: React.FC = ({
baseQuickPrompts,
baseSystemPrompts,
docLinks,
- getAddConnectorFlyout,
- getEditConnectorFlyout,
- getDeleteConnectorModalConfirmation,
getComments,
http,
knowledgeBase: { ...DEFAULT_KNOWLEDGE_BASE_SETTINGS, ...localStorageKnowledgeBase },
promptContexts,
+ navigateToApp,
nameSpace,
registerPromptContext,
selectedSettingsTab,
@@ -326,7 +313,6 @@ export const AssistantProvider: React.FC = ({
setKnowledgeBase: setLocalStorageKnowledgeBase,
setSelectedSettingsTab,
setShowAssistantOverlay,
- settings,
setTraceOptions: setSessionStorageTraceOptions,
showAssistantOverlay,
title,
@@ -351,13 +337,11 @@ export const AssistantProvider: React.FC = ({
baseQuickPrompts,
baseSystemPrompts,
docLinks,
- getAddConnectorFlyout,
- getEditConnectorFlyout,
- getDeleteConnectorModalConfirmation,
getComments,
http,
localStorageKnowledgeBase,
promptContexts,
+ navigateToApp,
nameSpace,
registerPromptContext,
selectedSettingsTab,
@@ -366,7 +350,6 @@ export const AssistantProvider: React.FC = ({
setLocalStorageQuickPrompts,
setLocalStorageSystemPrompts,
setLocalStorageKnowledgeBase,
- settings,
setSessionStorageTraceOptions,
showAssistantOverlay,
title,
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx
deleted file mode 100644
index 9a2b4824a3ba0..0000000000000
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/index.tsx
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * 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 { EuiCallOut, EuiInMemoryTable, EuiPanel, EuiSkeletonText } from '@elastic/eui';
-import React, { Suspense, useCallback, useMemo, useState } from 'react';
-import { ActionType } from '@kbn/triggers-actions-ui-plugin/public';
-import type { IHttpFetchError } from '@kbn/core-http-browser';
-
-import { UseQueryResult } from '@tanstack/react-query';
-import { useAssistantContext } from '../../assistant_context';
-import { AIConnector } from '../connector_selector';
-
-import {
- DELETE_CONNECTOR_CONFIRMATION_MULTIPLE_TITLE,
- DELETE_CONNECTOR_CONFIRMATION_SINGLE_TITLE,
- MISSING_READ_CONNECTORS_CALLOUT_TITLE,
-} from '../translations';
-
-import { useLoadActionTypes } from '../use_load_action_types';
-import { AddConnectorModal } from '../add_connector_modal';
-import { ActionConnectorTableItem } from './types';
-import { deleteActions } from '../helpers';
-import { useConnectorTable } from './use_connector_table';
-
-interface Props {
- connectors: AIConnector[] | undefined;
- refetchConnectors: UseQueryResult['refetch'];
- areConnectorsFetched: boolean;
-}
-
-const emptyConnectors = [] as ActionConnectorTableItem[];
-
-const ConnectorsSettingsComponent: React.FC = ({
- connectors: aiConnectors,
- refetchConnectors,
- areConnectorsFetched,
-}) => {
- const {
- actionTypeRegistry,
- http,
- assistantAvailability,
- getEditConnectorFlyout,
- getDeleteConnectorModalConfirmation,
- } = useAssistantContext();
-
- const { data: actionTypes } = useLoadActionTypes({ http });
-
- // Edit Connector
- const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false);
-
- const handleCloseEditFlyout = useCallback(() => {
- setEditFlyoutVisibility(false);
- }, []);
- const [editedConnectorItem, setEditedConnectorItem] = useState(null);
-
- // Add Connector
-
- const [isAddConnectorModalVisible, setIsAddConnectorModalVisible] = useState(false);
-
- const [selectedActionType, setSelectedActionType] = useState(null);
-
- const onSaveConnector = useCallback(() => {
- refetchConnectors?.();
- }, [refetchConnectors]);
-
- const handleAddConnector = useCallback(() => {
- handleCloseEditFlyout();
- setIsAddConnectorModalVisible(true);
- }, [handleCloseEditFlyout]);
-
- const onEditConnector = useCallback((connector: ActionConnectorTableItem) => {
- setIsAddConnectorModalVisible(false);
- setEditedConnectorItem(connector);
- setEditFlyoutVisibility(true);
- }, []);
-
- // delete
-
- const [connectorsToDelete, setConnectorsToDelete] = useState([]);
-
- const onDeleteConnector = useCallback((connector: ActionConnectorTableItem) => {
- const itemIds = [connector.id];
- setConnectorsToDelete(itemIds);
- }, []);
-
- const DeleteConnectorModalConfirmation = useMemo(
- () =>
- getDeleteConnectorModalConfirmation({
- idsToDelete: connectorsToDelete,
- apiDeleteCall: deleteActions,
- onDeleted: (deleted: string[]) => {
- refetchConnectors();
- },
- onCancel: () => {
- setConnectorsToDelete([]);
- },
- onErrors: () => {
- setConnectorsToDelete([]);
- },
- singleTitle: DELETE_CONNECTOR_CONFIRMATION_SINGLE_TITLE,
- multipleTitle: DELETE_CONNECTOR_CONFIRMATION_MULTIPLE_TITLE,
- setIsLoadingState: () => {},
- }),
- [connectorsToDelete, getDeleteConnectorModalConfirmation, refetchConnectors]
- );
-
- const onConnectorUpdated = useCallback(
- async (updatedConnector) => {
- setEditedConnectorItem(updatedConnector);
- refetchConnectors();
- handleCloseEditFlyout();
- },
- [handleCloseEditFlyout, refetchConnectors]
- );
-
- const ConnectorEditFlyout = useMemo(
- () =>
- editedConnectorItem && editFlyoutVisible
- ? getEditConnectorFlyout({
- connector: editedConnectorItem,
- onClose: handleCloseEditFlyout,
- onConnectorUpdated,
- })
- : null,
- [
- editFlyoutVisible,
- editedConnectorItem,
- getEditConnectorFlyout,
- handleCloseEditFlyout,
- onConnectorUpdated,
- ]
- );
-
- const { search, columns, aiConnectorTableItems } = useConnectorTable({
- actionTypes,
- actionTypeRegistry,
- aiConnectors,
- areConnectorsFetched,
- hasConnectorsAllPrivilege: assistantAvailability.hasConnectorsAllPrivilege,
- refetchConnectors,
- handleAddConnector,
- onEditConnector,
- onDeleteConnector,
- });
-
- if (!assistantAvailability.hasConnectorsReadPrivilege) {
- return (
-
- );
- }
-
- return areConnectorsFetched ? (
-
- {DeleteConnectorModalConfirmation}
-
- {ConnectorEditFlyout}
- {isAddConnectorModalVisible && (
- // Crashing management app otherwise
-
- setIsAddConnectorModalVisible(false)}
- onSaveConnector={onSaveConnector}
- onSelectActionType={(actionType: ActionType) => setSelectedActionType(actionType)}
- selectedActionType={selectedActionType}
- />
-
- )}
-
- ) : (
-
- );
-};
-
-export const ConnectorsSettings = React.memo(ConnectorsSettingsComponent);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/types.ts b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/types.ts
deleted file mode 100644
index ba613134b90ec..0000000000000
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/types.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * 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 { AIConnector } from '../connector_selector';
-
-export type ActionConnectorTableItem = AIConnector & {
- actionType: string;
- compatibility: string[];
-};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/use_connector_table.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/use_connector_table.tsx
deleted file mode 100644
index 9ea7412e598da..0000000000000
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings/use_connector_table.tsx
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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 {
- EuiBadge,
- EuiBasicTableColumn,
- EuiButton,
- EuiFlexGroup,
- EuiFlexItem,
- EuiLink,
- EuiSearchBarProps,
-} from '@elastic/eui';
-import React, { useState, useMemo } from 'react';
-import { ActionType, ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public';
-import { getConnectorCompatibility } from '@kbn/actions-plugin/common';
-import { RowActions } from '../../assistant/common/components/row_actions';
-import { AIConnector } from '../connector_selector';
-import { getActionTypeTitle, getGenAiConfig } from '../helpers';
-import {
- CONNECTORS_TABLE_COLUMN_ACTIONS,
- CONNECTORS_TABLE_COLUMN_ACTION_TYPE,
- CONNECTORS_TABLE_COLUMN_COMPATIBILITY,
- CONNECTORS_TABLE_COLUMN_NAME,
- CREATE_CONNECTOR_BUTTON,
- PRECONFIGURED_CONNECTOR,
- REFRESH_CONNECTORS_BUTTON,
- SEARCH_CONNECTOR_PLACEHOLDER,
-} from '../translations';
-import { ActionConnectorTableItem } from './types';
-
-interface Props {
- actionTypes: ActionType[] | undefined;
- actionTypeRegistry: ActionTypeRegistryContract;
- aiConnectors: AIConnector[] | undefined;
- areConnectorsFetched: boolean;
- hasConnectorsAllPrivilege: boolean;
- refetchConnectors: () => void;
- handleAddConnector: () => void;
- onEditConnector: (connector: ActionConnectorTableItem) => void;
- onDeleteConnector: (connector: ActionConnectorTableItem) => void;
-}
-export const useConnectorTable = ({
- actionTypes,
- actionTypeRegistry,
- aiConnectors,
- areConnectorsFetched,
- hasConnectorsAllPrivilege,
- refetchConnectors,
- handleAddConnector,
- onEditConnector,
- onDeleteConnector,
-}: Props) => {
- const [query, setQuery] = useState('');
-
- const handleOnChange: EuiSearchBarProps['onChange'] = ({ queryText, error }) => {
- if (!error) {
- setQuery(queryText);
- }
- };
-
- const search: EuiSearchBarProps = useMemo(
- () => ({
- query,
- onChange: handleOnChange,
- box: {
- schema: true,
- placeholder: SEARCH_CONNECTOR_PLACEHOLDER,
- },
- toolsRight: [
-
- {REFRESH_CONNECTORS_BUTTON}
- ,
-
- {CREATE_CONNECTOR_BUTTON}
- ,
- ],
- }),
- [areConnectorsFetched, hasConnectorsAllPrivilege, handleAddConnector, refetchConnectors, query]
- );
-
- const columns: Array> = useMemo(
- () => [
- {
- name: CONNECTORS_TABLE_COLUMN_NAME,
- truncateText: false,
- mobileOptions: {
- show: true,
- },
- render: (connector: ActionConnectorTableItem) => (
- onEditConnector(connector)}>{connector.name}
- ),
- },
- {
- field: 'actionType',
- name: CONNECTORS_TABLE_COLUMN_ACTION_TYPE,
- truncateText: false,
- mobileOptions: {
- show: true,
- },
- render: (actionType: ActionConnectorTableItem['actionType']) =>
- actionType ? {actionType} : null,
- },
- {
- name: CONNECTORS_TABLE_COLUMN_COMPATIBILITY,
- truncateText: true,
- mobileOptions: {
- show: true,
- },
- render: (tableItem: ActionConnectorTableItem) => {
- return (
-
- {tableItem?.compatibility?.map((compatibilityItem: string) => (
-
-
- {compatibilityItem}
-
-
- ))}
-
- );
- },
- },
- {
- name: CONNECTORS_TABLE_COLUMN_ACTIONS,
- actions: [
- {
- name: CONNECTORS_TABLE_COLUMN_ACTIONS,
- render: (connector: ActionConnectorTableItem) => {
- return (
-
- rowItem={connector}
- onEdit={onEditConnector}
- onDelete={onDeleteConnector}
- />
- );
- },
- },
- ],
- },
- ],
- [onDeleteConnector, onEditConnector]
- );
-
- const aiConnectorTableItems: ActionConnectorTableItem[] | undefined = areConnectorsFetched
- ? (aiConnectors ?? []).map((connector) => {
- const currentActionType = actionTypes?.find(
- (actionType) => actionType.id === connector.actionTypeId
- );
-
- const connectorTypeTitle =
- getGenAiConfig(connector)?.apiProvider ??
- getActionTypeTitle(actionTypeRegistry.get(connector.actionTypeId));
- const actionType = connector.isPreconfigured ? PRECONFIGURED_CONNECTOR : connectorTypeTitle;
- return {
- ...connector,
- actionType,
- compatibility: currentActionType
- ? getConnectorCompatibility(currentActionType.supportedFeatureIds)
- : [],
- };
- })
- : undefined;
-
- return { search, columns, aiConnectorTableItems };
-};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/index.tsx
new file mode 100644
index 0000000000000..34dd24e80c99f
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/index.tsx
@@ -0,0 +1,57 @@
+/*
+ * 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,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiPanel,
+ EuiSpacer,
+ EuiText,
+ EuiTitle,
+} from '@elastic/eui';
+import React, { useCallback } from 'react';
+import { useAssistantContext } from '../../assistant_context';
+
+import * as i18n from './translations';
+
+interface Props {
+ navigateToApp: (appId: string, options?: Record) => Promise;
+}
+
+const ConnectorsSettingsManagementComponent: React.FC = () => {
+ const { navigateToApp } = useAssistantContext();
+
+ const onClick = useCallback(
+ () =>
+ navigateToApp('management', {
+ path: 'insightsAndAlerting/triggersActionsConnectors/connectors',
+ }),
+ [navigateToApp]
+ );
+
+ return (
+
+
+ {i18n.CONNECTOR_SETTINGS_MANAGEMENT_TITLE}
+
+
+
+
+ {i18n.CONNECTOR_SETTINGS_MANAGEMENT_DESCRIPTION}
+
+
+
+ {i18n.CONNECTOR_MANAGEMENT_BUTTON_TITLE}
+
+
+
+ );
+};
+
+export const ConnectorsSettingsManagement = React.memo(ConnectorsSettingsManagementComponent);
+ConnectorsSettingsManagementComponent.displayName = 'ConnectorsSettingsManagementComponent';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/translations.ts
new file mode 100644
index 0000000000000..c564338df0913
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_settings_management/translations.ts
@@ -0,0 +1,30 @@
+/*
+ * 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 CONNECTOR_SETTINGS_MANAGEMENT_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.connectors.connectorSettingsManagement.title',
+ {
+ defaultMessage: 'Connector Settings',
+ }
+);
+
+export const CONNECTOR_SETTINGS_MANAGEMENT_DESCRIPTION = i18n.translate(
+ 'xpack.elasticAssistant.connectors.connectorSettingsManagement.description',
+ {
+ defaultMessage:
+ 'Using the Elastic AI Assistant requires setting up a connector with API access to OpenIA or Bedrock large language models. ',
+ }
+);
+
+export const CONNECTOR_MANAGEMENT_BUTTON_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.connectors.connectorSettingsManagement.buttonTitle',
+ {
+ defaultMessage: 'Manage Connectors',
+ }
+);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx
index d1e2b01007f67..74d6ef1bc169b 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx
@@ -10,8 +10,7 @@ import type {
ActionTypeModel,
ActionTypeRegistryContract,
} from '@kbn/triggers-actions-ui-plugin/public';
-import { HttpSetup } from '@kbn/core/public';
-import { BASE_ACTION_API_PATH } from '@kbn/actions-plugin/common';
+
import { ActionConnectorProps } from '@kbn/triggers-actions-ui-plugin/public/types';
import { PRECONFIGURED_CONNECTOR } from './translations';
@@ -76,27 +75,3 @@ export const getConnectorTypeTitle = (
return actionType;
};
-
-export async function deleteActions({
- ids,
- http,
-}: {
- ids: string[];
- http: HttpSetup;
-}): Promise<{ successes: string[]; errors: string[] }> {
- const successes: string[] = [];
- const errors: string[] = [];
- await Promise.all(
- ids.map((id) =>
- http.delete(`${BASE_ACTION_API_PATH}/connector/${encodeURIComponent(id)}`)
- )
- ).then(
- function (fulfilled) {
- successes.push(...fulfilled);
- },
- function (rejected) {
- errors.push(...rejected);
- }
- );
- return { successes, errors };
-}
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
index a12ebd61129e3..86c4bebeb320b 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
@@ -177,59 +177,3 @@ export const DELETE_CONNECTOR_BUTTON = i18n.translate(
defaultMessage: 'Delete',
}
);
-
-export const MISSING_READ_CONNECTORS_CALLOUT_TITLE = i18n.translate(
- 'xpack.elasticAssistant.assistant.connectors.connectorMissingCallout.missingReadConnectorsCalloutTitle',
- {
- defaultMessage: 'Missing Read Connectors Privileges',
- }
-);
-
-export const CONNECTORS_TABLE_COLUMN_NAME = i18n.translate(
- 'xpack.elasticAssistant.assistant.connectors.table.column.Name',
- {
- defaultMessage: 'Connector name',
- }
-);
-
-export const CONNECTORS_TABLE_COLUMN_ACTION_TYPE = i18n.translate(
- 'xpack.elasticAssistant.assistant.connectors.table.column.type',
- {
- defaultMessage: 'Type',
- }
-);
-
-export const CONNECTORS_TABLE_COLUMN_COMPATIBILITY = i18n.translate(
- 'xpack.elasticAssistant.assistant.connectors.table.column.compatibility',
- {
- defaultMessage: 'Compatibility',
- }
-);
-
-export const CONNECTORS_TABLE_COLUMN_ACTIONS = i18n.translate(
- 'xpack.elasticAssistant.assistant.connectors.table.column.actions',
- {
- defaultMessage: 'Actions',
- }
-);
-
-export const DELETE_CONNECTOR_CONFIRMATION_SINGLE_TITLE = i18n.translate(
- 'xpack.elasticAssistant.assistant.connectors.deleteConnectorConfirmation.singleTitle',
- {
- defaultMessage: 'connector',
- }
-);
-
-export const DELETE_CONNECTOR_CONFIRMATION_MULTIPLE_TITLE = i18n.translate(
- 'xpack.elasticAssistant.assistant.connectors.deleteConnectorConfirmation.multipleTitle',
- {
- defaultMessage: 'connectors',
- }
-);
-
-export const SEARCH_CONNECTOR_PLACEHOLDER = i18n.translate(
- 'xpack.elasticAssistant.assistant.connectors.searchConnectorPlaceholder',
- {
- defaultMessage: 'Search for connectors',
- }
-);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonomization_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonomization_settings_management/index.tsx
new file mode 100644
index 0000000000000..3e3812510f076
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonomization_settings_management/index.tsx
@@ -0,0 +1,78 @@
+/*
+ * 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 { EuiFlexGroup, EuiPanel, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
+import React from 'react';
+
+import { FindAnonymizationFieldsResponse } from '@kbn/elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.gen';
+import { PerformBulkActionRequestBody } from '@kbn/elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.gen';
+import { euiThemeVars } from '@kbn/ui-theme';
+import { Stats } from '../../../data_anonymization_editor/stats';
+import { ContextEditor } from '../../../data_anonymization_editor/context_editor';
+import * as i18n from '../anonymization_settings/translations';
+import { useAnonymizationListUpdate } from '../anonymization_settings/use_anonymization_list_update';
+
+export interface Props {
+ defaultPageSize?: number;
+ anonymizationFields: FindAnonymizationFieldsResponse;
+ anonymizationFieldsBulkActions: PerformBulkActionRequestBody;
+ setAnonymizationFieldsBulkActions: React.Dispatch<
+ React.SetStateAction
+ >;
+ setUpdatedAnonymizationData: React.Dispatch<
+ React.SetStateAction
+ >;
+}
+
+const AnonymizationSettingsManagementComponent: React.FC = ({
+ defaultPageSize,
+ anonymizationFields,
+ anonymizationFieldsBulkActions,
+ setAnonymizationFieldsBulkActions,
+ setUpdatedAnonymizationData,
+}) => {
+ const onListUpdated = useAnonymizationListUpdate({
+ anonymizationFields,
+ anonymizationFieldsBulkActions,
+ setAnonymizationFieldsBulkActions,
+ setUpdatedAnonymizationData,
+ });
+ return (
+
+
+ {i18n.SETTINGS_TITLE}
+
+
+ {i18n.SETTINGS_DESCRIPTION}
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+AnonymizationSettingsManagementComponent.displayName = 'AnonymizationSettingsManagementComponent';
+
+export const AnonymizationSettingsManagement = React.memo(AnonymizationSettingsManagementComponent);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/index.tsx
index e03a965f6c98c..c371c9498dc2f 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/index.tsx
@@ -6,14 +6,14 @@
*/
import { EuiFlexGroup, EuiHorizontalRule, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
-import React, { useCallback } from 'react';
+import React from 'react';
import { FindAnonymizationFieldsResponse } from '@kbn/elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.gen';
import { PerformBulkActionRequestBody } from '@kbn/elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.gen';
import { Stats } from '../../../data_anonymization_editor/stats';
import { ContextEditor } from '../../../data_anonymization_editor/context_editor';
-import type { BatchUpdateListItem } from '../../../data_anonymization_editor/context_editor/types';
import * as i18n from './translations';
+import { useAnonymizationListUpdate } from './use_anonymization_list_update';
export interface Props {
defaultPageSize?: number;
@@ -34,39 +34,12 @@ const AnonymizationSettingsComponent: React.FC = ({
setAnonymizationFieldsBulkActions,
setUpdatedAnonymizationData,
}) => {
- const onListUpdated = useCallback(
- async (updates: BatchUpdateListItem[]) => {
- const updatedFieldsKeys = updates.map((u) => u.field);
-
- const updatedFields = updates.map((u) => ({
- ...(anonymizationFields.data.find((f) => f.field === u.field) ?? { id: '', field: '' }),
- ...(u.update === 'allow' || u.update === 'defaultAllow'
- ? { allowed: u.operation === 'add' }
- : {}),
- ...(u.update === 'allowReplacement' || u.update === 'defaultAllowReplacement'
- ? { anonymized: u.operation === 'add' }
- : {}),
- }));
- setAnonymizationFieldsBulkActions({
- ...anonymizationFieldsBulkActions,
- // Only update makes sense now, as long as we don't have an add new field design/UX
- update: [...(anonymizationFieldsBulkActions?.update ?? []), ...updatedFields],
- });
- setUpdatedAnonymizationData({
- ...anonymizationFields,
- data: [
- ...anonymizationFields.data.filter((f) => !updatedFieldsKeys.includes(f.field)),
- ...updatedFields,
- ],
- });
- },
- [
- anonymizationFields,
- anonymizationFieldsBulkActions,
- setAnonymizationFieldsBulkActions,
- setUpdatedAnonymizationData,
- ]
- );
+ const onListUpdated = useAnonymizationListUpdate({
+ anonymizationFields,
+ anonymizationFieldsBulkActions,
+ setAnonymizationFieldsBulkActions,
+ setUpdatedAnonymizationData,
+ });
return (
<>
@@ -88,6 +61,7 @@ const AnonymizationSettingsComponent: React.FC = ({
onListUpdated={onListUpdated}
rawData={null}
pageSize={defaultPageSize}
+ compressed={true}
/>
>
);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/use_anonymization_list_update.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/use_anonymization_list_update.tsx
new file mode 100644
index 0000000000000..f9ee4875fad23
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/use_anonymization_list_update.tsx
@@ -0,0 +1,66 @@
+/*
+ * 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 { useCallback } from 'react';
+import { FindAnonymizationFieldsResponse } from '@kbn/elastic-assistant-common/impl/schemas/anonymization_fields/find_anonymization_fields_route.gen';
+import { PerformBulkActionRequestBody } from '@kbn/elastic-assistant-common/impl/schemas/anonymization_fields/bulk_crud_anonymization_fields_route.gen';
+
+import { BatchUpdateListItem } from '../../../data_anonymization_editor/context_editor/types';
+
+interface Props {
+ anonymizationFields: FindAnonymizationFieldsResponse;
+ anonymizationFieldsBulkActions: PerformBulkActionRequestBody;
+ setAnonymizationFieldsBulkActions: React.Dispatch<
+ React.SetStateAction
+ >;
+ setUpdatedAnonymizationData: React.Dispatch<
+ React.SetStateAction
+ >;
+}
+
+export const useAnonymizationListUpdate = ({
+ anonymizationFields,
+ anonymizationFieldsBulkActions,
+ setAnonymizationFieldsBulkActions,
+ setUpdatedAnonymizationData,
+}: Props) => {
+ const onListUpdated = useCallback(
+ async (updates: BatchUpdateListItem[]) => {
+ const updatedFieldsKeys = updates.map((u) => u.field);
+
+ const updatedFields = updates.map((u) => ({
+ ...(anonymizationFields.data.find((f) => f.field === u.field) ?? { id: '', field: '' }),
+ ...(u.update === 'allow' || u.update === 'defaultAllow'
+ ? { allowed: u.operation === 'add' }
+ : {}),
+ ...(u.update === 'allowReplacement' || u.update === 'defaultAllowReplacement'
+ ? { anonymized: u.operation === 'add' }
+ : {}),
+ }));
+ setAnonymizationFieldsBulkActions({
+ ...anonymizationFieldsBulkActions,
+ // Only update makes sense now, as long as we don't have an add new field design/UX
+ update: [...(anonymizationFieldsBulkActions?.update ?? []), ...updatedFields],
+ });
+ setUpdatedAnonymizationData({
+ ...anonymizationFields,
+ data: [
+ ...anonymizationFields.data.filter((f) => !updatedFieldsKeys.includes(f.field)),
+ ...updatedFields,
+ ],
+ });
+ },
+ [
+ anonymizationFields,
+ anonymizationFieldsBulkActions,
+ setAnonymizationFieldsBulkActions,
+ setUpdatedAnonymizationData,
+ ]
+ );
+
+ return onListUpdated;
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.tsx
index 6eeb80f2bb911..e215c8270746e 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.tsx
@@ -35,6 +35,7 @@ const defaultSort: SortConfig = {
export interface Props {
anonymizationFields: FindAnonymizationFieldsResponse;
+ compressed?: boolean;
onListUpdated: (updates: BatchUpdateListItem[]) => void;
rawData: Record | null;
pageSize?: number;
@@ -60,6 +61,7 @@ const search: EuiSearchBarProps = {
const ContextEditorComponent: React.FC = ({
anonymizationFields,
+ compressed = true,
onListUpdated,
rawData,
pageSize = DEFAULT_PAGE_SIZE,
@@ -131,7 +133,7 @@ const ContextEditorComponent: React.FC = ({
allowNeutralSort={false}
childrenBetween={hasUpdateAIAssistantAnonymization ? toolbar : undefined}
columns={columns}
- compressed={true}
+ compressed={compressed}
data-test-subj="contextEditor"
itemId={FIELDS.FIELD}
items={rows}
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/allowed_stat/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/allowed_stat/index.tsx
index 2febee604e4b5..9d893cdaa65a2 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/allowed_stat/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/allowed_stat/index.tsx
@@ -15,11 +15,19 @@ import * as i18n from './translations';
interface Props {
allowed: number;
+ titleSize?: 'xs' | 's' | 'xxxs' | 'xxs' | 'm' | 'l' | undefined;
+ gap?: string;
total: number;
inline?: boolean;
}
-const AllowedStatComponent: React.FC = ({ allowed, total, inline }) => {
+const AllowedStatComponent: React.FC = ({
+ allowed,
+ total,
+ inline,
+ titleSize = TITLE_SIZE,
+ gap = euiThemeVars.euiSizeXS,
+}) => {
const tooltipContent = useMemo(() => i18n.ALLOWED_TOOLTIP({ allowed, total }), [allowed, total]);
return (
@@ -30,7 +38,7 @@ const AllowedStatComponent: React.FC = ({ allowed, total, inline }) => {
? css`
display: flex;
align-items: center;
- gap: ${euiThemeVars.euiSizeXS};
+ gap: ${gap};
`
: null
}
@@ -38,7 +46,7 @@ const AllowedStatComponent: React.FC = ({ allowed, total, inline }) => {
description={i18n.ALLOWED}
reverse
title={allowed}
- titleSize={TITLE_SIZE}
+ titleSize={titleSize}
/>
);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/index.tsx
index 210b65c6d6a70..74b3e631b7117 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/index.tsx
@@ -16,11 +16,19 @@ import * as i18n from './translations';
interface Props {
anonymized: number;
+ titleSize?: 'xs' | 's' | 'xxxs' | 'xxs' | 'm' | 'l' | undefined;
+ gap?: string;
isDataAnonymizable: boolean;
inline?: boolean;
}
-const AnonymizedStatComponent: React.FC = ({ anonymized, isDataAnonymizable, inline }) => {
+const AnonymizedStatComponent: React.FC = ({
+ anonymized,
+ isDataAnonymizable,
+ inline,
+ titleSize = TITLE_SIZE,
+ gap = euiThemeVars.euiSizeXS,
+}) => {
const color = useMemo(() => getColor(isDataAnonymizable), [isDataAnonymizable]);
const tooltipContent = useMemo(
@@ -45,7 +53,7 @@ const AnonymizedStatComponent: React.FC = ({ anonymized, isDataAnonymizab
? css`
display: flex;
align-items: center;
- gap: ${euiThemeVars.euiSizeXS};
+ gap: ${gap};
`
: null
}
@@ -54,7 +62,7 @@ const AnonymizedStatComponent: React.FC = ({ anonymized, isDataAnonymizab
reverse
titleColor={color}
title={anonymized}
- titleSize={TITLE_SIZE}
+ titleSize={titleSize}
/>
);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/available_stat/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/available_stat/index.tsx
index 6e5853c871a6f..d29bfab02b897 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/available_stat/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/available_stat/index.tsx
@@ -15,10 +15,17 @@ import * as i18n from './translations';
interface Props {
total: number;
+ titleSize?: 'xs' | 's' | 'xxxs' | 'xxs' | 'm' | 'l' | undefined;
+ gap?: string;
inline?: boolean;
}
-const AvailableStatComponent: React.FC = ({ total, inline }) => {
+const AvailableStatComponent: React.FC = ({
+ total,
+ inline,
+ titleSize = TITLE_SIZE,
+ gap = euiThemeVars.euiSizeXS,
+}) => {
const tooltipContent = useMemo(() => i18n.AVAILABLE_TOOLTIP(total), [total]);
return (
@@ -29,7 +36,7 @@ const AvailableStatComponent: React.FC = ({ total, inline }) => {
? css`
display: flex;
align-items: center;
- gap: ${euiThemeVars.euiSizeXS};
+ gap: ${gap};
`
: null
}
@@ -37,7 +44,7 @@ const AvailableStatComponent: React.FC = ({ total, inline }) => {
description={i18n.AVAILABLE}
reverse
title={total}
- titleSize={TITLE_SIZE}
+ titleSize={titleSize}
/>
);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/constants.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/constants.ts
index ba1e02e569bc2..ed5c08a0c64f9 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/constants.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/constants.ts
@@ -6,3 +6,4 @@
*/
export const TITLE_SIZE = 'xs';
+export const STAT_TITLE_SIZE = 'm';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/index.tsx
index 2068bc517025d..b628119032d1a 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/index.tsx
@@ -27,6 +27,8 @@ interface Props {
rawData?: string | Record;
inline?: boolean;
replacements?: Replacements;
+ titleSize?: 's' | 'l' | 'xs' | 'm' | 'xxxs' | 'xxs' | undefined;
+ gap?: string;
}
const StatsComponent: React.FC = ({
@@ -35,6 +37,8 @@ const StatsComponent: React.FC = ({
rawData,
inline,
replacements,
+ titleSize,
+ gap,
}) => {
const { allowed, anonymized, total } = useMemo(
() =>
@@ -50,7 +54,13 @@ const StatsComponent: React.FC = ({
{isDataAnonymizable && (
-
+
)}
@@ -59,12 +69,14 @@ const StatsComponent: React.FC = ({
anonymized={anonymized}
isDataAnonymizable={isDataAnonymizable || anonymized > 0}
inline={inline}
+ titleSize={titleSize}
+ gap={gap}
/>
{isDataAnonymizable && (
-
+
)}
diff --git a/x-pack/plugins/security_solution/public/assistant/provider.tsx b/x-pack/plugins/security_solution/public/assistant/provider.tsx
index 106078f792d08..2b5daf73fbf4b 100644
--- a/x-pack/plugins/security_solution/public/assistant/provider.tsx
+++ b/x-pack/plugins/security_solution/public/assistant/provider.tsx
@@ -117,16 +117,11 @@ export const createConversations = async (
*/
export const AssistantProvider: FC> = ({ children }) => {
const {
+ application: { navigateToApp },
http,
notifications,
- settings,
storage,
- triggersActionsUi: {
- actionTypeRegistry,
- getAddConnectorFlyout,
- getDeleteConnectorModalConfirmation,
- getEditConnectorFlyout,
- },
+ triggersActionsUi: { actionTypeRegistry },
docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION },
} = useKibana().services;
const basePath = useBasePath();
@@ -174,12 +169,9 @@ export const AssistantProvider: FC> = ({ children })
baseQuickPrompts={BASE_SECURITY_QUICK_PROMPTS} // to server and plugin start
baseSystemPrompts={BASE_SECURITY_SYSTEM_PROMPTS} // to server and plugin start
baseConversations={baseConversations}
- getAddConnectorFlyout={getAddConnectorFlyout}
- getDeleteConnectorModalConfirmation={getDeleteConnectorModalConfirmation}
- getEditConnectorFlyout={getEditConnectorFlyout}
getComments={getComments}
http={http}
- settings={settings}
+ navigateToApp={navigateToApp}
title={ASSISTANT_TITLE}
toasts={toasts}
>
diff --git a/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx b/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx
index d7d4c180442ba..0a098b4900c77 100644
--- a/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx
+++ b/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx
@@ -32,7 +32,7 @@ export const ManagementSettings = React.memo(() => {
mergeBaseWithPersistedConversations(baseConversations, conversationsData),
[baseConversations]
);
- const { data: conversations } = useFetchCurrentUserConversations({
+ const { data: conversations, refetch: refetchConversations } = useFetchCurrentUserConversations({
http,
onFetch: onFetchedConversations,
isAssistantEnabled,
@@ -56,6 +56,7 @@ export const ManagementSettings = React.memo(() => {
setSelectedConversationId={setSelectedConversationId}
conversations={conversations}
isFlyoutMode={isFlyoutMode}
+ refetchConversations={refetchConversations}
/>
);
}
From 84f05a490e780173e458e5f161fc3de1416b1247 Mon Sep 17 00:00:00 2001
From: Angela Chuang
Date: Mon, 17 Jun 2024 14:59:11 +0100
Subject: [PATCH 05/37] revert changes
---
.../use_fetch_current_user_conversations.ts | 1 -
.../conversation_settings_editor.tsx | 76 +++++++++++--
.../use_connector_selector.ts | 100 ------------------
.../system_prompt_modal/translations.ts | 14 +++
4 files changed, 83 insertions(+), 108 deletions(-)
delete mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_connector_selector.ts
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.ts
index 08cbbeaef20a4..58be08317d40c 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api/conversations/use_fetch_current_user_conversations.ts
@@ -26,7 +26,6 @@ export interface UseFetchCurrentUserConversationsParams {
signal?: AbortSignal | undefined;
refetchOnWindowFocus?: boolean;
isAssistantEnabled: boolean;
- query?: { page: number; perPage: number };
}
/**
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx
index 691ad911be3a5..91de744ef75e8 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx
@@ -129,13 +129,75 @@ export const ConversationSettingsEditor: React.FC
+ selectedConversation?.id === ''
+ ? selectedConversation.title
+ : (selectedConversation?.id as string),
+ [selectedConversation]
+ );
+ const handleOnConnectorSelectionChange = useCallback(
+ (connector) => {
+ if (selectedConversation != null) {
+ const config = getGenAiConfig(connector);
+ const updatedConversation = {
+ ...selectedConversation,
+ apiConfig: {
+ ...selectedConversation.apiConfig,
+ connectorId: connector.id,
+ actionTypeId: connector.actionTypeId,
+ provider: config?.apiProvider,
+ model: config?.defaultModel,
+ },
+ };
+ setConversationSettings({
+ ...conversationSettings,
+ [selectedConversationId]: updatedConversation,
+ });
+ if (selectedConversation.id !== '') {
+ setConversationsSettingsBulkActions({
+ ...conversationsSettingsBulkActions,
+ update: {
+ ...(conversationsSettingsBulkActions.update ?? {}),
+ [updatedConversation.id]: {
+ ...updatedConversation,
+ ...(conversationsSettingsBulkActions.update
+ ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
+ : {}),
+ apiConfig: {
+ ...updatedConversation.apiConfig,
+ ...((conversationsSettingsBulkActions.update
+ ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
+ : {}
+ ).apiConfig ?? {}),
+ connectorId: connector?.id,
+ actionTypeId: connector?.actionTypeId,
+ provider: config?.apiProvider,
+ model: config?.defaultModel,
+ },
+ },
+ },
+ });
+ } else {
+ setConversationsSettingsBulkActions({
+ ...conversationsSettingsBulkActions,
+ create: {
+ ...(conversationsSettingsBulkActions.create ?? {}),
+ [updatedConversation.id]: updatedConversation,
+ },
+ });
+ }
+ }
+ },
+ [
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ selectedConversation,
+ selectedConversationId,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ ]
+ );
const selectedModel = useMemo(() => {
const connectorModel = getGenAiConfig(selectedConnector)?.defaultModel;
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_connector_selector.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_connector_selector.ts
deleted file mode 100644
index e295452ceaa6a..0000000000000
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_connector_selector.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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 { useCallback, useMemo } from 'react';
-import { Conversation, ConversationsBulkActions } from '../../../..';
-import { getGenAiConfig } from '../../../connectorland/helpers';
-
-interface Props {
- selectedConversation?: Conversation;
- setConversationSettings: React.Dispatch>>;
- conversationSettings: Record;
- setConversationsSettingsBulkActions: React.Dispatch<
- React.SetStateAction
- >;
- conversationsSettingsBulkActions: ConversationsBulkActions;
-}
-
-export const useConnectorSelector = ({
- selectedConversation,
- setConversationSettings,
- conversationSettings,
- setConversationsSettingsBulkActions,
- conversationsSettingsBulkActions,
-}: Props) => {
- const selectedConversationId = useMemo(
- () =>
- selectedConversation?.id === ''
- ? selectedConversation.title
- : (selectedConversation?.id as string),
- [selectedConversation]
- );
- const handleOnConnectorSelectionChange = useCallback(
- (connector) => {
- if (selectedConversation != null) {
- const config = getGenAiConfig(connector);
- const updatedConversation = {
- ...selectedConversation,
- apiConfig: {
- ...selectedConversation.apiConfig,
- connectorId: connector.id,
- actionTypeId: connector.actionTypeId,
- provider: config?.apiProvider,
- model: config?.defaultModel,
- },
- };
- setConversationSettings({
- ...conversationSettings,
- [selectedConversationId]: updatedConversation,
- });
- if (selectedConversation.id !== '') {
- setConversationsSettingsBulkActions({
- ...conversationsSettingsBulkActions,
- update: {
- ...(conversationsSettingsBulkActions.update ?? {}),
- [updatedConversation.id]: {
- ...updatedConversation,
- ...(conversationsSettingsBulkActions.update
- ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
- : {}),
- apiConfig: {
- ...updatedConversation.apiConfig,
- ...((conversationsSettingsBulkActions.update
- ? conversationsSettingsBulkActions.update[updatedConversation.id] ?? {}
- : {}
- ).apiConfig ?? {}),
- connectorId: connector?.id,
- actionTypeId: connector?.actionTypeId,
- provider: config?.apiProvider,
- model: config?.defaultModel,
- },
- },
- },
- });
- } else {
- setConversationsSettingsBulkActions({
- ...conversationsSettingsBulkActions,
- create: {
- ...(conversationsSettingsBulkActions.create ?? {}),
- [updatedConversation.id]: updatedConversation,
- },
- });
- }
- }
- },
- [
- conversationSettings,
- conversationsSettingsBulkActions,
- selectedConversation,
- selectedConversationId,
- setConversationSettings,
- setConversationsSettingsBulkActions,
- ]
- );
-
- return handleOnConnectorSelectionChange;
-};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/translations.ts
index c9cd7bde54797..06544b98a68bd 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/translations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/translations.ts
@@ -68,3 +68,17 @@ export const SYSTEM_PROMPT_DEFAULT_CONVERSATIONS_HELP_TEXT = i18n.translate(
defaultMessage: 'Conversations that should use this System Prompt by default',
}
);
+
+export const CANCEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.promptEditor.systemPrompt.slCancelButtonTitle',
+ {
+ defaultMessage: 'Cancel',
+ }
+);
+
+export const SAVE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.promptEditor.systemPrompt.slSaveButtonTitle',
+ {
+ defaultMessage: 'Save',
+ }
+);
From fd873ae409a0e511afde0ddc9d4ab1ae9f480c1e Mon Sep 17 00:00:00 2001
From: Angela Chuang
Date: Tue, 18 Jun 2024 21:24:27 +0100
Subject: [PATCH 06/37] evaluation tab
---
.../assistant_header_flyout.tsx | 3 +
.../impl/assistant/assistant_header/index.tsx | 3 +
.../use_conversation_selector_settings.tsx | 25 +-
.../conversation_settings.tsx | 76 +--
.../conversation_settings_editor.tsx | 3 +-
.../use_conversation_changed.tsx | 100 ++++
.../index.tsx | 94 ++--
.../impl/assistant/index.tsx | 2 +
.../index.tsx | 6 +
.../index.tsx | 6 +
.../assistant/settings/assistant_settings.tsx | 4 +-
.../settings/assistant_settings_button.tsx | 3 +
.../assistant_settings_management.tsx | 47 +-
.../use_evaluation_details.tsx | 87 ++++
.../evaluation_settings.tsx | 479 +++---------------
.../prediction_details/index.tsx | 60 +++
.../prediction_details/translations.ts | 35 ++
.../use_predictions_details.tsx | 108 ++++
.../run_details/data_set_toggle_button.tsx | 44 ++
.../evaluation_settings/run_details/index.tsx | 213 ++++++++
.../run_details/translations.ts | 158 ++++++
.../run_details/use_dataset.tsx | 64 +++
.../run_details/use_run_details.tsx | 55 ++
.../run_details/use_trace_options.tsx | 54 ++
.../evaluation_settings/translations.ts | 178 -------
.../evaluation_settings_management/index.tsx | 291 +++++++++++
.../translations.ts | 28 +
.../use_settings_updater.tsx | 7 +
.../stack_management/management_settings.tsx | 7 +-
29 files changed, 1511 insertions(+), 729 deletions(-)
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_conversation_changed.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_details/use_evaluation_details.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/prediction_details/index.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/prediction_details/translations.ts
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/prediction_details/use_predictions_details.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/data_set_toggle_button.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/index.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/translations.ts
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/use_dataset.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/use_run_details.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/use_trace_options.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings_management/index.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings_management/translations.ts
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/assistant_header_flyout.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/assistant_header_flyout.tsx
index be97f716b2740..d9ba27b96655f 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/assistant_header_flyout.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/assistant_header_flyout.tsx
@@ -43,6 +43,7 @@ interface OwnProps {
setChatHistoryVisible?: React.Dispatch>;
onConversationSelected: ({ cId, cTitle }: { cId: string; cTitle: string }) => void;
conversations: Record;
+ conversationsLoaded: boolean;
refetchConversationsState: () => Promise;
onConversationCreate: () => Promise;
isAssistantEnabled: boolean;
@@ -69,6 +70,7 @@ export const AssistantHeaderFlyout: React.FC = ({
onCloseFlyout,
onConversationSelected,
conversations,
+ conversationsLoaded,
refetchConversationsState,
onConversationCreate,
isAssistantEnabled,
@@ -158,6 +160,7 @@ export const AssistantHeaderFlyout: React.FC = ({
setIsSettingsModalVisible={setIsSettingsModalVisible}
onConversationSelected={onConversationSelected}
conversations={conversations}
+ conversationsLoaded={conversationsLoaded}
refetchConversationsState={refetchConversationsState}
isFlyoutMode={true}
/>
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/index.tsx
index bb2e72e2936d3..ac7ca235b36ee 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_header/index.tsx
@@ -38,6 +38,7 @@ interface OwnProps {
showAnonymizedValues: boolean;
title: string;
conversations: Record;
+ conversationsLoaded: boolean;
refetchConversationsState: () => Promise;
}
@@ -61,6 +62,7 @@ export const AssistantHeader: React.FC = ({
showAnonymizedValues,
title,
conversations,
+ conversationsLoaded,
refetchConversationsState,
}) => {
const showAnonymizedValuesChecked = useMemo(
@@ -151,6 +153,7 @@ export const AssistantHeader: React.FC = ({
setIsSettingsModalVisible={setIsSettingsModalVisible}
onConversationSelected={onConversationSelected}
conversations={conversations}
+ conversationsLoaded={conversationsLoaded}
refetchConversationsState={refetchConversationsState}
isFlyoutMode={false}
/>
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx
index 9a60f19209200..282f2e9f6b2f5 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx
@@ -20,11 +20,11 @@ export interface UseConversationSelectorSettingsProps {
actionTypeRegistry: ActionTypeRegistryContract;
connectors: AIConnector[] | undefined;
conversations: Record;
+ defaultConnector?: AIConnector;
}
export type ConversationTableItem = Conversation & {
actionType?: string | null;
- systemPrompt?: string;
};
export const useConversationsList = ({
@@ -32,17 +32,15 @@ export const useConversationsList = ({
actionTypeRegistry,
connectors,
conversations = emptyConversations,
+ defaultConnector,
}: UseConversationSelectorSettingsProps) => {
const conversationOptions = useMemo(() => {
return Object.values(conversations).map((conversation) => {
const connector: AIConnector | undefined = connectors?.find(
- (c) => c.id === conversation.apiConfig?.connectorId
+ (c) => c.id === conversation.apiConfig?.connectorId || defaultConnector?.id
);
const actionType = getConnectorTypeTitle(connector, actionTypeRegistry);
- const systemPrompt: Prompt | undefined = allSystemPrompts.find(
- ({ id }) => id === conversation.apiConfig?.defaultSystemPromptId
- );
const defaultSystemPrompt = getDefaultSystemPrompt({
allSystemPrompts,
@@ -51,14 +49,19 @@ export const useConversationsList = ({
return {
...conversation,
actionType,
- systemPrompt:
- systemPrompt?.label ??
- systemPrompt?.name ??
- defaultSystemPrompt?.label ??
- defaultSystemPrompt?.name,
+ ...(defaultConnector
+ ? {
+ apiConfig: {
+ connectorId: defaultConnector.id,
+ actionTypeId: defaultConnector.actionTypeId,
+ provider: defaultConnector.apiProvider,
+ defaultSystemPromptId: defaultSystemPrompt?.id,
+ },
+ }
+ : {}),
};
});
- }, [allSystemPrompts, actionTypeRegistry, connectors, conversations]);
+ }, [conversations, connectors, actionTypeRegistry, allSystemPrompts, defaultConnector]);
return conversationOptions;
};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx
index 9c89fc27302bc..c52af6eb878ab 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx
@@ -13,7 +13,7 @@ import {
EuiFormRow,
EuiSwitch,
} from '@elastic/eui';
-import React, { useCallback, useMemo } from 'react';
+import React from 'react';
import { HttpSetup } from '@kbn/core-http-browser';
@@ -24,11 +24,11 @@ import * as i18n from './translations';
import { AIConnector } from '../../../connectorland/connector_selector';
import { ConversationSelectorSettings } from '../conversation_selector_settings';
-import { getDefaultSystemPrompt } from '../../use_conversation/helpers';
import { ConversationsBulkActions } from '../../api';
import { useConversationDeleted } from './use_conversation_deleted';
import { ConversationSettingsEditor } from './conversation_settings_editor';
+import { useConversationChanged } from './use_conversation_changed';
export interface ConversationSettingsProps {
actionTypeRegistry: ActionTypeRegistryContract;
@@ -68,69 +68,15 @@ export const ConversationSettings: React.FC = React.m
conversationsSettingsBulkActions,
setConversationsSettingsBulkActions,
}) => {
- const defaultSystemPrompt = useMemo(() => {
- return getDefaultSystemPrompt({ allSystemPrompts, conversation: undefined });
- }, [allSystemPrompts]);
-
- // Conversation callbacks
- // When top level conversation selection changes
- const onConversationSelectionChange = useCallback(
- (c?: Conversation | string) => {
- const isNew = typeof c === 'string';
-
- const newSelectedConversation: Conversation | undefined = isNew
- ? {
- id: '',
- title: c ?? '',
- category: 'assistant',
- messages: [],
- replacements: {},
- ...(defaultConnector
- ? {
- apiConfig: {
- connectorId: defaultConnector.id,
- actionTypeId: defaultConnector.actionTypeId,
- provider: defaultConnector.apiProvider,
- defaultSystemPromptId: defaultSystemPrompt?.id,
- },
- }
- : {}),
- }
- : c;
-
- if (newSelectedConversation && (isNew || newSelectedConversation.id === '')) {
- setConversationSettings({
- ...conversationSettings,
- [isNew ? c : newSelectedConversation.title]: newSelectedConversation,
- });
- setConversationsSettingsBulkActions({
- ...conversationsSettingsBulkActions,
- create: {
- ...(conversationsSettingsBulkActions.create ?? {}),
- [newSelectedConversation.title]: newSelectedConversation,
- },
- });
- } else if (newSelectedConversation != null) {
- setConversationSettings((prev) => {
- return {
- ...prev,
- [newSelectedConversation.id]: newSelectedConversation,
- };
- });
- }
-
- onSelectedConversationChange(newSelectedConversation);
- },
- [
- conversationSettings,
- conversationsSettingsBulkActions,
- defaultConnector,
- defaultSystemPrompt?.id,
- onSelectedConversationChange,
- setConversationSettings,
- setConversationsSettingsBulkActions,
- ]
- );
+ const onConversationSelectionChange = useConversationChanged({
+ allSystemPrompts,
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ defaultConnector,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ onSelectedConversationChange,
+ });
const onConversationDeleted = useConversationDeleted({
conversationSettings,
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx
index 91de744ef75e8..12f13a4c9d6d0 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings_editor.tsx
@@ -22,7 +22,6 @@ import { ModelSelector } from '../../../connectorland/models/model_selector/mode
import { useLoadConnectors } from '../../../connectorland/use_load_connectors';
import { getGenAiConfig } from '../../../connectorland/helpers';
import { ConversationsBulkActions } from '../../api';
-import { useConnectorSelector } from './use_connector_selector';
import { getDefaultSystemPrompt } from '../../use_conversation/helpers';
export interface ConversationSettingsEditorProps {
@@ -73,7 +72,7 @@ export const ConversationSettingsEditor: React.FC;
+ conversationsSettingsBulkActions: ConversationsBulkActions;
+ defaultConnector?: AIConnector;
+ setConversationSettings: React.Dispatch>>;
+ setConversationsSettingsBulkActions: React.Dispatch<
+ React.SetStateAction
+ >;
+ onSelectedConversationChange: (conversation?: Conversation) => void;
+}
+
+export const useConversationChanged = ({
+ allSystemPrompts,
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ defaultConnector,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ onSelectedConversationChange,
+}: Props) => {
+ const defaultSystemPrompt = useMemo(() => {
+ return getDefaultSystemPrompt({ allSystemPrompts, conversation: undefined });
+ }, [allSystemPrompts]);
+
+ // Conversation callbacks
+ // When top level conversation selection changes
+ const onConversationSelectionChange = useCallback(
+ (c?: Conversation | string) => {
+ const isNew = typeof c === 'string';
+
+ const newSelectedConversation: Conversation | undefined = isNew
+ ? {
+ id: '',
+ title: c ?? '',
+ category: 'assistant',
+ messages: [],
+ replacements: {},
+ ...(defaultConnector
+ ? {
+ apiConfig: {
+ connectorId: defaultConnector.id,
+ actionTypeId: defaultConnector.actionTypeId,
+ provider: defaultConnector.apiProvider,
+ defaultSystemPromptId: defaultSystemPrompt?.id,
+ },
+ }
+ : {}),
+ }
+ : c;
+
+ if (newSelectedConversation && (isNew || newSelectedConversation.id === '')) {
+ setConversationSettings({
+ ...conversationSettings,
+ [isNew ? c : newSelectedConversation.title]: newSelectedConversation,
+ });
+ setConversationsSettingsBulkActions({
+ ...conversationsSettingsBulkActions,
+ create: {
+ ...(conversationsSettingsBulkActions.create ?? {}),
+ [newSelectedConversation.title]: newSelectedConversation,
+ },
+ });
+ } else if (newSelectedConversation != null) {
+ setConversationSettings((prev) => {
+ return {
+ ...prev,
+ [newSelectedConversation.id]: newSelectedConversation,
+ };
+ });
+ }
+
+ onSelectedConversationChange(newSelectedConversation);
+ },
+ [
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ defaultConnector,
+ defaultSystemPrompt?.id,
+ onSelectedConversationChange,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ ]
+ );
+
+ return onConversationSelectionChange;
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
index fb3b618ea9c8b..f607933623961 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
@@ -36,14 +36,18 @@ import { useFlyoutModalVisibility } from '../../common/components/assisttant_set
import { Flyout } from '../../common/components/assisttant_settings_management/flyout';
import { CANCEL, DELETE } from '../../settings/translations';
import { ConversationSettingsEditor } from '../conversation_settings/conversation_settings_editor';
+import { useConversationChanged } from '../conversation_settings/use_conversation_changed';
+import { getDefaultSystemPrompt } from '../../use_conversation/helpers';
interface Props {
actionTypeRegistry: ActionTypeRegistryContract;
allSystemPrompts: Prompt[];
assistantStreamingEnabled: boolean;
connectors: AIConnector[] | undefined;
- conversations: Record;
+ conversationSettings: Record;
conversationsSettingsBulkActions: ConversationsBulkActions;
+ conversationsLoaded: boolean;
+ defaultConnector?: AIConnector;
handleSave: () => void;
isDisabled?: boolean;
isFlyoutMode: boolean;
@@ -63,8 +67,10 @@ const ConversationSettingsManagementComponent: React.FC = ({
allSystemPrompts,
assistantStreamingEnabled,
connectors,
- conversations,
+ defaultConnector,
+ conversationSettings,
conversationsSettingsBulkActions,
+ conversationsLoaded,
handleSave,
isDisabled,
isFlyoutMode,
@@ -76,6 +82,8 @@ const ConversationSettingsManagementComponent: React.FC = ({
setConversationSettings,
setConversationsSettingsBulkActions,
}) => {
+ console.log('conversationSettings----', conversationSettings);
+ console.log('selectedConversation---', selectedConversation);
const { http } = useAssistantContext();
const {
isFlyoutOpen: editFlyoutVisible,
@@ -90,16 +98,26 @@ const ConversationSettingsManagementComponent: React.FC = ({
closeFlyout: closeConfirmModal,
} = useFlyoutModalVisibility();
+ const onConversationSelectionChange = useConversationChanged({
+ allSystemPrompts,
+ conversationSettings,
+ conversationsSettingsBulkActions,
+ defaultConnector,
+ setConversationSettings,
+ setConversationsSettingsBulkActions,
+ onSelectedConversationChange,
+ });
+
const onEditActionClicked = useCallback(
(rowItem: ConversationTableItem) => {
openEditFlyout();
- onSelectedConversationChange(rowItem);
+ onConversationSelectionChange(rowItem);
},
- [onSelectedConversationChange, openEditFlyout]
+ [onConversationSelectionChange, openEditFlyout]
);
const onConversationDeleted = useConversationDeleted({
- conversationSettings: conversations,
+ conversationSettings,
conversationsSettingsBulkActions,
setConversationSettings,
setConversationsSettingsBulkActions,
@@ -118,8 +136,7 @@ const ConversationSettingsManagementComponent: React.FC = ({
if (!deleteConversation) return;
onConversationDeleted(deleteConversation.title);
closeConfirmModal();
- refetchConversations();
- }, [deleteConversation, onConversationDeleted, closeConfirmModal, refetchConversations]);
+ }, [deleteConversation, onConversationDeleted, closeConfirmModal]);
const onDeleteCancelled = useCallback(() => {
setDeleteConversation(null);
@@ -131,7 +148,8 @@ const ConversationSettingsManagementComponent: React.FC = ({
allSystemPrompts,
actionTypeRegistry,
connectors,
- conversations,
+ conversations: conversationSettings,
+ defaultConnector,
});
const onEditFlyoutClosed = useCallback(() => {
@@ -142,8 +160,7 @@ const ConversationSettingsManagementComponent: React.FC = ({
const onEditFlyoutSaved = useCallback(() => {
handleSave();
closeEditFlyout();
- refetchConversations();
- }, [closeEditFlyout, handleSave, refetchConversations]);
+ }, [closeEditFlyout, handleSave]);
const columns: Array> = useMemo(
() => [
@@ -154,20 +171,38 @@ const ConversationSettingsManagementComponent: React.FC = ({
),
},
{
- field: 'systemPrompt',
name: i18n.CONVERSATIONS_TABLE_COLUMN_SYSTEM_PROMPT,
- render: (systemPrompt: ConversationTableItem['systemPrompt']) =>
- systemPrompt ? {systemPrompt} : null,
+ align: 'center',
+ render: (conversation: ConversationTableItem) => {
+ const systemPrompt: Prompt | undefined = allSystemPrompts.find(
+ ({ id }) => id === conversation.apiConfig?.defaultSystemPromptId
+ );
+
+ const defaultSystemPrompt = getDefaultSystemPrompt({
+ allSystemPrompts,
+ conversation,
+ });
+
+ const systemPromptTitle =
+ systemPrompt?.label ||
+ systemPrompt?.name ||
+ defaultSystemPrompt?.label ||
+ defaultSystemPrompt?.name;
+
+ return systemPromptTitle ? {systemPromptTitle} : null;
+ },
},
{
field: 'actionType',
name: i18n.CONVERSATIONS_TABLE_COLUMN_CONNECTOR,
+ align: 'center',
render: (actionType: ConversationTableItem['actionType']) =>
actionType ? {actionType} : null,
},
{
field: 'updatedAt',
name: i18n.CONVERSATIONS_TABLE_COLUMN_UPDATED_AT,
+ align: 'center',
render: (updatedAt: ConversationTableItem['updatedAt']) =>
updatedAt ? (
@@ -183,23 +218,20 @@ const ConversationSettingsManagementComponent: React.FC = ({
},
{
name: i18n.CONVERSATIONS_TABLE_COLUMN_ACTIONS,
- actions: [
- {
- name: i18n.CONVERSATIONS_TABLE_COLUMN_ACTIONS,
- render: (conversation: ConversationTableItem) => {
- return (
-
- rowItem={conversation}
- onEdit={onEditActionClicked}
- onDelete={onDeleteActionClicked}
- />
- );
- },
- },
- ],
+ width: '120px',
+ align: 'center',
+ render: (prompt: ConversationTableItem) => {
+ return (
+
+ rowItem={prompt}
+ onDelete={onDeleteActionClicked}
+ onEdit={onEditActionClicked}
+ />
+ );
+ },
},
],
- [onDeleteActionClicked, onEditActionClicked]
+ [allSystemPrompts, onDeleteActionClicked, onEditActionClicked]
);
const sorting = useMemo(
@@ -212,6 +244,10 @@ const ConversationSettingsManagementComponent: React.FC = ({
[]
);
+ if (!conversationsLoaded) {
+ return null;
+ }
+
return (
<>
@@ -238,7 +274,7 @@ const ConversationSettingsManagementComponent: React.FC = ({
>
= ({
setChatHistoryVisible={setChatHistoryVisible}
onConversationSelected={handleOnConversationSelected}
conversations={conversations}
+ conversationsLoaded={conversationsLoaded}
refetchConversationsState={refetchConversationsState}
onConversationCreate={handleCreateConversation}
isAssistantEnabled={isAssistantEnabled}
@@ -1114,6 +1115,7 @@ const AssistantComponent: React.FC = ({
showAnonymizedValues={showAnonymizedValues}
title={title}
conversations={conversations}
+ conversationsLoaded={conversationsLoaded}
onConversationDeleted={handleOnConversationDeleted}
refetchConversationsState={refetchConversationsState}
/>
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx
index 28cf547b15e7e..fcaf88be2b3e9 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx
@@ -14,6 +14,7 @@ import {
EuiFlexItem,
EuiLink,
EuiBadge,
+ EuiSpacer,
} from '@elastic/eui';
import React, { useCallback, useMemo, useState } from 'react';
import { Conversation, ConversationsBulkActions } from '../../../../..';
@@ -135,12 +136,16 @@ const SystemPromptSettingsManagementComponent = ({
)),
},
+ /* TODO: enable when createdAt is added
{
field: 'createdAt',
name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_CREATED_ON,
},
+ */
{
name: 'Actions',
+ align: 'center',
+ width: '120px',
render: (prompt: Prompt) => {
return (
@@ -178,6 +183,7 @@ const SystemPromptSettingsManagementComponent = ({
+
onEditActionClicked(prompt)}>{prompt?.title}
) : null,
},
+ /* TODO: enable when createdAt is added
{
field: 'createdAt',
name: i18n.QUICK_PROMPTS_TABLE_COLUMN_CREATED_AT,
},
+ */
{
name: i18n.QUICK_PROMPTS_TABLE_COLUMN_ACTIONS,
+ width: '120px',
+ align: 'center',
render: (prompt: QuickPrompt) => {
return (
@@ -139,6 +144,7 @@ const QuickPromptSettingsManagementComponent = ({
+
void;
conversations: Record;
+ conversationsLoaded: boolean;
}
/**
@@ -88,6 +89,7 @@ export const AssistantSettings: React.FC = React.memo(
selectedConversationId: defaultSelectedConversationId,
onConversationSelected,
conversations,
+ conversationsLoaded,
isFlyoutMode,
}) => {
const {
@@ -126,7 +128,7 @@ export const AssistantSettings: React.FC = React.memo(
anonymizationFieldsBulkActions,
setAnonymizationFieldsBulkActions,
setUpdatedAnonymizationData,
- } = useSettingsUpdater(conversations, anonymizationFields);
+ } = useSettingsUpdater(conversations, conversationsLoaded, anonymizationFields);
// Local state for saving previously selected items so tab switching is friendlier
// Conversation Selection State
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_button.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_button.tsx
index 47ca1d78de75d..b9b58dc0764a6 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_button.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_button.tsx
@@ -23,6 +23,7 @@ interface Props {
isDisabled?: boolean;
isFlyoutMode: boolean;
conversations: Record;
+ conversationsLoaded: boolean;
refetchConversationsState: () => Promise;
}
@@ -39,6 +40,7 @@ export const AssistantSettingsButton: React.FC = React.memo(
isFlyoutMode,
onConversationSelected,
conversations,
+ conversationsLoaded,
refetchConversationsState,
}) => {
const { toasts, setSelectedSettingsTab } = useAssistantContext();
@@ -94,6 +96,7 @@ export const AssistantSettingsButton: React.FC = React.memo(
onSave={handleSave}
isFlyoutMode={isFlyoutMode}
conversations={conversations}
+ conversationsLoaded={conversationsLoaded}
/>
)}
>
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
index 2664f01805bf7..ef505a3b4fa1d 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
@@ -13,7 +13,7 @@ import { Conversation, Prompt, QuickPrompt } from '../../..';
import * as i18n from './translations';
import { useAssistantContext } from '../../assistant_context';
import { useSettingsUpdater } from './use_settings_updater/use_settings_updater';
-import { EvaluationSettings, KnowledgeBaseSettings } from '.';
+import { KnowledgeBaseSettings } from '.';
import { useLoadConnectors } from '../../connectorland/use_load_connectors';
import { getDefaultConnector } from '../helpers';
import { useFetchAnonymizationFields } from '../api/anonymization_fields/use_fetch_anonymization_fields';
@@ -22,6 +22,7 @@ import { ConversationSettingsManagement } from '../conversations/converstaion_se
import { QuickPromptSettingsManagement } from '../quick_prompts/quick_prompt_settings_management.tsx';
import { SystemPromptSettingsManagement } from '../prompt_editor/system_prompt/system_prompt_settings_management';
import { AnonymizationSettingsManagement } from '../../data_anonymization/settings/anonomization_settings_management';
+import { EvaluationSettingsManagement } from './evaluation_settings_management';
export const CONNECTORS_TAB = 'CONNECTORS_TAB' as const;
export const CONVERSATIONS_TAB = 'CONVERSATION_TAB' as const;
@@ -33,6 +34,7 @@ export const EVALUATION_TAB = 'EVALUATION_TAB' as const;
interface Props {
conversations: Record;
+ conversationsLoaded: boolean;
selectedConversation: Conversation;
setSelectedConversationId: React.Dispatch>;
isFlyoutMode: boolean;
@@ -48,6 +50,7 @@ export const AssistantSettingsManagement: React.FC = React.memo(
selectedConversation: defaultSelectedConversation,
setSelectedConversationId,
conversations,
+ conversationsLoaded,
isFlyoutMode,
refetchConversations,
}) => {
@@ -92,6 +95,7 @@ export const AssistantSettingsManagement: React.FC = React.memo(
resetSettings,
} = useSettingsUpdater(
conversations,
+ conversationsLoaded,
anonymizationFields ?? { page: 0, perPage: 0, total: 0, data: [] }
);
@@ -109,7 +113,11 @@ export const AssistantSettingsManagement: React.FC = React.memo(
useEffect(() => {
if (selectedConversation != null) {
- setSelectedConversation(conversationSettings[selectedConversation.title]);
+ setSelectedConversation(
+ // conversationSettings has title as key, sometime has id as key
+ conversationSettings[selectedConversation.id] ||
+ conversationSettings[selectedConversation.title]
+ );
}
}, [conversationSettings, selectedConversation]);
@@ -248,8 +256,10 @@ export const AssistantSettingsManagement: React.FC = React.memo(
allSystemPrompts={systemPromptSettings}
assistantStreamingEnabled={assistantStreamingEnabled}
connectors={connectors}
- conversations={conversations}
+ conversationSettings={conversationSettings}
conversationsSettingsBulkActions={conversationsSettingsBulkActions}
+ conversationsLoaded={conversationsLoaded}
+ defaultConnector={defaultConnector}
handleSave={handleSave}
isFlyoutMode={isFlyoutMode}
refetchConversations={refetchConversations}
@@ -306,37 +316,8 @@ export const AssistantSettingsManagement: React.FC = React.memo(
setUpdatedKnowledgeBaseSettings={handleChange(setUpdatedKnowledgeBaseSettings)}
/>
)}
- {selectedSettingsTab === EVALUATION_TAB && }
+ {selectedSettingsTab === EVALUATION_TAB && }
- {/* {hasPendingChanges && (
-
-
-
-
- {i18n.CANCEL}
-
-
-
-
- {i18n.SAVE}
-
-
-
-
- )} */}
>
);
}
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_details/use_evaluation_details.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_details/use_evaluation_details.tsx
new file mode 100644
index 0000000000000..6f877deae07ff
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_details/use_evaluation_details.tsx
@@ -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 { EuiComboBoxOptionOption } from '@elastic/eui';
+import { useCallback, useMemo, useState } from 'react';
+
+const DEFAULT_EVAL_TYPES_OPTIONS = [
+ { label: 'correctness' },
+ { label: 'esql-validator', disabled: true },
+ { label: 'custom', disabled: true },
+];
+
+export interface EvaluationSettings {
+ selectedEvaluationType: Array>;
+ onEvaluationTypeChange: (evaluationType: Array>) => void;
+ onEvaluationTypeOptionsCreate: (searchValue: string) => void;
+ evaluationTypeOptions: Array>;
+ selectedEvaluatorModelOptions: Array>;
+ onEvaluatorModelOptionsChange: (selectedOptions: Array>) => void;
+ evalPrompt: string;
+ onEvalPromptChange: (e: React.ChangeEvent) => void;
+}
+
+export const useEvaluationDetails = (): EvaluationSettings => {
+ // Evaluation
+ // Evaluation Type
+ const [selectedEvaluationType, setSelectedEvaluationType] = useState<
+ Array>
+ >([]);
+ const onEvaluationTypeChange = useCallback(
+ (evaluationType: Array>) => {
+ setSelectedEvaluationType(evaluationType);
+ },
+ [setSelectedEvaluationType]
+ );
+ const onEvaluationTypeOptionsCreate = useCallback(
+ (searchValue: string) => {
+ const normalizedSearchValue = searchValue.trim();
+
+ if (!normalizedSearchValue) {
+ return;
+ }
+
+ setSelectedEvaluationType([{ label: normalizedSearchValue }]);
+ },
+ [setSelectedEvaluationType]
+ );
+ const evaluationTypeOptions = useMemo(() => {
+ return DEFAULT_EVAL_TYPES_OPTIONS;
+ }, []);
+
+ // Eval Model
+ const [selectedEvaluatorModelOptions, setSelectedEvaluatorModelOptions] = useState<
+ Array>
+ >([]);
+ const onEvaluatorModelOptionsChange = useCallback(
+ (selectedOptions: Array>) => {
+ setSelectedEvaluatorModelOptions(selectedOptions);
+ },
+ [setSelectedEvaluatorModelOptions]
+ );
+
+ // Eval Prompt
+ const sampleEvalPrompt: string = `For the below input: \n\n{{input}} \n\na prediction: \n\n{{prediction}} \n\nwas made. How's it stack up against this reference: \n\n{{reference}} \n\nReturn output in a succinct sentence ranking on a simple grading rubric focused on correctness.`;
+ const [evalPrompt, setEvalPrompt] = useState(sampleEvalPrompt);
+ const onEvalPromptChange = useCallback(
+ (e) => {
+ setEvalPrompt(e.target.value);
+ },
+ [setEvalPrompt]
+ );
+
+ return {
+ selectedEvaluationType,
+ onEvaluationTypeChange,
+ onEvaluationTypeOptionsCreate,
+ evaluationTypeOptions,
+ selectedEvaluatorModelOptions,
+ onEvaluatorModelOptionsChange,
+ evalPrompt,
+ onEvalPromptChange,
+ };
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx
index fe4d75be04004..cb0aa0ebe789d 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/evaluation_settings.tsx
@@ -5,10 +5,9 @@
* 2.0.
*/
-import React, { useCallback, useMemo, useState } from 'react';
+import React, { useCallback, useMemo } from 'react';
import {
EuiAccordion,
- euiPaletteComplementary,
EuiFormRow,
EuiTitle,
EuiText,
@@ -16,10 +15,8 @@ import {
EuiSpacer,
EuiComboBox,
EuiButton,
- EuiComboBoxOptionOption,
EuiTextArea,
EuiTextColor,
- EuiFieldText,
EuiFlexItem,
EuiFlexGroup,
EuiLink,
@@ -27,31 +24,43 @@ import {
import { css } from '@emotion/react';
import { FormattedMessage } from '@kbn/i18n-react';
-import type { GetEvaluateResponse, PostEvaluateResponse } from '@kbn/elastic-assistant-common';
+import type { PostEvaluateResponse } from '@kbn/elastic-assistant-common';
import * as i18n from './translations';
import { useAssistantContext } from '../../../assistant_context';
import { useLoadConnectors } from '../../../connectorland/use_load_connectors';
-import { getActionTypeTitle, getGenAiConfig } from '../../../connectorland/helpers';
-import { PRECONFIGURED_CONNECTOR } from '../../../connectorland/translations';
+
import { usePerformEvaluation } from '../../api/evaluate/use_perform_evaluation';
import { getApmLink, getDiscoverLink } from './utils';
-import { useEvaluationData } from '../../api/evaluate/use_evaluation_data';
+import { useRunDetails } from './run_details/use_run_details';
+import { useDataset } from './run_details/use_dataset';
+import { useTraceOptions } from './run_details/use_trace_options';
+import { RunDetailsEditor } from './run_details';
+import { PredictionDetails } from './prediction_details';
+import { usePredictionsDetails } from './prediction_details/use_predictions_details';
+import { useEvaluationDetails } from './evaluation_details/use_evaluation_details';
-const DEFAULT_EVAL_TYPES_OPTIONS = [
- { label: 'correctness' },
- { label: 'esql-validator', disabled: true },
- { label: 'custom', disabled: true },
-];
-const DEFAULT_OUTPUT_INDEX = '.kibana-elastic-ai-assistant-evaluation-results';
+const getSection = (title: string, description: string) => (
+
+
+
+
+ {title}
+
+
+
-interface Props {
- onEvaluationSettingsChange?: () => void;
-}
+
+
+ {description}
+
+
+
+);
/**
* Evaluation Settings -- development-only feature for evaluating models
*/
-export const EvaluationSettings: React.FC = React.memo(({ onEvaluationSettingsChange }) => {
+export const EvaluationSettings: React.FC = React.memo(() => {
const { actionTypeRegistry, basePath, http, setTraceOptions, traceOptions } =
useAssistantContext();
const { data: connectors } = useLoadConnectors({ http });
@@ -62,246 +71,66 @@ export const EvaluationSettings: React.FC = React.memo(({ onEvaluationSet
} = usePerformEvaluation({
http,
});
- const { data: evalData } = useEvaluationData({ http });
- const defaultAgents = useMemo(
- () => (evalData as GetEvaluateResponse)?.agentExecutors ?? [],
- [evalData]
- );
// Run Details
- // Project Name
- const [projectName, setProjectName] = useState();
- const onProjectNameChange = useCallback(
- (e) => {
- setProjectName(e.target.value);
- },
- [setProjectName]
- );
- // Run Name
- const [runName, setRunName] = useState();
- const onRunNameChange = useCallback(
- (e) => {
- setRunName(e.target.value);
- },
- [setRunName]
- );
- // Local Output Index
- const [outputIndex, setOutputIndex] = useState(DEFAULT_OUTPUT_INDEX);
- const onOutputIndexChange = useCallback(
- (e) => {
- setOutputIndex(e.target.value);
- },
- [setOutputIndex]
- );
+ const runDetailsSettings = useRunDetails();
/** Trace Options **/
- const [showTraceOptions, setShowTraceOptions] = useState(false);
- const onApmUrlChange = useCallback(
- (e) => {
- setTraceOptions({ ...traceOptions, apmUrl: e.target.value });
- },
- [setTraceOptions, traceOptions]
- );
- const onLangSmithProjectChange = useCallback(
- (e) => {
- setTraceOptions({ ...traceOptions, langSmithProject: e.target.value });
- },
- [setTraceOptions, traceOptions]
- );
- const onLangSmithApiKeyChange = useCallback(
- (e) => {
- setTraceOptions({ ...traceOptions, langSmithApiKey: e.target.value });
- },
- [setTraceOptions, traceOptions]
- );
+ const tracedOptionsSettings = useTraceOptions({ setTraceOptions, traceOptions });
/** Dataset **/
- const [useLangSmithDataset, setUseLangSmithDataset] = useState(true);
- const datasetToggleButton = useMemo(() => {
- return (
-
- {i18n.EVALUATOR_DATASET_LABEL}
- {' ('}
- setUseLangSmithDataset(true)}
- >
- {i18n.LANGSMITH_DATASET_LABEL}
-
- {' / '}
- setUseLangSmithDataset(false)}
- >
- {i18n.CUSTOM_DATASET_LABEL}
-
- {')'}
-
- );
- }, [useLangSmithDataset]);
- const [datasetName, setDatasetName] = useState();
- const onDatasetNameChange = useCallback(
- (e) => {
- setDatasetName(e.target.value);
- },
- [setDatasetName]
- );
- const sampleDataset = [
- {
- input:
- 'As an expert user of Elastic Security, please generate an accurate and valid ESQL query to detect the use case below. Your response should be formatted to be able to use immediately in an Elastic Security timeline or detection rule. Take your time with the answer, and really make sure you check your knowledge really well on all the functions I am asking for. check it multiple times if you need to. I cannot afford for queries to be inaccurate. Assume I am using the Elastic Common Schema. Ensure the answers are formatted in a way which is easily copyable.\n\n' +
- 'Write an ESQL query for detecting cryptomining activity on an AWS EC2 instance.',
- reference:
- 'FROM metrics-apm*\n| WHERE metricset.name == ""transaction"" AND metricset.interval == ""1m""\n| EVAL bucket = AUTO_BUCKET(transaction.duration.histogram, 50, , )\n| STATS avg_duration = AVG(transaction.duration.histogram) BY bucket',
- },
- ];
- const [datasetText, setDatasetText] = useState(JSON.stringify(sampleDataset, null, 2));
- const onDatasetTextChange = useCallback(
- (e) => {
- setDatasetText(e.target.value);
- },
- [setDatasetText]
- );
+ const datasetSettings = useDataset();
// Predictions
- // Connectors / Models
- const [selectedModelOptions, setSelectedModelOptions] = useState<
- Array>
- >([]);
- const onModelOptionsChange = useCallback(
- (selectedOptions: Array>) => {
- setSelectedModelOptions(selectedOptions);
- },
- [setSelectedModelOptions]
- );
- const visColorsBehindText = euiPaletteComplementary(connectors?.length ?? 0);
- const modelOptions = useMemo(() => {
- return (
- connectors?.map((c, index) => {
- const apiProvider = getGenAiConfig(c)?.apiProvider;
- const connectorTypeTitle =
- apiProvider ?? getActionTypeTitle(actionTypeRegistry.get(c.actionTypeId));
- const connectorDetails = c.isPreconfigured ? PRECONFIGURED_CONNECTOR : connectorTypeTitle;
- return {
- key: c.id,
- label: `${c.name} (${connectorDetails})`,
- color: visColorsBehindText[index],
- };
- }) ?? []
- );
- }, [actionTypeRegistry, connectors, visColorsBehindText]);
-
- // Agents
- const [selectedAgentOptions, setSelectedAgentOptions] = useState<
- Array>
- >([]);
- const onAgentOptionsChange = useCallback(
- (agentOptions: Array>) => {
- setSelectedAgentOptions(agentOptions);
- },
- [setSelectedAgentOptions]
- );
- const onAgentOptionsCreate = useCallback(
- (searchValue: string) => {
- const normalizedSearchValue = searchValue.trim();
-
- if (!normalizedSearchValue) {
- return;
- }
-
- setSelectedAgentOptions([...selectedAgentOptions, { label: normalizedSearchValue }]);
- },
- [selectedAgentOptions]
- );
- const agentOptions = useMemo(() => {
- return defaultAgents.map((label) => ({ label }));
- }, [defaultAgents]);
-
- // Evaluation
- // Evaluation Type
- const [selectedEvaluationType, setSelectedEvaluationType] = useState<
- Array>
- >([]);
- const onEvaluationTypeChange = useCallback(
- (evaluationType: Array>) => {
- setSelectedEvaluationType(evaluationType);
- },
- [setSelectedEvaluationType]
- );
- const onEvaluationTypeOptionsCreate = useCallback(
- (searchValue: string) => {
- const normalizedSearchValue = searchValue.trim();
-
- if (!normalizedSearchValue) {
- return;
- }
-
- setSelectedEvaluationType([{ label: normalizedSearchValue }]);
- },
- [setSelectedEvaluationType]
- );
- const evaluationTypeOptions = useMemo(() => {
- return DEFAULT_EVAL_TYPES_OPTIONS;
- }, []);
-
- // Eval Model
- const [selectedEvaluatorModelOptions, setSelectedEvaluatorModelOptions] = useState<
- Array>
- >([]);
- const onEvaluatorModelOptionsChange = useCallback(
- (selectedOptions: Array>) => {
- setSelectedEvaluatorModelOptions(selectedOptions);
- },
- [setSelectedEvaluatorModelOptions]
- );
+ const predictionsSettings = usePredictionsDetails({
+ http,
+ connectors,
+ actionTypeRegistry,
+ });
- // Eval Prompt
- const sampleEvalPrompt: string = `For the below input: \n\n{{input}} \n\na prediction: \n\n{{prediction}} \n\nwas made. How's it stack up against this reference: \n\n{{reference}} \n\nReturn output in a succinct sentence ranking on a simple grading rubric focused on correctness.`;
- const [evalPrompt, setEvalPrompt] = useState(sampleEvalPrompt);
- const onEvalPromptChange = useCallback(
- (e) => {
- setEvalPrompt(e.target.value);
- },
- [setEvalPrompt]
- );
+ const {
+ selectedEvaluationType,
+ onEvaluationTypeChange,
+ onEvaluationTypeOptionsCreate,
+ evaluationTypeOptions,
+ selectedEvaluatorModelOptions,
+ onEvaluatorModelOptionsChange,
+ evalPrompt,
+ onEvalPromptChange,
+ } = useEvaluationDetails();
// Required fields by eval API
const isPerformEvaluationDisabled =
- selectedModelOptions.length === 0 ||
- selectedAgentOptions.length === 0 ||
- outputIndex.length === 0;
+ predictionsSettings.selectedModelOptions.length === 0 ||
+ predictionsSettings.selectedAgentOptions.length === 0 ||
+ runDetailsSettings.outputIndex.length === 0;
// Perform Evaluation Button
const handlePerformEvaluation = useCallback(async () => {
const evalParams = {
- models: selectedModelOptions.flatMap((option) => option.key ?? []),
- agents: selectedAgentOptions.map((option) => option.label),
- dataset: useLangSmithDataset ? undefined : datasetText,
- datasetName: useLangSmithDataset ? datasetName : undefined,
+ models: predictionsSettings.selectedModelOptions.flatMap((option) => option.key ?? []),
+ agents: predictionsSettings.selectedAgentOptions.map((option) => option.label),
+ dataset: datasetSettings.useLangSmithDataset ? undefined : datasetSettings.datasetText,
+ datasetName: datasetSettings.useLangSmithDataset ? datasetSettings.datasetName : undefined,
evalModel: selectedEvaluatorModelOptions.flatMap((option) => option.key ?? []),
evalPrompt,
evaluationType: selectedEvaluationType.map((option) => option.label),
- outputIndex,
- projectName,
- runName,
+ outputIndex: runDetailsSettings.outputIndex,
+ projectName: runDetailsSettings.projectName,
+ runName: runDetailsSettings.runName,
};
performEvaluation(evalParams);
}, [
- datasetName,
- datasetText,
+ datasetSettings.datasetName,
+ datasetSettings.datasetText,
+ datasetSettings.useLangSmithDataset,
evalPrompt,
- outputIndex,
performEvaluation,
- projectName,
- runName,
- selectedAgentOptions,
+ predictionsSettings.selectedAgentOptions,
+ predictionsSettings.selectedModelOptions,
+ runDetailsSettings.outputIndex,
+ runDetailsSettings.projectName,
+ runDetailsSettings.runName,
selectedEvaluationType,
selectedEvaluatorModelOptions,
- selectedModelOptions,
- useLangSmithDataset,
]);
const discoverLink = useMemo(
@@ -314,24 +143,6 @@ export const EvaluationSettings: React.FC = React.memo(({ onEvaluationSet
[basePath, evalResponse]
);
- const getSection = (title: string, description: string) => (
-
-
-
-
- {title}
-
-
-
-
-
-
- {description}
-
-
-
- );
-
const runDetailsSection = useMemo(
() => getSection(i18n.RUN_DETAILS_TITLE, i18n.RUN_DETAILS_DESCRIPTION),
[]
@@ -369,134 +180,11 @@ export const EvaluationSettings: React.FC = React.memo(({ onEvaluationSet
initialIsOpen={true}
paddingSize="s"
>
-
-
-
-
-
-
-
-
-
-
-
-
-
- {useLangSmithDataset ? (
-
- ) : (
-
- )}
-
-
-
-
-
- setShowTraceOptions(!showTraceOptions)}>
- {i18n.SHOW_TRACE_OPTIONS}
-
-
- {showTraceOptions && (
- <>
-
-
-
-
-
-
-
-
-
- >
- )}
+
{/* Prediction Details*/}
@@ -509,34 +197,7 @@ export const EvaluationSettings: React.FC = React.memo(({ onEvaluationSet
initialIsOpen={true}
paddingSize="s"
>
-
-
-
-
-
-
-
+
{/* Evaluation Details*/}
@@ -556,7 +217,7 @@ export const EvaluationSettings: React.FC = React.memo(({ onEvaluationSet
= React.memo(({ predictionsSettings }) => {
+ const {
+ modelOptions,
+ selectedModelOptions,
+ onModelOptionsChange,
+ agentOptions,
+ selectedAgentOptions,
+ onAgentOptionsChange,
+ onAgentOptionsCreate,
+ } = predictionsSettings;
+ return (
+ <>
+
+
+
+
+
+
+
+ >
+ );
+});
+
+PredictionDetails.displayName = 'PredictionDetails';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/prediction_details/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/prediction_details/translations.ts
new file mode 100644
index 0000000000000..bf0f07714ec3c
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/prediction_details/translations.ts
@@ -0,0 +1,35 @@
+/*
+ * 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 CONNECTORS_LABEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.connectorsLabel',
+ {
+ defaultMessage: 'Connectors / Models',
+ }
+);
+
+export const CONNECTORS_DESCRIPTION = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.connectorsDescription',
+ {
+ defaultMessage: 'Select whichever models you want to evaluate the dataset against',
+ }
+);
+
+export const AGENTS_LABEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.agentsLabel',
+ {
+ defaultMessage: 'Agents',
+ }
+);
+
+export const AGENTS_DESCRIPTION = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.agentsDescription',
+ {
+ defaultMessage: 'Select the agents (i.e. RAG algos) to evaluate the dataset against',
+ }
+);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/prediction_details/use_predictions_details.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/prediction_details/use_predictions_details.tsx
new file mode 100644
index 0000000000000..4b41bb38a75a4
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/prediction_details/use_predictions_details.tsx
@@ -0,0 +1,108 @@
+/*
+ * 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 { EuiComboBoxOptionOption, euiPaletteComplementary } from '@elastic/eui';
+import { useCallback, useState, useMemo } from 'react';
+import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public';
+import { HttpSetup } from '@kbn/core/public';
+import type { GetEvaluateResponse } from '@kbn/elastic-assistant-common';
+import { AIConnector } from '../../../../connectorland/connector_selector';
+import { getActionTypeTitle, getGenAiConfig } from '../../../../connectorland/helpers';
+import { PRECONFIGURED_CONNECTOR } from '../../../../connectorland/translations';
+import { useEvaluationData } from '../../../api/evaluate/use_evaluation_data';
+
+interface Props {
+ actionTypeRegistry: ActionTypeRegistryContract;
+ connectors: AIConnector[] | undefined;
+ http: HttpSetup;
+}
+
+export interface PredictionsSettings {
+ modelOptions: Array>;
+ selectedModelOptions: Array>;
+ onModelOptionsChange: (selectedOptions: Array>) => void;
+ agentOptions: Array>;
+ selectedAgentOptions: Array>;
+ onAgentOptionsChange: (agentOptions: Array>) => void;
+ onAgentOptionsCreate: (searchValue: string) => void;
+}
+
+export const usePredictionsDetails = ({
+ http,
+ connectors,
+ actionTypeRegistry,
+}: Props): PredictionsSettings => {
+ const { data: evalData } = useEvaluationData({ http });
+ const defaultAgents = useMemo(
+ () => (evalData as GetEvaluateResponse)?.agentExecutors ?? [],
+ [evalData]
+ );
+
+ // Predictions
+ // Connectors / Models
+ const [selectedModelOptions, setSelectedModelOptions] = useState<
+ Array>
+ >([]);
+ const onModelOptionsChange = useCallback(
+ (selectedOptions: Array>) => {
+ setSelectedModelOptions(selectedOptions);
+ },
+ [setSelectedModelOptions]
+ );
+ const visColorsBehindText = euiPaletteComplementary(connectors?.length ?? 0);
+ const modelOptions = useMemo(() => {
+ return (
+ connectors?.map((c, index) => {
+ const apiProvider = getGenAiConfig(c)?.apiProvider;
+ const connectorTypeTitle =
+ apiProvider ?? getActionTypeTitle(actionTypeRegistry.get(c.actionTypeId));
+ const connectorDetails = c.isPreconfigured ? PRECONFIGURED_CONNECTOR : connectorTypeTitle;
+ return {
+ key: c.id,
+ label: `${c.name} (${connectorDetails})`,
+ color: visColorsBehindText[index],
+ };
+ }) ?? []
+ );
+ }, [actionTypeRegistry, connectors, visColorsBehindText]);
+
+ // Agents
+ const [selectedAgentOptions, setSelectedAgentOptions] = useState<
+ Array>
+ >([]);
+ const onAgentOptionsChange = useCallback(
+ (agentOptions: Array>) => {
+ setSelectedAgentOptions(agentOptions);
+ },
+ [setSelectedAgentOptions]
+ );
+ const onAgentOptionsCreate = useCallback(
+ (searchValue: string) => {
+ const normalizedSearchValue = searchValue.trim();
+
+ if (!normalizedSearchValue) {
+ return;
+ }
+
+ setSelectedAgentOptions([...selectedAgentOptions, { label: normalizedSearchValue }]);
+ },
+ [selectedAgentOptions]
+ );
+ const agentOptions = useMemo(() => {
+ return defaultAgents.map((label) => ({ label }));
+ }, [defaultAgents]);
+
+ return {
+ modelOptions,
+ selectedModelOptions,
+ onModelOptionsChange,
+ agentOptions,
+ selectedAgentOptions,
+ onAgentOptionsChange,
+ onAgentOptionsCreate,
+ };
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/data_set_toggle_button.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/data_set_toggle_button.tsx
new file mode 100644
index 0000000000000..b877fcd201a29
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/data_set_toggle_button.tsx
@@ -0,0 +1,44 @@
+/*
+ * 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 { EuiLink, EuiText } from '@elastic/eui';
+import React from 'react';
+import { css } from '@emotion/react';
+
+import * as i18n from './translations';
+
+interface Props {
+ useLangSmithDataset: boolean;
+ onUseLangSmith: () => void;
+ onUseCustom: () => void;
+}
+
+export const DatasetToggleButton: React.FC = React.memo(
+ ({ useLangSmithDataset, onUseLangSmith, onUseCustom }) => {
+ return (
+
+ {i18n.EVALUATOR_DATASET_LABEL}
+ {' ('}
+ onUseLangSmith()}>
+ {i18n.LANGSMITH_DATASET_LABEL}
+
+ {' / '}
+ onUseCustom()}>
+ {i18n.CUSTOM_DATASET_LABEL}
+
+ {')'}
+
+ );
+ }
+);
+
+DatasetToggleButton.displayName = 'DatasetToggleButton';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/index.tsx
new file mode 100644
index 0000000000000..2962cb4fcc8ca
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/index.tsx
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+/*
+ * 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 {
+ EuiFormRow,
+ EuiText,
+ EuiTextArea,
+ EuiFieldText,
+ EuiFlexItem,
+ EuiFlexGroup,
+ EuiLink,
+} from '@elastic/eui';
+
+import { css } from '@emotion/react';
+
+import * as i18n from './translations';
+import { DatasetToggleButton } from './data_set_toggle_button';
+import { RunDetailsSettings } from './use_run_details';
+import { DataSetSettings } from './use_dataset';
+import { TraceOptionsSettings } from './use_trace_options';
+
+/**
+ * Evaluation Settings -- development-only feature for evaluating models
+ */
+interface Props {
+ runDetailsSettings: RunDetailsSettings;
+ datasetSettings: DataSetSettings;
+ traceOptionsSettings: TraceOptionsSettings;
+}
+
+export const RunDetailsEditor: React.FC = React.memo(
+ ({ runDetailsSettings, datasetSettings, traceOptionsSettings }) => {
+ const {
+ projectName,
+ onProjectNameChange,
+ runName,
+ onRunNameChange,
+ outputIndex,
+ onOutputIndexChange,
+ } = runDetailsSettings;
+
+ const {
+ onUseLangSmith,
+ onUseCustom,
+ useLangSmithDataset,
+ datasetName,
+ onDatasetNameChange,
+ datasetText,
+ onDatasetTextChange,
+ } = datasetSettings;
+
+ const {
+ showTraceOptions,
+ setShowTraceOptions,
+ traceOptions,
+ onApmUrlChange,
+ onLangSmithProjectChange,
+ onLangSmithApiKeyChange,
+ } = traceOptionsSettings;
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ fullWidth
+ helpText={
+ useLangSmithDataset
+ ? i18n.LANGSMITH_DATASET_DESCRIPTION
+ : i18n.CUSTOM_DATASET_DESCRIPTION
+ }
+ >
+ {useLangSmithDataset ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+ setShowTraceOptions(!showTraceOptions)}>
+ {i18n.SHOW_TRACE_OPTIONS}
+
+
+ {showTraceOptions && (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ )}
+ >
+ );
+ }
+);
+
+RunDetailsEditor.displayName = 'RunDetailsEditor';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/translations.ts
new file mode 100644
index 0000000000000..3f62bd40a520e
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/translations.ts
@@ -0,0 +1,158 @@
+/*
+ * 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 SHOW_TRACE_OPTIONS = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.showTraceOptionsLabel',
+ {
+ defaultMessage: 'Show Trace Options (for internal use only)',
+ }
+);
+
+export const APM_URL_LABEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.apmUrlLabel',
+ {
+ defaultMessage: 'APM URL',
+ }
+);
+
+export const APM_URL_DESCRIPTION = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.apmUrlDescription',
+ {
+ defaultMessage:
+ 'URL for the Kibana APM app. Used to link to APM traces for evaluation results. Defaults to "$\\{basePath\\}/app/apm"',
+ }
+);
+
+export const EVALUATOR_DATASET_LABEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorDatasetLabel',
+ {
+ defaultMessage: 'Dataset',
+ }
+);
+
+export const LANGSMITH_DATASET_LABEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langsmithDatasetLabel',
+ {
+ defaultMessage: 'LangSmith',
+ }
+);
+
+export const LANGSMITH_DATASET_DESCRIPTION = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langsmithDatasetDescription',
+ {
+ defaultMessage: 'Name of dataset hosted on LangSmith to evaluate',
+ }
+);
+
+export const LANGSMITH_DATASET_PLACEHOLDER = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langsmithDatasetPlaceholder',
+ {
+ defaultMessage: 'ESQL Query Generation',
+ }
+);
+
+export const LANGSMITH_PROJECT_LABEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langSmithProjectLabel',
+ {
+ defaultMessage: 'LangSmith Project',
+ }
+);
+
+export const LANGSMITH_PROJECT_DESCRIPTION = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langSmithProjectDescription',
+ {
+ defaultMessage: 'LangSmith Project to write traces to',
+ }
+);
+
+export const LANGSMITH_API_KEY_LABEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langSmithApiKeyLabel',
+ {
+ defaultMessage: 'LangSmith API Key',
+ }
+);
+
+export const LANGSMITH_API_KEY_DESCRIPTION = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langSmithApiKeyDescription',
+ {
+ defaultMessage:
+ 'API Key for writing traces to LangSmith. Stored in Session Storage. Close tab to clear session.',
+ }
+);
+
+export const CUSTOM_DATASET_LABEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.customDatasetLabel',
+ {
+ defaultMessage: 'Custom',
+ }
+);
+
+export const CUSTOM_DATASET_DESCRIPTION = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.customDatasetDescription',
+ {
+ defaultMessage:
+ 'Custom dataset to evaluate. Array of objects with "input" and "references" properties',
+ }
+);
+
+export const EVALUATOR_OUTPUT_INDEX_LABEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorOutputIndexLabel',
+ {
+ defaultMessage: 'Output index',
+ }
+);
+
+export const EVALUATOR_OUTPUT_INDEX_DESCRIPTION = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorOutputIndexDescription',
+ {
+ defaultMessage:
+ 'Index to write results to. Must be prefixed with ".kibana-elastic-ai-assistant-"',
+ }
+);
+
+export const PROJECT_LABEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.projectLabel',
+ {
+ defaultMessage: 'Project',
+ }
+);
+
+export const PROJECT_DESCRIPTION = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.projectDescription',
+ {
+ defaultMessage: 'LangSmith project to write results to',
+ }
+);
+
+export const PROJECT_PLACEHOLDER = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.projectPlaceholder',
+ {
+ defaultMessage: '8.12 Testing',
+ }
+);
+
+export const RUN_NAME_LABEL = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.runNameLabel',
+ {
+ defaultMessage: 'Run name',
+ }
+);
+
+export const RUN_NAME_DESCRIPTION = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.runNameDescription',
+ {
+ defaultMessage: 'Name for this specific test run',
+ }
+);
+
+export const RUN_NAME_PLACEHOLDER = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettings.runNamePlaceholder',
+ {
+ defaultMessage: '8.12 ESQL Query Generation',
+ }
+);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/use_dataset.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/use_dataset.tsx
new file mode 100644
index 0000000000000..0959096d92c9a
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/use_dataset.tsx
@@ -0,0 +1,64 @@
+/*
+ * 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 { useCallback, useState } from 'react';
+
+export interface DataSetSettings {
+ onUseLangSmith: () => void;
+ onUseCustom: () => void;
+ useLangSmithDataset: boolean;
+ datasetName: string | undefined;
+ onDatasetNameChange: (e: React.ChangeEvent) => void;
+ datasetText: string;
+ onDatasetTextChange: (e: React.ChangeEvent) => void;
+}
+
+export const useDataset = (): DataSetSettings => {
+ /** Dataset **/
+ const [useLangSmithDataset, setUseLangSmithDataset] = useState(true);
+
+ const [datasetName, setDatasetName] = useState();
+ const onDatasetNameChange = useCallback(
+ (e) => {
+ setDatasetName(e.target.value);
+ },
+ [setDatasetName]
+ );
+ const sampleDataset = [
+ {
+ input:
+ 'As an expert user of Elastic Security, please generate an accurate and valid ESQL query to detect the use case below. Your response should be formatted to be able to use immediately in an Elastic Security timeline or detection rule. Take your time with the answer, and really make sure you check your knowledge really well on all the functions I am asking for. check it multiple times if you need to. I cannot afford for queries to be inaccurate. Assume I am using the Elastic Common Schema. Ensure the answers are formatted in a way which is easily copyable.\n\n' +
+ 'Write an ESQL query for detecting cryptomining activity on an AWS EC2 instance.',
+ reference:
+ 'FROM metrics-apm*\n| WHERE metricset.name == ""transaction"" AND metricset.interval == ""1m""\n| EVAL bucket = AUTO_BUCKET(transaction.duration.histogram, 50, , )\n| STATS avg_duration = AVG(transaction.duration.histogram) BY bucket',
+ },
+ ];
+ const [datasetText, setDatasetText] = useState(JSON.stringify(sampleDataset, null, 2));
+ const onDatasetTextChange = useCallback(
+ (e) => {
+ setDatasetText(e.target.value);
+ },
+ [setDatasetText]
+ );
+
+ const onUseLangSmith = useCallback(() => {
+ setUseLangSmithDataset(true);
+ }, []);
+
+ const onUseCustom = useCallback(() => {
+ setUseLangSmithDataset(false);
+ }, []);
+
+ return {
+ onUseLangSmith,
+ onUseCustom,
+ useLangSmithDataset,
+ datasetName,
+ onDatasetNameChange,
+ datasetText,
+ onDatasetTextChange,
+ };
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/use_run_details.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/use_run_details.tsx
new file mode 100644
index 0000000000000..7b594ac55af33
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/use_run_details.tsx
@@ -0,0 +1,55 @@
+/*
+ * 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 { useCallback, useState } from 'react';
+
+const DEFAULT_OUTPUT_INDEX = '.kibana-elastic-ai-assistant-evaluation-results';
+
+export interface RunDetailsSettings {
+ projectName: string | undefined;
+ onProjectNameChange: (e: React.ChangeEvent) => void;
+ runName: string | undefined;
+ onRunNameChange: (e: React.ChangeEvent) => void;
+ outputIndex: string;
+ onOutputIndexChange: (e: React.ChangeEvent) => void;
+}
+
+export const useRunDetails = (): RunDetailsSettings => {
+ // Run Details
+ // Project Name
+ const [projectName, setProjectName] = useState();
+ const onProjectNameChange = useCallback(
+ (e) => {
+ setProjectName(e.target.value);
+ },
+ [setProjectName]
+ );
+ // Run Name
+ const [runName, setRunName] = useState();
+ const onRunNameChange = useCallback(
+ (e) => {
+ setRunName(e.target.value);
+ },
+ [setRunName]
+ );
+ // Local Output Index
+ const [outputIndex, setOutputIndex] = useState(DEFAULT_OUTPUT_INDEX);
+ const onOutputIndexChange = useCallback(
+ (e) => {
+ setOutputIndex(e.target.value);
+ },
+ [setOutputIndex]
+ );
+
+ return {
+ projectName,
+ onProjectNameChange,
+ runName,
+ onRunNameChange,
+ outputIndex,
+ onOutputIndexChange,
+ };
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/use_trace_options.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/use_trace_options.tsx
new file mode 100644
index 0000000000000..be25925d71776
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/run_details/use_trace_options.tsx
@@ -0,0 +1,54 @@
+/*
+ * 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 { useCallback, useState } from 'react';
+import { UseAssistantContext } from '../../../../assistant_context';
+
+interface Props {
+ setTraceOptions: UseAssistantContext['setTraceOptions'];
+ traceOptions: UseAssistantContext['traceOptions'];
+}
+
+export interface TraceOptionsSettings {
+ showTraceOptions: boolean;
+ setShowTraceOptions: (value: boolean) => void;
+ traceOptions: UseAssistantContext['traceOptions'];
+ onApmUrlChange: (e: React.ChangeEvent) => void;
+ onLangSmithProjectChange: (e: React.ChangeEvent) => void;
+ onLangSmithApiKeyChange: (e: React.ChangeEvent) => void;
+}
+
+export const useTraceOptions = ({ setTraceOptions, traceOptions }: Props): TraceOptionsSettings => {
+ /** Trace Options **/
+ const [showTraceOptions, setShowTraceOptions] = useState(false);
+ const onApmUrlChange = useCallback(
+ (e) => {
+ setTraceOptions({ ...traceOptions, apmUrl: e.target.value });
+ },
+ [setTraceOptions, traceOptions]
+ );
+ const onLangSmithProjectChange = useCallback(
+ (e) => {
+ setTraceOptions({ ...traceOptions, langSmithProject: e.target.value });
+ },
+ [setTraceOptions, traceOptions]
+ );
+ const onLangSmithApiKeyChange = useCallback(
+ (e) => {
+ setTraceOptions({ ...traceOptions, langSmithApiKey: e.target.value });
+ },
+ [setTraceOptions, traceOptions]
+ );
+
+ return {
+ showTraceOptions,
+ setShowTraceOptions,
+ traceOptions,
+ onApmUrlChange,
+ onLangSmithProjectChange,
+ onLangSmithApiKeyChange,
+ };
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts
index 1b670384696c3..be33991b0178d 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings/translations.ts
@@ -65,76 +65,6 @@ export const EVALUATION_DETAILS_DESCRIPTION = i18n.translate(
}
);
-export const PROJECT_LABEL = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.projectLabel',
- {
- defaultMessage: 'Project',
- }
-);
-
-export const PROJECT_DESCRIPTION = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.projectDescription',
- {
- defaultMessage: 'LangSmith project to write results to',
- }
-);
-
-export const PROJECT_PLACEHOLDER = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.projectPlaceholder',
- {
- defaultMessage: '8.12 Testing',
- }
-);
-
-export const RUN_NAME_LABEL = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.runNameLabel',
- {
- defaultMessage: 'Run name',
- }
-);
-
-export const RUN_NAME_DESCRIPTION = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.runNameDescription',
- {
- defaultMessage: 'Name for this specific test run',
- }
-);
-
-export const RUN_NAME_PLACEHOLDER = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.runNamePlaceholder',
- {
- defaultMessage: '8.12 ESQL Query Generation',
- }
-);
-
-export const CONNECTORS_LABEL = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.connectorsLabel',
- {
- defaultMessage: 'Connectors / Models',
- }
-);
-
-export const CONNECTORS_DESCRIPTION = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.connectorsDescription',
- {
- defaultMessage: 'Select whichever models you want to evaluate the dataset against',
- }
-);
-
-export const AGENTS_LABEL = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.agentsLabel',
- {
- defaultMessage: 'Agents',
- }
-);
-
-export const AGENTS_DESCRIPTION = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.agentsDescription',
- {
- defaultMessage: 'Select the agents (i.e. RAG algos) to evaluate the dataset against',
- }
-);
-
export const EVALUATOR_MODEL_LABEL = i18n.translate(
'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorModelLabel',
{
@@ -178,114 +108,6 @@ export const EVALUATION_PROMPT_DESCRIPTION = i18n.translate(
'Prompt template given `input`, `reference` and `prediction` template variables',
}
);
-export const EVALUATOR_OUTPUT_INDEX_LABEL = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorOutputIndexLabel',
- {
- defaultMessage: 'Output index',
- }
-);
-
-export const EVALUATOR_OUTPUT_INDEX_DESCRIPTION = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorOutputIndexDescription',
- {
- defaultMessage:
- 'Index to write results to. Must be prefixed with ".kibana-elastic-ai-assistant-"',
- }
-);
-
-export const SHOW_TRACE_OPTIONS = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.showTraceOptionsLabel',
- {
- defaultMessage: 'Show Trace Options (for internal use only)',
- }
-);
-
-export const APM_URL_LABEL = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.apmUrlLabel',
- {
- defaultMessage: 'APM URL',
- }
-);
-
-export const APM_URL_DESCRIPTION = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.apmUrlDescription',
- {
- defaultMessage:
- 'URL for the Kibana APM app. Used to link to APM traces for evaluation results. Defaults to "$\\{basePath\\}/app/apm"',
- }
-);
-
-export const LANGSMITH_PROJECT_LABEL = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langSmithProjectLabel',
- {
- defaultMessage: 'LangSmith Project',
- }
-);
-
-export const LANGSMITH_PROJECT_DESCRIPTION = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langSmithProjectDescription',
- {
- defaultMessage: 'LangSmith Project to write traces to',
- }
-);
-
-export const LANGSMITH_API_KEY_LABEL = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langSmithApiKeyLabel',
- {
- defaultMessage: 'LangSmith API Key',
- }
-);
-
-export const LANGSMITH_API_KEY_DESCRIPTION = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langSmithApiKeyDescription',
- {
- defaultMessage:
- 'API Key for writing traces to LangSmith. Stored in Session Storage. Close tab to clear session.',
- }
-);
-
-export const EVALUATOR_DATASET_LABEL = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.evaluatorDatasetLabel',
- {
- defaultMessage: 'Dataset',
- }
-);
-
-export const LANGSMITH_DATASET_LABEL = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langsmithDatasetLabel',
- {
- defaultMessage: 'LangSmith',
- }
-);
-
-export const LANGSMITH_DATASET_DESCRIPTION = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langsmithDatasetDescription',
- {
- defaultMessage: 'Name of dataset hosted on LangSmith to evaluate',
- }
-);
-
-export const LANGSMITH_DATASET_PLACEHOLDER = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.langsmithDatasetPlaceholder',
- {
- defaultMessage: 'ESQL Query Generation',
- }
-);
-
-export const CUSTOM_DATASET_LABEL = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.customDatasetLabel',
- {
- defaultMessage: 'Custom',
- }
-);
-
-export const CUSTOM_DATASET_DESCRIPTION = i18n.translate(
- 'xpack.elasticAssistant.assistant.settings.evaluationSettings.customDatasetDescription',
- {
- defaultMessage:
- 'Custom dataset to evaluate. Array of objects with "input" and "references" properties',
- }
-);
export const PERFORM_EVALUATION = i18n.translate(
'xpack.elasticAssistant.assistant.settings.evaluationSettings.performEvaluationTitle',
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings_management/index.tsx
new file mode 100644
index 0000000000000..cb8c8ea8983f2
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings_management/index.tsx
@@ -0,0 +1,291 @@
+/*
+ * 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, { useCallback, useMemo } from 'react';
+import {
+ EuiAccordion,
+ EuiFormRow,
+ EuiTitle,
+ EuiText,
+ EuiHorizontalRule,
+ EuiSpacer,
+ EuiComboBox,
+ EuiButton,
+ EuiTextArea,
+ EuiFlexItem,
+ EuiFlexGroup,
+ EuiLink,
+} from '@elastic/eui';
+
+import { css } from '@emotion/react';
+import { FormattedMessage } from '@kbn/i18n-react';
+import type { PostEvaluateResponse } from '@kbn/elastic-assistant-common';
+import { useAssistantContext } from '../../../assistant_context';
+import { useLoadConnectors } from '../../../connectorland/use_load_connectors';
+
+import { usePerformEvaluation } from '../../api/evaluate/use_perform_evaluation';
+import { getApmLink, getDiscoverLink } from '../evaluation_settings/utils';
+import { useEvaluationDetails } from '../evaluation_settings/evaluation_details/use_evaluation_details';
+import { useRunDetails } from '../evaluation_settings/run_details/use_run_details';
+import { useTraceOptions } from '../evaluation_settings/run_details/use_trace_options';
+import { useDataset } from '../evaluation_settings/run_details/use_dataset';
+import { usePredictionsDetails } from '../evaluation_settings/prediction_details/use_predictions_details';
+import * as i18n from '../evaluation_settings/translations';
+import { RunDetailsEditor } from '../evaluation_settings/run_details';
+import { PredictionDetails } from '../evaluation_settings/prediction_details';
+import {
+ EVALUATION_DETAILS_TITLE,
+ PREDICTION_DETAILS_TITLE,
+ RUN_DETAILS_TITLE,
+} from './translations';
+
+const getSection = (title: string, description?: string) => (
+ <>
+
+ {title}
+
+
+ {description && {description}}
+
+ >
+);
+
+export const EvaluationSettingsManagement: React.FC = React.memo(() => {
+ const { actionTypeRegistry, basePath, http, setTraceOptions, traceOptions } =
+ useAssistantContext();
+ const { data: connectors } = useLoadConnectors({ http });
+ const {
+ data: evalResponse,
+ mutate: performEvaluation,
+ isLoading: isPerformingEvaluation,
+ } = usePerformEvaluation({
+ http,
+ });
+
+ // Run Details
+ const runDetailsSettings = useRunDetails();
+ /** Trace Options **/
+ const tracedOptionsSettings = useTraceOptions({ setTraceOptions, traceOptions });
+ /** Dataset **/
+ const datasetSettings = useDataset();
+ // Predictions
+ const predictionsSettings = usePredictionsDetails({
+ http,
+ connectors,
+ actionTypeRegistry,
+ });
+
+ const {
+ selectedEvaluationType,
+ onEvaluationTypeChange,
+ onEvaluationTypeOptionsCreate,
+ evaluationTypeOptions,
+ selectedEvaluatorModelOptions,
+ onEvaluatorModelOptionsChange,
+ evalPrompt,
+ onEvalPromptChange,
+ } = useEvaluationDetails();
+
+ // Required fields by eval API
+ const isPerformEvaluationDisabled =
+ predictionsSettings.selectedModelOptions.length === 0 ||
+ predictionsSettings.selectedAgentOptions.length === 0 ||
+ runDetailsSettings.outputIndex.length === 0;
+
+ // Perform Evaluation Button
+ const handlePerformEvaluation = useCallback(async () => {
+ const evalParams = {
+ models: predictionsSettings.selectedModelOptions.flatMap((option) => option.key ?? []),
+ agents: predictionsSettings.selectedAgentOptions.map((option) => option.label),
+ dataset: datasetSettings.useLangSmithDataset ? undefined : datasetSettings.datasetText,
+ datasetName: datasetSettings.useLangSmithDataset ? datasetSettings.datasetName : undefined,
+ evalModel: selectedEvaluatorModelOptions.flatMap((option) => option.key ?? []),
+ evalPrompt,
+ evaluationType: selectedEvaluationType.map((option) => option.label),
+ outputIndex: runDetailsSettings.outputIndex,
+ projectName: runDetailsSettings.projectName,
+ runName: runDetailsSettings.runName,
+ };
+ performEvaluation(evalParams);
+ }, [
+ datasetSettings.datasetName,
+ datasetSettings.datasetText,
+ datasetSettings.useLangSmithDataset,
+ evalPrompt,
+ performEvaluation,
+ predictionsSettings.selectedAgentOptions,
+ predictionsSettings.selectedModelOptions,
+ runDetailsSettings.outputIndex,
+ runDetailsSettings.projectName,
+ runDetailsSettings.runName,
+ selectedEvaluationType,
+ selectedEvaluatorModelOptions,
+ ]);
+
+ const discoverLink = useMemo(
+ () => getDiscoverLink(basePath, (evalResponse as PostEvaluateResponse)?.evaluationId ?? ''),
+ [basePath, evalResponse]
+ );
+
+ const apmLink = useMemo(
+ () => getApmLink(basePath, (evalResponse as PostEvaluateResponse)?.evaluationId ?? ''),
+ [basePath, evalResponse]
+ );
+
+ const runDetailsSection = useMemo(
+ () => getSection(RUN_DETAILS_TITLE, i18n.RUN_DETAILS_DESCRIPTION),
+ []
+ );
+ const predictionDetailsSection = useMemo(
+ () => getSection(PREDICTION_DETAILS_TITLE, i18n.PREDICTION_DETAILS_DESCRIPTION),
+ []
+ );
+ const evalDetailsSection = useMemo(() => getSection(EVALUATION_DETAILS_TITLE), []);
+
+ const buttonCss = css`
+ &:hover {
+ text-decoration: none;
+ }
+ `;
+
+ return (
+ <>
+
+ {i18n.SETTINGS_TITLE}
+
+
+ {i18n.SETTINGS_DESCRIPTION}
+
+ {/* Run Details*/}
+
+
+
+
+ {/* Prediction Details*/}
+
+
+
+
+ {/* Evaluation Details*/}
+
+
+
+
+
+
+
+
+
+ {i18n.PERFORM_EVALUATION}
+
+
+
+
+
+ {i18n.EVALUATOR_FUN_FACT_DISCOVER_LINK}
+
+ ),
+ apm: (
+
+ {i18n.EVALUATOR_FUN_FACT_APM_LINK}
+
+ ),
+ }}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+});
+EvaluationSettingsManagement.displayName = 'EvaluationSettingsManagement';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings_management/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings_management/translations.ts
new file mode 100644
index 0000000000000..ebec3c45c4bdc
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/evaluation_settings_management/translations.ts
@@ -0,0 +1,28 @@
+/*
+ * 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 RUN_DETAILS_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettingsManagement.runDetailsTitle',
+ {
+ defaultMessage: 'Run Details',
+ }
+);
+
+export const PREDICTION_DETAILS_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettingsManagement.predictionDetailsTitle',
+ {
+ defaultMessage: 'Predictions',
+ }
+);
+
+export const EVALUATION_DETAILS_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.evaluationSettingsManagement.evaluationDetailsTitle',
+ {
+ defaultMessage: 'Evaluation (Optional)',
+ }
+);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.tsx
index 1e1c3b0b026d6..a4c0959b57ff9 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.tsx
@@ -46,6 +46,7 @@ interface UseSettingsUpdater {
export const useSettingsUpdater = (
conversations: Record,
+ conversationsLoaded: boolean,
anonymizationFields: FindAnonymizationFieldsResponse
): UseSettingsUpdater => {
// Initial state from assistant context
@@ -188,6 +189,12 @@ export const useSettingsUpdater = (
anonymizationFieldsBulkActions.update?.length,
]);
+ useEffect(() => {
+ if (conversationsLoaded) {
+ setConversationSettings(conversations);
+ }
+ }, [conversations, conversationsLoaded]);
+
return {
conversationSettings,
conversationsSettingsBulkActions,
diff --git a/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx b/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx
index 0a098b4900c77..c648f8f6a50c6 100644
--- a/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx
+++ b/x-pack/plugins/security_solution/public/assistant/stack_management/management_settings.tsx
@@ -32,7 +32,11 @@ export const ManagementSettings = React.memo(() => {
mergeBaseWithPersistedConversations(baseConversations, conversationsData),
[baseConversations]
);
- const { data: conversations, refetch: refetchConversations } = useFetchCurrentUserConversations({
+ const {
+ data: conversations,
+ refetch: refetchConversations,
+ isFetched: conversationsLoaded,
+ } = useFetchCurrentUserConversations({
http,
onFetch: onFetchedConversations,
isAssistantEnabled,
@@ -55,6 +59,7 @@ export const ManagementSettings = React.memo(() => {
selectedConversation={currentConversation}
setSelectedConversationId={setSelectedConversationId}
conversations={conversations}
+ conversationsLoaded={conversationsLoaded}
isFlyoutMode={isFlyoutMode}
refetchConversations={refetchConversations}
/>
From d5892f1b253354be97440db6cd5aabb925269945 Mon Sep 17 00:00:00 2001
From: Angela Chuang
Date: Thu, 20 Jun 2024 14:15:49 +0100
Subject: [PATCH 07/37] system prompt
---
.../flyout/index.tsx | 0
.../flyout/translations.ts | 0
.../flyout/use_flyout_modal_visibility.ts | 0
.../row_actions/index.tsx} | 40 +++--
.../row_actions/translations.ts | 22 +++
.../use_conversation_selector_settings.tsx | 67 -------
.../use_conversation_changed.tsx | 11 +-
.../index.tsx | 164 ++++++------------
.../system_prompt_column.tsx | 38 ++++
.../translations.ts | 12 +-
.../use_conversation_selector_settings.tsx | 134 ++++++++++++++
.../system_prompt_editor.tsx | 107 ++++++------
.../system_prompt_settings.tsx | 2 +
.../system_prompt_modal/types.ts | 1 +
.../use_system_prompt_editor.tsx | 58 +++++++
.../default_conversations_column.tsx | 50 ++++++
.../index.tsx | 98 ++++-------
.../use_system_prompt_table.tsx | 116 +++++++++++++
.../utils.tsx | 24 +++
.../helpers.ts | 31 ----
.../index.tsx | 10 +-
.../assistant_settings_management.tsx | 24 +--
.../use_settings_updater.tsx | 1 +
.../assistant/use_conversation/helpers.ts | 38 +++-
.../impl/connectorland/translations.ts | 14 --
25 files changed, 681 insertions(+), 381 deletions(-)
rename x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/{assisttant_settings_management => assistant_settings_management}/flyout/index.tsx (100%)
rename x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/{assisttant_settings_management => assistant_settings_management}/flyout/translations.ts (100%)
rename x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/{assisttant_settings_management => assistant_settings_management}/flyout/use_flyout_modal_visibility.ts (100%)
rename x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/{assisttant_settings_management/row_actions.tsx => assistant_settings_management/row_actions/index.tsx} (73%)
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/row_actions/translations.ts
delete mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/system_prompt_column.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/use_conversation_selector_settings.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/use_system_prompt_editor.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/default_conversations_column.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.tsx
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/utils.tsx
delete mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/helpers.ts
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/index.tsx
similarity index 100%
rename from x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/index.tsx
rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/index.tsx
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/translations.ts
similarity index 100%
rename from x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/translations.ts
rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/translations.ts
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/use_flyout_modal_visibility.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/use_flyout_modal_visibility.ts
similarity index 100%
rename from x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/flyout/use_flyout_modal_visibility.ts
rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/use_flyout_modal_visibility.ts
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/row_actions.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/row_actions/index.tsx
similarity index 73%
rename from x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/row_actions.tsx
rename to x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/row_actions/index.tsx
index 7eeaf07f930d2..558d17cd66086 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assisttant_settings_management/row_actions.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/row_actions/index.tsx
@@ -7,22 +7,25 @@
import { EuiButtonEmpty, EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiPopover } from '@elastic/eui';
import React, { useCallback, useState } from 'react';
-
-import {
- DELETE_CONNECTOR_BUTTON,
- EDIT_CONNECTOR_BUTTON,
-} from '../../../../connectorland/translations';
+import * as i18n from './translations';
interface Props {
- rowItem: T;
- onEdit?: (rowItem: T) => void;
+ isDeletable?: boolean;
+ isEditable?: boolean;
onDelete?: (rowItem: T) => void;
- disabled?: boolean;
+ onEdit?: (rowItem: T) => void;
+ rowItem: T;
}
type RowActionsComponentType = (props: Props) => JSX.Element;
-const RowActionsComponent = ({ disabled, rowItem, onEdit, onDelete }: Props) => {
+const RowActionsComponent = ({
+ isDeletable = true,
+ isEditable = true,
+ onDelete,
+ onEdit,
+ rowItem,
+}: Props) => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const closePopover = useCallback(() => setIsPopoverOpen(false), []);
@@ -54,15 +57,26 @@ const RowActionsComponent = ({ disabled, rowItem, onEdit, onDelete }: Props<
{onEdit != null && (
-
- {EDIT_CONNECTOR_BUTTON}
+
+ {i18n.EDIT_BUTTON}
)}
{onDelete != null && (
-
- {DELETE_CONNECTOR_BUTTON}
+
+ {i18n.DELETE_BUTTON}
)}
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/row_actions/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/row_actions/translations.ts
new file mode 100644
index 0000000000000..1a2430cb6428c
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/row_actions/translations.ts
@@ -0,0 +1,22 @@
+/*
+ * 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 EDIT_BUTTON = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.editButtonTitle',
+ {
+ defaultMessage: 'Edit',
+ }
+);
+
+export const DELETE_BUTTON = i18n.translate(
+ 'xpack.elasticAssistant.assistant.settings.deleteButtonTitle',
+ {
+ defaultMessage: 'Delete',
+ }
+);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx
deleted file mode 100644
index 282f2e9f6b2f5..0000000000000
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/use_conversation_selector_settings.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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 { useMemo } from 'react';
-import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public';
-import { Conversation } from '../../../assistant_context/types';
-import { AIConnector } from '../../../connectorland/connector_selector';
-import { getConnectorTypeTitle } from '../../../connectorland/helpers';
-import { Prompt } from '../../../..';
-import { getDefaultSystemPrompt } from '../../use_conversation/helpers';
-
-const emptyConversations = {};
-
-export interface UseConversationSelectorSettingsProps {
- allSystemPrompts: Prompt[];
- actionTypeRegistry: ActionTypeRegistryContract;
- connectors: AIConnector[] | undefined;
- conversations: Record;
- defaultConnector?: AIConnector;
-}
-
-export type ConversationTableItem = Conversation & {
- actionType?: string | null;
-};
-
-export const useConversationsList = ({
- allSystemPrompts,
- actionTypeRegistry,
- connectors,
- conversations = emptyConversations,
- defaultConnector,
-}: UseConversationSelectorSettingsProps) => {
- const conversationOptions = useMemo(() => {
- return Object.values(conversations).map((conversation) => {
- const connector: AIConnector | undefined = connectors?.find(
- (c) => c.id === conversation.apiConfig?.connectorId || defaultConnector?.id
- );
-
- const actionType = getConnectorTypeTitle(connector, actionTypeRegistry);
-
- const defaultSystemPrompt = getDefaultSystemPrompt({
- allSystemPrompts,
- conversation,
- });
- return {
- ...conversation,
- actionType,
- ...(defaultConnector
- ? {
- apiConfig: {
- connectorId: defaultConnector.id,
- actionTypeId: defaultConnector.actionTypeId,
- provider: defaultConnector.apiProvider,
- defaultSystemPromptId: defaultSystemPrompt?.id,
- },
- }
- : {}),
- };
- });
- }, [conversations, connectors, actionTypeRegistry, allSystemPrompts, defaultConnector]);
-
- return conversationOptions;
-};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_conversation_changed.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_conversation_changed.tsx
index eadcd468cf841..ef3bd0511a68b 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_conversation_changed.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/use_conversation_changed.tsx
@@ -23,6 +23,8 @@ interface Props {
onSelectedConversationChange: (conversation?: Conversation) => void;
}
+type OnConversationSelectionChange = (c?: string | Conversation) => void;
+
export const useConversationChanged = ({
allSystemPrompts,
conversationSettings,
@@ -38,8 +40,8 @@ export const useConversationChanged = ({
// Conversation callbacks
// When top level conversation selection changes
- const onConversationSelectionChange = useCallback(
- (c?: Conversation | string) => {
+ const onConversationSelectionChange: OnConversationSelectionChange = useCallback(
+ (c = '') => {
const isNew = typeof c === 'string';
const newSelectedConversation: Conversation | undefined = isNew
@@ -83,7 +85,10 @@ export const useConversationChanged = ({
});
}
- onSelectedConversationChange(newSelectedConversation);
+ onSelectedConversationChange({
+ ...newSelectedConversation,
+ id: newSelectedConversation.id || newSelectedConversation.title,
+ });
},
[
conversationSettings,
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
index f607933623961..4f2545fe6f24b 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
@@ -5,39 +5,25 @@
* 2.0.
*/
-import {
- EuiPanel,
- EuiSpacer,
- EuiBadge,
- EuiLink,
- EuiBasicTableColumn,
- EuiConfirmModal,
- EuiInMemoryTable,
-} from '@elastic/eui';
+import { EuiPanel, EuiSpacer, EuiConfirmModal, EuiInMemoryTable } from '@elastic/eui';
import React, { useCallback, useMemo, useState } from 'react';
import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public';
-import { FormattedDate } from '@kbn/i18n-react';
import { Conversation } from '../../../assistant_context/types';
-import {
- ConversationTableItem,
- useConversationsList,
-} from '../conversation_selector_settings/use_conversation_selector_settings';
+import { ConversationTableItem, useConversationsTable } from './use_conversation_selector_settings';
import { ConversationStreamingSwitch } from '../conversation_settings/conversation_streaming_switch';
import { AIConnector } from '../../../connectorland/connector_selector';
-import { RowActions } from '../../common/components/assisttant_settings_management/row_actions';
import * as i18n from './translations';
import { Prompt } from '../../types';
import { ConversationsBulkActions } from '../../api';
import { useAssistantContext } from '../../../assistant_context';
import { useConversationDeleted } from '../conversation_settings/use_conversation_deleted';
-import { useFlyoutModalVisibility } from '../../common/components/assisttant_settings_management/flyout/use_flyout_modal_visibility';
-import { Flyout } from '../../common/components/assisttant_settings_management/flyout';
+import { useFlyoutModalVisibility } from '../../common/components/assistant_settings_management/flyout/use_flyout_modal_visibility';
+import { Flyout } from '../../common/components/assistant_settings_management/flyout';
import { CANCEL, DELETE } from '../../settings/translations';
import { ConversationSettingsEditor } from '../conversation_settings/conversation_settings_editor';
import { useConversationChanged } from '../conversation_settings/use_conversation_changed';
-import { getDefaultSystemPrompt } from '../../use_conversation/helpers';
interface Props {
actionTypeRegistry: ActionTypeRegistryContract;
@@ -82,15 +68,13 @@ const ConversationSettingsManagementComponent: React.FC = ({
setConversationSettings,
setConversationsSettingsBulkActions,
}) => {
- console.log('conversationSettings----', conversationSettings);
- console.log('selectedConversation---', selectedConversation);
const { http } = useAssistantContext();
const {
isFlyoutOpen: editFlyoutVisible,
openFlyout: openEditFlyout,
closeFlyout: closeEditFlyout,
} = useFlyoutModalVisibility();
- const [deleteConversation, setDeleteConversation] = useState();
+ const [deletedConversation, setDeletedConversation] = useState();
const {
isFlyoutOpen: deleteConfirmModalVisibility,
@@ -125,26 +109,41 @@ const ConversationSettingsManagementComponent: React.FC = ({
const onDeleteActionClicked = useCallback(
(rowItem: ConversationTableItem) => {
- setDeleteConversation(rowItem);
+ setDeletedConversation(rowItem);
+ onConversationDeleted(rowItem.title);
+
closeEditFlyout();
openConfirmModal();
},
- [closeEditFlyout, openConfirmModal]
+ [closeEditFlyout, onConversationDeleted, openConfirmModal]
);
const onDeleteConfirmed = useCallback(() => {
- if (!deleteConversation) return;
- onConversationDeleted(deleteConversation.title);
+ if (Object.keys(conversationsSettingsBulkActions).length === 0) {
+ return;
+ }
+
+ handleSave();
closeConfirmModal();
- }, [deleteConversation, onConversationDeleted, closeConfirmModal]);
+ setConversationsSettingsBulkActions({});
+ refetchConversations();
+ }, [
+ closeConfirmModal,
+ conversationsSettingsBulkActions,
+ handleSave,
+ refetchConversations,
+ setConversationsSettingsBulkActions,
+ ]);
const onDeleteCancelled = useCallback(() => {
- setDeleteConversation(null);
+ setDeletedConversation(null);
closeConfirmModal();
resetSettings();
}, [closeConfirmModal, resetSettings]);
- const conversationOptions = useConversationsList({
+ const { getConversationsList, getColumns } = useConversationsTable();
+
+ const conversationOptions = getConversationsList({
allSystemPrompts,
actionTypeRegistry,
connectors,
@@ -152,86 +151,27 @@ const ConversationSettingsManagementComponent: React.FC = ({
defaultConnector,
});
- const onEditFlyoutClosed = useCallback(() => {
+ const onSaveCancelled = useCallback(() => {
closeEditFlyout();
resetSettings();
}, [closeEditFlyout, resetSettings]);
- const onEditFlyoutSaved = useCallback(() => {
+ const onSaveConfirmed = useCallback(() => {
handleSave();
closeEditFlyout();
- }, [closeEditFlyout, handleSave]);
-
- const columns: Array> = useMemo(
- () => [
- {
- name: i18n.CONVERSATIONS_TABLE_COLUMN_TYPE,
- render: (conversation: ConversationTableItem) => (
- onEditActionClicked(conversation)}>{conversation.title}
- ),
- },
- {
- name: i18n.CONVERSATIONS_TABLE_COLUMN_SYSTEM_PROMPT,
- align: 'center',
- render: (conversation: ConversationTableItem) => {
- const systemPrompt: Prompt | undefined = allSystemPrompts.find(
- ({ id }) => id === conversation.apiConfig?.defaultSystemPromptId
- );
-
- const defaultSystemPrompt = getDefaultSystemPrompt({
- allSystemPrompts,
- conversation,
- });
+ refetchConversations();
+ setConversationsSettingsBulkActions({});
+ }, [closeEditFlyout, handleSave, refetchConversations, setConversationsSettingsBulkActions]);
- const systemPromptTitle =
- systemPrompt?.label ||
- systemPrompt?.name ||
- defaultSystemPrompt?.label ||
- defaultSystemPrompt?.name;
-
- return systemPromptTitle ? {systemPromptTitle} : null;
- },
- },
- {
- field: 'actionType',
- name: i18n.CONVERSATIONS_TABLE_COLUMN_CONNECTOR,
- align: 'center',
- render: (actionType: ConversationTableItem['actionType']) =>
- actionType ? {actionType} : null,
- },
- {
- field: 'updatedAt',
- name: i18n.CONVERSATIONS_TABLE_COLUMN_UPDATED_AT,
- align: 'center',
- render: (updatedAt: ConversationTableItem['updatedAt']) =>
- updatedAt ? (
-
-
-
- ) : null,
- },
- {
- name: i18n.CONVERSATIONS_TABLE_COLUMN_ACTIONS,
- width: '120px',
- align: 'center',
- render: (prompt: ConversationTableItem) => {
- return (
-
- rowItem={prompt}
- onDelete={onDeleteActionClicked}
- onEdit={onEditActionClicked}
- />
- );
- },
- },
- ],
- [allSystemPrompts, onDeleteActionClicked, onEditActionClicked]
+ const columns = useMemo(
+ () =>
+ getColumns({
+ conversations: conversationSettings,
+ onDeleteActionClicked,
+ onEditActionClicked,
+ allSystemPrompts,
+ }),
+ [allSystemPrompts, conversationSettings, getColumns, onDeleteActionClicked, onEditActionClicked]
);
const sorting = useMemo(
@@ -244,6 +184,14 @@ const ConversationSettingsManagementComponent: React.FC = ({
[]
);
+ const confirmationTitle = useMemo(
+ () =>
+ deletedConversation?.title
+ ? i18n.DELETE_CONVERSATION_CONFIRMATION_TITLE(deletedConversation?.title)
+ : i18n.DELETE_CONVERSATION_CONFIRMATION_DEFAULT_TITLE,
+ [deletedConversation?.title]
+ );
+
if (!conversationsLoaded) {
return null;
}
@@ -267,9 +215,9 @@ const ConversationSettingsManagementComponent: React.FC = ({
{editFlyoutVisible && (
= ({
/>
)}
- {deleteConfirmModalVisibility && deleteConversation?.title && (
+ {deleteConfirmModalVisibility && deletedConversation?.title && (
= ({ allSystemPrompts, conversation }) => {
+ const systemPrompt: Prompt | undefined = allSystemPrompts.find(
+ ({ id }) => id === conversation.apiConfig?.defaultSystemPromptId
+ );
+
+ const defaultSystemPrompt = getDefaultSystemPrompt({
+ allSystemPrompts,
+ conversation,
+ });
+
+ const systemPromptTitle =
+ systemPrompt?.label ||
+ systemPrompt?.name ||
+ defaultSystemPrompt?.label ||
+ defaultSystemPrompt?.name;
+
+ return systemPromptTitle ? {systemPromptTitle} : null;
+};
+
+SystemPromptColumn.displayName = 'SystemPromptColumn';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/translations.ts
index 783e641640b9c..a8da32d2d9153 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/translations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/translations.ts
@@ -42,9 +42,15 @@ export const CONVERSATIONS_TABLE_COLUMN_ACTIONS = i18n.translate(
}
);
-export const DELETE_CONVERSATION_CONFIRMATION_TITLE = i18n.translate(
- 'xpack.elasticAssistant.assistant.conversationSettings.deleteConfirmation.title',
+export const DELETE_CONVERSATION_CONFIRMATION_DEFAULT_TITLE = i18n.translate(
+ 'xpack.elasticAssistant.assistant.conversationSettings.deleteConfirmation.defaultTitle',
{
- defaultMessage: 'conversation',
+ defaultMessage: 'Delete conversation?',
}
);
+
+export const DELETE_CONVERSATION_CONFIRMATION_TITLE = (conversationTitle: string) =>
+ i18n.translate('xpack.elasticAssistant.assistant.conversationSettings.deleteConfirmation.Title', {
+ values: { conversationTitle },
+ defaultMessage: 'Delete "{conversationTitle}"?',
+ });
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/use_conversation_selector_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/use_conversation_selector_settings.tsx
new file mode 100644
index 0000000000000..a1d4ff39d672d
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/use_conversation_selector_settings.tsx
@@ -0,0 +1,134 @@
+/*
+ * 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, { useCallback } from 'react';
+import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public';
+import { EuiBadge, EuiBasicTableColumn, EuiLink } from '@elastic/eui';
+
+import { FormattedDate } from '@kbn/i18n-react';
+import { Conversation } from '../../../assistant_context/types';
+import { AIConnector } from '../../../connectorland/connector_selector';
+import { getConnectorTypeTitle } from '../../../connectorland/helpers';
+import { Prompt } from '../../../..';
+import { getApiConfig } from '../../use_conversation/helpers';
+import * as i18n from './translations';
+import { RowActions } from '../../common/components/assistant_settings_management/row_actions';
+import { SystemPromptColumn } from './system_prompt_column';
+
+const emptyConversations = {};
+
+export interface GetConversationsListParams {
+ allSystemPrompts: Prompt[];
+ actionTypeRegistry: ActionTypeRegistryContract;
+ connectors: AIConnector[] | undefined;
+ conversations: Record;
+ defaultConnector?: AIConnector;
+}
+
+export type ConversationTableItem = Conversation & {
+ actionType?: string | null;
+};
+
+export const useConversationsTable = () => {
+ const getColumns = useCallback(
+ ({
+ onDeleteActionClicked,
+ onEditActionClicked,
+ allSystemPrompts,
+ }): Array> => {
+ return [
+ {
+ name: i18n.CONVERSATIONS_TABLE_COLUMN_TYPE,
+ render: (conversation: ConversationTableItem) => (
+ onEditActionClicked(conversation)}>
+ {conversation.title}
+
+ ),
+ },
+ {
+ name: i18n.CONVERSATIONS_TABLE_COLUMN_SYSTEM_PROMPT,
+ align: 'center',
+ render: (conversation: ConversationTableItem) => (
+
+ ),
+ },
+ {
+ field: 'actionType',
+ name: i18n.CONVERSATIONS_TABLE_COLUMN_CONNECTOR,
+ align: 'center',
+ render: (actionType: ConversationTableItem['actionType']) =>
+ actionType ? {actionType} : null,
+ },
+ {
+ field: 'updatedAt',
+ name: i18n.CONVERSATIONS_TABLE_COLUMN_UPDATED_AT,
+ align: 'center',
+ render: (updatedAt: ConversationTableItem['updatedAt']) =>
+ updatedAt ? (
+
+
+
+ ) : null,
+ },
+ {
+ name: i18n.CONVERSATIONS_TABLE_COLUMN_ACTIONS,
+ width: '120px',
+ align: 'center',
+ render: (conversation: ConversationTableItem) => {
+ const isDeletable = !conversation.isDefault;
+ return (
+
+ rowItem={conversation}
+ onDelete={isDeletable ? onDeleteActionClicked : undefined}
+ onEdit={onEditActionClicked}
+ isDeletable={isDeletable}
+ />
+ );
+ },
+ },
+ ];
+ },
+ []
+ );
+ const getConversationsList = useCallback(
+ ({
+ allSystemPrompts,
+ actionTypeRegistry,
+ connectors,
+ conversations = emptyConversations,
+ defaultConnector,
+ }: GetConversationsListParams): ConversationTableItem[] => {
+ return Object.values(conversations).map((conversation) => {
+ const conversationApiConfig = getApiConfig({
+ allSystemPrompts,
+ connectors,
+ conversation,
+ defaultConnector,
+ });
+ const connector: AIConnector | undefined = connectors?.find(
+ (c) => c.id === conversationApiConfig.apiConfig?.connectorId
+ );
+
+ const actionType = getConnectorTypeTitle(connector, actionTypeRegistry);
+
+ return {
+ ...conversation,
+ actionType,
+ ...conversationApiConfig,
+ };
+ });
+ },
+ []
+ );
+
+ return { getColumns, getConversationsList };
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_editor.tsx
index 5f19726b1497a..15f3ba69aa5af 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_editor.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_editor.tsx
@@ -26,9 +26,12 @@ import { ConversationMultiSelector } from './conversation_multi_selector/convers
import { SystemPromptSelector } from './system_prompt_selector/system_prompt_selector';
import { TEST_IDS } from '../../../constants';
import { ConversationsBulkActions } from '../../../api';
-import { getSelectedConversations } from '../../../quick_prompts/quick_prompt_settings_management.tsx/helpers';
+import { getSelectedConversations } from '../system_prompt_settings_management/utils';
+import { useSystemPromptEditor } from './use_system_prompt_editor';
+import { getApiConfig, getDefaultNewSystemPrompt } from '../../../use_conversation/helpers';
interface Props {
+ connectors: AIConnector[] | undefined;
conversationSettings: Record;
conversationsSettingsBulkActions: ConversationsBulkActions;
onSelectedSystemPromptChange: (systemPrompt?: Prompt) => void;
@@ -46,6 +49,7 @@ interface Props {
* Settings for adding/removing system prompts. Configure name, prompt and default conversations.
*/
export const SystemPromptEditorComponent: React.FC = ({
+ connectors,
conversationSettings,
onSelectedSystemPromptChange,
selectedSystemPrompt,
@@ -87,22 +91,42 @@ export const SystemPromptEditorComponent: React.FC = ({
[selectedSystemPrompt, setUpdatedSystemPromptSettings]
);
+ const conversationsWithApiConfig = Object.entries(conversationSettings).reduce<
+ Record
+ >((acc, [key, conversation]) => {
+ acc[key] = {
+ ...conversation,
+ ...getApiConfig({
+ allSystemPrompts: systemPromptSettings,
+ connectors,
+ conversation,
+ defaultConnector,
+ }),
+ };
+ return acc;
+ }, {});
// Conversations this system prompt should be a default for
const conversationOptions = useMemo(
- () => Object.values(conversationSettings),
- [conversationSettings]
+ () => Object.values(conversationsWithApiConfig),
+ [conversationsWithApiConfig]
);
+
const selectedConversations = useMemo(() => {
return selectedSystemPrompt != null
- ? getSelectedConversations(conversationSettings, selectedSystemPrompt.id)
+ ? getSelectedConversations(
+ systemPromptSettings,
+ conversationsWithApiConfig,
+ selectedSystemPrompt.id
+ )
: [];
- }, [conversationSettings, selectedSystemPrompt]);
+ }, [conversationsWithApiConfig, selectedSystemPrompt, systemPromptSettings]);
const handleConversationSelectionChange = useCallback(
(currentPromptConversations: Conversation[]) => {
const currentPromptConversationTitles = currentPromptConversations.map(
(convo) => convo.title
);
+
const getDefaultSystemPromptId = (convo: Conversation) =>
currentPromptConversationTitles.includes(convo.title)
? selectedSystemPrompt?.id
@@ -110,7 +134,7 @@ export const SystemPromptEditorComponent: React.FC = ({
? // remove the default System Prompt if it is assigned to a conversation
// but that conversation is not in the currentPromptConversationList
// This means conversation was removed in the current transaction
- undefined
+ getDefaultNewSystemPrompt(systemPromptSettings).id
: // leave it as it is .. if that conversation was neither added nor removed.
convo.apiConfig?.defaultSystemPromptId;
@@ -145,16 +169,22 @@ export const SystemPromptEditorComponent: React.FC = ({
);
let updatedConversationsSettingsBulkActions = { ...conversationsSettingsBulkActions };
- Object.values(conversationSettings).forEach((convo) => {
- const getApiConfig = (): ApiConfig | {} => {
+ Object.values(conversationsWithApiConfig).forEach((convo) => {
+ const getApiConfigWithSelectedPrompt = (): ApiConfig | {} => {
if (convo.apiConfig) {
return {
apiConfig: {
- ...convo.apiConfig,
+ ...getApiConfig({
+ allSystemPrompts: systemPromptSettings,
+ connectors,
+ conversation: convo,
+ defaultConnector,
+ }).apiConfig,
defaultSystemPromptId: getDefaultSystemPromptId(convo),
},
};
}
+
return {};
};
const createOperation =
@@ -164,14 +194,7 @@ export const SystemPromptEditorComponent: React.FC = ({
...(updatedConversationsSettingsBulkActions.create ?? {}),
[convo.id]: {
...convo,
- ...(convo.apiConfig
- ? {
- apiConfig: {
- ...convo.apiConfig,
- defaultSystemPromptId: getDefaultSystemPromptId(convo),
- },
- }
- : {}),
+ ...(convo.apiConfig ? getApiConfigWithSelectedPrompt() : {}),
},
},
}
@@ -186,7 +209,7 @@ export const SystemPromptEditorComponent: React.FC = ({
...(updatedConversationsSettingsBulkActions.update
? updatedConversationsSettingsBulkActions.update[convo.id] ?? {}
: {}),
- ...getApiConfig(),
+ ...getApiConfigWithSelectedPrompt(),
},
},
}
@@ -198,17 +221,19 @@ export const SystemPromptEditorComponent: React.FC = ({
...updateOperation,
};
});
+
setConversationsSettingsBulkActions(updatedConversationsSettingsBulkActions);
}
},
[
- conversationSettings,
+ connectors,
conversationsSettingsBulkActions,
- defaultConnector?.actionTypeId,
- defaultConnector?.id,
+ conversationsWithApiConfig,
+ defaultConnector,
selectedSystemPrompt,
setConversationSettings,
setConversationsSettingsBulkActions,
+ systemPromptSettings,
]
);
@@ -236,42 +261,10 @@ export const SystemPromptEditorComponent: React.FC = ({
[selectedSystemPrompt, setUpdatedSystemPromptSettings]
);
- // When top level system prompt selection changes
- const onSystemPromptSelectionChange = useCallback(
- (systemPrompt?: Prompt | string) => {
- const isNew = typeof systemPrompt === 'string';
- const newSelectedSystemPrompt: Prompt | undefined = isNew
- ? {
- id: systemPrompt ?? '',
- content: '',
- name: systemPrompt ?? '',
- promptType: 'system',
- }
- : systemPrompt;
-
- if (newSelectedSystemPrompt != null) {
- setUpdatedSystemPromptSettings((prev) => {
- const alreadyExists = prev.some((sp) => sp.id === newSelectedSystemPrompt.id);
-
- if (!alreadyExists) {
- return [...prev, newSelectedSystemPrompt];
- }
-
- return prev;
- });
- }
-
- onSelectedSystemPromptChange(newSelectedSystemPrompt);
- },
- [onSelectedSystemPromptChange, setUpdatedSystemPromptSettings]
- );
-
- const onSystemPromptDeleted = useCallback(
- (id: string) => {
- setUpdatedSystemPromptSettings((prev) => prev.filter((sp) => sp.id !== id));
- },
- [setUpdatedSystemPromptSettings]
- );
+ const { onSystemPromptSelectionChange, onSystemPromptDeleted } = useSystemPromptEditor({
+ setUpdatedSystemPromptSettings,
+ onSelectedSystemPromptChange,
+ });
return (
<>
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_settings.tsx
index c228cc7df49c6..b7f66acba85c7 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_settings.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_settings.tsx
@@ -17,6 +17,7 @@ import { SystemPromptSettingsProps } from './types';
*/
export const SystemPromptSettings: React.FC = React.memo(
({
+ connectors,
conversationSettings,
onSelectedSystemPromptChange,
selectedSystemPrompt,
@@ -37,6 +38,7 @@ export const SystemPromptSettings: React.FC = React.m
;
conversationsSettingsBulkActions: ConversationsBulkActions;
onSelectedSystemPromptChange: (systemPrompt?: Prompt) => void;
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/use_system_prompt_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/use_system_prompt_editor.tsx
new file mode 100644
index 0000000000000..87e284d6dcf25
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/use_system_prompt_editor.tsx
@@ -0,0 +1,58 @@
+/*
+ * 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 { useCallback } from 'react';
+import { Prompt } from '../../../types';
+
+interface Props {
+ setUpdatedSystemPromptSettings: React.Dispatch>;
+ onSelectedSystemPromptChange: (systemPrompt?: Prompt) => void;
+}
+
+export const useSystemPromptEditor = ({
+ setUpdatedSystemPromptSettings,
+ onSelectedSystemPromptChange,
+}: Props) => {
+ // When top level system prompt selection changes
+ const onSystemPromptSelectionChange = useCallback(
+ (systemPrompt?: Prompt | string) => {
+ const isNew = typeof systemPrompt === 'string';
+ const newSelectedSystemPrompt: Prompt | undefined = isNew
+ ? {
+ id: systemPrompt ?? '',
+ content: '',
+ name: systemPrompt ?? '',
+ promptType: 'system',
+ }
+ : systemPrompt;
+
+ if (newSelectedSystemPrompt != null) {
+ setUpdatedSystemPromptSettings((prev) => {
+ const alreadyExists = prev.some((sp) => sp.id === newSelectedSystemPrompt.id);
+
+ if (!alreadyExists) {
+ return [...prev, newSelectedSystemPrompt];
+ }
+
+ return prev;
+ });
+ }
+
+ onSelectedSystemPromptChange(newSelectedSystemPrompt);
+ },
+ [onSelectedSystemPromptChange, setUpdatedSystemPromptSettings]
+ );
+
+ const onSystemPromptDeleted = useCallback(
+ (id: string) => {
+ setUpdatedSystemPromptSettings((prev) => prev.filter((sp) => sp.id !== id));
+ },
+ [setUpdatedSystemPromptSettings]
+ );
+
+ return { onSystemPromptSelectionChange, onSystemPromptDeleted };
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/default_conversations_column.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/default_conversations_column.tsx
new file mode 100644
index 0000000000000..7567775909a09
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/default_conversations_column.tsx
@@ -0,0 +1,50 @@
+/*
+ * 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 { EuiBadge, EuiLink } from '@elastic/eui';
+import React, { useCallback, useState } from 'react';
+
+interface Props {
+ defaultConversations: string[];
+}
+
+export const DefaultConversationsColumn: React.FC = React.memo(
+ ({ defaultConversations }) => {
+ const maxConversationsToShow = 5;
+ const isOverflow = defaultConversations.length > maxConversationsToShow;
+
+ const [isExpanded, setIsExpanded] = useState(false);
+
+ const currentDisplaying = isExpanded
+ ? defaultConversations.length
+ : Math.min(maxConversationsToShow, defaultConversations.length);
+ const itemsToDisplay = defaultConversations.slice(0, currentDisplaying - 1);
+
+ const toggleContent = useCallback((prev) => {
+ setIsExpanded(!prev);
+ }, []);
+
+ if (!defaultConversations || defaultConversations?.length === 0) {
+ return null;
+ }
+
+ return (
+ <>
+ {itemsToDisplay.map((c, idx) => (
+
+ {c}
+
+ ))}
+ {isOverflow && (
+ {isExpanded ? 'Show less' : 'Show All'}
+ )}
+ >
+ );
+ }
+);
+
+DefaultConversationsColumn.displayName = 'DefaultConversationsColumn';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx
index fcaf88be2b3e9..2377ea0a2b861 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx
@@ -12,24 +12,24 @@ import {
EuiButton,
EuiFlexGroup,
EuiFlexItem,
- EuiLink,
- EuiBadge,
EuiSpacer,
} from '@elastic/eui';
import React, { useCallback, useMemo, useState } from 'react';
+
import { Conversation, ConversationsBulkActions } from '../../../../..';
import { AIConnector } from '../../../../connectorland/connector_selector';
-import { Flyout } from '../../../common/components/assisttant_settings_management/flyout';
-import { useFlyoutModalVisibility } from '../../../common/components/assisttant_settings_management/flyout/use_flyout_modal_visibility';
-import { RowActions } from '../../../common/components/assisttant_settings_management/row_actions';
-import { getSystemPromptsList } from '../../../quick_prompts/quick_prompt_settings_management.tsx/helpers';
+import { Flyout } from '../../../common/components/assistant_settings_management/flyout';
+import { useFlyoutModalVisibility } from '../../../common/components/assistant_settings_management/flyout/use_flyout_modal_visibility';
import { CANCEL, DELETE } from '../../../settings/translations';
import { Prompt } from '../../../types';
import { SystemPromptEditor } from '../system_prompt_modal/system_prompt_editor';
import { SETTINGS_TITLE } from '../system_prompt_modal/translations';
+import { useSystemPromptEditor } from '../system_prompt_modal/use_system_prompt_editor';
import * as i18n from './translations';
+import { useSystemPromptTable } from './use_system_prompt_table';
interface Props {
+ connectors: AIConnector[] | undefined;
conversations: Record;
conversationSettings: Record;
conversationsSettingsBulkActions: ConversationsBulkActions;
@@ -47,6 +47,7 @@ interface Props {
}
const SystemPromptSettingsManagementComponent = ({
+ connectors,
conversations,
conversationSettings,
onSelectedSystemPromptChange,
@@ -78,87 +79,49 @@ const SystemPromptSettingsManagementComponent = ({
openFlyout();
}, [onSelectedSystemPromptChange, openFlyout]);
+ const { onSystemPromptSelectionChange, onSystemPromptDeleted } = useSystemPromptEditor({
+ setUpdatedSystemPromptSettings,
+ onSelectedSystemPromptChange,
+ });
+
const onEditActionClicked = useCallback(
(prompt: Prompt) => {
- onSelectedSystemPromptChange(prompt);
+ onSystemPromptSelectionChange(prompt);
openFlyout();
},
- [onSelectedSystemPromptChange, openFlyout]
+ [onSystemPromptSelectionChange, openFlyout]
);
const onDeleteActionClicked = useCallback(
(prompt: Prompt) => {
setDeletedPrompt(prompt);
+ onSystemPromptDeleted(prompt.id);
openConfirmModal();
},
- [openConfirmModal]
+ [onSystemPromptDeleted, openConfirmModal]
);
const onDeleteCancelled = useCallback(() => {
setDeletedPrompt(null);
closeConfirmModal();
- }, [closeConfirmModal]);
+ resetSettings();
+ }, [closeConfirmModal, resetSettings]);
const onDeleteConfirmed = useCallback(() => {
- setUpdatedSystemPromptSettings((prev) => prev.filter((sp) => sp.id !== deletedPrompt?.id));
handleSave();
closeConfirmModal();
- }, [closeConfirmModal, deletedPrompt?.id, handleSave, setUpdatedSystemPromptSettings]);
+ resetSettings();
+ }, [closeConfirmModal, handleSave, resetSettings]);
const onSaveCancelled = useCallback(() => {
- onSelectedSystemPromptChange();
closeFlyout();
resetSettings();
- }, [onSelectedSystemPromptChange, closeFlyout, resetSettings]);
+ }, [closeFlyout, resetSettings]);
const onSaveConfirmed = useCallback(() => {
handleSave();
- onSelectedSystemPromptChange();
closeFlyout();
- }, [closeFlyout, handleSave, onSelectedSystemPromptChange]);
-
- const columns = useMemo(
- () => [
- {
- name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_NAME,
- render: (prompt: Prompt) =>
- prompt?.name ? (
- onEditActionClicked(prompt)}>{prompt?.name}
- ) : null,
- },
- {
- field: 'defaultConversations',
- name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_DEFAULT_CONVERSATIONS,
- render: (defaultConversations: string[]) =>
- defaultConversations.map((c, idx) => (
-
- {c}
-
- )),
- },
- /* TODO: enable when createdAt is added
- {
- field: 'createdAt',
- name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_CREATED_ON,
- },
- */
- {
- name: 'Actions',
- align: 'center',
- width: '120px',
- render: (prompt: Prompt) => {
- return (
-
- rowItem={prompt}
- onEdit={onEditActionClicked}
- onDelete={onDeleteActionClicked}
- />
- );
- },
- },
- ],
- [onEditActionClicked, onDeleteActionClicked]
- );
+ }, [closeFlyout, handleSave]);
const confirmationTitle = useMemo(
() =>
@@ -168,9 +131,21 @@ const SystemPromptSettingsManagementComponent = ({
[deletedPrompt?.name]
);
+ const { getColumns, getSystemPromptsList } = useSystemPromptTable();
+
+ const columns = useMemo(
+ () => getColumns({ onEditActionClicked, onDeleteActionClicked }),
+ [getColumns, onEditActionClicked, onDeleteActionClicked]
+ );
const systemPromptListItems = useMemo(
- () => getSystemPromptsList(systemPromptSettings, conversations),
- [systemPromptSettings, conversations]
+ () =>
+ getSystemPromptsList({
+ connectors,
+ conversationSettings,
+ defaultConnector,
+ systemPromptSettings,
+ }),
+ [getSystemPromptsList, connectors, conversationSettings, defaultConnector, systemPromptSettings]
);
return (
<>
@@ -194,6 +169,7 @@ const SystemPromptSettingsManagementComponent = ({
onSaveConfirmed={onSaveConfirmed}
>
;
+
+type SystemPromptTableItem = Prompt & { defaultConversations: string[] };
+
+export const useSystemPromptTable = () => {
+ const getColumns = ({
+ onEditActionClicked,
+ onDeleteActionClicked,
+ }: {
+ onEditActionClicked: (prompt: SystemPromptTableItem) => void;
+ onDeleteActionClicked: (prompt: SystemPromptTableItem) => void;
+ }) => [
+ {
+ name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_NAME,
+ render: (prompt: SystemPromptTableItem) =>
+ prompt?.name ? (
+ onEditActionClicked(prompt)}>{prompt?.name}
+ ) : null,
+ },
+ {
+ field: 'defaultConversations',
+ name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_DEFAULT_CONVERSATIONS,
+ render: (defaultConversations: string[]) =>
+ defaultConversations.map((c, idx) => (
+
+ {c}
+
+ )),
+ },
+ /* TODO: enable when createdAt is added
+ {
+ field: 'createdAt',
+ name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_CREATED_ON,
+ },
+ */
+ {
+ name: 'Actions',
+ width: '120px',
+ render: (prompt: SystemPromptTableItem) => {
+ const isDeletable = !prompt.isDefault;
+ return (
+
+ rowItem={prompt}
+ onEdit={onEditActionClicked}
+ onDelete={isDeletable ? onDeleteActionClicked : undefined}
+ isDeletable={isDeletable}
+ />
+ );
+ },
+ },
+ ];
+
+ const getSystemPromptsList = ({
+ connectors,
+ conversationSettings,
+ defaultConnector,
+ systemPromptSettings,
+ }: {
+ connectors: AIConnector[] | undefined;
+ conversationSettings: Record;
+ defaultConnector: AIConnector | undefined;
+ systemPromptSettings: Prompt[];
+ }): SystemPromptTableItem[] => {
+ const conversationsWithApiConfig = Object.entries(
+ conversationSettings
+ ).reduce((acc, [key, conversation]) => {
+ const defaultSystemPrompt = getDefaultSystemPrompt({
+ allSystemPrompts: systemPromptSettings,
+ conversation,
+ });
+ acc[key] = {
+ ...conversation,
+ ...getApiConfig({
+ allSystemPrompts: systemPromptSettings,
+ connectors,
+ conversation,
+ defaultConnector,
+ }),
+ systemPrompt: defaultSystemPrompt,
+ };
+ return acc;
+ }, {});
+
+ return systemPromptSettings.map((systemPrompt) => {
+ return {
+ ...systemPrompt,
+ defaultConversations: getSelectedConversations(
+ systemPromptSettings,
+ conversationsWithApiConfig,
+ systemPrompt?.id
+ ).map(({ title }) => title),
+ };
+ });
+ };
+
+ return { getColumns, getSystemPromptsList };
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/utils.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/utils.tsx
new file mode 100644
index 0000000000000..fc9bbaed9bba0
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/utils.tsx
@@ -0,0 +1,24 @@
+/*
+ * 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 { Conversation } from '../../../../assistant_context/types';
+import { Prompt } from '../../../types';
+import { getDefaultSystemPrompt } from '../../../use_conversation/helpers';
+
+export const getSelectedConversations = (
+ allSystemPrompts: Prompt[],
+ conversationSettings: Record,
+ systemPromptId: string
+) => {
+ return Object.values(conversationSettings).filter((conversation) => {
+ const defaultSystemPrompt = getDefaultSystemPrompt({
+ allSystemPrompts,
+ conversation,
+ });
+ return defaultSystemPrompt?.id === systemPromptId;
+ });
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/helpers.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/helpers.ts
deleted file mode 100644
index 294527b5d8191..0000000000000
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/helpers.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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 { Conversation } from '../../../..';
-import { Prompt } from '../../types';
-
-export const getSelectedConversations = (
- conversationSettings: Record,
- systemPromptId: string
-) =>
- Object.values(conversationSettings).filter(
- (conversation) => conversation.apiConfig?.defaultSystemPromptId === systemPromptId
- );
-
-export const getSystemPromptsList = (
- systemPromptSettings: Prompt[],
- conversationSettings: Record
-): Array => {
- return systemPromptSettings.map((systemPrompt) => {
- return {
- ...systemPrompt,
- defaultConversations: getSelectedConversations(conversationSettings, systemPrompt.id).map(
- ({ title }) => title
- ),
- };
- });
-};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
index 32e6fae193cd0..df6d37049631b 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
@@ -17,11 +17,11 @@ import {
EuiSpacer,
} from '@elastic/eui';
import { QuickPrompt } from '../types';
-import { RowActions } from '../../common/components/assisttant_settings_management/row_actions';
+import { RowActions } from '../../common/components/assistant_settings_management/row_actions';
import { QuickPromptSettingsEditor } from '../quick_prompt_settings/quick_prompt_editor';
import * as i18n from './translations';
-import { useFlyoutModalVisibility } from '../../common/components/assisttant_settings_management/flyout/use_flyout_modal_visibility';
-import { Flyout } from '../../common/components/assisttant_settings_management/flyout';
+import { useFlyoutModalVisibility } from '../../common/components/assistant_settings_management/flyout/use_flyout_modal_visibility';
+import { Flyout } from '../../common/components/assistant_settings_management/flyout';
import { CANCEL, DELETE } from '../../settings/translations';
interface Props {
@@ -114,11 +114,13 @@ const QuickPromptSettingsManagementComponent = ({
width: '120px',
align: 'center',
render: (prompt: QuickPrompt) => {
+ const isDeletable = !prompt.isDefault;
return (
rowItem={prompt}
onDelete={onDeleteActionClicked}
- onEdit={onEditActionClicked}
+ onEdit={isDeletable ? onEditActionClicked : undefined}
+ isDeletable={isDeletable}
/>
);
},
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
index ef505a3b4fa1d..2fb49b3cea07c 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
@@ -152,26 +152,13 @@ export const AssistantSettingsManagement: React.FC = React.memo(
}, [selectedSystemPrompt, systemPromptSettings]);
const handleSave = useCallback(() => {
- // If the selected conversation is deleted, we need to select a new conversation to prevent a crash creating a conversation that already exists
- const isSelectedConversationDeleted =
- conversationSettings[defaultSelectedConversation.title] == null;
- const newSelectedConversationId: string | undefined = Object.keys(conversationSettings)[0];
- if (isSelectedConversationDeleted && newSelectedConversationId != null) {
- setSelectedConversationId(conversationSettings[newSelectedConversationId].title);
- }
saveSettings();
toasts?.addSuccess({
iconType: 'check',
title: i18n.SETTINGS_UPDATED_TOAST_TITLE,
});
setHasPendingChanges(false);
- }, [
- conversationSettings,
- defaultSelectedConversation.title,
- saveSettings,
- setSelectedConversationId,
- toasts,
- ]);
+ }, [saveSettings, toasts]);
const tabsConfig = useMemo(
() => [
@@ -183,14 +170,14 @@ export const AssistantSettingsManagement: React.FC = React.memo(
id: CONVERSATIONS_TAB,
label: i18n.CONVERSATIONS_MENU_ITEM,
},
- {
- id: QUICK_PROMPTS_TAB,
- label: i18n.QUICK_PROMPTS_MENU_ITEM,
- },
{
id: SYSTEM_PROMPTS_TAB,
label: i18n.SYSTEM_PROMPTS_MENU_ITEM,
},
+ {
+ id: QUICK_PROMPTS_TAB,
+ label: i18n.QUICK_PROMPTS_MENU_ITEM,
+ },
{
id: ANONYMIZATION_TAB,
label: i18n.ANONYMIZATION_MENU_ITEM,
@@ -275,6 +262,7 @@ export const AssistantSettingsManagement: React.FC = React.memo(
)}
{selectedSettingsTab === SYSTEM_PROMPTS_TAB && (
>(conversations);
const [conversationsSettingsBulkActions, setConversationsSettingsBulkActions] =
useState({});
+ console.log('updater---', conversationsSettingsBulkActions);
// Quick Prompts
const [updatedQuickPromptSettings, setUpdatedQuickPromptSettings] =
useState(allQuickPrompts);
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.ts
index de766085e1aee..e3cfa09f8073b 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.ts
@@ -8,6 +8,7 @@
import React from 'react';
import { Prompt } from '../types';
import { Conversation } from '../../assistant_context/types';
+import { AIConnector } from '../../connectorland/connector_selector';
export interface CodeBlockDetails {
type: QueryType;
@@ -68,6 +69,9 @@ export const analyzeMarkdown = (markdown: string): CodeBlockDetails[] => {
return result;
};
+export const getDefaultNewSystemPrompt = (allSystemPrompts: Prompt[]) =>
+ allSystemPrompts.find((prompt) => prompt.isNewConversationDefault) ?? allSystemPrompts?.[0];
+
/**
* Returns the default system prompt for a given conversation
*
@@ -84,7 +88,37 @@ export const getDefaultSystemPrompt = ({
const conversationSystemPrompt = allSystemPrompts.find(
(prompt) => prompt.id === conversation?.apiConfig?.defaultSystemPromptId
);
- const defaultNewSystemPrompt = allSystemPrompts.find((prompt) => prompt.isNewConversationDefault);
+ const defaultNewSystemPrompt = getDefaultNewSystemPrompt(allSystemPrompts);
+
+ return conversationSystemPrompt ?? defaultNewSystemPrompt;
+};
- return conversationSystemPrompt ?? defaultNewSystemPrompt ?? allSystemPrompts?.[0];
+export const getApiConfig = ({
+ allSystemPrompts,
+ conversation,
+ connectors,
+ defaultConnector,
+}: {
+ allSystemPrompts: Prompt[];
+ conversation: Conversation;
+ connectors?: AIConnector[];
+ defaultConnector?: AIConnector;
+}) => {
+ const connector: AIConnector | undefined = connectors?.find(
+ (c) => c.id === conversation.apiConfig?.connectorId || defaultConnector?.id
+ );
+ const defaultSystemPrompt = getDefaultSystemPrompt({
+ allSystemPrompts,
+ conversation,
+ });
+ return connector
+ ? {
+ apiConfig: {
+ connectorId: connector.id,
+ actionTypeId: connector.actionTypeId,
+ provider: connector.apiProvider,
+ defaultSystemPromptId: defaultSystemPrompt?.id,
+ },
+ }
+ : {};
};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
index 86c4bebeb320b..1ce84fdb6e9b6 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts
@@ -163,17 +163,3 @@ export const REFRESH_CONNECTORS_BUTTON = i18n.translate(
defaultMessage: 'Refresh',
}
);
-
-export const EDIT_CONNECTOR_BUTTON = i18n.translate(
- 'xpack.elasticAssistant.assistant.connectors.editConnectorButton',
- {
- defaultMessage: 'Edit',
- }
-);
-
-export const DELETE_CONNECTOR_BUTTON = i18n.translate(
- 'xpack.elasticAssistant.assistant.connectors.deleteConnectorButton',
- {
- defaultMessage: 'Delete',
- }
-);
From b591eb53fa5480f11143c89c69ef8ad843eb8ea6 Mon Sep 17 00:00:00 2001
From: Angela Chuang
Date: Thu, 20 Jun 2024 17:29:43 +0100
Subject: [PATCH 08/37] connector title
---
.../index.tsx | 18 +++---
.../index.tsx | 16 ++---
.../use_system_prompt_table.tsx | 16 +++--
.../quick_prompt_editor.tsx | 39 ++-----------
.../use_quick_prompt_editor.tsx | 58 +++++++++++++++++++
.../index.tsx | 54 +++++++++++------
.../translations.ts | 7 +++
.../assistant_settings_management.tsx | 45 ++++++++++++--
.../use_settings_updater.tsx | 4 +-
.../assistant/use_conversation/helpers.ts | 5 +-
.../impl/connectorland/helpers.tsx | 5 +-
11 files changed, 178 insertions(+), 89 deletions(-)
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/use_quick_prompt_editor.tsx
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
index 4f2545fe6f24b..e03419925ecda 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
@@ -38,7 +38,7 @@ interface Props {
isDisabled?: boolean;
isFlyoutMode: boolean;
refetchConversations: () => void;
- resetSettings: () => void;
+ onCancelClick: () => void;
setAssistantStreamingEnabled: React.Dispatch>;
setConversationSettings: React.Dispatch>>;
setConversationsSettingsBulkActions: React.Dispatch<
@@ -62,7 +62,7 @@ const ConversationSettingsManagementComponent: React.FC = ({
isFlyoutMode,
onSelectedConversationChange,
refetchConversations,
- resetSettings,
+ onCancelClick,
selectedConversation,
setAssistantStreamingEnabled,
setConversationSettings,
@@ -138,8 +138,8 @@ const ConversationSettingsManagementComponent: React.FC = ({
const onDeleteCancelled = useCallback(() => {
setDeletedConversation(null);
closeConfirmModal();
- resetSettings();
- }, [closeConfirmModal, resetSettings]);
+ onCancelClick();
+ }, [closeConfirmModal, onCancelClick]);
const { getConversationsList, getColumns } = useConversationsTable();
@@ -153,15 +153,13 @@ const ConversationSettingsManagementComponent: React.FC = ({
const onSaveCancelled = useCallback(() => {
closeEditFlyout();
- resetSettings();
- }, [closeEditFlyout, resetSettings]);
+ onCancelClick();
+ }, [closeEditFlyout, onCancelClick]);
const onSaveConfirmed = useCallback(() => {
- handleSave();
closeEditFlyout();
- refetchConversations();
- setConversationsSettingsBulkActions({});
- }, [closeEditFlyout, handleSave, refetchConversations, setConversationsSettingsBulkActions]);
+ handleSave();
+ }, [closeEditFlyout, handleSave]);
const columns = useMemo(
() =>
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx
index 2377ea0a2b861..59134aade4373 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/index.tsx
@@ -43,7 +43,7 @@ interface Props {
>;
defaultConnector?: AIConnector;
handleSave: () => void;
- resetSettings: () => void;
+ onCancelClick: () => void;
}
const SystemPromptSettingsManagementComponent = ({
@@ -59,7 +59,7 @@ const SystemPromptSettingsManagementComponent = ({
setConversationsSettingsBulkActions,
defaultConnector,
handleSave,
- resetSettings,
+ onCancelClick,
}: Props) => {
const { isFlyoutOpen: editFlyoutVisible, openFlyout, closeFlyout } = useFlyoutModalVisibility();
const {
@@ -104,19 +104,19 @@ const SystemPromptSettingsManagementComponent = ({
const onDeleteCancelled = useCallback(() => {
setDeletedPrompt(null);
closeConfirmModal();
- resetSettings();
- }, [closeConfirmModal, resetSettings]);
+ onCancelClick();
+ }, [closeConfirmModal, onCancelClick]);
const onDeleteConfirmed = useCallback(() => {
handleSave();
closeConfirmModal();
- resetSettings();
- }, [closeConfirmModal, handleSave, resetSettings]);
+ onCancelClick();
+ }, [closeConfirmModal, handleSave, onCancelClick]);
const onSaveCancelled = useCallback(() => {
closeFlyout();
- resetSettings();
- }, [closeFlyout, resetSettings]);
+ onCancelClick();
+ }, [closeFlyout, onCancelClick]);
const onSaveConfirmed = useCallback(() => {
handleSave();
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.tsx
index aa323d27be38c..c1e93e471e828 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.tsx
@@ -5,6 +5,7 @@
* 2.0.
*/
import { EuiLink, EuiBadge } from '@elastic/eui';
+import { css } from '@emotion/react';
import React from 'react';
import { Conversation } from '../../../../assistant_context/types';
import { AIConnector } from '../../../../connectorland/connector_selector';
@@ -39,12 +40,15 @@ export const useSystemPromptTable = () => {
{
field: 'defaultConversations',
name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_DEFAULT_CONVERSATIONS,
- render: (defaultConversations: string[]) =>
- defaultConversations.map((c, idx) => (
-
- {c}
-
- )),
+ render: (defaultConversations: string[]) => (
+
+ {defaultConversations.map((c, idx) => (
+
+ {c}
+
+ ))}
+
+ ),
},
/* TODO: enable when createdAt is added
{
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/quick_prompt_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/quick_prompt_editor.tsx
index 8a7e90a0f890b..ea903c1abce9d 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/quick_prompt_editor.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/quick_prompt_editor.tsx
@@ -16,6 +16,7 @@ import { QuickPrompt } from '../types';
import { QuickPromptSelector } from '../quick_prompt_selector/quick_prompt_selector';
import { PromptContextSelector } from '../prompt_context_selector/prompt_context_selector';
import { useAssistantContext } from '../../../assistant_context';
+import { useQuickPromptEditor } from './use_quick_prompt_editor';
const DEFAULT_COLOR = '#D36086';
@@ -126,41 +127,11 @@ const QuickPromptSettingsEditorComponent = ({
);
// When top level quick prompt selection changes
- const onQuickPromptSelectionChange = useCallback(
- (quickPrompt?: QuickPrompt | string) => {
- const isNew = typeof quickPrompt === 'string';
- const newSelectedQuickPrompt: QuickPrompt | undefined = isNew
- ? {
- title: quickPrompt ?? '',
- prompt: '',
- color: DEFAULT_COLOR,
- categories: [],
- }
- : quickPrompt;
-
- if (newSelectedQuickPrompt != null) {
- setUpdatedQuickPromptSettings((prev) => {
- const alreadyExists = prev.some((qp) => qp.title === newSelectedQuickPrompt.title);
-
- if (!alreadyExists) {
- return [...prev, newSelectedQuickPrompt];
- }
-
- return prev;
- });
- }
+ const { onQuickPromptDeleted, onQuickPromptSelectionChange } = useQuickPromptEditor({
+ onSelectedQuickPromptChange,
+ setUpdatedQuickPromptSettings,
+ });
- onSelectedQuickPromptChange(newSelectedQuickPrompt);
- },
- [onSelectedQuickPromptChange, setUpdatedQuickPromptSettings]
- );
-
- const onQuickPromptDeleted = useCallback(
- (title: string) => {
- setUpdatedQuickPromptSettings((prev) => prev.filter((qp) => qp.title !== title));
- },
- [setUpdatedQuickPromptSettings]
- );
return (
<>
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/use_quick_prompt_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/use_quick_prompt_editor.tsx
new file mode 100644
index 0000000000000..716298afb21da
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings/use_quick_prompt_editor.tsx
@@ -0,0 +1,58 @@
+/*
+ * 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 { useCallback } from 'react';
+import { QuickPrompt } from '../types';
+
+export const DEFAULT_COLOR = '#D36086';
+
+export const useQuickPromptEditor = ({
+ onSelectedQuickPromptChange,
+ setUpdatedQuickPromptSettings,
+}: {
+ onSelectedQuickPromptChange: (quickPrompt?: QuickPrompt) => void;
+ setUpdatedQuickPromptSettings: React.Dispatch>;
+}) => {
+ const onQuickPromptDeleted = useCallback(
+ (title: string) => {
+ setUpdatedQuickPromptSettings((prev) => prev.filter((qp) => qp.title !== title));
+ },
+ [setUpdatedQuickPromptSettings]
+ );
+
+ // When top level quick prompt selection changes
+ const onQuickPromptSelectionChange = useCallback(
+ (quickPrompt?: QuickPrompt | string) => {
+ const isNew = typeof quickPrompt === 'string';
+ const newSelectedQuickPrompt: QuickPrompt | undefined = isNew
+ ? {
+ title: quickPrompt ?? '',
+ prompt: '',
+ color: DEFAULT_COLOR,
+ categories: [],
+ }
+ : quickPrompt;
+
+ if (newSelectedQuickPrompt != null) {
+ setUpdatedQuickPromptSettings((prev) => {
+ const alreadyExists = prev.some((qp) => qp.title === newSelectedQuickPrompt.title);
+
+ if (!alreadyExists) {
+ return [...prev, newSelectedQuickPrompt];
+ }
+
+ return prev;
+ });
+ }
+
+ onSelectedQuickPromptChange(newSelectedQuickPrompt);
+ },
+ [onSelectedQuickPromptChange, setUpdatedQuickPromptSettings]
+ );
+
+ return { onQuickPromptDeleted, onQuickPromptSelectionChange };
+};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
index df6d37049631b..c9a2c90e46090 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
@@ -6,6 +6,7 @@
*/
import React, { useCallback, useMemo, useState } from 'react';
import {
+ EuiBadge,
EuiBasicTableColumn,
EuiButton,
EuiConfirmModal,
@@ -23,6 +24,7 @@ import * as i18n from './translations';
import { useFlyoutModalVisibility } from '../../common/components/assistant_settings_management/flyout/use_flyout_modal_visibility';
import { Flyout } from '../../common/components/assistant_settings_management/flyout';
import { CANCEL, DELETE } from '../../settings/translations';
+import { useQuickPromptEditor } from '../quick_prompt_settings/use_quick_prompt_editor';
interface Props {
onSelectedQuickPromptChange: (quickPrompt?: QuickPrompt) => void;
@@ -30,7 +32,7 @@ interface Props {
selectedQuickPrompt: QuickPrompt | undefined;
setUpdatedQuickPromptSettings: React.Dispatch>;
handleSave: () => void;
- resetSettings: () => void;
+ onCancelClick: () => void;
}
const QuickPromptSettingsManagementComponent = ({
onSelectedQuickPromptChange,
@@ -38,7 +40,7 @@ const QuickPromptSettingsManagementComponent = ({
selectedQuickPrompt,
setUpdatedQuickPromptSettings,
handleSave,
- resetSettings,
+ onCancelClick,
}: Props) => {
const { isFlyoutOpen: editFlyoutVisible, openFlyout, closeFlyout } = useFlyoutModalVisibility();
const [deletedQuickPrompt, setDeletedQuickPrompt] = useState();
@@ -48,47 +50,51 @@ const QuickPromptSettingsManagementComponent = ({
closeFlyout: closeConfirmModal,
} = useFlyoutModalVisibility();
+ const { onQuickPromptDeleted, onQuickPromptSelectionChange } = useQuickPromptEditor({
+ onSelectedQuickPromptChange,
+ setUpdatedQuickPromptSettings,
+ });
+
const onEditActionClicked = useCallback(
(prompt: QuickPrompt) => {
- onSelectedQuickPromptChange(prompt);
+ onQuickPromptSelectionChange(prompt);
openFlyout();
},
- [onSelectedQuickPromptChange, openFlyout]
+ [onQuickPromptSelectionChange, openFlyout]
);
const onDeleteActionClicked = useCallback(
(prompt: QuickPrompt) => {
setDeletedQuickPrompt(prompt);
+ onQuickPromptDeleted(prompt.title);
openConfirmModal();
},
- [openConfirmModal]
+ [onQuickPromptDeleted, openConfirmModal]
);
const onDeleteCancelled = useCallback(() => {
setDeletedQuickPrompt(null);
closeConfirmModal();
- }, [closeConfirmModal]);
+ onCancelClick();
+ }, [closeConfirmModal, onCancelClick]);
const onDeleteConfirmed = useCallback(() => {
- setUpdatedQuickPromptSettings((prev) =>
- prev.filter((p) => p.title !== deletedQuickPrompt?.title)
- );
handleSave();
closeConfirmModal();
- }, [closeConfirmModal, deletedQuickPrompt?.title, handleSave, setUpdatedQuickPromptSettings]);
+ }, [closeConfirmModal, handleSave]);
const onCreate = useCallback(() => {
onSelectedQuickPromptChange();
openFlyout();
}, [onSelectedQuickPromptChange, openFlyout]);
- const onCancel = useCallback(() => {
+ const onSaveCancelled = useCallback(() => {
onSelectedQuickPromptChange();
closeFlyout();
- resetSettings();
- }, [closeFlyout, onSelectedQuickPromptChange, resetSettings]);
+ onCancelClick();
+ }, [closeFlyout, onSelectedQuickPromptChange, onCancelClick]);
- const onSave = useCallback(() => {
+ const onSaveConfirmed = useCallback(() => {
handleSave();
onSelectedQuickPromptChange();
closeFlyout();
@@ -103,6 +109,16 @@ const QuickPromptSettingsManagementComponent = ({
onEditActionClicked(prompt)}>{prompt?.title}
) : null,
},
+ {
+ field: 'categories',
+ name: i18n.QUICK_PROMPTS_TABLE_COLUMN_CONTEXTS,
+ render: (categories: QuickPrompt['categories']) =>
+ categories?.map((c, idx) => (
+
+ {c}
+
+ )),
+ },
/* TODO: enable when createdAt is added
{
field: 'createdAt',
@@ -118,8 +134,8 @@ const QuickPromptSettingsManagementComponent = ({
return (
rowItem={prompt}
- onDelete={onDeleteActionClicked}
- onEdit={isDeletable ? onEditActionClicked : undefined}
+ onDelete={isDeletable ? onDeleteActionClicked : undefined}
+ onEdit={onEditActionClicked}
isDeletable={isDeletable}
/>
);
@@ -152,9 +168,9 @@ const QuickPromptSettingsManagementComponent = ({
i18n.translate(
'xpack.elasticAssistant.assistant.quickPromptsTable.modal.deleteQuickPromptConfirmationTitle',
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
index 2fb49b3cea07c..288613ba7d907 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings_management.tsx
@@ -6,7 +6,13 @@
*/
import React, { useCallback, useEffect, useMemo, useState } from 'react';
-import { EuiPageTemplate } from '@elastic/eui';
+import {
+ EuiButton,
+ EuiButtonEmpty,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiPageTemplate,
+} from '@elastic/eui';
import { css } from '@emotion/react';
import { Conversation, Prompt, QuickPrompt } from '../../..';
@@ -250,7 +256,7 @@ export const AssistantSettingsManagement: React.FC = React.memo(
handleSave={handleSave}
isFlyoutMode={isFlyoutMode}
refetchConversations={refetchConversations}
- resetSettings={resetSettings}
+ onCancelClick={onCancelClick}
selectedConversation={selectedConversation}
setAssistantStreamingEnabled={handleChange(setUpdatedAssistantStreamingEnabled)}
setConversationSettings={handleChange(setConversationSettings)}
@@ -276,7 +282,7 @@ export const AssistantSettingsManagement: React.FC = React.memo(
)}
conversationsSettingsBulkActions={conversationsSettingsBulkActions}
setUpdatedSystemPromptSettings={handleChange(setUpdatedSystemPromptSettings)}
- resetSettings={resetSettings}
+ onCancelClick={onCancelClick}
/>
)}
{selectedSettingsTab === QUICK_PROMPTS_TAB && (
@@ -286,7 +292,7 @@ export const AssistantSettingsManagement: React.FC = React.memo(
selectedQuickPrompt={selectedQuickPrompt}
setUpdatedQuickPromptSettings={handleChange(setUpdatedQuickPromptSettings)}
handleSave={handleSave}
- resetSettings={resetSettings}
+ onCancelClick={onCancelClick}
/>
)}
{selectedSettingsTab === ANONYMIZATION_TAB && (
@@ -306,9 +312,38 @@ export const AssistantSettingsManagement: React.FC = React.memo(
)}
{selectedSettingsTab === EVALUATION_TAB && }
+ {hasPendingChanges && (
+
+
+
+
+ {i18n.CANCEL}
+
+
+
+
+ {i18n.SAVE}
+
+
+
+
+ )}
>
);
}
);
-AssistantSettingsManagement.displayName = 'AssistantSettingsNew';
+AssistantSettingsManagement.displayName = 'AssistantSettingsManagement';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.tsx
index caff404937308..f2a4eacf47a40 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/use_settings_updater/use_settings_updater.tsx
@@ -72,7 +72,6 @@ export const useSettingsUpdater = (
useState>(conversations);
const [conversationsSettingsBulkActions, setConversationsSettingsBulkActions] =
useState({});
- console.log('updater---', conversationsSettingsBulkActions);
// Quick Prompts
const [updatedQuickPromptSettings, setUpdatedQuickPromptSettings] =
useState(allQuickPrompts);
@@ -153,7 +152,6 @@ export const useSettingsUpdater = (
const bulkAnonymizationFieldsResult = hasBulkAnonymizationFields
? await bulkUpdateAnonymizationFields(http, anonymizationFieldsBulkActions, toasts)
: undefined;
-
return (bulkResult?.success ?? true) && (bulkAnonymizationFieldsResult?.success ?? true);
}, [
setAllQuickPrompts,
@@ -165,9 +163,9 @@ export const useSettingsUpdater = (
toasts,
knowledgeBase.isEnabledKnowledgeBase,
knowledgeBase.isEnabledRAGAlerts,
- updatedAssistantStreamingEnabled,
updatedKnowledgeBaseSettings,
assistantStreamingEnabled,
+ updatedAssistantStreamingEnabled,
setAssistantStreamingEnabled,
setKnowledgeBase,
anonymizationFieldsBulkActions,
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.ts
index e3cfa09f8073b..08a88f4bc0af0 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/helpers.ts
@@ -104,9 +104,8 @@ export const getApiConfig = ({
connectors?: AIConnector[];
defaultConnector?: AIConnector;
}) => {
- const connector: AIConnector | undefined = connectors?.find(
- (c) => c.id === conversation.apiConfig?.connectorId || defaultConnector?.id
- );
+ const connector: AIConnector | undefined =
+ connectors?.find((c) => c.id === conversation.apiConfig?.connectorId) ?? defaultConnector;
const defaultSystemPrompt = getDefaultSystemPrompt({
allSystemPrompts,
conversation,
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx
index 74d6ef1bc169b..580d152e096e4 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx
@@ -70,7 +70,10 @@ export const getConnectorTypeTitle = (
const connectorTypeTitle =
getGenAiConfig(connector)?.apiProvider ??
getActionTypeTitle(actionTypeRegistry.get(connector.actionTypeId));
-
+ console.log('connector', connector);
+ console.log('genaiconfig', getGenAiConfig(connector));
+ console.log('genaiconfig apiProvider', getGenAiConfig(connector)?.apiProvider);
+ console.log('title', getActionTypeTitle(actionTypeRegistry.get(connector.actionTypeId)));
const actionType = connector.isPreconfigured ? PRECONFIGURED_CONNECTOR : connectorTypeTitle;
return actionType;
From 376d82ea003534d50276f42f676f55aaba9600e1 Mon Sep 17 00:00:00 2001
From: Angela Chuang
Date: Fri, 21 Jun 2024 10:14:37 +0100
Subject: [PATCH 09/37] clean up
---
.../use_system_prompt_table.tsx | 20 +++---
.../index.tsx | 54 ++-------------
.../use_quick_prompt_table.tsx | 68 +++++++++++++++++++
3 files changed, 84 insertions(+), 58 deletions(-)
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/use_quick_prompt_table.tsx
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.tsx
index c1e93e471e828..c9b0454a19518 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_settings_management/use_system_prompt_table.tsx
@@ -5,7 +5,6 @@
* 2.0.
*/
import { EuiLink, EuiBadge } from '@elastic/eui';
-import { css } from '@emotion/react';
import React from 'react';
import { Conversation } from '../../../../assistant_context/types';
import { AIConnector } from '../../../../connectorland/connector_selector';
@@ -40,15 +39,16 @@ export const useSystemPromptTable = () => {
{
field: 'defaultConversations',
name: i18n.SYSTEM_PROMPTS_TABLE_COLUMN_DEFAULT_CONVERSATIONS,
- render: (defaultConversations: string[]) => (
-
- {defaultConversations.map((c, idx) => (
-
- {c}
-
- ))}
-
- ),
+ render: (defaultConversations: string[]) =>
+ defaultConversations.length ? (
+
+ {defaultConversations.map((c, idx) => (
+
+ {c}
+
+ ))}
+
+ ) : null,
},
/* TODO: enable when createdAt is added
{
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
index c9a2c90e46090..7879a8da2d069 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/index.tsx
@@ -6,25 +6,22 @@
*/
import React, { useCallback, useMemo, useState } from 'react';
import {
- EuiBadge,
- EuiBasicTableColumn,
EuiButton,
EuiConfirmModal,
EuiFlexGroup,
EuiFlexItem,
EuiInMemoryTable,
- EuiLink,
EuiPanel,
EuiSpacer,
} from '@elastic/eui';
import { QuickPrompt } from '../types';
-import { RowActions } from '../../common/components/assistant_settings_management/row_actions';
import { QuickPromptSettingsEditor } from '../quick_prompt_settings/quick_prompt_editor';
import * as i18n from './translations';
import { useFlyoutModalVisibility } from '../../common/components/assistant_settings_management/flyout/use_flyout_modal_visibility';
import { Flyout } from '../../common/components/assistant_settings_management/flyout';
import { CANCEL, DELETE } from '../../settings/translations';
import { useQuickPromptEditor } from '../quick_prompt_settings/use_quick_prompt_editor';
+import { useQuickPromptTable } from './use_quick_prompt_table';
interface Props {
onSelectedQuickPromptChange: (quickPrompt?: QuickPrompt) => void;
@@ -100,50 +97,11 @@ const QuickPromptSettingsManagementComponent = ({
closeFlyout();
}, [closeFlyout, handleSave, onSelectedQuickPromptChange]);
- const columns: Array> = useMemo(
- () => [
- {
- name: i18n.QUICK_PROMPTS_TABLE_COLUMN_NAME,
- render: (prompt: QuickPrompt) =>
- prompt?.title ? (
- onEditActionClicked(prompt)}>{prompt?.title}
- ) : null,
- },
- {
- field: 'categories',
- name: i18n.QUICK_PROMPTS_TABLE_COLUMN_CONTEXTS,
- render: (categories: QuickPrompt['categories']) =>
- categories?.map((c, idx) => (
-
- {c}
-
- )),
- },
- /* TODO: enable when createdAt is added
- {
- field: 'createdAt',
- name: i18n.QUICK_PROMPTS_TABLE_COLUMN_CREATED_AT,
- },
- */
- {
- name: i18n.QUICK_PROMPTS_TABLE_COLUMN_ACTIONS,
- width: '120px',
- align: 'center',
- render: (prompt: QuickPrompt) => {
- const isDeletable = !prompt.isDefault;
- return (
-
- rowItem={prompt}
- onDelete={isDeletable ? onDeleteActionClicked : undefined}
- onEdit={onEditActionClicked}
- isDeletable={isDeletable}
- />
- );
- },
- },
- ],
- [onDeleteActionClicked, onEditActionClicked]
- );
+ const { getColumns } = useQuickPromptTable();
+ const columns = getColumns({
+ onEditActionClicked,
+ onDeleteActionClicked,
+ });
const confirmationTitle = useMemo(
() =>
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/use_quick_prompt_table.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/use_quick_prompt_table.tsx
new file mode 100644
index 0000000000000..4fe7edab67945
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/quick_prompts/quick_prompt_settings_management.tsx/use_quick_prompt_table.tsx
@@ -0,0 +1,68 @@
+/*
+ * 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 { EuiBadge, EuiLink } from '@elastic/eui';
+import React, { useCallback } from 'react';
+import { RowActions } from '../../common/components/assistant_settings_management/row_actions';
+import { QuickPrompt } from '../types';
+import * as i18n from './translations';
+
+export const useQuickPromptTable = () => {
+ const getColumns = useCallback(
+ ({
+ onEditActionClicked,
+ onDeleteActionClicked,
+ }: {
+ onEditActionClicked: (prompt: QuickPrompt) => void;
+ onDeleteActionClicked: (prompt: QuickPrompt) => void;
+ }) => [
+ {
+ name: i18n.QUICK_PROMPTS_TABLE_COLUMN_NAME,
+ render: (prompt: QuickPrompt) =>
+ prompt?.title ? (
+ onEditActionClicked(prompt)}>{prompt?.title}
+ ) : null,
+ },
+ {
+ field: 'categories',
+ name: i18n.QUICK_PROMPTS_TABLE_COLUMN_CONTEXTS,
+ render: (categories: QuickPrompt['categories']) =>
+ categories?.length
+ ? categories.map((c, idx) => (
+
+ {c}
+
+ ))
+ : null,
+ },
+ /* TODO: enable when createdAt is added
+ {
+ field: 'createdAt',
+ name: i18n.QUICK_PROMPTS_TABLE_COLUMN_CREATED_AT,
+ },
+ */
+ {
+ name: i18n.QUICK_PROMPTS_TABLE_COLUMN_ACTIONS,
+ width: '120px',
+ render: (prompt: QuickPrompt) => {
+ const isDeletable = !prompt.isDefault;
+ return (
+
+ rowItem={prompt}
+ onDelete={isDeletable ? onDeleteActionClicked : undefined}
+ onEdit={onEditActionClicked}
+ isDeletable={isDeletable}
+ />
+ );
+ },
+ },
+ ],
+ []
+ );
+
+ return { getColumns };
+};
From f97b70106757e6478b82d2726ebded2e1831d1b9 Mon Sep 17 00:00:00 2001
From: Angela Chuang
Date: Fri, 21 Jun 2024 13:17:24 +0100
Subject: [PATCH 10/37] default page size to 25
---
.../badges/index.tsx | 23 +++++++++++++++++++
.../flyout/use_flyout_modal_visibility.ts | 15 +++++++-----
.../index.tsx | 17 +++-----------
...ttings.tsx => use_conversations_table.tsx} | 0
.../index.tsx | 11 ++++++++-
.../use_system_prompt_table.tsx | 15 ++++--------
.../index.tsx | 12 +++++++++-
.../use_quick_prompt_table.tsx | 12 +++-------
.../assistant_settings_management.tsx | 5 ----
.../stack_management/management_settings.tsx | 20 ++++++----------
10 files changed, 70 insertions(+), 60 deletions(-)
create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/badges/index.tsx
rename x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/{use_conversation_selector_settings.tsx => use_conversations_table.tsx} (100%)
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/badges/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/badges/index.tsx
new file mode 100644
index 0000000000000..12cb3f49b92b0
--- /dev/null
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/badges/index.tsx
@@ -0,0 +1,23 @@
+/*
+ * 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 { EuiBadge } from '@elastic/eui';
+import React from 'react';
+
+export const BadgesColumn: React.FC<{ items: string[] | null | undefined }> = React.memo(
+ ({ items }) =>
+ items && items.length > 0 ? (
+
+ {items.map((c, idx) => (
+
+ {c}
+
+ ))}
+
+ ) : null
+);
+BadgesColumn.displayName = 'BadgesColumn';
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/use_flyout_modal_visibility.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/use_flyout_modal_visibility.ts
index 01291b6f77252..ad3da6b12242e 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/use_flyout_modal_visibility.ts
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/use_flyout_modal_visibility.ts
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { useState } from 'react';
+import { useMemo, useState } from 'react';
export const useFlyoutModalVisibility = () => {
const [isFlyoutOpen, setIsFlyoutOpen] = useState(false);
@@ -18,9 +18,12 @@ export const useFlyoutModalVisibility = () => {
setIsFlyoutOpen(false);
};
- return {
- isFlyoutOpen,
- openFlyout,
- closeFlyout,
- };
+ return useMemo(
+ () => ({
+ isFlyoutOpen,
+ openFlyout,
+ closeFlyout,
+ }),
+ [isFlyoutOpen]
+ );
};
diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
index e03419925ecda..100d629e1bb56 100644
--- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
+++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/converstaion_settings_management/index.tsx
@@ -10,7 +10,7 @@ import React, { useCallback, useMemo, useState } from 'react';
import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public';
import { Conversation } from '../../../assistant_context/types';
-import { ConversationTableItem, useConversationsTable } from './use_conversation_selector_settings';
+import { ConversationTableItem, useConversationsTable } from './use_conversations_table';
import { ConversationStreamingSwitch } from '../conversation_settings/conversation_streaming_switch';
import { AIConnector } from '../../../connectorland/connector_selector';
import * as i18n from './translations';
@@ -37,7 +37,6 @@ interface Props {
handleSave: () => void;
isDisabled?: boolean;
isFlyoutMode: boolean;
- refetchConversations: () => void;
onCancelClick: () => void;
setAssistantStreamingEnabled: React.Dispatch>;
setConversationSettings: React.Dispatch>>;
@@ -61,7 +60,6 @@ const ConversationSettingsManagementComponent: React.FC = ({
isDisabled,
isFlyoutMode,
onSelectedConversationChange,
- refetchConversations,
onCancelClick,
selectedConversation,
setAssistantStreamingEnabled,
@@ -122,18 +120,9 @@ const ConversationSettingsManagementComponent: React.FC