Commit 51bb42cb authored by Angelo Gulina's avatar Angelo Gulina Committed by Andrew Fontaine

Add remove button with confirmation

parent 2393b1eb
...@@ -8,6 +8,7 @@ import { ...@@ -8,6 +8,7 @@ import {
manageSubscriptionButtonText, manageSubscriptionButtonText,
notificationType, notificationType,
removeLicense, removeLicense,
removeLicenseConfirm,
subscriptionDetailsHeaderText, subscriptionDetailsHeaderText,
subscriptionType, subscriptionType,
syncSubscriptionButtonText, syncSubscriptionButtonText,
...@@ -28,6 +29,7 @@ export default { ...@@ -28,6 +29,7 @@ export default {
licensedToHeaderText, licensedToHeaderText,
manageSubscriptionButtonText, manageSubscriptionButtonText,
removeLicense, removeLicense,
removeLicenseConfirm,
subscriptionDetailsHeaderText, subscriptionDetailsHeaderText,
syncSubscriptionButtonText, syncSubscriptionButtonText,
uploadLicense, uploadLicense,
...@@ -47,7 +49,7 @@ export default { ...@@ -47,7 +49,7 @@ export default {
SubscriptionDetailsUserInfo, SubscriptionDetailsUserInfo,
SubscriptionSyncNotifications: () => import('./subscription_sync_notifications.vue'), SubscriptionSyncNotifications: () => import('./subscription_sync_notifications.vue'),
}, },
inject: ['customersPortalUrl', 'licenseUploadPath', 'subscriptionSyncPath'], inject: ['customersPortalUrl', 'licenseRemovePath', 'licenseUploadPath', 'subscriptionSyncPath'],
props: { props: {
subscription: { subscription: {
type: Object, type: Object,
...@@ -77,7 +79,7 @@ export default { ...@@ -77,7 +79,7 @@ export default {
return this.licenseUploadPath && this.isLegacyType; return this.licenseUploadPath && this.isLegacyType;
}, },
canRemoveLicense() { canRemoveLicense() {
return false; return this.licenseRemovePath && this.isLegacyType;
}, },
hasSubscription() { hasSubscription() {
return Boolean(Object.keys(this.subscription).length); return Boolean(Object.keys(this.subscription).length);
...@@ -172,6 +174,7 @@ export default { ...@@ -172,6 +174,7 @@ export default {
category="secondary" category="secondary"
variant="confirm" variant="confirm"
data-testid="license-upload-action" data-testid="license-upload-action"
data-qa-selector="license_upload_link"
> >
{{ $options.i18n.uploadLicense }} {{ $options.i18n.uploadLicense }}
</gl-button> </gl-button>
...@@ -189,7 +192,11 @@ export default { ...@@ -189,7 +192,11 @@ export default {
v-if="canRemoveLicense" v-if="canRemoveLicense"
category="secondary" category="secondary"
variant="danger" variant="danger"
:href="licenseRemovePath"
:data-confirm="$options.i18n.removeLicenseConfirm"
data-method="delete"
data-testid="license-remove-action" data-testid="license-remove-action"
data-qa-selector="remove_license_link"
> >
{{ $options.i18n.removeLicense }} {{ $options.i18n.removeLicense }}
</gl-button> </gl-button>
......
...@@ -107,15 +107,20 @@ export default { ...@@ -107,15 +107,20 @@ export default {
}, },
methods: { methods: {
cellClass(_, x, item) { cellClass(_, x, item) {
return item.id === this.currentSubscriptionId ? tdClassHighlight : tdClassBase; return this.isCurrentSubscription(item) ? tdClassHighlight : tdClassBase;
}, },
rowAttr() { isCurrentSubscription({ id }) {
return id === this.currentSubscriptionId;
},
rowAttr(item) {
return { return {
'data-testid': 'subscription-history-row', 'data-testid': this.isCurrentSubscription(item)
? 'subscription-current'
: 'subscription-history-row',
}; };
}, },
rowClass(item) { rowClass(item) {
return item.id === this.currentSubscriptionId ? 'gl-font-weight-bold gl-text-blue-500' : ''; return this.isCurrentSubscription(item) ? 'gl-font-weight-bold gl-text-blue-500' : '';
}, },
}, },
}; };
......
...@@ -38,6 +38,7 @@ export const detailsLabels = { ...@@ -38,6 +38,7 @@ export const detailsLabels = {
}; };
export const removeLicense = __('Remove license'); export const removeLicense = __('Remove license');
export const removeLicenseConfirm = __('Are you sure you want to remove the license?');
export const uploadLicense = __('Upload license'); export const uploadLicense = __('Upload license');
export const uploadLegacyLicense = s__('SuperSonics|Upload a legacy license'); export const uploadLegacyLicense = s__('SuperSonics|Upload a legacy license');
export const billableUsersTitle = s__('CloudLicense|Billable users'); export const billableUsersTitle = s__('CloudLicense|Billable users');
......
...@@ -28,6 +28,7 @@ export default () => { ...@@ -28,6 +28,7 @@ export default () => {
customersPortalUrl, customersPortalUrl,
freeTrialPath, freeTrialPath,
hasActiveLicense, hasActiveLicense,
licenseRemovePath,
licenseUploadPath, licenseUploadPath,
subscriptionSyncPath, subscriptionSyncPath,
} = el.dataset; } = el.dataset;
...@@ -43,6 +44,7 @@ export default () => { ...@@ -43,6 +44,7 @@ export default () => {
connectivityHelpURL, connectivityHelpURL,
customersPortalUrl, customersPortalUrl,
freeTrialPath, freeTrialPath,
licenseRemovePath,
licenseUploadPath, licenseUploadPath,
subscriptionSyncPath, subscriptionSyncPath,
}, },
......
...@@ -59,6 +59,7 @@ module LicenseHelper ...@@ -59,6 +59,7 @@ module LicenseHelper
free_trial_path: new_trial_url, free_trial_path: new_trial_url,
has_active_license: (has_active_license? ? 'true' : 'false'), has_active_license: (has_active_license? ? 'true' : 'false'),
license_upload_path: new_admin_license_path, license_upload_path: new_admin_license_path,
license_remove_path: admin_license_path,
subscription_sync_path: sync_seat_link_admin_license_path subscription_sync_path: sync_seat_link_admin_license_path
} }
end end
......
...@@ -11,36 +11,60 @@ RSpec.describe 'Admin views Cloud License', :js do ...@@ -11,36 +11,60 @@ RSpec.describe 'Admin views Cloud License', :js do
stub_application_setting(cloud_license_enabled: true) stub_application_setting(cloud_license_enabled: true)
end end
context 'Cloud license' do context 'with a cloud license' do
let_it_be(:license) { create_current_license(cloud_licensing_enabled: true, plan: License::ULTIMATE_PLAN) } let!(:license) { create_current_license(cloud_licensing_enabled: true, plan: License::ULTIMATE_PLAN) }
before do context 'with a cloud license only' do
visit(admin_cloud_license_path) before do
end visit(admin_cloud_license_path)
end
it 'displays the subscription details' do it 'displays the subscription details' do
page.within(find('#content-body', match: :first)) do page.within(find('#content-body', match: :first)) do
expect(page).to have_content('Subscription details') expect(page).to have_content('Subscription details')
expect(all("[data-testid='details-label']")[1]).to have_content('Plan:') expect(all("[data-testid='details-label']")[1]).to have_content('Plan:')
expect(all("[data-testid='details-content']")[1]).to have_content('Ultimate') expect(all("[data-testid='details-content']")[1]).to have_content('Ultimate')
end
end end
end
it 'succeeds to sync the subscription' do it 'succeeds to sync the subscription' do
page.within(find('#content-body', match: :first)) do page.within(find('#content-body', match: :first)) do
click_button('Sync subscription details') click_button('Sync subscription details')
expect(page).to have_content('The subscription details synced successfully') expect(page).to have_content('The subscription details synced successfully')
end
end
it 'fails to sync the subscription' do
create_current_license(cloud_licensing_enabled: true, plan: License::ULTIMATE_PLAN, expires_at: nil)
page.within(find('#content-body', match: :first)) do
click_button('Sync subscription details')
expect(page).to have_content('You can no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by troubleshooting the activation code')
end
end end
end end
end
it 'fails to sync the subscription' do context 'with a legacy license' do
create_current_license(cloud_licensing_enabled: true, plan: License::ULTIMATE_PLAN, expires_at: nil) let!(:license) { create_current_license(cloud_licensing_enabled: false, plan: License::ULTIMATE_PLAN) }
page.within(find('#content-body', match: :first)) do before do
click_button('Sync subscription details') visit(admin_cloud_license_path)
end
context 'when removing the a legacy license' do
before do
accept_alert do
click_on 'Remove license'
end
end
expect(page).to have_content('You can no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by troubleshooting the activation code') it 'shows a message saying the license was correctly removed' do
page.within(find('#content-body', match: :first)) do
expect(page).to have_content('The license was removed.')
end
end end
end end
end end
......
...@@ -33,6 +33,7 @@ describe('Subscription Breakdown', () => { ...@@ -33,6 +33,7 @@ describe('Subscription Breakdown', () => {
const [, legacyLicense] = subscriptionHistory; const [, legacyLicense] = subscriptionHistory;
const connectivityHelpURL = 'connectivity/help/url'; const connectivityHelpURL = 'connectivity/help/url';
const customersPortalUrl = 'customers.dot'; const customersPortalUrl = 'customers.dot';
const licenseRemovePath = '/license/remove/';
const licenseUploadPath = '/license/upload/'; const licenseUploadPath = '/license/upload/';
const subscriptionSyncPath = '/sync/path/'; const subscriptionSyncPath = '/sync/path/';
...@@ -41,6 +42,7 @@ describe('Subscription Breakdown', () => { ...@@ -41,6 +42,7 @@ describe('Subscription Breakdown', () => {
const findDetailsHistory = () => wrapper.findComponent(SubscriptionDetailsHistory); const findDetailsHistory = () => wrapper.findComponent(SubscriptionDetailsHistory);
const findDetailsUserInfo = () => wrapper.findComponent(SubscriptionDetailsUserInfo); const findDetailsUserInfo = () => wrapper.findComponent(SubscriptionDetailsUserInfo);
const findLicenseUploadAction = () => wrapper.findByTestId('license-upload-action'); const findLicenseUploadAction = () => wrapper.findByTestId('license-upload-action');
const findLicenseRemoveAction = () => wrapper.findByTestId('license-remove-action');
const findSubscriptionActivationAction = () => const findSubscriptionActivationAction = () =>
wrapper.findByTestId('subscription-activation-action'); wrapper.findByTestId('subscription-activation-action');
const findSubscriptionMangeAction = () => wrapper.findByTestId('subscription-manage-action'); const findSubscriptionMangeAction = () => wrapper.findByTestId('subscription-manage-action');
...@@ -64,6 +66,7 @@ describe('Subscription Breakdown', () => { ...@@ -64,6 +66,7 @@ describe('Subscription Breakdown', () => {
connectivityHelpURL, connectivityHelpURL,
customersPortalUrl, customersPortalUrl,
licenseUploadPath, licenseUploadPath,
licenseRemovePath,
subscriptionSyncPath, subscriptionSyncPath,
...provide, ...provide,
}, },
...@@ -154,7 +157,7 @@ describe('Subscription Breakdown', () => { ...@@ -154,7 +157,7 @@ describe('Subscription Breakdown', () => {
${undefined} | ${subscriptionType.CLOUD} | ${false} ${undefined} | ${subscriptionType.CLOUD} | ${false}
${undefined} | ${subscriptionType.LEGACY} | ${false} ${undefined} | ${subscriptionType.LEGACY} | ${false}
`( `(
'with url is $url and type is $type the sync buttons is shown: $shouldShow', 'with url is $url and type is $type the sync button is shown: $shouldShow',
({ url, type, shouldShow }) => { ({ url, type, shouldShow }) => {
const provide = { subscriptionSyncPath: url }; const provide = { subscriptionSyncPath: url };
const props = { subscription: { ...license.ULTIMATE, type } }; const props = { subscription: { ...license.ULTIMATE, type } };
...@@ -174,7 +177,7 @@ describe('Subscription Breakdown', () => { ...@@ -174,7 +177,7 @@ describe('Subscription Breakdown', () => {
${undefined} | ${subscriptionType.LEGACY} | ${false} ${undefined} | ${subscriptionType.LEGACY} | ${false}
${undefined} | ${subscriptionType.CLOUD} | ${false} ${undefined} | ${subscriptionType.CLOUD} | ${false}
`( `(
'with url is $url and type is $type the upload buttons is shown: $shouldShow', 'with url is $url and type is $type the upload button is shown: $shouldShow',
({ url, type, shouldShow }) => { ({ url, type, shouldShow }) => {
const provide = { licenseUploadPath: url }; const provide = { licenseUploadPath: url };
const props = { subscription: { ...license.ULTIMATE, type } }; const props = { subscription: { ...license.ULTIMATE, type } };
...@@ -190,7 +193,7 @@ describe('Subscription Breakdown', () => { ...@@ -190,7 +193,7 @@ describe('Subscription Breakdown', () => {
${customersPortalUrl} | ${true} ${customersPortalUrl} | ${true}
${''} | ${false} ${''} | ${false}
${undefined} | ${false} ${undefined} | ${false}
`('with url is $url the manage buttons is shown: $shouldShow', ({ url, shouldShow }) => { `('with url is $url the manage button is shown: $shouldShow', ({ url, shouldShow }) => {
const provide = { customersPortalUrl: url }; const provide = { customersPortalUrl: url };
const stubs = { GlCard, SubscriptionDetailsCard }; const stubs = { GlCard, SubscriptionDetailsCard };
createComponent({ provide, stubs }); createComponent({ provide, stubs });
...@@ -198,7 +201,25 @@ describe('Subscription Breakdown', () => { ...@@ -198,7 +201,25 @@ describe('Subscription Breakdown', () => {
expect(findSubscriptionMangeAction().exists()).toBe(shouldShow); expect(findSubscriptionMangeAction().exists()).toBe(shouldShow);
}); });
it.todo('should show a remove subscription button'); it.each`
url | type | shouldShow
${licenseRemovePath} | ${subscriptionType.LEGACY} | ${true}
${licenseRemovePath} | ${subscriptionType.CLOUD} | ${false}
${''} | ${subscriptionType.LEGACY} | ${false}
${''} | ${subscriptionType.CLOUD} | ${false}
${undefined} | ${subscriptionType.LEGACY} | ${false}
${undefined} | ${subscriptionType.CLOUD} | ${false}
`(
'with url is $url and type is $type the remove button is shown: $shouldShow',
({ url, type, shouldShow }) => {
const provide = { licenseRemovePath: url };
const props = { subscription: { ...license.ULTIMATE, type } };
const stubs = { GlCard, SubscriptionDetailsCard };
createComponent({ props, provide, stubs });
expect(findLicenseRemoveAction().exists()).toBe(shouldShow);
},
);
}); });
describe('with a legacy license', () => { describe('with a legacy license', () => {
......
...@@ -7,6 +7,7 @@ import { license, subscriptionHistory } from '../mock_data'; ...@@ -7,6 +7,7 @@ import { license, subscriptionHistory } from '../mock_data';
describe('Subscription Details History', () => { describe('Subscription Details History', () => {
let wrapper; let wrapper;
const findCurrentRow = () => wrapper.findByTestId('subscription-current');
const findTableRows = () => wrapper.findAllByTestId('subscription-history-row'); const findTableRows = () => wrapper.findAllByTestId('subscription-history-row');
const cellFinder = (row) => (testId) => extendedWrapper(row).findByTestId(testId); const cellFinder = (row) => (testId) => extendedWrapper(row).findByTestId(testId);
const containsABadge = (row) => row.findComponent(GlBadge).exists(); const containsABadge = (row) => row.findComponent(GlBadge).exists();
...@@ -32,13 +33,17 @@ describe('Subscription Details History', () => { ...@@ -32,13 +33,17 @@ describe('Subscription Details History', () => {
createComponent(); createComponent();
}); });
it('has the correct number of rows', () => { it('has a current subscription row', () => {
expect(findTableRows()).toHaveLength(2); expect(findCurrentRow().exists()).toBe(true);
});
it('has the correct number of subscription rows', () => {
expect(findTableRows()).toHaveLength(1);
}); });
it('has the correct license type', () => { it('has the correct license type', () => {
expect(findTableRows().at(0).text()).toContain('Cloud License'); expect(findCurrentRow().text()).toContain('Cloud License');
expect(findTableRows().at(1).text()).toContain('Legacy License'); expect(findTableRows().at(0).text()).toContain('Legacy License');
}); });
it('has a badge for the license type', () => { it('has a badge for the license type', () => {
...@@ -46,11 +51,11 @@ describe('Subscription Details History', () => { ...@@ -46,11 +51,11 @@ describe('Subscription Details History', () => {
}); });
it('highlights the current subscription row', () => { it('highlights the current subscription row', () => {
expect(findTableRows().at(0).classes('gl-text-blue-500')).toBe(true); expect(findCurrentRow().classes('gl-text-blue-500')).toBe(true);
}); });
it('does not highlight the current subscription row', () => { it('does not highlight the other subscription row', () => {
expect(findTableRows().at(1).classes('gl-text-blue-500')).toBe(false); expect(findTableRows().at(0).classes('gl-text-blue-500')).toBe(false);
}); });
describe('cell data', () => { describe('cell data', () => {
...@@ -58,7 +63,7 @@ describe('Subscription Details History', () => { ...@@ -58,7 +63,7 @@ describe('Subscription Details History', () => {
beforeEach(() => { beforeEach(() => {
createComponent(); createComponent();
findCellByTestid = cellFinder(findTableRows().at(0)); findCellByTestid = cellFinder(findCurrentRow());
}); });
it.each` it.each`
......
...@@ -98,7 +98,8 @@ RSpec.describe LicenseHelper do ...@@ -98,7 +98,8 @@ RSpec.describe LicenseHelper do
free_trial_path: 'new_trial_url', free_trial_path: 'new_trial_url',
buy_subscription_path: 'subscriptions_plans_url', buy_subscription_path: 'subscriptions_plans_url',
subscription_sync_path: sync_seat_link_admin_license_path, subscription_sync_path: sync_seat_link_admin_license_path,
license_upload_path: new_admin_license_path }) license_upload_path: new_admin_license_path,
license_remove_path: admin_license_path })
end end
end end
...@@ -111,7 +112,8 @@ RSpec.describe LicenseHelper do ...@@ -111,7 +112,8 @@ RSpec.describe LicenseHelper do
free_trial_path: 'new_trial_url', free_trial_path: 'new_trial_url',
buy_subscription_path: 'subscriptions_plans_url', buy_subscription_path: 'subscriptions_plans_url',
subscription_sync_path: sync_seat_link_admin_license_path, subscription_sync_path: sync_seat_link_admin_license_path,
license_upload_path: new_admin_license_path }) license_upload_path: new_admin_license_path,
license_remove_path: admin_license_path })
end end
end 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