Icu 12708 add scopes tab route in role route (#2322)
* feat: 🎸 add roles/role/scopes route ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * refactor: 💡 update role and scope mirage factories ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * feat: 🎸 add grantScopes to role model ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * feat: 🎸 fetch all scopes recursively ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * feat: 🎸 add new role grant scopes translations ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * feat: 🎸 add table to list grant scopes on a role ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * test: 💍 acceptance test for grant scope table and controller ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * test: 💍 add unit tests for grantScopes method on role model ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * refactor: 💡 small updates from PR feedback ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * refactor: 💡 update grantScopes to use sort ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * feat: 🎸 update role scope description for each scope type ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * refactor: 💡 make grant_scope_ids sort better ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * refactor: 💡 update global scope to show as Global vs global ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * refactor: 💡 update logic for display grant scope keywords ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * refactor: 💡 small improvement in role.grantScopes ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * refactor: 💡 move scope query to roles/scope route ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708 * refactor: 💡 remove console.log ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12708
This commit is contained in:
1 parent
e60b774d05
commit
2bc314d271
14 files changed
+587
-2
No files matched your search
@@ -7,6 +7,26 @@ import GeneratedRoleModel from '../generated/models/role';
|
||||
import { attr } from '@ember-data/model';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export const GRANT_SCOPE_THIS = 'this';
|
||||
export const GRANT_SCOPE_CHILDREN = 'children';
|
||||
export const GRANT_SCOPE_DESCENDANTS = 'descendants';
|
||||
export const GRANT_SCOPE_KEYWORDS = Object.freeze([
|
||||
GRANT_SCOPE_THIS,
|
||||
GRANT_SCOPE_CHILDREN,
|
||||
GRANT_SCOPE_DESCENDANTS,
|
||||
]);
|
||||
|
||||
// Sort the grant scope IDs by the order in which they should be displayed
|
||||
// in the UI as the API will return them in an arbitrary order.
|
||||
const sortOrder = {
|
||||
[GRANT_SCOPE_THIS]: 0,
|
||||
[GRANT_SCOPE_CHILDREN]: 1,
|
||||
[GRANT_SCOPE_DESCENDANTS]: 2,
|
||||
global: 3,
|
||||
o: 4,
|
||||
p: 5,
|
||||
};
|
||||
|
||||
export default class RoleModel extends GeneratedRoleModel {
|
||||
// =services
|
||||
|
||||
@@ -33,6 +53,34 @@ export default class RoleModel extends GeneratedRoleModel {
|
||||
*/
|
||||
@attr({ readOnly: true, emptyArrayIfMissing: true }) grant_strings;
|
||||
|
||||
/**
|
||||
* Convenience for looking up the grant scopes, if loaded.
|
||||
*/
|
||||
get grantScopes() {
|
||||
const grantScopes = [];
|
||||
if (this.grant_scope_ids) {
|
||||
const sortedScopeIDs = [...this.grant_scope_ids].sort((a, b) => {
|
||||
const aSplit = a.split('_')[0];
|
||||
const bSplit = b.split('_')[0];
|
||||
|
||||
return sortOrder[aSplit] - sortOrder[bSplit];
|
||||
});
|
||||
|
||||
sortedScopeIDs.forEach((id) => {
|
||||
if (GRANT_SCOPE_KEYWORDS.includes(id)) {
|
||||
grantScopes.push({ id });
|
||||
} else {
|
||||
const scope = this.store.peekRecord('scope', id);
|
||||
if (scope) {
|
||||
grantScopes.push(scope);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return grantScopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of IDs for principals of type `user`.
|
||||
* @type {string[]}
|
||||
|
||||
@@ -28,6 +28,16 @@ export default factory.extend({
|
||||
id: () => generateId('r_'),
|
||||
grant_scope_ids: () => ['this'],
|
||||
|
||||
/**
|
||||
* Adds grant scopes to the role.
|
||||
*/
|
||||
withScopes: trait({
|
||||
afterCreate(role) {
|
||||
const { scope } = role;
|
||||
role.update({ grant_scope_ids: ['this', scope.id] });
|
||||
},
|
||||
}),
|
||||
|
||||
/**
|
||||
* Adds principals to the role.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@ import factory from '../generated/factories/scope';
|
||||
import { trait } from 'miragejs';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
export default factory.extend({
|
||||
type: 'global',
|
||||
@@ -58,7 +59,24 @@ export default factory.extend({
|
||||
return collectionActions;
|
||||
},
|
||||
|
||||
id: () => generateId('s_'),
|
||||
id() {
|
||||
let id = 'global';
|
||||
if (this.type === 'org') {
|
||||
id = generateId('o_');
|
||||
}
|
||||
if (this.type === 'project') {
|
||||
id = generateId('p_');
|
||||
}
|
||||
return id;
|
||||
},
|
||||
|
||||
name() {
|
||||
let name = faker.word.words();
|
||||
if (this.type === 'global') {
|
||||
name = 'global';
|
||||
}
|
||||
return name;
|
||||
},
|
||||
|
||||
withChildren: trait({
|
||||
afterCreate(record, server) {
|
||||
|
||||
@@ -10,7 +10,6 @@ import { faker } from '@faker-js/faker';
|
||||
* GeneratedScopeModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
name: () => faker.word.words(),
|
||||
description: () => faker.word.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
updated_time: () => faker.date.recent(),
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import {
|
||||
GRANT_SCOPE_THIS,
|
||||
GRANT_SCOPE_CHILDREN,
|
||||
GRANT_SCOPE_DESCENDANTS,
|
||||
} from 'api/models/role';
|
||||
|
||||
module('Unit | Model | role', function (hooks) {
|
||||
setupTest(hooks);
|
||||
@@ -183,4 +188,133 @@ module('Unit | Model | role', function (hooks) {
|
||||
const model = store.peekRecord('role', '123abc');
|
||||
await model.removePrincipal('3');
|
||||
});
|
||||
|
||||
test('grantScopes returns an empty array when no grant_scope_ids are present', async function (assert) {
|
||||
const store = this.owner.lookup('service:store');
|
||||
const role = store.createRecord('role');
|
||||
|
||||
const grantScopes = role.grantScopes;
|
||||
|
||||
assert.strictEqual(grantScopes.length, 0);
|
||||
});
|
||||
|
||||
test('grantScopes returns an empty array when no grant_scope_ids are loaded', async function (assert) {
|
||||
const store = this.owner.lookup('service:store');
|
||||
const role = store.createRecord('role', {
|
||||
grant_scope_ids: ['o_123'],
|
||||
});
|
||||
|
||||
const grantScopes = role.grantScopes;
|
||||
|
||||
assert.strictEqual(grantScopes.length, 0);
|
||||
});
|
||||
|
||||
test('grantScopes returns an array of scope records', async function (assert) {
|
||||
const store = this.owner.lookup('service:store');
|
||||
const orgScope = store.createRecord('scope', { id: 'o_123' });
|
||||
const role = store.createRecord('role', {
|
||||
grant_scope_ids: [orgScope.id],
|
||||
});
|
||||
|
||||
const grantScopes = role.grantScopes;
|
||||
|
||||
assert.strictEqual(grantScopes.length, 1);
|
||||
assert.strictEqual(grantScopes[0].id, orgScope.id);
|
||||
});
|
||||
|
||||
test('grantScopes returns an array of scope records ordered by orgs then projects', async function (assert) {
|
||||
const store = this.owner.lookup('service:store');
|
||||
const orgScope = store.createRecord('scope', { id: 'o_123' });
|
||||
const projectScope = store.createRecord('scope', { id: 'p_123' });
|
||||
const role = store.createRecord('role', {
|
||||
grant_scope_ids: [projectScope.id, orgScope.id],
|
||||
});
|
||||
|
||||
const grantScopes = role.grantScopes;
|
||||
|
||||
assert.strictEqual(grantScopes.length, 2);
|
||||
assert.strictEqual(grantScopes[0].id, orgScope.id);
|
||||
assert.strictEqual(grantScopes[1].id, projectScope.id);
|
||||
});
|
||||
|
||||
test('grantScopes returns an array of keywords and scope records', async function (assert) {
|
||||
const store = this.owner.lookup('service:store');
|
||||
const orgScope = store.createRecord('scope', { id: 'o_123' });
|
||||
const projectScope = store.createRecord('scope', { id: 'p_123' });
|
||||
const role = store.createRecord('role', {
|
||||
grant_scope_ids: [projectScope.id, GRANT_SCOPE_THIS, orgScope.id],
|
||||
});
|
||||
|
||||
const grantScopes = role.grantScopes;
|
||||
|
||||
assert.strictEqual(grantScopes.length, 3);
|
||||
assert.strictEqual(grantScopes[0].id, GRANT_SCOPE_THIS);
|
||||
assert.strictEqual(grantScopes[1].id, orgScope.id);
|
||||
assert.strictEqual(grantScopes[2].id, projectScope.id);
|
||||
});
|
||||
|
||||
test('grantScopes orders keywords by this, children, descendants', async function (assert) {
|
||||
// A role cannot have this, children, and descendants at the same time
|
||||
// but for testing purposes, we want to show the order they are sorted in
|
||||
const store = this.owner.lookup('service:store');
|
||||
const role = store.createRecord('role', {
|
||||
grant_scope_ids: [
|
||||
GRANT_SCOPE_CHILDREN,
|
||||
GRANT_SCOPE_DESCENDANTS,
|
||||
GRANT_SCOPE_THIS,
|
||||
],
|
||||
});
|
||||
|
||||
const grantScopes = role.grantScopes;
|
||||
|
||||
assert.strictEqual(grantScopes.length, 3);
|
||||
assert.strictEqual(grantScopes[0].id, GRANT_SCOPE_THIS);
|
||||
assert.strictEqual(grantScopes[1].id, GRANT_SCOPE_CHILDREN);
|
||||
assert.strictEqual(grantScopes[2].id, GRANT_SCOPE_DESCENDANTS);
|
||||
});
|
||||
|
||||
test('grantScopes returns an array of keywords and scopes in the correct order', async function (assert) {
|
||||
const store = this.owner.lookup('service:store');
|
||||
const orgScope = store.createRecord('scope', { id: 'o_123' });
|
||||
const projectScope = store.createRecord('scope', { id: 'p_123' });
|
||||
const role = store.createRecord('role', {
|
||||
grant_scope_ids: [
|
||||
projectScope.id,
|
||||
GRANT_SCOPE_THIS,
|
||||
orgScope.id,
|
||||
GRANT_SCOPE_CHILDREN,
|
||||
],
|
||||
});
|
||||
|
||||
const grantScopes = role.grantScopes;
|
||||
|
||||
assert.strictEqual(grantScopes.length, 4);
|
||||
assert.strictEqual(grantScopes[0].id, GRANT_SCOPE_THIS);
|
||||
assert.strictEqual(grantScopes[1].id, GRANT_SCOPE_CHILDREN);
|
||||
assert.strictEqual(grantScopes[2].id, orgScope.id);
|
||||
assert.strictEqual(grantScopes[3].id, projectScope.id);
|
||||
});
|
||||
|
||||
test('grantScopes returns an array that orders global after keywords and before orgs and/or projects', async function (assert) {
|
||||
const store = this.owner.lookup('service:store');
|
||||
const orgScope = store.createRecord('scope', { id: 'o_123' });
|
||||
const projectScope = store.createRecord('scope', { id: 'p_123' });
|
||||
const globalScope = store.createRecord('scope', { id: 'global' });
|
||||
const role = store.createRecord('role', {
|
||||
grant_scope_ids: [
|
||||
projectScope.id,
|
||||
orgScope.id,
|
||||
GRANT_SCOPE_CHILDREN,
|
||||
globalScope.id,
|
||||
],
|
||||
});
|
||||
|
||||
const grantScopes = role.grantScopes;
|
||||
|
||||
assert.strictEqual(grantScopes.length, 4);
|
||||
assert.strictEqual(grantScopes[0].id, GRANT_SCOPE_CHILDREN);
|
||||
assert.strictEqual(grantScopes[1].id, globalScope.id);
|
||||
assert.strictEqual(grantScopes[2].id, orgScope.id);
|
||||
assert.strictEqual(grantScopes[3].id, projectScope.id);
|
||||
});
|
||||
});
|
||||
@@ -560,6 +560,25 @@ role:
|
||||
description: Grants are permissions which allow roles to take actions and access resources.
|
||||
actions:
|
||||
create: New Grant
|
||||
scope:
|
||||
title: Scope
|
||||
title_plural: Scopes
|
||||
description:
|
||||
global: Role grant sets can be applied to multiple descendants underneath this scope.
|
||||
org: Role grant sets can be applied to multiple children underneath this scope.
|
||||
project: Role grant sets can only be applied to this scope.
|
||||
titles:
|
||||
parent_scope: Parent scope
|
||||
resource_type: Resource type
|
||||
keywords:
|
||||
this:
|
||||
sub-title: This scope
|
||||
children:
|
||||
title: All Children
|
||||
sub-title: All children under this scope
|
||||
descendants:
|
||||
title: All Descendants
|
||||
sub-title: Add all of the orgs and the projects in the orgs that are underneath this scope
|
||||
target:
|
||||
title: Target
|
||||
title_plural: Targets
|
||||
@@ -872,6 +891,10 @@ scope:
|
||||
title_plural: Scopes
|
||||
messages:
|
||||
cannot_read: While you do not have permission to read this scope, you may have permission to view resources within it.
|
||||
types:
|
||||
global: Global
|
||||
org: Org
|
||||
project: Project
|
||||
managed-group:
|
||||
title: Managed Group
|
||||
title_plural: Managed Groups
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
<nav.link @route='scopes.scope.roles.role.index'>
|
||||
{{t 'titles.settings'}}
|
||||
</nav.link>
|
||||
<nav.link @route='scopes.scope.roles.role.scopes'>
|
||||
{{t 'resources.role.scope.title_plural'}}
|
||||
</nav.link>
|
||||
<nav.link @route='scopes.scope.roles.role.principals'>
|
||||
{{t 'resources.role.principal.title_plural'}}
|
||||
</nav.link>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import Controller, { inject as controller } from '@ember/controller';
|
||||
import {
|
||||
GRANT_SCOPE_THIS,
|
||||
GRANT_SCOPE_CHILDREN,
|
||||
GRANT_SCOPE_DESCENDANTS,
|
||||
} from 'api/models/role';
|
||||
|
||||
export default class ScopesScopeRolesRoleScopesController extends Controller {
|
||||
@controller('scopes/scope/roles/index') roles;
|
||||
|
||||
isKeywordThis(id) {
|
||||
return id === GRANT_SCOPE_THIS;
|
||||
}
|
||||
|
||||
isKeywordChildrenOrDescendants(id) {
|
||||
return id === GRANT_SCOPE_CHILDREN || id === GRANT_SCOPE_DESCENDANTS;
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,7 @@ Router.map(function () {
|
||||
this.route('grants');
|
||||
this.route('principals');
|
||||
this.route('add-principals');
|
||||
this.route('scopes');
|
||||
});
|
||||
this.route('new');
|
||||
});
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { GRANT_SCOPE_KEYWORDS } from 'api/models/role';
|
||||
|
||||
export default class ScopesScopeRolesRoleScopesRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service store;
|
||||
|
||||
async model() {
|
||||
const role = this.modelFor('scopes.scope.roles.role');
|
||||
if (!GRANT_SCOPE_KEYWORDS.some((id) => role.grant_scope_ids.includes(id))) {
|
||||
await this.store.query('scope', {
|
||||
scope_id: role.scope.id,
|
||||
recursive: true,
|
||||
});
|
||||
}
|
||||
return role;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
}}
|
||||
|
||||
{{page-title (t 'resources.role.scope.title_plural')}}
|
||||
<Breadcrumbs::Item
|
||||
@text={{t 'resources.role.scope.title_plural'}}
|
||||
@route='scopes.scope.roles.role.scopes'
|
||||
/>
|
||||
|
||||
<Rose::Layout::Page as |page|>
|
||||
|
||||
<page.breadcrumbs>
|
||||
<Breadcrumbs::Container />
|
||||
</page.breadcrumbs>
|
||||
|
||||
<page.header>
|
||||
<h2>
|
||||
{{t 'resources.role.title'}}
|
||||
<DocLink @doc='role' @iconSize='large' />
|
||||
</h2>
|
||||
<p>
|
||||
{{#if @model.scope.isOrg}}
|
||||
{{t 'resources.role.scope.description.org'}}
|
||||
{{else if @model.scope.isProject}}
|
||||
{{t 'resources.role.scope.description.project'}}
|
||||
{{else}}
|
||||
{{t 'resources.role.scope.description.global'}}
|
||||
{{/if}}
|
||||
</p>
|
||||
<Hds::Copy::Snippet @textToCopy={{@model.id}} @color='secondary' />
|
||||
</page.header>
|
||||
|
||||
<page.actions>
|
||||
<Roles::Role::Actions @model={{@model}} @delete={{this.roles.delete}} />
|
||||
</page.actions>
|
||||
|
||||
<page.navigation>
|
||||
<Roles::Role::Nav @model={{@model}} />
|
||||
</page.navigation>
|
||||
|
||||
<page.body>
|
||||
{{#if @model.grant_scope_ids}}
|
||||
<Hds::Table
|
||||
@model={{@model.grantScopes}}
|
||||
@columns={{array
|
||||
(hash label=(t 'resources.role.scope.title'))
|
||||
(hash label=(t 'form.id.label'))
|
||||
(hash label=(t 'resources.role.scope.titles.parent_scope'))
|
||||
(hash label=(t 'resources.role.scope.titles.resource_type'))
|
||||
}}
|
||||
@valin='middle'
|
||||
>
|
||||
<:body as |B|>
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
{{#if (this.isKeywordThis B.data.id)}}
|
||||
<Hds::Text::Body @tag='p'>
|
||||
{{#if @model.scope.name}}
|
||||
{{@model.scope.name}}
|
||||
{{else}}
|
||||
{{@model.scope.id}}
|
||||
{{/if}}
|
||||
</Hds::Text::Body>
|
||||
<Hds::Text::Body @tag='p'>
|
||||
<Hds::Badge
|
||||
@text={{t 'resources.role.scope.keywords.this.sub-title'}}
|
||||
@size='small'
|
||||
/>
|
||||
</Hds::Text::Body>
|
||||
{{else if (this.isKeywordChildrenOrDescendants B.data.id)}}
|
||||
<Hds::Text::Body @tag='p'>
|
||||
{{t
|
||||
(concat 'resources.role.scope.keywords.' B.data.id '.title')
|
||||
}}
|
||||
</Hds::Text::Body>
|
||||
<Hds::Text::Body @tag='p'>
|
||||
{{t
|
||||
(concat
|
||||
'resources.role.scope.keywords.' B.data.id '.sub-title'
|
||||
)
|
||||
}}
|
||||
</Hds::Text::Body>
|
||||
{{else}}
|
||||
{{#if (can 'read model' B.data)}}
|
||||
<LinkTo @route='scopes.scope' @model={{B.data}}>
|
||||
{{#if B.data.isGlobal}}
|
||||
{{t 'titles.global'}}
|
||||
{{else}}
|
||||
{{B.data.displayName}}
|
||||
{{/if}}
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
{{B.data.displayName}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
<Hds::Copy::Snippet
|
||||
@textToCopy={{B.data.id}}
|
||||
@color='secondary'
|
||||
/>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
{{#if B.data.scope.isGlobal}}
|
||||
<Hds::Link::Inline
|
||||
@route='scopes.scope'
|
||||
@model={{B.data.scope.id}}
|
||||
@icon='globe'
|
||||
@iconPosition='leading'
|
||||
>
|
||||
{{#if B.data.scope.name}}
|
||||
{{t 'titles.global'}}
|
||||
{{else}}
|
||||
{{B.data.scope.id}}
|
||||
{{/if}}
|
||||
</Hds::Link::Inline>
|
||||
{{else if B.data.scope.isOrg}}
|
||||
<Hds::Link::Inline
|
||||
@route='scopes.scope'
|
||||
@model={{B.data.scope.id}}
|
||||
@icon='org'
|
||||
@iconPosition='leading'
|
||||
>
|
||||
{{#if B.data.scope.name}}
|
||||
{{B.data.scope.name}}
|
||||
{{else}}
|
||||
{{B.data.scope.id}}
|
||||
{{/if}}
|
||||
</Hds::Link::Inline>
|
||||
{{else}}
|
||||
{{#if B.data.scope.name}}
|
||||
{{B.data.scope.name}}
|
||||
{{else}}
|
||||
{{B.data.scope.id}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
{{#if B.data.type}}
|
||||
<Hds::Badge
|
||||
@text={{t (concat 'resources.scope.types.' B.data.type)}}
|
||||
/>
|
||||
{{/if}}
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
</:body>
|
||||
</Hds::Table>
|
||||
{{/if}}
|
||||
|
||||
</page.body>
|
||||
|
||||
</Rose::Layout::Page>
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, currentURL, click } from '@ember/test-helpers';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import { authenticateSession } from 'ember-simple-auth/test-support';
|
||||
|
||||
module('Acceptance | roles | scopes', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
setupIndexedDb(hooks);
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
},
|
||||
role: null,
|
||||
};
|
||||
const urls = {
|
||||
orgScope: null,
|
||||
roles: null,
|
||||
role: null,
|
||||
roleScopes: null,
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
authenticateSession({});
|
||||
instances.scopes.global = this.server.create('scope', { id: 'global' });
|
||||
instances.scopes.org = this.server.create('scope', {
|
||||
type: 'org',
|
||||
scope: { id: 'global', type: 'global' },
|
||||
});
|
||||
instances.role = this.server.create(
|
||||
'role',
|
||||
{
|
||||
scope: instances.scopes.org,
|
||||
},
|
||||
'withScopes',
|
||||
);
|
||||
urls.roles = `/scopes/${instances.scopes.org.id}/roles`;
|
||||
urls.role = `${urls.roles}/${instances.role.id}`;
|
||||
urls.roleScopes = `${urls.role}/scopes`;
|
||||
});
|
||||
|
||||
test('visiting role scopes', async function (assert) {
|
||||
await visit(urls.roleScopes);
|
||||
await a11yAudit();
|
||||
assert.strictEqual(currentURL(), urls.roleScopes);
|
||||
assert
|
||||
.dom('tbody tr')
|
||||
.exists({ count: instances.role.grant_scope_ids.length });
|
||||
});
|
||||
|
||||
test('user can naviage to scope from role grant scopes', async function (assert) {
|
||||
await visit(urls.roleScopes);
|
||||
await click('tbody tr:nth-child(2) a');
|
||||
assert.strictEqual(
|
||||
currentURL(),
|
||||
`/scopes/${instances.scopes.org.id}/scopes`,
|
||||
);
|
||||
});
|
||||
|
||||
test('user can naviage to parent scope from role grant scopes', async function (assert) {
|
||||
await visit(urls.roleScopes);
|
||||
await click('tbody tr:nth-child(2) td:nth-child(3) a');
|
||||
assert.strictEqual(
|
||||
currentURL(),
|
||||
`/scopes/${instances.scopes.global.id}/scopes`,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'admin/tests/helpers';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import { authenticateSession } from 'ember-simple-auth/test-support';
|
||||
import {
|
||||
GRANT_SCOPE_THIS,
|
||||
GRANT_SCOPE_CHILDREN,
|
||||
GRANT_SCOPE_DESCENDANTS,
|
||||
} from 'api/models/role';
|
||||
|
||||
module('Unit | Controller | scopes/scope/roles/role/scopes', function (hooks) {
|
||||
setupTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
let controller;
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
},
|
||||
role: null,
|
||||
};
|
||||
|
||||
const urls = {
|
||||
globalScope: null,
|
||||
scopes: null,
|
||||
};
|
||||
|
||||
hooks.beforeEach(async function () {
|
||||
authenticateSession({});
|
||||
controller = this.owner.lookup('controller:scopes/scope/roles/role/scopes');
|
||||
|
||||
instances.scopes.global = this.server.create('scope', { id: 'global' });
|
||||
instances.role = this.server.create('role', {
|
||||
scopeId: 'global',
|
||||
});
|
||||
|
||||
urls.globalScope = `/scopes/global`;
|
||||
urls.scopes = `${urls.globalScope}/roles/${instances.role.id}/scopes`;
|
||||
});
|
||||
|
||||
test('it exists', function (assert) {
|
||||
assert.ok(controller);
|
||||
});
|
||||
|
||||
test('isKeywordThis action returns true if id is GRANT_SCOPE_THIS', function (assert) {
|
||||
assert.ok(controller.isKeywordThis(GRANT_SCOPE_THIS));
|
||||
assert.notOk(controller.isKeywordThis(GRANT_SCOPE_CHILDREN));
|
||||
});
|
||||
|
||||
test('isKeywordChildrenOrDescendants action returns true if id is GRANT_SCOPE_CHILDREN or GRANT_SCOPE_DESCENDANTS', function (assert) {
|
||||
assert.ok(controller.isKeywordChildrenOrDescendants(GRANT_SCOPE_CHILDREN));
|
||||
assert.ok(
|
||||
controller.isKeywordChildrenOrDescendants(GRANT_SCOPE_DESCENDANTS),
|
||||
);
|
||||
assert.notOk(controller.isKeywordChildrenOrDescendants(GRANT_SCOPE_THIS));
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'admin/tests/helpers';
|
||||
|
||||
module('Unit | Route | scopes/scope/roles/role/scopes', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test('it exists', function (assert) {
|
||||
let route = this.owner.lookup('route:scopes/scope/roles/role/scopes');
|
||||
assert.ok(route);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user