diff --git a/changelog/20747.txt b/changelog/20747.txt
new file mode 100644
index 000000000..4c600d203
--- /dev/null
+++ b/changelog/20747.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: Add filtering by auth type and auth name to the Authentication Method list view.
+```
diff --git a/ui/app/controllers/vault/cluster/access/methods.js b/ui/app/controllers/vault/cluster/access/methods.js
index b05c40d06..9e0fa3a98 100644
--- a/ui/app/controllers/vault/cluster/access/methods.js
+++ b/ui/app/controllers/vault/cluster/access/methods.js
@@ -4,22 +4,74 @@
*/
import Controller from '@ember/controller';
-import { task } from 'ember-concurrency';
+import { dropTask } from 'ember-concurrency';
import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+import { tracked } from '@glimmer/tracking';
-export default Controller.extend({
- flashMessages: service(),
+export default class VaultClusterAccessMethodsController extends Controller {
+ @service flashMessages;
- queryParams: {
- page: 'page',
- pageFilter: 'pageFilter',
- },
+ @tracked authMethodOptions = [];
+ @tracked selectedAuthType = null;
+ @tracked selectedAuthName = null;
- page: 1,
- pageFilter: null,
- filter: null,
+ queryParams = ['page, pageFilter'];
- disableMethod: task(function* (method) {
+ page = 1;
+ pageFilter = null;
+ filter = null;
+
+ get authMethodList() {
+ // return an options list to filter by engine type, ex: 'kv'
+ if (this.selectedAuthType) {
+ // check first if the user has also filtered by name.
+ // names are individualized across type so you can't have the same name for an aws auth method and userpass.
+ // this means it's fine to filter by first type and then name or just name.
+ if (this.selectedAuthName) {
+ return this.model.filter((method) => this.selectedAuthName === method.id);
+ }
+ // otherwise filter by auth type
+ return this.model.filter((method) => this.selectedAuthType === method.type);
+ }
+ // return an options list to filter by auth name, ex: 'my-userpass'
+ if (this.selectedAuthName) {
+ return this.model.filter((method) => this.selectedAuthName === method.id);
+ }
+ // no filters, return full sorted list.
+ return this.model;
+ }
+
+ get authMethodArrayByType() {
+ const arrayOfAllAuthTypes = this.authMethodList.map((modelObject) => modelObject.type);
+ // filter out repeated auth types (e.g. [userpass, userpass] => [userpass])
+ const arrayOfUniqueAuthTypes = [...new Set(arrayOfAllAuthTypes)];
+
+ return arrayOfUniqueAuthTypes.map((authType) => ({
+ name: authType,
+ id: authType,
+ }));
+ }
+
+ get authMethodArrayByName() {
+ return this.authMethodList.map((modelObject) => ({
+ name: modelObject.id,
+ id: modelObject.id,
+ }));
+ }
+
+ @action
+ filterAuthType([type]) {
+ this.selectedAuthType = type;
+ }
+
+ @action
+ filterAuthName([name]) {
+ this.selectedAuthName = name;
+ }
+
+ @dropTask
+ *disableMethod(method) {
const { type, path } = method;
try {
yield method.destroyRecord();
@@ -29,5 +81,5 @@ export default Controller.extend({
`There was an error disabling Auth Method at ${path}: ${err.errors.join(' ')}.`
);
}
- }).drop(),
-});
+ }
+}
diff --git a/ui/app/routes/vault/cluster/access/methods.js b/ui/app/routes/vault/cluster/access/methods.js
index e776b2dd4..7d573c254 100644
--- a/ui/app/routes/vault/cluster/access/methods.js
+++ b/ui/app/routes/vault/cluster/access/methods.js
@@ -6,19 +6,19 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
-export default Route.extend({
- store: service(),
+export default class VaultClusterAccessMethodsRoute extends Route {
+ @service store;
- queryParams: {
+ queryParams = {
page: {
refreshModel: true,
},
pageFilter: {
refreshModel: true,
},
- },
+ };
model() {
return this.store.findAll('auth-method');
- },
-});
+ }
+}
diff --git a/ui/app/templates/vault/cluster/access/methods.hbs b/ui/app/templates/vault/cluster/access/methods.hbs
index 7486c1002..c04c4c7f3 100644
--- a/ui/app/templates/vault/cluster/access/methods.hbs
+++ b/ui/app/templates/vault/cluster/access/methods.hbs
@@ -7,6 +7,33 @@
+
+
+
+
Enable new method
@@ -14,7 +41,7 @@
-{{#each (sort-by "path" this.model) as |method|}}
+{{#each (sort-by "path" this.authMethodList) as |method|}}
row.innerText.includes('userpass'));
+
+ assert.strictEqual(rows.length, rowsUserpass.length, 'all rows returned are userpass');
+
+ // filter by name
+ await clickTrigger('#filter-by-auth-name');
+ const firstItemToSelect = searchSelect.options.objectAt(0).text;
+ await searchSelect.options.objectAt(0).click();
+ const singleRow = document.querySelectorAll('[data-test-auth-backend-link]');
+
+ assert.strictEqual(singleRow.length, 1, 'returns only one row');
+ assert.dom(singleRow[0]).includesText(firstItemToSelect, 'shows the filtered by auth name');
+ // clear filter by engine name
+ await searchSelect.deleteButtons.objectAt(1).click();
+ const rowsAgain = document.querySelectorAll('[data-test-auth-backend-link]');
+ assert.ok(rowsAgain.length > 1, 'filter has been removed');
+
+ // cleanup
+ await consoleComponent.runCommands([`delete sys/auth/${authPath1}`]);
+ await consoleComponent.runCommands([`delete sys/auth/${authPath2}`]);
+ });
});
diff --git a/ui/tests/acceptance/secrets/backend/engines-test.js b/ui/tests/acceptance/secrets/backend/engines-test.js
index db2ab3cad..60fd9a2a8 100644
--- a/ui/tests/acceptance/secrets/backend/engines-test.js
+++ b/ui/tests/acceptance/secrets/backend/engines-test.js
@@ -7,7 +7,7 @@ import { currentRouteName, settled } from '@ember/test-helpers';
import { clickTrigger } from 'ember-power-select/test-support/helpers';
import { create } from 'ember-cli-page-object';
import { module, test } from 'qunit';
-import { runCommands } from 'vault/tests/helpers/pki/pki-run-commands';
+import consoleClass from 'vault/tests/pages/components/console/ui-panel';
import { setupApplicationTest } from 'ember-qunit';
import { v4 as uuidv4 } from 'uuid';
@@ -16,6 +16,7 @@ import backendsPage from 'vault/tests/pages/secrets/backends';
import authPage from 'vault/tests/pages/auth';
import ss from 'vault/tests/pages/components/search-select';
+const consoleComponent = create(consoleClass);
const searchSelect = create(ss);
module('Acceptance | secret-engine list view', function (hooks) {
@@ -76,7 +77,7 @@ module('Acceptance | secret-engine list view', function (hooks) {
assert.dom(rowSupported[0]).hasClass('linked-block', `linked-block class is added to supported engines.`);
// cleanup
- await runCommands([`delete sys/mounts/${enginePath}`]);
+ await consoleComponent.runCommands([`delete sys/mounts/${enginePath}`]);
});
test('it filters by name and engine type', async function (assert) {
@@ -109,7 +110,7 @@ module('Acceptance | secret-engine list view', function (hooks) {
assert.ok(rowsAgain.length > 1, 'filter has been removed');
// cleanup
- await runCommands([`delete sys/mounts/${enginePath1}`]);
- await runCommands([`delete sys/mounts/${enginePath2}`]);
+ await consoleComponent.runCommands([`delete sys/mounts/${enginePath1}`]);
+ await consoleComponent.runCommands([`delete sys/mounts/${enginePath2}`]);
});
});