diff --git a/ui/core/app/components/form/role/add-principals/index.hbs b/ui/core/app/components/form/role/add-principals/index.hbs new file mode 100644 index 000000000..d15f49bc3 --- /dev/null +++ b/ui/core/app/components/form/role/add-principals/index.hbs @@ -0,0 +1,66 @@ +{{#if this.hasAvailablePrincipals}} + + + + + + + + {{t 'form.label.id'}} + {{t 'form.label.name'}} + {{t 'form.label.type'}} + + + + {{#each @groups as |group|}} + + + + + {{group.name}} + + {{t "resources.group"}} + + + {{/each}} + {{#each @users as |user|}} + + + + + {{user.name}} + + {{t "resources.user"}} + + + {{/each}} + + + + +{{/if}} + +{{#unless this.hasAvailablePrincipals}} + + + + {{t "descriptions.no-principals"}} + + + +{{/unless}} diff --git a/ui/core/app/components/form/role/add-principals/index.js b/ui/core/app/components/form/role/add-principals/index.js new file mode 100644 index 000000000..34090a495 --- /dev/null +++ b/ui/core/app/components/form/role/add-principals/index.js @@ -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); + } + +} diff --git a/ui/core/app/routes/scopes/scope/roles/role/add-principals.js b/ui/core/app/routes/scopes/scope/roles/role/add-principals.js index 1c4d8bbb8..b4854a825 100644 --- a/ui/core/app/routes/scopes/scope/roles/role/add-principals.js +++ b/ui/core/app/routes/scopes/scope/roles/role/add-principals.js @@ -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'); + } + } diff --git a/ui/core/app/templates/scopes/scope/roles/role/add-principals.hbs b/ui/core/app/templates/scopes/scope/roles/role/add-principals.hbs index cf8fdc119..5110dbec0 100644 --- a/ui/core/app/templates/scopes/scope/roles/role/add-principals.hbs +++ b/ui/core/app/templates/scopes/scope/roles/role/add-principals.hbs @@ -1,3 +1,9 @@ {{title (t "actions.add-principals")}} -{{outlet}} + diff --git a/ui/core/mirage/generated/factories/role.js b/ui/core/mirage/generated/factories/role.js index 6265c7116..13e83aad3 100644 --- a/ui/core/mirage/generated/factories/role.js +++ b/ui/core/mirage/generated/factories/role.js @@ -12,5 +12,6 @@ export default Factory.extend({ created_time: () => date.recent(), updated_time: () => date.recent(), disabled: () => random.boolean(), + version: () => random.number(), }); diff --git a/ui/core/tests/acceptance/roles-test.js b/ui/core/tests/acceptance/roles-test.js index 5fc89b42e..07f55d080 100644 --- a/ui/core/tests/acceptance/roles-test.js +++ b/ui/core/tests/acceptance/roles-test.js @@ -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); + }); }); diff --git a/ui/core/tests/integration/components/form/role/add-principals-test.js b/ui/core/tests/integration/components/form/role/add-principals-test.js new file mode 100644 index 000000000..1e155a103 --- /dev/null +++ b/ui/core/tests/integration/components/form/role/add-principals-test.js @@ -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); + }); +});