Skip to content

Commit

Permalink
[Search] Add Inference endpoint Flyout in Inference Management UI (el…
Browse files Browse the repository at this point in the history
…astic#203204)

## Summary

This PR includes
- Create a UI component package to share AI connector form between
multiple plugins
- Integrate the packaged components into the `Search Inference Endpoint`
plugin.



https://github.com/user-attachments/assets/2b447b44-3d1d-4422-b76d-8d8fd160b2bc


### Checklist

Check the PR satisfies 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

---------

Co-authored-by: kibanamachine <[email protected]>
Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
3 people authored Dec 25, 2024
1 parent 155bdd0 commit bc466ea
Show file tree
Hide file tree
Showing 64 changed files with 4,288 additions and 9 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,7 @@ x-pack/platform/packages/shared/kbn-data-forge @elastic/obs-ux-management-team
x-pack/platform/packages/shared/kbn-elastic-assistant @elastic/security-generative-ai
x-pack/platform/packages/shared/kbn-elastic-assistant-common @elastic/security-generative-ai
x-pack/platform/packages/shared/kbn-entities-schema @elastic/obs-entities
x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common @elastic/response-ops @elastic/appex-ai-infra @elastic/obs-ai-assistant @elastic/security-generative-ai
x-pack/platform/packages/shared/kbn-langchain @elastic/security-generative-ai
x-pack/platform/packages/shared/kbn-slo-schema @elastic/obs-ux-management-team
x-pack/platform/packages/shared/ml/aiops_common @elastic/ml-ui
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,7 @@
"@kbn/index-management-shared-types": "link:x-pack/platform/packages/shared/index-management/index_management_shared_types",
"@kbn/index-patterns-test-plugin": "link:test/plugin_functional/plugins/index_patterns",
"@kbn/inference-common": "link:x-pack/platform/packages/shared/ai-infra/inference-common",
"@kbn/inference-endpoint-ui-common": "link:x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common",
"@kbn/inference-plugin": "link:x-pack/platform/plugins/shared/inference",
"@kbn/inference_integration_flyout": "link:x-pack/platform/packages/private/ml/inference_integration_flyout",
"@kbn/infra-forge": "link:x-pack/platform/packages/private/kbn-infra-forge",
Expand Down
2 changes: 2 additions & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,8 @@
"@kbn/inference_integration_flyout/*": ["x-pack/platform/packages/private/ml/inference_integration_flyout/*"],
"@kbn/inference-common": ["x-pack/platform/packages/shared/ai-infra/inference-common"],
"@kbn/inference-common/*": ["x-pack/platform/packages/shared/ai-infra/inference-common/*"],
"@kbn/inference-endpoint-ui-common": ["x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common"],
"@kbn/inference-endpoint-ui-common/*": ["x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common/*"],
"@kbn/inference-plugin": ["x-pack/platform/plugins/shared/inference"],
"@kbn/inference-plugin/*": ["x-pack/platform/plugins/shared/inference/*"],
"@kbn/infra-forge": ["x-pack/platform/packages/private/kbn-infra-forge"],
Expand Down
1 change: 1 addition & 0 deletions x-pack/.i18nrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"xpack.idxMgmt": "platform/plugins/shared/index_management",
"xpack.idxMgmtPackage": "packages/index-management",
"xpack.indexLifecycleMgmt": "platform/plugins/private/index_lifecycle_management",
"xpack.inferenceEndpointUICommon": "platform/packages/shared/kbn-inference-endpoint-ui-common",
"xpack.infra": "solutions/observability/plugins/infra",
"xpack.logsDataAccess": "platform/plugins/shared/logs_data_access",
"xpack.logsExplorer": "solutions/observability/plugins/logs_explorer",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# @kbn/kbn-inference-endpoint-ui-common

The `Inference Endpoint UI common` is a shared UI library to create AI Connector and/or inference endpoints.

This package provides:

- Components for rendering the GenAI services and their associated fields
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* 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 { InferenceServiceFormFields } from './src/components/inference_service_form_fields';

export * from './src/types/types';
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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.
*/

module.exports = {
preset: '@kbn/test',
rootDir: '../../../../..',
roots: ['<rootDir>/x-pack/platform/packages/shared/kbn-inference-endpoint-ui-common'],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"type": "shared-browser",
"id": "@kbn/inference-endpoint-ui-common",
"owner": [
"@elastic/response-ops",
"@elastic/appex-ai-infra",
"@elastic/obs-ai-assistant",
"@elastic/security-generative-ai"
],
"group": "platform",
"visibility": "shared"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@kbn/inference-endpoint-ui-common",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0"
}
Original file line number Diff line number Diff line change
@@ -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.
*/

// eslint-disable-next-line import/no-extraneous-dependencies
import '@testing-library/jest-dom';
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
/*
* 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, { useMemo } from 'react';
import { css } from '@emotion/react';

import {
EuiFormRow,
EuiSpacer,
EuiTitle,
EuiAccordion,
EuiFieldText,
useEuiTheme,
EuiTextColor,
EuiButtonGroup,
EuiPanel,
EuiButtonEmpty,
EuiCopy,
EuiButton,
useEuiFontSize,
EuiText,
} from '@elastic/eui';
import {
getFieldValidityAndErrorMessage,
UseField,
useFormContext,
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
import { FormattedMessage } from '@kbn/i18n-react';

import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
import { ConfigurationFormItems } from './configuration/configuration_form_items';
import * as LABELS from '../translations';
import { DEFAULT_TASK_TYPE } from '../constants';
import { Config, ConfigEntryView } from '../types/types';
import { TaskTypeOption } from '../utils/helpers';

// Custom trigger button CSS
const buttonCss = css`
&:hover {
text-decoration: none;
}
`;

interface AdditionalOptionsFieldsProps {
config: Config;
optionalProviderFormFields: ConfigEntryView[];
onSetProviderConfigEntry: (key: string, value: unknown) => Promise<void>;
onTaskTypeOptionsSelect: (taskType: string, provider?: string) => void;
selectedTaskType?: string;
taskTypeOptions: TaskTypeOption[];
}

export const AdditionalOptionsFields: React.FC<AdditionalOptionsFieldsProps> = ({
config,
taskTypeOptions,
optionalProviderFormFields,
selectedTaskType,
onSetProviderConfigEntry,
onTaskTypeOptionsSelect,
}) => {
const xsFontSize = useEuiFontSize('xs').fontSize;
const { euiTheme } = useEuiTheme();
const { setFieldValue } = useFormContext();

const taskTypeSettings = useMemo(
() =>
selectedTaskType || config.taskType?.length ? (
<>
<EuiTitle size="xxs" data-test-subj="task-type-details-label">
<h4>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.additionalInfo.taskTypeLabel"
defaultMessage="Task type"
/>
</h4>
</EuiTitle>
<EuiText
css={css`
font-size: ${xsFontSize};
color: ${euiTheme.colors.textSubdued};
`}
>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.additionalInfo.taskTypeHelpInfo"
defaultMessage="Configure the inference task. Task types are specific to the service and model selected."
/>
</EuiText>
<EuiSpacer size="m" />
<UseField
path="config.taskType"
config={{
validations: [
{
validator: fieldValidators.emptyField(LABELS.getRequiredMessage('Task type')),
isBlocking: true,
},
],
}}
>
{(field) => {
const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field);

return (
<EuiFormRow id="taskType" fullWidth isInvalid={isInvalid} error={errorMessage}>
{taskTypeOptions.length === 1 ? (
<EuiButton
css={{
background: euiTheme.colors.darkShade,
color: euiTheme.colors.lightestShade,
}}
data-test-subj="taskTypeSelectSingle"
onClick={() => onTaskTypeOptionsSelect(config.taskType)}
>
{config.taskType}
</EuiButton>
) : (
<EuiButtonGroup
data-test-subj="taskTypeSelect"
buttonSize="m"
legend="Task type"
defaultValue={DEFAULT_TASK_TYPE}
idSelected={config.taskType}
onChange={(id) => onTaskTypeOptionsSelect(id)}
options={taskTypeOptions}
color="text"
type="single"
/>
)}
</EuiFormRow>
);
}}
</UseField>
</>
) : null,
[
selectedTaskType,
config.taskType,
xsFontSize,
euiTheme.colors,
taskTypeOptions,
onTaskTypeOptionsSelect,
]
);

const inferenceUri = useMemo(() => `_inference/${selectedTaskType}/`, [selectedTaskType]);

return (
<EuiAccordion
id="inferenceAdditionalOptions"
data-test-subj="inference-endpoint-additional-options"
buttonProps={{ css: buttonCss }}
css={css`
.euiAccordion__triggerWrapper {
display: inline-flex;
}
`}
element="fieldset"
arrowDisplay="right"
arrowProps={{
color: 'primary',
}}
buttonElement="button"
borders="none"
buttonContent={
<EuiTextColor color={euiTheme.colors.primary}>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.additionalInfo.additionalOptionsLabel"
defaultMessage="Additional options"
/>
</EuiTextColor>
}
initialIsOpen={true}
>
<EuiSpacer size="m" />
<EuiPanel hasBorder={true}>
{optionalProviderFormFields.length > 0 ? (
<>
<EuiTitle size="xxs" data-test-subj="provider-optional-settings-label">
<h4>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.additionalInfo.providerOptionalSettingsLabel"
defaultMessage="Service settings"
/>
</h4>
</EuiTitle>
<EuiText
css={css`
font-size: ${xsFontSize};
color: ${euiTheme.colors.textSubdued};
`}
>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.additionalInfo.providerOptionalSettingsHelpLabel"
defaultMessage="Configure the inference provider. These settings are optional provider settings."
/>
</EuiText>
<EuiSpacer size="m" />
<ConfigurationFormItems
isLoading={false}
direction="column"
items={optionalProviderFormFields}
setConfigEntry={onSetProviderConfigEntry}
/>
<EuiSpacer size="m" />
</>
) : null}

{taskTypeSettings}
<EuiSpacer size="m" />
<EuiTitle size="xxs" data-test-subj="task-type-details-label">
<h4>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.additionalInfo.inferenceEndpointLabel"
defaultMessage="Inference Endpoint"
/>
</h4>
</EuiTitle>
<EuiText
css={css`
font-size: ${xsFontSize};
color: ${euiTheme.colors.textSubdued};
`}
>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.additionalInfo.inferenceEndpointHelpLabel"
defaultMessage="Inference endpoints provide a simplified method for using this configuration, ecpecially from the API"
/>
</EuiText>
<EuiSpacer size="s" />

<UseField path="config.inferenceId">
{(field) => {
const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field);

return (
<EuiFormRow
id="inferenceId"
isInvalid={isInvalid}
error={errorMessage}
fullWidth
helpText={
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.additionalInfo.inferenceIdHelpLabel"
defaultMessage="This ID cannot be changed once created."
/>
}
>
<EuiFieldText
data-test-subj="inference-endpoint-input-field"
fullWidth
value={config.inferenceId}
onChange={(e) => {
setFieldValue('config.inferenceId', e.target.value);
}}
prepend={inferenceUri}
append={
<EuiCopy
beforeMessage={LABELS.COPY_TOOLTIP}
afterMessage={LABELS.COPIED_TOOLTIP}
textToCopy={`${inferenceUri}${config.inferenceId}`}
>
{(copy) => (
<EuiButtonEmpty
iconType="copy"
size="xs"
iconSide="right"
onClick={copy}
data-test-subj="copyInferenceUriToClipboard"
>
<FormattedMessage
id="xpack.inferenceEndpointUICommon.components.additionalInfo.copyLabel"
defaultMessage="Copy"
/>
</EuiButtonEmpty>
)}
</EuiCopy>
}
/>
</EuiFormRow>
);
}}
</UseField>
</EuiPanel>
</EuiAccordion>
);
};
Loading

0 comments on commit bc466ea

Please sign in to comment.