mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Security Solution] Adds Connector Selector to Assistant Title Header (#163666)
## Summary Adds a new `ConnectorSelectorInline` component that is displayed below the Assistant title header. Default: <p align="center"> <img width="500" src="83e6a884
-103f-43c4-9a30-a0281d9941a2" /> </p> Overflow: <p align="center"> <img width="500" src="f0d8a04e
-963d-4053-90f5-2417f1c8eaca" /> </p> Missing: <p align="center"> <img width="500" src="eff04e75
-a5ab-468c-b801-1e056d527e6a" /> </p> Open: <p align="center"> <img width="500" src="b7b97244
-91a5-41ec-a096-b296e0cde644" /> </p> ### Checklist Delete any items that are not applicable to this PR. - [X] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [X] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [X] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
This commit is contained in:
parent
d0231b995a
commit
847e0cbe72
7 changed files with 494 additions and 31 deletions
|
@ -80,7 +80,11 @@ export const AssistantHeader: React.FC<Props> = ({
|
|||
justifyContent={'spaceBetween'}
|
||||
>
|
||||
<EuiFlexItem grow={false}>
|
||||
<AssistantTitle {...currentTitle} docLinks={docLinks} />
|
||||
<AssistantTitle
|
||||
{...currentTitle}
|
||||
docLinks={docLinks}
|
||||
selectedConversation={currentConversation}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem
|
||||
|
|
|
@ -14,18 +14,29 @@ const testProps = {
|
|||
title: 'Test Title',
|
||||
titleIcon: 'globe',
|
||||
docLinks: { ELASTIC_WEBSITE_URL: 'https://www.elastic.co/', DOC_LINK_VERSION: '7.15' },
|
||||
selectedConversation: undefined,
|
||||
};
|
||||
|
||||
describe('AssistantTitle', () => {
|
||||
it('the component renders correctly with valid props', () => {
|
||||
const { getByText, container } = render(<AssistantTitle {...testProps} />);
|
||||
const { getByText, container } = render(
|
||||
<TestProviders>
|
||||
<AssistantTitle {...testProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
expect(getByText('Test Title')).toBeInTheDocument();
|
||||
expect(container.querySelector('[data-euiicon-type="globe"]')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('clicking on the popover button opens the popover with the correct link', () => {
|
||||
const { getByTestId, queryByTestId } = render(<AssistantTitle {...testProps} />, {
|
||||
wrapper: TestProviders,
|
||||
});
|
||||
const { getByTestId, queryByTestId } = render(
|
||||
<TestProviders>
|
||||
<AssistantTitle {...testProps} />
|
||||
</TestProviders>,
|
||||
{
|
||||
wrapper: TestProviders,
|
||||
}
|
||||
);
|
||||
expect(queryByTestId('tooltipContent')).not.toBeInTheDocument();
|
||||
fireEvent.click(getByTestId('tooltipIcon'));
|
||||
expect(getByTestId('tooltipContent')).toBeInTheDocument();
|
||||
|
|
|
@ -15,10 +15,14 @@ import {
|
|||
EuiModalHeaderTitle,
|
||||
EuiPopover,
|
||||
EuiText,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import type { DocLinksStart } from '@kbn/core-doc-links-browser';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { css } from '@emotion/react';
|
||||
import * as i18n from '../translations';
|
||||
import type { Conversation } from '../../..';
|
||||
import { ConnectorSelectorInline } from '../../connectorland/connector_selector_inline/connector_selector_inline';
|
||||
|
||||
/**
|
||||
* Renders a header title with an icon, a tooltip button, and a popover with
|
||||
|
@ -28,7 +32,10 @@ export const AssistantTitle: React.FC<{
|
|||
title: string | JSX.Element;
|
||||
titleIcon: string;
|
||||
docLinks: Omit<DocLinksStart, 'links'>;
|
||||
}> = ({ title, titleIcon, docLinks }) => {
|
||||
selectedConversation: Conversation | undefined;
|
||||
}> = ({ title, titleIcon, docLinks, selectedConversation }) => {
|
||||
const selectedConnectorId = selectedConversation?.apiConfig?.connectorId;
|
||||
|
||||
const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = docLinks;
|
||||
const url = `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/security-assistant.html`;
|
||||
|
||||
|
@ -66,32 +73,57 @@ export const AssistantTitle: React.FC<{
|
|||
|
||||
return (
|
||||
<EuiModalHeaderTitle>
|
||||
<EuiFlexGroup gutterSize="xs" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup gutterSize="m">
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
css={css`
|
||||
margin-top: 3px;
|
||||
`}
|
||||
>
|
||||
<EuiIcon data-test-subj="titleIcon" type={titleIcon} size="xl" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>{title}</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiPopover
|
||||
button={
|
||||
<EuiButtonIcon
|
||||
aria-label={i18n.TOOLTIP_ARIA_LABEL}
|
||||
data-test-subj="tooltipIcon"
|
||||
iconSize="l"
|
||||
iconType="iInCircle"
|
||||
onClick={onButtonClick}
|
||||
/>
|
||||
}
|
||||
isOpen={isPopoverOpen}
|
||||
closePopover={closePopover}
|
||||
anchorPosition="upCenter"
|
||||
>
|
||||
<EuiText data-test-subj="tooltipContent" grow={false} css={{ maxWidth: '400px' }}>
|
||||
<h4>{i18n.TOOLTIP_TITLE}</h4>
|
||||
<p>{content}</p>
|
||||
</EuiText>
|
||||
</EuiPopover>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexGroup direction="column" gutterSize="none" justifyContent="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup gutterSize="xs" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size={'s'}>
|
||||
<h3>{title}</h3>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiPopover
|
||||
button={
|
||||
<EuiButtonIcon
|
||||
aria-label={i18n.TOOLTIP_ARIA_LABEL}
|
||||
data-test-subj="tooltipIcon"
|
||||
iconType="iInCircle"
|
||||
onClick={onButtonClick}
|
||||
/>
|
||||
}
|
||||
isOpen={isPopoverOpen}
|
||||
closePopover={closePopover}
|
||||
anchorPosition="rightUp"
|
||||
>
|
||||
<EuiText data-test-subj="tooltipContent" grow={false} css={{ maxWidth: '400px' }}>
|
||||
<h4>{i18n.TOOLTIP_TITLE}</h4>
|
||||
<EuiText size={'s'}>
|
||||
<p>{content}</p>
|
||||
</EuiText>
|
||||
</EuiText>
|
||||
</EuiPopover>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<ConnectorSelectorInline
|
||||
isDisabled={selectedConversation === undefined}
|
||||
onConnectorModalVisibilityChange={() => {}}
|
||||
onConnectorSelectionChange={() => {}}
|
||||
selectedConnectorId={selectedConnectorId}
|
||||
selectedConversation={selectedConversation}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexGroup>
|
||||
</EuiModalHeaderTitle>
|
||||
);
|
||||
|
|
|
@ -46,7 +46,7 @@ export const ConnectorMissingCallout: React.FC<Props> = React.memo(
|
|||
<p>
|
||||
{' '}
|
||||
<FormattedMessage
|
||||
defaultMessage="Select a connector from the {link} to continue"
|
||||
defaultMessage="Select a connector above or from the {link} to continue"
|
||||
id="xpack.elasticAssistant.assistant.connectors.connectorMissingCallout.calloutDescription"
|
||||
values={{
|
||||
link: (
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import { noop } from 'lodash/fp';
|
||||
import { TestProviders } from '../../mock/test_providers/test_providers';
|
||||
import { ConnectorSelectorInline } from './connector_selector_inline';
|
||||
import * as i18n from '../translations';
|
||||
import { Conversation } from '../../..';
|
||||
import { useLoadConnectors } from '../use_load_connectors';
|
||||
|
||||
jest.mock('@kbn/triggers-actions-ui-plugin/public/common/constants', () => ({
|
||||
loadActionTypes: jest.fn(() => {
|
||||
return Promise.resolve([
|
||||
{
|
||||
id: '.gen-ai',
|
||||
name: 'Gen AI',
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'basic',
|
||||
},
|
||||
]);
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('../use_load_connectors', () => ({
|
||||
useLoadConnectors: jest.fn(() => {
|
||||
return {
|
||||
data: [],
|
||||
error: null,
|
||||
isSuccess: true,
|
||||
};
|
||||
}),
|
||||
}));
|
||||
|
||||
const mockConnectors = [
|
||||
{
|
||||
id: 'connectorId',
|
||||
name: 'Captain Connector',
|
||||
isMissingSecrets: false,
|
||||
actionTypeId: '.gen-ai',
|
||||
config: {
|
||||
apiProvider: 'OpenAI',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
(useLoadConnectors as jest.Mock).mockReturnValue({
|
||||
data: mockConnectors,
|
||||
error: null,
|
||||
isSuccess: true,
|
||||
});
|
||||
|
||||
describe('ConnectorSelectorInline', () => {
|
||||
it('renders empty view if no selected conversation is provided', () => {
|
||||
const { getByText } = render(
|
||||
<TestProviders>
|
||||
<ConnectorSelectorInline
|
||||
isDisabled={false}
|
||||
onConnectorModalVisibilityChange={noop}
|
||||
onConnectorSelectionChange={noop}
|
||||
selectedConnectorId={undefined}
|
||||
selectedConversation={undefined}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
expect(getByText(i18n.INLINE_CONNECTOR_PLACEHOLDER)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders empty view if selectedConnectorId is NOT in list of connectors', () => {
|
||||
const conversation: Conversation = {
|
||||
id: 'conversation_id',
|
||||
messages: [],
|
||||
apiConfig: {},
|
||||
};
|
||||
const { getByText } = render(
|
||||
<TestProviders>
|
||||
<ConnectorSelectorInline
|
||||
isDisabled={false}
|
||||
onConnectorModalVisibilityChange={noop}
|
||||
onConnectorSelectionChange={noop}
|
||||
selectedConnectorId={'missing-connector-id'}
|
||||
selectedConversation={conversation}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
expect(getByText(i18n.INLINE_CONNECTOR_PLACEHOLDER)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders selected connector if selected selectedConnectorId is in list of connectors', () => {
|
||||
const conversation: Conversation = {
|
||||
id: 'conversation_id',
|
||||
messages: [],
|
||||
apiConfig: {},
|
||||
};
|
||||
const { getByText } = render(
|
||||
<TestProviders>
|
||||
<ConnectorSelectorInline
|
||||
isDisabled={false}
|
||||
onConnectorModalVisibilityChange={noop}
|
||||
onConnectorSelectionChange={noop}
|
||||
selectedConnectorId={mockConnectors[0].id}
|
||||
selectedConversation={conversation}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
expect(getByText(mockConnectors[0].name)).toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
* 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, EuiFlexGroup, EuiFlexItem, EuiSuperSelect, EuiText } from '@elastic/eui';
|
||||
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,
|
||||
OpenAiProviderType,
|
||||
} from '@kbn/stack-connectors-plugin/public/common';
|
||||
import { css } from '@emotion/css/dist/emotion-css.cjs';
|
||||
import { Conversation } from '../../..';
|
||||
import { useLoadConnectors } from '../use_load_connectors';
|
||||
import * as i18n from '../translations';
|
||||
import { useLoadActionTypes } from '../use_load_action_types';
|
||||
import { useAssistantContext } from '../../assistant_context';
|
||||
import { useConversation } from '../../assistant/use_conversation';
|
||||
|
||||
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;
|
||||
|
||||
.euiSuperSelect {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.euiSuperSelectControl {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.euiFormControlLayoutIcons {
|
||||
right: 14px;
|
||||
top: 2px;
|
||||
}
|
||||
`;
|
||||
|
||||
const inputDisplayClassName = css`
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 400px;
|
||||
`;
|
||||
|
||||
const placeholderButtonClassName = css`
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 400px;
|
||||
font-weight: normal;
|
||||
padding-bottom: 5px;
|
||||
padding-left: 0;
|
||||
padding-top: 2px;
|
||||
`;
|
||||
|
||||
/**
|
||||
* A minimal and connected version of the ConnectorSelector component used in the Settings modal.
|
||||
*/
|
||||
export const ConnectorSelectorInline: React.FC<Props> = React.memo(
|
||||
({
|
||||
isDisabled = false,
|
||||
onConnectorModalVisibilityChange,
|
||||
selectedConnectorId,
|
||||
selectedConversation,
|
||||
onConnectorSelectionChange,
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
const { actionTypeRegistry, http } = useAssistantContext();
|
||||
const { setApiConfig } = useConversation();
|
||||
// Connector Modal State
|
||||
const [isConnectorModalVisible, setIsConnectorModalVisible] = useState<boolean>(false);
|
||||
const { data: actionTypes } = useLoadActionTypes({ http });
|
||||
const actionType = actionTypes?.find((at) => at.id === GEN_AI_CONNECTOR_ID) ?? {
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'platinum',
|
||||
supportedFeatureIds: ['general'],
|
||||
isSystemActionType: false,
|
||||
id: '.gen-ai',
|
||||
name: 'Generative AI',
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
const {
|
||||
data: connectors,
|
||||
isLoading: isLoadingActionTypes,
|
||||
isFetching: isFetchingActionTypes,
|
||||
refetch: refetchConnectors,
|
||||
} = useLoadConnectors({ http });
|
||||
const isLoading = isLoadingActionTypes || isFetchingActionTypes;
|
||||
const selectedConnectorName =
|
||||
connectors?.find((c) => c.id === selectedConnectorId)?.name ??
|
||||
i18n.INLINE_CONNECTOR_PLACEHOLDER;
|
||||
|
||||
const addNewConnectorOption = useMemo(() => {
|
||||
return {
|
||||
value: ADD_NEW_CONNECTOR,
|
||||
inputDisplay: i18n.ADD_NEW_CONNECTOR,
|
||||
dropdownDisplay: (
|
||||
<EuiFlexGroup gutterSize="none" key={ADD_NEW_CONNECTOR}>
|
||||
<EuiFlexItem grow={true}>
|
||||
<EuiButtonEmpty data-test-subj="addNewConnectorButton" iconType="plus" size="xs">
|
||||
{i18n.ADD_NEW_CONNECTOR}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
{/* Right offset to compensate for 'selected' icon of EuiSuperSelect since native footers aren't supported*/}
|
||||
<div style={{ width: '24px' }} />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
),
|
||||
};
|
||||
}, []);
|
||||
|
||||
const connectorOptions = useMemo(() => {
|
||||
return (
|
||||
connectors?.map((connector) => {
|
||||
const apiProvider: string | undefined = (
|
||||
connector as ActionConnectorProps<Config, unknown>
|
||||
)?.config?.apiProvider;
|
||||
return {
|
||||
value: connector.id,
|
||||
inputDisplay: (
|
||||
<EuiText className={inputDisplayClassName} size="xs">
|
||||
{connector.name}
|
||||
</EuiText>
|
||||
),
|
||||
dropdownDisplay: (
|
||||
<React.Fragment key={connector.id}>
|
||||
<strong>{connector.name}</strong>
|
||||
{apiProvider && (
|
||||
<EuiText size="xs" color="subdued">
|
||||
<p>{apiProvider}</p>
|
||||
</EuiText>
|
||||
)}
|
||||
</React.Fragment>
|
||||
),
|
||||
};
|
||||
}) ?? []
|
||||
);
|
||||
}, [connectors]);
|
||||
|
||||
const cleanupAndCloseModal = useCallback(() => {
|
||||
onConnectorModalVisibilityChange?.(false);
|
||||
setIsConnectorModalVisible(false);
|
||||
}, [onConnectorModalVisibilityChange]);
|
||||
|
||||
const onConnectorClick = useCallback(() => {
|
||||
setIsOpen(!isOpen);
|
||||
}, [isOpen]);
|
||||
|
||||
const handleOnBlur = useCallback(() => setIsOpen(false), []);
|
||||
|
||||
const onChange = useCallback(
|
||||
(connectorId: string, apiProvider?: OpenAiProviderType) => {
|
||||
setIsOpen(false);
|
||||
|
||||
if (connectorId === ADD_NEW_CONNECTOR) {
|
||||
onConnectorModalVisibilityChange?.(true);
|
||||
setIsConnectorModalVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const provider =
|
||||
apiProvider ??
|
||||
((connectors?.find((c) => c.id === connectorId) as ActionConnectorProps<Config, unknown>)
|
||||
?.config.apiProvider as OpenAiProviderType);
|
||||
|
||||
if (selectedConversation != null) {
|
||||
setApiConfig({
|
||||
conversationId: selectedConversation.id,
|
||||
apiConfig: {
|
||||
...selectedConversation.apiConfig,
|
||||
connectorId,
|
||||
provider,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onConnectorSelectionChange(connectorId, provider);
|
||||
},
|
||||
[
|
||||
connectors,
|
||||
selectedConversation,
|
||||
onConnectorSelectionChange,
|
||||
onConnectorModalVisibilityChange,
|
||||
setApiConfig,
|
||||
]
|
||||
);
|
||||
|
||||
const placeholderComponent = useMemo(
|
||||
() => (
|
||||
<EuiText color="default" size={'xs'}>
|
||||
{i18n.INLINE_CONNECTOR_PLACEHOLDER}
|
||||
</EuiText>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup
|
||||
alignItems="center"
|
||||
className={inputContainerClassName}
|
||||
direction="row"
|
||||
gutterSize="xs"
|
||||
justifyContent={'flexStart'}
|
||||
responsive={false}
|
||||
>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="xs" color="subdued">
|
||||
{i18n.INLINE_CONNECTOR_LABEL}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
{isOpen ? (
|
||||
<EuiSuperSelect
|
||||
aria-label={i18n.CONNECTOR_SELECTOR_TITLE}
|
||||
compressed={true}
|
||||
disabled={isDisabled}
|
||||
hasDividers={true}
|
||||
isLoading={isLoading}
|
||||
isOpen={isOpen}
|
||||
onBlur={handleOnBlur}
|
||||
onChange={onChange}
|
||||
options={[...connectorOptions, addNewConnectorOption]}
|
||||
placeholder={placeholderComponent}
|
||||
valueOfSelected={selectedConnectorId}
|
||||
/>
|
||||
) : (
|
||||
<span>
|
||||
<EuiButtonEmpty
|
||||
className={placeholderButtonClassName}
|
||||
color={'text'}
|
||||
data-test-subj="connectorSelectorPlaceholderButton"
|
||||
iconSide={'right'}
|
||||
iconType="arrowDown"
|
||||
isDisabled={isDisabled}
|
||||
onClick={onConnectorClick}
|
||||
size="xs"
|
||||
>
|
||||
{selectedConnectorName}
|
||||
</EuiButtonEmpty>
|
||||
</span>
|
||||
)}
|
||||
{isConnectorModalVisible && (
|
||||
<ConnectorAddModal
|
||||
actionType={actionType}
|
||||
onClose={cleanupAndCloseModal}
|
||||
postSaveEventHandler={(savedAction: ActionConnector) => {
|
||||
const provider = (savedAction as ActionConnectorProps<Config, unknown>)?.config
|
||||
.apiProvider as OpenAiProviderType;
|
||||
onChange(savedAction.id, provider);
|
||||
onConnectorSelectionChange(savedAction.id, provider);
|
||||
refetchConnectors?.();
|
||||
cleanupAndCloseModal();
|
||||
}}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
/>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
ConnectorSelectorInline.displayName = 'ConnectorSelectorInline';
|
|
@ -45,6 +45,20 @@ export const ADD_NEW_CONNECTOR = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
export const INLINE_CONNECTOR_LABEL = i18n.translate(
|
||||
'xpack.elasticAssistant.assistant.connectors.connectorSelectorInline.connectorLabel',
|
||||
{
|
||||
defaultMessage: 'Connector:',
|
||||
}
|
||||
);
|
||||
|
||||
export const INLINE_CONNECTOR_PLACEHOLDER = i18n.translate(
|
||||
'xpack.elasticAssistant.assistant.connectors.connectorSelectorInline.connectorPlaceholder',
|
||||
{
|
||||
defaultMessage: 'Select a Connector',
|
||||
}
|
||||
);
|
||||
|
||||
export const ADD_CONNECTOR_TITLE = i18n.translate(
|
||||
'xpack.elasticAssistant.assistant.connectors.addConnectorButton.title',
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue