diff --git a/addons/api/addon/generated/models/session.js b/addons/api/addon/generated/models/session.js index ee751a988..a33426e4c 100644 --- a/addons/api/addon/generated/models/session.js +++ b/addons/api/addon/generated/models/session.js @@ -12,6 +12,7 @@ export default class GeneratedSessionModel extends BaseModel { @attr('string', { description: 'The name of the current status of this session.', + readOnly: true, }) status; diff --git a/ui/core/app/routes/scopes/scope/projects/project/sessions.js b/ui/core/app/routes/scopes/scope/projects/project/sessions.js index 48bbb5cc0..b41d76d7a 100644 --- a/ui/core/app/routes/scopes/scope/projects/project/sessions.js +++ b/ui/core/app/routes/scopes/scope/projects/project/sessions.js @@ -2,6 +2,9 @@ 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'; + +const POLL_TIMEOUT_SECONDS = 2.5; export default class ScopesScopeProjectsProjectSessionsRoute extends Route { @@ -10,6 +13,25 @@ export default class ScopesScopeProjectsProjectSessionsRoute extends Route { @service intl; @service notify; + // =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(true) { + yield timeout(POLL_TIMEOUT_SECONDS * 1000); + yield this.refresh(); + } + }).drop() poller; + // =methods /** @@ -29,6 +51,22 @@ export default class ScopesScopeProjectsProjectSessionsRoute extends Route { ); } + /** + * 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 + /** * Cancels the specified session and notifies user of success or error. * @param {SessionModel} diff --git a/ui/core/app/templates/scopes/scope/projects/project/sessions/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/sessions/index.hbs index 83e480e5e..6fe82d12b 100644 --- a/ui/core/app/templates/scopes/scope/projects/project/sessions/index.hbs +++ b/ui/core/app/templates/scopes/scope/projects/project/sessions/index.hbs @@ -19,6 +19,7 @@ {{t "resources.user"}} {{t "resources.target"}} {{t "form.label.started"}} + {{t "form.label.status"}} {{t "titles.actions"}} @@ -35,6 +36,9 @@ {{format-date-iso-human sessionAggregate.session.created_time}} + + {{sessionAggregate.session.status}} + {{t "actions.cancel"}} diff --git a/ui/core/mirage/config.js b/ui/core/mirage/config.js index fa23ee0e4..6803aac3d 100644 --- a/ui/core/mirage/config.js +++ b/ui/core/mirage/config.js @@ -1,5 +1,6 @@ import config from '../config/environment'; import { authHandler, deauthHandler } from './route-handlers/auth'; +import { pickRandomStatusString } from './factories/session'; //import { Response } from 'miragejs'; export default function() { @@ -295,10 +296,22 @@ export default function() { // session + // To simulate changes to `session.status` that may occur in the backend, + // we quietly randomize the value of the field on GET. this.get('/sessions', function ({ sessions }, { queryParams: { scope_id } }) { - return sessions.where(session => session.scopeId === scope_id); + sessions.where(session => session.scopeId === scope_id) + .models + .forEach(session => session.update({ + status: pickRandomStatusString() + })); + return sessions.where(session => session.scopeId === scope_id) + }); + this.get('/sessions/:id', function ({ sessions }, { params: { id } }) { + const session = sessions.find(id); + return session.update({ + status: pickRandomStatusString() + }); }); - this.get('/sessions/:id'); this.post('/sessions/:idMethod', function ({ sessions }, { params: { idMethod } }) { const attrs = this.normalizedRequestAttrs(); const id = idMethod.split(':')[0]; @@ -308,7 +321,7 @@ export default function() { version: attrs.version }; if (method === 'cancel') { - updatedAttrs.status = 'canceled'; + updatedAttrs.status = 'canceling'; } return session.update(updatedAttrs); }); diff --git a/ui/core/mirage/factories/session.js b/ui/core/mirage/factories/session.js index 9e5e31913..0100a4b75 100644 --- a/ui/core/mirage/factories/session.js +++ b/ui/core/mirage/factories/session.js @@ -1,9 +1,20 @@ import factory from '../generated/factories/target'; import { trait } from 'ember-cli-mirage'; +import { random } from 'faker'; + +const statusStrings = [ + 'pending', + 'active', + 'canceling', + 'terminated' +]; + +export const pickRandomStatusString = () => random.arrayElement(statusStrings); export default factory.extend({ id: (i) => `session-id-${i}`, + status: pickRandomStatusString, /** * Sessions generated with this trait will automatically form diff --git a/ui/core/package.json b/ui/core/package.json index 258f13a98..212ce3416 100644 --- a/ui/core/package.json +++ b/ui/core/package.json @@ -54,6 +54,7 @@ "ember-cli-sri": "^2.1.1", "ember-cli-template-lint": "^1.0.0-beta.3", "ember-cli-uglify": "^3.0.0", + "ember-concurrency": "^1.3.0", "ember-data": "~3.16.0", "ember-data-model-fragments": "5.0.0-beta.0", "ember-exam": "^5.0.1", diff --git a/ui/core/translations/en-us.yaml b/ui/core/translations/en-us.yaml index 7fb4748de..a37c9bfe3 100644 --- a/ui/core/translations/en-us.yaml +++ b/ui/core/translations/en-us.yaml @@ -163,6 +163,7 @@ form: current_password: Current Password new_password: New Password started: Started + status: Status errors: titles: unauthenticated-error: You are not signed in diff --git a/yarn.lock b/yarn.lock index 5304e5ace..658b62c2e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8923,6 +8923,15 @@ ember-compatibility-helpers@^1.1.1, ember-compatibility-helpers@^1.1.2, ember-co ember-cli-version-checker "^2.1.1" semver "^5.4.1" +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"