diff --git a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx index b4330bbea0301..523b12f3c43d4 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings.tsx @@ -5,28 +5,19 @@ * 2.0. */ -import { - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, - EuiRange, - EuiSpacer, - EuiSwitch, - EuiSwitchEvent, - EuiText, - useGeneratedHtmlId, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSpacer, EuiText } from '@elastic/eui'; import { css } from '@emotion/react'; -import React, { useCallback } from 'react'; +import React from 'react'; import { KnowledgeBaseConfig } from '../../assistant/types'; +import { AlertsRange } from '../../knowledge_base/alerts_range'; +import { AlertsSwitch } from '../../knowledge_base/alerts_switch'; import * as i18n from '../../knowledge_base/translations'; export const MIN_LATEST_ALERTS = 10; export const MAX_LATEST_ALERTS = 100; export const TICK_INTERVAL = 10; export const RANGE_CONTAINER_WIDTH = 300; // px -const LABEL_WRAPPER_MIN_WIDTH = 95; // px interface Props { knowledgeBase: KnowledgeBaseConfig; @@ -34,38 +25,13 @@ interface Props { } const AlertsSettingsComponent = ({ knowledgeBase, setUpdatedKnowledgeBaseSettings }: Props) => { - const inputRangeSliderId = useGeneratedHtmlId({ prefix: 'inputRangeSlider' }); - - const onEnableAlertsChange = useCallback( - (event: EuiSwitchEvent) => { - setUpdatedKnowledgeBaseSettings({ - ...knowledgeBase, - isEnabledRAGAlerts: event.target.checked, - }); - }, - [knowledgeBase, setUpdatedKnowledgeBaseSettings] - ); - return ( <> - - - + @@ -77,22 +43,9 @@ const AlertsSettingsComponent = ({ knowledgeBase, setUpdatedKnowledgeBaseSetting grow={false} > - - setUpdatedKnowledgeBaseSettings({ - ...knowledgeBase, - latestAlerts: Number(e.currentTarget.value), - }) - } - showTicks - step={TICK_INTERVAL} - value={knowledgeBase.latestAlerts} + diff --git a/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings_management.tsx b/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings_management.tsx new file mode 100644 index 0000000000000..ddf7f55dbcb2d --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/alerts/settings/alerts_settings_management.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 { EuiPanel, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; +import React from 'react'; +import { KnowledgeBaseConfig } from '../../assistant/types'; +import { AlertsRange } from '../../knowledge_base/alerts_range'; +import { AlertsSwitch } from '../../knowledge_base/alerts_switch'; +import * as i18n from '../../knowledge_base/translations'; + +interface Props { + knowledgeBase: KnowledgeBaseConfig; + setUpdatedKnowledgeBaseSettings: React.Dispatch>; +} + +export const AlertsSettingsManagement: React.FC = React.memo( + ({ knowledgeBase, setUpdatedKnowledgeBaseSettings }) => { + return ( + + +

{i18n.ALERTS_LABEL}

