From cf4046fa83d03710c65263f0b482ec4c565a0c9d Mon Sep 17 00:00:00 2001
From: fdegier <fdegier@gitlab.com>
Date: Tue, 3 Dec 2024 11:27:10 +0100
Subject: [PATCH] Model registry: Add Experiment to model card

Changelog: added

# Conflicts:
#	app/assets/javascripts/ml/model_registry/apps/show_ml_model.vue
---
 .../ml/model_registry/apps/show_ml_model.vue  | 18 +++++++++++++++
 .../graphql/queries/get_model.query.graphql   |  1 +
 locale/gitlab.pot                             |  3 +++
 .../model_registry/apps/show_ml_model_spec.js | 23 +++++++++++++++++++
 .../ml/model_registry/graphql_mock_data.js    |  2 ++
 5 files changed, 47 insertions(+)

diff --git a/app/assets/javascripts/ml/model_registry/apps/show_ml_model.vue b/app/assets/javascripts/ml/model_registry/apps/show_ml_model.vue
index 4f77d9c481768..afb877f2107f6 100644
--- a/app/assets/javascripts/ml/model_registry/apps/show_ml_model.vue
+++ b/app/assets/javascripts/ml/model_registry/apps/show_ml_model.vue
@@ -186,6 +186,9 @@ export default {
     showModelLatestVersion() {
       return Boolean(this.model?.latestVersion);
     },
+    showDefaultExperiment() {
+      return this.model?.defaultExperimentPath;
+    },
   },
   methods: {
     goTo(name) {
@@ -220,6 +223,8 @@ export default {
     latestVersionTitle: s__('MlModelRegistry|Latest version'),
     authorTitle: s__('MlModelRegistry|Publisher'),
     noneText: __('None'),
+    experimentTitle: s__('MlModelRegistry|Experiment'),
+    defaultExperimentPath: s__('MlModelRegistry|Default experiment'),
   },
   modelVersionEntity: MODEL_ENTITIES.modelVersion,
   ROUTE_DETAILS,
@@ -326,6 +331,19 @@ export default {
                 <span v-else>{{ $options.i18n.noneText }}</span>
               </div>
             </div>
+            <div v-if="showDefaultExperiment" class="gl-mt-5">
+              <div class="gl-text-lg gl-font-bold" data-testid="sidebar-experiment-title">
+                {{ $options.i18n.experimentTitle }}
+              </div>
+              <div class="gl-pt-2 gl-text-subtle" data-testid="sidebar-experiment-label">
+                <gl-link
+                  data-testid="sidebar-latest-experiment-link"
+                  :href="model.defaultExperimentPath"
+                >
+                  {{ $options.i18n.defaultExperimentPath }}
+                </gl-link>
+              </div>
+            </div>
             <div class="gl-mt-5">
               <div class="gl-text-lg gl-font-bold">{{ $options.i18n.latestVersionTitle }}</div>
               <div class="gl-pt-2 gl-text-subtle" data-testid="sidebar-latest-version">
diff --git a/app/assets/javascripts/ml/model_registry/graphql/queries/get_model.query.graphql b/app/assets/javascripts/ml/model_registry/graphql/queries/get_model.query.graphql
index 06dcfeecb5c1a..4d6b1683204c8 100644
--- a/app/assets/javascripts/ml/model_registry/graphql/queries/get_model.query.graphql
+++ b/app/assets/javascripts/ml/model_registry/graphql/queries/get_model.query.graphql
@@ -13,6 +13,7 @@ query getModel($id: MlModelID!) {
     name
     versionCount
     candidateCount
+    defaultExperimentPath
     latestVersion {
       id
       createdAt
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 4f36ec83756b4..1d02c2cbd42e6 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -35319,6 +35319,9 @@ msgstr ""
 msgid "MlModelRegistry|Creating models, model versions and candidates is also possible using the MLflow client:"
 msgstr ""
 
+msgid "MlModelRegistry|Default experiment"
+msgstr ""
+
 msgid "MlModelRegistry|Delete model"
 msgstr ""
 
diff --git a/spec/frontend/ml/model_registry/apps/show_ml_model_spec.js b/spec/frontend/ml/model_registry/apps/show_ml_model_spec.js
index d9374c03d042b..89e2998a44df8 100644
--- a/spec/frontend/ml/model_registry/apps/show_ml_model_spec.js
+++ b/spec/frontend/ml/model_registry/apps/show_ml_model_spec.js
@@ -359,6 +359,8 @@ describe('ml/model_registry/apps/show_ml_model', () => {
     const findAvatar = () => wrapper.findComponent(GlAvatar);
     const findLatestVersionLink = () => wrapper.findByTestId('sidebar-latest-version-link');
     const findVersionCount = () => wrapper.findByTestId('sidebar-version-count');
+    const findExperimentTitle = () => wrapper.findByTestId('sidebar-experiment-title');
+    const findExperiment = () => wrapper.findByTestId('sidebar-experiment-label');
 
     it('displays sidebar author link', () => {
       expect(findSidebarAuthorLink().attributes('href')).toBe('path/to/user');
@@ -388,6 +390,22 @@ describe('ml/model_registry/apps/show_ml_model', () => {
       expect(findVersionCount().text()).toBe('1');
     });
 
+    describe('displays experiment information', () => {
+      it('displays experiment title', () => {
+        expect(findExperimentTitle().text()).toBe('Experiment');
+      });
+
+      it('displays experiment label', () => {
+        expect(findExperiment().text()).toBe('Default experiment');
+      });
+
+      it('shows a link to the default experiment', () => {
+        expect(findExperiment().findComponent(GlLink).attributes('href')).toBe(
+          'path/to/experiment',
+        );
+      });
+    });
+
     describe('when model does not get loaded', () => {
       const error = new Error('Failure!');
       beforeEach(() => createWrapper({ modelDetailsResolver: jest.fn().mockRejectedValue(error) }));
@@ -403,6 +421,11 @@ describe('ml/model_registry/apps/show_ml_model', () => {
       it('does not display sidebar version count', () => {
         expect(findVersionCount().text()).toBe('None');
       });
+
+      it('does not display sidebar experiment information', () => {
+        expect(findExperimentTitle().exists()).toBe(false);
+        expect(findExperiment().exists()).toBe(false);
+      });
     });
   });
 });
diff --git a/spec/frontend/ml/model_registry/graphql_mock_data.js b/spec/frontend/ml/model_registry/graphql_mock_data.js
index 299990666491f..ea0c16323910b 100644
--- a/spec/frontend/ml/model_registry/graphql_mock_data.js
+++ b/spec/frontend/ml/model_registry/graphql_mock_data.js
@@ -392,6 +392,7 @@ export const model = {
     avatarUrl: 'path/to/avatar',
     webUrl: 'path/to/user',
   },
+  defaultExperimentPath: 'path/to/experiment',
   description: 'A model description',
   descriptionHtml: 'A model description',
   name: 'gitlab_amazing_model',
@@ -408,6 +409,7 @@ export const modelWithNoVersion = {
   createdAt: '2023-12-06T12:41:48Z',
   description: 'A model description',
   descriptionHtml: 'A model description',
+  defaultExperimentPath: 'path/to/experiment',
   author: {
     id: 'gid://gitlab/User/1',
     name: 'name',
-- 
GitLab