diff --git a/addons/core/addon/components/form/authenticate/details/index.js b/addons/core/addon/components/form/authenticate/details/index.js
index 7a3ab5398..e1d13d887 100644
--- a/addons/core/addon/components/form/authenticate/details/index.js
+++ b/addons/core/addon/components/form/authenticate/details/index.js
@@ -6,7 +6,6 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
-import { run } from '@ember/runloop';
export default class FormAuthenticateDetailsComponent extends Component {
// =properties
@@ -36,7 +35,7 @@ export default class FormAuthenticateDetailsComponent extends Component {
*/
@action
submit(fn, creds) {
- run(() => this.resetPassword());
- run(() => fn(creds));
+ this.resetPassword();
+ fn(creds);
}
}
diff --git a/addons/core/addon/components/loading-button/index.hbs b/addons/core/addon/components/loading-button/index.hbs
index 48f2ecda8..2d3c5cb96 100644
--- a/addons/core/addon/components/loading-button/index.hbs
+++ b/addons/core/addon/components/loading-button/index.hbs
@@ -6,7 +6,7 @@
\ No newline at end of file
diff --git a/addons/core/addon/components/loading-button/index.js b/addons/core/addon/components/loading-button/index.js
index 2828c5120..d1e45227b 100644
--- a/addons/core/addon/components/loading-button/index.js
+++ b/addons/core/addon/components/loading-button/index.js
@@ -4,22 +4,13 @@
*/
import Component from '@glimmer/component';
-import { tracked } from '@glimmer/tracking';
-import { action } from '@ember/object';
-import { later } from '@ember/runloop';
+import { dropTask, timeout } from 'ember-concurrency';
export default class LoadingButton extends Component {
- // =actions
- @tracked isLoading = false;
+ // =attributes
- @action
- async toggleRefresh() {
- this.isLoading = true;
- try {
- await this.args.onClick();
- } catch (e) {
- console.error('Error while loading data', e);
- }
- later(() => (this.isLoading = false), 1000);
- }
+ toggleRefresh = dropTask(async () => {
+ await this.args.onClick();
+ await timeout(1000);
+ });
}
diff --git a/addons/core/addon/helpers/time-remaining.js b/addons/core/addon/helpers/time-remaining.js
index ebd98fb87..72e5b5610 100644
--- a/addons/core/addon/helpers/time-remaining.js
+++ b/addons/core/addon/helpers/time-remaining.js
@@ -19,10 +19,10 @@ export default class extends Helper {
// Parse the expiration time
const expirationTime = new Date(expiration_time);
- // Get the curent time
+ // Get the current time
const currentTime = this.clockTick.now;
- // Calculate the difference in milleseconds
+ // Calculate the difference in milliseconds
const difference = expirationTime - currentTime;
// Calculate the difference in seconds if the difference is positive
diff --git a/addons/core/addon/services/clock-tick.js b/addons/core/addon/services/clock-tick.js
index a2b16d217..04410d65b 100644
--- a/addons/core/addon/services/clock-tick.js
+++ b/addons/core/addon/services/clock-tick.js
@@ -6,7 +6,7 @@
import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { getOwner } from '@ember/application';
-import { next } from '@ember/runloop';
+import { task, timeout } from 'ember-concurrency';
export default class ClockTickService extends Service {
// =attributes
@@ -25,9 +25,15 @@ export default class ClockTickService extends Service {
frequency = 1000;
/**
- * The timer interval ID
+ * Updates the value of `now` every `frequency` milliseconds.
*/
- #timer;
+ _tick = task(async () => {
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ await timeout(this.frequency);
+ this.now = Date.now();
+ }
+ });
/**
* This service is enabled only in non-test environments.
@@ -45,7 +51,7 @@ export default class ClockTickService extends Service {
*/
constructor() {
super(...arguments);
- if (this.enabled) this._start();
+ if (this.enabled) this._tick.perform();
}
/**
@@ -53,31 +59,6 @@ export default class ClockTickService extends Service {
*/
willDestroy() {
super.willDestroy(...arguments);
- this._stop();
- }
-
- /**
- * Sets up the timer interval, calling `_tick()` every
- * `frequency` milliseconds.
- */
- _start() {
- const self = this;
- this.#timer = setInterval(function () {
- self._tick();
- }, this.frequency);
- }
-
- /**
- * Clears the timer interval.
- */
- _stop() {
- clearInterval(this.#timer);
- }
-
- /**
- * Updates the value of `now` within the next runloop.
- */
- _tick() {
- next(() => (this.now = Date.now()));
+ this._tick.cancelAll();
}
}
diff --git a/addons/core/ember-cli-build.js b/addons/core/ember-cli-build.js
index bd89a3103..33e53c525 100644
--- a/addons/core/ember-cli-build.js
+++ b/addons/core/ember-cli-build.js
@@ -14,6 +14,11 @@ module.exports = function (defaults) {
'ember-simple-auth': {
useSessionSetupMethod: true,
},
+ babel: {
+ plugins: [
+ require.resolve('ember-concurrency/async-arrow-task-transform'),
+ ],
+ },
});
/*
diff --git a/addons/core/index.js b/addons/core/index.js
index 1760d1a66..684173c84 100644
--- a/addons/core/index.js
+++ b/addons/core/index.js
@@ -10,6 +10,14 @@ var path = require('path');
module.exports = {
name: require('./package').name,
+ options: {
+ babel: {
+ plugins: [
+ require.resolve('ember-concurrency/async-arrow-task-transform'),
+ ],
+ },
+ },
+
included(app) {
this._super.included.apply(this, arguments);
this.includePublic(app);
diff --git a/addons/core/package.json b/addons/core/package.json
index 8f75a7dea..fb77460c6 100644
--- a/addons/core/package.json
+++ b/addons/core/package.json
@@ -39,6 +39,7 @@
"ember-cli-babel": "^8.2.0",
"ember-cli-htmlbars": "^6.2.0",
"ember-cli-sass": "^11.0.1",
+ "ember-concurrency": "^4.0.3",
"ember-feature-flags": "^6.0.0",
"ember-intl": "^7.0.7",
"ember-loading": "^2.0.0",
diff --git a/ui/admin/app/components/form/account/password/change-password/index.js b/ui/admin/app/components/form/account/password/change-password/index.js
index 2f8f7063f..63ce014ff 100644
--- a/ui/admin/app/components/form/account/password/change-password/index.js
+++ b/ui/admin/app/components/form/account/password/change-password/index.js
@@ -5,9 +5,7 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
-import { computed } from '@ember/object';
import { action } from '@ember/object';
-import { run } from '@ember/runloop';
export default class FormAccountPasswordChangePasswordIndexComponent extends Component {
// =properties
@@ -25,7 +23,6 @@ export default class FormAccountPasswordChangePasswordIndexComponent extends Com
/**
* @type {boolean}
*/
- @computed('currentPassword', 'newPassword')
get canSave() {
return this.currentPassword && this.newPassword;
}
@@ -33,7 +30,6 @@ export default class FormAccountPasswordChangePasswordIndexComponent extends Com
/**
* @type {boolean}
*/
- @computed('canSave')
get cannotSave() {
return !this.canSave;
}
@@ -41,7 +37,7 @@ export default class FormAccountPasswordChangePasswordIndexComponent extends Com
// =methods
/**
- * Unsets the password fields.
+ * Un-sets the password fields.
*/
resetPasswords() {
this.currentPassword = null;
@@ -52,15 +48,15 @@ export default class FormAccountPasswordChangePasswordIndexComponent extends Com
/**
* Call passed submit function with passwords.
- * Unset passwords before callack.
+ * Unset passwords before callback.
* @param {function} fn
* @param {string} currentPassword
* @param {string} newPassword
*/
@action
submit(fn, currentPassword, newPassword) {
- run(() => this.resetPasswords());
- run(() => fn(currentPassword, newPassword));
+ this.resetPasswords();
+ fn(currentPassword, newPassword);
}
/**
diff --git a/ui/admin/app/components/form/account/password/index.js b/ui/admin/app/components/form/account/password/index.js
index e764e8b74..1dc6d12be 100644
--- a/ui/admin/app/components/form/account/password/index.js
+++ b/ui/admin/app/components/form/account/password/index.js
@@ -6,7 +6,6 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
-import { next } from '@ember/runloop';
export default class FormAccountPasswordIndexComponent extends Component {
// =properties
@@ -36,7 +35,7 @@ export default class FormAccountPasswordIndexComponent extends Component {
@action
submit(fn) {
const password = this.password;
- next(() => this.resetPassword());
+ this.resetPassword();
return this.args.model.isNew ? fn(password) : fn();
}
}
diff --git a/ui/admin/app/components/form/account/password/set-password/index.js b/ui/admin/app/components/form/account/password/set-password/index.js
index 295f03c0d..f64704d0d 100644
--- a/ui/admin/app/components/form/account/password/set-password/index.js
+++ b/ui/admin/app/components/form/account/password/set-password/index.js
@@ -5,9 +5,7 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
-import { computed } from '@ember/object';
import { action } from '@ember/object';
-import { run } from '@ember/runloop';
export default class FormAccountPasswordSetPasswordIndexComponent extends Component {
// =properties
@@ -21,7 +19,6 @@ export default class FormAccountPasswordSetPasswordIndexComponent extends Compon
/**
* @type {boolean}
*/
- @computed('password')
get cannotSave() {
return !this.password;
}
@@ -45,7 +42,7 @@ export default class FormAccountPasswordSetPasswordIndexComponent extends Compon
*/
@action
submit(fn, password) {
- run(() => this.resetPassword());
- run(() => fn(password));
+ this.resetPassword();
+ fn(password);
}
}
diff --git a/ui/admin/app/routes/scopes/scope/authenticate/method/oidc.js b/ui/admin/app/routes/scopes/scope/authenticate/method/oidc.js
index a2a729bc6..ff7f9ad6e 100644
--- a/ui/admin/app/routes/scopes/scope/authenticate/method/oidc.js
+++ b/ui/admin/app/routes/scopes/scope/authenticate/method/oidc.js
@@ -7,7 +7,7 @@ import Route from '@ember/routing/route';
import { getOwner } from '@ember/application';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
-import runEvery from 'ember-pollster/decorators/route/run-every';
+import { task, timeout } from 'ember-concurrency';
import { notifyError } from 'core/decorators/notify';
import config from '../../../../../config/environment';
@@ -20,6 +20,15 @@ export default class ScopesScopeAuthenticateMethodOidcRoute extends Route {
@service windowManager;
@service router;
+ // =attributes
+
+ poller = task(async () => {
+ while (!this.session.isAuthenticated) {
+ await timeout(POLL_TIMEOUT_SECONDS * 1000);
+ this.refresh();
+ }
+ });
+
// =methods
beforeModel;
@@ -43,9 +52,11 @@ export default class ScopesScopeAuthenticateMethodOidcRoute extends Route {
controller.authMethod = authMethod;
}
- @runEvery(POLL_TIMEOUT_SECONDS * 1000)
- poller() {
- this.refresh();
+ /**
+ * When this route is activated (entered), start polling for authentication.
+ */
+ activate() {
+ this.poller.perform();
}
/**
@@ -53,6 +64,7 @@ export default class ScopesScopeAuthenticateMethodOidcRoute extends Route {
* any windows opened via the window manager service.
*/
deactivate() {
+ this.poller.cancelAll();
this.windowManager.closeAll();
}
diff --git a/ui/admin/config/environment.js b/ui/admin/config/environment.js
index 2d675b3e7..256371f15 100644
--- a/ui/admin/config/environment.js
+++ b/ui/admin/config/environment.js
@@ -52,7 +52,6 @@ module.exports = function (environment) {
appName: APP_NAME,
companyName: 'HashiCorp',
- sessionPollingTimeoutSeconds: 300,
oidcPollingTimeoutSeconds: 1,
documentation: {
@@ -195,6 +194,8 @@ module.exports = function (environment) {
// Notification timeout should be 0 for fast tests
ENV.flashMessageDefaults.timeout = 0;
+ // OIDC Authentication timeout should be 0 for fast tests
+ ENV.oidcPollingTimeoutSeconds = 0;
ENV.enableConfirmService = false;
}
diff --git a/ui/admin/ember-cli-build.js b/ui/admin/ember-cli-build.js
index 91d853043..e4cfcebc3 100644
--- a/ui/admin/ember-cli-build.js
+++ b/ui/admin/ember-cli-build.js
@@ -18,6 +18,9 @@ module.exports = function (defaults) {
},
babel: {
sourceMaps: 'inline',
+ plugins: [
+ require.resolve('ember-concurrency/async-arrow-task-transform'),
+ ],
},
sourcemaps: {
enabled: true,
@@ -34,7 +37,7 @@ module.exports = function (defaults) {
},
},
// TODO: Update to 4.12 when deprecations are resolved
- // as multiple things break when forcing compatability on > 4.6
+ // as multiple things break when forcing compatibility on > 4.6
emberData: {
compatWith: '4.6',
},
diff --git a/ui/admin/package.json b/ui/admin/package.json
index de72f3653..24f583d73 100644
--- a/ui/admin/package.json
+++ b/ui/admin/package.json
@@ -71,12 +71,12 @@
"ember-cli-sass": "^11.0.1",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",
+ "ember-concurrency": "^4.0.3",
"ember-exam": "^8.0.0",
"ember-inline-svg": "^1.0.1",
"ember-load-initializers": "^2.1.2",
"ember-modifier": "^4.1.0",
"ember-page-title": "^7.0.0",
- "ember-pollster": "https://github.com/hashicorp/ember-pollster.git#605d82e986d829b098667e4a5e221877a4ee4ac8",
"ember-qunit": "^8.1.0",
"ember-resolver": "^10.0.0",
"ember-source": "~4.12.0",
diff --git a/ui/admin/tests/acceptance/authentication-test.js b/ui/admin/tests/acceptance/authentication-test.js
index 949f9e415..dd52710a2 100644
--- a/ui/admin/tests/acceptance/authentication-test.js
+++ b/ui/admin/tests/acceptance/authentication-test.js
@@ -16,7 +16,6 @@ import { setupApplicationTest } from 'admin/tests/helpers';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
import { Response } from 'miragejs';
-import { runAllJobs } from 'ember-pollster/test-support';
import a11yAudit from 'ember-a11y-testing/test-support/audit';
import {
currentSession,
@@ -86,7 +85,7 @@ module('Acceptance | authentication', function (hooks) {
},
'withChildren',
);
- // create an emtpy org with no auth methods
+ // create an empty org with no auth methods
this.server.create(
'scope',
{
@@ -391,9 +390,6 @@ module('Acceptance | authentication', function (hooks) {
);
await visit(authMethodOIDCAuthenticateURL);
await click('form [type="submit"]');
- // explicitly poll multiple times to trigger mock OIDC auth
- await runAllJobs();
- await runAllJobs();
});
// TODO: test OIDC retry and cancel
diff --git a/ui/desktop/app/components/settings-card/client-agent/index.js b/ui/desktop/app/components/settings-card/client-agent/index.js
index f75d5ff08..5cf787388 100644
--- a/ui/desktop/app/components/settings-card/client-agent/index.js
+++ b/ui/desktop/app/components/settings-card/client-agent/index.js
@@ -63,6 +63,8 @@ export default class SettingsCardClientAgentComponent extends Component {
} else {
await this.ipc.invoke('resumeClientAgent');
}
- await this.router.refresh('scopes.scope.projects.settings');
+ // Refresh projects page in order to stop or start
+ // polling when client agent status changes.
+ await this.router.refresh('scopes.scope.projects');
}
}
diff --git a/ui/desktop/app/routes/scopes/scope/authenticate/method/oidc.js b/ui/desktop/app/routes/scopes/scope/authenticate/method/oidc.js
index 1ca7eccc3..d55a08409 100644
--- a/ui/desktop/app/routes/scopes/scope/authenticate/method/oidc.js
+++ b/ui/desktop/app/routes/scopes/scope/authenticate/method/oidc.js
@@ -7,7 +7,7 @@ import Route from '@ember/routing/route';
import { getOwner } from '@ember/application';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
-import runEvery from 'ember-pollster/decorators/route/run-every';
+import { task, timeout } from 'ember-concurrency';
import { notifyError } from 'core/decorators/notify';
import config from '../../../../../config/environment';
@@ -19,6 +19,15 @@ export default class ScopesScopeAuthenticateMethodOidcRoute extends Route {
@service session;
@service router;
+ // =attributes
+
+ poller = task(async () => {
+ while (!this.session.isAuthenticated) {
+ await timeout(POLL_TIMEOUT_SECONDS * 1000);
+ this.refresh();
+ }
+ });
+
// =methods
model() {
@@ -41,9 +50,19 @@ export default class ScopesScopeAuthenticateMethodOidcRoute extends Route {
controller.authMethod = authMethod;
}
- @runEvery(POLL_TIMEOUT_SECONDS * 1000)
- poller() {
- this.refresh();
+ /**
+ * When this route is activated (entered), start polling for authentication.
+ */
+ activate() {
+ this.poller.perform();
+ }
+
+ /**
+ * When this route is deactivated (exited), stop polling for changes and close
+ * any windows opened via the window manager service.
+ */
+ deactivate() {
+ this.poller.cancelAll();
}
/**
diff --git a/ui/desktop/app/routes/scopes/scope/projects.js b/ui/desktop/app/routes/scopes/scope/projects.js
index bbbe26d42..60805045e 100644
--- a/ui/desktop/app/routes/scopes/scope/projects.js
+++ b/ui/desktop/app/routes/scopes/scope/projects.js
@@ -5,7 +5,10 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
+import { restartableTask, timeout } from 'ember-concurrency';
+import config from '../../../config/environment';
+const POLL_TIMEOUT_SECONDS = config.sessionPollingTimeoutSeconds;
const { __electronLog } = globalThis;
/**
@@ -23,10 +26,6 @@ const { __electronLog } = globalThis;
* It no longer makes sense as a dedicated route.
*/
export default class ScopesScopeProjectsRoute extends Route {
- // =attributes
-
- job;
-
// =services
@service session;
@@ -36,7 +35,6 @@ export default class ScopesScopeProjectsRoute extends Route {
@service intl;
@service ipc;
@service clientAgentSessions;
- @service pollster;
@service flashMessages;
// =methods
@@ -53,17 +51,13 @@ export default class ScopesScopeProjectsRoute extends Route {
* @return {Promise}
*/
async model() {
- // Setup the poller job
- if (!this.job) {
- this.boundPoller = this.poller.bind(this);
- this.job = this.pollster.findOrCreateJob(this.boundPoller, 2000);
- }
-
const isClientAgentRunning = await this.ipc.invoke('isClientAgentRunning');
if (isClientAgentRunning) {
- this.job.start();
+ this.poller.perform();
+ // start polling task
} else {
- this.job.stop();
+ this.poller.cancelAll();
+ // cancel polling job
}
const { id: scope_id } = this.modelFor('scopes.scope');
@@ -75,42 +69,48 @@ export default class ScopesScopeProjectsRoute extends Route {
return projects;
}
- willDestroy() {
- this.job?.stop();
- super.willDestroy();
+ /**
+ * Cancel poller task instances when exiting this route.
+ */
+ deactivate() {
+ this.poller.cancelAll();
}
/**
* Poll for new sessions with credentials. Sends a notification for each new session that has a credential.
*/
- async poller() {
+ poller = restartableTask(async () => {
let sessions;
- try {
- sessions = await this.clientAgentSessions.getNewSessionsWithCredentials();
- } catch (e) {
- // If we're unauthenticated, try and re-authenticate
- if (e.statusCode === 401 || e.statusCode === 403) {
- const sessionData = this.session.data?.authenticated;
- const auth_token_id = sessionData?.id;
- const token = sessionData?.token;
+ // We use a while loop to poll for new sessions from the client agent.
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ try {
+ sessions =
+ await this.clientAgentSessions.getNewSessionsWithCredentials();
+ } catch (e) {
+ // If we're unauthenticated, try and re-authenticate
+ if (e.statusCode === 401 || e.statusCode === 403) {
+ const sessionData = this.session.data?.authenticated;
+ const auth_token_id = sessionData?.id;
+ const token = sessionData?.token;
- try {
- await this.ipc.invoke('addTokenToDaemons', {
- tokenId: auth_token_id,
- token,
- });
- this.job.start();
- __electronLog?.info('Starting polling of new sessions again');
- return;
- } catch (e) {
- __electronLog?.error('Failed to add token to daemons', e.message);
- // If it fails again, just let the poller be killed
+ try {
+ await this.ipc.invoke('addTokenToDaemons', {
+ tokenId: auth_token_id,
+ token,
+ });
+
+ __electronLog?.info('Starting polling of new sessions again');
+ this.poller.perform();
+ return;
+ } catch (e) {
+ __electronLog?.error('Failed to add token to daemons', e.message);
+ // If it fails again, just let the poller be killed
+ }
}
- }
- __electronLog?.error('Failed to get new Sessions', e.message);
- if (this.job) {
+ __electronLog?.error('Failed to get new Sessions', e.message);
this.flashMessages.danger(
this.intl.t('errors.client-agent-failed.sessions'),
{
@@ -120,46 +120,46 @@ export default class ScopesScopeProjectsRoute extends Route {
},
);
- // Kill the poller if we get an error
- this.job.stop();
__electronLog?.info('Stopping polling of new sessions');
+ return;
}
- return;
+ sessions.forEach((session) => {
+ new window.Notification(
+ this.intl.t('notifications.connected-to-target.title', {
+ target: session.alias,
+ }),
+ {
+ body: this.intl.t('notifications.connected-to-target.description'),
+ // This only has an effect on windows
+ requireInteraction: true,
+ },
+ ).onclick = async () => {
+ let orgScope = 'global';
+
+ try {
+ const aliases = await this.store.query('alias', {
+ scope_id: 'global',
+ force_refresh: true,
+ });
+ const alias = aliases.find(
+ (alias) => alias.value === session.alias,
+ );
+
+ const target = await this.store.findRecord(
+ 'target',
+ alias.destination_id,
+ );
+ orgScope = target.scope.parent_scope_id;
+ } catch (e) {
+ // Do nothing and default scope to global if an error occurs
+ }
+
+ window.location.href = `serve://boundary/#/scopes/${orgScope}/projects/sessions/${session.session_authorization.session_id}`;
+ await this.ipc.invoke('focusWindow');
+ };
+ });
+ await timeout(POLL_TIMEOUT_SECONDS * 1000);
}
-
- sessions.forEach((session) => {
- new window.Notification(
- this.intl.t('notifications.connected-to-target.title', {
- target: session.alias,
- }),
- {
- body: this.intl.t('notifications.connected-to-target.description'),
- // This only has an effect on windows
- requireInteraction: true,
- },
- ).onclick = async () => {
- let orgScope = 'global';
-
- try {
- const aliases = await this.store.query('alias', {
- scope_id: 'global',
- force_refresh: true,
- });
- const alias = aliases.find((alias) => alias.value === session.alias);
-
- const target = await this.store.findRecord(
- 'target',
- alias.destination_id,
- );
- orgScope = target.scope.parent_scope_id;
- } catch (e) {
- // Do nothing and default scope to global if an error occurs
- }
-
- window.location.href = `serve://boundary/#/scopes/${orgScope}/projects/sessions/${session.session_authorization.session_id}`;
- await this.ipc.invoke('focusWindow');
- };
- });
- }
+ });
}
diff --git a/ui/desktop/config/environment.js b/ui/desktop/config/environment.js
index 7a4641079..f240a6ca8 100644
--- a/ui/desktop/config/environment.js
+++ b/ui/desktop/config/environment.js
@@ -43,8 +43,8 @@ module.exports = function (environment) {
appName: APP_NAME,
- sessionPollingTimeoutSeconds: 300,
oidcPollingTimeoutSeconds: 1,
+ sessionPollingTimeoutSeconds: 2,
documentation: {
baseURL: 'https://developer.hashicorp.com/boundary',
@@ -94,6 +94,10 @@ module.exports = function (environment) {
// Notification timeout should be 0 for fast tests
ENV.flashMessageDefaults.timeout = 0;
+ // OIDC Authentication timeout should be 0 for fast tests
+ ENV.oidcPollingTimeoutSeconds = 0;
+ // Sessions polling timeout should be 0 for fast tests
+ ENV.sessionPollingTimeoutSeconds = 0;
ENV.enableConfirmService = false;
diff --git a/ui/desktop/ember-cli-build.js b/ui/desktop/ember-cli-build.js
index d06785927..badd6fc75 100644
--- a/ui/desktop/ember-cli-build.js
+++ b/ui/desktop/ember-cli-build.js
@@ -18,6 +18,9 @@ module.exports = function (defaults) {
},
babel: {
sourceMaps: 'inline',
+ plugins: [
+ require.resolve('ember-concurrency/async-arrow-task-transform'),
+ ],
},
sourcemaps: {
enabled: true,
diff --git a/ui/desktop/package.json b/ui/desktop/package.json
index 60eb3f665..ab4f79940 100644
--- a/ui/desktop/package.json
+++ b/ui/desktop/package.json
@@ -76,13 +76,13 @@
"ember-cli-sass": "^11.0.1",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",
+ "ember-concurrency": "^4.0.3",
"ember-electron": "^4.2.2",
"ember-exam": "^8.0.0",
"ember-inline-svg": "^1.0.1",
"ember-load-initializers": "^2.1.2",
"ember-modifier": "^4.1.0",
"ember-page-title": "^7.0.0",
- "ember-pollster": "https://github.com/hashicorp/ember-pollster.git#605d82e986d829b098667e4a5e221877a4ee4ac8",
"ember-qunit": "^8.1.0",
"ember-resolver": "^10.0.0",
"ember-source": "~4.12.0",
diff --git a/yarn.lock b/yarn.lock
index 0dfa50a9a..020535b9b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -812,6 +812,16 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-module-imports@npm:^7.22.15, @babel/helper-module-imports@npm:^7.25.9":
+ version: 7.25.9
+ resolution: "@babel/helper-module-imports@npm:7.25.9"
+ dependencies:
+ "@babel/traverse": "npm:^7.25.9"
+ "@babel/types": "npm:^7.25.9"
+ checksum: 10c0/078d3c2b45d1f97ffe6bb47f61961be4785d2342a4156d8b42c92ee4e1b7b9e365655dd6cb25329e8fe1a675c91eeac7e3d04f0c518b67e417e29d6e27b6aa70
+ languageName: node
+ linkType: hard
+
"@babel/helper-module-imports@npm:^7.22.5":
version: 7.22.5
resolution: "@babel/helper-module-imports@npm:7.22.5"
@@ -831,16 +841,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-module-imports@npm:^7.25.9":
- version: 7.25.9
- resolution: "@babel/helper-module-imports@npm:7.25.9"
- dependencies:
- "@babel/traverse": "npm:^7.25.9"
- "@babel/types": "npm:^7.25.9"
- checksum: 10c0/078d3c2b45d1f97ffe6bb47f61961be4785d2342a4156d8b42c92ee4e1b7b9e365655dd6cb25329e8fe1a675c91eeac7e3d04f0c518b67e417e29d6e27b6aa70
- languageName: node
- linkType: hard
-
"@babel/helper-module-transforms@npm:^7.14.5":
version: 7.15.0
resolution: "@babel/helper-module-transforms@npm:7.15.0"
@@ -4409,6 +4409,16 @@ __metadata:
languageName: node
linkType: hard
+"@babel/types@npm:^7.12.13, @babel/types@npm:^7.8.3":
+ version: 7.26.9
+ resolution: "@babel/types@npm:7.26.9"
+ dependencies:
+ "@babel/helper-string-parser": "npm:^7.25.9"
+ "@babel/helper-validator-identifier": "npm:^7.25.9"
+ checksum: 10c0/999c56269ba00e5c57aa711fbe7ff071cd6990bafd1b978341ea7572cc78919986e2aa6ee51dacf4b6a7a6fa63ba4eb3f1a03cf55eee31b896a56d068b895964
+ languageName: node
+ linkType: hard
+
"@babel/types@npm:^7.14.5, @babel/types@npm:^7.14.8, @babel/types@npm:^7.15.0, @babel/types@npm:^7.4.4, @babel/types@npm:^7.7.2":
version: 7.15.0
resolution: "@babel/types@npm:7.15.0"
@@ -4472,16 +4482,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/types@npm:^7.8.3":
- version: 7.26.9
- resolution: "@babel/types@npm:7.26.9"
- dependencies:
- "@babel/helper-string-parser": "npm:^7.25.9"
- "@babel/helper-validator-identifier": "npm:^7.25.9"
- checksum: 10c0/999c56269ba00e5c57aa711fbe7ff071cd6990bafd1b978341ea7572cc78919986e2aa6ee51dacf4b6a7a6fa63ba4eb3f1a03cf55eee31b896a56d068b895964
- languageName: node
- linkType: hard
-
"@bcoe/v8-coverage@npm:^0.2.3":
version: 0.2.3
resolution: "@bcoe/v8-coverage@npm:0.2.3"
@@ -7187,13 +7187,13 @@ __metadata:
ember-cli-sass: "npm:^11.0.1"
ember-cli-sri: "npm:^2.1.1"
ember-cli-terser: "npm:^4.0.2"
+ ember-concurrency: "npm:^4.0.3"
ember-exam: "npm:^8.0.0"
ember-inline-svg: "npm:^1.0.1"
ember-load-initializers: "npm:^2.1.2"
ember-modifier: "npm:^4.1.0"
ember-named-blocks-polyfill: "npm:^0.2.5"
ember-page-title: "npm:^7.0.0"
- ember-pollster: "https://github.com/hashicorp/ember-pollster.git#605d82e986d829b098667e4a5e221877a4ee4ac8"
ember-qunit: "npm:^8.1.0"
ember-resolver: "npm:^10.0.0"
ember-source: "npm:~4.12.0"
@@ -10090,6 +10090,7 @@ __metadata:
ember-cli-sass: "npm:^11.0.1"
ember-cli-sri: "npm:^2.1.1"
ember-cli-terser: "npm:^4.0.2"
+ ember-concurrency: "npm:^4.0.3"
ember-feature-flags: "npm:^6.0.0"
ember-inline-svg: "npm:^1.0.1"
ember-intl: "npm:^7.0.7"
@@ -10488,7 +10489,7 @@ __metadata:
languageName: node
linkType: hard
-"decorator-transforms@npm:^1.1.0":
+"decorator-transforms@npm:^1.0.1, decorator-transforms@npm:^1.1.0":
version: 1.2.1
resolution: "decorator-transforms@npm:1.2.1"
dependencies:
@@ -10649,6 +10650,7 @@ __metadata:
ember-cli-sass: "npm:^11.0.1"
ember-cli-sri: "npm:^2.1.1"
ember-cli-terser: "npm:^4.0.2"
+ ember-concurrency: "npm:^4.0.3"
ember-electron: "npm:^4.2.2"
ember-exam: "npm:^8.0.0"
ember-inline-svg: "npm:^1.0.1"
@@ -10656,7 +10658,6 @@ __metadata:
ember-modifier: "npm:^4.1.0"
ember-named-blocks-polyfill: "npm:^0.2.5"
ember-page-title: "npm:^7.0.0"
- ember-pollster: "https://github.com/hashicorp/ember-pollster.git#605d82e986d829b098667e4a5e221877a4ee4ac8"
ember-qunit: "npm:^8.1.0"
ember-resolver: "npm:^10.0.0"
ember-source: "npm:~4.12.0"
@@ -11167,7 +11168,7 @@ __metadata:
languageName: node
linkType: hard
-"ember-cli-babel@npm:^7.10.0, ember-cli-babel@npm:^7.11.1, ember-cli-babel@npm:^7.13.0, ember-cli-babel@npm:^7.19.0, ember-cli-babel@npm:^7.21.0, ember-cli-babel@npm:^7.22.1, ember-cli-babel@npm:^7.23.0, ember-cli-babel@npm:^7.26.11, ember-cli-babel@npm:^7.26.3, ember-cli-babel@npm:^7.26.5, ember-cli-babel@npm:^7.26.6, ember-cli-babel@npm:^7.26.8, ember-cli-babel@npm:^7.7.3":
+"ember-cli-babel@npm:^7.10.0, ember-cli-babel@npm:^7.11.1, ember-cli-babel@npm:^7.13.0, ember-cli-babel@npm:^7.19.0, ember-cli-babel@npm:^7.21.0, ember-cli-babel@npm:^7.22.1, ember-cli-babel@npm:^7.23.0, ember-cli-babel@npm:^7.26.11, ember-cli-babel@npm:^7.26.3, ember-cli-babel@npm:^7.26.5, ember-cli-babel@npm:^7.26.6, ember-cli-babel@npm:^7.7.3":
version: 7.26.11
resolution: "ember-cli-babel@npm:7.26.11"
dependencies:
@@ -11933,6 +11934,26 @@ __metadata:
languageName: node
linkType: hard
+"ember-concurrency@npm:^4.0.3":
+ version: 4.0.3
+ resolution: "ember-concurrency@npm:4.0.3"
+ dependencies:
+ "@babel/helper-module-imports": "npm:^7.22.15"
+ "@babel/helper-plugin-utils": "npm:^7.12.13"
+ "@babel/types": "npm:^7.12.13"
+ "@embroider/addon-shim": "npm:^1.8.7"
+ decorator-transforms: "npm:^1.0.1"
+ peerDependencies:
+ "@glimmer/tracking": ^1.1.2
+ "@glint/template": ">= 1.0.0"
+ ember-source: ^3.28.0 || ^4.0.0 || >=5.0.0
+ peerDependenciesMeta:
+ "@glint/template":
+ optional: true
+ checksum: 10c0/01fd3b6b3358f185ee8df7667803044d9a0c13f5e8500c2c8c8b478632a070e03fd7372a2e557ec5fcd605bb34b1f2edea9d3e0968a222a1b1c2d0bce9a9bff3
+ languageName: node
+ linkType: hard
+
"ember-cookies@npm:^1.0.0, ember-cookies@npm:^1.2.0":
version: 1.2.0
resolution: "ember-cookies@npm:1.2.0"
@@ -12304,16 +12325,6 @@ __metadata:
languageName: node
linkType: hard
-"ember-pollster@https://github.com/hashicorp/ember-pollster.git#605d82e986d829b098667e4a5e221877a4ee4ac8":
- version: 0.0.1-beta.2
- resolution: "ember-pollster@https://github.com/hashicorp/ember-pollster.git#commit=605d82e986d829b098667e4a5e221877a4ee4ac8"
- dependencies:
- ember-cli-babel: "npm:^7.26.8"
- ember-cli-htmlbars: "npm:^6.0.1"
- checksum: 10c0/0e1b6e8b9ef466d864d01e63a5c58b9ccd81ea5d1e71402a5bd74d010f52a40bd9d257c2c9adf3ccd7f383327e8ffaa1b4ec73980afb6ddd4b1e18676ab099c4
- languageName: node
- linkType: hard
-
"ember-power-select@npm:^8.2.0":
version: 8.2.0
resolution: "ember-power-select@npm:8.2.0"