diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.test.tsx index 970b1488010c0..62ac53004a773 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.test.tsx @@ -11,11 +11,11 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { EuiButtonIcon, EuiPanel, EuiTextColor, EuiTitle } from '@elastic/eui'; +import { EuiButtonEmpty, EuiPanel, EuiText, EuiTitle } from '@elastic/eui'; import { InferencePipeline, TrainedModelState } from '../../../../../../common/types/pipelines'; -import { InferencePipelineCard } from './inference_pipeline_card'; +import { InferencePipelineCard, TrainedModelHealthPopover } from './inference_pipeline_card'; import { MLModelTypeBadge } from './ml_model_type_badge'; export const DEFAULT_VALUES: InferencePipeline = { @@ -40,7 +40,7 @@ describe('InferencePipelineCard', () => { it('renders pipeline as title', () => { const wrapper = shallow(); expect(wrapper.find(EuiTitle)).toHaveLength(1); - const title = wrapper.find(EuiTitle).dive(); + const title = wrapper.find(EuiTitle).at(0).children(); expect(title.text()).toBe(DEFAULT_VALUES.pipelineName); }); it('renders pipeline as title with unknown model type', () => { @@ -51,14 +51,14 @@ describe('InferencePipelineCard', () => { const wrapper = shallow(); expect(wrapper.find(EuiTitle)).toHaveLength(1); // does not render subtitle - expect(wrapper.find(EuiTextColor)).toHaveLength(0); - const title = wrapper.find(EuiTitle).dive(); + expect(wrapper.find(EuiText)).toHaveLength(0); + const title = wrapper.find(EuiTitle).at(0).children(); expect(title.text()).toBe(DEFAULT_VALUES.pipelineName); }); it('renders model ID as subtitle', () => { const wrapper = shallow(); - expect(wrapper.find(EuiTextColor)).toHaveLength(1); - const subtitle = wrapper.find(EuiTextColor).dive(); + expect(wrapper.find(EuiText)).toHaveLength(1); + const subtitle = wrapper.find(EuiText).at(0).children(); expect(subtitle.text()).toBe(DEFAULT_VALUES.modelId); }); it('renders model type as badge', () => { @@ -67,20 +67,28 @@ describe('InferencePipelineCard', () => { const badge = wrapper.find(MLModelTypeBadge).render(); expect(badge.text()).toBe('ner'); }); - it('renders fix button when model not deployed', () => { +}); + +describe('TrainedModelHealthPopover', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(mockValues); + }); + it('popover renders fix button when model not deployed', () => { const values = { ...DEFAULT_VALUES, modelState: TrainedModelState.NotDeployed, }; - const wrapper = shallow(); - expect(wrapper.find(EuiButtonIcon)).toHaveLength(1); + const wrapper = shallow(); + expect(wrapper.find(EuiButtonEmpty)).toHaveLength(3); - const fixButton = wrapper.find(EuiButtonIcon); + const fixButton = wrapper.find(EuiButtonEmpty).at(0); expect(fixButton.prop('iconType')).toBe('wrench'); expect(fixButton.prop('href')).toBe('/app/ml/trained_models'); + expect(fixButton.children().text()).toBe('Fix issue in Trained Models'); }); - it('does not render fix button when model deployed', () => { - const wrapper = shallow(); - expect(wrapper.find(EuiButtonIcon)).toHaveLength(0); + it('popover does not render fix button when model deployed', () => { + const wrapper = shallow(); + expect(wrapper.find(EuiButtonEmpty)).toHaveLength(2); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx index dcc4b2a0cad8f..342d05c398878 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx @@ -11,16 +11,14 @@ import { useActions, useValues } from 'kea'; import { EuiButtonEmpty, - EuiButtonIcon, EuiConfirmModal, EuiFlexGroup, EuiFlexItem, EuiPanel, EuiPopover, EuiText, - EuiTextColor, EuiTitle, - EuiToolTip, + useIsWithinMaxBreakpoint, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -39,20 +37,18 @@ import { TrainedModelHealth } from './ml_model_health'; import { MLModelTypeBadge } from './ml_model_type_badge'; import { PipelinesLogic } from './pipelines_logic'; -export const InferencePipelineCard: React.FC = (pipeline) => { +export const TrainedModelHealthPopover: React.FC = (pipeline) => { const { http } = useValues(HttpLogic); const { indexName } = useValues(IndexNameLogic); const { ingestionMethod } = useValues(IndexViewLogic); + + const { deleteMlPipeline, detachMlPipeline } = useActions(PipelinesLogic); + const [isPopOverOpen, setIsPopOverOpen] = useState(false); const [showConfirmDelete, setShowConfirmDelete] = useState(false); - const { deleteMlPipeline, detachMlPipeline } = useActions(PipelinesLogic); - const showConfirmDeleteModal = () => { - setShowConfirmDelete(true); - setIsPopOverOpen(false); - }; - const { modelId, pipelineName, types: modelTypes } = pipeline; - const modelType = getMLType(modelTypes); - const modelTitle = getModelDisplayTitle(modelType); + + const { pipelineName } = pipeline; + const actionButton = ( = (pipeline) => ); + const showConfirmDeleteModal = () => { + setShowConfirmDelete(true); + setIsPopOverOpen(false); + }; + return ( - - - - + <> + setIsPopOverOpen(false)} + > + + {pipeline.modelState === TrainedModelState.NotDeployed && ( - - - - {pipelineName ?? modelTitle} - - - - - - {modelTitle && ( - - - - {modelId} - - - - - - - - - )} - - - - setIsPopOverOpen(false)} - > - {pipeline.modelState === TrainedModelState.NotDeployed && ( - - + + {i18n.translate( 'xpack.enterpriseSearch.inferencePipelineCard.modelState.notDeployed.fixLink', - { defaultMessage: 'Fix issue in Trained Models' } + { + defaultMessage: 'Fix issue in Trained Models', + } )} - > - - - - )} - - - - - {i18n.translate('xpack.enterpriseSearch.inferencePipelineCard.action.view', { - defaultMessage: 'View in Stack Management', - })} - - - - - - { - detachMlPipeline({ indexName, pipelineName }); - setIsPopOverOpen(false); - }} - > - {i18n.translate('xpack.enterpriseSearch.inferencePipelineCard.action.detach', { - defaultMessage: 'Detach pipeline', - })} - - - - - - - - - - - - + + + + )} + + + + {i18n.translate('xpack.enterpriseSearch.inferencePipelineCard.action.view', { + defaultMessage: 'View in Stack Management', + })} + + + + + + { + detachMlPipeline({ indexName, pipelineName }); + setIsPopOverOpen(false); + }} + > + {i18n.translate('xpack.enterpriseSearch.inferencePipelineCard.action.detach', { + defaultMessage: 'Detach pipeline', + })} + + + + + + + + + + {showConfirmDelete && ( = (pipeline) => )} + > + ); +}; + +export const InferencePipelineCard: React.FC = (pipeline) => { + const { modelId, pipelineName, types: modelTypes } = pipeline; + const modelType = getMLType(modelTypes); + const modelTitle = getModelDisplayTitle(modelType); + const isSmallScreen = useIsWithinMaxBreakpoint('s'); + + return ( + + + + + + + {pipelineName ?? modelTitle} + + + {modelTitle && ( + + + + + {modelId} + + + + + + + + + + )} + + + + + + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/pipeline_select_option.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/pipeline_select_option.tsx index deea940cfe68d..49e00f30c12d4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/pipeline_select_option.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/pipeline_select_option.tsx @@ -45,21 +45,21 @@ export const PipelineSelectOption: React.FC = ({ pipe // TODO: Add model state & pipeline info link. Make sure to check mobile rendering when doing this! - - {pipeline.pipelineName} + + {pipeline.pipelineName} - + {modelIdDisplay} {pipeline.modelType.length > 0 && ( - {/* Wrap in a div to prevent the badge from growing to a whole row on mobile*/} - + {/* Wrap in a span to prevent the badge from growing to a whole row on mobile*/} + - + )}