Icu 16786 implement sort for targets (#2830)

* feat: 🎸 add sorting for targets

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-16786
This commit is contained in:
Lisbet Alvarez authored and GitHub committed 2025-05-21 12:20:48 -07:00
1 parent 8f3cccce32
commit 44bd5ee1c6
16 files changed
+264 -150

No files matched your search

@@ -28,6 +28,8 @@ export default class ScopesScopeTargetsIndexController extends Controller {
{ types: { type: 'array' } },
'page',
'pageSize',
'sortAttribute',
'sortDirection',
];
@tracked search;
@@ -37,6 +39,8 @@ export default class ScopesScopeTargetsIndexController extends Controller {
@tracked page = 1;
@tracked pageSize = 10;
@tracked selectedTarget;
@tracked sortAttribute;
@tracked sortDirection;
get availableSessionOptions() {
return [
@@ -301,7 +305,7 @@ export default class ScopesScopeTargetsIndexController extends Controller {
}
/**
* Remove destaination_id from alias
* Remove destination_id from alias
* @param {AliasModel} alias
*/
@action
@@ -363,4 +367,11 @@ export default class ScopesScopeTargetsIndexController extends Controller {
target.rollbackAttributes();
await this.router.replaceWith('scopes.scope.targets.target.workers');
}
@action
onSort(sortBy, sortOrder) {
this.sortAttribute = sortBy;
this.sortDirection = sortOrder;
this.page = 1;
}
}
@@ -39,6 +39,14 @@ export default class ScopesScopeTargetsIndexRoute extends Route {
pageSize: {
refreshModel: true,
},
sortAttribute: {
refreshModel: true,
replace: true,
},
sortDirection: {
refreshModel: true,
replace: true,
},
};
// =methods
@@ -61,6 +69,8 @@ export default class ScopesScopeTargetsIndexRoute extends Route {
types,
page,
pageSize,
sortAttribute,
sortDirection,
useDebounce,
}) => {
if (useDebounce) {
@@ -99,16 +109,19 @@ export default class ScopesScopeTargetsIndexRoute extends Route {
let totalItems = 0;
let doTargetsExist = false;
if (this.can.can('list model', scope, { collection: 'targets' })) {
const sort = {
attribute: sortAttribute,
direction: sortDirection,
};
targets = await this.store.query('target', {
scope_id,
query: { search, filters },
query: { search, filters, sort },
page,
pageSize,
});
totalItems = targets.meta?.totalItems;
doTargetsExist = await this.getDoTargetsExist(scope_id, totalItems);
}
return { targets, doTargetsExist, totalItems };
},
);
@@ -69,103 +69,73 @@
{{#if @model.targets}}
<Hds::Table
@columns={{array
(hash label=(t 'form.name.label'))
(hash label=(t 'form.type.label'))
(hash label=(t 'resources.target.titles.active-sessions'))
(hash label=(t 'form.id.label'))
}}
@model={{@model.targets}}
@valign='middle'
@onSort={{this.onSort}}
@sortBy={{this.sortAttribute}}
@sortOrder={{this.sortDirection}}
>
<:head as |H|>
<H.Tr>
<H.ThSort
@onClickSort={{fn H.setSortBy 'name'}}
@sortOrder={{if (eq 'name' H.sortBy) H.sortOrder}}
>{{t 'form.name.label'}}</H.ThSort>
<H.ThSort
@onClickSort={{fn H.setSortBy 'type'}}
@sortOrder={{if (eq 'type' H.sortBy) H.sortOrder}}
>{{t 'form.type.label'}}</H.ThSort>
<H.Th>{{t 'resources.target.titles.active-sessions'}}</H.Th>
<H.ThSort
@onClickSort={{fn H.setSortBy 'id'}}
@sortOrder={{if (eq 'id' H.sortBy) H.sortOrder}}
>{{t 'form.id.label'}}</H.ThSort>
</H.Tr>
</:head>
<:body as |B|>
{{#if (feature-flag 'ssh-target')}}
<B.Tr data-test-targets-table-row={{B.data.id}}>
<B.Td>
{{#if (can 'read model' B.data)}}
<LinkTo
@route='scopes.scope.targets.target'
@model={{B.data.id}}
>
{{B.data.displayName}}
</LinkTo>
{{else}}
{{B.data.displayName}}
{{/if}}
<Hds::Text::Body @tag='p'>
{{B.data.description}}
</Hds::Text::Body>
</B.Td>
<B.Td>
{{#if B.data.type}}
<Hds::Badge
@text={{t (concat 'resources.target.types.' B.data.type)}}
/>
{{/if}}
</B.Td>
<B.Td>
{{#if B.data.isActive}}
<Hds::Link::Standalone
@text={{t 'actions.yes'}}
@route='scopes.scope.sessions.index'
@query={{hash targets=(array B.data.id)}}
@icon='info'
/>
{{/if}}
</B.Td>
<B.Td>
<Hds::Copy::Snippet
@textToCopy={{B.data.id}}
@color='secondary'
/>
</B.Td>
</B.Tr>
{{else}}
{{#if B.data.isTCP}}
<B.Tr data-test-targets-table-row={{B.data.id}}>
{{#each @model.targets as |data|}}
{{#if (or (feature-flag 'ssh-target') data.isTCP)}}
<B.Tr data-test-targets-table-row={{data.id}}>
<B.Td>
{{#if (can 'read model' B.data)}}
{{#if (can 'read model' data)}}
<LinkTo
@route='scopes.scope.targets.target'
@model={{B.data.id}}
@model={{data.id}}
>
{{B.data.displayName}}
{{data.displayName}}
</LinkTo>
{{else}}
{{B.data.displayName}}
{{data.displayName}}
{{/if}}
<Hds::Text::Body @tag='p' class='p'>
{{B.data.description}}
{{data.description}}
</Hds::Text::Body>
</B.Td>
<B.Td>
{{#if B.data.type}}
{{#if data.type}}
<Hds::Badge
@text={{t
(concat 'resources.target.types.' B.data.type)
}}
@text={{t (concat 'resources.target.types.' data.type)}}
/>
{{/if}}
</B.Td>
<B.Td>
{{#if B.data.isActive}}
{{#if data.isActive}}
<Hds::Link::Standalone
@text={{t 'actions.yes'}}
@route='scopes.scope.sessions.index'
@query={{hash targets=(array B.data.id)}}
@query={{hash targets=(array data.id)}}
@icon='info'
/>
{{/if}}
</B.Td>
<B.Td>
<Hds::Copy::Snippet
@textToCopy={{B.data.id}}
@textToCopy={{data.id}}
@color='secondary'
/>
</B.Td>
</B.Tr>
{{/if}}
{{/if}}
{{/each}}
</:body>
</Hds::Table>
<Rose::Pagination
@@ -61,18 +61,18 @@ module('Acceptance | groups | members', function (hooks) {
await a11yAudit();
assert.strictEqual(currentURL(), urls.members);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: membersCount });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: membersCount });
});
test('can remove a member', async function (assert) {
await visit(urls.members);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: membersCount });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: membersCount });
await click(selectors.TABLE_MEMBER_ACTION_DROPDOWN);
await click(selectors.TABLE_MEMBER_ACTION_DROPDOWN_DELETE_MEMBER);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: membersCount - 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: membersCount - 1 });
});
test('cannot remove a member without proper authorization', async function (assert) {
@@ -102,7 +102,7 @@ module('Acceptance | groups | members', function (hooks) {
);
});
await visit(urls.members);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: membersCount });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: membersCount });
await click(selectors.TABLE_MEMBER_ACTION_DROPDOWN);
await click(selectors.TABLE_MEMBER_ACTION_DROPDOWN_DELETE_MEMBER);
@@ -137,7 +137,7 @@ module('Acceptance | groups | members', function (hooks) {
instances.group.update({ memberIds: [] });
await visit(urls.members);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
await click(selectors.MANAGE_DROPDOWN);
await click(selectors.MANAGE_DROPDOWN_ADD_MEMBER);
@@ -149,18 +149,18 @@ module('Acceptance | groups | members', function (hooks) {
await visit(urls.members);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 1 });
});
test('select and cancel members to add', async function (assert) {
await visit(urls.members);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: membersCount });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: membersCount });
await click(selectors.TABLE_MEMBER_ACTION_DROPDOWN);
await click(selectors.TABLE_MEMBER_ACTION_DROPDOWN_DELETE_MEMBER);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: membersCount - 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: membersCount - 1 });
await click(selectors.MANAGE_DROPDOWN);
await click(selectors.MANAGE_DROPDOWN_ADD_MEMBER);
@@ -172,7 +172,7 @@ module('Acceptance | groups | members', function (hooks) {
await click(commonSelectors.CANCEL_BTN);
assert.strictEqual(currentURL(), urls.members);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: membersCount - 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: membersCount - 1 });
});
test('shows error message on member add', async function (assert) {
@@ -93,7 +93,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
assert.strictEqual(currentURL(), urls.roleScopes);
assert
.dom(commonSelectors.TABLE_ROW)
.dom(commonSelectors.TABLE_ROWS)
.exists({ count: instances.role.grant_scope_ids.length });
});
@@ -276,7 +276,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.HREF(urls.roleScopes));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
await click(selectors.MANAGE_DROPDOWN_ROLES);
await click(selectors.MANAGE_DROPDOWN_ROLES_SCOPES);
@@ -291,7 +291,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.SAVE_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 1 });
});
test('user can cancel scope keywords to add on manage scopes page', async function (assert) {
@@ -300,7 +300,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.HREF(urls.roleScopes));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
await click(selectors.MANAGE_DROPDOWN_ROLES);
await click(selectors.MANAGE_DROPDOWN_ROLES_SCOPES);
@@ -314,7 +314,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.CANCEL_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
});
test('shows error message on scope save on manage scopes page', async function (assert) {
@@ -387,7 +387,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.HREF(urls.roleScopes));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
await click(selectors.MANAGE_DROPDOWN_ROLES);
await click(selectors.MANAGE_DROPDOWN_ROLES_SCOPES);
@@ -411,7 +411,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.SAVE_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 1 });
});
test('user can cancel custom scopes to add on manage custom scopes page', async function (assert) {
@@ -420,7 +420,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.HREF(urls.roleScopes));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
await click(selectors.MANAGE_DROPDOWN_ROLES);
await click(selectors.MANAGE_DROPDOWN_ROLES_SCOPES);
@@ -440,7 +440,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.CANCEL_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
});
test('shows error message on custom scope save on manage custom scopes page', async function (assert) {
@@ -522,7 +522,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.SAVE_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 1 });
});
test('user can choose to deselect an org and projects using modal on manage custom scopes page', async function (assert) {
@@ -545,7 +545,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.SAVE_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
});
test('user cannot trigger modal when deselecting an org with no projects selected on manage custom scopes page', async function (assert) {
@@ -565,7 +565,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.SAVE_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
});
test('user can choose to only deselect all orgs using modal on manage custom scopes page', async function (assert) {
@@ -591,7 +591,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.SAVE_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 1 });
});
test('user can choose to deselect all orgs and projects using modal on manage custom scopes page', async function (assert) {
@@ -617,7 +617,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.SAVE_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
});
test('user cannot trigger modal when deselecting all orgs with no projects selected on manage custom scopes page', async function (assert) {
@@ -640,7 +640,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.SAVE_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
});
test('user can search for a specific org scope by id on manage custom scopes page', async function (assert) {
@@ -706,7 +706,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.HREF(urls.roleScopes));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
await click(selectors.MANAGE_DROPDOWN_ROLES);
await click(selectors.MANAGE_DROPDOWN_ROLES_SCOPES);
@@ -736,7 +736,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.SAVE_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 1 });
});
test('user can cancel custom scopes to add on manage org projects page', async function (assert) {
@@ -745,7 +745,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.HREF(urls.roleScopes));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
await click(selectors.MANAGE_DROPDOWN_ROLES);
await click(selectors.MANAGE_DROPDOWN_ROLES_SCOPES);
@@ -773,7 +773,7 @@ module('Acceptance | roles | global-scope', function (hooks) {
await click(commonSelectors.CANCEL_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
});
test('shows error message on custom scope save on manage org projects page', async function (assert) {
@@ -91,7 +91,7 @@ module('Acceptance | roles | org-scope', function (hooks) {
assert.strictEqual(currentURL(), urls.roleScopes);
assert
.dom(commonSelectors.TABLE_ROW)
.dom(commonSelectors.TABLE_ROWS)
.exists({ count: instances.role.grant_scope_ids.length });
});
@@ -230,7 +230,7 @@ module('Acceptance | roles | org-scope', function (hooks) {
await click(commonSelectors.HREF(urls.roleScopes));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
await click(selectors.MANAGE_DROPDOWN_ROLES);
await click(selectors.MANAGE_DROPDOWN_ROLES_SCOPES);
@@ -245,7 +245,7 @@ module('Acceptance | roles | org-scope', function (hooks) {
await click(commonSelectors.SAVE_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 1 });
});
test('user can cancel scope keywords to add on manage scopes page', async function (assert) {
@@ -254,7 +254,7 @@ module('Acceptance | roles | org-scope', function (hooks) {
await click(commonSelectors.HREF(urls.roleScopes));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
await click(selectors.MANAGE_DROPDOWN_ROLES);
await click(selectors.MANAGE_DROPDOWN_ROLES_SCOPES);
@@ -268,7 +268,7 @@ module('Acceptance | roles | org-scope', function (hooks) {
await click(commonSelectors.CANCEL_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
});
test('shows error message on scope save on manage scopes page', async function (assert) {
@@ -335,7 +335,7 @@ module('Acceptance | roles | org-scope', function (hooks) {
await click(commonSelectors.HREF(urls.roleScopes));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
await click(selectors.MANAGE_DROPDOWN_ROLES);
await click(selectors.MANAGE_DROPDOWN_ROLES_SCOPES);
@@ -360,7 +360,7 @@ module('Acceptance | roles | org-scope', function (hooks) {
await click(commonSelectors.SAVE_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 1 });
});
test('user can cancel custom scopes to add on manage org projects page', async function (assert) {
@@ -369,7 +369,7 @@ module('Acceptance | roles | org-scope', function (hooks) {
await click(commonSelectors.HREF(urls.roleScopes));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
await click(selectors.MANAGE_DROPDOWN_ROLES);
await click(selectors.MANAGE_DROPDOWN_ROLES_SCOPES);
@@ -393,7 +393,7 @@ module('Acceptance | roles | org-scope', function (hooks) {
await click(commonSelectors.CANCEL_BTN);
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
});
test('shows error message on custom scope save on manage org projects page', async function (assert) {
@@ -69,13 +69,13 @@ module('Acceptance | roles | principals', function (hooks) {
test('principal can be removed from a role', async function (assert) {
await visit(urls.rolePrincipals);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: principalsCount });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: principalsCount });
await click(commonSelectors.TABLE_FIRST_ROW_ACTION_DROPDOWN);
await click(commonSelectors.TABLE_FIRST_ROW_ACTION_DROPDOWN_ITEM_BTN);
assert
.dom(commonSelectors.TABLE_ROW)
.dom(commonSelectors.TABLE_ROWS)
.exists({ count: principalsCount - 1 });
});
@@ -105,7 +105,7 @@ module('Acceptance | roles | principals', function (hooks) {
});
await visit(urls.rolePrincipals);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: principalsCount });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: principalsCount });
await click(commonSelectors.TABLE_FIRST_ROW_ACTION_DROPDOWN);
await click(commonSelectors.TABLE_FIRST_ROW_ACTION_DROPDOWN_ITEM_BTN);
@@ -131,7 +131,7 @@ module('Acceptance | roles | principals', function (hooks) {
instances.role.update({ userIds: [], groupIds: [], managedGroupIds: [] });
await visit(urls.rolePrincipals);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
await click(selectors.MANAGE_DROPDOWN_ROLES);
await click(selectors.MANAGE_DROPDOWN_ADD_PRINCIPALS);
@@ -145,20 +145,20 @@ module('Acceptance | roles | principals', function (hooks) {
await click(commonSelectors.SAVE_BTN);
await visit(urls.rolePrincipals);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 1 });
});
test('select and cancel principals to add', async function (assert) {
await visit(urls.rolePrincipals);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: principalsCount });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: principalsCount });
// Remove a principal to populate association view
await click(commonSelectors.TABLE_FIRST_ROW_ACTION_DROPDOWN);
await click(commonSelectors.TABLE_FIRST_ROW_ACTION_DROPDOWN_ITEM_BTN);
assert
.dom(commonSelectors.TABLE_ROW)
.dom(commonSelectors.TABLE_ROWS)
.exists({ count: principalsCount - 1 });
await click(selectors.MANAGE_DROPDOWN_ROLES);
@@ -171,7 +171,7 @@ module('Acceptance | roles | principals', function (hooks) {
await visit(urls.rolePrincipals);
assert
.dom(commonSelectors.TABLE_ROW)
.dom(commonSelectors.TABLE_ROWS)
.exists({ count: principalsCount - 1 });
});
@@ -61,7 +61,7 @@ module('Acceptance | roles | project-scope', function (hooks) {
assert.strictEqual(currentURL(), urls.roleScopes);
assert.dom(selectors.GRANT_SCOPE_ROW(GRANT_SCOPE_THIS)).isVisible();
assert
.dom(commonSelectors.TABLE_ROW)
.dom(commonSelectors.TABLE_ROWS)
.exists({ count: instances.role.grant_scope_ids.length });
});
@@ -180,13 +180,13 @@ module('Acceptance | session recordings | list', function (hooks) {
await click(commonSelectors.HREF(urls.sessionRecordings));
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 2 });
assert.dom(commonSelectors.TABLE_ROWS).isVisible({ count: 2 });
await click(commonSelectors.FILTER_DROPDOWN('user'));
await click(commonSelectors.FILTER_DROPDOWN_ITEM(instances.user.id));
await click(commonSelectors.FILTER_DROPDOWN_ITEM_APPLY_BTN('user'));
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).isVisible({ count: 1 });
});
test('user can filter session recordings by scope', async function (assert) {
@@ -194,13 +194,13 @@ module('Acceptance | session recordings | list', function (hooks) {
await click(commonSelectors.HREF(urls.sessionRecordings));
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 2 });
assert.dom(commonSelectors.TABLE_ROWS).isVisible({ count: 2 });
await click(commonSelectors.FILTER_DROPDOWN('target'));
await click(commonSelectors.FILTER_DROPDOWN_ITEM(instances.target.id));
await click(commonSelectors.FILTER_DROPDOWN_ITEM_APPLY_BTN('target'));
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).isVisible({ count: 1 });
});
test('user can filter session recordings by target', async function (assert) {
@@ -208,7 +208,7 @@ module('Acceptance | session recordings | list', function (hooks) {
await click(commonSelectors.HREF(urls.sessionRecordings));
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 2 });
assert.dom(commonSelectors.TABLE_ROWS).isVisible({ count: 2 });
await click(commonSelectors.FILTER_DROPDOWN('scope'));
await click(
@@ -216,7 +216,7 @@ module('Acceptance | session recordings | list', function (hooks) {
);
await click(commonSelectors.FILTER_DROPDOWN_ITEM_APPLY_BTN('scope'));
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).isVisible({ count: 1 });
});
test('user can filter session recordings by time', async function (assert) {
@@ -224,11 +224,11 @@ module('Acceptance | session recordings | list', function (hooks) {
await click(commonSelectors.HREF(urls.sessionRecordings));
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 2 });
assert.dom(commonSelectors.TABLE_ROWS).isVisible({ count: 2 });
await click(commonSelectors.FILTER_DROPDOWN('time'));
await click(selectors.LAST_3_DAYS_OPTION);
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).isVisible({ count: 1 });
});
});
@@ -106,7 +106,7 @@ module('Acceptance | sessions | list', function (hooks) {
assert.strictEqual(currentURL(), urls.sessions);
assert
.dom(commonSelectors.TABLE_ROW)
.dom(commonSelectors.TABLE_ROWS)
.exists({ count: instances.sessions.length });
});
@@ -152,7 +152,7 @@ module('Acceptance | sessions | list', function (hooks) {
await click(commonSelectors.HREF(urls.sessions));
assert
.dom(commonSelectors.TABLE_ROW)
.dom(commonSelectors.TABLE_ROWS)
.exists({ count: instances.sessions.length });
});
@@ -221,7 +221,7 @@ module('Acceptance | sessions | list', function (hooks) {
await click(commonSelectors.FILTER_DROPDOWN_ITEM_APPLY_BTN('user'));
assert.dom(SESSION_ID_SELECTOR(instances.sessions[2].id)).exists();
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 1 });
});
test('users filter is hidden if no users returned or no list permissions', async function (assert) {
@@ -251,7 +251,7 @@ module('Acceptance | sessions | list', function (hooks) {
await click(commonSelectors.FILTER_DROPDOWN_ITEM_APPLY_BTN('target'));
assert.dom(SESSION_ID_SELECTOR(instances.sessions[2].id)).exists();
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 1 });
});
test('targets filter is hidden if no targets returned or no list permissions', async function (assert) {
+112 -1
View File
@@ -10,6 +10,7 @@ import {
fillIn,
waitFor,
currentRouteName,
currentURL,
} from '@ember/test-helpers';
import { setupApplicationTest } from 'admin/tests/helpers';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
@@ -19,12 +20,23 @@ import { TYPE_TARGET_TCP, TYPE_TARGET_SSH } from 'api/models/target';
import { STATUS_SESSION_ACTIVE } from 'api/models/session';
import * as commonSelectors from 'admin/tests/helpers/selectors';
import * as selectors from './selectors';
import { faker } from '@faker-js/faker';
module('Acceptance | targets | list', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
setupIndexedDb(hooks);
const NAME_VALUES_ARRAY = ['Alpha', 'Beta', 'Delta', 'Epsilon', 'Gamma'];
const ID_VALUES_ARRAY = ['i_0001', 'i_0010', 'i_0100', 'i_1000', 'i_10000'];
const CREATED_TIME_VALUES_ARRAY = [
'2020-01-01T00:01:00.000Z',
'2020-01-01T00:00:10.000Z',
'2020-01-01T00:00:01.000Z',
'2020-01-01T00:00:00.100Z',
'2020-01-01T00:00:00.010Z',
];
const instances = {
scopes: {
global: null,
@@ -59,7 +71,7 @@ module('Acceptance | targets | list', function (hooks) {
scope: instances.scopes.project,
});
instances.sshTarget = this.server.create('target', {
id: 'target-1',
id: 'target-0',
type: TYPE_TARGET_SSH,
scope: instances.scopes.project,
});
@@ -76,6 +88,7 @@ module('Acceptance | targets | list', function (hooks) {
const featuresService = this.owner.lookup('service:features');
featuresService.enable('ssh-target');
await authenticateSession({});
});
@@ -253,4 +266,102 @@ module('Acceptance | targets | list', function (hooks) {
assert.strictEqual(currentRouteName(), 'scopes.scope.sessions.index');
assert.dom(selectors.TABLE_SESSIONS_ID(instances.session.id)).isVisible();
});
test('targets table is sorted by `created_time` descending by default', async function (assert) {
this.server.schema.targets.all().destroy();
const createdTimeToNameMapping = {};
CREATED_TIME_VALUES_ARRAY.forEach((value, index) => {
createdTimeToNameMapping[value] = NAME_VALUES_ARRAY[index];
});
faker.helpers.shuffle(CREATED_TIME_VALUES_ARRAY).forEach((value) => {
this.server.create('target', {
name: createdTimeToNameMapping[value],
created_time: value,
scope: instances.scopes.project,
});
});
await visit(urls.targets);
assert
.dom(commonSelectors.TABLE_ROWS)
.isVisible({ count: CREATED_TIME_VALUES_ARRAY.length });
NAME_VALUES_ARRAY.forEach((expected, index) => {
// nth-child index starts at 1
assert.dom(commonSelectors.TABLE_ROW(index + 1)).containsText(expected);
});
});
test.each(
'sorting',
{
'on name': {
attribute: {
key: 'name',
values: NAME_VALUES_ARRAY,
},
expectedAscendingSort: NAME_VALUES_ARRAY,
column: 1,
},
'on type': {
attribute: {
key: 'type',
values: [TYPE_TARGET_SSH, TYPE_TARGET_TCP, TYPE_TARGET_SSH],
},
expectedAscendingSort: ['SSH', 'SSH', 'Generic TCP'],
column: 2,
},
'on id': {
attribute: {
key: 'id',
values: ID_VALUES_ARRAY,
},
expectedAscendingSort: ID_VALUES_ARRAY,
column: 4,
},
},
async function (assert, input) {
this.server.schema.targets.all().destroy();
faker.helpers.shuffle(input.attribute.values).forEach((value) => {
this.server.create('target', {
[input.attribute.key]: value,
scope: instances.scopes.project,
});
});
await visit(urls.targets);
// click the sort button to sort in ascending order for provided column key
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);
});
},
);
});
@@ -72,7 +72,7 @@ module('Acceptance | users | accounts', function (hooks) {
await a11yAudit();
assert.strictEqual(currentURL(), urls.accounts);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: accountsCount });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: accountsCount });
});
test('can remove an account', async function (assert) {
@@ -80,12 +80,12 @@ module('Acceptance | users | accounts', function (hooks) {
await click(commonSelectors.HREF(urls.accounts));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: accountsCount });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: accountsCount });
await click(commonSelectors.TABLE_FIRST_ROW_ACTION_DROPDOWN);
await click(commonSelectors.TABLE_FIRST_ROW_ACTION_DROPDOWN_ITEM_BTN);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: accountsCount - 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: accountsCount - 1 });
});
test('cannot remove an account without proper authorization', async function (assert) {
@@ -158,7 +158,7 @@ module('Acceptance | users | accounts', function (hooks) {
await click(commonSelectors.HREF(urls.accounts));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: accountsCount });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: accountsCount });
await click(commonSelectors.TABLE_FIRST_ROW_ACTION_DROPDOWN);
await click(commonSelectors.TABLE_FIRST_ROW_ACTION_DROPDOWN_ITEM_BTN);
@@ -217,7 +217,7 @@ module('Acceptance | users | accounts', function (hooks) {
await click(selectors.MANAGE_DROPDOWN_USER_ADD_ACCOUNTS);
assert
.dom(commonSelectors.TABLE_ROW)
.dom(commonSelectors.TABLE_ROWS)
.exists({ count: accountsAvailableCount - 1 });
});
@@ -242,7 +242,7 @@ module('Acceptance | users | accounts', function (hooks) {
await click(selectors.MANAGE_DROPDOWN_USER_ADD_ACCOUNTS);
assert
.dom(commonSelectors.TABLE_ROW)
.dom(commonSelectors.TABLE_ROWS)
.exists({ count: accountsAvailableCount });
});
@@ -252,7 +252,7 @@ module('Acceptance | users | accounts', function (hooks) {
await click(commonSelectors.HREF(urls.accounts));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 0 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 0 });
await click(selectors.MANAGE_DROPDOWN_USER);
await click(selectors.MANAGE_DROPDOWN_USER_ADD_ACCOUNTS);
@@ -266,7 +266,7 @@ module('Acceptance | users | accounts', function (hooks) {
await click(commonSelectors.SAVE_BTN);
await visit(urls.accounts);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 1 });
assert.strictEqual(instances.user.accountIds.length, 1);
});
@@ -275,7 +275,7 @@ module('Acceptance | users | accounts', function (hooks) {
await click(commonSelectors.HREF(urls.accounts));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: accountsCount });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: accountsCount });
await click(selectors.MANAGE_DROPDOWN_USER);
await click(selectors.MANAGE_DROPDOWN_USER_ADD_ACCOUNTS);
@@ -286,7 +286,7 @@ module('Acceptance | users | accounts', function (hooks) {
await click(commonSelectors.CANCEL_BTN);
assert.strictEqual(currentURL(), urls.accounts);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: accountsCount });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: accountsCount });
});
test('shows error message on account add', async function (assert) {
@@ -315,7 +315,7 @@ module('Acceptance | users | accounts', function (hooks) {
await visit(urls.user);
await click(commonSelectors.HREF(urls.accounts));
assert.dom(commonSelectors.TABLE_ROW).exists({ count: accountsCount });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: accountsCount });
assert
.dom(
commonSelectors.TABLE_RESOURCE_LINK(
@@ -344,7 +344,7 @@ module('Acceptance | users | accounts', function (hooks) {
await visit(`${urls.users}/${user.id}`);
await click(commonSelectors.HREF(`${urls.users}/${user.id}/accounts`));
assert.dom(commonSelectors.TABLE_ROW).exists({ count });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count });
assert
.dom(
commonSelectors.TABLE_RESOURCE_LINK(
@@ -373,7 +373,7 @@ module('Acceptance | users | accounts', function (hooks) {
await visit(`${urls.users}/${user.id}`);
await click(commonSelectors.HREF(`${urls.users}/${user.id}/accounts`));
assert.dom(commonSelectors.TABLE_ROW).exists({ count });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count });
assert
.dom(
commonSelectors.TABLE_RESOURCE_LINK(
@@ -71,7 +71,7 @@ module('Acceptance | workers | worker | create-tags', function (hooks) {
test('user can save worker tags', async function (assert) {
await visit(urls.tags);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 11 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 11 });
await click(selectors.MANAGE_DROPDOWN_WORKER);
await click(selectors.MANAGE_DROPDOWN_WORKER_CREATE_TAGS);
@@ -80,7 +80,7 @@ module('Acceptance | workers | worker | create-tags', function (hooks) {
await click(selectors.ADD_WORKER_TAG_ACTION);
await click(commonSelectors.SAVE_BTN);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 12 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 12 });
assert.strictEqual(currentURL(), urls.tags);
});
@@ -92,13 +92,13 @@ module('Acceptance | workers | list', function (hooks) {
featuresService.enable('byow');
await visit(urls.workers);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 2 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 2 });
await click(selectors.WORKER_TAGS_FILTER_DROPDOWN);
await click(selectors.WORKER_TAGS_FILTER_DROPDOWN_FIRST_ITEM);
await click(selectors.WORKER_TAGS_FILTER_APPLY_BUTTON);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 1 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 1 });
});
test('Users can open and close tags flyout for a specific worker', async function (assert) {
@@ -56,7 +56,7 @@ module('Acceptance | workers | worker | tags', function (hooks) {
await a11yAudit();
assert.strictEqual(currentURL(), urls.tags);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 11 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 11 });
});
test('config tags display a tooltip for HCP managed tag', async function (assert) {
@@ -85,7 +85,7 @@ module('Acceptance | workers | worker | tags', function (hooks) {
test('users can remove a specific tag', async function (assert) {
await visit(urls.tags);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 11 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 11 });
await click(selectors.TABLE_ROW_API_TAG_ACTION_DROPDOWN);
await click(selectors.TABLE_ROW_API_TAG_ACTION_DROPDOWN_LAST_BUTTON);
@@ -98,20 +98,20 @@ module('Acceptance | workers | worker | tags', function (hooks) {
await click(selectors.MODAL_CONFIRMATION_SAVE_BUTTON);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 10 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 10 });
});
test('user can cancel tag removal', async function (assert) {
await visit(urls.tags);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 11 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 11 });
await click(selectors.TABLE_ROW_API_TAG_ACTION_DROPDOWN);
await click(selectors.TABLE_ROW_API_TAG_ACTION_DROPDOWN_LAST_BUTTON);
await click(selectors.MODAL_CONFIRMATION_CANCEL_BUTTON);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 11 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 11 });
});
test('user cannot remove a tag without proper permission', async function (assert) {
@@ -121,7 +121,7 @@ module('Acceptance | workers | worker | tags', function (hooks) {
);
await visit(urls.tags);
assert.dom(commonSelectors.TABLE_ROW).exists({ count: 11 });
assert.dom(commonSelectors.TABLE_ROWS).exists({ count: 11 });
await click(selectors.TABLE_ROW_API_TAG_ACTION_DROPDOWN);
+10 -1
View File
@@ -15,7 +15,8 @@ export const FIELD_DESCRIPTION = '[name=description]';
export const FIELD_DESCRIPTION_VALUE = 'description';
export const TABLE_RESOURCE_LINK = (url) => `tbody [href="${url}"]`;
export const TABLE_ROW = 'tbody tr';
export const TABLE_ROWS = 'tbody tr';
export const TABLE_ROW = (row) => `tbody tr:nth-child(${row})`;
export const TABLE_ROW_CHECKBOX = 'tbody tr input[type="checkbox"]';
export const TABLE_FIRST_ROW_ACTION_DROPDOWN =
'tbody tr:first-child td:last-child button';
@@ -66,3 +67,11 @@ export const FILTER_DROPDOWN_ITEM_APPLY_BTN = (filterName) =>
export const PAGINATION = '[data-test-pagination]';
export const LINK_LIST_ITEM_TEXT = '.link-list-item__text';
export const FORM = 'main form';
// Sorting selectors
export const TABLE_SORT_BTN = (column) =>
`thead tr th:nth-child(${column}) button`;
export const TABLE_SORT_BTN_ARROW_UP = (column) =>
`thead tr th:nth-child(${column}) button .hds-icon-arrow-up`;
export const TABLE_SORT_BTN_ARROW_DOWN = (column) =>
`thead tr th:nth-child(${column}) button .hds-icon-arrow-down`;