diff --git a/changelog/23143.txt b/changelog/23143.txt new file mode 100644 index 0000000000..5db4d66d15 --- /dev/null +++ b/changelog/23143.txt @@ -0,0 +1,3 @@ +```release-note:improvement +ui: Surface warning banner if UI has stopped auto-refreshing token +``` diff --git a/ui/app/components/token-expire-warning.hbs b/ui/app/components/token-expire-warning.hbs new file mode 100644 index 0000000000..43d68c2039 --- /dev/null +++ b/ui/app/components/token-expire-warning.hbs @@ -0,0 +1,55 @@ +{{! + Copyright (c) HashiCorp, Inc. + SPDX-License-Identifier: BUSL-1.1 +~}} + +{{#if (and this.showWarning (is-after (now interval=1000) @expirationDate))}} + + Error + + Your auth token expired on + {{date-format @expirationDate "MMMM do yyyy, h:mm:ss a"}}. You will need to re-authenticate. + + + +{{else}} +
+
+ {{#if (and this.showWarning @allowingExpiration this.canDismiss)}} + + Session will expire + + We've stopped auto-renewing your token due to inactivity. It will expire in + {{date-from-now @expirationDate}} + on + {{date-format @expirationDate "MMMM do yyyy, h:mm:ss a O"}}. + + + + + {{/if}} + {{yield}} +
+
+{{/if}} \ No newline at end of file diff --git a/ui/app/components/token-expire-warning.js b/ui/app/components/token-expire-warning.js index 436668ad1f..5b9419bd9c 100644 --- a/ui/app/components/token-expire-warning.js +++ b/ui/app/components/token-expire-warning.js @@ -5,9 +5,36 @@ import Component from '@glimmer/component'; import { inject as service } from '@ember/service'; +import { tracked } from '@glimmer/tracking'; +import { later } from '@ember/runloop'; +import { task } from 'ember-concurrency'; export default class TokenExpireWarning extends Component { + @service auth; @service router; + @tracked canDismiss = true; + + handleRenew() { + return new Promise((resolve) => { + later(() => { + this.auth + .renew() + .then(() => { + // This renewal was triggered by an explicit user action, + // so this will reset the time inactive calculation + this.auth.setLastFetch(Date.now()); + }) + .finally(() => { + resolve(); + }); + }, 200); + }); + } + + @task + *renewToken() { + yield this.handleRenew(); + } get showWarning() { const currentRoute = this.router.currentRouteName; diff --git a/ui/app/templates/components/token-expire-warning.hbs b/ui/app/templates/components/token-expire-warning.hbs deleted file mode 100644 index 7a84d2b3ba..0000000000 --- a/ui/app/templates/components/token-expire-warning.hbs +++ /dev/null @@ -1,21 +0,0 @@ -{{! - Copyright (c) HashiCorp, Inc. - SPDX-License-Identifier: BUSL-1.1 -~}} - -{{#if (and this.showWarning (is-after (now interval=1000) @expirationDate))}} - - Error - - Your auth token expired on - {{date-format @expirationDate "MMMM do yyyy, h:mm:ss a"}}. You will need to re-authenticate. - - - -{{else}} -
-
- {{yield}} -
-
-{{/if}} \ No newline at end of file diff --git a/ui/app/templates/vault/cluster.hbs b/ui/app/templates/vault/cluster.hbs index 4cdaf50eac..da95a414eb 100644 --- a/ui/app/templates/vault/cluster.hbs +++ b/ui/app/templates/vault/cluster.hbs @@ -41,7 +41,7 @@ {{#if this.auth.isActiveSession}} - + {{outlet}} {{else}} diff --git a/ui/tests/integration/components/token-expire-warning-test.js b/ui/tests/integration/components/token-expire-warning-test.js index b36506c80a..4c1c70ecf0 100644 --- a/ui/tests/integration/components/token-expire-warning-test.js +++ b/ui/tests/integration/components/token-expire-warning-test.js @@ -18,7 +18,7 @@ module('Integration | Component | token-expire-warning', function (hooks) { await render(hbs``); await waitUntil(() => find('#modal-overlays')); - assert.dom().includesText('Your auth token expired on'); + assert.dom('[data-test-token-expired-banner]').includesText('Your auth token expired on'); }); test('it does not render a warning when the token is not expired', async function (assert) { @@ -30,8 +30,45 @@ module('Integration | Component | token-expire-warning', function (hooks) {

Do not worry, your token has not expired.

`); - await waitUntil(() => find('#modal-overlays')); assert.dom().doesNotIncludeText('Your auth token expired on'); assert.dom().includesText('Do not worry'); }); + + test('it renders a warning when the token is no longer renewing', async function (assert) { + const expirationDate = addMinutes(Date.now(), 3); + this.set('expirationDate', expirationDate); + this.set('allowingExpiration', false); + + await render( + hbs` + +

This is the content

+
+ ` + ); + assert.dom('[data-test-token-expired-banner]').doesNotExist('Does not show token expired banner'); + assert.dom('[data-test-token-expiring-banner]').doesNotExist('Does not show token expiring banner'); + assert.dom('[data-test-content]').hasText('This is the content'); + + await this.set('allowingExpiration', true); + assert.dom('[data-test-token-expired-banner]').doesNotExist('Does not show token expired banner'); + assert.dom('[data-test-token-expiring-banner]').exists('Shows token expiring banner'); + assert.dom('[data-test-content]').hasText('This is the content'); + }); + + test('Does not render a warning if no expiration date', async function (assert) { + this.set('expirationDate', null); + this.set('allowingExpiration', true); + + await render( + hbs` + +

This is the content

+
+ ` + ); + assert.dom('[data-test-token-expired-banner]').doesNotExist('Does not show token expired banner'); + assert.dom('[data-test-token-expiring-banner]').doesNotExist('Does not show token expiring banner'); + assert.dom('[data-test-content]').hasText('This is the content'); + }); });