From d6e8e58ca1770dce49be693eb2fc74b618f67bc8 Mon Sep 17 00:00:00 2001 From: Lisbet Alvarez <107949262+lisbet-alvarez@users.noreply.github.com> Date: Thu, 26 Feb 2026 09:28:00 -0800 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Add=20sorting=20to=20ses?= =?UTF-8?q?sions=20started=20column=20(#3174)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 Add sorting to sessions started column * test: 💍 add missing a11y ignores for existing color issue ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-18520 --- .../scopes/scope/projects/sessions/index.js | 24 ++- .../scopes/scope/projects/sessions/index.js | 21 ++- .../scopes/scope/projects/sessions/index.hbs | 162 ++++++++++-------- .../projects/sessions/index-test.js | 42 +++++ .../acceptance/projects/targets/index-test.js | 9 + .../scope/projects/sessions/index-test.js | 12 ++ 6 files changed, 190 insertions(+), 80 deletions(-) diff --git a/ui/desktop/app/controllers/scopes/scope/projects/sessions/index.js b/ui/desktop/app/controllers/scopes/scope/projects/sessions/index.js index 6bf642de9..7ed18522e 100644 --- a/ui/desktop/app/controllers/scopes/scope/projects/sessions/index.js +++ b/ui/desktop/app/controllers/scopes/scope/projects/sessions/index.js @@ -35,6 +35,8 @@ export default class ScopesScopeProjectsSessionsIndexController extends Controll { scopes: { type: 'array' } }, 'page', 'pageSize', + 'sortAttribute', + 'sortDirection', ]; @tracked targets = []; @@ -46,14 +48,20 @@ export default class ScopesScopeProjectsSessionsIndexController extends Controll @tracked scopes = []; @tracked page = 1; @tracked pageSize = 10; + @tracked sortAttribute; + @tracked sortDirection; // =methods /** - * A list of sessions sorted by created time then sorted by availability + * A list of sessions sorted by created time then sorted by availability it no sort + * query params are set, otherwise sorted by the specified attribute and direction. * @type {[SessionModel]} */ get sortedSessions() { + if (this.sortAttribute && this.sortDirection) { + return this.model.sessions; + } return orderBy( this.model.sessions, ['isAvailable', 'created_time'], @@ -104,6 +112,8 @@ export default class ScopesScopeProjectsSessionsIndexController extends Controll }; } + // =actions + /** * Sets the query params to value of selectedItems * to trigger a query and closes the dropdown @@ -116,7 +126,17 @@ export default class ScopesScopeProjectsSessionsIndexController extends Controll this.page = 1; } - // =actions + /** + * Sets 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; + } /** * Cancels the specified session and notifies user of success or error. diff --git a/ui/desktop/app/routes/scopes/scope/projects/sessions/index.js b/ui/desktop/app/routes/scopes/scope/projects/sessions/index.js index 9616e831b..30b96f090 100644 --- a/ui/desktop/app/routes/scopes/scope/projects/sessions/index.js +++ b/ui/desktop/app/routes/scopes/scope/projects/sessions/index.js @@ -42,6 +42,14 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route { pageSize: { refreshModel: true, }, + sortAttribute: { + refreshModel: true, + replace: true, + }, + sortDirection: { + refreshModel: true, + replace: true, + }, }; allSessions; @@ -67,7 +75,15 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route { * all targets and all projects for filtering options for the current user. * @return {Promise<{sessions: [SessionModel], projects: [ScopeModel], allSessions: [SessionModel], associatedTargets: [TargetModel], totalItems: number}>} */ - async model({ targets, status, scopes, page, pageSize }) { + async model({ + targets, + status, + scopes, + page, + pageSize, + sortAttribute, + sortDirection, + }) { const projects = this.modelFor('scopes.scope.projects'); const orgScope = this.modelFor('scopes.scope'); // orgFilter used to narrow down resources to only those under @@ -90,10 +106,11 @@ export default class ScopesScopeProjectsSessionsIndexRoute extends Route { filters.scope_id.push({ equals: scope }); }); + const sort = { attribute: sortAttribute, direction: sortDirection }; const queryOptions = { scope_id: orgScope.id, recursive: true, - query: { filters }, + query: { filters, sort }, page, pageSize, force_refresh: true, diff --git a/ui/desktop/app/templates/scopes/scope/projects/sessions/index.hbs b/ui/desktop/app/templates/scopes/scope/projects/sessions/index.hbs index 7a25cb7f1..ce523bdce 100644 --- a/ui/desktop/app/templates/scopes/scope/projects/sessions/index.hbs +++ b/ui/desktop/app/templates/scopes/scope/projects/sessions/index.hbs @@ -63,90 +63,100 @@ {{/if}} {{#if @model.sessions}} + <:head as |H|> + + {{t 'form.started.label'}} + {{t 'form.session_id.label'}} + {{t 'resources.target.title'}} + {{t 'form.proxy_url.label'}} + {{t 'form.status.label'}} + {{t + 'titles.actions' + }} + + <:body as |B|> - - - - - - - - - {{B.data.target.displayName}} - - {{! - Two if's here because: - 1) Local proxy info is only relevant if the session is - active or pending (aka isAvailable). Once the session - is canceled or in the process thereof, the local proxy - may no longer be used. - 2) The session actually has proxy information associated - with it. It's possible for the user to start sessions - from other devices (or even another tab), in which case we - won't have the local proxy info available here. - }} - - {{#if B.data.isAvailable}} - {{#if B.data.proxy}} - + + + + + {{session.target.displayName}} + + {{! + Two if's here because: + 1) Local proxy info is only relevant if the session is + active or pending (aka isAvailable). Once the session + is canceled or in the process thereof, the local proxy + may no longer be used. + 2) The session actually has proxy information associated + with it. It's possible for the user to start sessions + from other devices (or even another tab), in which case we + won't have the local proxy info available here. + }} + + {{#if session.isAvailable}} + {{#if session.proxy}} + + {{/if}} + {{/if}} + + + + + + {{#if (can 'cancel session' session)}} + {{/if}} - {{/if}} - - - - - - {{#if (can 'cancel session' B.data)}} - - {{/if}} - - + + + {{/each}}