Commit ccdbd919 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch 'onboarding-experiment-popovers' into 'master'

Onboarding experiment popovers

Closes gitlab-org/growth/engineering#5364

See merge request gitlab-org/gitlab!33194
parents e4ed3ee7 e2847d64
......@@ -12,6 +12,8 @@ import itemStats from './item_stats.vue';
import itemStatsValue from './item_stats_value.vue';
import itemActions from './item_actions.vue';
import { showLearnGitLabGroupItemPopover } from '~/onboarding_issues';
export default {
directives: {
tooltip,
......@@ -73,6 +75,11 @@ export default {
return GROUP_VISIBILITY_TYPE[this.group.visibility];
},
},
mounted() {
if (this.group.name === 'Learn GitLab') {
showLearnGitLabGroupItemPopover(this.group.id);
}
},
methods: {
onClickRowGroup(e) {
const NO_EXPAND_CLS = 'no-expand';
......
import $ from 'jquery';
import { parseBoolean, getCookie, setCookie, removeCookie } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
const COOKIE_NAME = 'onboarding_issues_settings';
const POPOVER_LOCATIONS = {
GROUPS_SHOW: 'groups#show',
PROJECTS_SHOW: 'projects#show',
ISSUES_INDEX: 'issues#index',
};
const removeLearnGitLabCookie = () => {
removeCookie(COOKIE_NAME);
};
function disposePopover(event) {
event.preventDefault();
this.popover('dispose');
removeLearnGitLabCookie();
}
const showPopover = (el, path, footer, options) => {
// Cookie value looks like `{ 'groups#show': true, 'projects#show': true, 'issues#index': true }`. When it doesn't exist, don't show the popover.
const cookie = getCookie(COOKIE_NAME);
if (!cookie) return;
// When the popover action has already been taken, don't show the popover.
const settings = JSON.parse(cookie);
if (!parseBoolean(settings[path])) return;
const defaultOptions = {
boundary: 'window',
html: true,
placement: 'top',
template: `<div class="popover blue learn-gitlab d-none d-xl-block" role="tooltip">
<div class="arrow"></div>
<div class="close cursor-pointer gl-font-base text-white gl-opacity-10 p-2">&#10005</div>
<div class="popover-body gl-font-base gl-line-height-20 pb-0 px-3"></div>
<div class="bold text-right text-white p-2">${footer}</div>
</div>`,
};
// When one of the popovers is dismissed, remove the cookie.
const closeButton = () => document.querySelector('.learn-gitlab.popover .close');
// We still have to use jQuery, since Bootstrap's Popover is based on jQuery.
const jQueryEl = $(el);
const clickCloseButton = disposePopover.bind(jQueryEl);
jQueryEl
.popover({ ...defaultOptions, ...options })
.on('inserted.bs.popover', () => closeButton().addEventListener('click', clickCloseButton))
.on('hide.bs.dropdown', () => closeButton().removeEventListener('click', clickCloseButton))
.popover('show');
// The previous popover actions have been taken, don't show those popovers anymore.
Object.keys(settings).forEach(pathSetting => {
if (path !== pathSetting) {
settings[pathSetting] = false;
} else {
setCookie(COOKIE_NAME, settings);
}
});
// The final popover action will be taken on click, we then no longer need the cookie.
if (path === POPOVER_LOCATIONS.ISSUES_INDEX) {
el.addEventListener('click', removeLearnGitLabCookie);
}
};
export const showLearnGitLabGroupItemPopover = id => {
const el = document.querySelector(`#group-${id} .group-text a`);
if (!el) return;
const options = {
content: __(
'Here are all your projects in your group, including the one you just created. To start, let’s take a look at your personalized learning project which will help you learn about GitLab at your own pace.',
),
};
showPopover(el, POPOVER_LOCATIONS.GROUPS_SHOW, '1 / 2', options);
};
export const showLearnGitLabProjectPopover = () => {
// Do not show a popover if we are not viewing the 'Learn GitLab' project.
if (!window.location.pathname.includes('learn-gitlab')) return;
const el = document.querySelector('a.shortcuts-issues');
if (!el) return;
const options = {
content: __(
'Go to <strong>Issues</strong> > <strong>Boards</strong> to access your personalized learning issue board.',
),
};
showPopover(el, POPOVER_LOCATIONS.PROJECTS_SHOW, '2 / 2', options);
};
export const showLearnGitLabIssuesPopover = () => {
// Do not show a popover if we are not viewing the 'Learn GitLab' project.
if (!window.location.pathname.includes('learn-gitlab')) return;
const el = document.querySelector('a[data-qa-selector="issue_boards_link"]');
if (!el) return;
const options = {
content: __(
'Go to <strong>Issues</strong> > <strong>Boards</strong> to access your personalized learning issue board.',
),
};
showPopover(el, POPOVER_LOCATIONS.ISSUES_INDEX, '2 / 2', options);
};
......@@ -9,6 +9,7 @@ import { FILTERED_SEARCH } from '~/pages/constants';
import { ISSUABLE_INDEX } from '~/pages/projects/constants';
import initIssuablesList from '~/issuables_list';
import initManualOrdering from '~/manual_ordering';
import { showLearnGitLabIssuesPopover } from '~/onboarding_issues';
document.addEventListener('DOMContentLoaded', () => {
IssuableFilteredSearchTokenKeys.addExtraTokensForIssues();
......@@ -24,4 +25,5 @@ document.addEventListener('DOMContentLoaded', () => {
initManualOrdering();
initIssuablesList();
showLearnGitLabIssuesPopover();
});
......@@ -15,6 +15,7 @@ import leaveByUrl from '~/namespaces/leave_by_url';
import Star from '../../../star';
import notificationsDropdown from '../../../notifications_dropdown';
import initNamespaceStorageLimitAlert from '~/namespace_storage_limit_alert';
import { showLearnGitLabProjectPopover } from '~/onboarding_issues';
document.addEventListener('DOMContentLoaded', () => {
initReadMore();
......@@ -59,4 +60,6 @@ document.addEventListener('DOMContentLoaded', () => {
throw e;
});
}
showLearnGitLabProjectPopover();
});
......@@ -10766,6 +10766,9 @@ msgstr ""
msgid "Go to %{link_to_google_takeout}."
msgstr ""
msgid "Go to <strong>Issues</strong> > <strong>Boards</strong> to access your personalized learning issue board."
msgstr ""
msgid "Go to Pipelines"
msgstr ""
......@@ -11501,6 +11504,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths"
msgstr ""
msgid "Here are all your projects in your group, including the one you just created. To start, let’s take a look at your personalized learning project which will help you learn about GitLab at your own pace."
msgstr ""
msgid "Here you will find recent merge request activity"
msgstr ""
......
import $ from 'jquery';
import { showLearnGitLabIssuesPopover } from '~/onboarding_issues';
import { getCookie, setCookie, removeCookie } from '~/lib/utils/common_utils';
import setWindowLocation from 'helpers/set_window_location_helper';
describe('Onboarding Issues Popovers', () => {
const COOKIE_NAME = 'onboarding_issues_settings';
const getCookieValue = () => JSON.parse(getCookie(COOKIE_NAME));
beforeEach(() => {
jest.spyOn($.fn, 'popover');
});
afterEach(() => {
$.fn.popover.mockRestore();
document.getElementsByTagName('html')[0].innerHTML = '';
removeCookie(COOKIE_NAME);
});
const setupShowLearnGitLabIssuesPopoverTest = ({
currentPath = 'group/learn-gitlab',
isIssuesBoardsLinkShown = true,
isCookieSet = true,
cookieValue = true,
} = {}) => {
setWindowLocation(`http://example.com/${currentPath}`);
if (isIssuesBoardsLinkShown) {
const elem = document.createElement('a');
elem.setAttribute('data-qa-selector', 'issue_boards_link');
document.body.appendChild(elem);
}
if (isCookieSet) {
setCookie(COOKIE_NAME, { previous: true, 'issues#index': cookieValue });
}
showLearnGitLabIssuesPopover();
};
describe('showLearnGitLabIssuesPopover', () => {
describe('when on another project', () => {
beforeEach(() => {
setupShowLearnGitLabIssuesPopoverTest({
currentPath: 'group/another-project',
});
});
it('does not show a popover', () => {
expect($.fn.popover).not.toHaveBeenCalled();
});
});
describe('when the issues boards link is not shown', () => {
beforeEach(() => {
setupShowLearnGitLabIssuesPopoverTest({
isIssuesBoardsLinkShown: false,
});
});
it('does not show a popover', () => {
expect($.fn.popover).not.toHaveBeenCalled();
});
});
describe('when the cookie is not set', () => {
beforeEach(() => {
setupShowLearnGitLabIssuesPopoverTest({
isCookieSet: false,
});
});
it('does not show a popover', () => {
expect($.fn.popover).not.toHaveBeenCalled();
});
});
describe('when the cookie value is false', () => {
beforeEach(() => {
setupShowLearnGitLabIssuesPopoverTest({
cookieValue: false,
});
});
it('does not show a popover', () => {
expect($.fn.popover).not.toHaveBeenCalled();
});
});
describe('with all the right conditions', () => {
beforeEach(() => {
setupShowLearnGitLabIssuesPopoverTest();
});
it('shows a popover', () => {
expect($.fn.popover).toHaveBeenCalled();
});
it('does not change the cookie value', () => {
expect(getCookieValue()['issues#index']).toBe(true);
});
it('disables the previous popover', () => {
expect(getCookieValue().previous).toBe(false);
});
describe('when clicking the issues boards link', () => {
beforeEach(() => {
document.querySelector('a[data-qa-selector="issue_boards_link"]').click();
});
it('deletes the cookie', () => {
expect(getCookie(COOKIE_NAME)).toBe(undefined);
});
});
describe('when dismissing the popover', () => {
beforeEach(() => {
document.querySelector('.learn-gitlab.popover .close').click();
});
it('deletes the cookie', () => {
expect(getCookie(COOKIE_NAME)).toBe(undefined);
});
});
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment