mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[ML] Fix Trained Model stats and pipelines tab (#125382)
This commit is contained in:
parent
f1fcbe7f54
commit
67fb388acd
4 changed files with 285 additions and 131 deletions
|
@ -18,6 +18,7 @@ import {
|
|||
EuiSpacer,
|
||||
EuiTabbedContent,
|
||||
EuiTitle,
|
||||
EuiTabbedContentTab,
|
||||
} from '@elastic/eui';
|
||||
import type { EuiDescriptionListProps } from '@elastic/eui/src/components/description_list/description_list';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
@ -151,9 +152,10 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
|
|||
[stats.deployment_stats]
|
||||
);
|
||||
|
||||
const tabs = [
|
||||
const tabs: EuiTabbedContentTab[] = [
|
||||
{
|
||||
id: 'details',
|
||||
'data-test-subj': 'mlTrainedModelDetails',
|
||||
name: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.trainedModels.modelsList.expandedRow.detailsTabLabel"
|
||||
|
@ -161,7 +163,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
|
|||
/>
|
||||
),
|
||||
content: (
|
||||
<>
|
||||
<div data-test-subj={'mlTrainedModelDetailsContent'}>
|
||||
<EuiSpacer size={'s'} />
|
||||
<EuiFlexGrid columns={2} gutterSize={'m'}>
|
||||
<EuiFlexItem>
|
||||
|
@ -203,13 +205,14 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
|
|||
</EuiFlexItem>
|
||||
) : null}
|
||||
</EuiFlexGrid>
|
||||
</>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
...(inferenceConfig
|
||||
? [
|
||||
{
|
||||
id: 'config',
|
||||
'data-test-subj': 'mlTrainedModelInferenceConfig',
|
||||
name: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.trainedModels.modelsList.expandedRow.configTabLabel"
|
||||
|
@ -217,7 +220,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
|
|||
/>
|
||||
),
|
||||
content: (
|
||||
<>
|
||||
<div data-test-subj={'mlTrainedModelInferenceConfigContent'}>
|
||||
<EuiSpacer size={'s'} />
|
||||
<EuiFlexGrid columns={2} gutterSize={'m'}>
|
||||
<EuiFlexItem>
|
||||
|
@ -261,7 +264,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
|
|||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGrid>
|
||||
</>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
@ -270,6 +273,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
|
|||
? [
|
||||
{
|
||||
id: 'stats',
|
||||
'data-test-subj': 'mlTrainedModelStats',
|
||||
name: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.trainedModels.modelsList.expandedRow.statsTabLabel"
|
||||
|
@ -277,7 +281,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
|
|||
/>
|
||||
),
|
||||
content: (
|
||||
<>
|
||||
<div data-test-subj={'mlTrainedModelStatsContent'}>
|
||||
<EuiSpacer size={'s'} />
|
||||
|
||||
<EuiFlexGrid columns={2} gutterSize={'m'}>
|
||||
|
@ -317,8 +321,29 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
|
|||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
{isPopulatedObject(stats.model_size_stats) &&
|
||||
!isPopulatedObject(stats.inference_stats) ? (
|
||||
<EuiFlexItem>
|
||||
<EuiPanel>
|
||||
<EuiTitle size={'xs'}>
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.trainedModels.modelsList.expandedRow.modelSizeStatsTitle"
|
||||
defaultMessage="Model size stats"
|
||||
/>
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size={'m'} />
|
||||
<EuiDescriptionList
|
||||
compressed={true}
|
||||
type="column"
|
||||
listItems={formatToListItems(stats.model_size_stats)}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
</EuiFlexGrid>
|
||||
</>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
@ -327,6 +352,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
|
|||
? [
|
||||
{
|
||||
id: 'pipelines',
|
||||
'data-test-subj': 'mlTrainedModelPipelines',
|
||||
name: (
|
||||
<>
|
||||
<FormattedMessage
|
||||
|
@ -337,10 +363,10 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
|
|||
</>
|
||||
),
|
||||
content: (
|
||||
<>
|
||||
<div data-test-subj={'mlTrainedModelPipelinesContent'}>
|
||||
<EuiSpacer size={'s'} />
|
||||
<ModelPipelines pipelines={pipelines!} ingestStats={stats.ingest} />
|
||||
</>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
@ -355,6 +381,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => {
|
|||
initialSelectedTab={tabs[0]}
|
||||
autoFocus="selected"
|
||||
onTabClick={(tab) => {}}
|
||||
data-test-subj={'mlTrainedModelRowDetails'}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -23,7 +23,7 @@ import { ProcessorsStats } from './expanded_row';
|
|||
export type IngestStatsResponse = Exclude<ModelItem['stats'], undefined>['ingest'];
|
||||
|
||||
interface ModelPipelinesProps {
|
||||
pipelines: Exclude<ModelItem['pipelines'], null | undefined>;
|
||||
pipelines: ModelItem['pipelines'];
|
||||
ingestStats: IngestStatsResponse;
|
||||
}
|
||||
|
||||
|
@ -32,11 +32,18 @@ export const ModelPipelines: FC<ModelPipelinesProps> = ({ pipelines, ingestStats
|
|||
services: { share },
|
||||
} = useMlKibana();
|
||||
|
||||
const pipelineNames = Object.keys(pipelines ?? ingestStats?.pipelines ?? {});
|
||||
|
||||
if (!pipelineNames.length) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
{Object.entries(pipelines).map(([pipelineName, pipelineDefinition], i) => {
|
||||
{pipelineNames.map((pipelineName, i) => {
|
||||
// Expand first 3 pipelines by default
|
||||
const initialIsOpen = i <= 2;
|
||||
|
||||
const pipelineDefinition = pipelines?.[pipelineName];
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiAccordion
|
||||
|
@ -48,31 +55,34 @@ export const ModelPipelines: FC<ModelPipelinesProps> = ({ pipelines, ingestStats
|
|||
</EuiTitle>
|
||||
}
|
||||
extraAction={
|
||||
<EuiButtonEmpty
|
||||
onClick={() => {
|
||||
const locator = share.url.locators.get('INGEST_PIPELINES_APP_LOCATOR');
|
||||
if (!locator) return;
|
||||
locator.navigate({
|
||||
page: 'pipeline_edit',
|
||||
pipelineId: pipelineName,
|
||||
absolute: true,
|
||||
});
|
||||
}}
|
||||
iconType={'documentEdit'}
|
||||
iconSide="left"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.trainedModels.modelsList.expandedRow.editPipelineLabel"
|
||||
defaultMessage="Edit"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
pipelineDefinition ? (
|
||||
<EuiButtonEmpty
|
||||
data-test-subj={`mlTrainedModelPipelineEditButton_${pipelineName}`}
|
||||
onClick={() => {
|
||||
const locator = share.url.locators.get('INGEST_PIPELINES_APP_LOCATOR');
|
||||
if (!locator) return;
|
||||
locator.navigate({
|
||||
page: 'pipeline_edit',
|
||||
pipelineId: pipelineName,
|
||||
absolute: true,
|
||||
});
|
||||
}}
|
||||
iconType={'documentEdit'}
|
||||
iconSide="left"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.trainedModels.modelsList.expandedRow.editPipelineLabel"
|
||||
defaultMessage="Edit"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
) : undefined
|
||||
}
|
||||
paddingSize="l"
|
||||
initialIsOpen={initialIsOpen}
|
||||
>
|
||||
<EuiFlexGrid columns={2}>
|
||||
{ingestStats?.pipelines ? (
|
||||
<EuiFlexItem>
|
||||
<EuiFlexItem data-test-subj={`mlTrainedModelPipelineIngestStats_${pipelineName}`}>
|
||||
<EuiPanel>
|
||||
<EuiTitle size={'xxs'}>
|
||||
<h6>
|
||||
|
@ -88,27 +98,29 @@ export const ModelPipelines: FC<ModelPipelinesProps> = ({ pipelines, ingestStats
|
|||
</EuiFlexItem>
|
||||
) : null}
|
||||
|
||||
<EuiFlexItem>
|
||||
<EuiPanel>
|
||||
<EuiTitle size={'xxs'}>
|
||||
<h6>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.trainedModels.modelsList.expandedRow.processorsTitle"
|
||||
defaultMessage="Definition"
|
||||
/>
|
||||
</h6>
|
||||
</EuiTitle>
|
||||
<EuiCodeBlock
|
||||
language="json"
|
||||
fontSize="m"
|
||||
paddingSize="m"
|
||||
overflowHeight={300}
|
||||
isCopyable
|
||||
>
|
||||
{JSON.stringify(pipelineDefinition, null, 2)}
|
||||
</EuiCodeBlock>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
{pipelineDefinition ? (
|
||||
<EuiFlexItem data-test-subj={`mlTrainedModelPipelineDefinition_${pipelineName}`}>
|
||||
<EuiPanel>
|
||||
<EuiTitle size={'xxs'}>
|
||||
<h6>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.trainedModels.modelsList.expandedRow.processorsTitle"
|
||||
defaultMessage="Definition"
|
||||
/>
|
||||
</h6>
|
||||
</EuiTitle>
|
||||
<EuiCodeBlock
|
||||
language="json"
|
||||
fontSize="m"
|
||||
paddingSize="m"
|
||||
overflowHeight={300}
|
||||
isCopyable
|
||||
>
|
||||
{JSON.stringify(pipelineDefinition, null, 2)}
|
||||
</EuiCodeBlock>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
</EuiFlexGrid>
|
||||
</EuiAccordion>
|
||||
</>
|
||||
|
|
|
@ -42,96 +42,152 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
modelTypes: ['regression', 'tree_ensemble'],
|
||||
};
|
||||
|
||||
it('renders trained models list', async () => {
|
||||
await ml.testExecution.logTestStep(
|
||||
'should display the stats bar with the total number of models'
|
||||
);
|
||||
// +1 because of the built-in model
|
||||
await ml.trainedModels.assertStats(31);
|
||||
|
||||
await ml.testExecution.logTestStep('should display the table');
|
||||
await ml.trainedModels.assertTableExists();
|
||||
await ml.trainedModels.assertRowsNumberPerPage(10);
|
||||
});
|
||||
|
||||
it('displays the built-in model and no actions are enabled', async () => {
|
||||
await ml.testExecution.logTestStep('should display the model in the table');
|
||||
await ml.trainedModelsTable.filterWithSearchString(builtInModelData.modelId, 1);
|
||||
|
||||
await ml.testExecution.logTestStep('displays expected row values for the model in the table');
|
||||
await ml.trainedModelsTable.assertModelsRowFields(builtInModelData.modelId, {
|
||||
id: builtInModelData.modelId,
|
||||
description: builtInModelData.description,
|
||||
modelTypes: builtInModelData.modelTypes,
|
||||
describe('for ML power user', () => {
|
||||
before(async () => {
|
||||
await ml.securityUI.loginAsMlPowerUser();
|
||||
await ml.navigation.navigateToTrainedModels();
|
||||
});
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
'should not show collapsed actions menu for the model in the table'
|
||||
);
|
||||
await ml.trainedModelsTable.assertModelCollapsedActionsButtonExists(
|
||||
builtInModelData.modelId,
|
||||
false
|
||||
);
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
'should not show delete action for the model in the table'
|
||||
);
|
||||
await ml.trainedModelsTable.assertModelDeleteActionButtonExists(
|
||||
builtInModelData.modelId,
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it('displays a model with an ingest pipeline and delete action is disabled', async () => {
|
||||
await ml.testExecution.logTestStep('should display the model in the table');
|
||||
await ml.trainedModelsTable.filterWithSearchString(modelWithPipelineData.modelId, 1);
|
||||
|
||||
await ml.testExecution.logTestStep('displays expected row values for the model in the table');
|
||||
await ml.trainedModelsTable.assertModelsRowFields(modelWithPipelineData.modelId, {
|
||||
id: modelWithPipelineData.modelId,
|
||||
description: modelWithPipelineData.description,
|
||||
modelTypes: modelWithPipelineData.modelTypes,
|
||||
after(async () => {
|
||||
await ml.securityUI.logout();
|
||||
});
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
'should show disabled delete action for the model in the table'
|
||||
);
|
||||
it('renders trained models list', async () => {
|
||||
await ml.testExecution.logTestStep(
|
||||
'should display the stats bar with the total number of models'
|
||||
);
|
||||
// +1 because of the built-in model
|
||||
await ml.trainedModels.assertStats(31);
|
||||
|
||||
await ml.trainedModelsTable.assertModelDeleteActionButtonEnabled(
|
||||
modelWithPipelineData.modelId,
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it('displays a model without an ingest pipeline and model can be deleted', async () => {
|
||||
await ml.testExecution.logTestStep('should display the model in the table');
|
||||
await ml.trainedModelsTable.filterWithSearchString(modelWithoutPipelineData.modelId, 1);
|
||||
|
||||
await ml.testExecution.logTestStep('displays expected row values for the model in the table');
|
||||
await ml.trainedModelsTable.assertModelsRowFields(modelWithoutPipelineData.modelId, {
|
||||
id: modelWithoutPipelineData.modelId,
|
||||
description: modelWithoutPipelineData.description,
|
||||
modelTypes: modelWithoutPipelineData.modelTypes,
|
||||
await ml.testExecution.logTestStep('should display the table');
|
||||
await ml.trainedModels.assertTableExists();
|
||||
await ml.trainedModels.assertRowsNumberPerPage(10);
|
||||
});
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
'should show enabled delete action for the model in the table'
|
||||
);
|
||||
it('renders expanded row content correctly for model with pipelines', async () => {
|
||||
await ml.trainedModelsTable.ensureRowIsExpanded(modelWithPipelineData.modelId);
|
||||
await ml.trainedModelsTable.assertDetailsTabContent();
|
||||
await ml.trainedModelsTable.assertInferenceConfigTabContent();
|
||||
await ml.trainedModelsTable.assertStatsTabContent();
|
||||
await ml.trainedModelsTable.assertPipelinesTabContent(true, [
|
||||
{ pipelineName: `pipeline_${modelWithPipelineData.modelId}`, expectDefinition: true },
|
||||
]);
|
||||
});
|
||||
|
||||
await ml.trainedModelsTable.assertModelDeleteActionButtonEnabled(
|
||||
modelWithoutPipelineData.modelId,
|
||||
true
|
||||
);
|
||||
it('renders expanded row content correctly for model without pipelines', async () => {
|
||||
await ml.trainedModelsTable.ensureRowIsExpanded(modelWithoutPipelineData.modelId);
|
||||
await ml.trainedModelsTable.assertDetailsTabContent();
|
||||
await ml.trainedModelsTable.assertInferenceConfigTabContent();
|
||||
await ml.trainedModelsTable.assertStatsTabContent();
|
||||
await ml.trainedModelsTable.assertPipelinesTabContent(false);
|
||||
});
|
||||
|
||||
await ml.testExecution.logTestStep('should show the delete modal');
|
||||
await ml.trainedModelsTable.clickDeleteAction(modelWithoutPipelineData.modelId);
|
||||
it('displays the built-in model and no actions are enabled', async () => {
|
||||
await ml.testExecution.logTestStep('should display the model in the table');
|
||||
await ml.trainedModelsTable.filterWithSearchString(builtInModelData.modelId, 1);
|
||||
|
||||
await ml.testExecution.logTestStep('should delete the model');
|
||||
await ml.trainedModelsTable.confirmDeleteModel();
|
||||
await ml.trainedModelsTable.assertModelDisplayedInTable(
|
||||
modelWithoutPipelineData.modelId,
|
||||
false
|
||||
);
|
||||
await ml.testExecution.logTestStep(
|
||||
'displays expected row values for the model in the table'
|
||||
);
|
||||
await ml.trainedModelsTable.assertModelsRowFields(builtInModelData.modelId, {
|
||||
id: builtInModelData.modelId,
|
||||
description: builtInModelData.description,
|
||||
modelTypes: builtInModelData.modelTypes,
|
||||
});
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
'should not show collapsed actions menu for the model in the table'
|
||||
);
|
||||
await ml.trainedModelsTable.assertModelCollapsedActionsButtonExists(
|
||||
builtInModelData.modelId,
|
||||
false
|
||||
);
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
'should not show delete action for the model in the table'
|
||||
);
|
||||
await ml.trainedModelsTable.assertModelDeleteActionButtonExists(
|
||||
builtInModelData.modelId,
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it('displays a model with an ingest pipeline and delete action is disabled', async () => {
|
||||
await ml.testExecution.logTestStep('should display the model in the table');
|
||||
await ml.trainedModelsTable.filterWithSearchString(modelWithPipelineData.modelId, 1);
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
'displays expected row values for the model in the table'
|
||||
);
|
||||
await ml.trainedModelsTable.assertModelsRowFields(modelWithPipelineData.modelId, {
|
||||
id: modelWithPipelineData.modelId,
|
||||
description: modelWithPipelineData.description,
|
||||
modelTypes: modelWithPipelineData.modelTypes,
|
||||
});
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
'should show disabled delete action for the model in the table'
|
||||
);
|
||||
|
||||
await ml.trainedModelsTable.assertModelDeleteActionButtonEnabled(
|
||||
modelWithPipelineData.modelId,
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it('displays a model without an ingest pipeline and model can be deleted', async () => {
|
||||
await ml.testExecution.logTestStep('should display the model in the table');
|
||||
await ml.trainedModelsTable.filterWithSearchString(modelWithoutPipelineData.modelId, 1);
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
'displays expected row values for the model in the table'
|
||||
);
|
||||
await ml.trainedModelsTable.assertModelsRowFields(modelWithoutPipelineData.modelId, {
|
||||
id: modelWithoutPipelineData.modelId,
|
||||
description: modelWithoutPipelineData.description,
|
||||
modelTypes: modelWithoutPipelineData.modelTypes,
|
||||
});
|
||||
|
||||
await ml.testExecution.logTestStep(
|
||||
'should show enabled delete action for the model in the table'
|
||||
);
|
||||
|
||||
await ml.trainedModelsTable.assertModelDeleteActionButtonEnabled(
|
||||
modelWithoutPipelineData.modelId,
|
||||
true
|
||||
);
|
||||
|
||||
await ml.testExecution.logTestStep('should show the delete modal');
|
||||
await ml.trainedModelsTable.clickDeleteAction(modelWithoutPipelineData.modelId);
|
||||
|
||||
await ml.testExecution.logTestStep('should delete the model');
|
||||
await ml.trainedModelsTable.confirmDeleteModel();
|
||||
await ml.trainedModelsTable.assertModelDisplayedInTable(
|
||||
modelWithoutPipelineData.modelId,
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('for ML user with read-only access', () => {
|
||||
before(async () => {
|
||||
await ml.securityUI.loginAsMlViewer();
|
||||
await ml.navigation.navigateToTrainedModels();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await ml.securityUI.logout();
|
||||
});
|
||||
|
||||
it('renders expanded row content correctly for model with pipelines', async () => {
|
||||
await ml.trainedModelsTable.ensureRowIsExpanded(modelWithPipelineData.modelId);
|
||||
await ml.trainedModelsTable.assertDetailsTabContent();
|
||||
await ml.trainedModelsTable.assertInferenceConfigTabContent();
|
||||
await ml.trainedModelsTable.assertStatsTabContent();
|
||||
await ml.trainedModelsTable.assertPipelinesTabContent(true, [
|
||||
{ pipelineName: `pipeline_${modelWithPipelineData.modelId}`, expectDefinition: false },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import expect from '@kbn/expect';
|
||||
import { ProvidedType } from '@kbn/test';
|
||||
import { upperFirst } from 'lodash';
|
||||
|
||||
import { WebElementWrapper } from 'test/functional/services/lib/web_element_wrapper';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
@ -208,5 +209,63 @@ export function TrainedModelsTableProvider({ getService }: FtrProviderContext) {
|
|||
await testSubjects.click(this.rowSelector(modelId, 'mlModelsTableRowDeleteAction'));
|
||||
await this.assertDeleteModalExists();
|
||||
}
|
||||
|
||||
public async ensureRowIsExpanded(modelId: string) {
|
||||
await this.filterWithSearchString(modelId);
|
||||
await retry.tryForTime(10 * 1000, async () => {
|
||||
if (!(await testSubjects.exists('mlTrainedModelRowDetails'))) {
|
||||
await testSubjects.click(`${this.rowSelector(modelId)} > mlModelsTableRowDetailsToggle`);
|
||||
await testSubjects.existOrFail('mlTrainedModelRowDetails', { timeout: 1000 });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async assertTabContent(
|
||||
type: 'details' | 'stats' | 'inferenceConfig' | 'pipelines',
|
||||
expectVisible = true
|
||||
) {
|
||||
const tabTestSubj = `mlTrainedModel${upperFirst(type)}`;
|
||||
const tabContentTestSubj = `mlTrainedModel${upperFirst(type)}Content`;
|
||||
|
||||
if (!expectVisible) {
|
||||
await testSubjects.missingOrFail(tabTestSubj);
|
||||
return;
|
||||
}
|
||||
|
||||
await testSubjects.existOrFail(tabTestSubj);
|
||||
await testSubjects.click(tabTestSubj);
|
||||
await testSubjects.existOrFail(tabContentTestSubj);
|
||||
}
|
||||
|
||||
public async assertDetailsTabContent(expectVisible = true) {
|
||||
await this.assertTabContent('details', expectVisible);
|
||||
}
|
||||
|
||||
public async assertInferenceConfigTabContent(expectVisible = true) {
|
||||
await this.assertTabContent('inferenceConfig', expectVisible);
|
||||
}
|
||||
|
||||
public async assertStatsTabContent(expectVisible = true) {
|
||||
await this.assertTabContent('stats', expectVisible);
|
||||
}
|
||||
|
||||
public async assertPipelinesTabContent(
|
||||
expectVisible = true,
|
||||
pipelinesExpectOptions?: Array<{ pipelineName: string; expectDefinition: boolean }>
|
||||
) {
|
||||
await this.assertTabContent('pipelines', expectVisible);
|
||||
|
||||
if (Array.isArray(pipelinesExpectOptions)) {
|
||||
for (const p of pipelinesExpectOptions) {
|
||||
if (p.expectDefinition) {
|
||||
await testSubjects.existOrFail(`mlTrainedModelPipelineEditButton_${p.pipelineName}`);
|
||||
await testSubjects.existOrFail(`mlTrainedModelPipelineDefinition_${p.pipelineName}`);
|
||||
} else {
|
||||
await testSubjects.missingOrFail(`mlTrainedModelPipelineEditButton_${p.pipelineName}`);
|
||||
await testSubjects.missingOrFail(`mlTrainedModelPipelineDefinition_${p.pipelineName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue