diff --git a/ui/admin/app/controllers/scopes/scope/auth-methods/index.js b/ui/admin/app/controllers/scopes/scope/auth-methods/index.js index 5a12091a6..334c95eb2 100644 --- a/ui/admin/app/controllers/scopes/scope/auth-methods/index.js +++ b/ui/admin/app/controllers/scopes/scope/auth-methods/index.js @@ -28,6 +28,8 @@ export default class ScopesScopeAuthMethodsIndexController extends Controller { { primary: { type: 'array' } }, 'page', 'pageSize', + 'sortAttribute', + 'sortDirection', ]; @tracked search; @@ -35,6 +37,8 @@ export default class ScopesScopeAuthMethodsIndexController extends Controller { @tracked primary = []; @tracked page = 1; @tracked pageSize = 10; + @tracked sortAttribute; + @tracked sortDirection; /** * True if the current scope has a primary auth method set. @@ -326,4 +330,16 @@ export default class ScopesScopeAuthMethodsIndexController extends Controller { async changeState(authMethod, state) { await authMethod.changeState(state); } + + /** + * Set sort values and sets page to 1 + * @param {string} sortBy + * @param {string} sortOrder + */ + @action + onSort(sortBy, sortOrder) { + this.sortAttribute = sortBy; + this.sortDirection = sortOrder; + this.page = 1; + } } diff --git a/ui/admin/app/routes/scopes/scope/auth-methods/index.js b/ui/admin/app/routes/scopes/scope/auth-methods/index.js index 2ca60c9d2..00f8de14b 100644 --- a/ui/admin/app/routes/scopes/scope/auth-methods/index.js +++ b/ui/admin/app/routes/scopes/scope/auth-methods/index.js @@ -35,6 +35,14 @@ export default class ScopesScopeAuthMethodsIndexRoute extends Route { pageSize: { refreshModel: true, }, + sortAttribute: { + refreshModel: true, + replace: true, + }, + sortDirection: { + refreshModel: true, + replace: true, + }, }; // =methods @@ -50,7 +58,16 @@ export default class ScopesScopeAuthMethodsIndexRoute extends Route { } retrieveData = restartableTask( - async ({ search, types, primary, page, pageSize, useDebounce }) => { + async ({ + search, + types, + primary, + page, + pageSize, + sortAttribute, + sortDirection, + useDebounce, + }) => { if (useDebounce) { await timeout(250); } @@ -63,6 +80,11 @@ export default class ScopesScopeAuthMethodsIndexRoute extends Route { is_primary: [], }; + const sort = { + attribute: sortAttribute, + direction: sortDirection, + }; + types.forEach((type) => { filters.type.push({ equals: type }); }); @@ -82,7 +104,7 @@ export default class ScopesScopeAuthMethodsIndexRoute extends Route { 'auth-method', { scope_id, - query: { search, filters }, + query: { search, filters, sort }, page, pageSize, }, diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/index.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/index.hbs index 0268f9fab..5922d8727 100644 --- a/ui/admin/app/templates/scopes/scope/auth-methods/index.hbs +++ b/ui/admin/app/templates/scopes/scope/auth-methods/index.hbs @@ -94,80 +94,102 @@ {{#if @model.authMethods}} + <:head as |H|> + + {{t 'form.name.label'}} + {{t 'form.type.label'}} + {{t 'form.id.label'}} + {{t + 'resources.auth-method.titles.primary' + }} + {{t 'titles.actions'}} + + + <:body as |B|> - - - {{#if (can 'read auth-method' B.data)}} - - {{B.data.displayName}} - - {{else}} - {{B.data.displayName}} - {{/if}} - - {{B.data.description}} - - - - - - - - - - {{#if B.data.isPrimary}} - - {{/if}} - - - {{#if (can 'makePrimary auth-method' B.data)}} - - - {{#unless B.data.isPrimary}} - - {{t 'resources.auth-method.actions.make-primary'}} - - {{/unless}} - {{#if B.data.isPrimary}} - - {{t 'resources.auth-method.actions.remove-as-primary'}} - - {{/if}} - - {{/if}} - - + {{#each @model.authMethods as |data|}} + + {{! Name }} + + {{#if (can 'read auth-method' data)}} + + {{data.displayName}} + + {{else}} + {{data.displayName}} + {{/if}} + + {{data.description}} + + + {{! Type }} + + + + {{! ID }} + + + + {{! isPrimary }} + + {{#if data.isPrimary}} + + {{/if}} + + {{! Actions }} + + {{#if (can 'makePrimary auth-method' data)}} + + + {{#unless data.isPrimary}} + + {{t 'resources.auth-method.actions.make-primary'}} + + {{/unless}} + {{#if data.isPrimary}} + + {{t + 'resources.auth-method.actions.remove-as-primary' + }} + + {{/if}} + + {{/if}} + + + {{/each}} { + return this.server.create('auth-method', { + scope: instances.scopes.org, + type: TYPE_AUTH_METHOD_PASSWORD, + created_time: `${year}-01-01T00:00:00Z`, + name: `Auth-method ${year}`, + }); + }); + + await visit(urls.authMethods); + + assert.dom(commonSelectors.TABLE_ROWS).exists({ count: years.length }); + + years.forEach((year, index) => { + // nth-child index starts at 1 + assert + .dom(commonSelectors.TABLE_ROW(index + 1)) + .containsText(`Auth-method ${year}`); + }); + }); + + test.each( + 'sorting', + { + 'on name': { + attribute: { + key: 'name', + values: ['Alpha', 'Beta', 'Delta', 'Gamma', 'Epsilon'], + }, + expectedAscendingSort: ['Alpha', 'Beta', 'Delta', 'Epsilon', 'Gamma'], + column: 1, + }, + 'on type': { + attribute: { + key: 'type', + values: ['Password', 'Oidc', 'Oidc', 'Password', 'Ldap'], + }, + expectedAscendingSort: ['Ldap', 'Oidc', 'Oidc', 'Password', 'Password'], + column: 2, + }, + 'on id': { + attribute: { + key: 'id', + values: ['am_1000', 'am_0001', 'am_0100', 'am_0010'], + }, + expectedAscendingSort: ['am_0001', 'am_0010', 'am_0100', 'am_1000'], + column: 3, + }, + }, + async function (assert, input) { + this.server.schema.authMethods.all().destroy(); + faker.helpers.shuffle(input.attribute.values).forEach((value) => { + this.server.create('auth-method', { + [input.attribute.key]: value, + scope: instances.scopes.org, + }); + }); + + await visit(urls.authMethods); + + // click the sort button again to sort in ascending order + await click(commonSelectors.TABLE_SORT_BTN(input.column)); + assert.true(currentURL().includes('sortDirection=asc')); + assert.true( + currentURL().includes(`sortAttribute=${input.attribute.key}`), + ); + assert + .dom(commonSelectors.TABLE_SORT_BTN_ARROW_UP(input.column)) + .isVisible(); + + assert + .dom(commonSelectors.TABLE_ROWS) + .isVisible({ count: input.attribute.values.length }); + + input.expectedAscendingSort.forEach((expected, index) => { + // nth-child index starts at 1 + assert.dom(commonSelectors.TABLE_ROW(index + 1)).containsText(expected); + }); + + // click the sort button again to sort in descending order + await click(commonSelectors.TABLE_SORT_BTN(input.column)); + assert.true(currentURL().includes('sortDirection=desc')); + assert.true( + currentURL().includes(`sortAttribute=${input.attribute.key}`), + ); + assert + .dom(commonSelectors.TABLE_SORT_BTN_ARROW_DOWN(input.column)) + .isVisible(); + + input.expectedAscendingSort.toReversed().forEach((expected, index) => { + // nth-child index starts at 1 + assert.dom(commonSelectors.TABLE_ROW(index + 1)).containsText(expected); + }); + }, + ); });