Skip to content
Snippets Groups Projects
Verified Commit 461f58f4 authored by Jackie Fraser's avatar Jackie Fraser :red_circle:
Browse files

Experiment: Add Upgrade option to user dropdown

Adds Upgrade option to the User Dropdown menu as part of a Growth
Experiment gitlab-org/growth/product#843
parent 161cf676
No related branches found
No related tags found
No related merge requests found
......@@ -74,20 +74,27 @@ function initStatusTriggers() {
}
}
function trackShowUserDropdownLink(trackEvent, elToTrack, el) {
const { trackLabel, trackProperty } = elToTrack.dataset;
$(el).on('shown.bs.dropdown', () => {
Tracking.event(document.body.dataset.page, trackEvent, {
label: trackLabel,
property: trackProperty,
});
});
}
export function initNavUserDropdownTracking() {
const el = document.querySelector('.js-nav-user-dropdown');
const buyEl = document.querySelector('.js-buy-ci-minutes-link');
const upgradeEl = document.querySelector('.js-upgrade-plan-link');
if (el && buyEl) {
const { trackLabel, trackProperty } = buyEl.dataset;
const trackEvent = 'show_buy_ci_minutes';
trackShowUserDropdownLink('show_buy_ci_minutes', buyEl, el);
}
$(el).on('shown.bs.dropdown', () => {
Tracking.event(undefined, trackEvent, {
label: trackLabel,
property: trackProperty,
});
});
if (el && upgradeEl) {
trackShowUserDropdownLink('show_upgrade_link', upgradeEl, el);
}
}
......
......@@ -553,6 +553,7 @@
vertical-align: text-top;
}
a.upgrade-plan-link gl-emoji,
a.ci-minutes-emoji gl-emoji,
a.trial-link gl-emoji {
font-size: $gl-font-size;
......
......@@ -106,6 +106,11 @@ def work_information(user)
end
end
# overwritten in EE
def show_upgrade_link?(user)
false
end
private
def get_profile_tabs
......
......@@ -27,6 +27,7 @@
%li
= link_to s_("CurrentUser|Settings"), profile_path, data: { qa_selector: 'settings_link' }
= render_if_exists 'layouts/header/buy_ci_minutes', project: @project, namespace: @group
= render_if_exists 'layouts/header/upgrade'
- if current_user_menu?(:help)
%li.divider.d-md-none
......
......@@ -20,6 +20,16 @@ def user_badges_in_admin_section(user)
end
end
def show_upgrade_link?(user)
return unless user
return unless ::Gitlab.com?
return unless experiment_enabled?(:upgrade_link_in_user_menu_a)
Rails.cache.fetch(['users', user.id, 'show_upgrade_link?'], expires_in: 10.minutes) do
user.owns_upgradeable_namespace?
end
end
private
def trials_allowed?(user)
......
......@@ -245,15 +245,15 @@ def has_paid_namespace?
::Namespace
.from("(#{namespace_union_for_reporter_developer_maintainer_owned}) #{::Namespace.table_name}")
.include_gitlab_subscription
.where(gitlab_subscriptions: { hosted_plan: ::Plan.where(name: Plan::PAID_HOSTED_PLANS) })
.where(gitlab_subscriptions: { hosted_plan: ::Plan.where(name: ::Plan::PAID_HOSTED_PLANS) })
.any?
end
def owns_paid_namespace?
def owns_paid_namespace?(plans: ::Plan::PAID_HOSTED_PLANS)
::Namespace
.from("(#{namespace_union_for_owned}) #{::Namespace.table_name}")
.include_gitlab_subscription
.where(gitlab_subscriptions: { hosted_plan: ::Plan.where(name: Plan::PAID_HOSTED_PLANS) })
.where(gitlab_subscriptions: { hosted_plan: ::Plan.where(name: plans) })
.any?
end
......@@ -363,6 +363,11 @@ def security_dashboard
InstanceSecurityDashboard.new(self)
end
def owns_upgradeable_namespace?
!owns_paid_namespace?(plans: [::Plan::GOLD]) &&
owns_paid_namespace?(plans: [::Plan::BRONZE, ::Plan::SILVER])
end
protected
override :password_required?
......
- if show_upgrade_link?(current_user)
%li
.upgrade-plan-link.js-upgrade-plan-link= link_to EE::SUBSCRIPTIONS_PLANS_URL,
data: { 'track-event': 'click_upgrade_link', 'track-label': current_user.namespace.actual_plan_name, 'track-property': 'user_dropdown' } do
= s_("CurrentUser|Upgrade")
= emoji_icon('rocket', 'aria-hidden': true)
......@@ -1177,4 +1177,89 @@
expect(security_dashboard).to be_a(InstanceSecurityDashboard)
end
end
describe '#owns_upgradeable_namespace?' do
let_it_be(:user) { create(:user) }
let_it_be(:free_plan) { create(:free_plan) }
let_it_be(:bronze_plan) { create(:bronze_plan) }
let_it_be(:silver_plan) { create(:silver_plan) }
let_it_be(:gold_plan) { create(:gold_plan) }
subject { user.upgradeable? }
context 'for an upgradeable user' do
it 'returns true when their personal namespace has a bronze subscription' do
create(:gitlab_subscription, namespace: user.namespace, hosted_plan: bronze_plan)
expect(subject).to be true
end
it 'returns true when their personal namespace has a silver subscription' do
create(:gitlab_subscription, namespace: user.namespace, hosted_plan: silver_plan)
expect(subject).to be true
end
it 'returns true when the user owns a group with bronze' do
create(:group_with_plan, plan: :bronze_plan).add_owner(user)
expect(subject).to be true
end
it 'returns true when the user owns a group with silver' do
create(:group_with_plan, plan: :silver_plan).add_owner(user)
expect(subject).to be true
end
it 'returns true when the user owns groups with both bronze and silver' do
create(:group_with_plan, plan: :bronze_plan).add_owner(user)
create(:group_with_plan, plan: :silver_plan).add_owner(user)
user.namespace.plans.reload
expect(subject).to be true
end
end
context 'for a non-upgradeable user' do
it 'returns false when the user namespace subscription is a gold hosted_plan' do
create(:gitlab_subscription, namespace: user.namespace, hosted_plan: gold_plan)
user.reload
expect(subject).to be false
end
it 'returns false when the personal namespace is free' do
create(:gitlab_subscription, namespace: user.namespace, hosted_plan: free_plan)
user.reload
expect(subject).to be false
end
it 'returns false when the personal namespace is non-existant' do
expect(subject).to be false
end
it 'returns false when the user has a group with gold' do
create(:group_with_plan, plan: :gold_plan).add_owner(user)
user.reload
expect(subject).to be false
end
it 'returns false when the user has multiple groups and any group has gold' do
create(:group_with_plan, plan: :bronze_plan).add_owner(user)
create(:group_with_plan, plan: :silver_plan).add_owner(user)
create(:group_with_plan, plan: :gold_plan).add_owner(user)
user.reload
expect(subject).to be false
end
end
end
end
......@@ -4,31 +4,63 @@
describe 'layouts/header/_current_user_dropdown' do
let_it_be(:user) { create(:user) }
let(:need_minutes) { true }
before do
allow(view).to receive(:current_user).and_return(user)
allow(view).to receive(:show_buy_ci_minutes?).and_return(need_minutes)
describe 'Buy CI Minutes link in user dropdown' do
let(:need_minutes) { true }
render
end
before do
allow(view).to receive(:current_user).and_return(user)
allow(view).to receive(:show_upgrade_link?).and_return(false)
allow(view).to receive(:show_buy_ci_minutes?).and_return(need_minutes)
render
end
subject { rendered }
subject { rendered }
context 'when ci minutes need bought' do
it 'has "Buy CI minutes" link with correct data properties', :aggregate_failures do
expect(subject).to have_selector('[data-track-event="click_buy_ci_minutes"]')
expect(subject).to have_selector("[data-track-label='#{user.namespace.actual_plan_name}']")
expect(subject).to have_selector('[data-track-property="user_dropdown"]')
expect(subject).to have_link('Buy CI minutes')
context 'when ci minutes need bought' do
it 'has "Buy CI minutes" link with correct data properties', :aggregate_failures do
expect(subject).to have_selector('[data-track-event="click_buy_ci_minutes"]')
expect(subject).to have_selector("[data-track-label='#{user.namespace.actual_plan_name}']")
expect(subject).to have_selector('[data-track-property="user_dropdown"]')
expect(subject).to have_link('Buy CI minutes')
end
end
context 'when ci minutes do not need bought' do
let(:need_minutes) { false }
it 'has no "Buy CI minutes" link' do
expect(subject).not_to have_link('Buy CI minutes')
end
end
end
context 'when ci minutes do not need bought' do
let(:need_minutes) { false }
describe 'Upgrade link in user dropdown' do
let(:on_upgradeable_plan) { true }
before do
allow(view).to receive(:current_user).and_return(user)
allow(view).to receive(:show_buy_ci_minutes?).and_return(false)
allow(view).to receive(:show_upgrade_link?).and_return(on_upgradeable_plan)
render
end
subject { rendered }
context 'when user is on an upgradeable plan' do
it 'displays the Upgrade link' do
expect(subject).to have_link('Upgrade')
end
end
context 'when user is not on an upgradeable plan' do
let(:on_upgradeable_plan) { false }
it 'has no "Buy CI minutes" link' do
expect(subject).not_to have_link('Buy CI minutes')
it 'does not display the Upgrade link' do
expect(subject).not_to have_link('Upgrade')
end
end
end
end
......@@ -33,6 +33,9 @@ module Experimentation
},
buy_ci_minutes_version_a: {
tracking_category: 'Growth::Expansion::Experiment::BuyCiMinutesVersionA'
},
upgrade_link_in_user_menu_a: {
tracking_category: 'Growth::Expansion::Experiment::UpgradeLinkInUserMenuA'
}
}.freeze
......
......@@ -6384,6 +6384,9 @@ msgstr ""
msgid "CurrentUser|Start a Gold trial"
msgstr ""
 
