Merge branch 'init-sessions-view' of github.com:hashicorp/boundary-ui into init-sessions-view
This commit is contained in:
14 files changed
+194
-131
No files matched your search
@@ -50,25 +50,22 @@ export function notifyError(notification, options = { catch: false }) {
|
||||
desc.value = async function () {
|
||||
const owner = getOwner(this);
|
||||
const notifyService = owner.lookup('service:notify');
|
||||
//const intlService = owner.lookup('service:intl');
|
||||
const intlService = owner.lookup('service:intl');
|
||||
|
||||
try {
|
||||
return await method.apply(this, arguments);
|
||||
} catch (error) {
|
||||
// As of now all error notifications pass a function, but this code
|
||||
// could support either a function or a string.
|
||||
// const candidateKey = (typeof notification === 'function')
|
||||
// ? notification.apply(this, [error])
|
||||
// : notification;
|
||||
const candidateKey = notification.apply(this, [error]);
|
||||
|
||||
// As of now, we only use untranslated strings for error notifications,
|
||||
// but this code would support both translated and arbitrary strings.
|
||||
// const text = intlService.exists(candidateKey)
|
||||
// ? intlService.t(candidateKey)
|
||||
// : candidateKey;
|
||||
const text = candidateKey;
|
||||
const candidateKey = (typeof notification === 'function')
|
||||
? notification.apply(this, [error])
|
||||
: notification;
|
||||
|
||||
const text = intlService.exists(candidateKey)
|
||||
? intlService.t(candidateKey)
|
||||
: candidateKey;
|
||||
|
||||
notifyService.error(text, { closeAfter: null });
|
||||
|
||||
if (options.catch) {
|
||||
// squelch the error
|
||||
} else {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<LinkTo
|
||||
...attributes
|
||||
@route={{@route}}
|
||||
@query={{@query}}
|
||||
@model={{@model}}
|
||||
class="rose-dropdown-link {{if @style (concat "rose-dropdown-link-" @style)}}"
|
||||
>
|
||||
@@ -11,6 +12,7 @@
|
||||
<LinkTo
|
||||
...attributes
|
||||
@route={{@route}}
|
||||
@query={{@query}}
|
||||
class="rose-dropdown-link {{if @style (concat "rose-dropdown-link-" @style)}}"
|
||||
>
|
||||
{{yield}}
|
||||
|
||||
@@ -1,57 +1,7 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
<form.input
|
||||
@value={{@model.type}}
|
||||
@label={{t "form.type.label"}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}} />
|
||||
|
||||
<form.input
|
||||
@name="name"
|
||||
@type="name"
|
||||
@value={{@model.name}}
|
||||
@label={{t "form.name.label"}}
|
||||
@helperText={{t "form.name.help"}}
|
||||
@error={{@model.errors.name}}
|
||||
readonly={{false}}
|
||||
as |field|>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name="description"
|
||||
@type="description"
|
||||
@value={{@model.description}}
|
||||
@label={{t "form.description.label"}}
|
||||
@helperText={{t "form.description.help"}}
|
||||
@error={{@model.errors.description}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t "actions.edit-form"}}
|
||||
@submitText={{t "actions.save"}}
|
||||
@cancelText={{t "actions.cancel"}} />
|
||||
</Rose::Form>
|
||||
{{#if @model.type}}
|
||||
{{component (concat "form/auth-method/" @model.type)
|
||||
model=@model
|
||||
submit=@submit
|
||||
cancel=@cancel
|
||||
}}
|
||||
{{/if}}
|
||||
@@ -0,0 +1,57 @@
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
<form.input
|
||||
@value={{@model.type}}
|
||||
@label={{t "form.type.label"}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}} />
|
||||
|
||||
<form.input
|
||||
@name="name"
|
||||
@type="name"
|
||||
@value={{@model.name}}
|
||||
@label={{t "form.name.label"}}
|
||||
@helperText={{t "form.name.help"}}
|
||||
@error={{@model.errors.name}}
|
||||
readonly={{false}}
|
||||
as |field|>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<form.textarea
|
||||
@name="description"
|
||||
@type="description"
|
||||
@value={{@model.description}}
|
||||
@label={{t "form.description.label"}}
|
||||
@helperText={{t "form.description.help"}}
|
||||
@error={{@model.errors.description}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
as |field|>
|
||||
{{#if @model.errors.description}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.textarea>
|
||||
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@enableEditText={{t "actions.edit-form"}}
|
||||
@submitText={{t "actions.save"}}
|
||||
@cancelText={{t "actions.cancel"}} />
|
||||
</Rose::Form>
|
||||
@@ -0,0 +1,7 @@
|
||||
{{#if @model.type}}
|
||||
{{component (concat "form/authenticate/" @model.type)
|
||||
submit=@submit
|
||||
cancel=false
|
||||
disabled=@disabled
|
||||
}}
|
||||
{{/if}}
|
||||
@@ -0,0 +1,28 @@
|
||||
<Rose::Form
|
||||
class="full-width"
|
||||
@onSubmit={{fn this.submit @submit (hash
|
||||
identification=this.identification
|
||||
password=this.password
|
||||
)}}
|
||||
@cancel={{false}}
|
||||
@disabled={{@disabled}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<form.input
|
||||
@name="identification"
|
||||
@type="text"
|
||||
@value={{this.identification}}
|
||||
@label={{t "form.login_name.label"}} />
|
||||
|
||||
<form.input
|
||||
@name="password"
|
||||
@type="password"
|
||||
@value={{this.password}}
|
||||
@label={{t "form.password.label"}} />
|
||||
|
||||
<form.actions
|
||||
@submitText={{t "actions.authenticate"}}
|
||||
@showCancel={{false}} />
|
||||
|
||||
</Rose::Form>
|
||||
@@ -0,0 +1,37 @@
|
||||
import Component from '@glimmer/component';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { run } from '@ember/runloop';
|
||||
|
||||
export default class FormAuthenticatePasswordComponent extends Component {
|
||||
// =properties
|
||||
|
||||
/**
|
||||
* New password property
|
||||
* @type {string}
|
||||
*/
|
||||
@tracked password;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Unsets the password field.
|
||||
*/
|
||||
resetPassword() {
|
||||
this.password = null;
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
* Submit credentials, but reset the password first in case of failure.
|
||||
* Callback with no arguments otherwise.
|
||||
* @param {function} fn
|
||||
* @param {object} creds
|
||||
*/
|
||||
@action
|
||||
submit(fn, creds) {
|
||||
run(() => this.resetPassword());
|
||||
run(() => fn(creds));
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ export default class ScopesScopeAuthMethodsNewController extends Controller {
|
||||
|
||||
// =attributes
|
||||
|
||||
queryParams = ['type'];
|
||||
|
||||
/**
|
||||
* Translated new auth-method breadcrumb
|
||||
* @type {string}
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
import Route from '@ember/routing/route';
|
||||
|
||||
export default class ScopesScopeAuthMethodsNewRoute extends Route {
|
||||
// =attributes
|
||||
|
||||
queryParams = {
|
||||
type: {
|
||||
refreshModel: true
|
||||
}
|
||||
};
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Create a new unsaved auth-method.
|
||||
* @return {AuthMethodModel}
|
||||
*/
|
||||
model() {
|
||||
model(params) {
|
||||
const scopeModel = this.modelFor('scopes.scope');
|
||||
return this.store.createRecord('auth-method', {
|
||||
scopeModel,
|
||||
type: 'password',
|
||||
type: params.type,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,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 { notifyError } from 'core/decorators/notify';
|
||||
|
||||
export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
||||
// =services
|
||||
@@ -22,41 +23,26 @@ export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
||||
return this.store.findRecord('auth-method', id, adapterOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the password field on the controller so it is not
|
||||
* inadvertantly retained in memory.
|
||||
*/
|
||||
resetCredentials() {
|
||||
this.controller.setProperties({
|
||||
password: null,
|
||||
});
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
* Delegates authentication to the `password` authenticator.
|
||||
* If authentication fails, notifies with an alert.
|
||||
* Delegates authentication to an authenticator of type matching the current
|
||||
* auth method. If authentication fails, notifies with an alert.
|
||||
*/
|
||||
@action
|
||||
@loading
|
||||
@notifyError(() => 'errors.authentication-failed.title', { catch: true })
|
||||
async authenticate(creds) {
|
||||
this.resetCredentials();
|
||||
const authenticatorName = 'authenticator:password';
|
||||
const scope = this.modelFor('scopes.scope');
|
||||
const authMethod = this.currentModel;
|
||||
const authMethod = this.modelFor('scopes.scope.authenticate.method');
|
||||
const authenticatorName = `authenticator:${authMethod.type}`;
|
||||
const requestCookies = false;
|
||||
try {
|
||||
await this.session.authenticate(
|
||||
authenticatorName,
|
||||
creds,
|
||||
requestCookies,
|
||||
{ scope, authMethod }
|
||||
);
|
||||
this.transitionTo('index');
|
||||
} catch (e) {
|
||||
const errorMessage = this.intl.t('errors.authentication-failed.title');
|
||||
this.notify.error(errorMessage, { closeAfter: null });
|
||||
}
|
||||
await this.session.authenticate(
|
||||
authenticatorName,
|
||||
creds,
|
||||
requestCookies,
|
||||
{ scope, authMethod }
|
||||
);
|
||||
this.transitionTo('index');
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,17 @@
|
||||
|
||||
<page.actions>
|
||||
{{#if @model}}
|
||||
<Rose::LinkButton @route="scopes.scope.auth-methods.new" @style="primary">
|
||||
{{t "titles.new"}}
|
||||
</Rose::LinkButton>
|
||||
<Rose::Dropdown
|
||||
@text={{t "titles.new"}}
|
||||
@dropdownRight={{true}}
|
||||
as |dropdown|>
|
||||
<dropdown.link
|
||||
@route="scopes.scope.auth-methods.new"
|
||||
@query={{hash type="password"}}
|
||||
>
|
||||
{{t 'resources.auth-method.types.password'}}
|
||||
</dropdown.link>
|
||||
</Rose::Dropdown>
|
||||
{{/if}}
|
||||
</page.actions>
|
||||
|
||||
|
||||
@@ -29,7 +29,11 @@
|
||||
<Rose::Nav::Tabs as |nav|>
|
||||
{{#each @model.authMethods as |authMethod|}}
|
||||
<nav.link @route="scopes.scope.authenticate.method" @model={{authMethod.id}}>
|
||||
{{t (concat "resources.auth-method.types." authMethod.type)}}
|
||||
{{#if authMethod.name}}
|
||||
{{authMethod.name}}
|
||||
{{else}}
|
||||
{{t (concat "resources.auth-method.types." authMethod.type)}}
|
||||
{{/if}}
|
||||
</nav.link>
|
||||
{{/each}}
|
||||
</Rose::Nav::Tabs>
|
||||
|
||||
@@ -1,28 +1,5 @@
|
||||
<Rose::Form
|
||||
class="full-width"
|
||||
@onSubmit={{route-action "authenticate" (hash
|
||||
identification=this.identification
|
||||
password=this.password
|
||||
)}}
|
||||
@cancel={{false}}
|
||||
<Form::Authenticate
|
||||
@model={{@model}}
|
||||
@submit={{route-action "authenticate"}}
|
||||
@disabled={{is-loading}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<form.input
|
||||
@name="identification"
|
||||
@type="text"
|
||||
@value={{this.identification}}
|
||||
@label={{t "form.login_name.label"}} />
|
||||
|
||||
<form.input
|
||||
@name="password"
|
||||
@type="password"
|
||||
@value={{this.password}}
|
||||
@label={{t "form.password.label"}} />
|
||||
|
||||
<form.actions
|
||||
@submitText={{t "actions.authenticate"}}
|
||||
@showCancel={{false}} />
|
||||
|
||||
</Rose::Form>
|
||||
/>
|
||||
@@ -44,7 +44,7 @@ module('Acceptance | auth methods', function (hooks) {
|
||||
// Generate route URLs for resources
|
||||
urls.orgScope = `/scopes/${instances.scopes.org.id}`;
|
||||
urls.authMethods = `${urls.orgScope}/auth-methods`;
|
||||
urls.newAuthMethod = `${urls.authMethods}/new`;
|
||||
urls.newAuthMethod = `${urls.authMethods}/new?type=password`;
|
||||
urls.authMethod = `${urls.authMethods}/${instances.authMethod.id}`;
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user