feat: 🎸 add initial add-principals flow
This commit is contained in:
7 files changed
+194
-1
No files matched your search
@@ -0,0 +1,66 @@
|
||||
{{#if this.hasAvailablePrincipals}}
|
||||
<Rose::Form
|
||||
class="full-width"
|
||||
@onSubmit={{fn this.submit @submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@error={{@model.errors.base}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<form.actions
|
||||
@submitText={{t "actions.add-principals"}}
|
||||
@cancelText={{t "actions.cancel"}} />
|
||||
|
||||
<Rose::Table as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row as |row|>
|
||||
<row.headerCell>{{t 'form.label.id'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.label.name'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.label.type'}}</row.headerCell>
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @groups as |group|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.checkbox
|
||||
@label={{group.id}}
|
||||
@description={{group.description}}
|
||||
onChange={{fn this.togglePrincipal group}} />
|
||||
</row.cell>
|
||||
<row.cell>{{group.name}}</row.cell>
|
||||
<row.cell>
|
||||
<Rose::Badge>{{t "resources.group"}}</Rose::Badge>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
{{#each @users as |user|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.checkbox
|
||||
@label={{user.id}}
|
||||
@description={{user.description}}
|
||||
onChange={{fn this.togglePrincipal user}} />
|
||||
</row.cell>
|
||||
<row.cell>{{user.name}}</row.cell>
|
||||
<row.cell>
|
||||
<Rose::Badge>{{t "resources.user"}}</Rose::Badge>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
|
||||
</Rose::Form>
|
||||
{{/if}}
|
||||
|
||||
{{#unless this.hasAvailablePrincipals}}
|
||||
<Rose::Layout::Centered>
|
||||
<Rose::Message @title={{t "titles.no-principals"}} as |message|>
|
||||
<message.description>
|
||||
{{t "descriptions.no-principals"}}
|
||||
</message.description>
|
||||
</Rose::Message>
|
||||
</Rose::Layout::Centered>
|
||||
{{/unless}}
|
||||
@@ -0,0 +1,38 @@
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
import { A } from '@ember/array';
|
||||
|
||||
export default class FormRoleAddPrincipalsComponent extends Component {
|
||||
|
||||
// =properties
|
||||
|
||||
/**
|
||||
* Array of selected principal IDs.
|
||||
* @type {EmberArray}
|
||||
*/
|
||||
selectedPrincipalIDs = A();
|
||||
|
||||
/**
|
||||
* True if there are users or groups not yet added to this role.
|
||||
* TODO: this must be computed on users, groups, and role principals.
|
||||
* @type {boolean}
|
||||
*/
|
||||
hasAvailablePrincipals = true;
|
||||
|
||||
// =actions
|
||||
|
||||
@action
|
||||
togglePrincipal(principal) {
|
||||
if (!this.selectedPrincipalIDs.includes(principal.id)) {
|
||||
this.selectedPrincipalIDs.addObject(principal.id);
|
||||
} else {
|
||||
this.selectedPrincipalIDs.removeObject(principal.id);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
submit(fn) {
|
||||
fn(this.selectedPrincipalIDs);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,37 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { hash } from 'rsvp';
|
||||
|
||||
export default class ScopesScopeRolesRoleAddPrincipalsRoute extends Route {
|
||||
|
||||
// =services
|
||||
|
||||
@service intl;
|
||||
@service notify;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Emtpy out any previously loaded users and groups
|
||||
* (collectively, principals).
|
||||
*/
|
||||
beforeModel() {
|
||||
this.store.unloadAll('user');
|
||||
this.store.unloadAll('group');
|
||||
}
|
||||
|
||||
model() {
|
||||
const role = this.modelFor('scopes.scope.roles.role');
|
||||
const { scopeID } = role;
|
||||
const options = { adapterOptions: { scopeID } };
|
||||
return hash({
|
||||
role,
|
||||
users: this.store.findAll('user', options),
|
||||
groups: this.store.findAll('group', options)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Empties the actions and navigation outlets and renders a custom header.
|
||||
* @override
|
||||
@@ -26,4 +54,30 @@ export default class ScopesScopeRolesRoleAddPrincipalsRoute extends Route {
|
||||
outlet: 'navigation'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves principal IDs into the role via the API.
|
||||
* @param {RoleModel} role
|
||||
* @param {[string]} principalIDs
|
||||
*/
|
||||
@action
|
||||
async addPrincipals(role, principalIDs) {
|
||||
try {
|
||||
await role.addPrincipals(principalIDs);
|
||||
this.replaceWith('scopes.scope.roles.role.principals');
|
||||
this.notify.success(this.intl.t('notify.save-success'));
|
||||
} catch (error) {
|
||||
// TODO: replace with translated strings
|
||||
this.notify.error(error.message, { closeAfter: null });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to role principals as if nothing ever happened.
|
||||
*/
|
||||
@action
|
||||
cancel() {
|
||||
this.replaceWith('scopes.scope.roles.role.principals');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +1,9 @@
|
||||
{{title (t "actions.add-principals")}}
|
||||
|
||||
{{outlet}}
|
||||
<Form::Role::AddPrincipals
|
||||
@model={{@model.role}}
|
||||
@users={{@model.users}}
|
||||
@groups={{@model.groups}}
|
||||
@submit={{route-action "addPrincipals" @model.role}}
|
||||
@cancel={{route-action "cancel"}}
|
||||
/>
|
||||
@@ -12,5 +12,6 @@ export default Factory.extend({
|
||||
created_time: () => date.recent(),
|
||||
updated_time: () => date.recent(),
|
||||
disabled: () => random.boolean(),
|
||||
version: () => random.number(),
|
||||
|
||||
});
|
||||
@@ -237,4 +237,20 @@ module('Acceptance | roles', function (hooks) {
|
||||
test('new grants can be added and saved or canceled', async function (assert) {
|
||||
assert.expect(0);
|
||||
});
|
||||
|
||||
test('viewing role principals', async function (assert) {
|
||||
assert.expect(0);
|
||||
});
|
||||
|
||||
test('can delete a principal', async function(assert) {
|
||||
assert.expect(0);
|
||||
});
|
||||
|
||||
test('select and save principals to add', async function (assert) {
|
||||
assert.expect(0);
|
||||
});
|
||||
|
||||
test('select and cancel principals to add', async function (assert) {
|
||||
assert.expect(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
// import { render } from '@ember/test-helpers';
|
||||
// import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
module('Integration | Component | form/role/add-principals', function(hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function(assert) {
|
||||
assert.expect(0);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user