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

Cloud License - Render connectivity error

parent 39e47fd5
<script>
import {
GlAlert,
GlButton,
GlCard,
GlForm,
......@@ -13,6 +14,8 @@ import produce from 'immer';
import { helpPagePath } from '~/helpers/help_page_helper';
import validation from '~/vue_shared/directives/validation';
import {
CONNECTIVITY_ERROR,
connectivityErrorAlert,
fieldRequiredMessage,
subscriptionActivationForm,
subscriptionQueries,
......@@ -32,10 +35,13 @@ const getErrorsAsData = ({
export const SUBSCRIPTION_ACTIVATION_FAILURE_EVENT = 'subscription-activation-failure';
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 {
name: 'CloudLicenseSubscriptionActivationForm',
components: {
GlAlert,
GlButton,
GlCard,
GlForm,
......@@ -53,9 +59,16 @@ export default {
acceptTerms: subscriptionActivationForm.acceptTerms,
activateLabel: subscriptionActivationForm.activateLabel,
fieldRequiredMessage,
alert: {
title: connectivityErrorAlert.title,
subtitle: connectivityErrorAlert.subtitle,
helpText: connectivityErrorAlert.helpText,
},
},
links: {
adminLicenseUrl,
troubleshootingHelpLink,
subscriptionActivationHelpLink,
},
directives: {
validation: validation(),
......@@ -80,6 +93,7 @@ export default {
return {
form,
isLoading: false,
hasConnectivityIssue: false,
};
},
computed: {
......@@ -101,6 +115,7 @@ export default {
}
this.form.showValidation = false;
this.isLoading = true;
this.hasConnectivityIssue = false;
this.$apollo
.mutate({
mutation: subscriptionQueries.mutation,
......@@ -111,6 +126,9 @@ export default {
},
update: (cache, mutation) => {
const license = getLicenseFromData(mutation);
if (!license) {
return;
}
const { query } = subscriptionQueries;
const data = produce(license, (draftData) => {
draftData.currentLicense = license;
......@@ -121,6 +139,9 @@ export default {
.then((res) => {
const errors = getErrorsAsData(res);
if (errors.length) {
if (errors.find((error) => error === CONNECTIVITY_ERROR)) {
this.hasConnectivityIssue = true;
}
throw new Error();
}
})
......@@ -135,68 +156,99 @@ export default {
};
</script>
<template>
<gl-card>
<gl-card body-class="gl-p-0">
<template #header>
<h5 class="gl-my-0 gl-font-weight-bold">{{ $options.i18n.title }}</h5>
</template>
<p>
<gl-sprintf :message="$options.i18n.howToActivateSubscription">
<template #link="{ content }">
<gl-link :href="$options.links.adminLicenseUrl" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</p>
<gl-form novalidate @submit.prevent="submit">
<div class="gl-display-flex gl-flex-wrap">
<gl-form-group
class="gl-flex-grow-1"
:invalid-feedback="form.fields.activationCode.feedback"
data-testid="form-group-activation-code"
>
<label class="gl-w-full" for="activation-code-group">
{{ $options.i18n.activationCode }}
</label>
<gl-form-input
id="activation-code-group"
v-model="form.fields.activationCode.value"
v-validation:[form.showValidation]
:disabled="isLoading"
:placeholder="$options.i18n.pasteActivationCode"
:state="form.fields.activationCode.state"
name="activationCode"
class="gl-mb-4"
required
/>
</gl-form-group>
<gl-form-group
class="gl-mb-0"
:state="isCheckboxValid"
:invalid-feedback="$options.i18n.fieldRequiredMessage"
data-testid="form-group-terms"
>
<gl-form-checkbox v-model="form.fields.terms.state" :state="isCheckboxValid">
<gl-sprintf :message="$options.i18n.acceptTerms">
<template #link="{ content }">
<gl-link href="https://about.gitlab.com/terms/" target="_blank"
>{{ content }}
</gl-link>
</template>
</gl-sprintf>
</gl-form-checkbox>
</gl-form-group>
<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>
<gl-sprintf :message="$options.i18n.howToActivateSubscription">
<template #link="{ content }">
<gl-link href="$options.links.adminLicenseUrl" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</p>
<gl-form novalidate @submit.prevent="submit">
<div class="gl-display-flex gl-flex-wrap">
<gl-form-group
class="gl-flex-grow-1"
:invalid-feedback="form.fields.activationCode.feedback"
data-testid="form-group-activation-code"
>
<label class="gl-w-full" for="activation-code-group">
{{ $options.i18n.activationCode }}
</label>
<gl-form-input
id="activation-code-group"
v-model="form.fields.activationCode.value"
v-validation:[form.showValidation]
:disabled="isLoading"
:placeholder="$options.i18n.pasteActivationCode"
:state="form.fields.activationCode.state"
name="activationCode"
class="gl-mb-4"
required
/>
</gl-form-group>
<gl-form-group
class="gl-mb-0"
:state="isCheckboxValid"
:invalid-feedback="$options.i18n.fieldRequiredMessage"
data-testid="form-group-terms"
>
<gl-form-checkbox v-model="form.fields.terms.state" :state="isCheckboxValid">
<gl-sprintf :message="$options.i18n.acceptTerms">
<template #link="{ content }">
<gl-link href="https://about.gitlab.com/terms/" target="_blank"
>{{ content }}
</gl-link>
</template>
</gl-sprintf>
</gl-form-checkbox>
</gl-form-group>
<gl-button
:loading="isRequestingActivation"
category="primary"
class="gl-mt-6 js-no-auto-disable"
data-testid="activate-button"
type="submit"
variant="confirm"
>
{{ $options.i18n.activateLabel }}
</gl-button>
</div>
</gl-form>
<gl-button
:loading="isRequestingActivation"
category="primary"
class="gl-mt-6 js-no-auto-disable"
data-testid="activate-button"
type="submit"
variant="confirm"
>
{{ $options.i18n.activateLabel }}
</gl-button>
</div>
</gl-form>
</div>
</gl-card>
</template>
......@@ -115,3 +115,14 @@ export const buySubscriptionCard = {
),
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 VueApollo from 'vue-apollo';
import CloudLicenseSubscriptionActivationForm, {
SUBSCRIPTION_ACTIVATION_FAILURE_EVENT,
troubleshootingHelpLink,
subscriptionActivationHelpLink,
} from 'ee/pages/admin/cloud_licenses/components/subscription_activation_form.vue';
import { fieldRequiredMessage, subscriptionQueries } from 'ee/pages/admin/cloud_licenses/constants';
import createMockApollo from 'helpers/mock_apollo_helper';
......@@ -30,6 +32,7 @@ describe('CloudLicenseApp', () => {
const findActivationCodeFormGroup = () => wrapper.findByTestId('form-group-activation-code');
const findActivationCodeInput = () => wrapper.findComponent(GlFormInput);
const findActivateSubscriptionForm = () => wrapper.findComponent(GlForm);
const findConnectivityErrorAlert = () => wrapper.findComponent(GlAlert);
const GlFormInputStub = stubComponent(GlFormInput, {
template: `<input />`,
......@@ -146,6 +149,25 @@ describe('CloudLicenseApp', () => {
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', () => {
const mutationMock = jest.fn().mockRejectedValue(activateLicenseMutationResponse.FAILURE);
beforeEach(() => {
......
import { subscriptionType } from 'ee/pages/admin/cloud_licenses/constants';
import { CONNECTIVITY_ERROR, subscriptionType } from 'ee/pages/admin/cloud_licenses/constants';
export const license = {
ULTIMATE: {
......@@ -72,6 +72,15 @@ export const activateLicenseMutationResponse = {
],
},
],
CONNECTIVITY_ERROR: {
data: {
gitlabSubscriptionActivate: {
license: null,
errors: [CONNECTIVITY_ERROR],
__typename: 'GitlabSubscriptionActivatePayload',
},
},
},
ERRORS_AS_DATA: {
data: {
gitlabSubscriptionActivate: {
......
......@@ -6692,6 +6692,9 @@ msgstr ""
msgid "CloudLicense|Free trial"
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."
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."
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"
msgstr ""
......@@ -32183,6 +32189,9 @@ msgstr ""
msgid "There are running deployments on the environment. Please retry later."
msgstr ""
msgid "There is a connectivity issue"
msgstr ""
msgid "There is a halted Elasticsearch migration"
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