mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-01 02:57:59 +00:00
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:
3
changelog/19116.txt
Normal file
3
changelog/19116.txt
Normal file
@@ -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
|
* @module LicenseBanners
|
||||||
* LicenseBanners components are used to display Vault-specific license expiry messages
|
* LicenseBanners components are used to display Vault-specific license expiry messages
|
||||||
@@ -9,11 +17,23 @@
|
|||||||
* @param {string} expiry - RFC3339 date timestamp
|
* @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 {
|
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() {
|
get licenseExpired() {
|
||||||
if (!this.args.expiry) return false;
|
if (!this.args.expiry) return false;
|
||||||
return isAfter(new Date(), new Date(this.args.expiry));
|
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;
|
if (!this.args.expiry) return 99;
|
||||||
return differenceInDays(new Date(this.args.expiry), new Date());
|
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() {
|
keys() {
|
||||||
return Object.keys(window.localStorage);
|
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>
|
<div class="license-banner-wrapper" data-test-license-banner data-test-license-banner-expired>
|
||||||
<AlertBanner
|
<AlertBanner
|
||||||
@type="danger"
|
@type="danger"
|
||||||
@@ -13,9 +13,12 @@
|
|||||||
<Icon @name="learn-link" />
|
<Icon @name="learn-link" />
|
||||||
Read documentation
|
Read documentation
|
||||||
</DocLink>
|
</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>
|
</AlertBanner>
|
||||||
</div>
|
</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>
|
<div class="license-banner-wrapper" data-test-license-banner data-test-license-banner-warning>
|
||||||
<AlertBanner
|
<AlertBanner
|
||||||
@type="warning"
|
@type="warning"
|
||||||
@@ -34,6 +37,9 @@
|
|||||||
<Icon @name="learn-link" />
|
<Icon @name="learn-link" />
|
||||||
Read documentation
|
Read documentation
|
||||||
</DocLink>
|
</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>
|
</AlertBanner>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -1,39 +1,107 @@
|
|||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
import { setupRenderingTest } from 'ember-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 { hbs } from 'ember-cli-htmlbars';
|
||||||
import subDays from 'date-fns/subDays';
|
import subDays from 'date-fns/subDays';
|
||||||
import addDays from 'date-fns/addDays';
|
import addDays from 'date-fns/addDays';
|
||||||
import formatRFC3339 from 'date-fns/formatRFC3339';
|
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) {
|
module('Integration | Component | license-banners', function (hooks) {
|
||||||
setupRenderingTest(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) {
|
test('it does not render if no expiry', async function (assert) {
|
||||||
|
assert.expect(1);
|
||||||
await render(hbs`<LicenseBanners />`);
|
await render(hbs`<LicenseBanners />`);
|
||||||
assert.dom('[data-test-license-banner]').doesNotExist('License banner does not render');
|
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) {
|
test('it renders an error if expiry is before now', async function (assert) {
|
||||||
const yesterday = subDays(new Date(), 1);
|
assert.expect(2);
|
||||||
this.set('expiry', formatRFC3339(yesterday));
|
this.set('expiry', formatRFC3339(YESTERDAY));
|
||||||
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
||||||
assert.dom('[data-test-license-banner-expired]').exists('Expired license banner renders');
|
assert.dom('[data-test-license-banner-expired]').exists('Expired license banner renders');
|
||||||
assert.dom('.message-title').hasText('License expired', 'Shows correct title on alert');
|
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) {
|
test('it renders a warning if expiry is within 30 days', async function (assert) {
|
||||||
const nextMonth = addDays(new Date(), 30);
|
assert.expect(2);
|
||||||
this.set('expiry', formatRFC3339(nextMonth));
|
this.set('expiry', formatRFC3339(NEXT_MONTH));
|
||||||
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
||||||
assert.dom('[data-test-license-banner-warning]').exists('Warning license banner renders');
|
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');
|
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) {
|
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);
|
const outside30 = addDays(new Date(), 32);
|
||||||
this.set('expiry', formatRFC3339(outside30));
|
this.set('expiry', formatRFC3339(outside30));
|
||||||
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
|
||||||
assert.dom('[data-test-license-banner]').doesNotExist('License banner does not render');
|
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`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
47
ui/tests/unit/lib/local-storage-test.js
Normal file
47
ui/tests/unit/lib/local-storage-test.js
Normal file
@@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user