[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
This commit is contained in:
Phil Renaud
2024-11-07 13:57:58 -05:00
committed by GitHub
parent a0ff07393b
commit 3d9003879e
7 changed files with 96 additions and 58 deletions

3
.changelog/24133.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:improvement
ui: Indicates prestart/poststart tasks by running/failed/pending status
```

View File

@@ -11,6 +11,48 @@ import classic from 'ember-classic-decorator';
@classic @classic
@tagName('') @tagName('')
export default class LifecycleChartRow extends Component { 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') @computed('taskState.state')
get activeClass() { get activeClass() {
if (this.taskState && this.taskState.state === 'running') { if (this.taskState && this.taskState.state === 'running') {

View File

@@ -84,50 +84,33 @@
.lifecycle-chart-row { .lifecycle-chart-row {
position: relative; position: relative;
padding: 0.25rem 0.5rem;
.task { $pending-mid: rgba(255, 255, 255, 0.5);
margin: 0.55em 0.9em; .hds-alert {
padding: 0.3em 0.55em; padding: 4px 8px;
border: 1px solid $grey-blue;
border-radius: $radius;
background: white;
.name { &.pending {
font-weight: $weight-semibold; position: relative;
overflow: hidden;
border-style: dashed;
a { &:before {
color: inherit; content: '';
text-decoration: none; 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;
} }
} }
&: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;
}
}
}
&.is-finished {
.task {
color: $ui-gray-400;
}
} }
&.main { &.main {
@@ -159,9 +142,5 @@
&.poststop { &.poststop {
margin-left: 75%; margin-left: 75%;
} }
&:last-child .task {
margin-bottom: 0.9em;
}
} }
} }

View File

@@ -3,19 +3,23 @@
SPDX-License-Identifier: BUSL-1.1 SPDX-License-Identifier: BUSL-1.1
~}} ~}}
<div <div class="lifecycle-chart-row {{this.task.lifecycleName}} {{this.activeClass}} {{this.finishedClass}}" data-test-lifecycle-task>
class="lifecycle-chart-row {{this.task.lifecycleName}} {{this.activeClass}} {{this.finishedClass}}" <Hds::Alert
data-test-lifecycle-task> @type="inline"
<div class="task"> @color={{this.taskColor}}
<div class="name" data-test-name> class="{{if (eq this.taskState.state "pending") "pending"}}"
{{#if this.taskState}} @icon={{this.taskIcon}} as |A|>
<LinkTo @route="allocations.allocation.task" @models={{array this.taskState.allocation this.taskState}}> <A.Title class="name" data-test-name>
{{this.task.name}} {{#if this.taskState}}
</LinkTo> <LinkTo @route="allocations.allocation.task" @models={{array this.taskState.allocation this.taskState}}>
{{else}}
{{this.task.name}} {{this.task.name}}
{{/if}} </LinkTo>
</div> {{else}}
{{this.task.name}}
{{/if}}
</A.Title>
<A.Description>
<div class="lifecycle" data-test-lifecycle>{{capitalize this.lifecycleLabel}} Task</div> <div class="lifecycle" data-test-lifecycle>{{capitalize this.lifecycleLabel}} Task</div>
</div> </A.Description>
</Hds::Alert>
</div> </div>

View File

@@ -360,4 +360,4 @@
</div> </div>
</div> </div>
{{/if}} {{/if}}
</section> </section>

View File

@@ -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) { test('it reflects phase and task states when states are passed in', async function (assert) {
assert.expect(24); assert.expect(26);
this.set( this.set(
'taskStates', 'taskStates',
@@ -152,8 +152,12 @@ module('Integration | Component | lifecycle-chart', function (hooks) {
this.set('taskStates.4.finishedAt', new Date()); this.set('taskStates.4.finishedAt', new Date());
this.set('taskStates.4.state', 'dead'); this.set('taskStates.4.state', 'dead');
this.set('taskStates.4.failed', true);
this.set('taskStates.0.state', 'pending');
await settled(); 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); assert.ok(Chart.tasks[5].isFinished);
}); });

View File

@@ -23,6 +23,12 @@ export default {
isActive: hasClass('is-active'), isActive: hasClass('is-active'),
isFinished: hasClass('is-finished'), isFinished: hasClass('is-finished'),
child: {
scope: '.hds-alert',
failed: hasClass('hds-alert--color-critical'),
pending: hasClass('pending'),
},
isMain: hasClass('main'), isMain: hasClass('main'),
isPrestartEphemeral: hasClass('prestart-ephemeral'), isPrestartEphemeral: hasClass('prestart-ephemeral'),
isPrestartSidecar: hasClass('prestart-sidecar'), isPrestartSidecar: hasClass('prestart-sidecar'),