Skip to content

Commit

Permalink
[8.16] [Search: Inference Management UI] Adding restriction on deleti…
Browse files Browse the repository at this point in the history
…ng preconfigured endpoints (elastic#196580) (elastic#197378)

# Backport

This will backport the following commits from `main` to `8.16`:
- [[Search: Inference Management UI] Adding restriction on deleting
preconfigured endpoints
(elastic#196580)](elastic#196580)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Samiul
Monir","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-10-23T08:15:35Z","message":"[Search:
Inference Management UI] Adding restriction on deleting preconfigured
endpoints (elastic#196580)\n\n## Summary\r\n\r\nDisables the delete action when
the endpoints are preconfigured.\r\n\r\n![Screenshot 2024-10-18 at 12
12\r\n20 PM](https://github.com/user-attachments/assets/6684b5c6-5f7d-434f-83e3-74872125753b)\r\n\r\n\r\n\r\n###
Checklist\r\n\r\nDelete any items that are not applicable to this
PR.\r\n\r\n- [X] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [X] Any UI
touched in this PR does not create any new axe failures\r\n(run axe in
browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n-
[X] This renders correctly on smaller devices using a
responsive\r\nlayout. (You can test this [in
your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n-
[X] This was checked for
[cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)","sha":"dc219f9b309fe1582ce96d2c9ac9d42d91ea56bc","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Search","v8.16.0","backport:version"],"title":"[Search:
Inference Management UI] Adding restriction on deleting preconfigured
endpoints","number":196580,"url":"https://github.com/elastic/kibana/pull/196580","mergeCommit":{"message":"[Search:
Inference Management UI] Adding restriction on deleting preconfigured
endpoints (elastic#196580)\n\n## Summary\r\n\r\nDisables the delete action when
the endpoints are preconfigured.\r\n\r\n![Screenshot 2024-10-18 at 12
12\r\n20 PM](https://github.com/user-attachments/assets/6684b5c6-5f7d-434f-83e3-74872125753b)\r\n\r\n\r\n\r\n###
Checklist\r\n\r\nDelete any items that are not applicable to this
PR.\r\n\r\n- [X] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [X] Any UI
touched in this PR does not create any new axe failures\r\n(run axe in
browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n-
[X] This renders correctly on smaller devices using a
responsive\r\nlayout. (You can test this [in
your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n-
[X] This was checked for
[cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)","sha":"dc219f9b309fe1582ce96d2c9ac9d42d91ea56bc"}},"sourceBranch":"main","suggestedTargetBranches":["8.16"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/196580","number":196580,"mergeCommit":{"message":"[Search:
Inference Management UI] Adding restriction on deleting preconfigured
endpoints (elastic#196580)\n\n## Summary\r\n\r\nDisables the delete action when
the endpoints are preconfigured.\r\n\r\n![Screenshot 2024-10-18 at 12
12\r\n20 PM](https://github.com/user-attachments/assets/6684b5c6-5f7d-434f-83e3-74872125753b)\r\n\r\n\r\n\r\n###
Checklist\r\n\r\nDelete any items that are not applicable to this
PR.\r\n\r\n- [X] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [X] Any UI
touched in this PR does not create any new axe failures\r\n(run axe in
browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n-
[X] This renders correctly on smaller devices using a
responsive\r\nlayout. (You can test this [in
your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n-
[X] This was checked for
[cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)","sha":"dc219f9b309fe1582ce96d2c9ac9d42d91ea56bc"}},{"branch":"8.16","label":"v8.16.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Samiul Monir <[email protected]>
  • Loading branch information
kibanamachine and Samiul-TheSoccerFan authored Oct 23, 2024
1 parent c329375 commit da9808c
Show file tree
Hide file tree
Showing 10 changed files with 195 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ export const DEFAULT_INFERENCE_ENDPOINTS_TABLE_STATE: AllInferenceEndpointsTable
};

export const PIPELINE_URL = 'ingest/ingest_pipelines';

export const PRECONFIGURED_ENDPOINTS = {
ELSER: '.elser-2',
E5: '.multi-e5-small',
};
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export const ConfirmDeleteEndpointModal: React.FC<ConfirmDeleteEndpointModalProp
onConfirm={onConfirm}
title={i18n.DELETE_TITLE}
confirmButtonDisabled={deleteDisabled}
data-test-subj="deleteModalForInferenceUI"
>
<EuiFlexGroup gutterSize="l" direction="column">
<EuiFlexItem grow={false}>{i18n.CONFIRM_DELETE_WARNING}</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { render, screen, fireEvent } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import React from 'react';

import { DeleteAction } from './delete_action';
import { InferenceEndpointUI } from '../../../../types';

describe('Delete Action', () => {
const mockProvider = {
inference_id: 'my-hugging-face',
service: 'hugging_face',
service_settings: {
api_key: 'aaaa',
url: 'https://dummy.huggingface.com',
},
task_settings: {},
} as any;

const mockItem: InferenceEndpointUI = {
endpoint: 'my-hugging-face',
provider: mockProvider,
type: 'text_embedding',
};

const Wrapper = ({ item }: { item: InferenceEndpointUI }) => {
const queryClient = new QueryClient();
return (
<QueryClientProvider client={queryClient}>
<DeleteAction selectedEndpoint={item} />
</QueryClientProvider>
);
};
it('renders', () => {
render(<Wrapper item={mockItem} />);

expect(screen.getByTestId('inferenceUIDeleteAction')).toBeEnabled();
});

it('disable the delete action for preconfigured endpoint', () => {
const preconfiguredMockItem = { ...mockItem, endpoint: '.elser-2' };
render(<Wrapper item={preconfiguredMockItem} />);

expect(screen.getByTestId('inferenceUIDeleteAction')).toBeDisabled();
});

it('loads confirm delete modal', () => {
render(<Wrapper item={mockItem} />);

fireEvent.click(screen.getByTestId('inferenceUIDeleteAction'));
expect(screen.getByTestId('deleteModalForInferenceUI')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { EuiButtonIcon } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { useState } from 'react';
import { isEndpointPreconfigured } from '../../../../../../utils/preconfigured_endpoint_helper';
import { useDeleteEndpoint } from '../../../../../../hooks/use_delete_endpoint';
import { InferenceEndpointUI } from '../../../../types';
import { ConfirmDeleteEndpointModal } from './confirm_delete_endpoint';
Expand Down Expand Up @@ -39,6 +40,8 @@ export const DeleteAction: React.FC<DeleteActionProps> = ({ selectedEndpoint })
defaultMessage: 'Delete inference endpoint {selectedEndpointName}',
values: { selectedEndpointName: selectedEndpoint.endpoint },
})}
data-test-subj="inferenceUIDeleteAction"
disabled={isEndpointPreconfigured(selectedEndpoint.endpoint)}
key="delete"
iconType="trash"
color="danger"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,28 @@
* 2.0.
*/

import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import React from 'react';
import { isEndpointPreconfigured } from '../../../../utils/preconfigured_endpoint_helper';
import * as i18n from './translations';

export interface EndpointInfoProps {
inferenceId: string;
}

export const EndpointInfo: React.FC<EndpointInfoProps> = ({ inferenceId }) => (
<span>
<strong>{inferenceId}</strong>
</span>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<span>
<strong>{inferenceId}</strong>
</span>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<span>
{isEndpointPreconfigured(inferenceId) ? (
<EuiBetaBadge label={i18n.PRECONFIGURED_LABEL} size="s" color="hollow" />
) : null}
</span>
</EuiFlexItem>
</EuiFlexGroup>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* 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 PRECONFIGURED_LABEL = i18n.translate(
'xpack.searchInferenceEndpoints.elasticsearch.endpointInfo.preconfigured',
{
defaultMessage: 'PRECONFIGURED',
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,28 @@ const inferenceEndpoints = [
},
task_settings: {},
},
{
inference_id: '.elser-2',
task_type: 'sparse_embedding',
service: 'elasticsearch',
service_settings: {
num_allocations: 1,
num_threads: 1,
model_id: '.elser_model_2',
},
task_settings: {},
},
{
inference_id: '.multi-e5-small',
task_type: 'text_embedding',
service: 'elasticsearch',
service_settings: {
num_allocations: 1,
num_threads: 1,
model_id: '.multilingual-e5-small',
},
task_settings: {},
},
] as InferenceAPIConfigResponse[];

jest.mock('../../hooks/use_delete_endpoint', () => ({
Expand All @@ -58,22 +80,55 @@ describe('When the tabular page is loaded', () => {
render(<TabularPage inferenceEndpoints={inferenceEndpoints} />);

const rows = screen.getAllByRole('row');
expect(rows[1]).toHaveTextContent('local-model');
expect(rows[2]).toHaveTextContent('my-elser-model-05');
expect(rows[3]).toHaveTextContent('third-party-model');
expect(rows[1]).toHaveTextContent('.elser-2');
expect(rows[2]).toHaveTextContent('.multi-e5-small');
expect(rows[3]).toHaveTextContent('local-model');
expect(rows[4]).toHaveTextContent('my-elser-model-05');
expect(rows[5]).toHaveTextContent('third-party-model');
});

it('should display all service and model ids in the table', () => {
render(<TabularPage inferenceEndpoints={inferenceEndpoints} />);

const rows = screen.getAllByRole('row');
expect(rows[1]).toHaveTextContent('Elasticsearch');
expect(rows[1]).toHaveTextContent('.own_model');
expect(rows[1]).toHaveTextContent('.elser_model_2');

expect(rows[2]).toHaveTextContent('Elasticsearch');
expect(rows[2]).toHaveTextContent('.elser_model_2');
expect(rows[2]).toHaveTextContent('.multilingual-e5-small');

expect(rows[3]).toHaveTextContent('OpenAI');
expect(rows[3]).toHaveTextContent('Elasticsearch');
expect(rows[3]).toHaveTextContent('.own_model');

expect(rows[4]).toHaveTextContent('Elasticsearch');
expect(rows[4]).toHaveTextContent('.elser_model_2');

expect(rows[5]).toHaveTextContent('OpenAI');
expect(rows[5]).toHaveTextContent('.own_model');
});

it('should only disable delete action for preconfigured endpoints', () => {
render(<TabularPage inferenceEndpoints={inferenceEndpoints} />);

const deleteActions = screen.getAllByTestId('inferenceUIDeleteAction');

expect(deleteActions[0]).toBeDisabled();
expect(deleteActions[1]).toBeDisabled();
expect(deleteActions[2]).toBeEnabled();
expect(deleteActions[3]).toBeEnabled();
expect(deleteActions[4]).toBeEnabled();
});

it('should show preconfigured badge only for preconfigured endpoints', () => {
render(<TabularPage inferenceEndpoints={inferenceEndpoints} />);

const preconfigured = 'PRECONFIGURED';

const rows = screen.getAllByRole('row');
expect(rows[1]).toHaveTextContent(preconfigured);
expect(rows[2]).toHaveTextContent(preconfigured);
expect(rows[3]).not.toHaveTextContent(preconfigured);
expect(rows[4]).not.toHaveTextContent(preconfigured);
expect(rows[5]).not.toHaveTextContent(preconfigured);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ export const TabularPage: React.FC<TabularPageProps> = ({ inferenceEndpoints })
return null;
},
sortable: true,
truncateText: true,
width: '300px',
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { PRECONFIGURED_ENDPOINTS } from '../components/all_inference_endpoints/constants';
import { isEndpointPreconfigured } from './preconfigured_endpoint_helper';

describe('Preconfigured Endpoint helper', () => {
it('return true for preconfigured elser', () => {
expect(isEndpointPreconfigured(PRECONFIGURED_ENDPOINTS.ELSER)).toEqual(true);
});

it('return true for preconfigured e5', () => {
expect(isEndpointPreconfigured(PRECONFIGURED_ENDPOINTS.E5)).toEqual(true);
});

it('return false for other endpoints', () => {
expect(isEndpointPreconfigured('other-endpoints')).toEqual(false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* 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 { PRECONFIGURED_ENDPOINTS } from '../components/all_inference_endpoints/constants';

export const isEndpointPreconfigured = (endpoint: string) =>
Object.values(PRECONFIGURED_ENDPOINTS).includes(endpoint);

0 comments on commit da9808c

Please sign in to comment.