msgid "CurrentUser|Upgrade"
msgstr ""
msgid "Custom CI configuration path"
msgstr ""
 
......
......@@ -61,6 +61,7 @@ describe('Header', () => {
setFixtures(`
<li class="js-nav-user-dropdown">
<a class="js-buy-ci-minutes-link" data-track-event="click_buy_ci_minutes" data-track-label="free" data-track-property="user_dropdown">Buy CI minutes
<a class="js-upgrade-plan-link" data-track-event="click_upgrade_link" data-track-label="free" data-track-property="user_dropdown">Upgrade
</a>
</li>`);
......@@ -77,8 +78,16 @@ describe('Header', () => {
it('sends a tracking event when the dropdown is opened and contains Buy CI minutes link', () => {
$('.js-nav-user-dropdown').trigger('shown.bs.dropdown');
expect(trackingSpy).toHaveBeenCalledTimes(1);
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'show_buy_ci_minutes', {
expect(trackingSpy).toHaveBeenCalledWith('some:page', 'show_buy_ci_minutes', {
label: 'free',
property: 'user_dropdown',
});
});
it('sends a tracking event when the dropdown is opened and contains Upgrade link', () => {
$('.js-nav-user-dropdown').trigger('shown.bs.dropdown');
expect(trackingSpy).toHaveBeenCalledWith('some:page', 'show_upgrade_link', {
label: 'free',
property: 'user_dropdown',
});
......
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