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,9 +11,10 @@ RSpec.describe 'Admin views Cloud License', :js do ...@@ -11,9 +11,10 @@ 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) }
context 'with a cloud license only' do
before do before do
visit(admin_cloud_license_path) visit(admin_cloud_license_path)
end end
...@@ -44,6 +45,29 @@ RSpec.describe 'Admin views Cloud License', :js do ...@@ -44,6 +45,29 @@ RSpec.describe 'Admin views Cloud License', :js do
end end
end end
end end
end
context 'with a legacy license' do
let!(:license) { create_current_license(cloud_licensing_enabled: false, plan: License::ULTIMATE_PLAN) }
before do
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
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
context 'when there is no license' do context 'when there is no license' do
let_it_be(:license) { nil } let_it_be(:license) { nil }
......
...@@ -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