diff --git a/addons/core/addon/helpers/route-action.js b/addons/core/addon/helpers/route-action.js deleted file mode 100644 index e69a376cc..000000000 --- a/addons/core/addon/helpers/route-action.js +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) HashiCorp, Inc. - * SPDX-License-Identifier: BUSL-1.1 - */ - -import Helper from '@ember/component/helper'; -import { inject as service } from '@ember/service'; -import { join } from '@ember/runloop'; -import { runInDebug, assert } from '@ember/debug'; -import { A } from '@ember/array'; - -/** - * This helper is a modern update on ember-route-action-helper, which is - * now unmaintained. - * - * See https://github.com/DockYard/ember-route-action-helper - */ -export default class RouteActionHelper extends Helper { - // =services - - @service router; - - // =attributes - - get routes() { - const { currentInfos, mapBy } = this.currentInfos; - return A(currentInfos).mapBy(mapBy).reverse(); - } - - get currentInfos() { - // eslint-disable-next-line ember/no-private-routing-service - const routerLib = this.router._router._routerMicrolib; - return { - currentInfos: - routerLib.currentRouteInfos || routerLib.currentHandlerInfos, - mapBy: (routerLib.currentRouteInfos && 'route') || 'handler', - }; - } - - // =methods - - compute([actionName, ...outerArgs]) { - const { action, handler } = this.getRouteWithAction(actionName); - - runInDebug(() => { - assert( - ` - [boundary-core-helper-route-action] - Unable to find action ${actionName} - `, - handler, - ); - }); - - return (...innerArgs) => - join(handler, action, ...outerArgs.concat(innerArgs)); - } - - getRouteWithAction(actionName) { - let action; - const handler = A(this.routes).find((route) => { - const actions = route.actions || route._actions; - action = actions[actionName]; - return typeof action === 'function'; - }); - - return { action, handler }; - } -} diff --git a/addons/core/app/helpers/route-action.js b/addons/core/app/helpers/route-action.js deleted file mode 100644 index eaa68564a..000000000 --- a/addons/core/app/helpers/route-action.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Copyright (c) HashiCorp, Inc. - * SPDX-License-Identifier: BUSL-1.1 - */ - -export { default } from 'core/helpers/route-action'; diff --git a/ui/admin/.template-lintrc.js b/ui/admin/.template-lintrc.js index 05e4ca99d..71a2c0c5f 100644 --- a/ui/admin/.template-lintrc.js +++ b/ui/admin/.template-lintrc.js @@ -18,7 +18,6 @@ module.exports = { 'is-loading', ], }, - 'no-route-action': false, }, overrides: [ { diff --git a/ui/admin/app/controllers/scopes/scope/groups/group/add-members.js b/ui/admin/app/controllers/scopes/scope/groups/group/add-members.js index 6db68d193..4e1621695 100644 --- a/ui/admin/app/controllers/scopes/scope/groups/group/add-members.js +++ b/ui/admin/app/controllers/scopes/scope/groups/group/add-members.js @@ -57,4 +57,22 @@ export default class ScopesScopeGroupsGroupAddMembersController extends Controll async cancel() { await this.router.replaceWith('scopes.scope.groups.group.members'); } + + /** + * Calls filterBy action located in the route. + * @param {string} field + * @param {[ScopeModel]} value + */ + @action + callFilterBy(field, value) { + this.send('filterBy', field, value); + } + + /** + * Calls clearAllFilters action located in the route. + */ + @action + callClearAllFilters() { + this.send('clearAllFilters'); + } } diff --git a/ui/admin/app/controllers/scopes/scope/roles/role/add-principals.js b/ui/admin/app/controllers/scopes/scope/roles/role/add-principals.js index 9d710c839..83635e5fd 100644 --- a/ui/admin/app/controllers/scopes/scope/roles/role/add-principals.js +++ b/ui/admin/app/controllers/scopes/scope/roles/role/add-principals.js @@ -56,4 +56,22 @@ export default class ScopesScopeRolesRoleAddPrincipalsController extends Control cancel() { this.router.replaceWith('scopes.scope.roles.role.principals'); } + + /** + * Calls filterBy action located in the route. + * @param {string} field + * @param {[ScopeModel]} value + */ + @action + callFilterBy(field, value) { + this.send('filterBy', field, value); + } + + /** + * Calls clearAllFilters action located in the route. + */ + @action + callClearAllFilters() { + this.send('clearAllFilters'); + } } diff --git a/ui/admin/app/controllers/scopes/scope/workers/index.js b/ui/admin/app/controllers/scopes/scope/workers/index.js index 0619700d8..23219bb41 100644 --- a/ui/admin/app/controllers/scopes/scope/workers/index.js +++ b/ui/admin/app/controllers/scopes/scope/workers/index.js @@ -39,6 +39,15 @@ export default class ScopesScopeWorkersIndexController extends Controller { return `${tag.key} = ${tag.value}`; } + /** + * Determine equality between two tags based on both key and value. + * @param {object} firstTag + * @param {object} secondTag + */ + isEqual(firstTag, secondTag) { + return firstTag.key === secondTag.key && firstTag.value === secondTag.value; + } + // =actions /** @@ -96,4 +105,30 @@ export default class ScopesScopeWorkersIndexController extends Controller { await this.router.replaceWith('scopes.scope.workers'); await this.router.refresh(); } + + /** + * Calls filterBy action located in the route. + * @param {string} field + * @param {[object]} value + */ + @action + callFilterBy(field, value) { + this.send('filterBy', field, value); + } + + /** + * Calls clearAllFilters action located in the route. + */ + @action + callClearAllFilters() { + this.send('clearAllFilters'); + } + + /** + * Refreshes worker data. + */ + @action + refresh() { + this.router.refresh('scopes.scope.workers'); + } } diff --git a/ui/admin/app/routes/scopes/scope/workers.js b/ui/admin/app/routes/scopes/scope/workers.js index 6c96955b1..dd6c25ae5 100644 --- a/ui/admin/app/routes/scopes/scope/workers.js +++ b/ui/admin/app/routes/scopes/scope/workers.js @@ -5,7 +5,6 @@ import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; -import { action } from '@ember/object'; export default class ScopesScopeWorkersRoute extends Route { // =services @@ -35,12 +34,4 @@ export default class ScopesScopeWorkersRoute extends Route { return this.store.query('worker', { scope_id }); } } - - /** - * Refreshes worker data. - */ - @action - refresh() { - return super.refresh(...arguments); - } } diff --git a/ui/admin/app/routes/scopes/scope/workers/index.js b/ui/admin/app/routes/scopes/scope/workers/index.js index b1cb00cc9..3a253cf5f 100644 --- a/ui/admin/app/routes/scopes/scope/workers/index.js +++ b/ui/admin/app/routes/scopes/scope/workers/index.js @@ -98,11 +98,6 @@ export default class ScopesScopeWorkersIndexRoute extends Route { this.refresh(); } - @action - isEqual(firstTag, secondTag) { - return firstTag.key === secondTag.key && firstTag.value === secondTag.value; - } - setupController(controller) { const scope = this.modelFor('scopes.scope'); super.setupController(...arguments); diff --git a/ui/admin/app/templates/scopes/scope/groups/group/add-members.hbs b/ui/admin/app/templates/scopes/scope/groups/group/add-members.hbs index 6cbf9e82f..7d89f7b42 100644 --- a/ui/admin/app/templates/scopes/scope/groups/group/add-members.hbs +++ b/ui/admin/app/templates/scopes/scope/groups/group/add-members.hbs @@ -43,7 +43,7 @@ @name={{filter.name}} @items={{this.flatSortedScopes}} @selectedItems={{filter.selectedValue}} - @onChange={{route-action 'filterBy' filter.name}} + @onChange={{fn this.callFilterBy filter.name}} as |group| >
  • {{t 'actions.clear-all-filters'}} {{/if}} diff --git a/ui/admin/app/templates/scopes/scope/roles/role/add-principals.hbs b/ui/admin/app/templates/scopes/scope/roles/role/add-principals.hbs index fba47331e..3a4447a27 100644 --- a/ui/admin/app/templates/scopes/scope/roles/role/add-principals.hbs +++ b/ui/admin/app/templates/scopes/scope/roles/role/add-principals.hbs @@ -43,7 +43,7 @@ @name={{filter.name}} @items={{this.flatSortedScopes}} @selectedItems={{filter.selectedValue}} - @onChange={{route-action 'filterBy' filter.name}} + @onChange={{fn this.callFilterBy filter.name}} as |group| >
  • {{t 'actions.clear-all-filters'}} {{/if}} diff --git a/ui/admin/app/templates/scopes/scope/workers/index.hbs b/ui/admin/app/templates/scopes/scope/workers/index.hbs index 0fc830bf8..bf0879ce9 100644 --- a/ui/admin/app/templates/scopes/scope/workers/index.hbs +++ b/ui/admin/app/templates/scopes/scope/workers/index.hbs @@ -55,8 +55,8 @@ @name={{key}} @items={{tags}} @selectedItems={{filter.selectedValue}} - @onChange={{route-action 'filterBy' filter.name}} - @itemEqualityFunc={{route-action 'isEqual'}} + @onChange={{fn this.callFilterBy filter.name}} + @itemEqualityFunc={{this.isEqual}} as |group| > @@ -78,7 +78,7 @@ {{t 'actions.clear-all-filters'}} {{/if}} @@ -86,7 +86,7 @@ - + diff --git a/ui/admin/tests/unit/controllers/scopes/scope/groups/group/add-members-test.js b/ui/admin/tests/unit/controllers/scopes/scope/groups/group/add-members-test.js index ce58b1a34..c621b608f 100644 --- a/ui/admin/tests/unit/controllers/scopes/scope/groups/group/add-members-test.js +++ b/ui/admin/tests/unit/controllers/scopes/scope/groups/group/add-members-test.js @@ -4,18 +4,111 @@ */ import { module, test } from 'qunit'; -import { setupTest } from 'admin/tests/helpers'; +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/groups/group/add-members', 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, + org: null, + }, + group: null, + user: null, + }; + + const urls = { + globalScope: null, + addMembers: null, + }; + + hooks.beforeEach(function () { + authenticateSession({}); + store = this.owner.lookup('service:store'); + controller = this.owner.lookup( 'controller:scopes/scope/groups/group/add-members', ); + + instances.scopes.global = this.server.create('scope', { id: 'global' }); + instances.scopes.org = this.server.create('scope', { + type: 'org', + scope: { id: 'global', type: 'global' }, + }); + instances.group = this.server.create('group', { + scope: instances.scopes.global, + }); + instances.user = this.server.create('user', { + scope: instances.scopes.global, + }); + + urls.globalScope = `/scopes/global`; + urls.addMembers = `${urls.globalScope}/groups/${instances.group.id}/add-members`; + }); + + test('it exists', function (assert) { assert.ok(controller); }); + + test('flatSortedScopes returns array of sorted scopes', async function (assert) { + const globalScope = await store.findRecord( + 'scope', + instances.scopes.global.id, + ); + const orgScope = await store.findRecord('scope', instances.scopes.org.id); + await visit(urls.addMembers); + + assert.deepEqual(controller.flatSortedScopes, [globalScope, orgScope]); + }); + + test('addMembers action adds users to specified model', async function (assert) { + await visit(urls.addMembers); + const group = await store.findRecord('group', instances.group.id); + const user = await store.findRecord('user', instances.user.id); + + assert.deepEqual(group.members, []); + + await controller.addMembers(group, [instances.user.id]); + + assert.deepEqual(group.members, [user]); + }); + + test('callFilterBy action adds expected property values to route', async function (assert) { + const route = this.owner.lookup( + 'route:scopes/scope/groups/group/add-members', + ); + await visit(urls.addMembers); + const scope = await store.findRecord('scope', instances.scopes.global.id); + + assert.notOk(route.scope); + + controller.callFilterBy('scope', [scope]); + + assert.deepEqual(route.scope, [scope]); + }); + + test('callClearAllFilters action removes all filter values from route', async function (assert) { + const route = this.owner.lookup( + 'route:scopes/scope/groups/group/add-members', + ); + await visit(urls.addMembers); + const scope = await store.findRecord('scope', instances.scopes.global.id); + route.scope = [scope]; + + assert.deepEqual(route.scope, [scope]); + + controller.callClearAllFilters(); + + assert.deepEqual(route.scope, []); + }); }, ); diff --git a/ui/admin/tests/unit/controllers/scopes/scope/roles/role/add-principals-test.js b/ui/admin/tests/unit/controllers/scopes/scope/roles/role/add-principals-test.js index bfd6f25ab..eba139e05 100644 --- a/ui/admin/tests/unit/controllers/scopes/scope/roles/role/add-principals-test.js +++ b/ui/admin/tests/unit/controllers/scopes/scope/roles/role/add-principals-test.js @@ -21,6 +21,8 @@ module( const instances = { scopes: { global: null, + org: null, + project: null, }, role: null, user: null, @@ -39,6 +41,14 @@ module( ); instances.scopes.global = this.server.create('scope', { id: 'global' }); + instances.scopes.org = this.server.create('scope', { + type: 'org', + scope: { id: 'global', type: 'global' }, + }); + instances.scopes.project = this.server.create('scope', { + type: 'project', + scope: { id: instances.scopes.org.id, type: 'org' }, + }); instances.role = this.server.create('role', { scopeId: 'global', }); @@ -54,6 +64,25 @@ module( assert.ok(controller); }); + test('flatSortedScopes returns array of sorted scopes', async function (assert) { + const globalScope = await store.findRecord( + 'scope', + instances.scopes.global.id, + ); + const orgScope = await store.findRecord('scope', instances.scopes.org.id); + const projectScope = await store.findRecord( + 'scope', + instances.scopes.project.id, + ); + await visit(urls.addPrincipals); + + assert.deepEqual(controller.flatSortedScopes, [ + globalScope, + orgScope, + projectScope, + ]); + }); + test('addPrincipals action adds principals to specified model', async function (assert) { await visit(urls.addPrincipals); const role = await store.findRecord('role', instances.role.id); @@ -70,5 +99,34 @@ module( }, ]); }); + + test('callFilterBy action adds expected property values to route', async function (assert) { + const route = this.owner.lookup( + 'route:scopes/scope/roles/role/add-principals', + ); + await visit(urls.addPrincipals); + const scope = await store.findRecord('scope', instances.scopes.global.id); + + assert.notOk(route.scope); + + controller.callFilterBy('scope', [scope]); + + assert.deepEqual(route.scope, [scope]); + }); + + test('callClearAllFilters action removes all filter values from route', async function (assert) { + const route = this.owner.lookup( + 'route:scopes/scope/roles/role/add-principals', + ); + await visit(urls.addPrincipals); + const scope = await store.findRecord('scope', instances.scopes.global.id); + route.scope = [scope]; + + assert.deepEqual(route.scope, [scope]); + + controller.callClearAllFilters(); + + assert.deepEqual(route.scope, []); + }); }, ); diff --git a/ui/admin/tests/unit/controllers/scopes/scope/workers/index-test.js b/ui/admin/tests/unit/controllers/scopes/scope/workers/index-test.js index 4466e12c1..c80f0a8e4 100644 --- a/ui/admin/tests/unit/controllers/scopes/scope/workers/index-test.js +++ b/ui/admin/tests/unit/controllers/scopes/scope/workers/index-test.js @@ -39,6 +39,7 @@ module('Unit | Controller | scopes/scope/workers/index', function (hooks) { instances.scopes.global = this.server.create('scope', { id: 'global' }); instances.worker = this.server.create('worker', { scope: instances.scopes.global, + config_tags: { type: ['dev'] }, }); urls.globalScope = `/scopes/global`; @@ -81,4 +82,31 @@ module('Unit | Controller | scopes/scope/workers/index', function (hooks) { assert.strictEqual(getWorkerCount(), workerCount - 1); }); + + test('callFilterBy action adds expected property values to route', async function (assert) { + const route = this.owner.lookup('route:scopes/scope/workers/index'); + await visit(urls.workers); + const tag = { key: 'type', value: 'dev', type: 'config' }; + + assert.notOk(route.tags); + + controller.callFilterBy('tags', [tag]); + + assert.deepEqual(route.tags, [tag]); + }); + + test('callClearAllFilters action removes all filter values from route', async function (assert) { + const route = this.owner.lookup('route:scopes/scope/workers/index'); + await visit(urls.workers); + const tag = { key: 'type', value: 'dev', type: 'config' }; + controller.callFilterBy('tags', [tag]); + + assert.deepEqual(route.tags, [ + { key: 'type', value: 'dev', type: 'config' }, + ]); + + controller.callClearAllFilters(); + + assert.deepEqual(route.tags, []); + }); });