[ui] General status for steady-state jobs (#17599)

* Degraded vs Healthy etc. status

* Standardize the look of a deploying status panel

* badge styles

* remove job.status from title component in favour of in-panel status

* Remove a redundant check

* re-attrd fail-deployment button considered
This commit is contained in:
Phil Renaud 2023-06-21 11:57:28 -04:00 committed by GitHub
parent 67efb19e94
commit 94507cc7b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 101 additions and 37 deletions

View File

@ -3,34 +3,28 @@
SPDX-License-Identifier: MPL-2.0
~}}
<div class="job-status-panel boxed-section active-deployment is-info" data-test-job-status-panel>
<div class="boxed-section-head">
<div class="job-status-panel boxed-section active-deployment" data-test-job-status-panel>
<div class="boxed-section-head hds-foreground-primary">
<div class="boxed-section-row"
{{did-insert (action this.establishOldAllocBlockIDs)}}
>
Deployment Status
<span class="badge is-white bumper-left" data-test-active-deployment-stat="id">{{@job.latestDeployment.shortId}}</span>
<h2>Status:
<Hds::Badge @text="Deploying {{@job.latestDeployment.shortId}}" @color="highlight" @type="filled" />
</h2>
<div class="pull-right">
{{#if @job.latestDeployment.isRunning}}
<TwoStepButton
<Hds::Button
data-test-fail
{{on "click" (perform this.fail)}}
disabled={{this.fail.isRunning}}
@color="critical"
@text="Fail Deployment"
{{keyboard-shortcut
label="Fail Deployment"
pattern=(array "f" "a" "i" "l")
action=(perform this.fail)
}}
data-test-fail
@classes={{hash
idleButton="is-danger"
confirmationMessage="inherit-color"
confirmButton="is-danger"}}
@idleText="Fail Deployment"
@cancelText="Cancel"
@confirmText="Yes, Fail Deployment"
@confirmationMessage="Are you sure?"
@inlineText={{true}}
@awaitingConfirmation={{this.fail.isRunning}}
@disabled={{this.fail.isRunning}}
@onConfirm={{perform this.fail}} />
/>
{{/if}}
</div>
</div>
@ -56,7 +50,7 @@
<A.Description>Your canary allocations have failed their health checks. Please have a look at the error logs and task events for the allocations in question.</A.Description>
</Hds::Alert>
{{else}}
<Hds::Alert @type="inline" @color="highlight" as |A|>
<Hds::Alert @type="inline" @color="neutral" as |A|>
<A.Title>Checking Canary health</A.Title>
{{#if this.deploymentIsAutoPromoted}}
<A.Description>Your canary allocations are being placed and health-checked. If they pass, they will be automatically promoted and your deployment will continue.</A.Description>

View File

@ -5,7 +5,8 @@
<div class="job-status-panel boxed-section steady-state {{if (eq @statusMode "historical") "historical-state" "current-state"}}" data-test-job-status-panel data-test-status-mode={{@statusMode}}>
<div class="boxed-section-head">
<h2>Status</h2>
<h2>Status: <Hds::Badge @text={{this.currentStatus.label}} @color={{this.currentStatus.state}} @type="filled" /></h2>
<div class="select-mode">
<button type="button"
data-test-status-mode-current

View File

@ -34,11 +34,12 @@ export default class JobStatusPanelSteadyComponent extends Component {
/**
* @typedef {Object} AllocationBlock
* @property {AllocationStatus} [RUNNING]
* @property {AllocationStatus} [PENDING]
* @property {AllocationStatus} [FAILED]
* @property {AllocationStatus} [LOST]
* @property {AllocationStatus} [UNPLACED]
* @property {AllocationStatus} [running]
* @property {AllocationStatus} [pending]
* @property {AllocationStatus} [failed]
* @property {AllocationStatus} [lost]
* @property {AllocationStatus} [unplaced]
* @property {AllocationStatus} [complete]
*/
/**
@ -200,4 +201,57 @@ export default class JobStatusPanelSteadyComponent extends Component {
get latestVersionAllocations() {
return this.job.allocations.filter((a) => !a.isOld);
}
/**
* @typedef {Object} CurrentStatus
* @property {"Healthy"|"Failed"|"Degraded"|"Recovering"|"Complete"|"Running"} label - The current status of the job
* @property {"highlight"|"success"|"warning"|"critical"} state -
*/
/**
* A general assessment for how a job is going, in a non-deployment state
* @returns {CurrentStatus}
*/
get currentStatus() {
// If all allocs are running, the job is Healthy
const totalAllocs = this.totalAllocs;
if (this.job.type === 'batch' || this.job.type === 'sysbatch') {
// If all the allocs are complete, the job is Complete
const completeAllocs = this.allocBlocks.complete?.healthy?.nonCanary;
if (completeAllocs?.length === totalAllocs) {
return { label: 'Complete', state: 'success' };
}
// If any allocations are running the job is "Running"
const healthyAllocs = this.allocBlocks.running?.healthy?.nonCanary;
if (healthyAllocs?.length + completeAllocs?.length === totalAllocs) {
return { label: 'Running', state: 'success' };
}
}
const healthyAllocs = this.allocBlocks.running?.healthy?.nonCanary;
if (healthyAllocs?.length === totalAllocs) {
return { label: 'Healthy', state: 'success' };
}
// If any allocations are pending the job is "Recovering"
const pendingAllocs = this.allocBlocks.pending?.healthy?.nonCanary;
if (pendingAllocs?.length > 0) {
return { label: 'Recovering', state: 'highlight' };
}
// If any allocations are failed, lost, or unplaced in a steady state, the job is "Degraded"
const failedOrLostAllocs = [
...this.allocBlocks.failed?.healthy?.nonCanary,
...this.allocBlocks.lost?.healthy?.nonCanary,
...this.allocBlocks.unplaced?.healthy?.nonCanary,
];
if (failedOrLostAllocs.length === totalAllocs) {
return { label: 'Failed', state: 'critical' };
} else {
return { label: 'Degraded', state: 'warning' };
}
}
}

View File

@ -2,6 +2,7 @@
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
@import '~@hashicorp/design-system-tokens/dist/products/css/helpers/colors.css';
.job-status-panel {
// #region layout
@ -24,6 +25,28 @@
}
}
.boxed-section-head h2 .hds-badge {
margin-left: 5px;
margin-top: -2px;
}
&.active-deployment {
& > .boxed-section-head {
background: var(--token-color-surface-highlight);
h2 .hds-badge {
background-color: var(--token-color-border-highlight);
border-color: var(--token-color-border-highlight);
color: var(--token-color-foreground-highlight-high-contrast);
}
}
& > .boxed-section-head,
& > .boxed-section-body,
& > .boxed-section-foot {
border-color: var(--token-color-border-highlight);
}
}
&.active-deployment .boxed-section-body {
display: grid;
grid-template-areas:
@ -132,7 +155,7 @@
gap: 0.5rem;
grid-template-columns: 1fr 1fr;
padding: 0.25rem 0.5rem;
margin-left: 1rem;
margin-left: auto;
button {
height: auto;

View File

@ -12,7 +12,6 @@
<span>Pack</span>
</span>
{{/if}}
<span class="bumper-left tag {{this.job.statusClass}}" data-test-job-status>{{this.job.status}}</span>
{{yield}}
</div>
<div>

View File

@ -303,8 +303,7 @@ module('Integration | Component | job-page/service', function (hooks) {
this.setProperties(commonProperties(job));
await render(commonTemplate);
await click('.active-deployment [data-test-idle-button]');
await click('.active-deployment [data-test-confirm-button]');
await click('.active-deployment [data-test-fail]');
const requests = this.server.pretender.handledRequests;
@ -331,8 +330,7 @@ module('Integration | Component | job-page/service', function (hooks) {
this.setProperties(commonProperties(job));
await render(commonTemplate);
await click('.active-deployment [data-test-idle-button]');
await click('.active-deployment [data-test-confirm-button]');
await click('.active-deployment [data-test-fail]');
assert.equal(
find('[data-test-job-error-title]').textContent,

View File

@ -48,7 +48,7 @@ module(
});
test('the latest deployment section shows up for the currently running deployment: Ungrouped Allocations (small cluster)', async function (assert) {
assert.expect(25);
assert.expect(24);
this.server.create('node');
@ -116,11 +116,6 @@ module(
'Shows an active deployment if latest status is Running'
);
assert.ok(
find('.active-deployment').classList.contains('is-info'),
'Running deployment gets the is-info class'
);
// Half the shown allocations are running, 1 is pending, 1 is failed; none are canaries or healthy.
// The rest (lost, unknown, etc.) all show up as "Unplaced"
assert