From aba18a4f5cc87731d11eb494c43023445e48d1ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Enrique=20Alc=C3=A1ntara?= <ealcantara@gitlab.com>
Date: Wed, 23 Dec 2020 13:43:51 +0000
Subject: [PATCH] Define GlTooltips feature flag

Allow gl-emoji tags in the tooltip HTML mode
Do not init tooltips with empty titles
---
 .../javascripts/tooltips/components/tooltips.vue       |  8 ++++++--
 app/assets/javascripts/tooltips/index.js               |  2 +-
 config/feature_flags/development/gl_tooltips.yml       |  8 ++++++++
 lib/gitlab/gon_helper.rb                               |  1 +
 spec/frontend/tooltips/components/tooltips_spec.js     | 10 ++++++++++
 spec/frontend/tooltips/index_spec.js                   |  4 ++--
 6 files changed, 28 insertions(+), 5 deletions(-)
 create mode 100644 config/feature_flags/development/gl_tooltips.yml

diff --git a/app/assets/javascripts/tooltips/components/tooltips.vue b/app/assets/javascripts/tooltips/components/tooltips.vue
index 05927006ea61d..15fc84368b2cd 100644
--- a/app/assets/javascripts/tooltips/components/tooltips.vue
+++ b/app/assets/javascripts/tooltips/components/tooltips.vue
@@ -50,7 +50,8 @@ export default {
     addTooltips(elements, config) {
       const newTooltips = elements
         .filter(element => !this.tooltipExists(element))
-        .map(element => newTooltip(element, config));
+        .map(element => newTooltip(element, config))
+        .filter(tooltip => tooltip.title);
 
       newTooltips.forEach(tooltip => this.observe(tooltip));
 
@@ -93,6 +94,9 @@ export default {
       return this.tooltips.find(tooltip => tooltip.target === element);
     },
   },
+  safeHtmlConfig: {
+    ADD_TAGS: ['gl-emoji'],
+  },
 };
 </script>
 <template>
@@ -110,7 +114,7 @@ export default {
       :disabled="tooltip.disabled"
       :show="tooltip.show"
     >
-      <span v-if="tooltip.html" v-safe-html="tooltip.title"></span>
+      <span v-if="tooltip.html" v-safe-html:[$options.safeHtmlConfig]="tooltip.title"></span>
       <span v-else>{{ tooltip.title }}</span>
     </gl-tooltip>
   </div>
diff --git a/app/assets/javascripts/tooltips/index.js b/app/assets/javascripts/tooltips/index.js
index f7cad6639ae65..335925aec5fd5 100644
--- a/app/assets/javascripts/tooltips/index.js
+++ b/app/assets/javascripts/tooltips/index.js
@@ -68,7 +68,7 @@ const invokeBootstrapApi = (elements, method) => {
   }
 };
 
-const isGlTooltipsEnabled = () => Boolean(window.gon.glTooltipsEnabled);
+const isGlTooltipsEnabled = () => Boolean(window.gon.features?.glTooltips);
 
 const tooltipApiInvoker = ({ glHandler, bsHandler }) => (elements, ...params) => {
   if (isGlTooltipsEnabled()) {
diff --git a/config/feature_flags/development/gl_tooltips.yml b/config/feature_flags/development/gl_tooltips.yml
new file mode 100644
index 0000000000000..22c67019c338c
--- /dev/null
+++ b/config/feature_flags/development/gl_tooltips.yml
@@ -0,0 +1,8 @@
+---
+name: gl_tooltips
+introduced_by_url: 
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/292972
+milestone: '13.8'
+type: development
+group: group::editor
+default_enabled: false
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index 362da8ea53e48..10e8f00874d50 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -48,6 +48,7 @@ def add_gon_variables
       push_frontend_feature_flag(:snippets_binary_blob, default_enabled: false)
       push_frontend_feature_flag(:usage_data_api, default_enabled: true)
       push_frontend_feature_flag(:security_auto_fix, default_enabled: false)
+      push_frontend_feature_flag(:gl_tooltips, default_enabled: :yaml)
 
       # Startup CSS feature is a special one as it can be enabled by means of cookies and params
       gon.push({ features: { 'startupCss' => use_startup_css? } }, true)
diff --git a/spec/frontend/tooltips/components/tooltips_spec.js b/spec/frontend/tooltips/components/tooltips_spec.js
index 50848ca2978ff..0b8c76db11d9c 100644
--- a/spec/frontend/tooltips/components/tooltips_spec.js
+++ b/spec/frontend/tooltips/components/tooltips_spec.js
@@ -51,6 +51,16 @@ describe('tooltips/components/tooltips.vue', () => {
       expect(wrapper.find(GlTooltip).props('target')).toBe(target);
     });
 
+    it('does not attach a tooltip to a target with empty title', async () => {
+      target.setAttribute('title', '');
+
+      wrapper.vm.addTooltips([target]);
+
+      await wrapper.vm.$nextTick();
+
+      expect(wrapper.find(GlTooltip).exists()).toBe(false);
+    });
+
     it('does not attach a tooltip twice to the same element', async () => {
       wrapper.vm.addTooltips([target]);
       wrapper.vm.addTooltips([target]);
diff --git a/spec/frontend/tooltips/index_spec.js b/spec/frontend/tooltips/index_spec.js
index 511003fdb8f4c..86da1caab3ee3 100644
--- a/spec/frontend/tooltips/index_spec.js
+++ b/spec/frontend/tooltips/index_spec.js
@@ -42,7 +42,7 @@ describe('tooltips/index.js', () => {
   };
 
   beforeEach(() => {
-    window.gon.glTooltipsEnabled = true;
+    window.gon.features = { glTooltips: true };
   });
 
   afterEach(() => {
@@ -149,7 +149,7 @@ describe('tooltips/index.js', () => {
 
   describe('when glTooltipsEnabled feature flag is disabled', () => {
     beforeEach(() => {
-      window.gon.glTooltipsEnabled = false;
+      window.gon.features.glTooltips = false;
     });
 
     it.each`
-- 
GitLab