Commit e08bbf6a authored by Etienne Baqué's avatar Etienne Baqué

Merge branch '349810-mlunoe-add-offline-cloud-license-and-subscription-type' into 'master'

Feat(Licensing): add Offline cloud type

See merge request gitlab-org/gitlab!80833
parents ae69176e aa32508a
...@@ -19,7 +19,7 @@ import { ...@@ -19,7 +19,7 @@ import {
SUBSCRIPTION_ACTIVATION_FINALIZED_EVENT, SUBSCRIPTION_ACTIVATION_FINALIZED_EVENT,
subscriptionActivationForm, subscriptionActivationForm,
} from '../constants'; } from '../constants';
import { getErrorsAsData, getLicenseFromData } from '../graphql/utils'; import { getErrorsAsData, getLicenseFromData } from '../utils';
import activateSubscriptionMutation from '../graphql/mutations/activate_subscription.mutation.graphql'; import activateSubscriptionMutation from '../graphql/mutations/activate_subscription.mutation.graphql';
const feedbackMap = { const feedbackMap = {
......
...@@ -20,7 +20,14 @@ import SubscriptionDetailsCard from './subscription_details_card.vue'; ...@@ -20,7 +20,14 @@ import SubscriptionDetailsCard from './subscription_details_card.vue';
import SubscriptionDetailsHistory from './subscription_details_history.vue'; import SubscriptionDetailsHistory from './subscription_details_history.vue';
import SubscriptionDetailsUserInfo from './subscription_details_user_info.vue'; import SubscriptionDetailsUserInfo from './subscription_details_user_info.vue';
export const subscriptionDetailsFields = ['id', 'plan', 'expiresAt', 'lastSync', 'startsAt']; export const subscriptionDetailsFields = [
'id',
'plan',
'type',
'expiresAt',
'lastSync',
'startsAt',
];
export const licensedToFields = ['name', 'email', 'company']; export const licensedToFields = ['name', 'email', 'company'];
export const modalId = 'subscription-activation-modal'; export const modalId = 'subscription-activation-modal';
...@@ -86,7 +93,7 @@ export default { ...@@ -86,7 +93,7 @@ export default {
return this.customersPortalUrl && this.hasSubscription; return this.customersPortalUrl && this.hasSubscription;
}, },
canSyncSubscription() { canSyncSubscription() {
return this.subscriptionSyncPath && this.isCloudType; return this.subscriptionSyncPath && this.isOnlineCloudType;
}, },
canRemoveLicense() { canRemoveLicense() {
return this.licenseRemovePath; return this.licenseRemovePath;
...@@ -97,8 +104,8 @@ export default { ...@@ -97,8 +104,8 @@ export default {
hasSubscriptionHistory() { hasSubscriptionHistory() {
return Boolean(this.subscriptionList.length); return Boolean(this.subscriptionList.length);
}, },
isCloudType() { isOnlineCloudType() {
return this.subscription.type === subscriptionTypes.CLOUD; return this.subscription.type === subscriptionTypes.ONLINE_CLOUD;
}, },
isLicenseFileType() { isLicenseFileType() {
return this.subscription.type === subscriptionTypes.LICENSE_FILE; return this.subscription.type === subscriptionTypes.LICENSE_FILE;
......
...@@ -4,12 +4,14 @@ import { identity } from 'lodash'; ...@@ -4,12 +4,14 @@ import { identity } from 'lodash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { getTimeago } from '~/lib/utils/datetime_utility'; import { getTimeago } from '~/lib/utils/datetime_utility';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import { getLicenseTypeLabel } from '../utils';
import SubscriptionDetailsTable from './subscription_details_table.vue'; import SubscriptionDetailsTable from './subscription_details_table.vue';
const subscriptionDetailsFormatRules = { const subscriptionDetailsFormatRules = {
id: getIdFromGraphQLId, id: getIdFromGraphQLId,
expiresAt: getTimeago().format, expiresAt: getTimeago().format,
lastSync: getTimeago().format, lastSync: getTimeago().format,
type: getLicenseTypeLabel,
plan: capitalizeFirstCharacter, plan: capitalizeFirstCharacter,
}; };
......
...@@ -2,13 +2,8 @@ ...@@ -2,13 +2,8 @@
import { GlTooltip, GlTooltipDirective, GlIcon, GlBadge, GlTableLite } from '@gitlab/ui'; import { GlTooltip, GlTooltipDirective, GlIcon, GlBadge, GlTableLite } from '@gitlab/ui';
import { kebabCase } from 'lodash'; import { kebabCase } from 'lodash';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import { import { detailsLabels, subscriptionTable } from '../constants';
cloudLicenseText, import { getLicenseTypeLabel } from '../utils';
detailsLabels,
licenseFileText,
subscriptionTable,
subscriptionTypes,
} from '../constants';
const DEFAULT_BORDER_CLASSES = 'gl-border-b-1! gl-border-b-gray-100! gl-border-b-solid!'; const DEFAULT_BORDER_CLASSES = 'gl-border-b-1! gl-border-b-gray-100! gl-border-b-solid!';
const DEFAULT_TH_CLASSES = 'gl-bg-white! gl-border-t-0! gl-pb-5! gl-px-5! gl-text-gray-700!'; const DEFAULT_TH_CLASSES = 'gl-bg-white! gl-border-t-0! gl-pb-5! gl-px-5! gl-text-gray-700!';
...@@ -99,8 +94,7 @@ export default { ...@@ -99,8 +94,7 @@ export default {
}, },
{ {
key: 'type', key: 'type',
formatter: (v, k, item) => formatter: (v, k, item) => getLicenseTypeLabel(item.type),
item.type === subscriptionTypes.LICENSE_FILE ? licenseFileText : cloudLicenseText,
label: subscriptionTable.type, label: subscriptionTable.type,
tdAttr, tdAttr,
tdClass: this.cellClass, tdClass: this.cellClass,
......
<script> <script>
import { GlSkeletonLoader, GlTableLite } from '@gitlab/ui'; import { GlSkeletonLoader, GlTableLite, GlBadge } from '@gitlab/ui';
import { slugifyWithUnderscore } from '~/lib/utils/text_utility'; import { slugifyWithUnderscore } from '~/lib/utils/text_utility';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { copySubscriptionIdButtonText, detailsLabels } from '../constants'; import { copySubscriptionIdButtonText, detailsLabels } from '../constants';
...@@ -23,7 +23,7 @@ export default { ...@@ -23,7 +23,7 @@ export default {
}, },
{ {
key: 'value', key: 'value',
formatter: (v, k, item) => item.value.toString(), formatter: (v, k, item) => item.value?.toString() || '-',
label: '', label: '',
thClass: DEFAULT_TH_CLASSES, thClass: DEFAULT_TH_CLASSES,
tdClass: DEFAULT_TD_CLASSES, tdClass: DEFAULT_TD_CLASSES,
...@@ -34,6 +34,7 @@ export default { ...@@ -34,6 +34,7 @@ export default {
ClipboardButton, ClipboardButton,
GlSkeletonLoader, GlSkeletonLoader,
GlTableLite, GlTableLite,
GlBadge,
}, },
props: { props: {
details: { details: {
...@@ -61,9 +62,6 @@ export default { ...@@ -61,9 +62,6 @@ export default {
}, },
}, },
methods: { methods: {
isLastRow(index) {
return index === this.details.length - 1;
},
placeHolderPosition(index) { placeHolderPosition(index) {
return (index - 1) * placeholderHeightFactor; return (index - 1) * placeholderHeightFactor;
}, },
...@@ -106,7 +104,12 @@ export default { ...@@ -106,7 +104,12 @@ export default {
data-testid="details-content" data-testid="details-content"
:data-qa-selector="qaSelectorValue(item)" :data-qa-selector="qaSelectorValue(item)"
> >
{{ value || '-' }} <gl-badge v-if="item.detail === 'type'" size="md" variant="info">
{{ value }}
</gl-badge>
<span v-else>
{{ value }}
</span>
<clipboard-button <clipboard-button
v-if="item.detail === 'id'" v-if="item.detail === 'id'"
:text="value" :text="value"
......
...@@ -36,7 +36,8 @@ export const manageSubscriptionButtonText = s__('SuperSonics|Manage'); ...@@ -36,7 +36,8 @@ export const manageSubscriptionButtonText = s__('SuperSonics|Manage');
export const syncSubscriptionButtonText = s__('SuperSonics|Sync subscription details'); export const syncSubscriptionButtonText = s__('SuperSonics|Sync subscription details');
export const copySubscriptionIdButtonText = __('Copy'); export const copySubscriptionIdButtonText = __('Copy');
export const licenseFileText = __('License file'); export const licenseFileText = __('License file');
export const cloudLicenseText = s__('SuperSonics|Cloud license'); export const onlineCloudLicenseText = s__('SuperSonics|Cloud license');
export const offlineCloudLicenseText = s__('SuperSonics|Offline cloud');
export const usersInSubscriptionUnlimited = __('Unlimited'); export const usersInSubscriptionUnlimited = __('Unlimited');
export const detailsLabels = { export const detailsLabels = {
address: __('Address'), address: __('Address'),
...@@ -46,6 +47,7 @@ export const detailsLabels = { ...@@ -46,6 +47,7 @@ export const detailsLabels = {
lastSync: __('Last Sync'), lastSync: __('Last Sync'),
name: licensedToHeaderText, name: licensedToHeaderText,
plan: __('Plan'), plan: __('Plan'),
type: __('Type'),
expiresAt: __('Renews'), expiresAt: __('Renews'),
startsAt: __('Started'), startsAt: __('Started'),
}; };
...@@ -106,7 +108,8 @@ export const subscriptionSyncStatus = { ...@@ -106,7 +108,8 @@ export const subscriptionSyncStatus = {
}; };
export const subscriptionTypes = { export const subscriptionTypes = {
CLOUD: 'cloud', ONLINE_CLOUD: 'cloud',
OFFLINE_CLOUD: 'offline_cloud',
LICENSE_FILE: 'license_file', LICENSE_FILE: 'license_file',
}; };
......
import {
subscriptionTypes,
offlineCloudLicenseText,
onlineCloudLicenseText,
licenseFileText,
} from './constants';
export const getLicenseFromData = ({ data } = {}) => data?.gitlabSubscriptionActivate?.license; export const getLicenseFromData = ({ data } = {}) => data?.gitlabSubscriptionActivate?.license;
export const getErrorsAsData = ({ data } = {}) => data?.gitlabSubscriptionActivate?.errors || []; export const getErrorsAsData = ({ data } = {}) => data?.gitlabSubscriptionActivate?.errors || [];
export function getLicenseTypeLabel(type) {
switch (type) {
case subscriptionTypes.OFFLINE_CLOUD:
return offlineCloudLicenseText;
case subscriptionTypes.ONLINE_CLOUD:
return onlineCloudLicenseText;
default:
return licenseFileText;
}
}
...@@ -12,7 +12,13 @@ module Resolvers ...@@ -12,7 +12,13 @@ module Resolvers
authorize! authorize!
::Gitlab::CurrentSettings.future_subscriptions.each do |subscription| ::Gitlab::CurrentSettings.future_subscriptions.each do |subscription|
subscription['type'] = subscription['cloud_license_enabled'] ? License::CLOUD_LICENSE_TYPE : License::LICENSE_FILE_TYPE subscription['type'] = if subscription['offline_cloud_licensing'] && subscription['cloud_license_enabled']
License::OFFLINE_CLOUD_TYPE
elsif subscription['cloud_license_enabled'] && !subscription['offline_cloud_licensing']
License::CLOUD_LICENSE_TYPE
else
License::LICENSE_FILE_TYPE
end
end end
end end
......
...@@ -8,6 +8,7 @@ class License < ApplicationRecord ...@@ -8,6 +8,7 @@ class License < ApplicationRecord
PREMIUM_PLAN = 'premium' PREMIUM_PLAN = 'premium'
ULTIMATE_PLAN = 'ultimate' ULTIMATE_PLAN = 'ultimate'
CLOUD_LICENSE_TYPE = 'cloud' CLOUD_LICENSE_TYPE = 'cloud'
OFFLINE_CLOUD_TYPE = 'offline_cloud'
LICENSE_FILE_TYPE = 'license_file' LICENSE_FILE_TYPE = 'license_file'
ALLOWED_PERCENTAGE_OF_USERS_OVERAGE = (10 / 100.0) ALLOWED_PERCENTAGE_OF_USERS_OVERAGE = (10 / 100.0)
...@@ -587,11 +588,11 @@ class License < ApplicationRecord ...@@ -587,11 +588,11 @@ class License < ApplicationRecord
end end
def offline_cloud_license? def offline_cloud_license?
!!license&.offline_cloud_licensing? cloud_license? && !!license&.offline_cloud_licensing?
end end
def online_cloud_license? def online_cloud_license?
cloud_license? && !offline_cloud_license? cloud_license? && !license&.offline_cloud_licensing?
end end
def customer_service_enabled? def customer_service_enabled?
...@@ -603,7 +604,10 @@ class License < ApplicationRecord ...@@ -603,7 +604,10 @@ class License < ApplicationRecord
end end
def license_type def license_type
cloud_license? ? CLOUD_LICENSE_TYPE : LICENSE_FILE_TYPE return OFFLINE_CLOUD_TYPE if offline_cloud_license?
return CLOUD_LICENSE_TYPE if online_cloud_license?
LICENSE_FILE_TYPE
end end
def auto_renew def auto_renew
......
...@@ -180,13 +180,16 @@ describe('Subscription Breakdown', () => { ...@@ -180,13 +180,16 @@ describe('Subscription Breakdown', () => {
describe('footer buttons', () => { describe('footer buttons', () => {
it.each` it.each`
url | type | shouldShow url | type | shouldShow
${subscriptionSyncPath} | ${subscriptionTypes.CLOUD} | ${true} ${subscriptionSyncPath} | ${subscriptionTypes.ONLINE_CLOUD} | ${true}
${subscriptionSyncPath} | ${subscriptionTypes.LICENSE_FILE} | ${false} ${subscriptionSyncPath} | ${subscriptionTypes.OFFLINE_CLOUD} | ${false}
${''} | ${subscriptionTypes.CLOUD} | ${false} ${subscriptionSyncPath} | ${subscriptionTypes.LICENSE_FILE} | ${false}
${''} | ${subscriptionTypes.LICENSE_FILE} | ${false} ${''} | ${subscriptionTypes.ONLINE_CLOUD} | ${false}
${undefined} | ${subscriptionTypes.CLOUD} | ${false} ${''} | ${subscriptionTypes.OFFLINE_CLOUD} | ${false}
${undefined} | ${subscriptionTypes.LICENSE_FILE} | ${false} ${''} | ${subscriptionTypes.LICENSE_FILE} | ${false}
${undefined} | ${subscriptionTypes.ONLINE_CLOUD} | ${false}
${undefined} | ${subscriptionTypes.OFFLINE_CLOUD} | ${false}
${undefined} | ${subscriptionTypes.LICENSE_FILE} | ${false}
`( `(
'with url is $url and type is $type the sync button is shown: $shouldShow', 'with url is $url and type is $type the sync button is shown: $shouldShow',
({ url, type, shouldShow }) => { ({ url, type, shouldShow }) => {
...@@ -229,13 +232,16 @@ describe('Subscription Breakdown', () => { ...@@ -229,13 +232,16 @@ describe('Subscription Breakdown', () => {
}); });
it.each` it.each`
url | type | shouldShow url | type | shouldShow
${licenseRemovePath} | ${subscriptionTypes.LICENSE_FILE} | ${true} ${licenseRemovePath} | ${subscriptionTypes.LICENSE_FILE} | ${true}
${licenseRemovePath} | ${subscriptionTypes.CLOUD} | ${true} ${licenseRemovePath} | ${subscriptionTypes.ONLINE_CLOUD} | ${true}
${''} | ${subscriptionTypes.LICENSE_FILE} | ${false} ${licenseRemovePath} | ${subscriptionTypes.OFFLINE_CLOUD} | ${true}
${''} | ${subscriptionTypes.CLOUD} | ${false} ${''} | ${subscriptionTypes.LICENSE_FILE} | ${false}
${undefined} | ${subscriptionTypes.LICENSE_FILE} | ${false} ${''} | ${subscriptionTypes.ONLINE_CLOUD} | ${false}
${undefined} | ${subscriptionTypes.CLOUD} | ${false} ${''} | ${subscriptionTypes.OFFLINE_CLOUD} | ${false}
${undefined} | ${subscriptionTypes.LICENSE_FILE} | ${false}
${undefined} | ${subscriptionTypes.ONLINE_CLOUD} | ${false}
${undefined} | ${subscriptionTypes.OFFLINE_CLOUD} | ${false}
`( `(
'with url is $url and type is $type the remove button is shown: $shouldShow', 'with url is $url and type is $type the remove button is shown: $shouldShow',
({ url, type, shouldShow }) => { ({ url, type, shouldShow }) => {
...@@ -254,9 +260,10 @@ describe('Subscription Breakdown', () => { ...@@ -254,9 +260,10 @@ describe('Subscription Breakdown', () => {
); );
it.each` it.each`
type | shouldShow type | shouldShow
${subscriptionTypes.LICENSE_FILE} | ${true} ${subscriptionTypes.LICENSE_FILE} | ${true}
${subscriptionTypes.CLOUD} | ${false} ${subscriptionTypes.ONLINE_CLOUD} | ${false}
${subscriptionTypes.OFFLINE_CLOUD} | ${false}
`( `(
'with url is $url and type is $type the activate cloud license button is shown: $shouldShow', 'with url is $url and type is $type the activate cloud license button is shown: $shouldShow',
({ type, shouldShow }) => { ({ type, shouldShow }) => {
......
...@@ -63,6 +63,10 @@ describe('Subscription Details Card', () => { ...@@ -63,6 +63,10 @@ describe('Subscription Details Card', () => {
detail: 'plan', detail: 'plan',
value: 'Ultimate', value: 'Ultimate',
}, },
{
detail: 'type',
value: 'Cloud license',
},
{ {
detail: 'expiresAt', detail: 'expiresAt',
value: 'in 1 year', value: 'in 1 year',
......
...@@ -2,12 +2,8 @@ import { GlBadge, GlIcon, GlTooltip } from '@gitlab/ui'; ...@@ -2,12 +2,8 @@ import { GlBadge, GlIcon, GlTooltip } from '@gitlab/ui';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import SubscriptionDetailsHistory from 'ee/admin/subscriptions/show/components/subscription_details_history.vue'; import SubscriptionDetailsHistory from 'ee/admin/subscriptions/show/components/subscription_details_history.vue';
import { import { detailsLabels, onlineCloudLicenseText } from 'ee/admin/subscriptions/show/constants';
detailsLabels, import { getLicenseTypeLabel } from 'ee/admin/subscriptions/show/utils';
cloudLicenseText,
licenseFileText,
subscriptionTypes,
} from 'ee/admin/subscriptions/show/constants';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { license, subscriptionFutureHistory, subscriptionPastHistory } from '../mock_data'; import { license, subscriptionFutureHistory, subscriptionPastHistory } from '../mock_data';
...@@ -54,7 +50,7 @@ describe('Subscription Details History', () => { ...@@ -54,7 +50,7 @@ describe('Subscription Details History', () => {
}); });
it('has the correct license type', () => { it('has the correct license type', () => {
expect(findCurrentRow().text()).toContain(cloudLicenseText); expect(findCurrentRow().text()).toContain(onlineCloudLicenseText);
expect(findTableRows().at(-1).text()).toContain('License file'); expect(findTableRows().at(-1).text()).toContain('License file');
}); });
...@@ -119,9 +115,7 @@ describe('Subscription Details History', () => { ...@@ -119,9 +115,7 @@ describe('Subscription Details History', () => {
it('displays the correct value for the type cell', () => { it('displays the correct value for the type cell', () => {
const cellTestId = `subscription-cell-type`; const cellTestId = `subscription-cell-type`;
const type = expect(findCellByTestid(cellTestId).text()).toBe(getLicenseTypeLabel(subscription.type));
subscription.type === subscriptionTypes.LICENSE_FILE ? licenseFileText : cloudLicenseText;
expect(findCellByTestid(cellTestId).text()).toBe(type);
}); });
it('displays the correct value for the plan cell', () => { it('displays the correct value for the plan cell', () => {
......
import { GlSkeletonLoader } from '@gitlab/ui'; import { GlSkeletonLoader, GlBadge } from '@gitlab/ui';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import SubscriptionDetailsTable from 'ee/admin/subscriptions/show/components/subscription_details_table.vue'; import SubscriptionDetailsTable from 'ee/admin/subscriptions/show/components/subscription_details_table.vue';
import { detailsLabels } from 'ee/admin/subscriptions/show/constants'; import { detailsLabels } from 'ee/admin/subscriptions/show/constants';
...@@ -14,6 +14,9 @@ const licenseDetails = [ ...@@ -14,6 +14,9 @@ const licenseDetails = [
detail: 'lastSync', detail: 'lastSync',
value: 'just now', value: 'just now',
}, },
{
detail: 'email',
},
]; ];
const hasFontWeightBold = (wrapper) => wrapper.classes('gl-font-weight-bold'); const hasFontWeightBold = (wrapper) => wrapper.classes('gl-font-weight-bold');
...@@ -26,6 +29,7 @@ describe('Subscription Details Table', () => { ...@@ -26,6 +29,7 @@ describe('Subscription Details Table', () => {
const findLabelCells = () => wrapper.findAllByTestId('details-label'); const findLabelCells = () => wrapper.findAllByTestId('details-label');
const findLastSyncRow = () => wrapper.findByTestId('row-lastsync'); const findLastSyncRow = () => wrapper.findByTestId('row-lastsync');
const findClipboardButton = () => wrapper.findComponent(ClipboardButton); const findClipboardButton = () => wrapper.findComponent(ClipboardButton);
const findTypeBadge = () => wrapper.findComponent(GlBadge);
const hasClass = (className) => (w) => w.classes(className); const hasClass = (className) => (w) => w.classes(className);
const isNotLastSyncRow = (w) => w.attributes('data-testid') !== 'row-lastsync'; const isNotLastSyncRow = (w) => w.attributes('data-testid') !== 'row-lastsync';
...@@ -45,8 +49,8 @@ describe('Subscription Details Table', () => { ...@@ -45,8 +49,8 @@ describe('Subscription Details Table', () => {
}); });
it('displays the correct number of rows', () => { it('displays the correct number of rows', () => {
expect(findLabelCells()).toHaveLength(2); expect(findLabelCells()).toHaveLength(licenseDetails.length);
expect(findContentCells()).toHaveLength(2); expect(findContentCells()).toHaveLength(licenseDetails.length);
}); });
it('displays the correct content for rows', () => { it('displays the correct content for rows', () => {
...@@ -62,9 +66,39 @@ describe('Subscription Details Table', () => { ...@@ -62,9 +66,39 @@ describe('Subscription Details Table', () => {
expect(findClipboardButton().exists()).toBe(false); expect(findClipboardButton().exists()).toBe(false);
}); });
it('does not show a badge', () => {
expect(findTypeBadge().exists()).toBe(false);
});
it('shows the default row color', () => { it('shows the default row color', () => {
expect(findLastSyncRow().classes('gl-text-gray-800')).toBe(true); expect(findLastSyncRow().classes('gl-text-gray-800')).toBe(true);
}); });
it('displays a dash for empty values', () => {
expect(findLabelCells().at(2).text()).toBe(`${detailsLabels.email}:`);
expect(findContentCells().at(2).text()).toBe('-');
});
});
describe('with type detail', () => {
beforeEach(() => {
createComponent({
details: [
{
detail: 'type',
value: 'My type',
},
],
});
});
it('shows a badge', () => {
expect(findTypeBadge().exists()).toBe(true);
});
it('displays the correct text', () => {
expect(findContentCells().at(0).text()).toBe('My type');
});
}); });
describe('with copy-able detail', () => { describe('with copy-able detail', () => {
......
...@@ -13,7 +13,7 @@ export const license = { ...@@ -13,7 +13,7 @@ export const license = {
name: 'Jane Doe', name: 'Jane Doe',
plan: 'ultimate', plan: 'ultimate',
startsAt: '2021-03-11', startsAt: '2021-03-11',
type: subscriptionTypes.CLOUD, type: subscriptionTypes.ONLINE_CLOUD,
usersInLicenseCount: '10', usersInLicenseCount: '10',
usersOverLicenseCount: '0', usersOverLicenseCount: '0',
}, },
...@@ -29,7 +29,7 @@ export const license = { ...@@ -29,7 +29,7 @@ export const license = {
name: 'Jane Doe', name: 'Jane Doe',
plan: 'ultimate', plan: 'ultimate',
startsAt: '2022-03-16', startsAt: '2022-03-16',
type: subscriptionTypes.CLOUD, type: subscriptionTypes.ONLINE_CLOUD,
usersInLicenseCount: '10', usersInLicenseCount: '10',
usersOverLicenseCount: '0', usersOverLicenseCount: '0',
}, },
...@@ -45,7 +45,7 @@ export const subscriptionPastHistory = [ ...@@ -45,7 +45,7 @@ export const subscriptionPastHistory = [
name: 'Jane Doe', name: 'Jane Doe',
plan: 'ultimate', plan: 'ultimate',
startsAt: '2021-03-11', startsAt: '2021-03-11',
type: subscriptionTypes.CLOUD, type: subscriptionTypes.ONLINE_CLOUD,
usersInLicenseCount: '10', usersInLicenseCount: '10',
}, },
{ {
...@@ -70,7 +70,7 @@ export const subscriptionFutureHistory = [ ...@@ -70,7 +70,7 @@ export const subscriptionFutureHistory = [
name: 'Jane Doe', name: 'Jane Doe',
plan: 'ultimate', plan: 'ultimate',
startsAt: '2022-03-11', startsAt: '2022-03-11',
type: subscriptionTypes.CLOUD, type: subscriptionTypes.OFFLINE_CLOUD,
usersInLicenseCount: '15', usersInLicenseCount: '15',
}, },
{ {
...@@ -80,7 +80,7 @@ export const subscriptionFutureHistory = [ ...@@ -80,7 +80,7 @@ export const subscriptionFutureHistory = [
name: 'Jane Doe', name: 'Jane Doe',
plan: 'ultimate', plan: 'ultimate',
startsAt: '2021-03-16', startsAt: '2021-03-16',
type: subscriptionTypes.CLOUD, type: subscriptionTypes.ONLINE_CLOUD,
usersInLicenseCount: '10', usersInLicenseCount: '10',
}, },
]; ];
......
import { getErrorsAsData, getLicenseFromData } from 'ee/admin/subscriptions/show/graphql/utils'; import {
subscriptionTypes,
describe('graphQl utils', () => { offlineCloudLicenseText,
onlineCloudLicenseText,
licenseFileText,
} from 'ee/admin/subscriptions/show/constants';
import {
getErrorsAsData,
getLicenseFromData,
getLicenseTypeLabel,
} from 'ee/admin/subscriptions/show/utils';
describe('utils', () => {
describe('getLicenseFromData', () => { describe('getLicenseFromData', () => {
const license = { id: 'license-id' }; const license = { id: 'license-id' };
const gitlabSubscriptionActivate = { license }; const gitlabSubscriptionActivate = { license };
...@@ -58,4 +68,16 @@ describe('graphQl utils', () => { ...@@ -58,4 +68,16 @@ describe('graphQl utils', () => {
expect(result).toEqual([]); expect(result).toEqual([]);
}); });
}); });
describe('getLicenseTypeLabel', () => {
const typeLabels = {
OFFLINE_CLOUD: offlineCloudLicenseText,
ONLINE_CLOUD: onlineCloudLicenseText,
LICENSE_FILE: licenseFileText,
};
it.each(Object.keys(subscriptionTypes))('should return correct label for type', (key) => {
expect(getLicenseTypeLabel(subscriptionTypes[key])).toBe(typeLabels[key]);
});
});
}); });
...@@ -24,19 +24,21 @@ RSpec.describe Resolvers::Admin::CloudLicenses::SubscriptionFutureEntriesResolve ...@@ -24,19 +24,21 @@ RSpec.describe Resolvers::Admin::CloudLicenses::SubscriptionFutureEntriesResolve
end end
end end
context 'when no subscriptions exist' do context 'when no subscriptions exist', :enable_admin_mode do
it 'returns an empty array', :enable_admin_mode do it 'returns an empty array' do
allow(::Gitlab::CurrentSettings).to receive(:future_subscriptions).and_return([]) allow(::Gitlab::CurrentSettings).to receive(:future_subscriptions).and_return([])
expect(result).to eq([]) expect(result).to eq([])
end end
end end
context 'when future subscriptions exist' do context 'when future subscriptions exist', :enable_admin_mode do
let(:cloud_license_enabled) { true } let(:cloud_license_enabled) { true }
let(:offline_cloud_licensing) { false }
let(:subscription) do let(:subscription) do
{ {
'cloud_license_enabled' => cloud_license_enabled, 'cloud_license_enabled' => cloud_license_enabled,
'offline_cloud_licensing' => offline_cloud_licensing,
'plan' => 'ultimate', 'plan' => 'ultimate',
'name' => 'User Example', 'name' => 'User Example',
'email' => 'user@example.com', 'email' => 'user@example.com',
...@@ -51,11 +53,11 @@ RSpec.describe Resolvers::Admin::CloudLicenses::SubscriptionFutureEntriesResolve ...@@ -51,11 +53,11 @@ RSpec.describe Resolvers::Admin::CloudLicenses::SubscriptionFutureEntriesResolve
allow(::Gitlab::CurrentSettings).to receive(:future_subscriptions).and_return([subscription]) allow(::Gitlab::CurrentSettings).to receive(:future_subscriptions).and_return([subscription])
end end
it 'returns the subscription future entries', :enable_admin_mode do it 'returns the subscription future entries' do
expect(result).to match( expect(result).to match(
[ [
hash_including( hash_including(
'type' => 'cloud', 'type' => License::CLOUD_LICENSE_TYPE,
'plan' => 'ultimate', 'plan' => 'ultimate',
'name' => 'User Example', 'name' => 'User Example',
'email' => 'user@example.com', 'email' => 'user@example.com',
...@@ -71,8 +73,16 @@ RSpec.describe Resolvers::Admin::CloudLicenses::SubscriptionFutureEntriesResolve ...@@ -71,8 +73,16 @@ RSpec.describe Resolvers::Admin::CloudLicenses::SubscriptionFutureEntriesResolve
context 'cloud_license_enabled is false' do context 'cloud_license_enabled is false' do
let(:cloud_license_enabled) { false } let(:cloud_license_enabled) { false }
it 'returns type as license_file', :enable_admin_mode do it 'returns type as license_file' do
expect(result.first).to include('type' => 'license_file') expect(result.first).to include('type' => License::LICENSE_FILE_TYPE)
end
end
context 'cloud_license_enabled is true and offline_cloud_licensing is true' do
let(:offline_cloud_licensing) { true }
it 'returns type as offline_cloud' do
expect(result.first).to include('type' => License::OFFLINE_CLOUD_TYPE)
end end
end end
end end
......
...@@ -1640,11 +1640,17 @@ RSpec.describe License do ...@@ -1640,11 +1640,17 @@ RSpec.describe License do
it { is_expected.to eq(described_class::LICENSE_FILE_TYPE) } it { is_expected.to eq(described_class::LICENSE_FILE_TYPE) }
end end
context 'when the license is a cloud license' do context 'when the license is an online cloud license' do
let(:gl_license) { build(:gitlab_license, cloud_licensing_enabled: true) } let(:gl_license) { build(:gitlab_license, cloud_licensing_enabled: true) }
it { is_expected.to eq(described_class::CLOUD_LICENSE_TYPE) } it { is_expected.to eq(described_class::CLOUD_LICENSE_TYPE) }
end end
context 'when the license is an offline cloud license' do
let(:gl_license) { build(:gitlab_license, cloud_licensing_enabled: true, offline_cloud_licensing_enabled: true) }
it { is_expected.to eq(described_class::OFFLINE_CLOUD_TYPE) }
end
end end
describe '#auto_renew' do describe '#auto_renew' do
......
...@@ -35558,6 +35558,9 @@ msgstr "" ...@@ -35558,6 +35558,9 @@ msgstr ""
msgid "SuperSonics|Maximum users" msgid "SuperSonics|Maximum users"
msgstr "" msgstr ""
msgid "SuperSonics|Offline cloud"
msgstr ""
msgid "SuperSonics|Paste your activation code" msgid "SuperSonics|Paste your activation code"
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