Commit 9272fb9c authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '341171-mlunoe-subscription-history-table-add-error-handling' into 'master'

Refactor(SM: Subscription history): direct import

See merge request gitlab-org/gitlab!78391
parents 98831624 33eb839b
<script>
import { GlAlert, GlButton } from '@gitlab/ui';
import { GlAlert, GlButton, GlSprintf } from '@gitlab/ui';
import { isInFuture } from '~/lib/utils/datetime/date_calculation_utility';
import { sprintf } from '~/locale';
import {
......@@ -8,12 +8,16 @@ import {
subscriptionActivationNotificationText,
subscriptionActivationFutureDatedNotificationTitle,
subscriptionActivationFutureDatedNotificationMessage,
subscriptionHistoryQueries,
subscriptionHistoryFailedTitle,
subscriptionHistoryFailedMessage,
currentSubscriptionsEntryName,
historySubscriptionsEntryName,
subscriptionMainTitle,
subscriptionQueries,
exportLicenseUsageBtnText,
SUBSCRIPTION_ACTIVATION_SUCCESS_EVENT,
} from '../constants';
import getCurrentLicense from '../graphql/queries/get_current_license.query.graphql';
import getLicenseHistory from '../graphql/queries/get_license_history.query.graphql';
import SubscriptionActivationCard from './subscription_activation_card.vue';
import SubscriptionBreakdown from './subscription_breakdown.vue';
import SubscriptionPurchaseCard from './subscription_purchase_card.vue';
......@@ -24,6 +28,7 @@ export default {
components: {
GlAlert,
GlButton,
GlSprintf,
SubscriptionActivationCard,
SubscriptionBreakdown,
SubscriptionPurchaseCard,
......@@ -34,6 +39,8 @@ export default {
exportLicenseUsageBtnText,
noActiveSubscription,
subscriptionMainTitle,
subscriptionHistoryFailedTitle,
subscriptionHistoryFailedMessage,
},
props: {
licenseUsageFilePath: {
......@@ -48,15 +55,21 @@ export default {
},
apollo: {
currentSubscription: {
query: subscriptionQueries.query,
query: getCurrentLicense,
update({ currentLicense }) {
return currentLicense || {};
},
error() {
this.subscriptionFetchError = currentSubscriptionsEntryName;
},
},
subscriptionHistory: {
query: subscriptionHistoryQueries.query,
query: getLicenseHistory,
update({ licenseHistoryEntries }) {
return licenseHistoryEntries.nodes || [];
return licenseHistoryEntries?.nodes || [];
},
error() {
this.subscriptionFetchError = historySubscriptionsEntryName;
},
},
},
......@@ -65,6 +78,7 @@ export default {
currentSubscription: {},
activationNotification: null,
subscriptionHistory: [],
subscriptionFetchError: null,
};
},
computed: {
......@@ -96,6 +110,9 @@ export default {
dismissActivationNotification() {
this.activationNotification = null;
},
dismissSubscriptionFetchError() {
this.subscriptionFetchError = null;
},
},
};
</script>
......@@ -121,6 +138,20 @@ export default {
>
{{ activationNotification.message }}
</gl-alert>
<gl-alert
v-if="subscriptionFetchError"
:title="$options.i18n.subscriptionHistoryFailedTitle"
variant="danger"
class="gl-mb-6"
data-testid="subscription-fetch-error-alert"
@dismiss="dismissSubscriptionFetchError"
>
<gl-sprintf :message="$options.i18n.subscriptionHistoryFailedMessage">
<template #subscriptionEntryName>
{{ subscriptionFetchError }}
</template>
</gl-sprintf>
</gl-alert>
<subscription-breakdown
v-if="canShowSubscriptionDetails"
:subscription="currentSubscription"
......
......@@ -18,9 +18,9 @@ import {
SUBSCRIPTION_ACTIVATION_SUCCESS_EVENT,
SUBSCRIPTION_ACTIVATION_FINALIZED_EVENT,
subscriptionActivationForm,
subscriptionQueries,
} from '../constants';
import { getErrorsAsData, getLicenseFromData, updateSubscriptionAppCache } from '../graphql/utils';
import activateSubscriptionMutation from '../graphql/mutations/activate_subscription.mutation.graphql';
const feedbackMap = {
valueMissing: {
......@@ -103,7 +103,7 @@ export default {
this.isLoading = true;
this.$apollo
.mutate({
mutation: subscriptionQueries.mutation,
mutation: activateSubscriptionMutation,
variables: {
gitlabSubscriptionActivateInput: {
activationCode: this.form.fields.activationCode.value,
......
import { __, s__ } from '~/locale';
import { PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
import activateSubscriptionMutation from './graphql/mutations/activate_subscription.mutation.graphql';
import getCurrentLicense from './graphql/queries/get_current_license.query.graphql';
import getLicenseHistory from './graphql/queries/get_license_history.query.graphql';
export const subscriptionMainTitle = s__('SuperSonics|Your subscription');
export const subscriptionActivationNotificationText = s__(
......@@ -20,6 +17,13 @@ export const subscriptionActivationInsertCode = __(
export const howToActivateSubscription = s__(
'SuperSonics|Learn how to %{linkStart}activate your subscription%{linkEnd}.',
);
export const subscriptionHistoryFailedTitle = s__('SuperSonics|Subscription unavailable');
export const subscriptionHistoryFailedMessage = s__(
'SuperSonics|Your %{subscriptionEntryName} cannot be displayed at the moment. Please refresh the page to try again.',
);
export const currentSubscriptionsEntryName = s__('SuperSonics|current subscription');
export const historySubscriptionsEntryName = s__('SuperSonics|history subscriptions');
export const cancelLabel = __('Cancel');
export const activateLabel = s__('AdminUsers|Activate');
export const activateSubscription = s__('SuperSonics|Activate subscription');
......@@ -39,7 +43,7 @@ export const detailsLabels = {
email: __('Email'),
id: __('ID'),
lastSync: __('Last Sync'),
name: __('Name'),
name: licensedToHeaderText,
plan: __('Plan'),
expiresAt: __('Renews'),
startsAt: __('Started'),
......@@ -104,15 +108,6 @@ export const subscriptionTypes = {
LICENSE_FILE: 'license_file',
};
export const subscriptionQueries = {
query: getCurrentLicense,
mutation: activateSubscriptionMutation,
};
export const subscriptionHistoryQueries = {
query: getLicenseHistory,
};
export const trialCard = {
title: s__('SuperSonics|Free trial'),
description: s__(
......
import produce from 'immer';
import { subscriptionHistoryQueries, subscriptionQueries } from '../constants';
import getCurrentLicense from './queries/get_current_license.query.graphql';
import getLicenseHistory from './queries/get_license_history.query.graphql';
export const getLicenseFromData = ({ data } = {}) => data?.gitlabSubscriptionActivate?.license;
export const getErrorsAsData = ({ data } = {}) => data?.gitlabSubscriptionActivate?.errors || [];
......@@ -9,18 +10,16 @@ export const updateSubscriptionAppCache = (cache, mutation) => {
if (!license) {
return;
}
const { query } = subscriptionQueries;
const { query: historyQuery } = subscriptionHistoryQueries;
const data = produce({}, (draftData) => {
draftData.currentLicense = license;
});
cache.writeQuery({ query, data });
const subscriptionsList = cache.readQuery({ query: historyQuery });
cache.writeQuery({ query: getCurrentLicense, data });
const subscriptionsList = cache.readQuery({ query: getLicenseHistory });
const subscriptionListData = produce(subscriptionsList, (draftData) => {
draftData.licenseHistoryEntries.nodes = [
license,
...subscriptionsList.licenseHistoryEntries.nodes,
];
});
cache.writeQuery({ query: historyQuery, data: subscriptionListData });
cache.writeQuery({ query: getLicenseHistory, data: subscriptionListData });
};
import { GlButton } from '@gitlab/ui';
import { GlButton, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import SubscriptionManagementApp from 'ee/admin/subscriptions/show/components/app.vue';
import SubscriptionActivationCard from 'ee/admin/subscriptions/show/components/subscription_activation_card.vue';
import SubscriptionBreakdown from 'ee/admin/subscriptions/show/components/subscription_breakdown.vue';
import {
noActiveSubscription,
subscriptionActivationNotificationText,
subscriptionActivationFutureDatedNotificationTitle,
subscriptionHistoryQueries,
subscriptionHistoryFailedTitle,
subscriptionHistoryFailedMessage,
currentSubscriptionsEntryName,
historySubscriptionsEntryName,
subscriptionMainTitle,
subscriptionQueries,
SUBSCRIPTION_ACTIVATION_SUCCESS_EVENT,
} from 'ee/admin/subscriptions/show/constants';
import getCurrentLicense from 'ee/admin/subscriptions/show/graphql/queries/get_current_license.query.graphql';
import getLicenseHistory from 'ee/admin/subscriptions/show/graphql/queries/get_license_history.query.graphql';
import waitForPromises from 'helpers/wait_for_promises';
import { useFakeDate } from 'helpers/fake_date';
import createMockApollo from 'helpers/mock_apollo_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { sprintf } from '~/locale';
import { license, subscriptionHistory } from '../mock_data';
Vue.use(VueApollo);
......@@ -35,6 +40,8 @@ describe('SubscriptionManagementApp', () => {
const findSubscriptionMainTitle = () => wrapper.findByTestId('subscription-main-title');
const findSubscriptionActivationSuccessAlert = () =>
wrapper.findByTestId('subscription-activation-success-alert');
const findSubscriptionFetchErrorAlert = () =>
wrapper.findByTestId('subscription-fetch-error-alert');
const findExportLicenseUsageFileLink = () => wrapper.findComponent(GlButton);
let currentSubscriptionResolver;
......@@ -42,8 +49,8 @@ describe('SubscriptionManagementApp', () => {
const createMockApolloProvider = ([subscriptionResolver, historyResolver]) => {
Vue.use(VueApollo);
return createMockApollo([
[subscriptionQueries.query, subscriptionResolver],
[subscriptionHistoryQueries.query, historyResolver],
[getCurrentLicense, subscriptionResolver],
[getLicenseHistory, historyResolver],
]);
};
......@@ -55,6 +62,9 @@ describe('SubscriptionManagementApp', () => {
licenseUsageFilePath: 'about:blank',
...props,
},
stubs: {
GlSprintf,
},
}),
);
};
......@@ -63,6 +73,48 @@ describe('SubscriptionManagementApp', () => {
wrapper.destroy();
});
describe('when failing to fetch subcriptions', () => {
describe('when failing to fetch history subcriptions', () => {
describe.each`
currentFails | historyFails
${true} | ${false}
${false} | ${true}
${true} | ${true}
`(
'with current subscription failing to fetch=$currentFails and history subscriptions failing to fetch=$historyFails',
({ currentFails, historyFails }) => {
const error = new Error('Network error!');
beforeEach(async () => {
currentSubscriptionResolver = currentFails
? jest.fn().mockRejectedValue({ error })
: jest.fn().mockResolvedValue({ data: { currentLicense: license.ULTIMATE } });
subscriptionHistoryResolver = historyFails
? jest.fn().mockRejectedValue({ error })
: jest.fn().mockResolvedValue({
data: { licenseHistoryEntries: { nodes: subscriptionHistory } },
});
createComponent({}, [currentSubscriptionResolver, subscriptionHistoryResolver]);
await waitForPromises();
});
it('renders the error alert', () => {
const alert = findSubscriptionFetchErrorAlert();
const subscriptionEntryName = historyFails
? historySubscriptionsEntryName
: currentSubscriptionsEntryName;
expect(alert.exists()).toBe(true);
expect(alert.props('title')).toBe(subscriptionHistoryFailedTitle);
expect(alert.text().replace(/\s+/g, ' ')).toBe(
sprintf(subscriptionHistoryFailedMessage, { subscriptionEntryName }),
);
});
},
);
});
});
describe('Subscription Activation Form', () => {
it('shows the main title', () => {
currentSubscriptionResolver = jest
......
......@@ -9,9 +9,9 @@ import {
SUBSCRIPTION_ACTIVATION_FAILURE_EVENT,
SUBSCRIPTION_ACTIVATION_SUCCESS_EVENT,
SUBSCRIPTION_ACTIVATION_FINALIZED_EVENT,
subscriptionQueries,
subscriptionActivationForm,
} from 'ee/admin/subscriptions/show/constants';
import activateSubscriptionMutation from 'ee/admin/subscriptions/show/graphql/mutations/activate_subscription.mutation.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
import { stubComponent } from 'helpers/stub_component';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
......@@ -29,7 +29,7 @@ describe('SubscriptionActivationForm', () => {
let wrapper;
const createMockApolloProvider = (resolverMock) => {
return createMockApollo([[subscriptionQueries.mutation, resolverMock]]);
return createMockApollo([[activateSubscriptionMutation, resolverMock]]);
};
const findActivateButton = () => wrapper.findByTestId('activate-button');
......
......@@ -34687,6 +34687,9 @@ msgstr ""
msgid "SuperSonics|Subscription details"
msgstr ""
msgid "SuperSonics|Subscription unavailable"
msgstr ""
msgid "SuperSonics|Sync subscription details"
msgstr ""
......@@ -34741,6 +34744,9 @@ msgstr ""
msgid "SuperSonics|You'll be charged for %{trueUpLinkStart}users over license%{trueUpLinkEnd} on a quarterly or annual basis, depending on the terms of your agreement."
msgstr ""
msgid "SuperSonics|Your %{subscriptionEntryName} cannot be displayed at the moment. Please refresh the page to try again."
msgstr ""
msgid "SuperSonics|Your future dated license was successfully added"
msgstr ""
......@@ -34753,6 +34759,12 @@ msgstr ""
msgid "SuperSonics|Your subscription was successfully activated. You can see the details below."
msgstr ""
msgid "SuperSonics|current subscription"
msgstr ""
msgid "SuperSonics|history subscriptions"
msgstr ""
msgid "Support"
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