From 3d9003879e764d86f5c001719a75a8b8a1955486 Mon Sep 17 00:00:00 2001 From: Phil Renaud Date: Thu, 7 Nov 2024 13:57:58 -0500 Subject: [PATCH] [ui] Update the Task Lifecycle Status chart (#24133) * Updates the Task Lifecycle Status chart to show which pre/poststart task may have failed * Default colour to prevent HDS error * De-duplicated data-test attr and added is-active and is-finished test classes * Failed and Pending state tests --- .changelog/24133.txt | 3 + ui/app/components/lifecycle-chart-row.js | 42 +++++++++++ ui/app/styles/components/lifecycle-chart.scss | 71 +++++++------------ .../components/lifecycle-chart-row.hbs | 30 ++++---- ui/app/templates/jobs/job/task-group.hbs | 2 +- .../components/lifecycle-chart-test.js | 6 +- ui/tests/pages/components/lifecycle-chart.js | 6 ++ 7 files changed, 99 insertions(+), 61 deletions(-) create mode 100644 .changelog/24133.txt diff --git a/.changelog/24133.txt b/.changelog/24133.txt new file mode 100644 index 00000000000..cf3ab07f80c --- /dev/null +++ b/.changelog/24133.txt @@ -0,0 +1,3 @@ +```release-note:improvement +ui: Indicates prestart/poststart tasks by running/failed/pending status +``` diff --git a/ui/app/components/lifecycle-chart-row.js b/ui/app/components/lifecycle-chart-row.js index 81285c0a14a..71b367e4492 100644 --- a/ui/app/components/lifecycle-chart-row.js +++ b/ui/app/components/lifecycle-chart-row.js @@ -11,6 +11,48 @@ import classic from 'ember-classic-decorator'; @classic @tagName('') export default class LifecycleChartRow extends Component { + @computed('taskState.{failed,state}') + get taskColor() { + let color = 'neutral'; + if (this.taskState?.state === 'running') { + color = 'success'; + } + if (this.taskState?.state === 'pending') { + color = 'neutral'; + } + if (this.taskState?.state === 'dead') { + if (this.taskState?.failed) { + color = 'critical'; + } else { + color = 'neutral'; + } + } + return color; + } + + get taskIcon() { + let icon; + if (this.taskState?.state === 'running') { + icon = 'running'; + } + if (this.taskState?.state === 'pending') { + icon = 'test'; + } + if (this.taskState?.state === 'dead') { + if (this.taskState?.failed) { + icon = 'alert-circle'; + } else { + if (this.taskState?.startedAt) { + icon = 'check-circle'; + } else { + icon = 'minus-circle'; + } + } + } + + return icon; + } + @computed('taskState.state') get activeClass() { if (this.taskState && this.taskState.state === 'running') { diff --git a/ui/app/styles/components/lifecycle-chart.scss b/ui/app/styles/components/lifecycle-chart.scss index 7ae11cc8d0d..1434658ea0c 100644 --- a/ui/app/styles/components/lifecycle-chart.scss +++ b/ui/app/styles/components/lifecycle-chart.scss @@ -84,52 +84,35 @@ .lifecycle-chart-row { position: relative; - - .task { - margin: 0.55em 0.9em; - padding: 0.3em 0.55em; - border: 1px solid $grey-blue; - border-radius: $radius; - background: white; - - .name { - font-weight: $weight-semibold; - - a { - color: inherit; - text-decoration: none; - } - } - - &:hover { - .name a { - text-decoration: underline; - } - } - - .lifecycle { - font-size: $size-7; - color: $ui-gray-400; - } - } - - &.is-active { - .task { - border-color: $nomad-green; - background: lighten($nomad-green, 50%); - - .lifecycle { - color: $ui-gray-500; + padding: 0.25rem 0.5rem; + + $pending-mid: rgba(255, 255, 255, 0.5); + .hds-alert { + padding: 4px 8px; + + &.pending { + position: relative; + overflow: hidden; + border-style: dashed; + + &:before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient( + -60deg, + transparent, + $pending-mid, + transparent + ); + animation: shimmer 2s ease-in-out infinite; } } } - &.is-finished { - .task { - color: $ui-gray-400; - } - } - &.main { margin-left: 25%; margin-right: 25%; @@ -159,9 +142,5 @@ &.poststop { margin-left: 75%; } - - &:last-child .task { - margin-bottom: 0.9em; - } } } diff --git a/ui/app/templates/components/lifecycle-chart-row.hbs b/ui/app/templates/components/lifecycle-chart-row.hbs index 82eb679f7b8..184f260072f 100644 --- a/ui/app/templates/components/lifecycle-chart-row.hbs +++ b/ui/app/templates/components/lifecycle-chart-row.hbs @@ -3,19 +3,23 @@ SPDX-License-Identifier: BUSL-1.1 ~}} -
-
-
- {{#if this.taskState}} - - {{this.task.name}} - - {{else}} +
+ + + {{#if this.taskState}} + {{this.task.name}} - {{/if}} -
+ + {{else}} + {{this.task.name}} + {{/if}} + +
{{capitalize this.lifecycleLabel}} Task
-
+ +
diff --git a/ui/app/templates/jobs/job/task-group.hbs b/ui/app/templates/jobs/job/task-group.hbs index 1adbbb23781..ebd0eb386ac 100644 --- a/ui/app/templates/jobs/job/task-group.hbs +++ b/ui/app/templates/jobs/job/task-group.hbs @@ -360,4 +360,4 @@
{{/if}} - \ No newline at end of file + diff --git a/ui/tests/integration/components/lifecycle-chart-test.js b/ui/tests/integration/components/lifecycle-chart-test.js index 9318c4c147e..a204628d1cc 100644 --- a/ui/tests/integration/components/lifecycle-chart-test.js +++ b/ui/tests/integration/components/lifecycle-chart-test.js @@ -117,7 +117,7 @@ module('Integration | Component | lifecycle-chart', function (hooks) { }); test('it reflects phase and task states when states are passed in', async function (assert) { - assert.expect(24); + assert.expect(26); this.set( 'taskStates', @@ -152,8 +152,12 @@ module('Integration | Component | lifecycle-chart', function (hooks) { this.set('taskStates.4.finishedAt', new Date()); this.set('taskStates.4.state', 'dead'); + this.set('taskStates.4.failed', true); + this.set('taskStates.0.state', 'pending'); await settled(); + assert.ok(Chart.tasks[3].child.pending, 'Task is pending'); + assert.ok(Chart.tasks[5].child.failed, 'Task is failed'); assert.ok(Chart.tasks[5].isFinished); }); diff --git a/ui/tests/pages/components/lifecycle-chart.js b/ui/tests/pages/components/lifecycle-chart.js index a805d416c71..95e64716920 100644 --- a/ui/tests/pages/components/lifecycle-chart.js +++ b/ui/tests/pages/components/lifecycle-chart.js @@ -23,6 +23,12 @@ export default { isActive: hasClass('is-active'), isFinished: hasClass('is-finished'), + child: { + scope: '.hds-alert', + failed: hasClass('hds-alert--color-critical'), + pending: hasClass('pending'), + }, + isMain: hasClass('main'), isPrestartEphemeral: hasClass('prestart-ephemeral'), isPrestartSidecar: hasClass('prestart-sidecar'),