+
+ + + + {i18n.LATEST_AND_RISKIEST_OPEN_ALERTS(knowledgeBase.latestAlerts)} + {i18n.YOUR_ANONYMIZATION_SETTINGS} + + + + + + +
+ ); + } +); + +AlertsSettingsManagement.displayName = 'AlertsSettingsManagement'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/index.tsx index f36591e5dbb0e..ac0109f31b9b7 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/common/components/assistant_settings_management/flyout/index.tsx @@ -22,7 +22,7 @@ import * as i18n from './translations'; interface Props { children: React.ReactNode; - title: string; + title?: string; flyoutVisible: boolean; onClose: () => void; onSaveCancelled: () => void; 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 89c00fbf88773..5f7bd9ab391c2 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 @@ -19,6 +19,8 @@ import { ConversationSettingsManagement } from '../conversations/conversation_se import { QuickPromptSettingsManagement } from '../quick_prompts/quick_prompt_settings_management'; import { SystemPromptSettingsManagement } from '../prompt_editor/system_prompt/system_prompt_settings_management'; import { AnonymizationSettingsManagement } from '../../data_anonymization/settings/anonymization_settings_management'; +import { KnowledgeBaseSettingsManagement } from '../../knowledge_base/knowledge_base_settings_management'; +import { EvaluationSettings } from '.'; import { ANONYMIZATION_TAB, @@ -29,8 +31,6 @@ import { QUICK_PROMPTS_TAB, SYSTEM_PROMPTS_TAB, } from './const'; -import { KnowledgeBaseSettingsManagement } from '../../knowledge_base/knowledge_base_settings_management'; -import { EvaluationSettings } from '.'; interface Props { selectedConversation: Conversation; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/alerts_range.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/alerts_range.tsx new file mode 100644 index 0000000000000..152f0a91a7d04 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/alerts_range.tsx @@ -0,0 +1,60 @@ +/* + * 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 { EuiRange, useGeneratedHtmlId } from '@elastic/eui'; +import { css } from '@emotion/react'; +import React from 'react'; +import { + MAX_LATEST_ALERTS, + MIN_LATEST_ALERTS, + TICK_INTERVAL, +} from '../alerts/settings/alerts_settings'; +import { KnowledgeBaseConfig } from '../assistant/types'; +import { ALERTS_RANGE } from './translations'; + +interface Props { + knowledgeBase: KnowledgeBaseConfig; + setUpdatedKnowledgeBaseSettings: React.Dispatch>; + compressed?: boolean; +} + +const MAX_ALERTS_RANGE_WIDTH = 649; // px + +export const AlertsRange: React.FC = React.memo( + ({ knowledgeBase, setUpdatedKnowledgeBaseSettings, compressed = true }) => { + const inputRangeSliderId = useGeneratedHtmlId({ prefix: 'inputRangeSlider' }); + + return ( + + setUpdatedKnowledgeBaseSettings({ + ...knowledgeBase, + latestAlerts: Number(e.currentTarget.value), + }) + } + showTicks + step={TICK_INTERVAL} + value={knowledgeBase.latestAlerts} + css={css` + max-inline-size: ${MAX_ALERTS_RANGE_WIDTH}px; + & .euiRangeTrack { + margin-inline-start: 0; + margin-inline-end: 0; + } + `} + /> + ); + } +); + +AlertsRange.displayName = 'AlertsRange'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/alerts_switch.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/alerts_switch.tsx new file mode 100644 index 0000000000000..84415326183e1 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/alerts_switch.tsx @@ -0,0 +1,72 @@ +/* + * 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, EuiSwitchEvent, EuiText, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/css'; +import React, { useCallback } from 'react'; +import { KnowledgeBaseConfig } from '../assistant/types'; +import { SEND_ALERTS_LABEL } from './translations'; + +interface Props { + compressed?: boolean; + isEnabledRAGAlerts: boolean; + knowledgeBase: KnowledgeBaseConfig; + setUpdatedKnowledgeBaseSettings: React.Dispatch>; + showLabel?: boolean; +} +const LABEL_WRAPPER_MIN_WIDTH = 95; // px + +export const AlertsSwitch: React.FC = React.memo( + ({ + isEnabledRAGAlerts, + compressed = true, + setUpdatedKnowledgeBaseSettings, + knowledgeBase, + showLabel, + }) => { + const { euiTheme } = useEuiTheme(); + + const onEnableAlertsChange = useCallback( + (event: EuiSwitchEvent) => { + setUpdatedKnowledgeBaseSettings({ + ...knowledgeBase, + isEnabledRAGAlerts: event.target.checked, + }); + }, + [knowledgeBase, setUpdatedKnowledgeBaseSettings] + ); + return ( + + {SEND_ALERTS_LABEL}} + onChange={onEnableAlertsChange} + showLabel={showLabel} + labelProps={ + compressed + ? {} + : { + style: { + paddingLeft: euiTheme.size.base, + }, + } + } + /> + + ); + } +); +AlertsSwitch.displayName = 'AlertsSwitch'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/const.ts b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/const.ts new file mode 100644 index 0000000000000..3cfd0cf3b4205 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/const.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +export const ESQL_RESOURCE = 'esql'; +export const KNOWLEDGE_BASE_INDEX_PATTERN_OLD = '.kibana-elastic-ai-assistant-kb'; +export const KNOWLEDGE_BASE_INDEX_PATTERN = '.kibana-elastic-ai-assistant-knowledge-base-(SPACE)'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx index 335f654890a62..4eb19045a9766 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings.tsx @@ -11,17 +11,13 @@ import { EuiTitle, EuiText, EuiHorizontalRule, - EuiLoadingSpinner, EuiSpacer, - EuiSwitchEvent, EuiLink, EuiBetaBadge, EuiFlexGroup, EuiFlexItem, EuiHealth, EuiButtonEmpty, - EuiToolTip, - EuiSwitch, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; @@ -33,10 +29,13 @@ import * as i18n from './translations'; import { useDeleteKnowledgeBase } from '../assistant/api/knowledge_base/use_delete_knowledge_base'; import { useKnowledgeBaseStatus } from '../assistant/api/knowledge_base/use_knowledge_base_status'; import { useSetupKnowledgeBase } from '../assistant/api/knowledge_base/use_setup_knowledge_base'; - -const ESQL_RESOURCE = 'esql'; -const KNOWLEDGE_BASE_INDEX_PATTERN_OLD = '.kibana-elastic-ai-assistant-kb'; -const KNOWLEDGE_BASE_INDEX_PATTERN = '.kibana-elastic-ai-assistant-knowledge-base-(SPACE)'; +import { KnowledgeBaseToggle } from './knowledge_base_toggle'; +import { + ESQL_RESOURCE, + KNOWLEDGE_BASE_INDEX_PATTERN, + KNOWLEDGE_BASE_INDEX_PATTERN_OLD, +} from './const'; +import { useKnowledgeBaseResultStatus } from './use_knowledge_base_result_status'; interface Props { knowledgeBase: KnowledgeBaseConfig; @@ -60,75 +59,29 @@ export const KnowledgeBaseSettings: React.FC = React.memo( const { mutate: setupKB, isLoading: isSettingUpKB } = useSetupKnowledgeBase({ http }); const { mutate: deleteKB, isLoading: isDeletingUpKB } = useDeleteKnowledgeBase({ http }); - // Resource enabled state - const isElserEnabled = kbStatus?.elser_exists ?? false; - const isKnowledgeBaseEnabled = (kbStatus?.index_exists && kbStatus?.pipeline_exists) ?? false; - const isESQLEnabled = kbStatus?.esql_exists ?? false; - const isSetupInProgress = kbStatus?.is_setup_in_progress ?? false; - - // Resource availability state - const isLoadingKb = - isLoading || isFetching || isSettingUpKB || isDeletingUpKB || isSetupInProgress; - const isKnowledgeBaseAvailable = knowledgeBase.isEnabledKnowledgeBase && kbStatus?.elser_exists; - const isESQLAvailable = - knowledgeBase.isEnabledKnowledgeBase && isKnowledgeBaseAvailable && isKnowledgeBaseEnabled; - // Prevent enabling if elser doesn't exist, but always allow to disable - const isSwitchDisabled = enableKnowledgeBaseByDefault - ? false - : !kbStatus?.elser_exists && !knowledgeBase.isEnabledKnowledgeBase; + const { + isElserEnabled, + isKnowledgeBaseEnabled, + isESQLEnabled, + isLoadingKb, + isKnowledgeBaseAvailable, + isESQLAvailable, + isSwitchDisabled, + } = useKnowledgeBaseResultStatus({ + enableKnowledgeBaseByDefault, + kbStatus, + knowledgeBase, + isLoading, + isFetching, + isSettingUpKB, + isDeletingUpKB, + }); // Calculated health state for EuiHealth component const elserHealth = isElserEnabled ? 'success' : 'subdued'; const knowledgeBaseHealth = isKnowledgeBaseEnabled ? 'success' : 'subdued'; const esqlHealth = isESQLEnabled ? 'success' : 'subdued'; - ////////////////////////////////////////////////////////////////////////////////////////// - // Main `Knowledge Base` switch, which toggles the `isEnabledKnowledgeBase` UI feature toggle - // setting that is saved to localstorage - const onEnableAssistantLangChainChange = useCallback( - (event: EuiSwitchEvent) => { - setUpdatedKnowledgeBaseSettings({ - ...knowledgeBase, - isEnabledKnowledgeBase: event.target.checked, - }); - - // If enabling and ELSER exists or automatic KB setup FF is enabled, try to set up automatically - if (event.target.checked && (enableKnowledgeBaseByDefault || kbStatus?.elser_exists)) { - setupKB(ESQL_RESOURCE); - } - }, - [ - enableKnowledgeBaseByDefault, - kbStatus?.elser_exists, - knowledgeBase, - setUpdatedKnowledgeBaseSettings, - setupKB, - ] - ); - - const isEnabledKnowledgeBaseSwitch = useMemo(() => { - return isLoadingKb ? ( - - ) : ( - - - - ); - }, [ - isLoadingKb, - isSwitchDisabled, - knowledgeBase.isEnabledKnowledgeBase, - onEnableAssistantLangChainChange, - ]); - ////////////////////////////////////////////////////////////////////////////////////////// // Knowledge Base Resource const onEnableKB = useCallback( @@ -255,7 +208,18 @@ export const KnowledgeBaseSettings: React.FC = React.memo( } `} > - {isEnabledKnowledgeBaseSwitch} + diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management.tsx deleted file mode 100644 index d4e9fe7ab6d1d..0000000000000 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management.tsx +++ /dev/null @@ -1,387 +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 React, { useCallback, useMemo, useState } from 'react'; -import { - EuiFormRow, - EuiText, - EuiHorizontalRule, - EuiLoadingSpinner, - EuiSpacer, - EuiSwitchEvent, - EuiLink, - EuiFlexGroup, - EuiFlexItem, - EuiHealth, - EuiButtonEmpty, - EuiToolTip, - EuiSwitch, - EuiPanel, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { css } from '@emotion/react'; - -import { AlertsSettings } from '../alerts/settings/alerts_settings'; -import { useAssistantContext } from '../assistant_context'; -import * as i18n from './translations'; -import { useDeleteKnowledgeBase } from '../assistant/api/knowledge_base/use_delete_knowledge_base'; -import { useKnowledgeBaseStatus } from '../assistant/api/knowledge_base/use_knowledge_base_status'; -import { useSetupKnowledgeBase } from '../assistant/api/knowledge_base/use_setup_knowledge_base'; -import { - useSettingsUpdater, - DEFAULT_CONVERSATIONS, - DEFAULT_PROMPTS, -} from '../assistant/settings/use_settings_updater/use_settings_updater'; -import { AssistantSettingsBottomBar } from '../assistant/settings/assistant_settings_bottom_bar'; -import { SETTINGS_UPDATED_TOAST_TITLE } from '../assistant/settings/translations'; - -const ESQL_RESOURCE = 'esql'; -const KNOWLEDGE_BASE_INDEX_PATTERN_OLD = '.kibana-elastic-ai-assistant-kb'; -const KNOWLEDGE_BASE_INDEX_PATTERN = '.kibana-elastic-ai-assistant-knowledge-base-(SPACE)'; - -/** - * Knowledge Base Settings -- enable and disable LangChain integration, Knowledge Base, and ESQL KB Documents - */ -export const KnowledgeBaseSettingsManagement: React.FC = React.memo(() => { - const { - assistantFeatures: { assistantKnowledgeBaseByDefault: enableKnowledgeBaseByDefault }, - http, - toasts, - } = useAssistantContext(); - const [hasPendingChanges, setHasPendingChanges] = useState(false); - - const { knowledgeBase, setUpdatedKnowledgeBaseSettings, resetSettings, saveSettings } = - useSettingsUpdater( - DEFAULT_CONVERSATIONS, // Knowledge Base settings do not require conversations - DEFAULT_PROMPTS, // Knowledge Base settings do not require prompts - false, // Knowledge Base settings do not require prompts - false // Knowledge Base settings do not require conversations - ); - - const handleSave = useCallback( - async (param?: { callback?: () => void }) => { - await saveSettings(); - toasts?.addSuccess({ - iconType: 'check', - title: SETTINGS_UPDATED_TOAST_TITLE, - }); - setHasPendingChanges(false); - param?.callback?.(); - }, - [saveSettings, toasts] - ); - - const handleUpdateKnowledgeBaseSettings = useCallback( - (updatedKnowledgebase) => { - setHasPendingChanges(true); - setUpdatedKnowledgeBaseSettings(updatedKnowledgebase); - }, - [setUpdatedKnowledgeBaseSettings] - ); - - const onCancelClick = useCallback(() => { - resetSettings(); - setHasPendingChanges(false); - }, [resetSettings]); - - const onSaveButtonClicked = useCallback(() => { - handleSave(); - }, [handleSave]); - - const { - data: kbStatus, - isLoading, - isFetching, - } = useKnowledgeBaseStatus({ http, resource: ESQL_RESOURCE }); - const { mutate: setupKB, isLoading: isSettingUpKB } = useSetupKnowledgeBase({ http }); - const { mutate: deleteKB, isLoading: isDeletingUpKB } = useDeleteKnowledgeBase({ http }); - - // Resource enabled state - const isElserEnabled = kbStatus?.elser_exists ?? false; - const isKnowledgeBaseEnabled = (kbStatus?.index_exists && kbStatus?.pipeline_exists) ?? false; - const isESQLEnabled = kbStatus?.esql_exists ?? false; - const isSetupInProgress = kbStatus?.is_setup_in_progress ?? false; - - // Resource availability state - const isLoadingKb = - isLoading || isFetching || isSettingUpKB || isDeletingUpKB || isSetupInProgress; - const isKnowledgeBaseAvailable = knowledgeBase.isEnabledKnowledgeBase && kbStatus?.elser_exists; - const isESQLAvailable = - knowledgeBase.isEnabledKnowledgeBase && isKnowledgeBaseAvailable && isKnowledgeBaseEnabled; - // Prevent enabling if elser doesn't exist, but always allow to disable - const isSwitchDisabled = enableKnowledgeBaseByDefault - ? false - : !kbStatus?.elser_exists && !knowledgeBase.isEnabledKnowledgeBase; - - // Calculated health state for EuiHealth component - const elserHealth = isElserEnabled ? 'success' : 'subdued'; - const knowledgeBaseHealth = isKnowledgeBaseEnabled ? 'success' : 'subdued'; - const esqlHealth = isESQLEnabled ? 'success' : 'subdued'; - - ////////////////////////////////////////////////////////////////////////////////////////// - // Main `Knowledge Base` switch, which toggles the `isEnabledKnowledgeBase` UI feature toggle - // setting that is saved to localstorage - const onEnableAssistantLangChainChange = useCallback( - (event: EuiSwitchEvent) => { - handleUpdateKnowledgeBaseSettings({ - ...knowledgeBase, - isEnabledKnowledgeBase: event.target.checked, - }); - - // If enabling and ELSER exists or automatic KB setup FF is enabled, try to set up automatically - if (event.target.checked && (enableKnowledgeBaseByDefault || kbStatus?.elser_exists)) { - setupKB(ESQL_RESOURCE); - } - }, - [ - enableKnowledgeBaseByDefault, - handleUpdateKnowledgeBaseSettings, - kbStatus?.elser_exists, - knowledgeBase, - setupKB, - ] - ); - - const isEnabledKnowledgeBaseSwitch = useMemo(() => { - return isLoadingKb ? ( - - ) : ( - - - - ); - }, [ - isLoadingKb, - isSwitchDisabled, - knowledgeBase.isEnabledKnowledgeBase, - onEnableAssistantLangChainChange, - ]); - - ////////////////////////////////////////////////////////////////////////////////////////// - // Knowledge Base Resource - const onEnableKB = useCallback( - (enabled: boolean) => { - if (enabled) { - setupKB(); - } else { - deleteKB(); - } - }, - [deleteKB, setupKB] - ); - - const knowledgeBaseActionButton = useMemo(() => { - return isLoadingKb || !isKnowledgeBaseAvailable ? ( - <> - ) : ( - onEnableKB(!isKnowledgeBaseEnabled)} - size="xs" - > - {isKnowledgeBaseEnabled - ? i18n.KNOWLEDGE_BASE_DELETE_BUTTON - : i18n.KNOWLEDGE_BASE_INIT_BUTTON} - - ); - }, [isKnowledgeBaseAvailable, isKnowledgeBaseEnabled, isLoadingKb, onEnableKB]); - - const knowledgeBaseDescription = useMemo(() => { - return isKnowledgeBaseEnabled ? ( - - {i18n.KNOWLEDGE_BASE_DESCRIPTION_INSTALLED( - enableKnowledgeBaseByDefault - ? KNOWLEDGE_BASE_INDEX_PATTERN - : KNOWLEDGE_BASE_INDEX_PATTERN_OLD - )}{' '} - {knowledgeBaseActionButton} - - ) : ( - - {i18n.KNOWLEDGE_BASE_DESCRIPTION} {knowledgeBaseActionButton} - - ); - }, [enableKnowledgeBaseByDefault, isKnowledgeBaseEnabled, knowledgeBaseActionButton]); - - ////////////////////////////////////////////////////////////////////////////////////////// - // ESQL Resource - const onEnableESQL = useCallback( - (enabled: boolean) => { - if (enabled) { - setupKB(ESQL_RESOURCE); - } else { - deleteKB(ESQL_RESOURCE); - } - }, - [deleteKB, setupKB] - ); - - const esqlActionButton = useMemo(() => { - return isLoadingKb || !isESQLAvailable ? ( - <> - ) : ( - onEnableESQL(!isESQLEnabled)} - size="xs" - > - {isESQLEnabled ? i18n.KNOWLEDGE_BASE_DELETE_BUTTON : i18n.KNOWLEDGE_BASE_INIT_BUTTON} - - ); - }, [isLoadingKb, isESQLAvailable, isESQLEnabled, onEnableESQL]); - - const esqlDescription = useMemo(() => { - return isESQLEnabled ? ( - - {i18n.ESQL_DESCRIPTION_INSTALLED} {esqlActionButton} - - ) : ( - - {i18n.ESQL_DESCRIPTION} {esqlActionButton} - - ); - }, [esqlActionButton, isESQLEnabled]); - - return ( - - - - {i18n.KNOWLEDGE_BASE_DOCUMENTATION} - - ), - }} - /> - - - - - {isEnabledKnowledgeBaseSwitch} - - - - - -
- {i18n.KNOWLEDGE_BASE_ELSER_LABEL} - - - {i18n.KNOWLEDGE_BASE_ELSER_MACHINE_LEARNING} - - ), - seeDocs: ( - - {i18n.KNOWLEDGE_BASE_ELSER_SEE_DOCS} - - ), - }} - /> - -
-
- -
- {i18n.KNOWLEDGE_BASE_LABEL} - - {knowledgeBaseDescription} - -
-
- - - {i18n.ESQL_LABEL} - - {esqlDescription} - - - -
- - - - - - -
- ); -}); - -KnowledgeBaseSettingsManagement.displayName = 'KnowledgeBaseSettingsManagement'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/entry_button.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/entry_button.tsx new file mode 100644 index 0000000000000..a6507be37dfd7 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/entry_button.tsx @@ -0,0 +1,90 @@ +/* + * 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, + EuiIcon, + EuiPopover, +} from '@elastic/eui'; +import React, { useCallback, useState } from 'react'; +import * as i18n from './translations'; + +interface Props { + isDocumentAvailable?: boolean; + isIndexAvailable?: boolean; + onDocumentClicked?: () => void; + onIndexClicked?: () => void; +} + +const EntryButtonComponent = ({ + isDocumentAvailable = true, + isIndexAvailable = true, + onDocumentClicked, + onIndexClicked, +}: Props) => { + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const closePopover = useCallback(() => setIsPopoverOpen(false), []); + const handleIndexClicked = useCallback(() => { + closePopover(); + onIndexClicked?.(); + }, [closePopover, onIndexClicked]); + + const handleDocumentClicked = useCallback(() => { + closePopover(); + onDocumentClicked?.(); + }, [closePopover, onDocumentClicked]); + + const onButtonClick = useCallback(() => setIsPopoverOpen((prevState) => !prevState), []); + return onIndexClicked || onDocumentClicked ? ( + + + {i18n.ENTRY} + + } + isOpen={isPopoverOpen} + closePopover={closePopover} + anchorPosition="downLeft" + > + + {onIndexClicked != null && ( + + + {i18n.INDEX} + + + )} + {onDocumentClicked != null && ( + + + {i18n.DOCUMENT} + + + )} + + + ) : null; +}; + +export const EntryButton = React.memo(EntryButtonComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/entry_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/entry_editor.tsx new file mode 100644 index 0000000000000..bbe19132491a9 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/entry_editor.tsx @@ -0,0 +1,96 @@ +/* + * 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 { + EuiButtonGroup, + EuiCheckbox, + EuiComboBox, + EuiFieldText, + EuiForm, + EuiFormRow, + EuiMarkdownEditor, +} from '@elastic/eui'; +import React, { useCallback, useMemo, useState } from 'react'; +import { KnowledgeBaseEntryResponse } from '@kbn/elastic-assistant-common'; +import { css } from '@emotion/react'; +import * as i18n from './translations'; + +interface Props { + entry?: KnowledgeBaseEntryResponse; +} + +export const EntryEditor: React.FC = React.memo(({ entry }) => { + const [markdownValue, setMarkdownValue] = React.useState(''); + const accessOptions = useMemo( + () => [ + { id: 'user', label: i18n.ENTRY_ACCESS_USER_BUTTON_LABEL }, + { id: 'global', label: i18n.ENTRY_ACCESS_GLOBAL_BUTTON_LABEL }, + ], + [] + ); + const [toggleCompressedIdSelected, setToggleCompressedIdSelected] = useState(accessOptions[0].id); + + const onAccessChanged = useCallback((optionId: string) => { + setToggleCompressedIdSelected(optionId); + }, []); + + const onRequiredKnowledgeChanged = useCallback((e: React.ChangeEvent) => {}, + []); + return ( + + + + + + + + + + + + onAccessChanged(id)} + isFullWidth + css={css` + width: 300px; + `} + /> + + + + + + ); +}); + +EntryEditor.displayName = 'EntryEditor'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx new file mode 100644 index 0000000000000..84252543f3e91 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index.tsx @@ -0,0 +1,233 @@ +/* + * 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, + EuiLink, + EuiPanel, + EuiSearchBarProps, + EuiSpacer, + EuiText, +} from '@elastic/eui'; +import React, { useCallback, useMemo, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { KnowledgeBaseEntryResponse } from '@kbn/elastic-assistant-common'; +import { AlertsSettingsManagement } from '../../alerts/settings/alerts_settings_management'; +import { useKnowledgeBaseEntries } from '../../assistant/api/knowledge_base/entries/use_knowledge_base_entries'; +import { useDeleteKnowledgeBase } from '../../assistant/api/knowledge_base/use_delete_knowledge_base'; +import { useKnowledgeBaseStatus } from '../../assistant/api/knowledge_base/use_knowledge_base_status'; +import { useSetupKnowledgeBase } from '../../assistant/api/knowledge_base/use_setup_knowledge_base'; +import { useAssistantContext } from '../../assistant_context'; +import { ESQL_RESOURCE } from '../const'; +import { KnowledgeBaseToggle } from '../knowledge_base_toggle'; +import { useKnowledgeBaseResultStatus } from '../use_knowledge_base_result_status'; +import { useKnowledgeBaseTable } from './use_knowledge_base_table'; +import { AssistantSettingsBottomBar } from '../../assistant/settings/assistant_settings_bottom_bar'; +import { + useSettingsUpdater, + DEFAULT_CONVERSATIONS, + DEFAULT_PROMPTS, +} from '../../assistant/settings/use_settings_updater/use_settings_updater'; +import { SETTINGS_UPDATED_TOAST_TITLE } from '../../assistant/settings/translations'; +import { KnowledgeBaseSettings } from '../knowledge_base_settings'; +import { EntryButton } from './entry_button'; +import { + DEFAULT_FLYOUT_TITLE, + SEARCH_PLACEHOLDER, + KNOWLEDGE_BASE_DOCUMENTATION, +} from './translations'; +import { Flyout } from '../../assistant/common/components/assistant_settings_management/flyout'; +import { useFlyoutModalVisibility } from '../../assistant/common/components/assistant_settings_management/flyout/use_flyout_modal_visibility'; +import { IndexEntryEditor } from './index_entry_editor'; +import { EntryEditor } from './entry_editor'; + +export const KnowledgeBaseSettingsManagement: React.FC = React.memo(() => { + const { + assistantFeatures: { assistantKnowledgeBaseByDefault: enableKnowledgeBaseByDefault }, + http, + toasts, + } = useAssistantContext(); + const [hasPendingChanges, setHasPendingChanges] = useState(false); + + const { knowledgeBase, setUpdatedKnowledgeBaseSettings, resetSettings, saveSettings } = + useSettingsUpdater( + DEFAULT_CONVERSATIONS, // Knowledge Base settings do not require conversations + DEFAULT_PROMPTS, // Knowledge Base settings do not require prompts + false, // Knowledge Base settings do not require conversations + false // Knowledge Base settings do not require prompts + ); + + const handleSave = useCallback( + async (param?: { callback?: () => void }) => { + await saveSettings(); + toasts?.addSuccess({ + iconType: 'check', + title: SETTINGS_UPDATED_TOAST_TITLE, + }); + setHasPendingChanges(false); + param?.callback?.(); + }, + [saveSettings, toasts] + ); + + const onCancelClick = useCallback(() => { + resetSettings(); + setHasPendingChanges(false); + }, [resetSettings]); + + const onSaveButtonClicked = useCallback(() => { + handleSave(); + }, [handleSave]); + + const { isFlyoutOpen: isFlyoutVisible, openFlyout, closeFlyout } = useFlyoutModalVisibility(); + + const onSaveConfirmed = useCallback(() => { + handleSave({ callback: closeFlyout }); + }, [handleSave, closeFlyout]); + + const onSaveCancelled = useCallback(() => { + onCancelClick(); + closeFlyout(); + }, [closeFlyout, onCancelClick]); + + const { + data: kbStatus, + isLoading, + isFetching, + } = useKnowledgeBaseStatus({ http, resource: ESQL_RESOURCE }); + const { mutate: setupKB, isLoading: isSettingUpKB } = useSetupKnowledgeBase({ http }); + const { isLoading: isDeletingUpKB } = useDeleteKnowledgeBase({ http }); + const { data: entries } = useKnowledgeBaseEntries({ http }); + const { getColumns } = useKnowledgeBaseTable(); + const columns = useMemo( + () => + getColumns({ + onEntryNameClicked: ({ id }: KnowledgeBaseEntryResponse) => {}, + onSpaceNameClicked: ({ namespace }: KnowledgeBaseEntryResponse) => {}, + onDeleteActionClicked: ({ id }: KnowledgeBaseEntryResponse) => {}, + onEditActionClicked: ({ id }: KnowledgeBaseEntryResponse) => {}, + }), + [getColumns] + ); + + const { isLoadingKb, isSwitchDisabled } = useKnowledgeBaseResultStatus({ + enableKnowledgeBaseByDefault, + kbStatus, + knowledgeBase, + isLoading, + isFetching, + isSettingUpKB, + isDeletingUpKB, + }); + + const [selectedType, setSelectedType] = useState(null); + const onDocumentClicked = useCallback(() => { + setSelectedType('Document'); + openFlyout(); + }, [openFlyout]); + + const onIndexClicked = useCallback(() => { + setSelectedType('Index'); + openFlyout(); + }, [openFlyout]); + + const search: EuiSearchBarProps = useMemo( + () => ({ + toolsRight: ( + + ), + box: { + incremental: true, + placeholder: SEARCH_PLACEHOLDER, + }, + filters: [ + { + type: 'field_value_selection', + field: 'namespace', + name: 'Spaces', + multiSelect: false, + options: entries.data.map(({ namespace }) => ({ + value: namespace, + })), + }, + ], + }), + [entries.data, onDocumentClicked, onIndexClicked] + ); + + if (!enableKnowledgeBaseByDefault) { + return ( + + ); + } + + return ( + <> + + + + + + {KNOWLEDGE_BASE_DOCUMENTATION} + + ), + }} + /> + + + + + + + + + <> + {selectedType === 'Document' && } + {selectedType === 'Index' && } + + + + ); +}); + +KnowledgeBaseSettingsManagement.displayName = 'KnowledgeBaseSettingsManagement'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.tsx new file mode 100644 index 0000000000000..ff8a3563d09ce --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/index_entry_editor.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 { EuiComboBox, EuiFieldText, EuiForm, EuiFormRow } from '@elastic/eui'; +import React from 'react'; +import { KnowledgeBaseEntryResponse } from '@kbn/elastic-assistant-common'; +import * as i18n from './translations'; + +interface Props { + entry?: KnowledgeBaseEntryResponse; +} + +export const IndexEntryEditor: React.FC = React.memo(({ entry }) => { + return ( + + + + + + + + + + + + + + + + + + ); +}); +IndexEntryEditor.displayName = 'IndexEntryEditor'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/translations.ts new file mode 100644 index 0000000000000..604108377b666 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/translations.ts @@ -0,0 +1,228 @@ +/* + * 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 ENTRY = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryLabel', + { + defaultMessage: 'Entry', + } +); + +export const INDEX = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.indexLabel', + { + defaultMessage: 'Index', + } +); + +export const DOCUMENT = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.documentLabel', + { + defaultMessage: 'Document', + } +); + +export const COLUMN_NAME = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.columnNameLabel', + { + defaultMessage: 'Name', + } +); + +export const COLUMN_USERS = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.columnUsersLabel', + { + defaultMessage: 'Users', + } +); + +export const COLUMN_SPACE = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.columnSpaceLabel', + { + defaultMessage: 'Space', + } +); + +export const COLUMN_DATE_CREATED = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.columnDateCreatedLabel', + { + defaultMessage: 'Date created', + } +); + +export const COLUMN_ACTIONS = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.columnActionsLabel', + { + defaultMessage: 'Actions', + } +); + +export const SEARCH_PLACEHOLDER = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.searchPlaceholder', + { + defaultMessage: 'Search for an entry', + } +); + +export const DEFAULT_FLYOUT_TITLE = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.defaultFlyoutTitle', + { + defaultMessage: 'Knowledge Base', + } +); + +export const MANUAL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.manualButtonLabel', + { + defaultMessage: 'Manual', + } +); + +export const CREATE_INDEX_TITLE = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.createIndexTitle', + { + defaultMessage: 'New Index entry', + } +); + +export const NEW_ENTRY_TITLE = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.newEntryTitle', + { + defaultMessage: 'New entry', + } +); + +export const DELETE_ENTRY_DEFAULT_TITLE = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.deleteEntryDefaultTitle', + { + defaultMessage: 'Delete item', + } +); + +export const ENTRY_NAME_INPUT_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryNameInputLabel', + { + defaultMessage: 'Name', + } +); + +export const ENTRY_NAME_INPUT_PLACEHOLDER = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryNameInputPlaceholder', + { + defaultMessage: 'Name your Knowledge Base entry', + } +); + +export const ENTRY_SPACE_INPUT_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entrySpaceInputLabel', + { + defaultMessage: 'Space', + } +); + +export const ENTRY_SPACE_INPUT_PLACEHOLDER = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entrySpaceInputPlaceholder', + { + defaultMessage: 'Select', + } +); + +export const DELETE_ENTRY_CONFIRMATION_TITLE = (title: string) => + i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.deleteEntryTitle', + { + values: { title }, + defaultMessage: 'Delete "{title}"?', + } + ); + +export const ENTRY_MARKDOWN_INPUT_TEXT = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryMarkdownInputText', + { + defaultMessage: 'Markdown text', + } +); + +export const ENTRY_ACCESS_INPUT_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryAccessInputLabel', + { + defaultMessage: 'Access', + } +); + +export const ENTRY_ACCESS_HELP_TEXT = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryAccessHelpText', + { + defaultMessage: 'Set to global if you’d like other users in your Org to have access.', + } +); + +export const ENTRY_ACCESS_USER_BUTTON_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryAccessUserButtonLabel', + { + defaultMessage: 'User', + } +); + +export const ENTRY_ACCESS_GLOBAL_BUTTON_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryAccessGlobalButtonLabel', + { + defaultMessage: 'Global', + } +); + +export const ENTRY_REQUIRED_KNOWLEDGE_HELP_TEXT = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryRequiredKnowledgeHelpText', + { + defaultMessage: + 'Check to indicate a Knowledge Base entry that’s included in every conversation', + } +); + +export const ENTRY_REQUIRED_KNOWLEDGE_CHECKBOX_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryRequiredKnowledgeCheckboxLabel', + { + defaultMessage: 'Required knowledge', + } +); + +export const ENTRY_INDEX_NAME_INPUT_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryIndexNameInputLabel', + { + defaultMessage: 'Index', + } +); + +export const ENTRY_FIELD_INPUT_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryFieldInputLabel', + { + defaultMessage: 'Field', + } +); + +export const ENTRY_DESCRIPTION_INPUT_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryDescriptionInputLabel', + { + defaultMessage: 'Description', + } +); + +export const ENTRY_INPUT_PLACEHOLDER = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.entryInputPlaceholder', + { + defaultMessage: 'Input', + } +); + +export const KNOWLEDGE_BASE_DOCUMENTATION = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettingsManagement.knowledgeBaseDocumentation', + { + defaultMessage: 'documentation', + } +); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/use_knowledge_base_table.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/use_knowledge_base_table.tsx new file mode 100644 index 0000000000000..b8253cb576b15 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_settings_management/use_knowledge_base_table.tsx @@ -0,0 +1,82 @@ +/* + * 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, EuiLink } from '@elastic/eui'; +import React, { useCallback } from 'react'; +import { FormattedDate } from '@kbn/i18n-react'; +import { KnowledgeBaseEntryResponse } from '@kbn/elastic-assistant-common'; +import * as i18n from './translations'; +import { BadgesColumn } from '../../assistant/common/components/assistant_settings_management/badges'; +import { useInlineActions } from '../../assistant/common/components/assistant_settings_management/inline_actions'; + +export const useKnowledgeBaseTable = () => { + const getActions = useInlineActions(); + + const getColumns = useCallback( + ({ + onEntryNameClicked, + onSpaceNameClicked, + onDeleteActionClicked, + onEditActionClicked, + }): Array> => { + return [ + { + name: i18n.COLUMN_NAME, + render: ({ id }: KnowledgeBaseEntryResponse) => ( + onEntryNameClicked(id)}>{id} + ), + sortable: ({ id }: KnowledgeBaseEntryResponse) => id, + }, + { + name: i18n.COLUMN_USERS, + render: ({ id, users }: KnowledgeBaseEntryResponse) => { + const items = users?.reduce((acc, user) => { + if (user.name && user.name.length > 0) { + acc.push(user.name); + } + return acc; + }, []); + return ; + }, + }, + { + name: i18n.COLUMN_SPACE, + render: ({ namespace }: { namespace: string }) => ( + onSpaceNameClicked(namespace)}>{namespace} + ), + sortable: ({ namespace }: KnowledgeBaseEntryResponse) => namespace, + }, + { + name: i18n.COLUMN_DATE_CREATED, + render: ({ createdAt }: { createdAt: string }) => ( + <> + {createdAt ? ( + + + + ) : null} + + ), + sortable: ({ createdAt }: KnowledgeBaseEntryResponse) => createdAt, + }, + { + ...getActions({ + onDelete: onDeleteActionClicked, + onEdit: onEditActionClicked, + }), + }, + ]; + }, + [getActions] + ); + return { getColumns }; +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_toggle.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_toggle.tsx new file mode 100644 index 0000000000000..6cffc1e913220 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/knowledge_base_toggle.tsx @@ -0,0 +1,109 @@ +/* + * 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, + EuiLoadingSpinner, + EuiSwitch, + EuiSwitchEvent, + EuiTitle, + EuiToolTip, + useEuiTheme, +} from '@elastic/eui'; +import React, { useCallback } from 'react'; +import { KnowledgeBaseConfig } from '../assistant/types'; +import { ESQL_RESOURCE } from './const'; +import * as i18n from './translations'; + +interface Props { + compressed: boolean; + enableKnowledgeBaseByDefault: boolean; + isEnabledKnowledgeBase: boolean; + isLoadingKb: boolean; + isSwitchDisabled: boolean; + kbStatusElserExists: boolean; + knowledgeBase: KnowledgeBaseConfig; + setUpdatedKnowledgeBaseSettings: React.Dispatch>; + setupKB: (resource: string) => void; + showLabel?: boolean; +} + +export const KnowledgeBaseToggle: React.FC = React.memo( + ({ + compressed, + enableKnowledgeBaseByDefault, + isEnabledKnowledgeBase, + isLoadingKb, + isSwitchDisabled, + kbStatusElserExists, + knowledgeBase, + setUpdatedKnowledgeBaseSettings, + setupKB, + showLabel, + }) => { + const { euiTheme } = useEuiTheme(); + ////////////////////////////////////////////////////////////////////////////////////////// + // Main `Knowledge Base` switch, which toggles the `isEnabledKnowledgeBase` UI feature toggle + // setting that is saved to localstorage + const onEnableAssistantLangChainChange = useCallback( + (event: EuiSwitchEvent) => { + setUpdatedKnowledgeBaseSettings({ + ...knowledgeBase, + isEnabledKnowledgeBase: event.target.checked, + }); + + // If enabling and ELSER exists or automatic KB setup FF is enabled, try to set up automatically + if (event.target.checked && (enableKnowledgeBaseByDefault || kbStatusElserExists)) { + setupKB(ESQL_RESOURCE); + } + }, + [ + enableKnowledgeBaseByDefault, + kbStatusElserExists, + knowledgeBase, + setUpdatedKnowledgeBaseSettings, + setupKB, + ] + ); + return isLoadingKb ? ( + + ) : ( + + + + ) : ( + +

{i18n.KNOWLEDGE_BASE_LABEL}

+
+ ) + } + compressed={compressed} + labelProps={ + compressed + ? {} + : { + style: { + paddingLeft: euiTheme.size.base, + }, + } + } + /> +
+
+ ); + } +); + +KnowledgeBaseToggle.displayName = 'KnowledgeBaseToggle'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/translations.ts index 28cd2092e4cfa..31d2beaabe753 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/translations.ts @@ -14,6 +14,13 @@ export const ALERTS_LABEL = i18n.translate( } ); +export const SEND_ALERTS_LABEL = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettings.sendAlertsLabel', + { + defaultMessage: 'Send Alerts', + } +); + export const ASK_QUESTIONS_ABOUT = i18n.translate( 'xpack.elasticAssistant.assistant.settings.knowledgeBaseSettings.askQuestionsAboutLabel', { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_knowledge_base_result_status.tsx b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_knowledge_base_result_status.tsx new file mode 100644 index 0000000000000..5371e81e94cb7 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/knowledge_base/use_knowledge_base_result_status.tsx @@ -0,0 +1,56 @@ +/* + * 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 { ReadKnowledgeBaseResponse } from '@kbn/elastic-assistant-common'; +import { KnowledgeBaseConfig } from '../assistant/types'; +interface Props { + enableKnowledgeBaseByDefault: boolean; + kbStatus: ReadKnowledgeBaseResponse | undefined; + knowledgeBase: KnowledgeBaseConfig; + isLoading: boolean; + isFetching: boolean; + isSettingUpKB: boolean; + isDeletingUpKB: boolean; +} + +export const useKnowledgeBaseResultStatus = ({ + enableKnowledgeBaseByDefault, + kbStatus, + knowledgeBase, + isLoading, + isFetching, + isSettingUpKB, + isDeletingUpKB, +}: Props) => { + // Resource enabled state + const isElserEnabled = kbStatus?.elser_exists ?? false; + const isKnowledgeBaseEnabled = (kbStatus?.index_exists && kbStatus?.pipeline_exists) ?? false; + const isESQLEnabled = kbStatus?.esql_exists ?? false; + const isSetupInProgress = kbStatus?.is_setup_in_progress ?? false; + + // Resource availability state + const isLoadingKb = + isLoading || isFetching || isSettingUpKB || isDeletingUpKB || isSetupInProgress; + const isKnowledgeBaseAvailable = knowledgeBase.isEnabledKnowledgeBase && kbStatus?.elser_exists; + const isESQLAvailable = + knowledgeBase.isEnabledKnowledgeBase && isKnowledgeBaseAvailable && isKnowledgeBaseEnabled; + // Prevent enabling if elser doesn't exist, but always allow to disable + const isSwitchDisabled = enableKnowledgeBaseByDefault + ? false + : !kbStatus?.elser_exists && !knowledgeBase.isEnabledKnowledgeBase; + + return { + isElserEnabled, + isKnowledgeBaseEnabled, + isESQLEnabled, + isSetupInProgress, + isLoadingKb, + isKnowledgeBaseAvailable, + isESQLAvailable, + isSwitchDisabled, + }; +};