Skip to content
代码片段 群组 项目
未验证 提交 6bfba418 编辑于 作者: Alper Akgun's avatar Alper Akgun 提交者: GitLab
浏览文件

Merge branch '508887-model-experiments-add-button-to-mlflow-usage-example' into 'master'

Model Experiments: Add menu item to MLflow usage example

See merge request https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175813



Merged-by: default avatarAlper Akgun <aakgun@gitlab.com>
Approved-by: default avatarAndras Herczeg <aherczeg@gitlab.com>
Approved-by: default avatarVitaly Slobodin <vslobodin@gitlab.com>
Approved-by: default avatarEduardo Bonet <ebonet@gitlab.com>
Reviewed-by: default avatarAlper Akgun <aakgun@gitlab.com>
No related branches found
No related tags found
无相关合并请求
显示
140 个添加32 个删除
<script>
import { GlBadge } from '@gitlab/ui';
import { __ } from '~/locale';
import {
GlBadge,
GlDisclosureDropdown,
GlDisclosureDropdownGroup,
GlDisclosureDropdownItem,
GlModalDirective,
} from '@gitlab/ui';
import { __, s__ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import PageHeading from '~/vue_shared/components/page_heading.vue';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import { MLFLOW_USAGE_MODAL_ID } from '../routes/experiments/index/constants';
import MlflowModal from '../routes/experiments/index/components/mlflow_usage_modal.vue';
export default {
components: {
GlBadge,
PageHeading,
GlDisclosureDropdown,
GlDisclosureDropdownGroup,
GlDisclosureDropdownItem,
MlflowModal,
TitleArea,
},
directives: {
GlModal: GlModalDirective,
},
props: {
pageTitle: {
type: String,
required: true,
},
hideMlflowUsage: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
mlflowUsageModalItem() {
return {
text: this.$options.i18n.importMlflow,
};
},
},
i18n: {
experimentBadgeLabel: __('Experiment'),
createTitle: s__('MlModelRegistry|Create'),
importMlflow: s__('MlModelRegistry|Create experiments using MLflow'),
},
experimentDocHref: helpPagePath('user/project/ml/experiment_tracking/index.md'),
mlflowModalId: MLFLOW_USAGE_MODAL_ID,
};
</script>
<template>
<page-heading>
<template #heading>
<span class="gl-inline-flex gl-items-center gl-gap-3">
{{ pageTitle }}
<gl-badge variant="info" :href="$options.experimentDocHref">
{{ $options.i18n.experimentBadgeLabel }}
</gl-badge>
<slot></slot>
</span>
<title-area>
<template #title>
<div class="gl-flex gl-grow gl-items-center">
<span class="gl-inline-flex gl-items-center gl-gap-3" data-testid="page-heading">
{{ pageTitle }}
<gl-badge variant="info" :href="$options.experimentDocHref">
{{ $options.i18n.experimentBadgeLabel }}
</gl-badge>
<slot></slot>
</span>
</div>
</template>
<template #right-actions>
<gl-disclosure-dropdown
v-if="!hideMlflowUsage"
:toggle-text="$options.i18n.createTitle"
toggle-class="gl-w-full"
data-testid="create-dropdown"
variant="confirm"
category="primary"
placement="bottom-end"
>
<gl-disclosure-dropdown-group>
<gl-disclosure-dropdown-item
v-gl-modal="$options.mlflowModalId"
data-testid="create-menu-item"
:item="mlflowUsageModalItem"
/>
</gl-disclosure-dropdown-group>
<mlflow-modal />
</gl-disclosure-dropdown>
</template>
</page-heading>
</title-area>
</template>
......@@ -35,7 +35,7 @@ export default {
<template>
<div>
<model-experiments-header :page-title="$options.i18n.TITLE_LABEL">
<model-experiments-header :page-title="$options.i18n.TITLE_LABEL" hide-mlflow-usage>
<delete-button
:delete-path="info.path"
:delete-confirmation-text="$options.i18n.DELETE_CANDIDATE_CONFIRMATION_MESSAGE"
......
......@@ -6,7 +6,6 @@ import * as translations from '~/ml/experiment_tracking/routes/experiments/index
import ModelExperimentsHeader from '~/ml/experiment_tracking/components/model_experiments_header.vue';
import Pagination from '~/ml/experiment_tracking/components/pagination.vue';
import { MLFLOW_USAGE_MODAL_ID } from '../constants';
import MlflowModal from './mlflow_usage_modal.vue';
export default {
name: 'MlExperimentsIndexApp',
......@@ -17,7 +16,6 @@ export default {
GlEmptyState,
GlLink,
GlButton,
MlflowModal,
},
directives: {
GlModal: GlModalDirective,
......@@ -93,12 +91,14 @@ export default {
class="gl-py-8"
>
<template #actions>
<gl-button v-gl-modal="$options.mlflowModalId" class="gl-mx-2 gl-mb-3 gl-mr-3">
<gl-button
v-gl-modal="$options.mlflowModalId"
data-testid="empty-create-using-button"
class="gl-mx-2 gl-mb-3 gl-mr-3"
>
{{ $options.i18n.CREATE_USING_MLFLOW_LABEL }}
</gl-button>
</template>
</gl-empty-state>
<mlflow-modal />
</div>
</template>
......@@ -31,6 +31,11 @@ export default {
DeleteButton,
PerformanceGraph,
},
provide() {
return {
mlflowTrackingUrl: this.mlflowTrackingUrl,
};
},
props: {
experiment: {
type: Object,
......@@ -56,6 +61,11 @@ export default {
type: String,
required: true,
},
mlflowTrackingUrl: {
type: String,
required: false,
default: '',
},
},
data() {
const query = queryToObject(window.location.search);
......
......@@ -8,7 +8,15 @@ const initShowExperiment = () => {
return undefined;
}
const { experiment, candidates, metrics, params, pageInfo, emptyStateSvgPath } = element.dataset;
const {
experiment,
candidates,
metrics,
params,
pageInfo,
emptyStateSvgPath,
mlflowTrackingUrl,
} = element.dataset;
const props = {
experiment: JSON.parse(experiment),
......@@ -17,6 +25,7 @@ const initShowExperiment = () => {
paramNames: JSON.parse(params),
pageInfo: convertObjectPropsToCamelCase(JSON.parse(pageInfo)),
emptyStateSvgPath,
mlflowTrackingUrl,
};
return new Vue({
......
......@@ -16,4 +16,5 @@
params: params,
page_info: page_info,
empty_state_svg_path: image_path('illustrations/status/status-new-md.svg'),
mlflow_tracking_url: mlflow_tracking_url(@project),
} }
......@@ -35352,6 +35352,9 @@ msgstr ""
msgid "MlModelRegistry|Create & import"
msgstr ""
 
msgid "MlModelRegistry|Create experiments using MLflow"
msgstr ""
msgid "MlModelRegistry|Create model"
msgstr ""
 
import { GlBadge } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ModelExperimentsHeader from '~/ml/experiment_tracking/components/model_experiments_header.vue';
import PageHeading from '~/vue_shared/components/page_heading.vue';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
describe('ml/experiment_tracking/components/model_experiments_header.vue', () => {
let wrapper;
const createWrapper = () => {
const createWrapper = ({ propsData = {} } = {}) => {
wrapper = shallowMountExtended(ModelExperimentsHeader, {
propsData: { pageTitle: 'Some Title' },
propsData: { pageTitle: 'Some Title', ...propsData },
slots: {
default: 'Slot content',
},
stubs: {
PageHeading,
},
});
};
......@@ -22,11 +19,39 @@ describe('ml/experiment_tracking/components/model_experiments_header.vue', () =>
const findBadge = () => wrapper.findComponent(GlBadge);
const findTitle = () => wrapper.findByTestId('page-heading');
const findTitleArea = () => wrapper.findComponent(TitleArea);
const findDropdown = () => wrapper.findByTestId('create-dropdown');
const findMenuItem = () => wrapper.findByTestId('create-menu-item');
it('title area exists', () => {
expect(findTitleArea().exists()).toBe(true);
});
it('renders title', () => {
it('title is set', () => {
expect(findTitle().text()).toContain('Some Title');
});
it('dropdown exists', () => {
expect(findDropdown().props()).toMatchObject({
toggleText: 'Create',
variant: 'confirm',
category: 'primary',
});
});
it('dropdown is hidden when hideMlflowUsage is true', () => {
createWrapper({ propsData: { hideMlflowUsage: true } });
expect(findDropdown().exists()).toBe(false);
});
it('a menu item for creating experiments exist', () => {
expect(findMenuItem().props()).toMatchObject({
item: {
text: 'Create experiments using MLflow',
},
});
});
it('link points to documentation', () => {
expect(findBadge().attributes().href).toBe(
'/help/user/project/ml/experiment_tracking/index.md',
......
import { GlEmptyState, GlLink, GlTableLite, GlButton } from '@gitlab/ui';
import { GlEmptyState, GlLink, GlTableLite } from '@gitlab/ui';
import MlExperimentsIndexApp from '~/ml/experiment_tracking/routes/experiments/index';
import ModelExperimentsHeader from '~/ml/experiment_tracking/components/model_experiments_header.vue';
import { mountExtended } from 'helpers/vue_test_utils_helper';
......@@ -33,8 +33,7 @@ const findColumnInRow = (row, col) => findNthTableRow(row).findAll('td').at(col)
const hrefInRowAndColumn = (row, col) =>
findColumnInRow(row, col).findComponent(GlLink).attributes().href;
const findTitleHeader = () => wrapper.findComponent(ModelExperimentsHeader);
const findDocsButton = () => wrapper.findAllComponents(GlButton).at(0);
const findDocsButton = () => wrapper.findByTestId('empty-create-using-button');
describe('MlExperimentsIndex', () => {
describe('empty state', () => {
......
......@@ -26,10 +26,19 @@ describe('MlExperimentsShow', () => {
pageInfo = MOCK_PAGE_INFO,
experiment = MOCK_EXPERIMENT,
emptyStateSvgPath = 'path',
mlflowTrackingUrl = 'mlflow/tracking/url',
// eslint-disable-next-line max-params
) => {
wrapper = mount(MlExperimentsShow, {
propsData: { experiment, candidates, metricNames, paramNames, pageInfo, emptyStateSvgPath },
propsData: {
experiment,
candidates,
metricNames,
paramNames,
pageInfo,
emptyStateSvgPath,
mlflowTrackingUrl,
},
});
};
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册