Commit f6392723 authored by Sheldon Led's avatar Sheldon Led Committed by Mayra Cabrera

Initial PipelineUsageApp with Buy More Minutes button

This creates the Vue app and add the button to Buy Additional Minutes
parent 056adee2
......@@ -232,35 +232,40 @@ export const trackTransaction = (transactionDetails) => {
pushEnhancedEcommerceEvent('EECtransactionSuccess', eventData);
};
export const trackAddToCartUsageTab = () => {
export const pushEECproductAddToCartEvent = () => {
if (!isSupported()) {
return;
}
const getStartedButton = document.querySelector('.js-buy-additional-minutes');
getStartedButton.addEventListener('click', () => {
window.dataLayer.push({
event: 'EECproductAddToCart',
ecommerce: {
currencyCode: 'USD',
add: {
products: [
{
name: 'CI/CD Minutes',
id: '0003',
price: '10',
brand: 'GitLab',
category: 'DevOps',
variant: 'add-on',
quantity: 1,
},
],
},
window.dataLayer.push({
event: 'EECproductAddToCart',
ecommerce: {
currencyCode: 'USD',
add: {
products: [
{
name: 'CI/CD Minutes',
id: '0003',
price: '10',
brand: 'GitLab',
category: 'DevOps',
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 = () => {
if (!isSupported()) {
return;
......
......@@ -88,6 +88,15 @@ module NamespacesHelper
}.to_json
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
# 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
namespace.root_ancestor.free_plan? && !minute_limit_banner_dismissed?
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
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
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
......@@ -268,4 +268,15 @@ RSpec.describe NamespacesHelper do
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
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