diff --git a/addons/api/addon/abilities/role.js b/addons/api/addon/abilities/role.js index f9a5b26ce..323106252 100644 --- a/addons/api/addon/abilities/role.js +++ b/addons/api/addon/abilities/role.js @@ -27,6 +27,13 @@ export default class RoleAbility extends ModelAbility { return this.hasAuthorizedAction('set-grants'); } + /** + * @type {boolean} + */ + get canSetGrantScopes() { + return this.hasAuthorizedAction('set-grant-scopes'); + } + /** * @type {boolean} */ diff --git a/addons/api/mirage/factories/role.js b/addons/api/mirage/factories/role.js index fc59bbcaa..7b1536a21 100644 --- a/addons/api/mirage/factories/role.js +++ b/addons/api/mirage/factories/role.js @@ -18,6 +18,7 @@ export default factory.extend({ 'set-grants', 'add-principals', 'remove-principals', + 'set-grant-scopes', ], // eslint-disable-next-line ember/avoid-leaking-state-in-ember-objects grant_strings: () => [ diff --git a/addons/api/mirage/serializers/role.js b/addons/api/mirage/serializers/role.js index b5753dc12..619814bef 100644 --- a/addons/api/mirage/serializers/role.js +++ b/addons/api/mirage/serializers/role.js @@ -38,11 +38,6 @@ export default ApplicationSerializer.extend({ if (!json.principals.length) delete json.principals; - // default grant scopes - if (json.grant_scope_ids.length === 0) { - json.grant_scope_ids = ['this']; - } - return json; }, }); diff --git a/addons/api/tests/unit/abilities/role-test.js b/addons/api/tests/unit/abilities/role-test.js index de3109552..e601bcc1b 100644 --- a/addons/api/tests/unit/abilities/role-test.js +++ b/addons/api/tests/unit/abilities/role-test.js @@ -75,4 +75,14 @@ module('Unit | Abilities | Role', function (hooks) { }); assert.true(service.can('read account', account)); }); + + test('can set grant scopes based on authorized_actions', function (assert) { + const service = this.owner.lookup('service:can'); + const model = { + authorized_actions: ['set-grant-scopes'], + }; + assert.true(service.can('setGrantScopes role', model)); + model.authorized_actions = []; + assert.false(service.can('setGrantScopes role', model)); + }); }); diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 24014971d..c34d84430 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -570,6 +570,10 @@ role: titles: parent_scope: Parent scope resource_type: Resource type + messages: + title: No scopes added + description: You haven’t added any scopes to this role’s grant sets. + action: Add scopes to this role keywords: this: sub-title: This scope diff --git a/ui/admin/app/routes/scopes/scope/roles/role/scopes.js b/ui/admin/app/routes/scopes/scope/roles/role/scopes.js index 6ddc733bf..bf43ea083 100644 --- a/ui/admin/app/routes/scopes/scope/roles/role/scopes.js +++ b/ui/admin/app/routes/scopes/scope/roles/role/scopes.js @@ -9,7 +9,10 @@ export default class ScopesScopeRolesRoleScopesRoute extends Route { async model() { const role = this.modelFor('scopes.scope.roles.role'); - if (!GRANT_SCOPE_KEYWORDS.some((id) => role.grant_scope_ids.includes(id))) { + if ( + role.grant_scope_ids && + !GRANT_SCOPE_KEYWORDS.some((id) => role.grant_scope_ids.includes(id)) + ) { await this.store.query('scope', { scope_id: role.scope.id, recursive: true, diff --git a/ui/admin/app/styles/app.scss b/ui/admin/app/styles/app.scss index 4d5f2227c..f1aaa6622 100644 --- a/ui/admin/app/styles/app.scss +++ b/ui/admin/app/styles/app.scss @@ -1036,3 +1036,10 @@ .loading-indicator { margin-top: 20%; } + +// Roles +.role-grant-scopes { + .hds-application-state { + margin-top: 3rem; + } +} diff --git a/ui/admin/app/templates/scopes/scope/roles/role/scopes.hbs b/ui/admin/app/templates/scopes/scope/roles/role/scopes.hbs index 2c2c31d7b..e4227b2a3 100644 --- a/ui/admin/app/templates/scopes/scope/roles/role/scopes.hbs +++ b/ui/admin/app/templates/scopes/scope/roles/role/scopes.hbs @@ -40,7 +40,7 @@ - + {{#if @model.grant_scope_ids}} + {{else}} + + + + {{#if (can 'setGrantScopes role' @model)}} + + {{! TODO: Update route to manage-scopes once it is implemented }} + + + {{/if}} + {{/if}} diff --git a/ui/admin/tests/acceptance/roles/scopes-test.js b/ui/admin/tests/acceptance/roles/scopes-test.js index 392141004..d2d1c5c0f 100644 --- a/ui/admin/tests/acceptance/roles/scopes-test.js +++ b/ui/admin/tests/acceptance/roles/scopes-test.js @@ -75,4 +75,22 @@ module('Acceptance | roles | scopes', function (hooks) { `/scopes/${instances.scopes.global.id}/scopes`, ); }); + + test('user sees no scopes message and action when role has no grant scopes', async function (assert) { + instances.role.update({ grant_scope_ids: [] }); + await visit(urls.roleScopes); + assert.dom('.role-grant-scopes div').includesText('No scopes added'); + assert.dom('.role-grant-scopes div div:nth-child(3) a').isVisible(); + }); + + test('user does not see action to add scopes when role has no grant scopes without proper permissions', async function (assert) { + instances.role.update({ + grant_scope_ids: [], + authorized_actions: instances.role.authorized_actions.filter( + (action) => action !== 'set-grant-scopes', + ), + }); + await visit(urls.roleScopes); + assert.dom('.role-grant-scopes div div:nth-child(3) a').doesNotExist(); + }); });