Commit 72b97b20 authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch 'led/345373-move-pipeline-usage-quota-to-vue' into 'master'

PipelinesUsageApp: Buy Additional Minutes button

See merge request gitlab-org/gitlab!83021
parents 7cc9c5a2 f6392723
...@@ -232,35 +232,40 @@ export const trackTransaction = (transactionDetails) => { ...@@ -232,35 +232,40 @@ export const trackTransaction = (transactionDetails) => {
pushEnhancedEcommerceEvent('EECtransactionSuccess', eventData); pushEnhancedEcommerceEvent('EECtransactionSuccess', eventData);
}; };
export const trackAddToCartUsageTab = () => { export const pushEECproductAddToCartEvent = () => {
if (!isSupported()) { if (!isSupported()) {
return; return;
} }
const getStartedButton = document.querySelector('.js-buy-additional-minutes'); window.dataLayer.push({
getStartedButton.addEventListener('click', () => { event: 'EECproductAddToCart',
window.dataLayer.push({ ecommerce: {
event: 'EECproductAddToCart', currencyCode: 'USD',
ecommerce: { add: {
currencyCode: 'USD', products: [
add: { {
products: [ name: 'CI/CD Minutes',
{ id: '0003',
name: 'CI/CD Minutes', price: '10',
id: '0003', brand: 'GitLab',
price: '10', category: 'DevOps',
brand: 'GitLab', variant: 'add-on',
category: 'DevOps', quantity: 1,
variant: 'add-on', },
quantity: 1, ],
},
],
},
}, },
}); },
}); });
}; };
export const trackAddToCartUsageTab = () => {
const getStartedButton = document.querySelector('.js-buy-additional-minutes');
if (!getStartedButton) {
return;
}
getStartedButton.addEventListener('click', pushEECproductAddToCartEvent);
};
export const trackCombinedGroupProjectForm = () => { export const trackCombinedGroupProjectForm = () => {
if (!isSupported()) { if (!isSupported()) {
return; return;
......
...@@ -88,6 +88,15 @@ module NamespacesHelper ...@@ -88,6 +88,15 @@ module NamespacesHelper
}.to_json }.to_json
end end
def pipeline_usage_quota_app_data(namespace)
{
namespace_actual_plan_name: namespace.actual_plan_name,
namespace_path: namespace.full_path,
namespace_id: namespace.id,
page_size: page_size
}
end
private private
# Many importers create a temporary Group, so use the real # Many importers create a temporary Group, so use the real
......
<script>
import { GlButton } from '@gitlab/ui';
import { pushEECproductAddToCartEvent } from '~/google_tag_manager';
import { LABEL_BUY_ADDITIONAL_MINUTES } from '../constants';
export default {
name: 'PipelineUsageApp',
components: { GlButton },
inject: ['namespaceActualPlanName', 'buyAdditionalMinutesPath', 'buyAdditionalMinutesTarget'],
methods: {
trackBuyAdditionalMinutesClick() {
pushEECproductAddToCartEvent();
},
},
LABEL_BUY_ADDITIONAL_MINUTES,
};
</script>
<template>
<div>
<div
v-if="buyAdditionalMinutesPath && buyAdditionalMinutesTarget"
class="gl-display-flex gl-justify-content-end"
>
<gl-button
:href="buyAdditionalMinutesPath"
:target="buyAdditionalMinutesTarget"
:data-track-label="namespaceActualPlanName"
data-track-action="click_buy_ci_minutes"
data-track-property="pipeline_quota_page"
data-testid="buy-additional-minutes-button"
category="primary"
variant="confirm"
@click="trackBuyAdditionalMinutesClick"
>
{{ $options.LABEL_BUY_ADDITIONAL_MINUTES }}
</gl-button>
</div>
</div>
</template>
import { s__ } from '~/locale';
export const LABEL_BUY_ADDITIONAL_MINUTES = s__('UsageQuota|Buy additional minutes');
import Vue from 'vue';
import PipelineUsageApp from './components/app.vue';
export default () => {
const el = document.getElementById('js-pipeline-usage-app');
if (!el) {
return false;
}
const {
namespaceActualPlanName,
buyAdditionalMinutesPath,
buyAdditionalMinutesTarget,
} = el.dataset;
return new Vue({
el,
name: 'PipelinesUsageView',
provide: {
namespaceActualPlanName,
buyAdditionalMinutesPath,
buyAdditionalMinutesTarget,
},
render(createElement) {
return createElement(PipelineUsageApp);
},
});
};
...@@ -67,6 +67,16 @@ module EE ...@@ -67,6 +67,16 @@ module EE
namespace.root_ancestor.free_plan? && !minute_limit_banner_dismissed? namespace.root_ancestor.free_plan? && !minute_limit_banner_dismissed?
end end
override :pipeline_usage_quota_app_data
def pipeline_usage_quota_app_data(namespace)
return super unless ::Gitlab::CurrentSettings.should_check_namespace_plan?
super.merge(
buy_additional_minutes_path: buy_additional_minutes_path(namespace),
buy_additional_minutes_target: buy_addon_target_attr(namespace)
)
end
private private
def use_customers_dot_for_addon_path?(namespace) def use_customers_dot_for_addon_path?(namespace)
......
import { GlButton } from '@gitlab/ui';
import { pushEECproductAddToCartEvent } from '~/google_tag_manager';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import PipelineUsageApp from 'ee/usage_quotas/pipelines/components/app.vue';
import { LABEL_BUY_ADDITIONAL_MINUTES } from 'ee/usage_quotas/pipelines/constants';
import { defaultProvide } from '../mock_data';
jest.mock('~/google_tag_manager');
describe('PipelineUsageApp', () => {
let wrapper;
const findBuyAdditionalMinutesButton = () =>
wrapper.findByTestId('buy-additional-minutes-button');
const createComponent = ({ provide = {} } = {}) => {
wrapper = shallowMountExtended(PipelineUsageApp, {
provide: {
...defaultProvide,
...provide,
},
stubs: {
GlButton,
},
});
};
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
describe('Buy additional minutes Button', () => {
it('calls pushEECproductAddToCartEvent on click', async () => {
findBuyAdditionalMinutesButton().trigger('click');
expect(pushEECproductAddToCartEvent).toHaveBeenCalledTimes(1);
});
describe('Gitlab SaaS: valid data for buyAdditionalMinutesPath and buyAdditionalMinutesTarget', () => {
it('renders the button to buy additional minutes', () => {
expect(findBuyAdditionalMinutesButton().exists()).toBe(true);
expect(findBuyAdditionalMinutesButton().text()).toBe(LABEL_BUY_ADDITIONAL_MINUTES);
});
});
describe('Gitlab Self-Managed: buyAdditionalMinutesPath and buyAdditionalMinutesTarget not provided', () => {
beforeEach(() => {
createComponent({
provide: {
buyAdditionalMinutesPath: undefined,
buyAdditionalMinutesTarget: undefined,
},
});
});
it('does not render the button to buy additional minutes', () => {
expect(findBuyAdditionalMinutesButton().exists()).toBe(false);
});
});
});
});
import { TEST_HOST } from 'helpers/test_constants';
export const defaultProvide = {
namespaceActualPlanName: 'MyGroup',
buyAdditionalMinutesPath: `${TEST_HOST}/-/subscriptions/buy_minutes?selected_group=12345`,
buyAdditionalMinutesTarget: '_self',
};
...@@ -264,4 +264,34 @@ RSpec.describe EE::NamespacesHelper do ...@@ -264,4 +264,34 @@ RSpec.describe EE::NamespacesHelper do
end end
end end
end end
describe '#pipeline_usage_quota_app_data' do
context 'Gitlab SaaS', :saas do
before do
stub_ee_application_setting(should_check_namespace_plan: true)
end
it 'returns a hash with buy_additional_minutes data' do
expect(helper.pipeline_usage_quota_app_data(user_group)).to eql({
namespace_actual_plan_name: user_group.actual_plan_name,
namespace_path: user_group.full_path,
namespace_id: user_group.id,
page_size: Kaminari.config.default_per_page,
buy_additional_minutes_path: EE::SUBSCRIPTIONS_MORE_MINUTES_URL,
buy_additional_minutes_target: '_blank'
})
end
end
context 'Gitlab Self-Managed' do
it 'returns a hash without buy_additional_minutes data' do
expect(helper.pipeline_usage_quota_app_data(user_group)).to eql({
namespace_actual_plan_name: user_group.actual_plan_name,
namespace_path: user_group.full_path,
namespace_id: user_group.id,
page_size: Kaminari.config.default_per_page
})
end
end
end
end end
...@@ -268,4 +268,15 @@ RSpec.describe NamespacesHelper do ...@@ -268,4 +268,15 @@ RSpec.describe NamespacesHelper do
end end
end end
end end
describe '#pipeline_usage_quota_app_data' do
it 'returns a hash with necessary data for the frontend' do
expect(helper.pipeline_usage_quota_app_data(user_group)).to eql({
namespace_actual_plan_name: user_group.actual_plan_name,
namespace_path: user_group.full_path,
namespace_id: user_group.id,
page_size: Kaminari.config.default_per_page
})
end
end
end end
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