refactor: 💡 remove route-action usage for roles (#2292)

* refactor: 💡 remove route-action usage for roles

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12608
This commit is contained in:
Lisbet Alvarez authored and GitHub committed 2024-05-23 15:35:49 -07:00
1 parent 534c4419e7
commit b9b4e33f5a
23 files changed
+466 -182

No files matched your search

@@ -18,7 +18,7 @@
<dropdown.button
@style='danger'
@disabled={{@model.canSave}}
{{on 'click' (route-action 'delete' @model)}}
{{on 'click' (fn @delete @model)}}
>
{{t 'resources.role.actions.delete'}}
</dropdown.button>
@@ -6,13 +6,17 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { loading } from 'ember-loading';
import { tracked } from '@glimmer/tracking';
import { debounce } from 'core/decorators/debounce';
import { confirm } from 'core/decorators/confirm';
import { notifySuccess, notifyError } from 'core/decorators/notify';
export default class ScopesScopeRolesIndexController extends Controller {
// =services
@service intl;
@service can;
@service router;
// =attributes
@@ -22,7 +26,7 @@ export default class ScopesScopeRolesIndexController extends Controller {
@tracked page = 1;
@tracked pageSize = 10;
// =methods
// =actions
/**
* Handles input on each keystroke and the search queryParam
@@ -35,4 +39,65 @@ export default class ScopesScopeRolesIndexController extends Controller {
this.search = value;
this.page = 1;
}
/**
* Rollback changes on an role.
* @param {RoleModel} role
*/
@action
cancel(role) {
const { isNew } = role;
role.rollbackAttributes();
if (isNew) this.router.transitionTo('scopes.scope.roles');
}
/**
* Save an role in current scope.
* @param {RoleModel} role
*/
@action
@loading
@notifyError(({ message }) => message)
@notifySuccess(({ isNew }) =>
isNew ? 'notifications.create-success' : 'notifications.save-success',
)
async save(role) {
await role.save();
if (this.can.can('read model', role)) {
await this.router.transitionTo('scopes.scope.roles.role', role);
} else {
await this.router.transitionTo('scopes.scope.roles');
}
await this.router.refresh();
}
/**
* Delete role in current scope and redirect to index.
* @param {RoleModel} role
*/
@action
@loading
@confirm('questions.delete-confirm')
@notifyError(({ message }) => message, { catch: true })
@notifySuccess('notifications.delete-success')
async delete(role) {
await role.destroyRecord();
this.router.replaceWith('scopes.scope.roles');
await this.router.refresh();
}
/**
* Remove a principal from the current role and redirect to principals index.
* @param {RoleModel} role
* @param {UserModel, GroupModel, ManagedGroupModel} principal
*/
@action
@loading
@confirm('questions.remove-confirm')
@notifyError(({ message }) => message, { catch: true })
@notifySuccess('notifications.remove-success')
async removePrincipal(role, principal) {
await role.removePrincipal(principal.id);
await this.router.refresh();
}
}
@@ -0,0 +1,5 @@
import Controller, { inject as controller } from '@ember/controller';
export default class ScopesScopeRolesNewController extends Controller {
@controller('scopes/scope/roles/index') roles;
}
@@ -4,10 +4,16 @@
*/
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { loading } from 'ember-loading';
import { notifySuccess, notifyError } from 'core/decorators/notify';
export default class ScopesScopeRolesRoleAddPrincipalsController extends Controller {
// =services
@service router;
// =attributes
/**
@@ -26,4 +32,28 @@ export default class ScopesScopeRolesRoleAddPrincipalsController extends Control
const sorted = [global, ...orgsAndProjects].flat();
return sorted;
}
// =actions
/**
* Save principal IDs to current role via the API.
* @param {RoleModel} role
* @param {[string]} principalIDs
*/
@action
@loading
@notifyError(({ message }) => message, { catch: true })
@notifySuccess('notifications.add-success')
async addPrincipals(role, principalIDs) {
await role.addPrincipals(principalIDs);
this.router.replaceWith('scopes.scope.roles.role.principals');
}
/**
* Redirect to role principals as if nothing ever happened.
*/
@action
cancel() {
this.router.replaceWith('scopes.scope.roles.role.principals');
}
}
@@ -0,0 +1,63 @@
import Controller, { inject as controller } from '@ember/controller';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { loading } from 'ember-loading';
import { notifySuccess, notifyError } from 'core/decorators/notify';
export default class ScopesScopeRolesRoleGrantsController extends Controller {
@controller('scopes/scope/roles/index') roles;
// =services
@service router;
// =actions
/**
* Adds a new grant to the role at the beginning of the grants list.
* Grant creation is not immediately permanent; users may rollback the change
* via "cancel" or commit it via "save".
* @param {RoleModel} role
* @param {string} grantString
*/
@action
addGrant(role, grantString) {
role.grant_strings = [grantString].concat(role.grant_strings);
}
/**
* Removes a grant from the role. Grant removal is not immediately permanent;
* users may rollback the change via "cancel" or commit it via "save".
* @param {RoleModel} role
* @param {string} grantString
*/
@action
removeGrant(role, grantString) {
role.grant_strings = role.grant_strings.filter(
(str) => str !== grantString,
);
}
/**
* Save a role.
* @param {RoleModel} role
* @param {[string]} grantStrings
*/
@action
@loading
@notifyError(({ message }) => message, { catch: true })
@notifySuccess('notifications.save-success')
async save(role, grantStrings) {
await role.saveGrantStrings(grantStrings);
}
/**
* Rollback changes on a role.
* @param {RoleModel} role
*/
@action
async cancel(role) {
role.rollbackAttributes();
await this.router.refresh('scopes.scope.roles.role');
}
}
@@ -0,0 +1,5 @@
import Controller, { inject as controller } from '@ember/controller';
export default class ScopesScopeRolesRoleIndexController extends Controller {
@controller('scopes/scope/roles/index') roles;
}
@@ -0,0 +1,5 @@
import Controller, { inject as controller } from '@ember/controller';
export default class ScopesScopeRolesRolePrincipalsController extends Controller {
@controller('scopes/scope/roles/index') roles;
}
-53
View File
@@ -5,16 +5,11 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { loading } from 'ember-loading';
import { confirm } from 'core/decorators/confirm';
import { notifySuccess, notifyError } from 'core/decorators/notify';
export default class ScopesScopeRolesRoute extends Route {
// =services
@service session;
@service can;
@service router;
// =methods
@@ -25,52 +20,4 @@ export default class ScopesScopeRolesRoute extends Route {
beforeModel() {
if (!this.session.isAuthenticated) this.router.transitionTo('index');
}
// =actions
/**
* Rollback changes on an role.
* @param {RoleModel} role
*/
@action
cancel(role) {
const { isNew } = role;
role.rollbackAttributes();
if (isNew) this.router.transitionTo('scopes.scope.roles');
}
/**
* Save an role in current scope.
* @param {RoleModel} role
*/
@action
@loading
@notifyError(({ message }) => message)
@notifySuccess(({ isNew }) =>
isNew ? 'notifications.create-success' : 'notifications.save-success',
)
async save(role) {
await role.save();
if (this.can.can('read model', role)) {
await this.router.transitionTo('scopes.scope.roles.role', role);
} else {
await this.router.transitionTo('scopes.scope.roles');
}
this.refresh();
}
/**
* Delete role in current scope and redirect to index.
* @param {RoleModel} role
*/
@action
@loading
@confirm('questions.delete-confirm')
@notifyError(({ message }) => message, { catch: true })
@notifySuccess('notifications.delete-success')
async delete(role) {
await role.destroyRecord();
this.router.replaceWith('scopes.scope.roles');
this.refresh();
}
}
@@ -4,7 +4,6 @@
*/
import Route from '@ember/routing/route';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
export default class ScopesScopeRolesRoleRoute extends Route {
@@ -41,15 +40,4 @@ export default class ScopesScopeRolesRoleRoute extends Route {
this.router.replaceWith(transition.to.name, role.scopeID, role.id);
}
}
// =actions
/**
* Rollback changes on a role.
* @param {RoleModel} role
*/
@action
cancel(role) {
role.rollbackAttributes();
this.refresh();
}
}
@@ -6,8 +6,6 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { loading } from 'ember-loading';
import { notifySuccess, notifyError } from 'core/decorators/notify';
import { resourceFilter } from 'core/decorators/resource-filter';
import {
TYPE_AUTH_METHOD_OIDC,
@@ -88,30 +86,6 @@ export default class ScopesScopeRolesRoleAddPrincipalsRoute extends Route {
};
}
// =actions
/**
* Save principal IDs to current role via the API.
* @param {RoleModel} role
* @param {[string]} principalIDs
*/
@action
@loading
@notifyError(({ message }) => message, { catch: true })
@notifySuccess('notifications.add-success')
async addPrincipals(role, principalIDs) {
await role.addPrincipals(principalIDs);
this.router.replaceWith('scopes.scope.roles.role.principals');
}
/**
* Redirect to role principals as if nothing ever happened.
*/
@action
cancel() {
this.router.replaceWith('scopes.scope.roles.role.principals');
}
/**
* Sets the specified resource filter field to the specified value.
* @param {string} field
@@ -4,53 +4,5 @@
*/
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { loading } from 'ember-loading';
import { notifySuccess, notifyError } from 'core/decorators/notify';
export default class ScopesScopeRolesRoleGrantsRoute extends Route {
// =services
@service intl;
// =actions
/**
* Adds a new grant to the role at the beginning of the grants list.
* Grant creation is not immediately permanent; users may rollback the change
* via "cancel" or commit it via "save".
* @param {RoleModel} role
* @param {string} grantString
*/
@action
addGrant(role, grantString) {
role.grant_strings = [grantString].concat(role.grant_strings);
}
/**
* Removes a grant from the role. Grant removal is not immediately permanent;
* users may rollback the change via "cancel" or commit it via "save".
* @param {RoleModel} role
* @param {string} grantString
*/
@action
removeGrant(role, grantString) {
role.grant_strings = role.grant_strings.filter(
(str) => str !== grantString,
);
}
/**
* Save a role.
* @param {RoleModel} role
* @param {[string]} grantStrings
*/
@action
@loading
@notifyError(({ message }) => message, { catch: true })
@notifySuccess('notifications.save-success')
async save(role, grantStrings) {
await role.saveGrantStrings(grantStrings);
}
}
export default class ScopesScopeRolesRoleGrantsRoute extends Route {}
@@ -4,11 +4,7 @@
*/
import Route from '@ember/routing/route';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
import { loading } from 'ember-loading';
import { confirm } from 'core/decorators/confirm';
import { notifySuccess, notifyError } from 'core/decorators/notify';
import {
TYPE_AUTH_METHOD_OIDC,
TYPE_AUTH_METHOD_LDAP,
@@ -118,21 +114,4 @@ export default class ScopesScopeRolesRolePrincipalsRoute extends Route {
}
return managedGroups;
}
// =actions
/**
* Remove a principal from the current role and redirect to principals index.
* @param {UserModel, GroupModel, ManagedGroupModel} principal
*/
@action
@loading
@confirm('questions.remove-confirm')
@notifyError(({ message }) => message, { catch: true })
@notifySuccess('notifications.remove-success')
async removePrincipal(principal) {
const role = this.modelFor('scopes.scope.roles.role');
await role.removePrincipal(principal.id);
this.refresh();
}
}
@@ -25,8 +25,8 @@
<page.body>
<Form::Role
@model={{@model}}
@submit={{route-action 'save' @model}}
@cancel={{route-action 'cancel' @model}}
@submit={{fn this.roles.save @model}}
@cancel={{fn this.roles.cancel @model}}
/>
</page.body>
</Rose::Layout::Page>
@@ -88,8 +88,8 @@
@users={{@model.users}}
@groups={{@model.groups}}
@managedGroups={{@model.managedGroups}}
@submit={{route-action 'addPrincipals' @model.role}}
@cancel={{route-action 'cancel'}}
@submit={{fn this.addPrincipals @model.role}}
@cancel={{this.cancel}}
/>
</page.body>
@@ -25,7 +25,7 @@
</page.header>
<page.actions>
<Roles::Role::Actions @model={{@model}} />
<Roles::Role::Actions @model={{@model}} @delete={{this.roles.delete}} />
</page.actions>
<page.navigation>
@@ -35,10 +35,10 @@
<page.body>
<Form::Role::Grants
@model={{@model}}
@submit={{route-action 'save' @model}}
@cancel={{route-action 'cancel' @model}}
@addGrant={{route-action 'addGrant' @model}}
@removeGrant={{route-action 'removeGrant' @model}}
@submit={{fn this.save @model}}
@cancel={{fn this.cancel @model}}
@addGrant={{fn this.addGrant @model}}
@removeGrant={{fn this.removeGrant @model}}
/>
</page.body>
@@ -14,7 +14,7 @@
</page.header>
<page.actions>
<Roles::Role::Actions @model={{@model}} />
<Roles::Role::Actions @model={{@model}} @delete={{this.roles.delete}} />
</page.actions>
<page.navigation>
@@ -25,8 +25,8 @@
<Form::Role
@model={{@model}}
@grantScopes={{this.grantScopes}}
@submit={{route-action 'save' @model}}
@cancel={{route-action 'cancel' @model}}
@submit={{fn this.roles.save @model}}
@cancel={{fn this.roles.cancel @model}}
/>
</page.body>
@@ -25,7 +25,10 @@
</page.header>
<page.actions>
<Roles::Role::Actions @model={{@model.role}} />
<Roles::Role::Actions
@model={{@model.role}}
@delete={{this.roles.delete}}
/>
</page.actions>
<page.navigation>
@@ -81,7 +84,10 @@
<dd.Interactive
@color='critical'
@text={{t 'actions.remove'}}
{{on 'click' (route-action 'removePrincipal' B.data)}}
{{on
'click'
(fn this.roles.removePrincipal @model.role B.data)
}}
/>
</Hds::Dropdown>
{{/if}}
@@ -5,13 +5,53 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import { waitUntil } from '@ember/test-helpers';
import { waitUntil, visit } from '@ember/test-helpers';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
import { authenticateSession } from 'ember-simple-auth/test-support';
module('Unit | Controller | scopes/scope/roles/index', function (hooks) {
setupTest(hooks);
setupMirage(hooks);
setupIndexedDb(hooks);
let store;
let controller;
let getRoleCount;
const instances = {
scopes: {
global: null,
},
role: null,
user: null,
};
const urls = {
globalScope: null,
roles: null,
};
hooks.beforeEach(async function () {
authenticateSession({});
store = this.owner.lookup('service:store');
controller = this.owner.lookup('controller:scopes/scope/roles/index');
instances.scopes.global = this.server.create('scope', { id: 'global' });
instances.role = this.server.create('role', {
scopeId: 'global',
});
instances.user = this.server.create('user', {
scopeId: 'global',
});
urls.globalScope = `/scopes/global`;
urls.roles = `${urls.globalScope}/roles`;
getRoleCount = () => this.server.schema.roles.all().models.length;
});
test('it exists', function (assert) {
let controller = this.owner.lookup('controller:scopes/scope/roles/index');
assert.ok(controller);
});
@@ -24,4 +64,48 @@ module('Unit | Controller | scopes/scope/roles/index', function (hooks) {
assert.strictEqual(controller.page, 1);
assert.strictEqual(controller.search, searchValue);
});
test('cancel action rolls-back changes on the specified model', async function (assert) {
await visit(urls.roles);
const role = await store.findRecord('role', instances.role.id);
role.name = 'test';
assert.strictEqual(role.name, 'test');
await controller.cancel(role);
assert.notEqual(role.name, 'test');
});
test('save action saves changes on the specified model', async function (assert) {
await visit(urls.roles);
const role = await store.findRecord('role', instances.role.id);
role.name = 'test';
await controller.save(role);
assert.strictEqual(role.name, 'test');
});
test('delete action destroys specified model', async function (assert) {
const role = await store.findRecord('role', instances.role.id);
const roleCount = getRoleCount();
await controller.delete(role);
assert.strictEqual(getRoleCount(), roleCount - 1);
});
test('removePrincipal action removes a principal from specified model', async function (assert) {
const role = await store.findRecord('role', instances.role.id);
await role.addPrincipals([instances.user.id]);
assert.deepEqual(role.principals, [
{ id: instances.user.id, scope_id: instances.user.scopeId, type: 'user' },
]);
await controller.removePrincipal(role, instances.user);
assert.deepEqual(role.principals, []);
});
});
@@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Controller | scopes/scope/roles/new', function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let controller = this.owner.lookup('controller:scopes/scope/roles/new');
assert.ok(controller);
});
});
@@ -5,17 +5,70 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import { visit } from '@ember/test-helpers';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import { authenticateSession } from 'ember-simple-auth/test-support';
module(
'Unit | Controller | scopes/scope/roles/role/add-principals',
function (hooks) {
setupTest(hooks);
setupMirage(hooks);
test('it exists', function (assert) {
let controller = this.owner.lookup(
let store;
let controller;
const instances = {
scopes: {
global: null,
},
role: null,
user: null,
};
const urls = {
globalScope: null,
addPrincipals: null,
};
hooks.beforeEach(async function () {
authenticateSession({});
store = this.owner.lookup('service:store');
controller = this.owner.lookup(
'controller:scopes/scope/roles/role/add-principals',
);
instances.scopes.global = this.server.create('scope', { id: 'global' });
instances.role = this.server.create('role', {
scopeId: 'global',
});
instances.user = this.server.create('user', {
scopeId: 'global',
});
urls.globalScope = `/scopes/global`;
urls.addPrincipals = `${urls.globalScope}/roles/${instances.role.id}/add-principals`;
});
test('it exists', function (assert) {
assert.ok(controller);
});
test('addPrincipals action adds principals to specified model', async function (assert) {
await visit(urls.addPrincipals);
const role = await store.findRecord('role', instances.role.id);
assert.deepEqual(role.principals, []);
await controller.addPrincipals(role, [instances.user.id]);
assert.deepEqual(role.principals, [
{
id: instances.user.id,
scope_id: instances.user.scopeId,
type: 'user',
},
]);
});
},
);
@@ -0,0 +1,88 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import { visit } from '@ember/test-helpers';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import { authenticateSession } from 'ember-simple-auth/test-support';
module('Unit | Controller | scopes/scope/roles/role/grants', function (hooks) {
setupTest(hooks);
setupMirage(hooks);
let store;
let controller;
const instances = {
scopes: {
global: null,
},
role: null,
};
const urls = {
globalScope: null,
grants: null,
};
hooks.beforeEach(async function () {
authenticateSession({});
store = this.owner.lookup('service:store');
controller = this.owner.lookup('controller:scopes/scope/roles/role/grants');
instances.scopes.global = this.server.create('scope', { id: 'global' });
instances.role = this.server.create('role', {
scopeId: 'global',
});
urls.globalScope = `/scopes/global`;
urls.grants = `${urls.globalScope}/roles/${instances.role.id}/grants`;
});
test('it exists', function (assert) {
assert.ok(controller);
});
test('cancel action rolls-back changes on the specified model', async function (assert) {
await visit(urls.grants);
const role = await store.findRecord('role', instances.role.id);
const grantStrings = role.grant_strings;
role.grant_strings = ['ids=*;type=*;actions=read'];
assert.deepEqual(role.grant_strings, ['ids=*;type=*;actions=read']);
await controller.cancel(role);
assert.deepEqual(role.grant_strings, grantStrings);
});
test('save action saves grantStrings to specified model', async function (assert) {
await visit(urls.grants);
const role = await store.findRecord('role', instances.role.id);
const grantStrings = role.grant_strings;
const newGrantStrings = [...grantStrings, 'ids=*;type=*;actions=read'];
await controller.save(role, newGrantStrings);
assert.deepEqual(role.grant_strings, newGrantStrings);
});
test('removeGrant action removes a grant string from a role', async function (assert) {
await visit(urls.grants);
const role = await store.findRecord('role', instances.role.id);
const grantStrings = role.grant_strings;
await controller.removeGrant(role, grantStrings[0]);
assert.deepEqual(role.grant_strings, grantStrings.slice(1));
});
test('addGrant action adds a grant string from a role', async function (assert) {
await visit(urls.grants);
const role = await store.findRecord('role', instances.role.id);
const grantStrings = role.grant_strings;
const grantString = 'ids=*;type=*;actions=read';
await controller.addGrant(role, grantString);
assert.deepEqual(role.grant_strings, [grantString, ...grantStrings]);
});
});
@@ -0,0 +1,13 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Controller | scopes/scope/roles/role/index', function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let controller = this.owner.lookup(
'controller:scopes/scope/roles/role/index',
);
assert.ok(controller);
});
});
@@ -0,0 +1,16 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module(
'Unit | Controller | scopes/scope/roles/role/principals',
function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let controller = this.owner.lookup(
'controller:scopes/scope/roles/role/principals',
);
assert.ok(controller);
});
},
);