From c9c4a2b6a0a8f4a43ee033fb3175e47bbaa4595b Mon Sep 17 00:00:00 2001 From: Chad Woolley Date: Wed, 12 Jun 2024 19:13:11 -0700 Subject: [PATCH 1/3] Display 'Hours remaining until termination' for workspace list - See: https://gitlab.com/gitlab-org/gitlab/-/issues/467319 --- .../workspaces_list/workspaces_table.vue | 59 +++++++++++++------ .../fragments/workspace_item.fragment.graphql | 1 + .../workspaces_list/workspaces_table_spec.js | 22 ++++--- .../frontend/workspaces/mock_data/index.js | 4 ++ locale/gitlab.pot | 3 + 5 files changed, 64 insertions(+), 25 deletions(-) diff --git a/ee/app/assets/javascripts/workspaces/common/components/workspaces_list/workspaces_table.vue b/ee/app/assets/javascripts/workspaces/common/components/workspaces_list/workspaces_table.vue index 091d3ce8e8e42f..f4497c836e23c7 100644 --- a/ee/app/assets/javascripts/workspaces/common/components/workspaces_list/workspaces_table.vue +++ b/ee/app/assets/javascripts/workspaces/common/components/workspaces_list/workspaces_table.vue @@ -7,29 +7,13 @@ import WorkspaceStateIndicator from '../workspace_state_indicator.vue'; import UpdateWorkspaceMutation from '../update_workspace_mutation.vue'; import WorkspaceActions from '../workspace_actions.vue'; -const isTerminated = (w) => w.actualState === WORKSPACE_STATES.terminated; - -// Moves terminated workspaces to the end of the list -const sortWorkspacesByTerminatedState = (workspaceA, workspaceB) => { - const isWorkspaceATerminated = isTerminated(workspaceA); - const isWorkspaceBTerminated = isTerminated(workspaceB); - - if (isWorkspaceATerminated === isWorkspaceBTerminated) { - return 0; // Preserve default order when neither workspace is terminated, or both workspaces are terminated. - } - if (isWorkspaceATerminated) { - return 1; // Place workspaceA after workspaceB since it is terminated. - } - - return -1; // Place workspaceA before workspaceB since it is not terminated. -}; - export const i18n = { tableColumnHeaders: { name: __('Name'), devfile: __('Devfile'), preview: __('Preview'), created: __('Created'), + hoursRemainingUntilTermination: __('Hours remaining until termination'), }, }; @@ -53,7 +37,10 @@ export default { }, computed: { sortedWorkspaces() { - return [...this.workspaces].sort(sortWorkspacesByTerminatedState); + return [...this.workspaces].sort(this.sortWorkspacesByTerminatedState); + }, + currentTime() { + return new Date(); }, }, methods: { @@ -63,6 +50,28 @@ export default { } return sprintf(__(`%{path} on %{ref}`), { ref, path }); }, + hoursRemainingUntilTermination(workspace) { + const createdAt = new Date(workspace.createdAt); + const hoursSinceCreation = Math.floor((this.currentTime - createdAt) / (1000 * 60 * 60)); + return workspace.maxHoursBeforeTermination - hoursSinceCreation; + }, + // Moves terminated workspaces to the end of the list + sortWorkspacesByTerminatedState(workspaceA, workspaceB) { + const isWorkspaceATerminated = this.isTerminated(workspaceA); + const isWorkspaceBTerminated = this.isTerminated(workspaceB); + + if (isWorkspaceATerminated === isWorkspaceBTerminated) { + return 0; // Preserve default order when neither workspace is terminated, or both workspaces are terminated. + } + if (isWorkspaceATerminated) { + return 1; // Place workspaceA after workspaceB since it is terminated. + } + + return -1; // Place workspaceA before workspaceB since it is not terminated. + }, + isTerminated(workspace) { + return workspace.actualState === WORKSPACE_STATES.terminated; + }, }, fields: [ { @@ -87,6 +96,11 @@ export default { label: i18n.tableColumnHeaders.created, thClass: 'gl-w-3/20', }, + { + key: 'hoursRemainingUntilTermination', + label: i18n.tableColumnHeaders.hoursRemainingUntilTermination, + thClass: 'gl-w-3/20', + }, { key: 'devfile', label: i18n.tableColumnHeaders.devfile, @@ -134,6 +148,15 @@ export default { :time="item.createdAt" /> +