Skip to content
Snippets Groups Projects
Unverified Commit ede6224e authored by Enrique Alcántara's avatar Enrique Alcántara
Browse files

Migrate feature highlight to Vue

Re-implements the feature highlight popover feature
using Vue instead of vanilla javascript and HAML
parent 15c87e7c
No related branches found
No related tags found
No related merge requests found
export const POPOVER_TARGET_ID = 'feature-highlight-trigger';
<script>
import {
GlPopover,
GlSprintf,
GlLink,
GlButton,
GlSafeHtmlDirective as SafeHtml,
} from '@gitlab/ui';
import clusterPopover from '@gitlab/svgs/dist/illustrations/cluster_popover.svg';
import { dismiss } from './feature_highlight_helper';
import { POPOVER_TARGET_ID } from './constants';
export default {
components: {
GlPopover,
GlSprintf,
GlLink,
GlButton,
},
directives: {
SafeHtml,
},
props: {
autoDevopsHelpPath: {
type: String,
required: true,
},
highlightId: {
type: String,
required: true,
},
dismissEndpoint: {
type: String,
required: true,
},
},
data() {
return {
dismissed: false,
triggerHidden: false,
};
},
methods: {
async dismiss() {
dismiss(this.dismissEndpoint, this.highlightId);
this.$refs.popover.$emit('close');
this.dismissed = true;
},
hideTrigger() {
if (this.dismissed) {
this.triggerHidden = true;
}
},
},
clusterPopover,
targetId: POPOVER_TARGET_ID,
};
</script>
<template>
<span class="gl-ml-3">
<span v-if="!triggerHidden" :id="$options.targetId" class="feature-highlight"></span>
<gl-popover
ref="popover"
:target="$options.targetId"
:css-classes="['feature-highlight-popover']"
triggers="hover"
container="body"
placement="right"
boundary="viewport"
@hidden="hideTrigger"
>
<!-- eslint-disable-next-line @gitlab/vue-require-i18n-attribute-strings -->
<span
v-safe-html="$options.clusterPopover"
class="feature-highlight-illustration gl-display-flex gl-justify-content-center gl-py-4 gl-w-full"
></span>
<div class="gl-px-4 gl-py-5">
<p>
{{ __('Allows you to add and manage Kubernetes clusters.') }}
</p>
<p>
<gl-sprintf
:message="
__(
'Protip: %{linkStart}Auto DevOps%{linkEnd} uses Kubernetes clusters to deploy your code!',
)
"
>
<template #link="{ content }">
<gl-link class="gl-font-sm" :href="autoDevopsHelpPath">{{ content }}</gl-link>
</template>
</gl-sprintf>
</p>
<hr />
<gl-button size="small" icon="thumb-up" variant="success" @click="dismiss">
{{ __('Got it!') }}
</gl-button>
</div>
</gl-popover>
</span>
</template>
import Vue from 'vue';
const init = async () => {
const el = document.querySelector('.js-feature-highlight');
if (!el) {
return null;
}
const { autoDevopsHelpPath, highlight: highlightId, dismissEndpoint } = el.dataset;
const { default: FeatureHighlight } = await import(
/* webpackChunkName: 'feature_highlight' */ './feature_highlight_popover.vue'
);
return new Vue({
el,
render: (h) =>
h(FeatureHighlight, {
props: {
autoDevopsHelpPath,
highlightId,
dismissEndpoint,
},
}),
});
};
export default init;
Loading
Loading
@@ -23775,6 +23775,9 @@ msgstr ""
msgid "Protip:"
msgstr ""
 
msgid "Protip: %{linkStart}Auto DevOps%{linkEnd} uses Kubernetes clusters to deploy your code!"
msgstr ""
msgid "Protocol"
msgstr ""
 
Loading
Loading
Loading
Loading
@@ -38,7 +38,9 @@ jest.mock('@gitlab/ui/dist/components/base/popover/popover.js', () => ({
required: false,
default: () => [],
},
...Object.fromEntries(['target', 'triggers', 'placement'].map((prop) => [prop, {}])),
...Object.fromEntries(
['target', 'triggers', 'placement', 'boundary', 'container'].map((prop) => [prop, {}]),
),
},
render(h) {
return h(
Loading
Loading
import { mount } from '@vue/test-utils';
import { GlPopover, GlLink, GlButton } from '@gitlab/ui';
import FeatureHighlightPopover from '~/feature_highlight/feature_highlight_popover.vue';
import { dismiss } from '~/feature_highlight/feature_highlight_helper';
import { POPOVER_TARGET_ID } from '~/feature_highlight/constants';
jest.mock('~/feature_highlight/feature_highlight_helper');
describe('feature_highlight/feature_highlight_popover', () => {
let wrapper;
const props = {
autoDevopsHelpPath: '/help/autodevops',
highlightId: '123',
dismissEndpoint: '/api/dismiss',
};
const buildWrapper = (propsData = props) => {
wrapper = mount(FeatureHighlightPopover, {
propsData,
});
};
const findPopoverTarget = () => wrapper.find(`#${POPOVER_TARGET_ID}`);
const findPopover = () => wrapper.findComponent(GlPopover);
const findAutodevopsHelpLink = () => wrapper.findComponent(GlLink);
const findDismissButton = () => wrapper.findComponent(GlButton);
beforeEach(() => {
buildWrapper();
});
afterEach(() => {
wrapper.destroy();
});
it('renders popover target', () => {
expect(findPopoverTarget().exists()).toBe(true);
});
it('renders popover', () => {
expect(findPopover().props()).toMatchObject({
target: POPOVER_TARGET_ID,
cssClasses: ['feature-highlight-popover'],
triggers: 'hover',
container: 'body',
placement: 'right',
boundary: 'viewport',
});
});
it('renders link that points to the autodevops help page', () => {
expect(findAutodevopsHelpLink().attributes().href).toBe(props.autoDevopsHelpPath);
expect(findAutodevopsHelpLink().text()).toBe('Auto DevOps');
});
it('renders dismiss button', () => {
expect(findDismissButton().props()).toMatchObject({
size: 'small',
icon: 'thumb-up',
variant: 'success',
});
});
it('dismisses popover when dismiss button is clicked', () => {
findDismissButton().vm.$emit('click');
expect(findPopover().emitted('close')).toHaveLength(1);
expect(dismiss).toHaveBeenCalledWith(props.dismissEndpoint, props.highlightId);
});
describe('when popover is dismissed and hidden', () => {
it('hides the popover target', async () => {
findDismissButton().vm.$emit('click');
await wrapper.vm.$nextTick();
findPopover().vm.$emit('hidden');
await wrapper.vm.$nextTick();
expect(findPopoverTarget().exists()).toBe(false);
});
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment