Skip to content

Commit

Permalink
Merge branch 'main' of github.com:elastic/kibana into slo-add-preview…
Browse files Browse the repository at this point in the history
…-to-custom-metric
  • Loading branch information
simianhacker committed Jul 10, 2023
2 parents f1d9be4 + 4439121 commit 7eba465
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 72 deletions.
Expand Up @@ -211,12 +211,12 @@ describe('MlInferenceLogic', () => {

expect(MLInferenceLogic.values.existingInferencePipelines).toEqual([
{
destinationField: 'test-field',
disabled: false,
modelId: 'test-model',
modelType: '',
pipelineName: 'unit-test',
sourceField: 'body',
sourceFields: ['body'],
indexFields: ['body'],
},
]);
});
Expand Down Expand Up @@ -258,13 +258,13 @@ describe('MlInferenceLogic', () => {

expect(MLInferenceLogic.values.existingInferencePipelines).toEqual([
{
destinationField: 'title',
disabled: true,
disabledReason: expect.stringContaining('title, body_content'),
modelId: 'test-model',
modelType: '',
pipelineName: 'unit-test',
sourceField: 'title',
sourceFields: ['title', 'body', 'body_content'],
indexFields: ['body'],
},
]);
});
Expand All @@ -288,12 +288,12 @@ describe('MlInferenceLogic', () => {

expect(MLInferenceLogic.values.existingInferencePipelines).toEqual([
{
destinationField: 'test-field',
disabled: false,
pipelineName: 'unit-test',
modelType: '',
modelId: '',
sourceField: 'body',
sourceFields: ['body'],
indexFields: ['body'],
},
]);
});
Expand Down Expand Up @@ -326,13 +326,13 @@ describe('MlInferenceLogic', () => {

expect(MLInferenceLogic.values.existingInferencePipelines).toEqual([
{
destinationField: 'test-field',
disabled: true,
disabledReason: expect.any(String),
pipelineName: 'unit-test',
modelType: '',
modelId: 'test-model',
sourceField: 'body',
sourceFields: ['body'],
indexFields: ['body'],
},
]);
});
Expand Down
Expand Up @@ -99,13 +99,13 @@ const API_REQUEST_COMPLETE_STATUSES = [Status.SUCCESS, Status.ERROR];
const DEFAULT_CONNECTOR_FIELDS = ['body', 'title', 'id', 'type', 'url'];

export interface MLInferencePipelineOption {
destinationField: string;
disabled: boolean;
disabledReason?: string;
modelId: string;
modelType: string;
pipelineName: string;
sourceField: string;
sourceFields: string[];
indexFields: string[];
}

