[8.6] [Enterprise Search][ML Inference] UX improvements (#145305) (#145902)

# Backport

This will backport the following commits from `main` to `8.6`:
- [[Enterprise Search][ML Inference] UX improvements
(#145305)](https://github.com/elastic/kibana/pull/145305)

<!--- Backport version: 8.9.7 -->

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

<!--BACKPORT [{"author":{"name":"Rodney
Norris","email":"rodney.norris@elastic.co"},"sourceCommit":{"committedDate":"2022-11-21T17:42:56Z","message":"[Enterprise
Search][ML Inference] UX improvements (#145305)\n\n## Summary\r\n\r\n-
[x] Drop subtext from \"Ingestion error logs\" card\r\n- [x] Update no
items copy for Ingestion history table, align with\r\nerrors no items
message\r\n- [x] Add to complete name help text \"This will create a
pipeline named\r\n{complete name}\"\r\n- [x] Capitalize \"Space\" in
\"This model isn't available in the space\"\r\nmessage\r\n- [x] Re-use
\"This model isn't available in the space\" message for model\r\nselect
display when re-using a pipeline with a redacted model.\r\n- [x] Add
right padding to add inference modal back button, going back\r\nfrom
review to test it is highlighted and ends at the `k` of `Back`\r\n- [x]
Rename \"Destination field\" to \"Target field\" to align
with\r\npipelines UI\r\n- [x] Update help text for Target field to
call-out first class field\r\nwill be created\r\nSomething like: \"This
names the field that holds the commonly searched\r\nvalue and names the
subfield used to contain the complete processor\r\nresult. {{Line
break}} Learn more (link to docs - to the guide
when\r\navailable)\"\r\n- [x] Existing or New select value not retained
when leaving configure\r\nstep and going back\r\n- [x] Removed inference
history footer as we do not have a good doc to\r\nlink to
currently.\r\n\r\n### Screenshots\r\nPipelines
Screen\r\n\r\n![image](https://user-images.githubusercontent.com/1972968/202573755-c32ebff1-b8ca-476f-b35b-73e9a74ee145.png)\r\nAdd
Inference
Modal\r\n\r\n![image](https://user-images.githubusercontent.com/1972968/202573942-94bb7828-ead5-48bf-a1b2-ba746cef006a.png)\r\nAdd
inference pipeline modal Back button
padding\r\n\r\n![image](https://user-images.githubusercontent.com/1972968/202574202-920c5d83-3d2a-4659-b052-76ebfcd231e6.png)","sha":"acb4db605a61cd089c736946ce8fc0048775a1ad","branchLabelMapping":{"^v8.7.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:EnterpriseSearch","v8.6.0","v8.7.0"],"number":145305,"url":"https://github.com/elastic/kibana/pull/145305","mergeCommit":{"message":"[Enterprise
Search][ML Inference] UX improvements (#145305)\n\n## Summary\r\n\r\n-
[x] Drop subtext from \"Ingestion error logs\" card\r\n- [x] Update no
items copy for Ingestion history table, align with\r\nerrors no items
message\r\n- [x] Add to complete name help text \"This will create a
pipeline named\r\n{complete name}\"\r\n- [x] Capitalize \"Space\" in
\"This model isn't available in the space\"\r\nmessage\r\n- [x] Re-use
\"This model isn't available in the space\" message for model\r\nselect
display when re-using a pipeline with a redacted model.\r\n- [x] Add
right padding to add inference modal back button, going back\r\nfrom
review to test it is highlighted and ends at the `k` of `Back`\r\n- [x]
Rename \"Destination field\" to \"Target field\" to align
with\r\npipelines UI\r\n- [x] Update help text for Target field to
call-out first class field\r\nwill be created\r\nSomething like: \"This
names the field that holds the commonly searched\r\nvalue and names the
subfield used to contain the complete processor\r\nresult. {{Line
break}} Learn more (link to docs - to the guide
when\r\navailable)\"\r\n- [x] Existing or New select value not retained
when leaving configure\r\nstep and going back\r\n- [x] Removed inference
history footer as we do not have a good doc to\r\nlink to
currently.\r\n\r\n### Screenshots\r\nPipelines
Screen\r\n\r\n![image](https://user-images.githubusercontent.com/1972968/202573755-c32ebff1-b8ca-476f-b35b-73e9a74ee145.png)\r\nAdd
Inference
Modal\r\n\r\n![image](https://user-images.githubusercontent.com/1972968/202573942-94bb7828-ead5-48bf-a1b2-ba746cef006a.png)\r\nAdd
inference pipeline modal Back button
padding\r\n\r\n![image](https://user-images.githubusercontent.com/1972968/202574202-920c5d83-3d2a-4659-b052-76ebfcd231e6.png)","sha":"acb4db605a61cd089c736946ce8fc0048775a1ad"}},"sourceBranch":"main","suggestedTargetBranches":["8.6"],"targetPullRequestStates":[{"branch":"8.6","label":"v8.6.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.7.0","labelRegex":"^v8.7.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/145305","number":145305,"mergeCommit":{"message":"[Enterprise
Search][ML Inference] UX improvements (#145305)\n\n## Summary\r\n\r\n-
[x] Drop subtext from \"Ingestion error logs\" card\r\n- [x] Update no
items copy for Ingestion history table, align with\r\nerrors no items
message\r\n- [x] Add to complete name help text \"This will create a
pipeline named\r\n{complete name}\"\r\n- [x] Capitalize \"Space\" in
\"This model isn't available in the space\"\r\nmessage\r\n- [x] Re-use
\"This model isn't available in the space\" message for model\r\nselect
display when re-using a pipeline with a redacted model.\r\n- [x] Add
right padding to add inference modal back button, going back\r\nfrom
review to test it is highlighted and ends at the `k` of `Back`\r\n- [x]
Rename \"Destination field\" to \"Target field\" to align
with\r\npipelines UI\r\n- [x] Update help text for Target field to
call-out first class field\r\nwill be created\r\nSomething like: \"This
names the field that holds the commonly searched\r\nvalue and names the
subfield used to contain the complete processor\r\nresult. {{Line
break}} Learn more (link to docs - to the guide
when\r\navailable)\"\r\n- [x] Existing or New select value not retained
when leaving configure\r\nstep and going back\r\n- [x] Removed inference
history footer as we do not have a good doc to\r\nlink to
currently.\r\n\r\n### Screenshots\r\nPipelines
Screen\r\n\r\n![image](https://user-images.githubusercontent.com/1972968/202573755-c32ebff1-b8ca-476f-b35b-73e9a74ee145.png)\r\nAdd
Inference
Modal\r\n\r\n![image](https://user-images.githubusercontent.com/1972968/202573942-94bb7828-ead5-48bf-a1b2-ba746cef006a.png)\r\nAdd
inference pipeline modal Back button
padding\r\n\r\n![image](https://user-images.githubusercontent.com/1972968/202574202-920c5d83-3d2a-4659-b052-76ebfcd231e6.png)","sha":"acb4db605a61cd089c736946ce8fc0048775a1ad"}}]}]
BACKPORT-->

Co-authored-by: Rodney Norris <rodney.norris@elastic.co>
This commit is contained in:
Kibana Machine 2022-11-21 13:47:52 -05:00 committed by GitHub
parent e1c4607e48
commit 22c00575cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 142 additions and 58 deletions

View file

@ -31,7 +31,7 @@ export const InferenceErrors: React.FC = () => {
dataType: 'date',
field: 'timestamp',
name: i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.pipelineLogs.tableColumn.timestamp',
'xpack.enterpriseSearch.content.indices.pipelines.tabs.pipelineInferenceLogs.tableColumn.timestamp',
{ defaultMessage: 'Timestamp' }
),
},
@ -39,8 +39,8 @@ export const InferenceErrors: React.FC = () => {
dataType: 'string',
field: 'message',
name: i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.pipelineLogs.tableColumn.message',
{ defaultMessage: 'Inference error' }
'xpack.enterpriseSearch.content.indices.pipelines.tabs.pipelineInferenceLogs.tableColumn.message',
{ defaultMessage: 'Error message' }
),
textOnly: true,
},
@ -48,7 +48,7 @@ export const InferenceErrors: React.FC = () => {
dataType: 'number',
field: 'doc_count',
name: i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.pipelineLogs.tableColumn.docCount',
'xpack.enterpriseSearch.content.indices.pipelines.tabs.pipelineInferenceLogs.tableColumn.docCount',
{ defaultMessage: 'Approx. document count' }
),
},
@ -63,15 +63,11 @@ export const InferenceErrors: React.FC = () => {
title={
<h2>
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.pipelineLogs.title',
{ defaultMessage: 'Ingestion logs' }
'xpack.enterpriseSearch.content.indices.pipelines.tabs.pipelineInferenceLogs.title',
{ defaultMessage: 'Inference errors' }
)}
</h2>
}
subtitle={i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.pipelineLogs.subtitle',
{ defaultMessage: 'Errors and dropped data failures' }
)}
>
{isLoading ? (
<EuiLoadingSpinner />
@ -82,7 +78,7 @@ export const InferenceErrors: React.FC = () => {
items={inferenceErrors}
rowHeader="message"
noItemsMessage={i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.pipelineLogs.emptyMessage',
'xpack.enterpriseSearch.content.indices.pipelines.tabs.pipelineInferenceLogs.emptyMessage',
{ defaultMessage: 'This index has no inference errors' }
)}
/>

View file

@ -9,13 +9,7 @@ import React, { useEffect } from 'react';
import { useActions, useValues } from 'kea';
import {
EuiBasicTable,
EuiBasicTableColumn,
EuiLink,
EuiSpacer,
EuiLoadingSpinner,
} from '@elastic/eui';
import { EuiBasicTable, EuiBasicTableColumn, EuiSpacer, EuiLoadingSpinner } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
@ -71,17 +65,6 @@ export const InferenceHistory: React.FC = () => {
'The following inference processors were found in the _ingest.processors field of documents on this index.',
}
)}
footerDocLink={
// TODO: insert real doc link
<EuiLink href="#" target="_blank" color="subdued">
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.inferenceHistory.docLink',
{
defaultMessage: 'Learn more about inference history',
}
)}
</EuiLink>
}
>
{isLoading ? (
<EuiLoadingSpinner />
@ -90,6 +73,10 @@ export const InferenceHistory: React.FC = () => {
columns={historyColumns}
items={inferenceHistory ?? []}
rowHeader="pipeline"
noItemsMessage={i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.inferenceHistory.emptyMessage',
{ defaultMessage: 'This index has no inference history' }
)}
/>
)}
</DataPanel>

View file

@ -15,4 +15,11 @@
height: 100%;
}
}
.enterpriseSearchInferencePipelineModalFooter {
.euiButtonEmpty__content {
padding-left: $euiSizeM;
padding-right: $euiSizeM;
}
}
}

View file

@ -215,7 +215,7 @@ export const ModalFooter: React.FC<
break;
}
return (
<EuiModalFooter>
<EuiModalFooter className="enterpriseSearchInferencePipelineModalFooter">
<EuiFlexGroup>
<EuiFlexItem grow={false}>
{previousStep !== undefined ? (

View file

@ -33,6 +33,7 @@ import { IndexViewLogic } from '../../index_view_logic';
import { EMPTY_PIPELINE_CONFIGURATION, MLInferenceLogic } from './ml_inference_logic';
import { MlModelSelectOption } from './model_select_option';
import { PipelineSelectOption } from './pipeline_select_option';
import { TargetFieldHelpText } from './target_field_help_text';
import { MODEL_REDACTED_VALUE, MODEL_SELECT_PLACEHOLDER } from './utils';
const MODEL_SELECT_PLACEHOLDER_VALUE = 'model_placeholder$$';
@ -117,6 +118,7 @@ export const ConfigurePipeline: React.FC = () => {
];
const inputsDisabled = configuration.existingPipeline !== false;
const selectedModel = supportedMLModels.find((model) => model.model_id === modelID);
return (
<>
@ -173,6 +175,7 @@ export const ConfigurePipeline: React.FC = () => {
existingPipeline: e.target.value === 'true',
})
}
value={configuration.existingPipeline?.toString() ?? ''}
/>
</EuiFormRow>
</EuiFlexItem>
@ -209,12 +212,21 @@ export const ConfigurePipeline: React.FC = () => {
)}
helpText={
!nameError &&
i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.name.helpText',
{
defaultMessage:
'Pipeline names are unique within a deployment and can only contain letters, numbers, underscores, and hyphens.',
}
configuration.existingPipeline === false && (
<EuiText size="xs">
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.name.helpText',
{
defaultMessage:
'Pipeline names are unique within a deployment and can only contain letters, numbers, underscores, and hyphens. This will create a pipeline named {pipelineName}.',
values: {
pipelineName: `ml-inference-${
pipelineName.length > 0 ? pipelineName : '<name>'
}`,
},
}
)}
</EuiText>
)
}
error={nameError && formErrors.pipelineName}
@ -312,29 +324,26 @@ export const ConfigurePipeline: React.FC = () => {
<EuiFlexItem>
<EuiFormRow
label={i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.destinationField.label',
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.targetField.label',
{
defaultMessage: 'Destination field (optional)',
defaultMessage: 'Target field (optional)',
}
)}
helpText={
formErrors.destinationField === undefined &&
i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.destinationField.helpText',
{
defaultMessage:
'Your field name will be prefixed with "ml.inference.", if not set it will be defaulted to "ml.inference.{pipelineName}"',
values: {
pipelineName,
},
}
configuration.existingPipeline !== true && (
<TargetFieldHelpText
pipelineName={pipelineName}
targetField={destinationField}
model={selectedModel}
/>
)
}
error={formErrors.destinationField}
isInvalid={formErrors.destinationField !== undefined}
>
<EuiFieldText
data-telemetry-id={`entSearchContent-${ingestionMethod}-pipelines-configureInferencePipeline-destionationField`}
data-telemetry-id={`entSearchContent-${ingestionMethod}-pipelines-configureInferencePipeline-targetField`}
disabled={inputsDisabled}
placeholder="custom_field_name"
value={destinationField}

View file

@ -11,21 +11,14 @@ import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiTextColor, EuiTitle }
import { i18n } from '@kbn/i18n';
import { MLInferencePipelineOption } from './ml_inference_logic';
import { EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELD } from './utils';
import { EXISTING_PIPELINE_DISABLED_MISSING_SOURCE_FIELD, MODEL_REDACTED_VALUE } from './utils';
export interface PipelineSelectOptionProps {
pipeline: MLInferencePipelineOption;
}
const REDACTED_MODE_ID_DISPLAY = i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.existingPipeline.redactedModel',
{
defaultMessage: 'Trained model not available in this space',
}
);
export const PipelineSelectOption: React.FC<PipelineSelectOptionProps> = ({ pipeline }) => {
const modelIdDisplay = pipeline.modelId.length > 0 ? pipeline.modelId : REDACTED_MODE_ID_DISPLAY;
const modelIdDisplay = pipeline.modelId.length > 0 ? pipeline.modelId : MODEL_REDACTED_VALUE;
return (
<EuiFlexGroup direction="column" gutterSize="xs">
{pipeline.disabled && (

View file

@ -0,0 +1,92 @@
/*
* 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 { EuiText } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage, FormattedNumber } from '@kbn/i18n-react';
import {
getMlModelTypesForModelConfig,
SUPPORTED_PYTORCH_TASKS,
} from '../../../../../../../common/ml_inference_pipeline';
import { TrainedModel } from '../../../../api/ml_models/ml_trained_models_logic';
import { getMLType } from '../../../shared/ml_inference/utils';
export interface TargetFieldHelpTextProps {
model?: TrainedModel;
pipelineName: string;
targetField: string;
}
export const TargetFieldHelpText: React.FC<TargetFieldHelpTextProps> = ({
pipelineName,
targetField,
model,
}) => {
const baseText = targetField
? i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.targetField.helpText.userProvided',
{
defaultMessage:
'This names the field that holds the inference result. It will be prefixed with "ml.inference", ml.inference.{targetField}',
values: {
targetField,
},
}
)
: i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.targetField.helpText.default',
{
defaultMessage:
'This names the field that holds the inference result. It will be prefixed with "ml.inference", if not set it will be defaulted to "ml.inference.{pipelineName}"',
values: {
pipelineName: pipelineName || '<Pipeline Name>',
},
}
);
const fieldName = targetField || pipelineName || '<Pipeline Name>';
const modelType = model ? getMLType(getMlModelTypesForModelConfig(model)) : '';
if (modelType === SUPPORTED_PYTORCH_TASKS.TEXT_CLASSIFICATION) {
return (
<EuiText size="xs">
<p>{baseText}</p>
<p>
<FormattedMessage
id="xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.targetField.helpText.textClassificationModel"
defaultMessage='Additionally the predicted_value will be copied to "{fieldName}", if the prediction_probability is greater than {probabilityThreshold}'
values={{
fieldName,
probabilityThreshold: <FormattedNumber value={0.5} />,
}}
/>
</p>
</EuiText>
);
}
if (modelType === SUPPORTED_PYTORCH_TASKS.TEXT_EMBEDDING) {
return (
<EuiText size="xs">
<p>{baseText}</p>
<p>
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.targetField.helpText.textEmbeddingModel',
{
defaultMessage: 'Additionally the predicted_value will be copied to "{fieldName}"',
values: {
fieldName,
},
}
)}
</p>
</EuiText>
);
}
return <EuiText size="xs">{baseText}</EuiText>;
};

View file

@ -74,5 +74,5 @@ export const MODEL_SELECT_PLACEHOLDER = i18n.translate(
export const MODEL_REDACTED_VALUE = i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.model.redactedValue',
{ defaultMessage: 'Model is unavailable' }
{ defaultMessage: "This model isn't available in the Kibana space" }
);