Disabling License Banners (#19116)
* work in progress: got the expired banner set with license check * wip: got the logic for both banners, need to test and write tests * add notes * prep for test writing * test coverage * add changelog * clean up * clarify dismissTypes and conditionals * updates * update comment * update comment * address pr comments * update test * small naming change * small naming changes * clean localStorage * comment clean up * another comment clean up * remove meep * add test coverage for new method in localStorage
This commit is contained in:
parent
d0925f3661
commit
3003ff85ce
|
@ -0,0 +1,3 @@
|
|||
```release-note:improvement
|
||||
ui: Allows license-banners to be dismissed. Saves preferences in localStorage.
|
||||
```
|
|
@ -1,3 +1,11 @@
|
|||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { inject as service } from '@ember/service';
|
||||
import isAfter from 'date-fns/isAfter';
|
||||
import differenceInDays from 'date-fns/differenceInDays';
|
||||
import localStorage from 'vault/lib/local-storage';
|
||||
|
||||
/**
|
||||
* @module LicenseBanners
|
||||
* LicenseBanners components are used to display Vault-specific license expiry messages
|
||||
|
@ -9,11 +17,23 @@
|
|||
* @param {string} expiry - RFC3339 date timestamp
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import isAfter from 'date-fns/isAfter';
|
||||
import differenceInDays from 'date-fns/differenceInDays';
|
||||
|
||||
export default class LicenseBanners extends Component {
|
||||
@service version;
|
||||
|
||||
@tracked warningDismissed;
|
||||
@tracked expiredDismissed;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
// do not dismiss any banners if the user has updated their version
|
||||
const dismissedBanner = localStorage.getItem(`dismiss-license-banner-${this.currentVersion}`); // returns either warning or expired
|
||||
this.updateDismissType(dismissedBanner);
|
||||
}
|
||||
|
||||
get currentVersion() {
|
||||
return this.version.version;
|
||||
}
|
||||
|
||||
get licenseExpired() {
|
||||
if (!this.args.expiry) return false;
|
||||
return isAfter(new Date(), new Date(this.args.expiry));
|
||||
|
@ -24,4 +44,22 @@ export default class LicenseBanners extends Component {
|
|||
if (!this.args.expiry) return 99;
|
||||
return differenceInDays(new Date(this.args.expiry), new Date());
|
||||
}
|
||||
|
||||
@action
|
||||
dismissBanner(dismissAction) {
|
||||
// if a client's version changed their old localStorage key will still exists.
|
||||
localStorage.cleanUpStorage('dismiss-license-banner', `dismiss-license-banner-${this.currentVersion}`);
|
||||
// updates localStorage and then updates the template by calling updateDismissType
|
||||
localStorage.setItem(`dismiss-license-banner-${this.currentVersion}`, dismissAction);
|
||||
this.updateDismissType(dismissAction);
|
||||
}
|
||||
|
||||
updateDismissType(dismissType) {
|
||||
// updates tracked properties to update template
|
||||
if (dismissType === 'warning') {
|
||||
this.warningDismissed = true;
|
||||
} else if (dismissType === 'expired') {
|
||||
this.expiredDismissed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,4 +15,14 @@ export default {
|
|||
keys() {
|
||||
return Object.keys(window.localStorage);
|
||||
},
|
||||
|
||||
cleanUpStorage(string, keyToKeep) {
|
||||
if (!string) return;
|
||||
const relevantKeys = this.keys().filter((str) => str.startsWith(string));
|
||||
relevantKeys?.forEach((key) => {
|
||||
if (key !== keyToKeep) {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{#if this.licenseExpired}}
|
||||
{{#if (and this.licenseExpired (not this.expiredDismissed))}}
|
||||
<div class="license-banner-wrapper" data-test-license-banner data-test-license-banner-expired>
|
||||
<AlertBanner
|
||||
@type="danger"
|
||||
|
@ -13,9 +13,12 @@
|
|||
<Icon @name="learn-link" />
|
||||
Read documentation
|
||||
</DocLink>
|
||||
<button type="button" class="close-button" {{on "click" (fn this.dismissBanner "expired")}} data-test-dismiss-expired>
|
||||
<Icon @name="x" aria-label="dismiss license expired warning" />
|
||||
</button>
|
||||
</AlertBanner>
|
||||
</div>
|
||||
{{else if (lte this.licenseExpiringInDays 30)}}
|
||||
{{else if (and (lte this.licenseExpiringInDays 30) (not this.warningDismissed))}}
|
||||
<div class="license-banner-wrapper" data-test-license-banner data-test-license-banner-warning>
|
||||
<AlertBanner
|
||||
@type="warning"
|
||||
|
@ -34,6 +37,9 @@
|
|||
<Icon @name="learn-link" />
|
||||
Read documentation
|
||||
</DocLink>
|
||||
<button type="button" class="close-button" {{on "click" (fn this.dismissBanner "warning")}} data-test-dismiss-warning>
|
||||
<Icon @name="x" aria-label="dismiss license expire soon warning" />
|
||||
</button>
|
||||
</AlertBanner>
|
||||
</div>
|
||||
{{/if}}
|
|
@ -1,39 +1,107 @@
|
|||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import { render, click } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
import subDays from 'date-fns/subDays';
|
||||
import addDays from 'date-fns/addDays';
|
||||
import formatRFC3339 from 'date-fns/formatRFC3339';
|
||||
|
||||
const YESTERDAY = subDays(new Date(), 1);
|
||||
const NEXT_MONTH = addDays(new Date(), 30);
|
||||
|
||||
module('Integration | Component | license-banners', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.version = this.owner.lookup('service:version');
|
||||
this.version.version = '1.13.1+ent';
|
||||
});
|
||||
|
||||
test('it does not render if no expiry', async function (assert) {
|
||||
assert.expect(1);
|
||||
await render(hbs`<LicenseBanners />`);
|
||||
assert.dom('[data-test-license-banner]').doesNotExist('License banner does not render');
|
||||
});
|
||||
|
||||
test('it renders an error if expiry is before now', async function (assert) {
|
||||
const yesterday = subDays(new Date(), 1);
|
||||
this.set('expiry', formatRFC3339(yesterday));
|
||||
assert.expect(2);
|
||||
this.set('expiry', formatRFC3339(YESTERDAY));
|
||||
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
||||
assert.dom('[data-test-license-banner-expired]').exists('Expired license banner renders');
|
||||
assert.dom('.message-title').hasText('License expired', 'Shows correct title on alert');
|
||||
});
|
||||
|
||||
test('it renders a warning if expiry is within 30 days', async function (assert) {
|
||||
const nextMonth = addDays(new Date(), 30);
|
||||
this.set('expiry', formatRFC3339(nextMonth));
|
||||
assert.expect(2);
|
||||
this.set('expiry', formatRFC3339(NEXT_MONTH));
|
||||
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
||||
assert.dom('[data-test-license-banner-warning]').exists('Warning license banner renders');
|
||||
assert.dom('.message-title').hasText('Vault license expiring', 'Shows correct title on alert');
|
||||
});
|
||||
|
||||
test('it does not render a banner if expiry is outside 30 days', async function (assert) {
|
||||
assert.expect(1);
|
||||
const outside30 = addDays(new Date(), 32);
|
||||
this.set('expiry', formatRFC3339(outside30));
|
||||
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
||||
assert.dom('[data-test-license-banner]').doesNotExist('License banner does not render');
|
||||
});
|
||||
|
||||
test('it does not render the expired banner if it has been dismissed', async function (assert) {
|
||||
assert.expect(3);
|
||||
this.set('expiry', formatRFC3339(YESTERDAY));
|
||||
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
||||
await click('[data-test-dismiss-expired]');
|
||||
assert.dom('[data-test-license-banner-expired]').doesNotExist('Expired license banner does not render');
|
||||
|
||||
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
||||
const localStorageResult = JSON.parse(localStorage.getItem(`dismiss-license-banner-1.13.1+ent`));
|
||||
assert.strictEqual(localStorageResult, 'expired');
|
||||
assert
|
||||
.dom('[data-test-license-banner-expired]')
|
||||
.doesNotExist('The expired banner still does not render after a re-render.');
|
||||
localStorage.removeItem(`dismiss-license-banner-1.13.1+ent`);
|
||||
});
|
||||
|
||||
test('it does not render the warning banner if it has been dismissed', async function (assert) {
|
||||
assert.expect(3);
|
||||
this.set('expiry', formatRFC3339(NEXT_MONTH));
|
||||
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
||||
await click('[data-test-dismiss-warning]');
|
||||
assert.dom('[data-test-license-banner-warning]').doesNotExist('Warning license banner does not render');
|
||||
|
||||
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
||||
const localStorageResult = JSON.parse(localStorage.getItem(`dismiss-license-banner-1.13.1+ent`));
|
||||
assert.strictEqual(localStorageResult, 'warning');
|
||||
assert
|
||||
.dom('[data-test-license-banner-warning]')
|
||||
.doesNotExist('The warning banner still does not render after a re-render.');
|
||||
localStorage.removeItem(`dismiss-license-banner-1.13.1+ent`);
|
||||
});
|
||||
|
||||
test('it renders a banner if the vault license has changed', async function (assert) {
|
||||
assert.expect(3);
|
||||
this.version.version = '1.12.1+ent';
|
||||
this.set('expiry', formatRFC3339(NEXT_MONTH));
|
||||
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
||||
await click('[data-test-dismiss-warning]');
|
||||
this.version.version = '1.13.1+ent';
|
||||
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
||||
assert
|
||||
.dom('[data-test-license-banner-warning]')
|
||||
.exists('The warning banner shows even though we have dismissed it earlier.');
|
||||
|
||||
await click('[data-test-dismiss-warning]');
|
||||
const localStorageResultNewVersion = JSON.parse(
|
||||
localStorage.getItem(`dismiss-license-banner-1.13.1+ent`)
|
||||
);
|
||||
const localStorageResultOldVersion = JSON.parse(
|
||||
localStorage.getItem(`dismiss-license-banner-1.12.1+ent`)
|
||||
);
|
||||
// Check that localStorage was cleaned and no longer contains the old version storage key.
|
||||
assert.strictEqual(localStorageResultOldVersion, null);
|
||||
assert.strictEqual(localStorageResultNewVersion, 'warning');
|
||||
// If debugging this test remember to clear localStorage if the test was not run to completion.
|
||||
localStorage.removeItem(`dismiss-license-banner-1.13.1+ent`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
import LocalStorage from 'vault/lib/local-storage';
|
||||
|
||||
module('Unit | lib | local-storage', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
window.localStorage.clear();
|
||||
});
|
||||
|
||||
test('it does not error if nothing is in local storage', async function (assert) {
|
||||
assert.expect(1);
|
||||
assert.strictEqual(
|
||||
LocalStorage.cleanUpStorage('something', 'something-key'),
|
||||
undefined,
|
||||
'returns undefined and does not throw an error when method is called and nothing exist in localStorage.'
|
||||
);
|
||||
});
|
||||
|
||||
test('it does not remove anything in localStorage that does not start with the string or we have specified to keep.', async function (assert) {
|
||||
assert.expect(3);
|
||||
LocalStorage.setItem('string-key-remove', 'string-key-remove-value');
|
||||
LocalStorage.setItem('beep-boop-bop-key', 'beep-boop-bop-value');
|
||||
LocalStorage.setItem('string-key', 'string-key-value');
|
||||
const storageLengthBefore = window.localStorage.length;
|
||||
LocalStorage.cleanUpStorage('string', 'string-key');
|
||||
const storageLengthAfter = window.localStorage.length;
|
||||
assert.strictEqual(
|
||||
storageLengthBefore - storageLengthAfter,
|
||||
1,
|
||||
'the method should only remove one key from localStorage.'
|
||||
);
|
||||
assert.strictEqual(
|
||||
LocalStorage.getItem('string-key'),
|
||||
'string-key-value',
|
||||
'the key we asked to keep still exists in localStorage.'
|
||||
);
|
||||
assert.strictEqual(
|
||||
LocalStorage.getItem('string-key-remove'),
|
||||
null,
|
||||
'the key we did not specify to keep was removed from localStorage.'
|
||||
);
|
||||
// clear storage
|
||||
window.localStorage.clear();
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue