forked from elastic/kibana
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding flyout to create inference endpoint from Index Management (ela…
…stic#205184) ## Summary ### Current Behavior When adding the `semantic_text` field, users can choose from the preconfigured `elser` or `e5` endpoints. If they wish to use a third-party endpoint or create a new `elser` or `e5` endpoint, they need to use the API or the inference management UI. ### Planned Improvement To streamline this process, we plan to integrate the functionality for creating inference endpoints directly within the `semantic_text` inference selection popover. This enhancement will allow users to create inference endpoints without leaving the index management interface, making it more convenient to add fields within the index management mapping tab. This PR includes: - Adding inference endpoint from the `mapping` tab of `index management`. ### Recording https://github.com/user-attachments/assets/2f94cc93-9829-444d-a60f-0e721a4a751b ### Checklist Check the PR satisfies the following conditions. Reviewers should verify this PR satisfies this list as well. - [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] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [X] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <[email protected]>
- Loading branch information
1 parent
d4cc532
commit fc79f62
Showing
23 changed files
with
679 additions
and
680 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
90 changes: 90 additions & 0 deletions
90
.../shared/kbn-inference-endpoint-ui-common/src/components/inference_flyout_wrapper.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 { Form, useForm } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; | ||
import { I18nProvider } from '@kbn/i18n-react'; | ||
import userEvent from '@testing-library/user-event'; | ||
import { render, screen } from '@testing-library/react'; | ||
import { act } from 'react-dom/test-utils'; | ||
import React from 'react'; | ||
import { httpServiceMock } from '@kbn/core-http-browser-mocks'; | ||
import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; | ||
|
||
import { InferenceFlyoutWrapper } from './inference_flyout_wrapper'; | ||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; | ||
import { mockProviders } from '../utils/mock_providers'; | ||
|
||
const mockAddEndpoint = jest.fn(); | ||
const mockOnSubmitSuccess = jest.fn(); | ||
const mockOnClose = jest.fn(); | ||
const httpMock = httpServiceMock.createStartContract(); | ||
const notificationsMock = notificationServiceMock.createStartContract(); | ||
|
||
jest.mock('../hooks/use_providers', () => ({ | ||
useProviders: jest.fn(() => ({ | ||
data: mockProviders, | ||
})), | ||
})); | ||
|
||
const MockFormProvider = ({ children }: { children: React.ReactElement }) => { | ||
const { form } = useForm(); | ||
const queryClient = new QueryClient(); | ||
return ( | ||
<I18nProvider> | ||
<QueryClientProvider client={queryClient}> | ||
<Form form={form}>{children}</Form> | ||
</QueryClientProvider> | ||
</I18nProvider> | ||
); | ||
}; | ||
|
||
describe('InferenceFlyout', () => { | ||
beforeEach(async () => { | ||
jest.clearAllMocks(); | ||
|
||
await act(async () => { | ||
render( | ||
<MockFormProvider> | ||
<InferenceFlyoutWrapper | ||
onFlyoutClose={mockOnClose} | ||
onSubmitSuccess={mockOnSubmitSuccess} | ||
isEdit={false} | ||
http={httpMock} | ||
toasts={notificationsMock.toasts} | ||
addInferenceEndpoint={mockAddEndpoint} | ||
/> | ||
</MockFormProvider> | ||
); | ||
}); | ||
}); | ||
|
||
it('renders', async () => { | ||
expect(screen.getByTestId('inference-flyout')).toBeInTheDocument(); | ||
expect(screen.getByTestId('inference-flyout-header')).toBeInTheDocument(); | ||
expect(screen.getByTestId('inference-flyout-close-button')).toBeInTheDocument(); | ||
}); | ||
|
||
it('invalidates form if no provider is selected', async () => { | ||
await userEvent.click(screen.getByTestId('inference-endpoint-submit-button')); | ||
expect(screen.getByText('Provider is required.')).toBeInTheDocument(); | ||
expect(mockAddEndpoint).not.toHaveBeenCalled(); | ||
expect(screen.getByTestId('inference-endpoint-submit-button')).toBeDisabled(); | ||
}); | ||
|
||
it('submit form', async () => { | ||
await userEvent.click(screen.getByTestId('provider-select')); | ||
await userEvent.click(screen.getByText('Elasticsearch')); | ||
await userEvent.click(screen.getByTestId('inference-endpoint-submit-button')); | ||
|
||
expect(mockAddEndpoint).toHaveBeenCalled(); | ||
}); | ||
|
||
it('closes flyout', async () => { | ||
await userEvent.click(screen.getByTestId('inference-flyout-close-button')); | ||
expect(mockOnClose).toBeCalled(); | ||
}); | ||
}); |
126 changes: 126 additions & 0 deletions
126
...kages/shared/kbn-inference-endpoint-ui-common/src/components/inference_flyout_wrapper.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { | ||
EuiButton, | ||
EuiButtonEmpty, | ||
EuiFlexGroup, | ||
EuiFlexItem, | ||
EuiFlyout, | ||
EuiFlyoutBody, | ||
EuiFlyoutFooter, | ||
EuiFlyoutHeader, | ||
EuiSpacer, | ||
EuiTitle, | ||
useGeneratedHtmlId, | ||
} from '@elastic/eui'; | ||
import React, { useCallback, useState } from 'react'; | ||
|
||
import { HttpSetup, IToasts } from '@kbn/core/public'; | ||
import { Form, useForm } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; | ||
import * as LABELS from '../translations'; | ||
import { InferenceEndpoint } from '../types/types'; | ||
import { InferenceServiceFormFields } from './inference_service_form_fields'; | ||
|
||
interface InferenceFlyoutWrapperProps { | ||
onFlyoutClose: (state: boolean) => void; | ||
addInferenceEndpoint: ( | ||
inferenceEndpoint: InferenceEndpoint, | ||
onSuccess: (inferenceId: string) => void, | ||
onError: () => void | ||
) => Promise<void>; | ||
http: HttpSetup; | ||
toasts: IToasts; | ||
onSubmitSuccess?: (inferenceId: string) => void; | ||
isEdit?: boolean; | ||
} | ||
|
||
export const InferenceFlyoutWrapper: React.FC<InferenceFlyoutWrapperProps> = ({ | ||
onFlyoutClose, | ||
addInferenceEndpoint, | ||
http, | ||
toasts, | ||
onSubmitSuccess, | ||
isEdit, | ||
}) => { | ||
const inferenceCreationFlyoutId = useGeneratedHtmlId({ | ||
prefix: 'InferenceFlyoutId', | ||
}); | ||
const closeFlyout = () => onFlyoutClose(false); | ||
const [isLoading, setIsLoading] = useState<boolean>(false); | ||
const onSuccess = useCallback( | ||
(inferenceId: string) => { | ||
setIsLoading(false); | ||
onSubmitSuccess?.(inferenceId); | ||
}, | ||
[onSubmitSuccess] | ||
); | ||
const onError = useCallback(() => { | ||
setIsLoading(false); | ||
}, []); | ||
|
||
const { form } = useForm(); | ||
const handleSubmit = useCallback(async () => { | ||
setIsLoading(true); | ||
const { isValid, data } = await form.submit(); | ||
|
||
if (isValid) { | ||
addInferenceEndpoint(data as InferenceEndpoint, onSuccess, onError); | ||
} else { | ||
setIsLoading(false); | ||
} | ||
}, [addInferenceEndpoint, form, onError, onSuccess]); | ||
|
||
return ( | ||
<EuiFlyout | ||
ownFocus | ||
onClose={closeFlyout} | ||
aria-labelledby={inferenceCreationFlyoutId} | ||
data-test-subj="inference-flyout" | ||
> | ||
<EuiFlyoutHeader hasBorder data-test-subj="inference-flyout-header"> | ||
<EuiTitle size="m"> | ||
<h2 id={inferenceCreationFlyoutId}>{LABELS.ENDPOINT_TITLE}</h2> | ||
</EuiTitle> | ||
</EuiFlyoutHeader> | ||
<EuiFlyoutBody> | ||
<Form form={form}> | ||
<InferenceServiceFormFields http={http} toasts={toasts} isEdit={isEdit} /> | ||
<EuiSpacer size="m" /> | ||
<EuiFlexGroup justifyContent="flexStart"> | ||
<EuiFlexItem grow={false}> | ||
<EuiButton | ||
fill | ||
color="success" | ||
size="m" | ||
isLoading={form.isSubmitting || isLoading} | ||
disabled={(!form.isValid && form.isSubmitted) || isLoading} | ||
data-test-subj="inference-endpoint-submit-button" | ||
onClick={handleSubmit} | ||
> | ||
{LABELS.SAVE} | ||
</EuiButton> | ||
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
</Form> | ||
</EuiFlyoutBody> | ||
<EuiFlyoutFooter> | ||
<EuiFlexGroup justifyContent="spaceBetween"> | ||
<EuiFlexItem grow={false}> | ||
<EuiButtonEmpty | ||
data-test-subj="inference-flyout-close-button" | ||
onClick={closeFlyout} | ||
flush="left" | ||
> | ||
{LABELS.CANCEL} | ||
</EuiButtonEmpty> | ||
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
</EuiFlyoutFooter> | ||
</EuiFlyout> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.