Merge branch 'main' into fix-field-name
This commit is contained in:
74 files changed
+1588
-829
No files matched your search
@@ -25,7 +25,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"ember-can": "^3.1.0",
|
||||
"ember-cli-babel": "^7.26.6",
|
||||
"ember-cli-babel": "^7.26.8",
|
||||
"ember-cli-htmlbars": "^5.7.1",
|
||||
"ember-cli-mirage": "^2.2.0",
|
||||
"ember-data": "^3.20.0",
|
||||
@@ -34,7 +34,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1",
|
||||
"@babel/core": "^7.15.8",
|
||||
"@babel/core": "^7.16.5",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/test-helpers": "^2.4.2",
|
||||
"@glimmer/component": "^1.0.4",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"doc:toc": "doctoc README.md"
|
||||
},
|
||||
"dependencies": {
|
||||
"ember-cli-babel": "^7.26.6",
|
||||
"ember-cli-babel": "^7.26.8",
|
||||
"ember-cli-htmlbars": "^5.7.1",
|
||||
"ember-fetch": "^8.1.1",
|
||||
"ember-simple-auth": "^4.0.0"
|
||||
|
||||
@@ -44,6 +44,11 @@ class RouteResourceFilter extends EmberObject {
|
||||
return this.allowed;
|
||||
}
|
||||
|
||||
get router() {
|
||||
const owner = getOwner(this.route);
|
||||
return owner.lookup('service:router');
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently selected value(s) for this filter, deserialized from the value of
|
||||
* the associated route query parameter.
|
||||
@@ -67,7 +72,7 @@ class RouteResourceFilter extends EmberObject {
|
||||
const queryParams = {};
|
||||
const serialized = value.map((value) => this.serializeValue(value));
|
||||
queryParams[this.filterKey] = JSON.stringify(serialized);
|
||||
this.route.transitionTo({ queryParams });
|
||||
this.router.transitionTo(this.route.routeName, { queryParams });
|
||||
}
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -31,11 +31,11 @@
|
||||
"api": "*",
|
||||
"auth": "*",
|
||||
"ember-browser-services": "^2.0.0",
|
||||
"ember-cli-babel": "^7.26.6",
|
||||
"ember-cli-babel": "^7.26.8",
|
||||
"ember-cli-htmlbars": "^5.7.1",
|
||||
"ember-feature-flags": "^6.0.0",
|
||||
"ember-intl": "^5.7.0",
|
||||
"ember-loading": "^0.4.0",
|
||||
"ember-loading": "^2.0.0",
|
||||
"ember-route-action-helper": "^2.0.8",
|
||||
"ember-truth-helpers": "^3.0.0",
|
||||
"rose": "*"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"doc:toc": "doctoc README.md"
|
||||
},
|
||||
"dependencies": {
|
||||
"ember-cli-babel": "^7.26.6",
|
||||
"ember-cli-babel": "^7.26.8",
|
||||
"ember-cli-htmlbars": "^5.7.1",
|
||||
"ember-focus-trap": "^0.7.0",
|
||||
"ember-named-blocks-polyfill": "^0.2.4",
|
||||
@@ -39,7 +39,7 @@
|
||||
"ember-composable-helpers": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.5",
|
||||
"@babel/core": "^7.16.5",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/test-helpers": "^2.4.2",
|
||||
"@glimmer/component": "^1.0.4",
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@
|
||||
"tmpl": "^1.0.5",
|
||||
"set-value": "^4.0.1",
|
||||
"ansi-regex": "^5.0.1",
|
||||
"ember-cli-babel": "^7.26.6",
|
||||
"ember-cli-babel": "^7.26.8",
|
||||
"jsonpointer": "5.0.0",
|
||||
"json-schema": "^0.4.0"
|
||||
},
|
||||
|
||||
@@ -2,11 +2,10 @@ import Component from '@glimmer/component';
|
||||
import ClipboardJS from 'clipboard';
|
||||
import { action } from '@ember/object';
|
||||
import { generateComponentID } from 'rose/utilities/component-auto-id';
|
||||
import { task, timeout } from 'ember-concurrency';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { later } from '@ember/runloop';
|
||||
|
||||
export default class CopyableComponent extends Component {
|
||||
|
||||
// =attributes
|
||||
|
||||
id = generateComponentID();
|
||||
@@ -21,23 +20,10 @@ export default class CopyableComponent extends Component {
|
||||
|
||||
clipboard = null;
|
||||
|
||||
/**
|
||||
* A Ember Concurrency-based task that updates copy icon to a success state
|
||||
* and back after 1 second. This icon flash indicates success on
|
||||
* copy to clipboard action.
|
||||
*
|
||||
* 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}
|
||||
*/
|
||||
/* istanbul ignore next */
|
||||
@task(function * () {
|
||||
confirmCopy() {
|
||||
this.copied = true;
|
||||
yield timeout(1000);
|
||||
this.copied = false;
|
||||
/* eslint-disable-next-line prettier/prettier */
|
||||
}).drop() confirmCopyTimer;
|
||||
later(() => (this.copied = false), 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for ClipboardJS support.
|
||||
@@ -62,7 +48,7 @@ export default class CopyableComponent extends Component {
|
||||
/* istanbul ignore next */
|
||||
this.clipboard.on('success', (clipboardEvent) => {
|
||||
clipboardEvent.clearSelection();
|
||||
this.confirmCopyTimer.perform();
|
||||
this.confirmCopy();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,7 +59,5 @@ export default class CopyableComponent extends Component {
|
||||
tearDown() {
|
||||
this.clipboard?.destroy();
|
||||
this.clipboard = null;
|
||||
this.confirmCopyTimer.cancelAll();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ export default class AccountRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service session;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -12,6 +13,6 @@ export default class AccountRoute extends Route {
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ export default class AccountChangePasswordRoute extends Route {
|
||||
@service session;
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -42,7 +43,7 @@ export default class AccountChangePasswordRoute extends Route {
|
||||
// redirects depending on the authentication context. These additional
|
||||
// redirects may abort this initial transition, resulting in a
|
||||
// TransitionAborted error, which we do not want to show to the user.
|
||||
await this.replaceWith('index').catch(() => {});
|
||||
await this.router.replaceWith('index').catch(() => {});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,6 +51,6 @@ export default class AccountChangePasswordRoute extends Route {
|
||||
*/
|
||||
@action
|
||||
cancel() {
|
||||
this.replaceWith('index');
|
||||
this.router.replaceWith('index');
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,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 loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { A } from '@ember/array';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class IndexRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Redirects to scopes route for further processing.
|
||||
*/
|
||||
redirect() {
|
||||
this.transitionTo('scopes');
|
||||
this.router.transitionTo('scopes');
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ export default class ScopesIndexRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service session;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -21,9 +22,9 @@ export default class ScopesIndexRoute extends Route {
|
||||
'data.authenticated.scope.id'
|
||||
);
|
||||
if (authenticatedScopeID) {
|
||||
this.transitionTo('scopes.scope', authenticatedScopeID);
|
||||
this.router.transitionTo('scopes.scope', authenticatedScopeID);
|
||||
} else {
|
||||
this.transitionTo('scopes.scope', 'global');
|
||||
this.router.transitionTo('scopes.scope', 'global');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { A } from '@ember/array';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
@@ -12,6 +12,7 @@ export default class ScopesScopeRoute extends Route {
|
||||
@service intl;
|
||||
@service session;
|
||||
@service scope;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -116,7 +117,7 @@ export default class ScopesScopeRoute extends Route {
|
||||
cancel(scope) {
|
||||
const { isNew } = scope;
|
||||
scope.rollbackAttributes();
|
||||
if (isNew) this.transitionTo('scopes.scope');
|
||||
if (isNew) this.router.transitionTo('scopes.scope');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,7 +134,7 @@ export default class ScopesScopeRoute extends Route {
|
||||
async save(scope) {
|
||||
const { isNew } = scope;
|
||||
await scope.save();
|
||||
await this.transitionTo('scopes.scope.edit', scope);
|
||||
await this.router.transitionTo('scopes.scope.edit', scope);
|
||||
if (isNew) this.refresh();
|
||||
}
|
||||
|
||||
@@ -149,7 +150,7 @@ export default class ScopesScopeRoute extends Route {
|
||||
async delete(scope) {
|
||||
const { scopeID } = scope;
|
||||
await scope.destroyRecord();
|
||||
await this.replaceWith('scopes.scope.scopes', scopeID);
|
||||
await this.router.replaceWith('scopes.scope.scopes', scopeID);
|
||||
//this.refresh();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
import { resourceFilter } from 'core/decorators/resource-filter';
|
||||
@@ -14,6 +14,7 @@ export default class ScopesScopeAuthMethodsRoute extends Route {
|
||||
@service session;
|
||||
@service can;
|
||||
@service resourceFilterStore;
|
||||
@service router;
|
||||
|
||||
// =attributes
|
||||
|
||||
@@ -25,7 +26,7 @@ export default class ScopesScopeAuthMethodsRoute extends Route {
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,7 +57,7 @@ export default class ScopesScopeAuthMethodsRoute extends Route {
|
||||
cancel(authMethod) {
|
||||
const { isNew } = authMethod;
|
||||
authMethod.rollbackAttributes();
|
||||
if (isNew) this.transitionTo('scopes.scope.auth-methods');
|
||||
if (isNew) this.router.transitionTo('scopes.scope.auth-methods');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,12 +73,12 @@ export default class ScopesScopeAuthMethodsRoute extends Route {
|
||||
async save(authMethod) {
|
||||
await authMethod.save();
|
||||
if (this.can.can('read model', authMethod)) {
|
||||
await this.transitionTo(
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.auth-methods.auth-method',
|
||||
authMethod
|
||||
);
|
||||
} else {
|
||||
await this.transitionTo('scopes.scope.auth-methods');
|
||||
await this.router.transitionTo('scopes.scope.auth-methods');
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
@@ -97,7 +98,7 @@ export default class ScopesScopeAuthMethodsRoute extends Route {
|
||||
// Reload the scope, since this is where the primary_auth_method_id is
|
||||
// stored. An auth method deletion could affect this field.
|
||||
await scopeModel.reload();
|
||||
await this.replaceWith('scopes.scope.auth-methods');
|
||||
await this.router.replaceWith('scopes.scope.auth-methods');
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
@@ -11,6 +11,8 @@ export default class ScopesScopeAuthMethodsAuthMethodAccountsRoute extends Route
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service can;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
@@ -40,7 +42,9 @@ export default class ScopesScopeAuthMethodsAuthMethodAccountsRoute extends Route
|
||||
const { isNew } = account;
|
||||
account.rollbackAttributes();
|
||||
if (isNew)
|
||||
this.transitionTo('scopes.scope.auth-methods.auth-method.accounts');
|
||||
this.router.transitionTo(
|
||||
'scopes.scope.auth-methods.auth-method.accounts'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,12 +65,14 @@ export default class ScopesScopeAuthMethodsAuthMethodAccountsRoute extends Route
|
||||
}
|
||||
await account.save({ adapterOptions });
|
||||
if (this.can.can('read model', account)) {
|
||||
await this.transitionTo(
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.auth-methods.auth-method.accounts.account',
|
||||
account
|
||||
);
|
||||
} else {
|
||||
await this.transitionTo('scopes.scope.auth-methods.auth-method.accounts');
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.auth-methods.auth-method.accounts'
|
||||
);
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
@@ -82,7 +88,9 @@ export default class ScopesScopeAuthMethodsAuthMethodAccountsRoute extends Route
|
||||
@notifySuccess('notifications.delete-success')
|
||||
async deleteAccount(account) {
|
||||
await account.destroyRecord();
|
||||
await this.replaceWith('scopes.scope.auth-methods.auth-method.accounts');
|
||||
await this.router.replaceWith(
|
||||
'scopes.scope.auth-methods.auth-method.accounts'
|
||||
);
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeAuthMethodsAuthMethodAccountsAccountSettingsRoute extends Route {
|
||||
@@ -9,6 +9,7 @@ export default class ScopesScopeAuthMethodsAuthMethodAccountsAccountSettingsRout
|
||||
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -40,7 +41,7 @@ export default class ScopesScopeAuthMethodsAuthMethodAccountsAccountSettingsRout
|
||||
@notifySuccess('notifications.save-success')
|
||||
async setPassword(account, password) {
|
||||
await account.setPassword(password);
|
||||
await this.replaceWith(
|
||||
await this.router.replaceWith(
|
||||
'scopes.scope.auth-methods.auth-method.accounts.account.set-password'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
@@ -11,6 +11,7 @@ export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsRoute extends
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service can;
|
||||
@service router;
|
||||
|
||||
//=methods
|
||||
|
||||
@@ -40,7 +41,9 @@ export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsRoute extends
|
||||
const { isNew } = managedGroup;
|
||||
managedGroup.rollbackAttributes();
|
||||
if (isNew) {
|
||||
this.transitionTo('scopes.scope.auth-methods.auth-method.managed-groups');
|
||||
this.router.transitionTo(
|
||||
'scopes.scope.auth-methods.auth-method.managed-groups'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,12 +60,12 @@ export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsRoute extends
|
||||
async save(managedGroup) {
|
||||
await managedGroup.save();
|
||||
if (this.can.can('read model', managedGroup)) {
|
||||
await this.transitionTo(
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.auth-methods.auth-method.managed-groups.managed-group',
|
||||
managedGroup
|
||||
);
|
||||
} else {
|
||||
await this.transitionTo(
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.auth-methods.auth-method.managed-groups'
|
||||
);
|
||||
}
|
||||
@@ -80,7 +83,7 @@ export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsRoute extends
|
||||
@notifySuccess('notifications.delete-success')
|
||||
async delete(managedGroup) {
|
||||
await managedGroup.destroyRecord();
|
||||
await this.replaceWith(
|
||||
await this.router.replaceWith(
|
||||
'scopes.scope.auth-methods.auth-method.managed-groups'
|
||||
);
|
||||
this.refresh();
|
||||
|
||||
@@ -6,11 +6,13 @@ export default class ScopesScopeAuthenticateRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service session;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
beforeModel() {
|
||||
if (this.session.isAuthenticated) this.transitionTo('scopes.scope.index');
|
||||
if (this.session.isAuthenticated)
|
||||
this.router.transitionTo('scopes.scope.index');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class ScopesScopeAuthenticateIndexRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
@@ -12,7 +17,10 @@ export default class ScopesScopeAuthenticateIndexRoute extends Route {
|
||||
redirect({ authMethods }) {
|
||||
const firstAuthMethod = authMethods.firstObject;
|
||||
if (firstAuthMethod) {
|
||||
this.transitionTo('scopes.scope.authenticate.method', firstAuthMethod);
|
||||
this.router.transitionTo(
|
||||
'scopes.scope.authenticate.method',
|
||||
firstAuthMethod
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { getOwner } from '@ember/application';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
||||
@@ -12,6 +12,7 @@ export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
||||
@service notify;
|
||||
@service intl;
|
||||
@service windowManager;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -60,14 +61,14 @@ export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
||||
requestCookies,
|
||||
{ scope, authMethod }
|
||||
);
|
||||
this.transitionTo('index');
|
||||
this.router.transitionTo('index');
|
||||
break;
|
||||
case 'oidc':
|
||||
await this.startOIDCAuthentication(authenticatorName, {
|
||||
scope,
|
||||
authMethod,
|
||||
});
|
||||
this.transitionTo('scopes.scope.authenticate.method.oidc');
|
||||
this.router.transitionTo('scopes.scope.authenticate.method.oidc');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,23 @@
|
||||
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;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
beforeModel;
|
||||
model() {
|
||||
const scope = this.modelFor('scopes.scope');
|
||||
const authMethod = this.modelFor('scopes.scope.authenticate.method');
|
||||
@@ -47,18 +28,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 +38,6 @@ export default class ScopesScopeAuthenticateMethodOidcRoute extends Route {
|
||||
* any windows opened via the window manager service.
|
||||
*/
|
||||
deactivate() {
|
||||
this.poller.cancelAll();
|
||||
this.windowManager.closeAll();
|
||||
}
|
||||
|
||||
@@ -77,9 +48,8 @@ export default class ScopesScopeAuthenticateMethodOidcRoute extends Route {
|
||||
@action
|
||||
@notifyError(() => 'errors.authentication-failed.title', { catch: true })
|
||||
error(e) {
|
||||
this.transitionTo('scopes.scope.authenticate.method.index');
|
||||
this.router.transitionTo('scopes.scope.authenticate.method.index');
|
||||
// rethrow the error to activate the notifyError decorator
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +1,18 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeCredentialStoresRoute extends Route {
|
||||
// =methods
|
||||
// =services
|
||||
|
||||
@service can;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Load all credential stores under current scope
|
||||
* @returns {Promise[CredentialStoreModel]}
|
||||
@@ -36,7 +41,7 @@ export default class ScopesScopeCredentialStoresRoute extends Route {
|
||||
@notifySuccess('notifications.save-success')
|
||||
async save(credentialStore) {
|
||||
await credentialStore.save();
|
||||
await this.transitionTo(
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.credential-stores.credential-store',
|
||||
credentialStore
|
||||
);
|
||||
@@ -51,7 +56,7 @@ export default class ScopesScopeCredentialStoresRoute extends Route {
|
||||
cancel(credentialStore) {
|
||||
const { isNew } = credentialStore;
|
||||
credentialStore.rollbackAttributes();
|
||||
if (isNew) this.transitionTo('scopes.scope.credential-stores');
|
||||
if (isNew) this.router.transitionTo('scopes.scope.credential-stores');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +70,7 @@ export default class ScopesScopeCredentialStoresRoute extends Route {
|
||||
@notifySuccess('notifications.delete-success')
|
||||
async delete(credentialStore) {
|
||||
await credentialStore.destroyRecord();
|
||||
await this.replaceWith('scopes.scope.credential-stores');
|
||||
await this.router.replaceWith('scopes.scope.credential-stores');
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
+10
-6
@@ -1,13 +1,17 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrariesRoute extends Route {
|
||||
// =methods
|
||||
// =services
|
||||
|
||||
@service can;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Loads all credential libraries under the current credential store.
|
||||
@@ -38,7 +42,7 @@ export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrari
|
||||
const { isNew } = credentialLibrary;
|
||||
credentialLibrary.rollbackAttributes();
|
||||
if (isNew)
|
||||
this.transitionTo(
|
||||
this.router.transitionTo(
|
||||
'scopes.scope.credential-stores.credential-store.credential-libraries'
|
||||
);
|
||||
}
|
||||
@@ -56,12 +60,12 @@ export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrari
|
||||
async save(credentialLibrary) {
|
||||
await credentialLibrary.save();
|
||||
if (this.can.can('read model', credentialLibrary)) {
|
||||
await this.transitionTo(
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.credential-stores.credential-store.credential-libraries.credential-library',
|
||||
credentialLibrary
|
||||
);
|
||||
} else {
|
||||
await this.transitionTo(
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.credential-stores.credential-store.credential-libraries'
|
||||
);
|
||||
}
|
||||
@@ -79,7 +83,7 @@ export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrari
|
||||
@notifySuccess('notifications.delete-success')
|
||||
async delete(credentialLibrary) {
|
||||
await credentialLibrary.destroyRecord();
|
||||
await this.replaceWith(
|
||||
await this.router.replaceWith(
|
||||
'scopes.scope.credential-stores.credential-store.credential-libraries'
|
||||
);
|
||||
this.refresh();
|
||||
|
||||
@@ -5,6 +5,7 @@ export default class ScopesScopeEditRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service session;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -12,6 +13,6 @@ export default class ScopesScopeEditRoute extends Route {
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
@@ -12,13 +12,15 @@ export default class ScopesScopeGroupsRoute extends Route {
|
||||
@service notify;
|
||||
@service session;
|
||||
@service can;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,7 +44,7 @@ export default class ScopesScopeGroupsRoute extends Route {
|
||||
cancel(group) {
|
||||
const { isNew } = group;
|
||||
group.rollbackAttributes();
|
||||
if (isNew) this.transitionTo('scopes.scope.groups');
|
||||
if (isNew) this.router.transitionTo('scopes.scope.groups');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,9 +60,9 @@ export default class ScopesScopeGroupsRoute extends Route {
|
||||
async save(group) {
|
||||
await group.save();
|
||||
if (this.can.can('read model', group)) {
|
||||
await this.transitionTo('scopes.scope.groups.group', group);
|
||||
await this.router.transitionTo('scopes.scope.groups.group', group);
|
||||
} else {
|
||||
await this.transitionTo('scopes.scope.groups');
|
||||
await this.router.transitionTo('scopes.scope.groups');
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
@@ -76,7 +78,7 @@ export default class ScopesScopeGroupsRoute extends Route {
|
||||
@notifySuccess('notifications.delete-success')
|
||||
async delete(group) {
|
||||
await group.destroyRecord();
|
||||
await this.replaceWith('scopes.scope.groups');
|
||||
await this.router.replaceWith('scopes.scope.groups');
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { hash } from 'rsvp';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeGroupsGroupAddMembersRoute extends Route {
|
||||
@@ -10,6 +10,7 @@ export default class ScopesScopeGroupsGroupAddMembersRoute extends Route {
|
||||
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -70,7 +71,7 @@ export default class ScopesScopeGroupsGroupAddMembersRoute extends Route {
|
||||
@notifySuccess('notifications.add-success')
|
||||
async addMembers(group, userIDs) {
|
||||
await group.addMembers(userIDs);
|
||||
await this.replaceWith('scopes.scope.groups.group.members');
|
||||
await this.router.replaceWith('scopes.scope.groups.group.members');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,6 +79,6 @@ export default class ScopesScopeGroupsGroupAddMembersRoute extends Route {
|
||||
*/
|
||||
@action
|
||||
cancel() {
|
||||
this.replaceWith('scopes.scope.groups.group.members');
|
||||
this.router.replaceWith('scopes.scope.groups.group.members');
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { hash, all } from 'rsvp';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
@@ -12,13 +12,15 @@ export default class ScopesScopeHostCatalogsRoute extends Route {
|
||||
@service notify;
|
||||
@service session;
|
||||
@service can;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,7 +47,7 @@ export default class ScopesScopeHostCatalogsRoute extends Route {
|
||||
cancel(hostCatalog) {
|
||||
const { isNew } = hostCatalog;
|
||||
hostCatalog.rollbackAttributes();
|
||||
if (isNew) this.transitionTo('scopes.scope.host-catalogs');
|
||||
if (isNew) this.router.transitionTo('scopes.scope.host-catalogs');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,7 +63,7 @@ export default class ScopesScopeHostCatalogsRoute extends Route {
|
||||
)
|
||||
async save(hostCatalog) {
|
||||
await hostCatalog.save();
|
||||
await this.transitionTo(
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.host-catalogs.host-catalog',
|
||||
hostCatalog
|
||||
);
|
||||
@@ -79,7 +81,7 @@ export default class ScopesScopeHostCatalogsRoute extends Route {
|
||||
@notifySuccess('notifications.delete-success')
|
||||
async delete(hostCatalog) {
|
||||
await hostCatalog.destroyRecord();
|
||||
await this.replaceWith('scopes.scope.host-catalogs');
|
||||
await this.router.replaceWith('scopes.scope.host-catalogs');
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
@@ -11,6 +11,8 @@ export default class ScopesScopeHostCatalogsHostCatalogHostSetsRoute extends Rou
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service can;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
@@ -43,7 +45,9 @@ export default class ScopesScopeHostCatalogsHostCatalogHostSetsRoute extends Rou
|
||||
const { isNew } = hostSet;
|
||||
hostSet.rollbackAttributes();
|
||||
if (isNew)
|
||||
this.transitionTo('scopes.scope.host-catalogs.host-catalog.host-sets');
|
||||
this.router.transitionTo(
|
||||
'scopes.scope.host-catalogs.host-catalog.host-sets'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,12 +64,12 @@ export default class ScopesScopeHostCatalogsHostCatalogHostSetsRoute extends Rou
|
||||
async save(hostSet) {
|
||||
await hostSet.save();
|
||||
if (this.can.can('read model', hostSet)) {
|
||||
await this.transitionTo(
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.host-catalogs.host-catalog.host-sets.host-set',
|
||||
hostSet
|
||||
);
|
||||
} else {
|
||||
await this.transitionTo(
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.host-catalogs.host-catalog.host-sets'
|
||||
);
|
||||
}
|
||||
@@ -83,6 +87,8 @@ export default class ScopesScopeHostCatalogsHostCatalogHostSetsRoute extends Rou
|
||||
@notifySuccess('notifications.delete-success')
|
||||
async deleteHostSet(hostSet) {
|
||||
await hostSet.destroyRecord();
|
||||
await this.replaceWith('scopes.scope.host-catalogs.host-catalog.host-sets');
|
||||
await this.router.replaceWith(
|
||||
'scopes.scope.host-catalogs.host-catalog.host-sets'
|
||||
);
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { hash } from 'rsvp';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeHostCatalogsHostCatalogHostSetsHostSetAddHostsRoute extends Route {
|
||||
@@ -10,6 +10,7 @@ export default class ScopesScopeHostCatalogsHostCatalogHostSetsHostSetAddHostsRo
|
||||
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -75,7 +76,7 @@ export default class ScopesScopeHostCatalogsHostCatalogHostSetsHostSetAddHostsRo
|
||||
@notifySuccess('notifications.add-success')
|
||||
async addHosts(hostSet, hostIDs) {
|
||||
await hostSet.addHosts(hostIDs);
|
||||
await this.replaceWith(
|
||||
await this.router.replaceWith(
|
||||
'scopes.scope.host-catalogs.host-catalog.host-sets.host-set.hosts'
|
||||
);
|
||||
}
|
||||
@@ -85,7 +86,7 @@ export default class ScopesScopeHostCatalogsHostCatalogHostSetsHostSetAddHostsRo
|
||||
*/
|
||||
@action
|
||||
cancel() {
|
||||
this.replaceWith(
|
||||
this.router.replaceWith(
|
||||
'scopes.scope.host-catalogs.host-catalog.host-sets.host-set.hosts'
|
||||
);
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeHostCatalogsHostCatalogHostSetsHostSetCreateAndAddHostRoute extends Route {
|
||||
@@ -9,6 +9,7 @@ export default class ScopesScopeHostCatalogsHostCatalogHostSetsHostSetCreateAndA
|
||||
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -70,7 +71,7 @@ export default class ScopesScopeHostCatalogsHostCatalogHostSetsHostSetCreateAndA
|
||||
);
|
||||
await host.save();
|
||||
await hostSet.addHost(host.id);
|
||||
await this.replaceWith(
|
||||
await this.router.replaceWith(
|
||||
'scopes.scope.host-catalogs.host-catalog.host-sets.host-set.hosts'
|
||||
);
|
||||
}
|
||||
@@ -80,7 +81,7 @@ export default class ScopesScopeHostCatalogsHostCatalogHostSetsHostSetCreateAndA
|
||||
*/
|
||||
@action
|
||||
cancel() {
|
||||
this.replaceWith(
|
||||
this.router.replaceWith(
|
||||
'scopes.scope.host-catalogs.host-catalog.host-sets.host-set.hosts'
|
||||
);
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { hash, all } from 'rsvp';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
@@ -11,6 +11,8 @@ export default class ScopesScopeHostCatalogsHostCatalogHostsRoute extends Route
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service can;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
@@ -42,7 +44,7 @@ export default class ScopesScopeHostCatalogsHostCatalogHostsRoute extends Route
|
||||
const { isNew } = host;
|
||||
host.rollbackAttributes();
|
||||
if (isNew)
|
||||
this.transitionTo('scopes.scope.host-catalogs.host-catalog.hosts');
|
||||
this.router.transitionTo('scopes.scope.host-catalogs.host-catalog.hosts');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,12 +61,14 @@ export default class ScopesScopeHostCatalogsHostCatalogHostsRoute extends Route
|
||||
async save(host) {
|
||||
await host.save();
|
||||
if (this.can.can('read model', host)) {
|
||||
await this.transitionTo(
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.host-catalogs.host-catalog.hosts.host',
|
||||
host
|
||||
);
|
||||
} else {
|
||||
await this.transitionTo('scopes.scope.host-catalogs.host-catalog.hosts');
|
||||
await this.router.transitionTo(
|
||||
'scopes.scope.host-catalogs.host-catalog.hosts'
|
||||
);
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
@@ -80,7 +84,9 @@ export default class ScopesScopeHostCatalogsHostCatalogHostsRoute extends Route
|
||||
@notifySuccess('notifications.delete-success')
|
||||
async deleteHost(host) {
|
||||
await host.destroyRecord();
|
||||
await this.replaceWith('scopes.scope.host-catalogs.host-catalog.hosts');
|
||||
await this.router.replaceWith(
|
||||
'scopes.scope.host-catalogs.host-catalog.hosts'
|
||||
);
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ export default class ScopesScopeIndexRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service session;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -15,11 +16,11 @@ export default class ScopesScopeIndexRoute extends Route {
|
||||
*/
|
||||
redirect(model) {
|
||||
if (!this.session.isAuthenticated) {
|
||||
this.transitionTo('scopes.scope.authenticate');
|
||||
this.router.transitionTo('scopes.scope.authenticate');
|
||||
} else if (model.isProject) {
|
||||
this.transitionTo('scopes.scope.edit');
|
||||
this.router.transitionTo('scopes.scope.edit');
|
||||
} else {
|
||||
this.transitionTo('scopes.scope.scopes');
|
||||
this.router.transitionTo('scopes.scope.scopes');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ export default class ScopesScopeNewRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service session;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -12,7 +13,7 @@ export default class ScopesScopeNewRoute extends Route {
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
@@ -12,6 +12,7 @@ export default class ScopesScopeRolesRoute extends Route {
|
||||
@service notify;
|
||||
@service session;
|
||||
@service can;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -19,7 +20,7 @@ export default class ScopesScopeRolesRoute extends Route {
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +44,7 @@ export default class ScopesScopeRolesRoute extends Route {
|
||||
cancel(role) {
|
||||
const { isNew } = role;
|
||||
role.rollbackAttributes();
|
||||
if (isNew) this.transitionTo('scopes.scope.roles');
|
||||
if (isNew) this.router.transitionTo('scopes.scope.roles');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,9 +60,9 @@ export default class ScopesScopeRolesRoute extends Route {
|
||||
async save(role) {
|
||||
await role.save();
|
||||
if (this.can.can('read model', role)) {
|
||||
await this.transitionTo('scopes.scope.roles.role', role);
|
||||
await this.router.transitionTo('scopes.scope.roles.role', role);
|
||||
} else {
|
||||
await this.transitionTo('scopes.scope.roles');
|
||||
await this.router.transitionTo('scopes.scope.roles');
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
@@ -77,7 +78,7 @@ export default class ScopesScopeRolesRoute extends Route {
|
||||
@notifySuccess('notifications.delete-success')
|
||||
async delete(role) {
|
||||
await role.destroyRecord();
|
||||
await this.replaceWith('scopes.scope.roles');
|
||||
await this.router.replaceWith('scopes.scope.roles');
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { hash } from 'rsvp';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeRolesRoleAddPrincipalsRoute extends Route {
|
||||
@@ -10,6 +10,7 @@ export default class ScopesScopeRolesRoleAddPrincipalsRoute extends Route {
|
||||
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -64,7 +65,7 @@ export default class ScopesScopeRolesRoleAddPrincipalsRoute extends Route {
|
||||
@notifySuccess('notifications.add-success')
|
||||
async addPrincipals(role, principalIDs) {
|
||||
await role.addPrincipals(principalIDs);
|
||||
this.replaceWith('scopes.scope.roles.role.principals');
|
||||
this.router.replaceWith('scopes.scope.roles.role.principals');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,6 +73,6 @@ export default class ScopesScopeRolesRoleAddPrincipalsRoute extends Route {
|
||||
*/
|
||||
@action
|
||||
cancel() {
|
||||
this.replaceWith('scopes.scope.roles.role.principals');
|
||||
this.router.replaceWith('scopes.scope.roles.role.principals');
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeRolesRoleGrantsRoute extends Route {
|
||||
|
||||
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { all, hash } from 'rsvp';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ export default class ScopesScopeScopesRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service session;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -17,7 +18,7 @@ export default class ScopesScopeScopesRoute extends Route {
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,38 +11,26 @@ import { resourceFilter } from 'core/decorators/resource-filter';
|
||||
const POLL_TIMEOUT_SECONDS = config.sessionPollingTimeoutSeconds;
|
||||
|
||||
export default class ScopesScopeSessionsRoute extends Route {
|
||||
|
||||
// =services
|
||||
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service session;
|
||||
@service resourceFilterStore;
|
||||
@service router;
|
||||
|
||||
// =attributes
|
||||
|
||||
@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
|
||||
|
||||
@@ -50,7 +38,7 @@ export default class ScopesScopeSessionsRoute extends Route {
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,47 +56,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 +99,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 = [];
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
@@ -12,6 +12,7 @@ export default class ScopesScopeTargetsRoute extends Route {
|
||||
@service notify;
|
||||
@service session;
|
||||
@service can;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -19,7 +20,7 @@ export default class ScopesScopeTargetsRoute extends Route {
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,7 +45,7 @@ export default class ScopesScopeTargetsRoute extends Route {
|
||||
cancel(target) {
|
||||
const { isNew } = target;
|
||||
target.rollbackAttributes();
|
||||
if (isNew) this.transitionTo('scopes.scope.targets');
|
||||
if (isNew) this.router.transitionTo('scopes.scope.targets');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,9 +62,9 @@ export default class ScopesScopeTargetsRoute extends Route {
|
||||
async save(target) {
|
||||
await target.save();
|
||||
if (this.can.can('read model', target)) {
|
||||
await this.transitionTo('scopes.scope.targets.target', target);
|
||||
await this.router.transitionTo('scopes.scope.targets.target', target);
|
||||
} else {
|
||||
await this.transitionTo('scopes.scope.targets');
|
||||
await this.router.transitionTo('scopes.scope.targets');
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
@@ -79,7 +80,7 @@ export default class ScopesScopeTargetsRoute extends Route {
|
||||
@notifySuccess('notifications.delete-success')
|
||||
async delete(target) {
|
||||
await target.destroyRecord();
|
||||
await this.replaceWith('scopes.scope.targets');
|
||||
await this.router.replaceWith('scopes.scope.targets');
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { all } from 'rsvp';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeTargetsTargetAddCredentialSourcesRoute extends Route {
|
||||
@@ -10,6 +10,7 @@ export default class ScopesScopeTargetsTargetAddCredentialSourcesRoute extends R
|
||||
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -78,7 +79,7 @@ export default class ScopesScopeTargetsTargetAddCredentialSourcesRoute extends R
|
||||
@notifySuccess('notifications.add-success')
|
||||
async save(target, credentialLibraryIDs) {
|
||||
await target.addCredentialSources(credentialLibraryIDs);
|
||||
this.replaceWith('scopes.scope.targets.target.credential-sources');
|
||||
this.router.replaceWith('scopes.scope.targets.target.credential-sources');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,6 +87,6 @@ export default class ScopesScopeTargetsTargetAddCredentialSourcesRoute extends R
|
||||
*/
|
||||
@action
|
||||
cancel() {
|
||||
this.replaceWith('scopes.scope.targets.target.credential-sources');
|
||||
this.router.replaceWith('scopes.scope.targets.target.credential-sources');
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { all } from 'rsvp';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeTargetsTargetAddHostSourcesRoute extends Route {
|
||||
@@ -10,6 +10,7 @@ export default class ScopesScopeTargetsTargetAddHostSourcesRoute extends Route {
|
||||
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -72,7 +73,7 @@ export default class ScopesScopeTargetsTargetAddHostSourcesRoute extends Route {
|
||||
@notifySuccess('notifications.add-success')
|
||||
async save(target, hostSetIDs) {
|
||||
await target.addHostSources(hostSetIDs);
|
||||
this.replaceWith('scopes.scope.targets.target.host-sources');
|
||||
this.router.replaceWith('scopes.scope.targets.target.host-sources');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,6 +81,6 @@ export default class ScopesScopeTargetsTargetAddHostSourcesRoute extends Route {
|
||||
*/
|
||||
@action
|
||||
cancel() {
|
||||
this.replaceWith('scopes.scope.targets.target.host-sources');
|
||||
this.router.replaceWith('scopes.scope.targets.target.host-sources');
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { all } from 'rsvp';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { all, hash } from 'rsvp';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
@@ -12,6 +12,7 @@ export default class ScopesScopeUsersRoute extends Route {
|
||||
@service notify;
|
||||
@service session;
|
||||
@service can;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -19,7 +20,7 @@ export default class ScopesScopeUsersRoute extends Route {
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +44,7 @@ export default class ScopesScopeUsersRoute extends Route {
|
||||
cancel(user) {
|
||||
const { isNew } = user;
|
||||
user.rollbackAttributes();
|
||||
if (isNew) this.transitionTo('scopes.scope.users');
|
||||
if (isNew) this.router.transitionTo('scopes.scope.users');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,9 +61,9 @@ export default class ScopesScopeUsersRoute extends Route {
|
||||
async save(user) {
|
||||
await user.save();
|
||||
if (this.can.can('read model', user)) {
|
||||
await this.transitionTo('scopes.scope.users.user', user);
|
||||
await this.router.transitionTo('scopes.scope.users.user', user);
|
||||
} else {
|
||||
await this.transitionTo('scopes.scope.users');
|
||||
await this.router.transitionTo('scopes.scope.users');
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
@@ -78,7 +79,7 @@ export default class ScopesScopeUsersRoute extends Route {
|
||||
@notifySuccess('notifications.delete-success')
|
||||
async delete(user) {
|
||||
await user.destroyRecord();
|
||||
await this.replaceWith('scopes.scope.users');
|
||||
await this.router.replaceWith('scopes.scope.users');
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { hash, all } from 'rsvp';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeUsersUserAccountsRoute extends Route {
|
||||
|
||||
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { all } from 'rsvp';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeUsersUserAddAccountsRoute extends Route {
|
||||
@@ -10,6 +10,7 @@ export default class ScopesScopeUsersUserAddAccountsRoute extends Route {
|
||||
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -74,7 +75,7 @@ export default class ScopesScopeUsersUserAddAccountsRoute extends Route {
|
||||
@notifySuccess('notifications.add-success')
|
||||
async addAccounts(user, accountIDs) {
|
||||
await user.addAccounts(accountIDs);
|
||||
await this.replaceWith('scopes.scope.users.user.accounts');
|
||||
await this.router.replaceWith('scopes.scope.users.user.accounts');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,6 +83,6 @@ export default class ScopesScopeUsersUserAddAccountsRoute extends Route {
|
||||
*/
|
||||
@action
|
||||
cancel() {
|
||||
this.replaceWith('scopes.scope.users.user.accounts');
|
||||
this.router.replaceWith('scopes.scope.users.user.accounts');
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
.rose-dropdown {
|
||||
$icon-width: sizing.rems(m) + sizing.rems(s);
|
||||
$indent: $icon-width + sizing.rems(xs);
|
||||
$indent: $icon-width + sizing.rems(xs);
|
||||
|
||||
.rose-form-radio-label {
|
||||
display: flex;
|
||||
@@ -129,7 +129,14 @@
|
||||
&.loading {
|
||||
&::after {
|
||||
animation: gradient 1s linear infinite;
|
||||
background: repeating-linear-gradient(to right, var(--subtle), var(--subtle), var(--info), var(--subtle), var(--subtle));
|
||||
background: repeating-linear-gradient(
|
||||
to right,
|
||||
var(--subtle),
|
||||
var(--subtle),
|
||||
var(--info),
|
||||
var(--subtle),
|
||||
var(--subtle)
|
||||
);
|
||||
background-position: -100% 0;
|
||||
background-size: 200% auto;
|
||||
content: ' ';
|
||||
@@ -140,8 +147,12 @@
|
||||
top: 100%;
|
||||
|
||||
@keyframes gradient {
|
||||
0% { background-position: -100% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
0% {
|
||||
background-position: -100% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,8 +194,12 @@
|
||||
color: inherit;
|
||||
|
||||
@keyframes fadeBackground {
|
||||
0% { background-color: var(--action-subtler-1); }
|
||||
100% { background-color: transparent; }
|
||||
0% {
|
||||
background-color: var(--action-subtler-1);
|
||||
}
|
||||
100% {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -35,8 +35,7 @@
|
||||
"ember-named-blocks-polyfill": "^0.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1",
|
||||
"@babel/core": "^7.15.5",
|
||||
"@babel/core": "^7.16.5",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/render-modifiers": "^1.0.2",
|
||||
"@ember/test-helpers": "^2.4.2",
|
||||
@@ -53,7 +52,7 @@
|
||||
"ember-breadcrumbs": "^0.2.3",
|
||||
"ember-cli": "~3.28.3",
|
||||
"ember-cli-app-version": "^5.0.0",
|
||||
"ember-cli-babel": "^7.26.6",
|
||||
"ember-cli-babel": "^7.26.8",
|
||||
"ember-cli-code-coverage": "^1.0.3",
|
||||
"ember-cli-content-security-policy": "^1.1.1",
|
||||
"ember-cli-dependency-checker": "^3.2.0",
|
||||
@@ -63,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",
|
||||
@@ -72,6 +70,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 +83,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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'));
|
||||
});
|
||||
});
|
||||
@@ -1,13 +1,12 @@
|
||||
import Component from '@glimmer/component';
|
||||
import ClipboardJS from 'clipboard';
|
||||
import { action } from '@ember/object';
|
||||
import { getOwner } from '@ember/application';
|
||||
import { generateComponentID } from 'rose/utilities/component-auto-id';
|
||||
import { task, timeout } from 'ember-concurrency';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import ClipboardJS from 'clipboard';
|
||||
import { later } from '@ember/runloop';
|
||||
|
||||
export default class CopyableComponent extends Component {
|
||||
|
||||
// =attributes
|
||||
|
||||
id = generateComponentID();
|
||||
@@ -22,23 +21,10 @@ export default class CopyableComponent extends Component {
|
||||
|
||||
clipboard = null;
|
||||
|
||||
/**
|
||||
* A Ember Concurrency-based task that updates copy icon to a success state
|
||||
* and back after 1 second. This icon flash indicates success on
|
||||
* copy to clipboard action.
|
||||
*
|
||||
* 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}
|
||||
*/
|
||||
/* istanbul ignore next */
|
||||
@task(function * () {
|
||||
confirmCopy() {
|
||||
this.copied = true;
|
||||
yield timeout(1000);
|
||||
this.copied = false;
|
||||
/* eslint-disable-next-line prettier/prettier */
|
||||
}).drop() confirmCopyTimer;
|
||||
later(() => (this.copied = false), 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for ClipboardJS support.
|
||||
@@ -77,12 +63,12 @@ export default class CopyableComponent extends Component {
|
||||
// container to a modal (if exists), since this is the only container
|
||||
// a user would be able to interact with. If a modal doesn't exist,
|
||||
// container is set to `undefined` and thus uses the default body element.
|
||||
container: this.getFirstElementByClassName('rose-dialog')
|
||||
container: this.getFirstElementByClassName('rose-dialog'),
|
||||
});
|
||||
/* istanbul ignore next */
|
||||
this.clipboard.on('success', (clipboardEvent) => {
|
||||
clipboardEvent.clearSelection();
|
||||
this.confirmCopyTimer.perform();
|
||||
this.confirmCopy();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -93,7 +79,5 @@ export default class CopyableComponent extends Component {
|
||||
tearDown() {
|
||||
this.clipboard?.destroy();
|
||||
this.clipboard = null;
|
||||
this.confirmCopyTimer.cancelAll();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { A } from '@ember/array';
|
||||
import { getOwner } from '@ember/application';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
|
||||
export default class ApplicationRoute extends Route {
|
||||
// =services
|
||||
|
||||
@@ -5,6 +5,7 @@ export default class IndexRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service origin;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -14,9 +15,9 @@ export default class IndexRoute extends Route {
|
||||
redirect() {
|
||||
const rendererOrigin = this.origin.rendererOrigin;
|
||||
if (!rendererOrigin) {
|
||||
this.replaceWith('origin');
|
||||
this.router.replaceWith('origin');
|
||||
} else {
|
||||
this.replaceWith('scopes');
|
||||
this.router.replaceWith('scopes');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { getOwner } from '@ember/application';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import config from '../config/environment';
|
||||
|
||||
export default class OriginRoute extends Route {
|
||||
@@ -12,6 +12,7 @@ export default class OriginRoute extends Route {
|
||||
@service origin;
|
||||
@service intl;
|
||||
@service notify;
|
||||
@service router;
|
||||
|
||||
// =attributes
|
||||
|
||||
@@ -40,7 +41,7 @@ export default class OriginRoute extends Route {
|
||||
* processing. User must be logged out before changing the origin.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (this.session.isAuthenticated) this.replaceWith('index');
|
||||
if (this.session.isAuthenticated) this.router.replaceWith('index');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,7 +72,7 @@ export default class OriginRoute extends Route {
|
||||
async setOrigin(origin) {
|
||||
try {
|
||||
await this.origin.setOrigin(origin);
|
||||
this.replaceWith('index');
|
||||
this.router.replaceWith('index');
|
||||
} catch (e) {
|
||||
// If scopes do not load, we assume this is not a Boundary API
|
||||
const errorMessage = this.intl.t(
|
||||
|
||||
@@ -6,6 +6,7 @@ export default class ScopesIndexRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service session;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -21,9 +22,9 @@ export default class ScopesIndexRoute extends Route {
|
||||
'data.authenticated.scope.id'
|
||||
);
|
||||
if (authenticatedScopeID) {
|
||||
this.replaceWith('scopes.scope', authenticatedScopeID);
|
||||
this.router.replaceWith('scopes.scope', authenticatedScopeID);
|
||||
} else {
|
||||
this.replaceWith('scopes.scope', 'global');
|
||||
this.router.replaceWith('scopes.scope', 'global');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,13 @@ export default class ScopesScopeAuthenticateRoute extends Route {
|
||||
|
||||
@service session;
|
||||
@service origin;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
beforeModel() {
|
||||
if (this.session.isAuthenticated) this.replaceWith('scopes.scope.index');
|
||||
if (this.session.isAuthenticated)
|
||||
this.router.replaceWith('scopes.scope.index');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,7 +31,7 @@ export default class ScopesScopeAuthenticateRoute extends Route {
|
||||
}
|
||||
|
||||
redirect() {
|
||||
if (!this.origin.rendererOrigin) this.replaceWith('index');
|
||||
if (!this.origin.rendererOrigin) this.router.replaceWith('index');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class ScopesScopeAuthenticateIndexRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
@@ -12,7 +17,10 @@ export default class ScopesScopeAuthenticateIndexRoute extends Route {
|
||||
redirect({ authMethods }) {
|
||||
const firstAuthMethod = authMethods.firstObject;
|
||||
if (firstAuthMethod) {
|
||||
this.replaceWith('scopes.scope.authenticate.method', firstAuthMethod);
|
||||
this.router.replaceWith(
|
||||
'scopes.scope.authenticate.method',
|
||||
firstAuthMethod
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { getOwner } from '@ember/application';
|
||||
import { action } from '@ember/object';
|
||||
import loading from 'ember-loading/decorator';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
||||
@@ -12,6 +12,7 @@ export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
||||
@service notify;
|
||||
@service ipc;
|
||||
@service intl;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -67,14 +68,14 @@ export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
||||
requestCookies,
|
||||
{ scope, authMethod }
|
||||
);
|
||||
this.transitionTo('index');
|
||||
this.router.transitionTo('index');
|
||||
break;
|
||||
case 'oidc':
|
||||
await this.startOIDCAuthentication(authenticatorName, {
|
||||
scope,
|
||||
authMethod,
|
||||
});
|
||||
this.transitionTo('scopes.scope.authenticate.method.oidc');
|
||||
this.router.transitionTo('scopes.scope.authenticate.method.oidc');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,18 @@
|
||||
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;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -46,25 +26,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();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,9 +38,8 @@ export default class ScopesScopeAuthenticateMethodOidcRoute extends Route {
|
||||
@action
|
||||
@notifyError(() => 'errors.authentication-failed.title', { catch: true })
|
||||
error(e) {
|
||||
this.transitionTo('scopes.scope.authenticate.method.index');
|
||||
this.router.transitionTo('scopes.scope.authenticate.method.index');
|
||||
// rethrow the error to activate the notifyError decorator
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ export default class ScopesScopeIndexRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service session;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -15,9 +16,9 @@ export default class ScopesScopeIndexRoute extends Route {
|
||||
*/
|
||||
redirect() {
|
||||
if (!this.session.isAuthenticated) {
|
||||
this.replaceWith('scopes.scope.authenticate');
|
||||
this.router.replaceWith('scopes.scope.authenticate');
|
||||
} else {
|
||||
this.replaceWith('scopes.scope.projects.targets');
|
||||
this.router.replaceWith('scopes.scope.projects.targets');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ export default class ScopesScopeProjectsRoute extends Route {
|
||||
|
||||
@service session;
|
||||
@service resourceFilterStore;
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -27,7 +28,7 @@ export default class ScopesScopeProjectsRoute extends Route {
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,51 +1,35 @@
|
||||
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;
|
||||
@service session;
|
||||
@service resourceFilterStore;
|
||||
@service router;
|
||||
|
||||
// =attributes
|
||||
|
||||
@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
|
||||
|
||||
@@ -53,7 +37,7 @@ export default class ScopesScopeProjectsSessionsRoute extends Route {
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,28 +51,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
|
||||
|
||||
@@ -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;
|
||||
@@ -17,32 +16,16 @@ export default class ScopesScopeProjectsTargetsRoute extends Route {
|
||||
@service notify;
|
||||
@service confirm;
|
||||
@service resourceFilterStore;
|
||||
@service router;
|
||||
|
||||
// =attributes
|
||||
|
||||
@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
|
||||
|
||||
@@ -50,7 +33,7 @@ export default class ScopesScopeProjectsTargetsRoute extends Route {
|
||||
* If arriving here unauthenticated, redirect to index for further processing.
|
||||
*/
|
||||
beforeModel() {
|
||||
if (!this.session.isAuthenticated) this.transitionTo('index');
|
||||
if (!this.session.isAuthenticated) this.router.transitionTo('index');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,33 +44,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 +92,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 +112,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 */);
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class ScopesScopeProjectsTargetsTargetIndexRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service router;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Navigate to hosts within a target.
|
||||
*/
|
||||
afterModel() {
|
||||
this.transitionTo('scopes.scope.projects.targets.target.sessions');
|
||||
this.router.transitionTo('scopes.scope.projects.targets.target.sessions');
|
||||
}
|
||||
}
|
||||
@@ -257,7 +257,8 @@
|
||||
border-radius: sizing.rems(xxxs);
|
||||
margin: 0 auto;
|
||||
margin-top: sizing.rems(l) * 1.25;
|
||||
padding: (sizing.rems(l) * 4) (sizing.rems(l) * 3) (sizing.rems(l) * 2) (sizing.rems(l) * 3);
|
||||
padding: (sizing.rems(l) * 4) (sizing.rems(l) * 3) (sizing.rems(l) * 2)
|
||||
(sizing.rems(l) * 3);
|
||||
position: relative;
|
||||
width: sizing.rems(l) * 16;
|
||||
|
||||
@@ -324,7 +325,6 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
// Dialog Detail
|
||||
// These styles are a Work In Progress. Expect changes (lots of them)
|
||||
.rose-dialog,
|
||||
@@ -487,12 +487,14 @@ $chevron-down: url("data:image/svg+xml;utf-8,<svg viewBox='0 0 24 24' fill='%231
|
||||
color: var(--ui-gray-subtler-2);
|
||||
}
|
||||
|
||||
.rose-button-ghost { // Copyable button icon.
|
||||
.rose-button-ghost {
|
||||
// Copyable button icon.
|
||||
color: var(--ui-gray-subtler-1);
|
||||
}
|
||||
}
|
||||
|
||||
.rose-button-ghost { // Hide/Show secret button icon.
|
||||
.rose-button-ghost {
|
||||
// Hide/Show secret button icon.
|
||||
color: var(--ui-gray);
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
@@ -74,7 +73,7 @@
|
||||
"ember-autofocus-modifier": "^2.0.0",
|
||||
"ember-cli": "~3.28.3",
|
||||
"ember-cli-app-version": "^5.0.0",
|
||||
"ember-cli-babel": "^7.26.6",
|
||||
"ember-cli-babel": "^7.26.8",
|
||||
"ember-cli-code-coverage": "^1.0.3",
|
||||
"ember-cli-dependency-checker": "^3.2.0",
|
||||
"ember-cli-htmlbars": "^5.7.1",
|
||||
@@ -83,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",
|
||||
@@ -93,6 +91,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 +104,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",
|
||||
|
||||
@@ -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';
|
||||
@@ -35,6 +34,9 @@ module('Acceptance | authentication', function (hooks) {
|
||||
global: null,
|
||||
org: null,
|
||||
},
|
||||
user: null,
|
||||
target: null,
|
||||
session: null,
|
||||
};
|
||||
|
||||
const stubs = {
|
||||
@@ -66,6 +68,10 @@ module('Acceptance | authentication', function (hooks) {
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
instances.user = this.server.create('user', {
|
||||
scope: instances.scopes.global,
|
||||
});
|
||||
|
||||
invalidateSession();
|
||||
|
||||
// create scopes
|
||||
@@ -92,6 +98,22 @@ module('Acceptance | authentication', function (hooks) {
|
||||
type: 'password',
|
||||
});
|
||||
|
||||
instances.target = this.server.create(
|
||||
'target',
|
||||
{ scope: instances.scopes.project },
|
||||
'withAssociations'
|
||||
);
|
||||
instances.session = this.server.create(
|
||||
'session',
|
||||
{
|
||||
scope: instances.scopes.project,
|
||||
target: instances.target,
|
||||
status: 'active',
|
||||
user: instances.user,
|
||||
},
|
||||
'withAssociations'
|
||||
);
|
||||
|
||||
urls.scopes.global = `/scopes/${instances.scopes.global.id}`;
|
||||
urls.scopes.org = `/scopes/${instances.scopes.org.id}`;
|
||||
urls.authenticate.global = `${urls.scopes.global}/authenticate`;
|
||||
@@ -162,42 +184,40 @@ 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) {
|
||||
assert.expect(3);
|
||||
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"]');
|
||||
authenticateSession({
|
||||
scope: {
|
||||
id: instances.scopes.global.id,
|
||||
type: instances.scopes.global.type,
|
||||
},
|
||||
});
|
||||
await visit(urls.sessions);
|
||||
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.targets);
|
||||
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 +228,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'));
|
||||
});
|
||||
});
|
||||
@@ -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'));
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user