Skip to content

Commit

Permalink
[8.12] [Enterprise Search] Split details panel from model selection l…
Browse files Browse the repository at this point in the history
…ist (#173434) (#173697)

# Backport

This will backport the following commits from `main` to `8.12`:
- [[Enterprise Search] Split details panel from model selection list
(#173434)](#173434)

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

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

<!--BACKPORT [{"author":{"name":"Adam
Demjen","email":"[email protected]"},"sourceCommit":{"committedDate":"2023-12-19T22:37:29Z","message":"[Enterprise
Search] Split details panel from model selection list (#173434)\n\n##
Summary\r\n\r\nIn this PR the ML model selection list is being split
into a simplified\r\nlist and a details panel for the selected model.
This change provides\r\nproblem-free keyboard navigation and a cleaner
look.\r\n\r\n<img width=\"1206\" alt=\"Screenshot 2023-12-18 at 09 34
40\"\r\nsrc=\"https://github.com/elastic/kibana/assets/14224983/815fe106-cc7b-4bab-8a03-0bda6ec6459e\">\r\n\r\nThe
Start button in the model panel now appears and works for any
model,\r\nnot just ELSER/E5.\r\n\r\nIn order to make the model status
labels and actions consistent, some\r\nlabels have been renamed:\r\n-
\"Downloaded\" -> \"Deployed\"\r\n- \"Downloading\" ->
\"Deploying\"\r\n\r\nThe fetch logic is now returning \"Not deployed\"
for a downloaded curated\r\nmodel. Any model (curated or 3rd party) in
this state can be started\r\nwith the Start button.\r\n\r\n###
Checklist\r\n\r\nDelete any items that are not applicable to this
PR.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\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 is usable by keyboard only (learn more\r\nabout
[keyboard accessibility](https://webaim.org/techniques/keyboard/))\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\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<[email protected]>","sha":"641177e2fed06a4c4d44eb6ba8e2bea2310f5404","branchLabelMapping":{"^v8.13.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:EnterpriseSearch","v8.12.0","a11yReviewNeeded","v8.13.0"],"number":173434,"url":"https://github.com/elastic/kibana/pull/173434","mergeCommit":{"message":"[Enterprise
Search] Split details panel from model selection list (#173434)\n\n##
Summary\r\n\r\nIn this PR the ML model selection list is being split
into a simplified\r\nlist and a details panel for the selected model.
This change provides\r\nproblem-free keyboard navigation and a cleaner
look.\r\n\r\n<img width=\"1206\" alt=\"Screenshot 2023-12-18 at 09 34
40\"\r\nsrc=\"https://github.com/elastic/kibana/assets/14224983/815fe106-cc7b-4bab-8a03-0bda6ec6459e\">\r\n\r\nThe
Start button in the model panel now appears and works for any
model,\r\nnot just ELSER/E5.\r\n\r\nIn order to make the model status
labels and actions consistent, some\r\nlabels have been renamed:\r\n-
\"Downloaded\" -> \"Deployed\"\r\n- \"Downloading\" ->
\"Deploying\"\r\n\r\nThe fetch logic is now returning \"Not deployed\"
for a downloaded curated\r\nmodel. Any model (curated or 3rd party) in
this state can be started\r\nwith the Start button.\r\n\r\n###
Checklist\r\n\r\nDelete any items that are not applicable to this
PR.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\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 is usable by keyboard only (learn more\r\nabout
[keyboard accessibility](https://webaim.org/techniques/keyboard/))\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\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<[email protected]>","sha":"641177e2fed06a4c4d44eb6ba8e2bea2310f5404"}},"sourceBranch":"main","suggestedTargetBranches":["8.12"],"targetPullRequestStates":[{"branch":"8.12","label":"v8.12.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.13.0","labelRegex":"^v8.13.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/173434","number":173434,"mergeCommit":{"message":"[Enterprise
Search] Split details panel from model selection list (#173434)\n\n##
Summary\r\n\r\nIn this PR the ML model selection list is being split
into a simplified\r\nlist and a details panel for the selected model.
This change provides\r\nproblem-free keyboard navigation and a cleaner
look.\r\n\r\n<img width=\"1206\" alt=\"Screenshot 2023-12-18 at 09 34
40\"\r\nsrc=\"https://github.com/elastic/kibana/assets/14224983/815fe106-cc7b-4bab-8a03-0bda6ec6459e\">\r\n\r\nThe
Start button in the model panel now appears and works for any
model,\r\nnot just ELSER/E5.\r\n\r\nIn order to make the model status
labels and actions consistent, some\r\nlabels have been renamed:\r\n-
\"Downloaded\" -> \"Deployed\"\r\n- \"Downloading\" ->
\"Deploying\"\r\n\r\nThe fetch logic is now returning \"Not deployed\"
for a downloaded curated\r\nmodel. Any model (curated or 3rd party) in
this state can be started\r\nwith the Start button.\r\n\r\n###
Checklist\r\n\r\nDelete any items that are not applicable to this
PR.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\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 is usable by keyboard only (learn more\r\nabout
[keyboard accessibility](https://webaim.org/techniques/keyboard/))\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\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<[email protected]>","sha":"641177e2fed06a4c4d44eb6ba8e2bea2310f5404"}}]}]
BACKPORT-->

Co-authored-by: Adam Demjen <[email protected]>
  • Loading branch information
kibanamachine and demjened authored Dec 19, 2023
1 parent 0f9c1ea commit f7e2d6e
Show file tree
Hide file tree
Showing 13 changed files with 614 additions and 345 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
EuiTabbedContentTab,
EuiTitle,
EuiText,
EuiTextColor,
} from '@elastic/eui';

import { i18n } from '@kbn/i18n';
Expand Down Expand Up @@ -131,27 +130,15 @@ export const ConfigurePipeline: React.FC = () => {
<EuiSpacer />
</>
)}
<EuiSpacer size="s" />
<EuiTitle size="xxxs">
<h6>
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.titleSelectTrainedModel',
{ defaultMessage: 'Select a trained ML Model' }
)}
</h6>
</EuiTitle>
{formErrors.modelStatus !== undefined && (
<>
<EuiSpacer size="xs" />
<EuiText size="xs">
<p>
<EuiTextColor color="danger">{formErrors.modelStatus}</EuiTextColor>
</p>
</EuiText>
</>
)}
<EuiSpacer size="xs" />
<ModelSelect />
<EuiFormRow
fullWidth
label={i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.titleSelectTrainedModel',
{ defaultMessage: 'Select a trained ML Model' }
)}
>
<ModelSelect />
</EuiFormRow>
</EuiForm>
</>
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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 { EuiLink } from '@elastic/eui';

import { LicenseBadge, LicenseBadgeProps } from './license_badge';

const DEFAULT_PROPS: LicenseBadgeProps = {
licenseType: 'mit',
modelDetailsPageUrl: 'https://my-model.ai',
};

describe('LicenseBadge', () => {
it('renders with link if URL is present', () => {
const wrapper = shallow(
<LicenseBadge
licenseType={DEFAULT_PROPS.licenseType}
modelDetailsPageUrl={DEFAULT_PROPS.modelDetailsPageUrl}
/>
);
expect(wrapper.find(EuiLink)).toHaveLength(1);
});
it('renders without link if URL is not present', () => {
const wrapper = shallow(<LicenseBadge licenseType={DEFAULT_PROPS.licenseType} />);
expect(wrapper.find(EuiLink)).toHaveLength(0);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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 { EuiBadge, EuiLink } from '@elastic/eui';

import { i18n } from '@kbn/i18n';

export interface LicenseBadgeProps {
licenseType: string;
modelDetailsPageUrl?: string;
}

export const LicenseBadge: React.FC<LicenseBadgeProps> = ({ licenseType, modelDetailsPageUrl }) => {
const licenseLabel = i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.modelSelectOption.licenseBadge.label',
{
defaultMessage: 'License: {licenseType}',
values: {
licenseType,
},
}
);

return (
<EuiBadge color="hollow">
{modelDetailsPageUrl ? (
<EuiLink target="_blank" href={modelDetailsPageUrl}>
{licenseLabel}
</EuiLink>
) : (
<p>{licenseLabel}</p>
)}
</EuiBadge>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export interface MLInferencePipelineOption {
indexFields: string[];
}

interface MLInferenceProcessorsActions {
export interface MLInferenceProcessorsActions {
addSelectedFieldsToMapping: (isTextExpansionModelSelected: boolean) => {
isTextExpansionModelSelected: boolean;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,23 @@ import React from 'react';

import { shallow } from 'enzyme';

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

import { ModelSelect } from './model_select';
import { MlModel, MlModelDeploymentState } from '../../../../../../../common/types/ml';

import { LicenseBadge } from './license_badge';
import {
DeployModelButton,
ModelSelect,
NoModelSelected,
SelectedModel,
StartModelButton,
} from './model_select';

const DEFAULT_VALUES = {
addInferencePipelineModal: {
configuration: {},
indexName: 'my-index',
},
selectableModels: [
{
Expand All @@ -27,8 +37,23 @@ const DEFAULT_VALUES = {
modelId: 'model_2',
},
],
indexName: 'my-index',
};
const DEFAULT_MODEL: MlModel = {
modelId: 'model_1',
type: 'ner',
title: 'Model 1',
description: 'Model 1 description',
licenseType: 'elastic',
modelDetailsPageUrl: 'https://my-model.ai',
deploymentState: MlModelDeploymentState.NotDeployed,
startTime: 0,
targetAllocationCount: 0,
nodeAllocationCount: 0,
threadsPerAllocation: 0,
isPlaceholder: false,
hasStats: false,
};

const MOCK_ACTIONS = {
setInferencePipelineConfiguration: jest.fn(),
};
Expand Down Expand Up @@ -150,4 +175,74 @@ describe('ModelSelect', () => {
})
);
});
it('renders selected model panel if a model is selected', () => {
setMockValues({
...DEFAULT_VALUES,
addInferencePipelineModal: {
configuration: {
...DEFAULT_VALUES.addInferencePipelineModal.configuration,
modelID: 'model_2',
},
},
selectedModel: DEFAULT_MODEL,
});

const wrapper = shallow(<ModelSelect />);
expect(wrapper.find(SelectedModel)).toHaveLength(1);
expect(wrapper.find(NoModelSelected)).toHaveLength(0);
});
it('renders no model selected panel if no model is selected', () => {
setMockValues(DEFAULT_VALUES);

const wrapper = shallow(<ModelSelect />);
expect(wrapper.find(SelectedModel)).toHaveLength(0);
expect(wrapper.find(NoModelSelected)).toHaveLength(1);
});

describe('SelectedModel', () => {
it('renders with license badge if present', () => {
const wrapper = shallow(<SelectedModel {...DEFAULT_MODEL} />);
expect(wrapper.find(LicenseBadge)).toHaveLength(1);
});
it('renders without license badge if not present', () => {
const props = {
...DEFAULT_MODEL,
licenseType: undefined,
};

const wrapper = shallow(<SelectedModel {...props} />);
expect(wrapper.find(LicenseBadge)).toHaveLength(0);
});
it('renders with description if present', () => {
const wrapper = shallow(<SelectedModel {...DEFAULT_MODEL} />);
expect(wrapper.find(EuiText)).toHaveLength(1);
});
it('renders without description if not present', () => {
const props = {
...DEFAULT_MODEL,
description: undefined,
};

const wrapper = shallow(<SelectedModel {...props} />);
expect(wrapper.find(EuiText)).toHaveLength(0);
});
it('renders deploy button for a model placeholder', () => {
const props = {
...DEFAULT_MODEL,
isPlaceholder: true,
};

const wrapper = shallow(<SelectedModel {...props} />);
expect(wrapper.find(DeployModelButton)).toHaveLength(1);
});
it('renders start button for a downloaded model', () => {
const props = {
...DEFAULT_MODEL,
deploymentState: MlModelDeploymentState.NotDeployed,
};

const wrapper = shallow(<SelectedModel {...props} />);
expect(wrapper.find(StartModelButton)).toHaveLength(1);
});
});
});
Loading

0 comments on commit f7e2d6e

Please sign in to comment.