interface MLInferenceProcessorsActions {
Expand Down Expand Up @@ -570,7 +570,7 @@ export const MLInferenceLogic = kea<
],
(
mlInferencePipelinesData: MLInferenceProcessorsValues['mlInferencePipelinesData'],
sourceFields: MLInferenceProcessorsValues['sourceFields'],
indexFields: MLInferenceProcessorsValues['sourceFields'],
supportedMLModels: MLInferenceProcessorsValues['supportedMLModels'],
mlInferencePipelineProcessors: MLInferenceProcessorsValues['mlInferencePipelineProcessors']
) => {
Expand All @@ -587,16 +587,10 @@ export const MLInferenceLogic = kea<
if (!pipeline) return undefined;
const pipelineParams = parseMlInferenceParametersFromPipeline(pipelineName, pipeline);
if (!pipelineParams) return undefined;
const {
destination_field: destinationField,
model_id: modelId,
source_field: sourceField,
field_mappings: fieldMappings,
} = pipelineParams;
const { model_id: modelId, field_mappings: fieldMappings } = pipelineParams;

const missingSourceFields =
fieldMappings?.map((f) => f.sourceField).filter((f) => !sourceFields?.includes(f)) ??
[];
const sourceFields = fieldMappings?.map((m) => m.sourceField) ?? [];
const missingSourceFields = sourceFields.filter((f) => !indexFields?.includes(f)) ?? [];
const mlModel = supportedMLModels.find((model) => model.model_id === modelId);
const modelType = mlModel ? getMLType(getMlModelTypesForModelConfig(mlModel)) : '';
const disabledReason = getDisabledReason(
Expand All @@ -606,13 +600,13 @@ export const MLInferenceLogic = kea<
);

return {
destinationField: destinationField ?? '',
disabled: disabledReason !== undefined,
disabledReason,
modelId,
modelType,
pipelineName,
sourceField,
sourceFields,
indexFields: indexFields ?? [],
};
})
.filter((p): p is MLInferencePipelineOption => p !== undefined);
Expand Down
@@ -0,0 +1,75 @@
/*
* 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 { shallow } from 'enzyme';

import { EuiText, EuiTitle } from '@elastic/eui';

import { MLModelTypeBadge } from '../ml_model_type_badge';

import { MLInferencePipelineOption } from './ml_inference_logic';
import { PipelineSelectOption, PipelineSelectOptionDisabled } from './pipeline_select_option';

import { MODEL_REDACTED_VALUE } from './utils';

describe('PipelineSelectOption', () => {
const pipeline: MLInferencePipelineOption = {
disabled: false,
disabledReason: undefined,
modelId: 'my-model-id',
modelType: 'my-model-type',
pipelineName: 'my-pipeline',
sourceFields: ['my-source-field1', 'my-source-field2'],
indexFields: [],
};

beforeEach(() => {
jest.clearAllMocks();
});
it('renders pipeline selection option', () => {
const wrapper = shallow(<PipelineSelectOption pipeline={pipeline} />);
expect(wrapper.find(EuiTitle)).toHaveLength(1);
expect(wrapper.find(MLModelTypeBadge)).toHaveLength(1);
});
it('does not render model type badge if model type is unknown', () => {
const wrapper = shallow(
<PipelineSelectOption
pipeline={{
...pipeline,
modelType: '',
}}
/>
);
expect(wrapper.find(MLModelTypeBadge)).toHaveLength(0);
});
it("redacts model ID if it's unavailable", () => {
const wrapper = shallow(
<PipelineSelectOption
pipeline={{
...pipeline,
modelId: '',
}}
/>
);
expect(wrapper.find(EuiText)).toHaveLength(4);
expect(wrapper.find(EuiText).at(1).children().text()).toEqual(MODEL_REDACTED_VALUE);
});
it('renders disable warning text if the pipeline is disabled', () => {
const wrapper = shallow(
<PipelineSelectOption
pipeline={{
...pipeline,
disabled: true,
disabledReason: 'my-reason',
}}
/>
);
expect(wrapper.find(PipelineSelectOptionDisabled)).toHaveLength(1);
});
});
Expand Up @@ -7,49 +7,59 @@

import React from 'react';

import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiTextColor, EuiTitle } from '@elastic/eui';
import {
EuiFlexGroup,
EuiFlexItem,
EuiIcon,
EuiSpacer,
EuiText,
EuiTextColor,
EuiTitle,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';

import { MLModelTypeBadge } from '../ml_model_type_badge';

import { MLInferencePipelineOption } from './ml_inference_logic';
import { EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELD, MODEL_REDACTED_VALUE } from './utils';
import { EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELDS, MODEL_REDACTED_VALUE } from './utils';

export interface PipelineSelectOptionProps {
pipeline: MLInferencePipelineOption;
}

export const PipelineSelectOption: React.FC<PipelineSelectOptionProps> = ({ pipeline }) => {
const modelIdDisplay = pipeline.modelId.length > 0 ? pipeline.modelId : MODEL_REDACTED_VALUE;
export const PipelineSelectOptionDisabled: React.FC<{ disabledReason?: string }> = ({
disabledReason,
}) => {
return (
<EuiFlexGroup direction="column" gutterSize="xs">
{pipeline.disabled && (
<EuiFlexItem>
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiIcon type="warning" color="warning" />
</EuiFlexItem>
<EuiFlexItem>
<EuiTextColor color="default">
{pipeline.disabledReason ?? EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELD}
</EuiTextColor>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
)}
<>
<EuiSpacer size="xs" />
<EuiFlexItem>
<EuiTitle size="xs">
<h4>{pipeline.pipelineName}</h4>
</EuiTitle>
<EuiFlexGroup alignItems="center" gutterSize="s">
<EuiFlexItem grow={false}>
<EuiIcon type="warning" color="warning" />
</EuiFlexItem>
<EuiFlexItem>
<EuiTextColor color="warning">
{disabledReason ?? EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELDS}
</EuiTextColor>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiSpacer size="xs" />
</>
);
};

export const PipelineSelectOption: React.FC<PipelineSelectOptionProps> = ({ pipeline }) => {
const modelIdDisplay = pipeline.modelId.length > 0 ? pipeline.modelId : MODEL_REDACTED_VALUE;
return (
<EuiFlexGroup direction="column" gutterSize="none">
<EuiFlexItem>
<EuiFlexGroup gutterSize="s" alignItems="center" justifyContent="flexEnd">
<EuiFlexItem>
{pipeline.disabled ? (
modelIdDisplay
) : (
<EuiTextColor color="subdued">{modelIdDisplay}</EuiTextColor>
)}
<EuiTitle size="xs">
<h4>{pipeline.pipelineName}</h4>
</EuiTitle>
</EuiFlexItem>
{pipeline.modelType.length > 0 && (
<EuiFlexItem grow={false}>
Expand All @@ -58,32 +68,46 @@ export const PipelineSelectOption: React.FC<PipelineSelectOptionProps> = ({ pipe
)}
</EuiFlexGroup>
</EuiFlexItem>
<EuiSpacer size="m" />
<EuiFlexItem>
<EuiFlexGroup>
<EuiFlexGroup gutterSize="s" alignItems="center" justifyContent="flexEnd">
<EuiFlexItem>
<strong>
<EuiText size="s" color="subdued">
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.sourceField',
{ defaultMessage: 'Source field' }
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.model',
{ defaultMessage: 'Model' }
)}
</strong>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="s" color={pipeline.disabled ? 'subdued' : 'normal'}>
{modelIdDisplay}
</EuiText>
</EuiFlexItem>
<EuiFlexItem>{pipeline.sourceField}</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiSpacer size="xs" />
<EuiFlexItem>
<EuiFlexGroup>
<EuiFlexItem>
<strong>
<EuiFlexItem style={{ minWidth: 100 }}>
<EuiText size="s" color="subdued">
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.destinationField',
{ defaultMessage: 'Destination field' }
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.sourceFields',
{ defaultMessage: 'Source fields' }
)}
</strong>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="s" color={pipeline.disabled ? 'subdued' : 'normal'} textAlign="right">
{pipeline.sourceFields.join(', ')}
</EuiText>
</EuiFlexItem>
<EuiFlexItem>{pipeline.destinationField}</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiSpacer size="s" />
{pipeline.disabled && (
<PipelineSelectOptionDisabled disabledReason={pipeline.disabledReason} />
)}
</EuiFlexGroup>
);
};
Expand Up @@ -84,14 +84,13 @@ export const validateInferencePipelineFields = (
return errors;
};

export const EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELD = (
export const EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELDS = (
commaSeparatedMissingSourceFields: string
) =>
i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.disabledSourceFieldDescription',
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.missingSourceFieldsDescription',
{
defaultMessage:
"This pipeline cannot be selected because some source fields don't exist in this index: {commaSeparatedMissingSourceFields}.",
defaultMessage: 'Fields missing in this index: {commaSeparatedMissingSourceFields}',
values: { commaSeparatedMissingSourceFields },
}
);
Expand All @@ -109,7 +108,7 @@ export const getDisabledReason = (
pipelineName: string
): string | undefined => {
if (missingSourceFields.length > 0) {
return EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELD(missingSourceFields.join(', '));
return EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELDS(missingSourceFields.join(', '));
} else if (indexProcessorNames.includes(pipelineName)) {
return EXISTING_PIPELINE_DISABLED_PIPELINE_EXISTS;
}
Expand Down
2 changes: 0 additions & 2 deletions x-pack/plugins/translations/translations/fr-FR.json
Expand Up @@ -13143,12 +13143,10 @@
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.docsLink": "Découvrez l'importation et l'utilisation des modèles de ML dans Enterprise Search",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.emptyValueError": "Champ obligatoire.",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.chooseLabel": "Choisir",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.destinationField": "Champ de destination",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.disabledPipelineExistsDescription": "Ce pipeline ne peut pas être sélectionné car il est déjà attaché.",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.existingLabel": "Pipeline existant",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.newLabel": "Nouveau pipeline",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.placeholder": "Effectuez une sélection",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.sourceField": "Champ source",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipelineLabel": "Sélectionner un pipeline d'inférence existant",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.inference.title": "Configuration de l'inférence",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.inference.zeroShot.labels.label": "Étiquettes de classe",
Expand Down
2 changes: 0 additions & 2 deletions x-pack/plugins/translations/translations/ja-JP.json
Expand Up @@ -13142,12 +13142,10 @@
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.docsLink": "エンタープライズ サーチでのMLモデルのインポートと使用の詳細",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.emptyValueError": "フィールドが必要です。",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.chooseLabel": "選択",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.destinationField": "デスティネーションフィールド",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.disabledPipelineExistsDescription": "このパイプラインはすでにアタッチされているため、選択できません。",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.existingLabel": "既存のパイプライン",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.newLabel": "新しいパイプライン",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.placeholder": "1 つ選択してください",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.sourceField": "ソースフィールド",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipelineLabel": "既存の推論パイプラインを選択",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.inference.title": "推論構成",
"xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.inference.zeroShot.labels.label": "クラスラベル",
Expand Down

0 comments on commit 7eba465

Please sign in to comment.