Commit e3f1d9c4 authored by Ammar Alakkad's avatar Ammar Alakkad Committed by Jacques Erasmus

Cloud License - Render connectivity error

parent 39e47fd5
<script> <script>
import { import {
GlAlert,
GlButton, GlButton,
GlCard, GlCard,
GlForm, GlForm,
...@@ -13,6 +14,8 @@ import produce from 'immer'; ...@@ -13,6 +14,8 @@ import produce from 'immer';
import { helpPagePath } from '~/helpers/help_page_helper'; import { helpPagePath } from '~/helpers/help_page_helper';
import validation from '~/vue_shared/directives/validation'; import validation from '~/vue_shared/directives/validation';
import { import {
CONNECTIVITY_ERROR,
connectivityErrorAlert,
fieldRequiredMessage, fieldRequiredMessage,
subscriptionActivationForm, subscriptionActivationForm,
subscriptionQueries, subscriptionQueries,
...@@ -32,10 +35,13 @@ const getErrorsAsData = ({ ...@@ -32,10 +35,13 @@ const getErrorsAsData = ({
export const SUBSCRIPTION_ACTIVATION_FAILURE_EVENT = 'subscription-activation-failure'; export const SUBSCRIPTION_ACTIVATION_FAILURE_EVENT = 'subscription-activation-failure';
export const adminLicenseUrl = helpPagePath('/user/admin_area/license'); export const adminLicenseUrl = helpPagePath('/user/admin_area/license');
export const troubleshootingHelpLink = helpPagePath('user/admin_area/license.html#troubleshooting');
export const subscriptionActivationHelpLink = helpPagePath('user/admin_area/license.html');
export default { export default {
name: 'CloudLicenseSubscriptionActivationForm', name: 'CloudLicenseSubscriptionActivationForm',
components: { components: {
GlAlert,
GlButton, GlButton,
GlCard, GlCard,
GlForm, GlForm,
...@@ -53,9 +59,16 @@ export default { ...@@ -53,9 +59,16 @@ export default {
acceptTerms: subscriptionActivationForm.acceptTerms, acceptTerms: subscriptionActivationForm.acceptTerms,
activateLabel: subscriptionActivationForm.activateLabel, activateLabel: subscriptionActivationForm.activateLabel,
fieldRequiredMessage, fieldRequiredMessage,
alert: {
title: connectivityErrorAlert.title,
subtitle: connectivityErrorAlert.subtitle,
helpText: connectivityErrorAlert.helpText,
},
}, },
links: { links: {
adminLicenseUrl, adminLicenseUrl,
troubleshootingHelpLink,
subscriptionActivationHelpLink,
}, },
directives: { directives: {
validation: validation(), validation: validation(),
...@@ -80,6 +93,7 @@ export default { ...@@ -80,6 +93,7 @@ export default {
return { return {
form, form,
isLoading: false, isLoading: false,
hasConnectivityIssue: false,
}; };
}, },
computed: { computed: {
...@@ -101,6 +115,7 @@ export default { ...@@ -101,6 +115,7 @@ export default {
} }
this.form.showValidation = false; this.form.showValidation = false;
this.isLoading = true; this.isLoading = true;
this.hasConnectivityIssue = false;
this.$apollo this.$apollo
.mutate({ .mutate({
mutation: subscriptionQueries.mutation, mutation: subscriptionQueries.mutation,
...@@ -111,6 +126,9 @@ export default { ...@@ -111,6 +126,9 @@ export default {
}, },
update: (cache, mutation) => { update: (cache, mutation) => {
const license = getLicenseFromData(mutation); const license = getLicenseFromData(mutation);
if (!license) {
return;
}
const { query } = subscriptionQueries; const { query } = subscriptionQueries;
const data = produce(license, (draftData) => { const data = produce(license, (draftData) => {
draftData.currentLicense = license; draftData.currentLicense = license;
...@@ -121,6 +139,9 @@ export default { ...@@ -121,6 +139,9 @@ export default {
.then((res) => { .then((res) => {
const errors = getErrorsAsData(res); const errors = getErrorsAsData(res);
if (errors.length) { if (errors.length) {
if (errors.find((error) => error === CONNECTIVITY_ERROR)) {
this.hasConnectivityIssue = true;
}
throw new Error(); throw new Error();
} }
}) })
...@@ -135,14 +156,44 @@ export default { ...@@ -135,14 +156,44 @@ export default {
}; };
</script> </script>
<template> <template>
<gl-card> <gl-card body-class="gl-p-0">
<template #header> <template #header>
<h5 class="gl-my-0 gl-font-weight-bold">{{ $options.i18n.title }}</h5> <h5 class="gl-my-0 gl-font-weight-bold">{{ $options.i18n.title }}</h5>
</template> </template>
<div
v-if="hasConnectivityIssue"
class="gl-p-5 gl-border-b-1 gl-border-gray-100 gl-border-b-solid"
>
<gl-alert variant="danger" :title="$options.i18n.alert.title" :dismissible="false">
<gl-sprintf :message="$options.i18n.alert.subtitle">
<template #link="{ content }">
<gl-link
:href="$options.links.subscriptionActivationHelpLink"
target="_blank"
class="gl-text-decoration-none!"
>{{ content }}</gl-link
>
</template>
</gl-sprintf>
<gl-sprintf :message="$options.i18n.alert.helpText">
<template #link="{ content }">
<gl-link
:href="$options.links.troubleshootingHelpLink"
target="_blank"
class="gl-text-decoration-none!"
>
{{ content }}
</gl-link>
</template>
</gl-sprintf>
</gl-alert>
</div>
<div class="gl-p-5">
<p> <p>
<gl-sprintf :message="$options.i18n.howToActivateSubscription"> <gl-sprintf :message="$options.i18n.howToActivateSubscription">
<template #link="{ content }"> <template #link="{ content }">
<gl-link :href="$options.links.adminLicenseUrl" target="_blank">{{ content }}</gl-link> <gl-link href="$options.links.adminLicenseUrl" target="_blank">{{ content }}</gl-link>
</template> </template>
</gl-sprintf> </gl-sprintf>
</p> </p>
...@@ -198,5 +249,6 @@ export default { ...@@ -198,5 +249,6 @@ export default {
</gl-button> </gl-button>
</div> </div>
</gl-form> </gl-form>
</div>
</gl-card> </gl-card>
</template> </template>
...@@ -115,3 +115,14 @@ export const buySubscriptionCard = { ...@@ -115,3 +115,14 @@ export const buySubscriptionCard = {
), ),
buttonLabel: s__('CloudLicense|Buy subscription'), buttonLabel: s__('CloudLicense|Buy subscription'),
}; };
export const CONNECTIVITY_ERROR = 'CONNECTIVITY_ERROR';
export const connectivityErrorAlert = {
title: s__('There is a connectivity issue'),
subtitle: s__(
'CloudLicense|To activate your subscription, connect to GitLab servers through the %{linkStart}Cloud Sync service%{linkEnd}, a hassle-free way to manage your subscription.',
),
helpText: s__(
'CloudLicense|Get help for the most common connectivity issues by %{linkStart}troubleshooting the activation code%{linkEnd}.',
),
};
import { GlForm, GlFormCheckbox, GlFormInput } from '@gitlab/ui'; import { GlAlert, GlForm, GlFormInput, GlFormCheckbox, GlLink, GlSprintf } from '@gitlab/ui';
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import CloudLicenseSubscriptionActivationForm, { import CloudLicenseSubscriptionActivationForm, {
SUBSCRIPTION_ACTIVATION_FAILURE_EVENT, SUBSCRIPTION_ACTIVATION_FAILURE_EVENT,
troubleshootingHelpLink,
subscriptionActivationHelpLink,
} from 'ee/pages/admin/cloud_licenses/components/subscription_activation_form.vue'; } from 'ee/pages/admin/cloud_licenses/components/subscription_activation_form.vue';
import { fieldRequiredMessage, subscriptionQueries } from 'ee/pages/admin/cloud_licenses/constants'; import { fieldRequiredMessage, subscriptionQueries } from 'ee/pages/admin/cloud_licenses/constants';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
...@@ -30,6 +32,7 @@ describe('CloudLicenseApp', () => { ...@@ -30,6 +32,7 @@ describe('CloudLicenseApp', () => {
const findActivationCodeFormGroup = () => wrapper.findByTestId('form-group-activation-code'); const findActivationCodeFormGroup = () => wrapper.findByTestId('form-group-activation-code');
const findActivationCodeInput = () => wrapper.findComponent(GlFormInput); const findActivationCodeInput = () => wrapper.findComponent(GlFormInput);
const findActivateSubscriptionForm = () => wrapper.findComponent(GlForm); const findActivateSubscriptionForm = () => wrapper.findComponent(GlForm);
const findConnectivityErrorAlert = () => wrapper.findComponent(GlAlert);
const GlFormInputStub = stubComponent(GlFormInput, { const GlFormInputStub = stubComponent(GlFormInput, {
template: `<input />`, template: `<input />`,
...@@ -146,6 +149,25 @@ describe('CloudLicenseApp', () => { ...@@ -146,6 +149,25 @@ describe('CloudLicenseApp', () => {
it.todo('deals with failures in a meaningful way'); it.todo('deals with failures in a meaningful way');
}); });
describe('when the mutation is not successful with connectivity error', () => {
const mutationMock = jest
.fn()
.mockResolvedValue(activateLicenseMutationResponse.CONNECTIVITY_ERROR);
beforeEach(async () => {
createComponentWithApollo({ mutationMock, stubs: { GlSprintf } });
await findActivationCodeInput().vm.$emit('input', fakeActivationCode);
await findAgreementCheckbox().vm.$emit('input', true);
findActivateSubscriptionForm().vm.$emit('submit', createFakeEvent());
});
it('shows alert component guiding the user to resolve the connectivity problem', () => {
const alert = findConnectivityErrorAlert();
expect(alert.exists()).toBe(true);
expect(alert.findAll(GlLink).at(0).attributes('href')).toBe(subscriptionActivationHelpLink);
expect(alert.findAll(GlLink).at(1).attributes('href')).toBe(troubleshootingHelpLink);
});
});
describe('when the mutation is not successful', () => { describe('when the mutation is not successful', () => {
const mutationMock = jest.fn().mockRejectedValue(activateLicenseMutationResponse.FAILURE); const mutationMock = jest.fn().mockRejectedValue(activateLicenseMutationResponse.FAILURE);
beforeEach(() => { beforeEach(() => {
......
import { subscriptionType } from 'ee/pages/admin/cloud_licenses/constants'; import { CONNECTIVITY_ERROR, subscriptionType } from 'ee/pages/admin/cloud_licenses/constants';
export const license = { export const license = {
ULTIMATE: { ULTIMATE: {
...@@ -72,6 +72,15 @@ export const activateLicenseMutationResponse = { ...@@ -72,6 +72,15 @@ export const activateLicenseMutationResponse = {
], ],
}, },
], ],
CONNECTIVITY_ERROR: {
data: {
gitlabSubscriptionActivate: {
license: null,
errors: [CONNECTIVITY_ERROR],
__typename: 'GitlabSubscriptionActivatePayload',
},
},
},
ERRORS_AS_DATA: { ERRORS_AS_DATA: {
data: { data: {
gitlabSubscriptionActivate: { gitlabSubscriptionActivate: {
......
...@@ -6692,6 +6692,9 @@ msgstr "" ...@@ -6692,6 +6692,9 @@ msgstr ""
msgid "CloudLicense|Free trial" msgid "CloudLicense|Free trial"
msgstr "" msgstr ""
msgid "CloudLicense|Get help for the most common connectivity issues by %{linkStart}troubleshooting the activation code%{linkEnd}."
msgstr ""
msgid "CloudLicense|I agree that my use of the GitLab Software is subject to the Subscription Agreement located at the %{linkStart}Terms of Service%{linkEnd}, unless otherwise agreed to in writing with GitLab." msgid "CloudLicense|I agree that my use of the GitLab Software is subject to the Subscription Agreement located at the %{linkStart}Terms of Service%{linkEnd}, unless otherwise agreed to in writing with GitLab."
msgstr "" msgstr ""
...@@ -6719,6 +6722,9 @@ msgstr "" ...@@ -6719,6 +6722,9 @@ msgstr ""
msgid "CloudLicense|This is the number of %{billableUsersLinkStart}billable users%{billableUsersLinkEnd} on your installation, and this is the minimum number you need to purchase when you renew your license." msgid "CloudLicense|This is the number of %{billableUsersLinkStart}billable users%{billableUsersLinkEnd} on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr "" msgstr ""
msgid "CloudLicense|To activate your subscription, connect to GitLab servers through the %{linkStart}Cloud Sync service%{linkEnd}, a hassle-free way to manage your subscription."
msgstr ""
msgid "CloudLicense|Users in subscription" msgid "CloudLicense|Users in subscription"
msgstr "" msgstr ""
...@@ -32183,6 +32189,9 @@ msgstr "" ...@@ -32183,6 +32189,9 @@ msgstr ""
msgid "There are running deployments on the environment. Please retry later." msgid "There are running deployments on the environment. Please retry later."
msgstr "" msgstr ""
msgid "There is a connectivity issue"
msgstr ""
msgid "There is a halted Elasticsearch migration" msgid "There is a halted Elasticsearch migration"
msgstr "" msgstr ""
......
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