diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_title/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_title/index.tsx index 766811d70ebe6..ccf04c38f5c93 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_title/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_title/index.tsx @@ -56,7 +56,7 @@ export const AssistantTitle: React.FC<{ const content = useMemo( () => ( -

{i18n.TOOLTIP_TITLE}

{content}

@@ -112,7 +111,6 @@ export const AssistantTitle: React.FC<{ {}} - onConnectorSelectionChange={() => {}} selectedConnectorId={selectedConnectorId} selectedConversation={selectedConversation} /> 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 853501da409c1..a0c8226b3ea7e 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 @@ -23,6 +23,8 @@ import { ModelSelector } from '../../../connectorland/models/model_selector/mode import { UseAssistantContext } from '../../../assistant_context'; import { ConversationSelectorSettings } from '../conversation_selector_settings'; import { getDefaultSystemPrompt } from '../../use_conversation/helpers'; +import { useLoadConnectors } from '../../../connectorland/use_load_connectors'; +import { getGenAiConfig } from '../../../connectorland/helpers'; export interface ConversationSettingsProps { actionTypeRegistry: ActionTypeRegistryContract; @@ -63,6 +65,8 @@ export const ConversationSettings: React.FC = React.m return getDefaultSystemPrompt({ allSystemPrompts, conversation: selectedConversation }); }, [allSystemPrompts, selectedConversation]); + const { data: connectors, isSuccess: areConnectorsFetched } = useLoadConnectors({ http }); + // Conversation callbacks // When top level conversation selection changes const onConversationSelectionChange = useCallback( @@ -131,10 +135,13 @@ export const ConversationSettings: React.FC = React.m [selectedConversation, setUpdatedConversationSettings] ); - const selectedConnectorId = useMemo( - () => selectedConversation?.apiConfig.connectorId, - [selectedConversation?.apiConfig.connectorId] - ); + 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, @@ -142,16 +149,19 @@ export const ConversationSettings: React.FC = React.m ); const handleOnConnectorSelectionChange = useCallback( - (connectorId: string, provider: OpenAiProviderType) => { + (connector) => { if (selectedConversation != null) { + const config = getGenAiConfig(connector); + setUpdatedConversationSettings((prev) => ({ ...prev, [selectedConversation.id]: { ...selectedConversation, apiConfig: { ...selectedConversation.apiConfig, - connectorId, - provider, + connectorId: connector?.id, + provider: config?.apiProvider, + model: config?.defaultModel, }, }, })); @@ -160,10 +170,11 @@ export const ConversationSettings: React.FC = React.m [selectedConversation, setUpdatedConversationSettings] ); - const selectedModel = useMemo( - () => selectedConversation?.apiConfig.model, - [selectedConversation?.apiConfig.model] - ); + 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) => { @@ -244,23 +255,24 @@ export const ConversationSettings: React.FC = React.m isDisabled={selectedConversation == null} onConnectorModalVisibilityChange={() => {}} onConnectorSelectionChange={handleOnConnectorSelectionChange} - selectedConnectorId={selectedConnectorId} + selectedConnectorId={selectedConnector?.id} /> - {selectedProvider === OpenAiProviderType.OpenAi && ( - - - - )} + {selectedConnector?.isPreconfigured === false && + selectedProvider === OpenAiProviderType.OpenAi && ( + + + + )} ); } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/translations.ts index 580e02247e3ee..7afa89f8f4ab6 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/translations.ts @@ -41,13 +41,6 @@ export const API_ERROR = i18n.translate('xpack.elasticAssistant.assistant.apiErr 'An error occurred sending your message. If the problem persists, please test the connector configuration.', }); -export const TOOLTIP_TITLE = i18n.translate( - 'xpack.elasticAssistant.assistant.technicalPreview.tooltipTitle', - { - defaultMessage: 'Beta', - } -); - export const TOOLTIP_ARIA_LABEL = i18n.translate( 'xpack.elasticAssistant.documentationLinks.ariaLabel', { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector/index.tsx index f1a03329657b6..df3f0b54cd14f 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector/index.tsx @@ -14,31 +14,24 @@ import { } from '@kbn/triggers-actions-ui-plugin/public'; import { HttpSetup } from '@kbn/core-http-browser'; -import { ActionConnectorProps } from '@kbn/triggers-actions-ui-plugin/public/types'; import { ConnectorAddModal } from '@kbn/triggers-actions-ui-plugin/public/common/constants'; -import { - GEN_AI_CONNECTOR_ID, - OpenAiProviderType, -} from '@kbn/stack-connectors-plugin/public/common'; +import { GEN_AI_CONNECTOR_ID } from '@kbn/stack-connectors-plugin/public/common'; import { useLoadConnectors } from '../use_load_connectors'; import * as i18n from '../translations'; import { useLoadActionTypes } from '../use_load_action_types'; import { useAssistantContext } from '../../assistant_context'; +import { getGenAiConfig } from '../helpers'; export const ADD_NEW_CONNECTOR = 'ADD_NEW_CONNECTOR'; interface Props { actionTypeRegistry: ActionTypeRegistryContract; http: HttpSetup; isDisabled?: boolean; - onConnectorSelectionChange: (connectorId: string, provider: OpenAiProviderType) => void; + onConnectorSelectionChange: (connector: ActionConnector | undefined) => void; selectedConnectorId?: string; onConnectorModalVisibilityChange?: (isVisible: boolean) => void; } -interface Config { - apiProvider: string; -} - export const ConnectorSelector: React.FC = React.memo( ({ actionTypeRegistry, @@ -95,18 +88,19 @@ export const ConnectorSelector: React.FC = React.memo( const connectorOptions = useMemo(() => { return ( connectors?.map((connector) => { - const apiProvider: string | undefined = ( - connector as ActionConnectorProps - )?.config?.apiProvider; + const apiProvider = getGenAiConfig(connector)?.apiProvider; + const connectorDetails = connector.isPreconfigured + ? i18n.PRECONFIGURED_CONNECTOR + : apiProvider; return { value: connector.id, inputDisplay: connector.name, dropdownDisplay: ( {connector.name} - {apiProvider && ( - -

{apiProvider}

+ {connectorDetails && ( + +

{connectorDetails}

)}
@@ -138,10 +132,8 @@ export const ConnectorSelector: React.FC = React.memo( return; } - const apiProvider = ( - connectors?.find((c) => c.id === connectorId) as ActionConnectorProps - )?.config.apiProvider as OpenAiProviderType; - onConnectorSelectionChange(connectorId, apiProvider); + const connector = connectors?.find((c) => c.id === connectorId); + onConnectorSelectionChange(connector); }, [connectors, onConnectorSelectionChange, onConnectorModalVisibilityChange] ); @@ -162,12 +154,8 @@ export const ConnectorSelector: React.FC = React.memo( { - onConnectorSelectionChange( - savedAction.id, - (savedAction as ActionConnectorProps)?.config - .apiProvider as OpenAiProviderType - ); + postSaveEventHandler={(connector: ActionConnector) => { + onConnectorSelectionChange(connector); refetchConnectors?.(); cleanupAndCloseModal(); }} diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.test.tsx index 774098eba8b2e..3b1ff0be86181 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.test.tsx @@ -65,7 +65,6 @@ describe('ConnectorSelectorInline', () => { @@ -85,7 +84,6 @@ describe('ConnectorSelectorInline', () => { @@ -105,7 +103,6 @@ describe('ConnectorSelectorInline', () => { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.tsx index 66d7971731deb..d7f4a50f90ae9 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.tsx @@ -10,7 +10,6 @@ import React, { useCallback, useMemo, useState } from 'react'; import { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public'; -import { ActionConnectorProps } from '@kbn/triggers-actions-ui-plugin/public/types'; import { ConnectorAddModal } from '@kbn/triggers-actions-ui-plugin/public/common/constants'; import { GEN_AI_CONNECTOR_ID, @@ -23,20 +22,16 @@ import * as i18n from '../translations'; import { useLoadActionTypes } from '../use_load_action_types'; import { useAssistantContext } from '../../assistant_context'; import { useConversation } from '../../assistant/use_conversation'; +import { getGenAiConfig } from '../helpers'; export const ADD_NEW_CONNECTOR = 'ADD_NEW_CONNECTOR'; interface Props { isDisabled?: boolean; - onConnectorSelectionChange: (connectorId: string, provider: OpenAiProviderType) => void; selectedConnectorId?: string; selectedConversation?: Conversation; onConnectorModalVisibilityChange?: (isVisible: boolean) => void; } -interface Config { - apiProvider: string; -} - const inputContainerClassName = css` height: 32px; @@ -82,7 +77,6 @@ export const ConnectorSelectorInline: React.FC = React.memo( onConnectorModalVisibilityChange, selectedConnectorId, selectedConversation, - onConnectorSelectionChange, }) => { const [isOpen, setIsOpen] = useState(false); const { actionTypeRegistry, assistantAvailability, http } = useAssistantContext(); @@ -136,9 +130,10 @@ export const ConnectorSelectorInline: React.FC = React.memo( const connectorOptions = useMemo(() => { return ( connectors?.map((connector) => { - const apiProvider: string | undefined = ( - connector as ActionConnectorProps - )?.config?.apiProvider; + const apiProvider = getGenAiConfig(connector)?.apiProvider; + const connectorDetails = connector.isPreconfigured + ? i18n.PRECONFIGURED_CONNECTOR + : apiProvider; return { value: connector.id, inputDisplay: ( @@ -149,9 +144,9 @@ export const ConnectorSelectorInline: React.FC = React.memo( dropdownDisplay: ( {connector.name} - {apiProvider && ( + {connectorDetails && ( -

{apiProvider}

+

{connectorDetails}

)}
@@ -182,7 +177,7 @@ export const ConnectorSelectorInline: React.FC = React.memo( const handleOnBlur = useCallback(() => setIsOpen(false), []); const onChange = useCallback( - (connectorId: string, apiProvider?: OpenAiProviderType) => { + (connectorId: string, apiProvider?: OpenAiProviderType, model?: string) => { setIsOpen(false); if (connectorId === ADD_NEW_CONNECTOR) { @@ -191,31 +186,22 @@ export const ConnectorSelectorInline: React.FC = React.memo( return; } - const provider = - apiProvider ?? - ((connectors?.find((c) => c.id === connectorId) as ActionConnectorProps) - ?.config.apiProvider as OpenAiProviderType); - + const connector = connectors?.find((c) => c.id === connectorId); + const config = getGenAiConfig(connector); if (selectedConversation != null) { setApiConfig({ conversationId: selectedConversation.id, apiConfig: { ...selectedConversation.apiConfig, connectorId, - provider, + // With the inline component, prefer config args to handle 'new connector' case + provider: apiProvider ?? config?.apiProvider, + model: model ?? config?.defaultModel, }, }); } - - onConnectorSelectionChange(connectorId, provider); }, - [ - connectors, - selectedConversation, - onConnectorSelectionChange, - onConnectorModalVisibilityChange, - setApiConfig, - ] + [connectors, selectedConversation, onConnectorModalVisibilityChange, setApiConfig] ); const placeholderComponent = useMemo( @@ -276,11 +262,9 @@ export const ConnectorSelectorInline: React.FC = React.memo( { - const provider = (savedAction as ActionConnectorProps)?.config - .apiProvider as OpenAiProviderType; - onChange(savedAction.id, provider); - onConnectorSelectionChange(savedAction.id, provider); + postSaveEventHandler={(connector: ActionConnector) => { + const config = getGenAiConfig(connector); + onChange(connector.id, config?.apiProvider, config?.defaultModel); refetchConnectors?.(); cleanupAndCloseModal(); }} 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 23ccc51943655..9429ad9435ea7 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 @@ -14,11 +14,7 @@ import { ConnectorAddModal } from '@kbn/triggers-actions-ui-plugin/public/common import type { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public'; import { ActionType } from '@kbn/triggers-actions-ui-plugin/public'; -import { - GEN_AI_CONNECTOR_ID, - OpenAiProviderType, -} from '@kbn/stack-connectors-plugin/public/common'; -import { ActionConnectorProps } from '@kbn/triggers-actions-ui-plugin/public/types'; +import { GEN_AI_CONNECTOR_ID } from '@kbn/stack-connectors-plugin/public/common'; import { WELCOME_CONVERSATION } from '../../assistant/use_conversation/sample_conversations'; import { Conversation, Message } from '../../..'; import { useLoadActionTypes } from '../use_load_action_types'; @@ -30,6 +26,7 @@ import * as i18n from '../translations'; import { useAssistantContext } from '../../assistant_context'; import { useLoadConnectors } from '../use_load_connectors'; import { AssistantAvatar } from '../../assistant/assistant_avatar/assistant_avatar'; +import { getGenAiConfig } from '../helpers'; const ConnectorButtonWrapper = styled.div` margin-bottom: 10px; @@ -39,10 +36,6 @@ const SkipEuiText = styled(EuiText)` margin-top: 20px; `; -interface Config { - apiProvider: string; -} - export interface ConnectorSetupProps { conversation?: Conversation; onSetupComplete?: () => void; @@ -223,16 +216,17 @@ export const useConnectorSetup = ({ setIsConnectorModalVisible(false)} - postSaveEventHandler={(savedAction: ActionConnector) => { + postSaveEventHandler={(connector: ActionConnector) => { + const config = getGenAiConfig(connector); // Add connector to all conversations Object.values(conversations).forEach((c) => { setApiConfig({ conversationId: c.id, apiConfig: { ...c.apiConfig, - connectorId: savedAction.id, - provider: (savedAction as ActionConnectorProps)?.config - .apiProvider as OpenAiProviderType, + connectorId: connector.id, + provider: config?.apiProvider, + model: config?.defaultModel, }, }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx new file mode 100644 index 0000000000000..ffd9604ab328f --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx @@ -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 type { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public'; +import { ActionConnectorProps } from '@kbn/triggers-actions-ui-plugin/public/types'; +import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/common/gen_ai/constants'; + +interface GenAiConfig { + apiProvider?: OpenAiProviderType; + apiUrl?: string; + defaultModel?: string; +} + +/** + * Returns the GenAiConfig for a given ActionConnector. Note that if the connector is preconfigured, + * the config will be undefined as the connector is neither available nor editable. + * + * TODO: Extract and use separate types from GenAiConfig from '@kbn/stack-connectors-plugin/common/gen_ai/types' + * + * @param connector + */ +export const getGenAiConfig = (connector: ActionConnector | undefined): GenAiConfig | undefined => { + if (!connector?.isPreconfigured) { + return (connector as ActionConnectorProps)?.config; + } + return undefined; +}; 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 dbc692d6b5493..ae84527b21c7d 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts @@ -31,6 +31,13 @@ export const WELCOME_SECURITY = i18n.translate( } ); +export const PRECONFIGURED_CONNECTOR = i18n.translate( + 'xpack.elasticAssistant.assistant.connectors.preconfiguredTitle', + { + defaultMessage: 'Preconfigured', + } +); + export const CONNECTOR_SELECTOR_TITLE = i18n.translate( 'xpack.elasticAssistant.assistant.connectors.connectorSelector.ariaLabel', { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_toolbar.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_toolbar.tsx index c1aec33b2a2f7..fb2c17ddb2fa1 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_toolbar.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_toolbar.tsx @@ -5,12 +5,18 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { NewChat } from '@kbn/elastic-assistant'; import { useUserData } from '../../../../detections/components/user_info'; import { TabNavigation } from '../../../../common/components/navigation/tab_navigation'; import { usePrebuiltRulesStatus } from '../../../rule_management/logic/prebuilt_rules/use_prebuilt_rules_status'; import { useRuleManagementFilters } from '../../../rule_management/logic/use_rule_management_filters'; import * as i18n from './translations'; +import { getPromptContextFromDetectionRules } from '../../../../assistant/helpers'; +import { useRulesTableContext } from './rules_table/rules_table_context'; +import { useAssistantAvailability } from '../../../../assistant/use_assistant_availability'; +import * as i18nAssistant from '../../../../detections/pages/detection_engine/rules/translations'; export enum AllRulesTabs { management = 'management', @@ -71,7 +77,39 @@ export const RulesTableToolbar = React.memo(() => { [installedTotal, updateTotal, shouldDisplayRuleUpdatesTab] ); - return ; + // Assistant integration for using selected rules as prompt context + const { hasAssistantPrivilege } = useAssistantAvailability(); + const { + state: { rules, selectedRuleIds }, + } = useRulesTableContext(); + const selectedRules = useMemo( + () => rules.filter((rule) => selectedRuleIds.includes(rule.id)), + [rules, selectedRuleIds] + ); + const getPromptContext = useCallback( + async () => getPromptContextFromDetectionRules(selectedRules), + [selectedRules] + ); + + return ( + + + + + + {hasAssistantPrivilege && selectedRules.length > 0 && ( + + )} + + + ); }); RulesTableToolbar.displayName = 'RulesTableToolbar'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx index 2f5a202459f79..b27a322331fc7 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/index.tsx @@ -32,8 +32,8 @@ import { useInvalidateFindRulesQuery } from '../../../rule_management/api/hooks/ import { importRules } from '../../../rule_management/logic'; import { AllRules } from '../../components/rules_table'; import { RulesTableContextProvider } from '../../components/rules_table/rules_table/rules_table_context'; -import { SuperHeader } from './super_header'; import { useInvalidateFetchCoverageOverviewQuery } from '../../../rule_management/api/hooks/use_fetch_coverage_overview'; +import { HeaderPage } from '../../../../common/components/header_page'; const RulesPageComponent: React.FC = () => { const [isImportModalVisible, showImportModal, hideImportModal] = useBoolState(); @@ -110,7 +110,7 @@ const RulesPageComponent: React.FC = () => { - + @@ -149,7 +149,7 @@ const RulesPageComponent: React.FC = () => { - + diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/super_header.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/super_header.tsx deleted file mode 100644 index b3e7d6f3f6401..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/super_header.tsx +++ /dev/null @@ -1,61 +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 { NewChat } from '@kbn/elastic-assistant'; -import React, { useCallback, useMemo } from 'react'; - -import { useAssistantAvailability } from '../../../../assistant/use_assistant_availability'; -import { getPromptContextFromDetectionRules } from '../../../../assistant/helpers'; -import { HeaderPage } from '../../../../common/components/header_page'; -import { useRulesTableContext } from '../../components/rules_table/rules_table/rules_table_context'; -import * as i18n from '../../../../detections/pages/detection_engine/rules/translations'; - -export const SuperHeader: React.FC<{ children: React.ReactNode }> = React.memo(({ children }) => { - const { hasAssistantPrivilege } = useAssistantAvailability(); - const memoizedChildren = useMemo(() => children, [children]); - // Rules state - const { - state: { rules, selectedRuleIds }, - } = useRulesTableContext(); - - const selectedRules = useMemo( - () => rules.filter((rule) => selectedRuleIds.includes(rule.id)), - [rules, selectedRuleIds] - ); - - const getPromptContext = useCallback( - async () => getPromptContextFromDetectionRules(selectedRules), - [selectedRules] - ); - - return ( - - {i18n.PAGE_TITLE}{' '} - {hasAssistantPrivilege && selectedRules.length > 0 && ( - - {'🪄✨'} - - )} - - } - > - {memoizedChildren} - - ); -}); - -SuperHeader.displayName = 'NewChatComponent';