From 618d418093b6f1effe3f5e6c0520ce972be82999 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Sun, 2 Jan 2022 15:55:05 -0500 Subject: [PATCH 1/6] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20rewrite=20sessio?= =?UTF-8?q?ns=20polling=20for=20ember-pollster?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/admin/app/routes/scopes/scope/sessions.js | 104 ++++------ ui/admin/package.json | 3 +- ui/admin/tests/acceptance/sessions-test.js | 63 +++--- yarn.lock | 198 +++++++++++++++---- 4 files changed, 229 insertions(+), 139 deletions(-) diff --git a/ui/admin/app/routes/scopes/scope/sessions.js b/ui/admin/app/routes/scopes/scope/sessions.js index 29a0d87a5..71038382c 100644 --- a/ui/admin/app/routes/scopes/scope/sessions.js +++ b/ui/admin/app/routes/scopes/scope/sessions.js @@ -2,8 +2,8 @@ import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; import { action } from '@ember/object'; import { all, hash } from 'rsvp'; -import { task, timeout } from 'ember-concurrency'; import { A } from '@ember/array'; +import runEvery from 'ember-pollster/decorators/route/run-every'; import { notifySuccess, notifyError } from 'core/decorators/notify'; import config from '../../../config/environment'; import { resourceFilter } from 'core/decorators/resource-filter'; @@ -11,7 +11,6 @@ import { resourceFilter } from 'core/decorators/resource-filter'; const POLL_TIMEOUT_SECONDS = config.sessionPollingTimeoutSeconds; export default class ScopesScopeSessionsRoute extends Route { - // =services @service intl; @@ -23,26 +22,14 @@ export default class ScopesScopeSessionsRoute extends Route { @resourceFilter({ allowed: ['active', 'pending', 'canceling', 'terminated'], - defaultValue: ['active','pending', 'canceling'] - }) status; + defaultValue: ['active', 'pending', 'canceling'], + }) + status; - /** - * A simple Ember Concurrency-based polling task that refreshes the route - * every POLL_TIMEOUT_SECONDS seconds. This is necessary to display changes - * to session `status` that may occur. - * - * NOTE: tasks are sort of attributes and sort of methods, but they are not - * language-level constructs. Thus we annotate this task as if it - * is an attribute. - * @type {Task} - */ - @task(function * () { - while(true) { - yield timeout(POLL_TIMEOUT_SECONDS * 1000); - yield this.refresh(); - } - /* eslint-disable-next-line prettier/prettier */ - }).drop() poller; + @runEvery(POLL_TIMEOUT_SECONDS * 1000) + poller() { + return this.refresh(); + } // =methods @@ -68,47 +55,36 @@ export default class ScopesScopeSessionsRoute extends Route { ); const sessionAggregates = await all( - sessions.map(session => hash({ - session, - user: session.user_id - ? ( - this.store.peekRecord('user', session.user_id) || + sessions.map((session) => + hash({ + session, + user: session.user_id + ? this.store.peekRecord('user', session.user_id) || this.store.findRecord('user', session.user_id) - ) - : null, - target: session.target_id - ? ( - this.store.peekRecord('target', session.target_id) || + : null, + target: session.target_id + ? this.store.peekRecord('target', session.target_id) || this.store.findRecord('target', session.target_id) - ) - : null, - })) + : null, + }) + ) ); // Sort sessions by time created... - let sortedSessionAggregates = - A(sessionAggregates).sortBy('session.created_time').reverse(); + let sortedSessionAggregates = A(sessionAggregates) + .sortBy('session.created_time') + .reverse(); // Then move active sessions to the top... sortedSessionAggregates = [ - ...sortedSessionAggregates.filter((aggregate) => aggregate.session.status === 'active'), - ...sortedSessionAggregates.filter((aggregate) => aggregate.session.status !== 'active'), + ...sortedSessionAggregates.filter( + (aggregate) => aggregate.session.status === 'active' + ), + ...sortedSessionAggregates.filter( + (aggregate) => aggregate.session.status !== 'active' + ), ]; return sortedSessionAggregates; } - /** - * When this route is activated (entered), begin polling for changes. - */ - activate() { - this.poller.perform(); - } - - /** - * When this route is deactivated (exited), stop polling for changes. - */ - deactivate() { - this.poller.cancelAll(); - } - // =actions /** @@ -122,21 +98,21 @@ export default class ScopesScopeSessionsRoute extends Route { await session.cancelSession(); } - /** + /** * Sets the specified resource filter field to the specified value. * @param {string} field * @param value */ - @action - filterBy(field, value) { - this[field] = value; - } + @action + filterBy(field, value) { + this[field] = value; + } - /** - * Clears and filter selections. - */ - @action - clearAllFilters() { - this.status = []; - } + /** + * Clears and filter selections. + */ + @action + clearAllFilters() { + this.status = []; + } } diff --git a/ui/admin/package.json b/ui/admin/package.json index aa23dd91b..9347d3adf 100644 --- a/ui/admin/package.json +++ b/ui/admin/package.json @@ -35,7 +35,6 @@ "ember-named-blocks-polyfill": "^0.2.4" }, "devDependencies": { - "js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1", "@babel/core": "^7.16.5", "@ember/optional-features": "^2.0.0", "@ember/render-modifiers": "^1.0.2", @@ -72,6 +71,7 @@ "ember-modifier": "^2.1.2", "ember-notify": "^6.0.1", "ember-page-title": "^6.2.2", + "ember-pollster": "^0.0.1-beta.2", "ember-qunit": "^5.1.4", "ember-resolver": "^8.0.3", "ember-source": "~3.28.4", @@ -84,6 +84,7 @@ "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-qunit": "^6.2.0", "faker": "^5.5.3", + "js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1", "loader.js": "^4.7.0", "npm-run-all": "^4.1.5", "prettier": "^2.4.0", diff --git a/ui/admin/tests/acceptance/sessions-test.js b/ui/admin/tests/acceptance/sessions-test.js index a5dfa25ff..904eaaf56 100644 --- a/ui/admin/tests/acceptance/sessions-test.js +++ b/ui/admin/tests/acceptance/sessions-test.js @@ -3,7 +3,6 @@ import { visit, currentURL, findAll, find, click } from '@ember/test-helpers'; import { setupApplicationTest } from 'ember-qunit'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; import a11yAudit from 'ember-a11y-testing/test-support/audit'; -import { run, later } from '@ember/runloop'; import { Response } from 'miragejs'; import { authenticateSession, @@ -81,45 +80,36 @@ module('Acceptance | sessions', function (hooks) { test('visiting sessions', async function (assert) { assert.expect(2); authenticateSession({}); - later(async () => { - run.cancelTimers(); - await a11yAudit(); - assert.equal(currentURL(), urls.sessions); - assert.equal(findAll('tbody tr').length, instances.sessions.length); - }, 750); await visit(urls.sessions); + await a11yAudit(); + assert.equal(currentURL(), urls.sessions); + assert.equal(findAll('tbody tr').length, instances.sessions.length); }); test('Users cannot navigate to sessions without proper authorization', async function (assert) { assert.expect(2); instances.scopes.project.authorized_collection_actions.sessions = []; authenticateSession({}); - later(async () => { - run.cancelTimers(); - assert.notOk( - instances.scopes.project.authorized_collection_actions.sessions.includes( - 'list' - ) - ); - assert.notOk(find(`[href="${urls.sessions}"]`)); - }, 750); await visit(urls.orgScope); + assert.notOk( + instances.scopes.project.authorized_collection_actions.sessions.includes( + 'list' + ) + ); + assert.notOk(find(`[href="${urls.sessions}"]`)); }); test('Users can navigate to sessions with proper authorization', async function (assert) { assert.expect(2); instances.scopes.project.authorized_collection_actions.sessions = ['list']; authenticateSession({}); - later(async () => { - run.cancelTimers(); - assert.ok( - instances.scopes.project.authorized_collection_actions.sessions.includes( - 'list' - ) - ); - assert.ok(find(`[href="${urls.sessions}"]`)); - }, 750); await visit(urls.orgScope); + assert.ok( + instances.scopes.project.authorized_collection_actions.sessions.includes( + 'list' + ) + ); + assert.ok(find(`[href="${urls.sessions}"]`)); }); test('visiting sessions without users or targets is OK', async function (assert) { @@ -129,37 +119,28 @@ module('Acceptance | sessions', function (hooks) { targetId: null, }); authenticateSession({}); - later(async () => { - run.cancelTimers(); - await a11yAudit(); - assert.equal(currentURL(), urls.sessions); - assert.equal(findAll('tbody tr').length, instances.sessions.length); - }, 750); await visit(urls.sessions); + await a11yAudit(); + assert.equal(currentURL(), urls.sessions); + assert.equal(findAll('tbody tr').length, instances.sessions.length); }); test('cancelling a session', async function (assert) { assert.expect(2); authenticateSession({}); - later(async () => { - run.cancelTimers(); - await click('tbody tr:first-child td:last-child button'); - assert.ok(find('[role="alert"].is-success')); - }, 750); await visit(urls.sessions); assert.equal(currentURL(), urls.sessions); + await click('tbody tr:first-child td:last-child button'); + assert.ok(find('[role="alert"].is-success')); }); test('cancelling a session with error shows notification', async function (assert) { assert.expect(2); this.server.post('/sessions/:id_method', () => new Response(400)); authenticateSession({}); - later(async () => { - run.cancelTimers(); - await click('tbody tr:first-child td:last-child button'); - assert.ok(find('[role="alert"].is-error')); - }, 750); await visit(urls.sessions); assert.equal(currentURL(), urls.sessions); + await click('tbody tr:first-child td:last-child button'); + assert.ok(find('[role="alert"].is-error')); }); }); diff --git a/yarn.lock b/yarn.lock index 5de73fdd9..f4fde0895 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5867,9 +5867,9 @@ agentkeepalive@^3.4.1: humanize-ms "^1.2.1" agentkeepalive@^4.1.3: - version "4.1.4" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.1.4.tgz#d928028a4862cb11718e55227872e842a44c945b" - integrity sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ== + version "4.2.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.2.0.tgz#616ce94ccb41d1a39a45d203d8076fe98713062d" + integrity sha512-0PhAp58jZNw13UJv7NVdTGb0ZcghHUb3DrZ046JiiJY/BOaTTpbwdHq2VObPCBV8M2GPh7sgrJ3AQ8Ey468LJw== dependencies: debug "^4.1.0" depd "^1.1.2" @@ -6500,6 +6500,11 @@ babel-helpers@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" +babel-import-util@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/babel-import-util/-/babel-import-util-0.2.0.tgz#b468bb679919601a3570f9e317536c54f2862e23" + integrity sha512-CtWYYHU/MgK88rxMrLfkD356dApswtR/kWZ/c6JifG1m10e7tBBrs/366dFzWMAoqYmG5/JSh+94tUSpIwh+ag== + babel-loader@^8.0.6, babel-loader@^8.2.2: version "8.2.2" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.2.tgz#9363ce84c10c9a40e6c753748e1441b60c8a0b81" @@ -6560,6 +6565,16 @@ babel-plugin-ember-modules-api-polyfill@^3.5.0: dependencies: ember-rfc176-data "^0.3.17" +babel-plugin-ember-template-compilation@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-template-compilation/-/babel-plugin-ember-template-compilation-1.0.1.tgz#64baf434ff1b751c6292936f8b9eb75a2f8149dc" + integrity sha512-V/kY6CDyUNrl5Kx6UPKUPhzSKNfdrxNii+S5zK4dgJvVyoxFv7Ykg06Ct/yskY0LkA4wUPdYN7JOBtYJwHk2sg== + dependencies: + babel-import-util "^0.2.0" + line-column "^1.0.2" + magic-string "^0.25.7" + string.prototype.matchall "^4.0.5" + babel-plugin-emotion@^10.0.27: version "10.2.2" resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz#a1fe3503cff80abfd0bdda14abd2e8e57a79d17d" @@ -6607,6 +6622,17 @@ babel-plugin-htmlbars-inline-precompile@^5.0.0: parse-static-imports "^1.1.0" string.prototype.matchall "^4.0.4" +babel-plugin-htmlbars-inline-precompile@^5.3.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-5.3.1.tgz#5ba272e2e4b6221522401f5f1d98a73b1de38787" + integrity sha512-QWjjFgSKtSRIcsBhJmEwS2laIdrA6na8HAlc/pEAhjHgQsah/gMiBFRZvbQTy//hWxR4BMwV7/Mya7q5H8uHeA== + dependencies: + babel-plugin-ember-modules-api-polyfill "^3.5.0" + line-column "^1.0.2" + magic-string "^0.25.7" + parse-static-imports "^1.1.0" + string.prototype.matchall "^4.0.5" + babel-plugin-istanbul@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" @@ -7798,12 +7824,12 @@ browserify-zlib@^0.2.0: pako "~1.0.5" browserslist@4.14.2, browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.5, browserslist@^4.16.6, browserslist@^4.16.7, browserslist@^4.17.3, browserslist@^4.17.5, browserslist@^4.19.1: - version "4.17.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.6.tgz#c76be33e7786b497f66cad25a73756c8b938985d" - integrity sha512-uPgz3vyRTlEiCv4ee9KlsKgo2V6qPk7Jsn0KAn2OBqbqKo3iNcPEC1Ti6J4dwnz+aIRfEEEuOzC9IBk8tXUomw== + version "4.19.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3" + integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A== dependencies: - caniuse-lite "^1.0.30001274" - electron-to-chromium "^1.3.886" + caniuse-lite "^1.0.30001286" + electron-to-chromium "^1.4.17" escalade "^3.1.1" node-releases "^2.0.1" picocolors "^1.0.0" @@ -8116,10 +8142,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001157, caniuse-lite@^1.0.30001274: - version "1.0.30001279" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001279.tgz#eb06818da481ef5096a3b3760f43e5382ed6b0ce" - integrity sha512-VfEHpzHEXj6/CxggTwSFoZBBYGQfQv9Cf42KPlO79sWXCD1QNKWKsKzFeWL7QpZHJQYAvocqV6Rty1yJMkqWLQ== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001157, caniuse-lite@^1.0.30001286: + version "1.0.30001295" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001295.tgz#68a60f8f0664f342b2835c5d8898b4faea7b3d51" + integrity sha512-lSP16vcyC0FEy0R4ECc9duSPoKoZy+YkpGkue9G4D81OfPnliopaZrU10+qtPdT8PbGXad/PNx43TIQrOmJZSQ== capture-exit@^2.0.0: version "2.0.0" @@ -9383,7 +9409,7 @@ debug@^3.0.0, debug@^3.0.1, debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: dependencies: ms "^2.1.1" -debuglog@^1.0.1: +debuglog@*, debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= @@ -9964,10 +9990,10 @@ electron-rebuild@^2.0.3: tar "^6.0.5" yargs "^16.0.0" -electron-to-chromium@^1.3.886: - version "1.3.895" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.895.tgz#9b0f8f2e32d8283bbb200156fd5d8dfd775f31ed" - integrity sha512-9Ww3fB8CWctjqHwkOt7DQbMZMpal2x2reod+/lU4b9axO1XJEDUpPMBxs7YnjLhhqpKXIIB5SRYN/B4K0QpvyQ== +electron-to-chromium@^1.4.17: + version "1.4.31" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.31.tgz#8d5ccc3f8253cd142b07afaa84f200fd33a7f2a6" + integrity sha512-t3XVQtk+Frkv6aTD4RRk0OqosU+VLe1dQFW83MDer78ZD6a52frgXuYOIsLYTQiH2Lm+JB2OKYcn7zrX+YGAiQ== element-resize-detector@^1.2.2: version "1.2.3" @@ -10275,6 +10301,27 @@ ember-cli-htmlbars@^5.3.1, ember-cli-htmlbars@^5.3.2, ember-cli-htmlbars@^5.7.1: strip-bom "^4.0.0" walk-sync "^2.2.0" +ember-cli-htmlbars@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-6.0.1.tgz#5487831d477e61682bc867fd138808269e5d2152" + integrity sha512-IDsl9uty+MXtMfp/BUTEc/Q36EmlHYj8ZdPekcoRa8hmdsigHnK4iokfaB7dJFktlf6luruei+imv7JrJrBQPQ== + dependencies: + "@ember/edition-utils" "^1.2.0" + babel-plugin-ember-template-compilation "^1.0.0" + babel-plugin-htmlbars-inline-precompile "^5.3.0" + broccoli-debug "^0.6.5" + broccoli-persistent-filter "^3.1.2" + broccoli-plugin "^4.0.3" + ember-cli-version-checker "^5.1.2" + fs-tree-diff "^2.0.1" + hash-for-dep "^1.5.1" + heimdalljs-logger "^0.1.10" + json-stable-stringify "^1.0.1" + semver "^7.3.4" + silent-error "^1.1.1" + strip-bom "^4.0.0" + walk-sync "^2.2.0" + ember-cli-inject-live-reload@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-2.1.0.tgz#ef63c733c133024d5726405a3c247fa12e88a385" @@ -10973,6 +11020,14 @@ ember-page-title@^6.2.2: dependencies: ember-cli-babel "^7.23.1" +ember-pollster@^0.0.1-beta.2: + version "0.0.1-beta.2" + resolved "https://registry.yarnpkg.com/ember-pollster/-/ember-pollster-0.0.1-beta.2.tgz#07b8a49683cfb04e33a60713fb044e07a0a8f330" + integrity sha512-vnWBzPIJ0NU6065OLgLd84Snalfxi5Z606wiDSMnW1oSl20D3cAsGEwmpujZsfzlof7Y2McE/ghNjMBKYveyIQ== + dependencies: + ember-cli-babel "^7.26.8" + ember-cli-htmlbars "^6.0.1" + ember-qunit@^5.1.4: version "5.1.4" resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-5.1.4.tgz#bc69f963a0f5409ce33bee1e4d8146b1407147bf" @@ -11414,6 +11469,32 @@ es-abstract@^1.17.0-next.0, es-abstract@^1.17.2, es-abstract@^1.18.0-next.1, es- string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.1" +es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.1" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + object-inspect "^1.11.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + es-array-method-boxes-properly@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" @@ -13111,6 +13192,14 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -14193,9 +14282,9 @@ ignore@^5.1.1, ignore@^5.1.4, ignore@^5.1.8: integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== immer@8.0.1, immer@^9.0.6: - version "9.0.6" - resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.6.tgz#7a96bf2674d06c8143e327cbf73539388ddf1a73" - integrity sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ== + version "9.0.7" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.7.tgz#b6156bd7db55db7abc73fd2fdadf4e579a701075" + integrity sha512-KGllzpbamZDvOIxnmJ0jI840g7Oikx58lBPWV0hUh7dtAyZpFqqrBZdKka5GlTwMTZ1Tjc/bKKW4VSFAt6BqMA== import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: version "3.3.0" @@ -14215,7 +14304,7 @@ import-lazy@^4.0.0: resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== -imurmurhash@^0.1.4: +imurmurhash@*, imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= @@ -14530,7 +14619,7 @@ is-buffer@^2.0.0: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== -is-callable@^1.1.4, is-callable@^1.2.3: +is-callable@^1.1.4, is-callable@^1.2.3, is-callable@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== @@ -14862,7 +14951,7 @@ is-reference@^1.1.0: dependencies: "@types/estree" "*" -is-regex@^1.1.2, is-regex@^1.1.3: +is-regex@^1.1.2, is-regex@^1.1.3, is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== @@ -14895,6 +14984,11 @@ is-set@^2.0.2: resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + is-stream@^1.0.0, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -14905,7 +14999,7 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-string@^1.0.5, is-string@^1.0.6: +is-string@^1.0.5, is-string@^1.0.6, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== @@ -14941,6 +15035,13 @@ is-utf8@^0.2.0, is-utf8@^0.2.1: resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= +is-weakref@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + is-whitespace-character@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" @@ -16017,6 +16118,11 @@ lodash._baseflatten@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" +lodash._baseindexof@*: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" + integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw= + lodash._baseuniq@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" @@ -16025,11 +16131,16 @@ lodash._baseuniq@~4.6.0: lodash._createset "~4.0.0" lodash._root "~3.0.0" -lodash._bindcallback@^3.0.0: +lodash._bindcallback@*, lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4= +lodash._cacheindexof@*: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" + integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI= + lodash._createassigner@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" @@ -16039,12 +16150,19 @@ lodash._createassigner@^3.0.0: lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" +lodash._createcache@*: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" + integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM= + dependencies: + lodash._getnative "^3.0.0" + lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY= -lodash._getnative@^3.0.0: +lodash._getnative@*, lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= @@ -16262,7 +16380,7 @@ lodash.pick@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= -lodash.restparam@^3.0.0: +lodash.restparam@*, lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= @@ -17073,9 +17191,9 @@ minipass@^3.0.0, minipass@^3.1.1: yallist "^4.0.0" minipass@^3.1.0, minipass@^3.1.3: - version "3.1.5" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.5.tgz#71f6251b0a33a49c01b3cf97ff77eda030dff732" - integrity sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw== + version "3.1.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee" + integrity sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ== dependencies: yallist "^4.0.0" @@ -21540,6 +21658,20 @@ string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2 regexp.prototype.flags "^1.3.1" side-channel "^1.0.4" +string.prototype.matchall@^4.0.5: + version "4.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" + integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.3.1" + side-channel "^1.0.4" + string.prototype.padend@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz#6858ca4f35c5268ebd5e8615e1327d55f59ee311" @@ -22649,9 +22781,9 @@ underscore.string@^3.2.2, underscore.string@~3.3.4: util-deprecate "^1.0.2" underscore@>=1.8.3, underscore@^1.12.1, underscore@~1.12.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1" - integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g== + version "1.13.2" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.2.tgz#276cea1e8b9722a8dbed0100a407dda572125881" + integrity sha512-ekY1NhRzq0B08g4bGuX4wd2jZx5GnKz6mKSqFL4nqBlfyMGiG10gDFhDTMEfYmDL6Jy0FUIZp7wiRB+0BP7J2g== unfetch@^4.2.0: version "4.2.0" From fe509d2e86e71a65a05db2eda6743f78956b59dc Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Sun, 2 Jan 2022 19:21:03 -0500 Subject: [PATCH 2/6] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20rewrite=20sessio?= =?UTF-8?q?ns=20polling=20for=20ember-pollster?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../routes/scopes/scope/projects/sessions.js | 68 +++++---------- ui/desktop/package.json | 3 +- .../acceptance/projects/sessions-test.js | 84 ++++++------------- 3 files changed, 50 insertions(+), 105 deletions(-) diff --git a/ui/desktop/app/routes/scopes/scope/projects/sessions.js b/ui/desktop/app/routes/scopes/scope/projects/sessions.js index b353fb8a7..668d0cc52 100644 --- a/ui/desktop/app/routes/scopes/scope/projects/sessions.js +++ b/ui/desktop/app/routes/scopes/scope/projects/sessions.js @@ -1,15 +1,14 @@ import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; -import { task, timeout } from 'ember-concurrency'; -import config from '../../../../config/environment'; import { action } from '@ember/object'; +import runEvery from 'ember-pollster/decorators/route/run-every'; import { notifySuccess, notifyError } from 'core/decorators/notify'; import { resourceFilter } from 'core/decorators/resource-filter'; +import config from '../../../../config/environment'; const POLL_TIMEOUT_SECONDS = config.sessionPollingTimeoutSeconds; export default class ScopesScopeProjectsSessionsRoute extends Route { - // =services @service ipc; @@ -20,32 +19,16 @@ export default class ScopesScopeProjectsSessionsRoute extends Route { @resourceFilter({ allowed: ['active', 'pending', 'canceling', 'terminated'], - defaultValue: ['active','pending', 'canceling'] - }) status; + defaultValue: ['active', 'pending', 'canceling'], + }) + status; @resourceFilter({ allowed: (route) => route.modelFor('scopes.scope.projects'), serialize: ({ id }) => id, - findBySerialized: ({ id }, value) => id === value - }) project; - - /** - * A simple Ember Concurrency-based polling task that refreshes the route - * every POLL_TIMEOUT_SECONDS seconds. This is necessary to display changes - * to session `status` that may occur. - * - * NOTE: tasks are sort of attributes and sort of methods, but they are not - * language-level constructs. Thus we annotate this task as if it - * is an attribute. - * @type {Task} - */ - @task(function * () { - while(true) { - yield timeout(POLL_TIMEOUT_SECONDS * 1000); - yield this.refresh(); - } - /* eslint-disable-next-line prettier/prettier */ - }).drop() poller; + findBySerialized: ({ id }, value) => id === value, + }) + project; // =methods @@ -67,28 +50,23 @@ export default class ScopesScopeProjectsSessionsRoute extends Route { const { user_id } = this.session.data.authenticated; const projects = this.project || []; await this.store.query('target', { recursive: true, scope_id }); - return await this.resourceFilterStore.queryBy('session', { - user_id, - status, - scope_id: projects.map(({ id }) => id) - }, { - recursive: true, - scope_id - }); + return await this.resourceFilterStore.queryBy( + 'session', + { + user_id, + status, + scope_id: projects.map(({ id }) => id), + }, + { + recursive: true, + scope_id, + } + ); } - /** - * When this route is activated (entered), begin polling for changes. - */ - activate() { - this.poller.perform(); - } - - /** - * When this route is deactivated (exited), stop polling for changes. - */ - deactivate() { - this.poller.cancelAll(); + @runEvery(POLL_TIMEOUT_SECONDS * 1000) + poller() { + return this.refresh(); } // =actions diff --git a/ui/desktop/package.json b/ui/desktop/package.json index e1af18657..8bbca0a80 100755 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -53,7 +53,6 @@ "ember-named-blocks-polyfill": "^0.2.4" }, "devDependencies": { - "js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1", "@doyensec/electronegativity": "^1.9.1", "@ember/optional-features": "^2.0.0", "@ember/render-modifiers": "^1.0.2", @@ -93,6 +92,7 @@ "ember-modifier": "^2.1.2", "ember-notify": "^6.0.1", "ember-page-title": "^6.2.2", + "ember-pollster": "^0.0.1-beta.2", "ember-qunit": "^5.1.4", "ember-resolver": "^8.0.3", "ember-source": "~3.28.4", @@ -105,6 +105,7 @@ "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-qunit": "^6.2.0", "faker": "^5.5.3", + "js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1", "loader.js": "^4.7.0", "npm-run-all": "^4.1.5", "playwright": "^1.15.0", diff --git a/ui/desktop/tests/acceptance/projects/sessions-test.js b/ui/desktop/tests/acceptance/projects/sessions-test.js index 2b31e5eaa..e2e4db9e0 100644 --- a/ui/desktop/tests/acceptance/projects/sessions-test.js +++ b/ui/desktop/tests/acceptance/projects/sessions-test.js @@ -9,7 +9,6 @@ import { //getRootElement //setupOnerror, } from '@ember/test-helpers'; -import { run, later } from '@ember/runloop'; import { setupApplicationTest } from 'ember-qunit'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; import { Response } from 'miragejs'; @@ -167,112 +166,79 @@ module('Acceptance | projects | sessions', function (hooks) { test('visiting index', async function (assert) { assert.expect(2); const sessionsCount = this.server.schema.sessions.all().models.length; - // This later/cancelTimers technique allows us to test a page with - // active polling. Normally an acceptance test waits for all runloop timers - // to stop before returning from an awaited test, but polling means that - // runloop timers exist indefinitely. We thus schedule a cancelation before - // proceeding with our tests. - later(async () => { - run.cancelTimers(); - // await a11yAudit(); - assert.equal(currentURL(), urls.sessions); - assert.equal(findAll('tbody tr').length, sessionsCount); - }, 750); await visit(urls.sessions); + assert.equal(currentURL(), urls.sessions); + assert.equal(findAll('tbody tr').length, sessionsCount); }); test('visiting empty sessions', async function (assert) { assert.expect(1); this.server.get('/sessions', () => new Response(200)); - later(async () => { - run.cancelTimers(); - await a11yAudit(); - assert.ok( - find('.rose-message-title').textContent.trim(), - 'No Sessions Available' - ); - }, 750); await visit(urls.sessions); + await a11yAudit(); + assert.ok( + find('.rose-message-title').textContent.trim(), + 'No Sessions Available' + ); }); test('visiting sessions without targets is OK', async function (assert) { assert.expect(2); instances.session.update({ targetId: undefined }); const sessionsCount = this.server.schema.sessions.all().models.length; - later(async () => { - run.cancelTimers(); - await a11yAudit(); - assert.equal(currentURL(), urls.sessions); - assert.equal(findAll('tbody tr').length, sessionsCount); - }, 750); await visit(urls.sessions); + await a11yAudit(); + assert.equal(currentURL(), urls.sessions); + assert.equal(findAll('tbody tr').length, sessionsCount); }); test('can identify active sessions', async function (assert) { assert.expect(1); - later(async () => { - run.cancelTimers(); - assert.ok( - find('tbody tr:first-child th:first-child .session-status-active') - ); - }, 750); await visit(urls.sessions); + assert.ok( + find('tbody tr:first-child th:first-child .session-status-active') + ); }); test('cannot identify pending sessions', async function (assert) { assert.expect(1); instances.session.update({ status: 'pending' }); - later(async () => { - run.cancelTimers(); - assert.notOk( - find('tbody tr:first-child th:first-child .session-status-active') - ); - }, 750); await visit(urls.sessions); + assert.notOk( + find('tbody tr:first-child th:first-child .session-status-active') + ); }); test('cannot identify terminated sessions', async function (assert) { assert.expect(1); instances.session.update({ status: 'terminated' }); - later(async () => { - run.cancelTimers(); - assert.notOk( - find('tbody tr:first-child th:first-child .session-status-active') - ); - }, 750); await visit(urls.sessions); + assert.notOk( + find('tbody tr:first-child th:first-child .session-status-active') + ); }); test('cancelling a session', async function (assert) { assert.expect(1); stubs.ipcService.withArgs('stop'); - later(async () => { - run.cancelTimers(); - await click('tbody tr:first-child td:last-child button'); - assert.ok(find('[role="alert"].is-success')); - }, 750); await visit(urls.sessions); + await click('tbody tr:first-child td:last-child button'); + assert.ok(find('[role="alert"].is-success')); }); test('cancelling a session with error shows notification', async function (assert) { assert.expect(1); this.server.post('/sessions/:id_method', () => new Response(400)); - later(async () => { - run.cancelTimers(); - await click('tbody tr:first-child td:last-child button'); - assert.ok(find('[role="alert"].is-error')); - }, 750); await visit(urls.sessions); + await click('tbody tr:first-child td:last-child button'); + assert.ok(find('[role="alert"].is-error')); }); test('cancelling a session with ipc error shows notification', async function (assert) { assert.expect(1); stubs.ipcService.withArgs('stop').throws(); - later(async () => { - run.cancelTimers(); - await click('tbody tr:first-child td:last-child button'); - assert.ok(find('[role="alert"].is-error')); - }, 750); await visit(urls.sessions); + await click('tbody tr:first-child td:last-child button'); + assert.ok(find('[role="alert"].is-error')); }); }); From 71361799f754967fef255976fbf2417c123fc8a1 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Sun, 2 Jan 2022 19:40:45 -0500 Subject: [PATCH 3/6] refactor: rewrite targets polling for ember-pollster --- .../routes/scopes/scope/projects/targets.js | 84 ++++------ .../tests/acceptance/projects/targets-test.js | 143 +++++++----------- 2 files changed, 85 insertions(+), 142 deletions(-) diff --git a/ui/desktop/app/routes/scopes/scope/projects/targets.js b/ui/desktop/app/routes/scopes/scope/projects/targets.js index 2bed7e272..e33c5b833 100644 --- a/ui/desktop/app/routes/scopes/scope/projects/targets.js +++ b/ui/desktop/app/routes/scopes/scope/projects/targets.js @@ -1,14 +1,13 @@ import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; import { action } from '@ember/object'; -import { task, timeout } from 'ember-concurrency'; -import config from '../../../../config/environment'; import { resourceFilter } from 'core/decorators/resource-filter'; +import runEvery from 'ember-pollster/decorators/route/run-every'; +import config from '../../../../config/environment'; const POLL_TIMEOUT_SECONDS = config.sessionPollingTimeoutSeconds; export default class ScopesScopeProjectsTargetsRoute extends Route { - // =services @service ipc; @@ -23,26 +22,9 @@ export default class ScopesScopeProjectsTargetsRoute extends Route { @resourceFilter({ allowed: (route) => route.modelFor('scopes.scope.projects'), serialize: ({ id }) => id, - findBySerialized: ({ id }, value) => id === value - }) project; - - /** - * A simple Ember Concurrency-based polling task that refreshes the route - * every POLL_TIMEOUT_SECONDS seconds. This is necessary to display changes - * to session `status` that may occur. - * - * NOTE: tasks are sort of attributes and sort of methods, but they are not - * language-level constructs. Thus we annotate this task as if it - * is an attribute. - * @type {Task} - */ - @task(function * () { - while(true) { - yield timeout(POLL_TIMEOUT_SECONDS * 1000); - yield this.refresh(); - } - /* eslint-disable-next-line prettier/prettier */ - }).drop() poller; + findBySerialized: ({ id }, value) => id === value, + }) + project; // =methods @@ -61,33 +43,30 @@ export default class ScopesScopeProjectsTargetsRoute extends Route { const { id: scope_id } = this.modelFor('scopes.scope'); const { user_id } = this.session.data.authenticated; const projects = this.project || []; - await this.resourceFilterStore.queryBy('session', { user_id }, { - recursive: true, - scope_id - }); - return this.resourceFilterStore.queryBy('target', { - scope_id: projects.map(({ id }) => id), - authorized_actions: [ - { contains: 'authorize-session' }, - ] - }, { - recursive: true, - scope_id - }); + await this.resourceFilterStore.queryBy( + 'session', + { user_id }, + { + recursive: true, + scope_id, + } + ); + return this.resourceFilterStore.queryBy( + 'target', + { + scope_id: projects.map(({ id }) => id), + authorized_actions: [{ contains: 'authorize-session' }], + }, + { + recursive: true, + scope_id, + } + ); } - /** - * When this route is activated (entered), begin polling for changes. - */ - activate() { - this.poller.perform(); - } - - /** - * When this route is deactivated (exited), stop polling for changes. - */ - deactivate() { - this.poller.cancelAll(); + @runEvery(POLL_TIMEOUT_SECONDS * 1000) + poller() { + return this.refresh(); } // =actions @@ -112,7 +91,7 @@ export default class ScopesScopeProjectsTargetsRoute extends Route { const options = { target_id: model.id, - token: this.session.data.authenticated.token + token: this.session.data.authenticated.token, }; if (host) options.host_id = host.id; @@ -132,10 +111,11 @@ export default class ScopesScopeProjectsTargetsRoute extends Route { session.proxy_address = address; session.proxy_port = port; if (credentials) { - credentials.forEach(cred => session.addCredential(cred)); + credentials.forEach((cred) => session.addCredential(cred)); } - } catch(e) { - this.confirm.confirm(e.message, { isConnectError: true }) + } catch (e) { + this.confirm + .confirm(e.message, { isConnectError: true }) // Retry .then(() => this.connect(model)) .catch(() => null /* no op */); diff --git a/ui/desktop/tests/acceptance/projects/targets-test.js b/ui/desktop/tests/acceptance/projects/targets-test.js index 4971f209f..2935cef15 100644 --- a/ui/desktop/tests/acceptance/projects/targets-test.js +++ b/ui/desktop/tests/acceptance/projects/targets-test.js @@ -9,7 +9,6 @@ import { //getRootElement //setupOnerror, } from '@ember/test-helpers'; -import { run, later } from '@ember/runloop'; import { setupApplicationTest } from 'ember-qunit'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; import { Response } from 'miragejs'; @@ -174,52 +173,35 @@ module('Acceptance | projects | targets', function (hooks) { test('visiting index', async function (assert) { assert.expect(2); const targetsCount = this.server.schema.targets.all().models.length; - // This later/cancelTimers technique allows us to test a page with - // active polling. Normally an acceptance test waits for all runloop timers - // to stop before returning from an awaited test, but polling means that - // runloop timers exist indefinitely. We thus schedule a cancelation before - // proceeding with our tests. - later(async () => { - run.cancelTimers(); - await a11yAudit(); - assert.equal(currentURL(), urls.targets); - assert.equal(findAll('tbody tr').length, targetsCount); - }, 750); await visit(urls.targets); + await a11yAudit(); + assert.equal(currentURL(), urls.targets); + assert.equal(findAll('tbody tr').length, targetsCount); }); test('visiting a target', async function (assert) { assert.expect(1); - later(async () => { - run.cancelTimers(); - await click('tbody tr th a'); - assert.equal(currentURL(), urls.sessions); - }, 750); await visit(urls.targets); + await click('tbody tr th a'); + assert.equal(currentURL(), urls.sessions); }); test('visiting empty targets', async function (assert) { assert.expect(1); this.server.get('/targets', () => new Response(200)); - later(async () => { - run.cancelTimers(); - assert.equal( - find('.rose-message-title').textContent.trim(), - 'No Targets Available' - ); - }, 750); await visit(urls.targets); + assert.equal( + find('.rose-message-title').textContent.trim(), + 'No Targets Available' + ); }); test('cannot navigate to a target without proper authorization', async function (assert) { assert.expect(1); instances.target.authorized_actions = instances.target.authorized_actions.filter((item) => item !== 'read'); - later(async () => { - run.cancelTimers(); - assert.notOk(find('main tbody .rose-table-header-cell:nth-child(1) a')); - }, 750); await visit(urls.targets); + assert.notOk(find('main tbody .rose-table-header-cell:nth-child(1) a')); }); test('connecting to a target', async function (assert) { @@ -233,26 +215,22 @@ module('Acceptance | projects | targets', function (hooks) { }); const confirmService = this.owner.lookup('service:confirm'); confirmService.enabled = true; - - later(async () => { - run.cancelTimers(); - await click( - 'tbody tr:first-child td:last-child button', - 'Activate connect mode' - ); - assert.ok(find('.dialog-detail'), 'Success dialog'); - assert.equal(findAll('.rose-dialog-footer button').length, 1); - assert.equal( - find('.rose-dialog-footer button').textContent.trim(), - 'Close', - 'Cannot retry' - ); - assert.equal( - find('.rose-dialog-body .copyable-content').textContent.trim(), - 'a_123:p_123' - ); - }, 750); await visit(urls.targets); + await click( + 'tbody tr:first-child td:last-child button', + 'Activate connect mode' + ); + assert.ok(find('.dialog-detail'), 'Success dialog'); + assert.equal(findAll('.rose-dialog-footer button').length, 1); + assert.equal( + find('.rose-dialog-footer button').textContent.trim(), + 'Close', + 'Cannot retry' + ); + assert.equal( + find('.rose-dialog-body .copyable-content').textContent.trim(), + 'a_123:p_123' + ); }); // Skipping because this test doesn't make sense. Users will never even see @@ -269,12 +247,9 @@ module('Acceptance | projects | targets', function (hooks) { assert.notOk( instances.target.authorized_actions.includes('authorize-session') ); - later(async () => { - run.cancelTimers(); - assert.ok(find('tbody tr:first-child')); - assert.notOk(find('tbody tr:first-child td:last-child button')); - }, 750); await visit(urls.targets); + assert.ok(find('tbody tr:first-child')); + assert.notOk(find('tbody tr:first-child td:last-child button')); }); test('handles cli error on connect', async function (assert) { @@ -282,20 +257,16 @@ module('Acceptance | projects | targets', function (hooks) { stubs.ipcService.withArgs('cliExists').returns(true); const confirmService = this.owner.lookup('service:confirm'); confirmService.enabled = true; - - later(async () => { - run.cancelTimers(); - await click( - 'tbody tr:first-child td:last-child button', - 'Activate connect mode' - ); - assert.ok(find('.rose-dialog-error'), 'Error dialog'); - const dialogButtons = findAll('.rose-dialog-footer button'); - assert.equal(dialogButtons.length, 2); - assert.equal(dialogButtons[0].textContent.trim(), 'Retry', 'Can retry'); - assert.equal(dialogButtons[1].textContent.trim(), 'Cancel', 'Can cancel'); - }, 750); await visit(urls.targets); + await click( + 'tbody tr:first-child td:last-child button', + 'Activate connect mode' + ); + assert.ok(find('.rose-dialog-error'), 'Error dialog'); + const dialogButtons = findAll('.rose-dialog-footer button'); + assert.equal(dialogButtons.length, 2); + assert.equal(dialogButtons[0].textContent.trim(), 'Retry', 'Can retry'); + assert.equal(dialogButtons[1].textContent.trim(), 'Cancel', 'Can cancel'); }); test('handles connect error', async function (assert) { @@ -304,20 +275,16 @@ module('Acceptance | projects | targets', function (hooks) { stubs.ipcService.withArgs('connect').rejects(); const confirmService = this.owner.lookup('service:confirm'); confirmService.enabled = true; - - later(async () => { - run.cancelTimers(); - await click( - 'tbody tr:first-child td:last-child button', - 'Activate connect mode' - ); - assert.ok(find('.rose-dialog-error'), 'Error dialog'); - const dialogButtons = findAll('.rose-dialog-footer button'); - assert.equal(dialogButtons.length, 2); - assert.equal(dialogButtons[0].textContent.trim(), 'Retry', 'Can retry'); - assert.equal(dialogButtons[1].textContent.trim(), 'Cancel', 'Can cancel'); - }, 750); await visit(urls.targets); + await click( + 'tbody tr:first-child td:last-child button', + 'Activate connect mode' + ); + assert.ok(find('.rose-dialog-error'), 'Error dialog'); + const dialogButtons = findAll('.rose-dialog-footer button'); + assert.equal(dialogButtons.length, 2); + assert.equal(dialogButtons[0].textContent.trim(), 'Retry', 'Can retry'); + assert.equal(dialogButtons[1].textContent.trim(), 'Cancel', 'Can cancel'); }); test('can retry on error', async function (assert) { @@ -325,18 +292,14 @@ module('Acceptance | projects | targets', function (hooks) { stubs.ipcService.withArgs('cliExists').rejects(); const confirmService = this.owner.lookup('service:confirm'); confirmService.enabled = true; - - later(async () => { - run.cancelTimers(); - await click( - 'tbody tr:first-child td:last-child button', - 'Activate connect mode' - ); - const firstErrorDialog = find('.rose-dialog'); - await click('.rose-dialog footer .rose-button-primary', 'Retry'); - const secondErrorDialog = find('.rose-dialog'); - assert.notEqual(secondErrorDialog.id, firstErrorDialog.id); - }, 750); await visit(urls.targets); + await click( + 'tbody tr:first-child td:last-child button', + 'Activate connect mode' + ); + const firstErrorDialog = find('.rose-dialog'); + await click('.rose-dialog footer .rose-button-primary', 'Retry'); + const secondErrorDialog = find('.rose-dialog'); + assert.notEqual(secondErrorDialog.id, firstErrorDialog.id); }); }); From a3bb788716fb0b78fc02b4b444538a0aaaa4b094 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Sun, 2 Jan 2022 22:02:56 -0500 Subject: [PATCH 4/6] refactor: rewrite OIDC polling for ember pollster --- .../scopes/scope/authenticate/method/oidc.js | 41 +++---------------- ui/admin/config/environment.js | 3 -- .../tests/acceptance/authentication-test.js | 5 ++- 3 files changed, 9 insertions(+), 40 deletions(-) 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 db24f3bbd..b8fa4519c 100644 --- a/ui/admin/app/routes/scopes/scope/authenticate/method/oidc.js +++ b/ui/admin/app/routes/scopes/scope/authenticate/method/oidc.js @@ -1,42 +1,22 @@ import Route from '@ember/routing/route'; import { getOwner } from '@ember/application'; import { inject as service } from '@ember/service'; -import { task, timeout } from 'ember-concurrency'; import { action } from '@ember/object'; +import runEvery from 'ember-pollster/decorators/route/run-every'; import { notifyError } from 'core/decorators/notify'; import config from '../../../../../config/environment'; const POLL_TIMEOUT_SECONDS = config.oidcPollingTimeoutSeconds; export default class ScopesScopeAuthenticateMethodOidcRoute extends Route { - // =services @service session; @service windowManager; - // =attributes - - /** - * A simple Ember Concurrency-based polling task that refreshes the route - * every POLL_TIMEOUT_SECONDS seconds. This is necessary to display changes - * to session `status` that may occur. - * - * NOTE: tasks are sort of attributes and sort of methods, but they are not - * language-level constructs. Thus we annotate this task as if it - * is an attribute. - * @type {Task} - */ - @task(function * () { - while(!this.session.isAuthenticated) { - yield timeout(POLL_TIMEOUT_SECONDS * 1000); - yield this.refresh(); - } - /* eslint-disable-next-line prettier/prettier */ - }).drop() poller; - // =methods + beforeModel; model() { const scope = this.modelFor('scopes.scope'); const authMethod = this.modelFor('scopes.scope.authenticate.method'); @@ -47,18 +27,9 @@ export default class ScopesScopeAuthenticateMethodOidcRoute extends Route { return oidc.attemptFetchToken({ scope, authMethod }); } - /** - * If authenticated, redirects to index for further processing. - */ - redirect() { - if (this.session.isAuthenticated) this.replaceWith('index'); - } - - /** - * When this route is activated (entered), begin polling for changes. - */ - activate() { - this.poller.perform(); + @runEvery(POLL_TIMEOUT_SECONDS * 1000) + poller() { + this.refresh(); } /** @@ -66,7 +37,6 @@ export default class ScopesScopeAuthenticateMethodOidcRoute extends Route { * any windows opened via the window manager service. */ deactivate() { - this.poller.cancelAll(); this.windowManager.closeAll(); } @@ -81,5 +51,4 @@ export default class ScopesScopeAuthenticateMethodOidcRoute extends Route { // rethrow the error to activate the notifyError decorator throw e; } - } diff --git a/ui/admin/config/environment.js b/ui/admin/config/environment.js index 4792a3c17..dc951f583 100644 --- a/ui/admin/config/environment.js +++ b/ui/admin/config/environment.js @@ -151,9 +151,6 @@ module.exports = function (environment) { // Notification timeout should be 0 for fast tests ENV.notifyTimeout = 0; - // Polling timeouts should be short - ENV.sessionPollingTimeoutSeconds = 0.25; - ENV.oidcPollingTimeoutSeconds = 0; ENV.enableConfirmService = false; // Enable tests for development features diff --git a/ui/admin/tests/acceptance/authentication-test.js b/ui/admin/tests/acceptance/authentication-test.js index 3c1cedd48..b4ed094ea 100644 --- a/ui/admin/tests/acceptance/authentication-test.js +++ b/ui/admin/tests/acceptance/authentication-test.js @@ -12,7 +12,7 @@ import { import { setupApplicationTest } from 'ember-qunit'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; import { Response } from 'miragejs'; -//import { run, later } from '@ember/runloop'; +import { runAllJobs } from 'ember-pollster/test-support'; import a11yAudit from 'ember-a11y-testing/test-support/audit'; import { currentSession, @@ -383,6 +383,9 @@ 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 From 28de23b51783d09649b08f19ec7b3efaf9bc7917 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Sun, 2 Jan 2022 22:36:53 -0500 Subject: [PATCH 5/6] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20rewrite=20OIDC?= =?UTF-8?q?=20polling=20for=20ember=20pollster?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scopes/scope/authenticate/method/oidc.js | 44 +-------- .../tests/acceptance/authentication-test.js | 91 ++++++++----------- 2 files changed, 44 insertions(+), 91 deletions(-) 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 b6cb354c4..f2f8f81cd 100644 --- a/ui/desktop/app/routes/scopes/scope/authenticate/method/oidc.js +++ b/ui/desktop/app/routes/scopes/scope/authenticate/method/oidc.js @@ -1,39 +1,20 @@ import Route from '@ember/routing/route'; import { getOwner } from '@ember/application'; import { inject as service } from '@ember/service'; -import { task, timeout } from 'ember-concurrency'; import { action } from '@ember/object'; +import runEvery from 'ember-pollster/decorators/route/run-every'; import { notifyError } from 'core/decorators/notify'; import config from '../../../../../config/environment'; const POLL_TIMEOUT_SECONDS = config.oidcPollingTimeoutSeconds; export default class ScopesScopeAuthenticateMethodOidcRoute extends Route { - // =services @service session; // =attributes - /** - * A simple Ember Concurrency-based polling task that refreshes the route - * every POLL_TIMEOUT_SECONDS seconds. This is necessary to display changes - * to session `status` that may occur. - * - * NOTE: tasks are sort of attributes and sort of methods, but they are not - * language-level constructs. Thus we annotate this task as if it - * is an attribute. - * @type {Task} - */ - @task(function * () { - while(!this.session.isAuthenticated) { - yield timeout(POLL_TIMEOUT_SECONDS * 1000); - yield this.refresh(); - } - /* eslint-disable-next-line prettier/prettier */ - }).drop() poller; - // =methods model() { @@ -46,25 +27,9 @@ export default class ScopesScopeAuthenticateMethodOidcRoute extends Route { return oidc.attemptFetchToken({ scope, authMethod }); } - /** - * If authenticated, redirects to index for further processing. - */ - redirect() { - if (this.session.isAuthenticated) this.replaceWith('index'); - } - - /** - * When this route is activated (entered), begin polling for changes. - */ - activate() { - this.poller.perform(); - } - - /** - * When this route is deactivated (exited), stop polling for changes. - */ - deactivate() { - this.poller.cancelAll(); + @runEvery(POLL_TIMEOUT_SECONDS * 1000) + poller() { + this.refresh(); } /** @@ -78,5 +43,4 @@ export default class ScopesScopeAuthenticateMethodOidcRoute extends Route { // rethrow the error to activate the notifyError decorator throw e; } - } diff --git a/ui/desktop/tests/acceptance/authentication-test.js b/ui/desktop/tests/acceptance/authentication-test.js index c030a22c3..085a7d045 100644 --- a/ui/desktop/tests/acceptance/authentication-test.js +++ b/ui/desktop/tests/acceptance/authentication-test.js @@ -9,7 +9,6 @@ import { getRootElement, //setupOnerror, } from '@ember/test-helpers'; -import { run, later } from '@ember/runloop'; import { setupApplicationTest } from 'ember-qunit'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; import { Response } from 'miragejs'; @@ -162,20 +161,17 @@ module('Acceptance | authentication', function (hooks) { await visit(urls.authenticate.methods.global); await fillIn('[name="identification"]', 'test'); await fillIn('[name="password"]', 'test'); - later(async () => { - run.cancelTimers(); - assert.ok(currentSession().isAuthenticated); - await click('.rose-header-utilities .rose-dropdown summary'); - assert.equal( - find( - '.rose-header-utilities .rose-dropdown-content button' - ).textContent.trim(), - 'Deauthenticate' - ); - await click('.rose-header-utilities .rose-dropdown-content button'); - assert.notOk(currentSession().isAuthenticated); - }, 750); await click('[type="submit"]'); + assert.ok(currentSession().isAuthenticated); + await click('.rose-header-utilities .rose-dropdown summary'); + assert.equal( + find( + '.rose-header-utilities .rose-dropdown-content button' + ).textContent.trim(), + 'Deauthenticate' + ); + await click('.rose-header-utilities .rose-dropdown-content button'); + assert.notOk(currentSession().isAuthenticated); }); test('401 responses result in deauthentication', async function (assert) { @@ -183,21 +179,18 @@ module('Acceptance | authentication', function (hooks) { await visit(urls.authenticate.methods.global); await fillIn('[name="identification"]', 'test'); await fillIn('[name="password"]', 'test'); - later(async () => { - run.cancelTimers(); - assert.ok( - currentSession().isAuthenticated, - 'Session begins authenticated, before encountering 401' - ); - assert.ok(currentURL(), urls.targets); - this.server.get('/sessions', () => new Response(401)); - await visit(urls.sessions); - assert.notOk( - currentSession().isAuthenticated, - 'Session is unauthenticated, after encountering 401' - ); - }, 750); await click('[type="submit"]'); + assert.ok( + currentSession().isAuthenticated, + 'Session begins authenticated, before encountering 401' + ); + assert.ok(currentURL(), urls.targets); + this.server.get('/sessions', () => new Response(401)); + await visit(urls.sessions); + assert.notOk( + currentSession().isAuthenticated, + 'Session is unauthenticated, after encountering 401' + ); }); test('color theme is applied from session data', async function (assert) { @@ -208,29 +201,25 @@ module('Acceptance | authentication', function (hooks) { type: instances.scopes.global.type, }, }); - later(async () => { - run.cancelTimers(); - // system default - assert.notOk(currentSession().get('data.theme')); - assert.notOk(getRootElement().classList.contains('rose-theme-light')); - assert.notOk(getRootElement().classList.contains('rose-theme-dark')); - // toggle light mode - await click('[name="theme"][value="light"]'); - assert.equal(currentSession().get('data.theme'), 'light'); - assert.ok(getRootElement().classList.contains('rose-theme-light')); - assert.notOk(getRootElement().classList.contains('rose-theme-dark')); - // toggle dark mode - await click('[name="theme"][value="dark"]'); - assert.equal(currentSession().get('data.theme'), 'dark'); - assert.notOk(getRootElement().classList.contains('rose-theme-light')); - assert.ok(getRootElement().classList.contains('rose-theme-dark')); - // toggle system default - await click('[name="theme"][value=""]'); - assert.notOk(currentSession().get('data.theme')); - assert.notOk(getRootElement().classList.contains('rose-theme-light')); - assert.notOk(getRootElement().classList.contains('rose-theme-dark')); - }, 750); - await visit(urls.scopes.org); + // system default + assert.notOk(currentSession().get('data.theme')); + assert.notOk(getRootElement().classList.contains('rose-theme-light')); + assert.notOk(getRootElement().classList.contains('rose-theme-dark')); + // toggle light mode + await click('[name="theme"][value="light"]'); + assert.equal(currentSession().get('data.theme'), 'light'); + assert.ok(getRootElement().classList.contains('rose-theme-light')); + assert.notOk(getRootElement().classList.contains('rose-theme-dark')); + // toggle dark mode + await click('[name="theme"][value="dark"]'); + assert.equal(currentSession().get('data.theme'), 'dark'); + assert.notOk(getRootElement().classList.contains('rose-theme-light')); + assert.ok(getRootElement().classList.contains('rose-theme-dark')); + // toggle system default + await click('[name="theme"][value=""]'); + assert.notOk(currentSession().get('data.theme')); + assert.notOk(getRootElement().classList.contains('rose-theme-light')); + assert.notOk(getRootElement().classList.contains('rose-theme-dark')); }); }); From ebf2a0f11574442efc155cb7658d835471da7197 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Sun, 2 Jan 2022 22:38:32 -0500 Subject: [PATCH 6/6] chore: remove ember-concurrency dependency --- ui/admin/package.json | 1 - ui/desktop/package.json | 1 - yarn.lock | 38 ++++++-------------------------------- 3 files changed, 6 insertions(+), 34 deletions(-) diff --git a/ui/admin/package.json b/ui/admin/package.json index 9347d3adf..1ad98308e 100644 --- a/ui/admin/package.json +++ b/ui/admin/package.json @@ -62,7 +62,6 @@ "ember-cli-sri": "^2.1.1", "ember-cli-template-lint": "^2.0.2", "ember-cli-terser": "^4.0.2", - "ember-concurrency": "^1.3.0", "ember-exam": "^6.1.0", "ember-export-application-global": "^2.0.1", "ember-inline-svg": "^1.0.0", diff --git a/ui/desktop/package.json b/ui/desktop/package.json index 8bbca0a80..04733fe59 100755 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -82,7 +82,6 @@ "ember-cli-sri": "^2.1.1", "ember-cli-template-lint": "^2.0.2", "ember-cli-terser": "^4.0.2", - "ember-concurrency": "^1.3.0", "ember-electron": "^3.0.0", "ember-exam": "^6.1.0", "ember-export-application-global": "^2.0.1", diff --git a/yarn.lock b/yarn.lock index f4fde0895..ea6ccfe59 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9409,7 +9409,7 @@ debug@^3.0.0, debug@^3.0.1, debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: dependencies: ms "^2.1.1" -debuglog@*, debuglog@^1.0.1: +debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= @@ -10677,15 +10677,6 @@ ember-concurrency@^0.10.0: ember-compatibility-helpers "^1.2.0" ember-maybe-import-regenerator "^0.1.5" -ember-concurrency@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/ember-concurrency/-/ember-concurrency-1.3.0.tgz#66f90fb792687470bcee1172adc0ebf33f5e8b9c" - integrity sha512-DwGlfWFpYyAkTwsedlEtK4t1DznJSculAW6Vq5S1C0shVPc5b6tTpHB2FFYisannSYkm+wpm1f1Pd40qiNPtOQ== - dependencies: - ember-cli-babel "^7.7.3" - ember-compatibility-helpers "^1.2.0" - ember-maybe-import-regenerator "^0.1.6" - ember-cookies@^0.5.0, ember-cookies@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/ember-cookies/-/ember-cookies-0.5.2.tgz#06e33463f2f83254fefaf224cc944dec3fb9d3ba" @@ -10943,7 +10934,7 @@ ember-loading@^0.4.0: ember-concurrency "^0.10.0" ember-decorators-polyfill "^1.1.5" -ember-maybe-import-regenerator@^0.1.5, ember-maybe-import-regenerator@^0.1.6: +ember-maybe-import-regenerator@^0.1.5: version "0.1.6" resolved "https://registry.yarnpkg.com/ember-maybe-import-regenerator/-/ember-maybe-import-regenerator-0.1.6.tgz#35d41828afa6d6a59bc0da3ce47f34c573d776ca" integrity sha1-NdQYKK+m1qWbwNo85H80xXPXdso= @@ -14304,7 +14295,7 @@ import-lazy@^4.0.0: resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== -imurmurhash@*, imurmurhash@^0.1.4: +imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= @@ -16118,11 +16109,6 @@ lodash._baseflatten@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" -lodash._baseindexof@*: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" - integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw= - lodash._baseuniq@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" @@ -16131,16 +16117,11 @@ lodash._baseuniq@~4.6.0: lodash._createset "~4.0.0" lodash._root "~3.0.0" -lodash._bindcallback@*, lodash._bindcallback@^3.0.0: +lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4= -lodash._cacheindexof@*: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" - integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI= - lodash._createassigner@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" @@ -16150,19 +16131,12 @@ lodash._createassigner@^3.0.0: lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" -lodash._createcache@*: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" - integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM= - dependencies: - lodash._getnative "^3.0.0" - lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY= -lodash._getnative@*, lodash._getnative@^3.0.0: +lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= @@ -16380,7 +16354,7 @@ lodash.pick@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= -lodash.restparam@*, lodash.restparam@^3.0.0: +lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=