mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 10:25:42 +03:00
[ui] Latest Deployment component removed (#17192)
* Latest Deployment component removed * Integration test selector update
This commit is contained in:
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import Component from '@ember/component';
|
||||
import { task } from 'ember-concurrency';
|
||||
import messageFromAdapterError from 'nomad-ui/utils/message-from-adapter-error';
|
||||
import { tagName } from '@ember-decorators/component';
|
||||
import classic from 'ember-classic-decorator';
|
||||
|
||||
@classic
|
||||
@tagName('')
|
||||
export default class LatestDeployment extends Component {
|
||||
job = null;
|
||||
|
||||
handleError() {}
|
||||
|
||||
isShowingDeploymentDetails = false;
|
||||
|
||||
@task(function* () {
|
||||
try {
|
||||
yield this.get('job.latestDeployment.content').promote();
|
||||
} catch (err) {
|
||||
this.handleError({
|
||||
title: 'Could Not Promote Deployment',
|
||||
description: messageFromAdapterError(err, 'promote deployments'),
|
||||
});
|
||||
}
|
||||
})
|
||||
promote;
|
||||
|
||||
@task(function* () {
|
||||
try {
|
||||
yield this.get('job.latestDeployment.content').fail();
|
||||
} catch (err) {
|
||||
this.handleError({
|
||||
title: 'Could Not Fail Deployment',
|
||||
description: messageFromAdapterError(err, 'fail deployments'),
|
||||
});
|
||||
}
|
||||
})
|
||||
fail;
|
||||
}
|
||||
@@ -20,9 +20,6 @@
|
||||
StatsBox=(component "job-page/parts/stats-box" job=@job)
|
||||
Summary=(component "job-page/parts/summary" job=@job)
|
||||
PlacementFailures=(component "job-page/parts/placement-failures" job=@job)
|
||||
LatestDeployment=(component
|
||||
"job-page/parts/latest-deployment" job=@job handleError=this.handleError
|
||||
)
|
||||
TaskGroups=(component "job-page/parts/task-groups" job=@job)
|
||||
RecentAllocations=(component "job-page/parts/recent-allocations" job=@job activeTask=@activeTask setActiveTaskQueryParam=@setActiveTaskQueryParam)
|
||||
Meta=(component "job-page/parts/meta" job=@job)
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
~}}
|
||||
|
||||
{{#if this.job.latestDeployment}}
|
||||
<div class="boxed-section {{if this.job.latestDeployment.isRunning "is-info"}}" data-test-active-deployment>
|
||||
<div class="boxed-section-head">
|
||||
<div class="boxed-section-row">
|
||||
{{if this.job.latestDeployment.isRunning "Active" "Latest"}} Deployment
|
||||
<span class="badge is-white {{if this.job.latestDeployment.isRunning "is-subtle"}} bumper-left" data-test-active-deployment-stat="id">{{this.job.latestDeployment.shortId}}</span>
|
||||
{{#if this.job.latestDeployment.version.submitTime}}
|
||||
<span class="pull-right submit-time tooltip" data-test-active-deployment-stat="submit-time" aria-label="{{format-ts this.job.latestDeployment.version.submitTime}}">
|
||||
{{moment-from-now this.job.latestDeployment.version.submitTime}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="boxed-section-row">
|
||||
<span class="tag is-outlined {{this.job.latestDeployment.statusClass}}" data-test-deployment-status="{{this.job.latestDeployment.statusClass}}">
|
||||
{{this.job.latestDeployment.status}}
|
||||
</span>
|
||||
<div class="pull-right">
|
||||
{{#if this.job.latestDeployment.isRunning}}
|
||||
<TwoStepButton
|
||||
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}}
|
||||
{{#if this.job.latestDeployment.requiresPromotion}}
|
||||
<button
|
||||
data-test-promote-canary
|
||||
type="button"
|
||||
class="button is-warning is-small {{if this.promote.isRunning "is-loading"}}"
|
||||
disabled={{this.promote.isRunning}}
|
||||
onclick={{perform this.promote}}>Promote Canary</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxed-section-body with-foot">
|
||||
<JobDeploymentDetails @deployment={{this.job.latestDeployment}} as |d|>
|
||||
<d.metrics />
|
||||
{{#if this.isShowingDeploymentDetails}}
|
||||
<d.taskGroups />
|
||||
<d.allocations />
|
||||
{{/if}}
|
||||
</JobDeploymentDetails>
|
||||
</div>
|
||||
<div class="boxed-section-foot">
|
||||
<a class="pull-right" {{action (toggle "isShowingDeploymentDetails" this)}} href="#" data-test-deployment-toggle-details>
|
||||
{{if this.isShowingDeploymentDetails "Hide" "Show"}} deployment task groups and allocations
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -11,8 +11,6 @@
|
||||
<jobPage.ui.DasRecommendations />
|
||||
<jobPage.ui.StatusPanel @statusMode={{@statusMode}} @setStatusMode={{@setStatusMode}} />
|
||||
<jobPage.ui.PlacementFailures />
|
||||
{{!-- latestDeployment only included here for visual comparison during build-out --}}
|
||||
<jobPage.ui.LatestDeployment />
|
||||
<jobPage.ui.TaskGroups @sortProperty={{@sortProperty}} @sortDescending={{@sortDescending}} />
|
||||
<jobPage.ui.RecentAllocations @activeTask={{@activeTask}} @setActiveTaskQueryParam={{@setActiveTaskQueryParam}} />
|
||||
<jobPage.ui.Meta />
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { click, find, render } from '@ember/test-helpers';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import moment from 'moment';
|
||||
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
|
||||
import { initialize as fragmentSerializerInitializer } from 'nomad-ui/initializers/fragment-serializer';
|
||||
import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit';
|
||||
|
||||
module(
|
||||
'Integration | Component | job-page/parts/latest-deployment',
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
fragmentSerializerInitializer(this.owner);
|
||||
window.localStorage.clear();
|
||||
this.store = this.owner.lookup('service:store');
|
||||
this.server = startMirage();
|
||||
this.server.create('namespace');
|
||||
});
|
||||
|
||||
hooks.afterEach(function () {
|
||||
this.server.shutdown();
|
||||
window.localStorage.clear();
|
||||
});
|
||||
|
||||
test('there is no latest deployment section when the job has no deployments', async function (assert) {
|
||||
this.server.create('job', {
|
||||
type: 'service',
|
||||
noDeployments: true,
|
||||
createAllocations: false,
|
||||
});
|
||||
|
||||
await this.store.findAll('job');
|
||||
|
||||
this.set('job', this.store.peekAll('job').get('firstObject'));
|
||||
await render(hbs`
|
||||
<JobPage::Parts::LatestDeployment @job={{job}} />)
|
||||
`);
|
||||
|
||||
assert.notOk(
|
||||
find('[data-test-active-deployment]'),
|
||||
'No active deployment'
|
||||
);
|
||||
});
|
||||
|
||||
test('the latest deployment section shows up for the currently running deployment', async function (assert) {
|
||||
assert.expect(11);
|
||||
|
||||
this.server.create('job', {
|
||||
type: 'service',
|
||||
createAllocations: false,
|
||||
activeDeployment: true,
|
||||
});
|
||||
|
||||
await this.store.findAll('job');
|
||||
|
||||
this.set('job', this.store.peekAll('job').get('firstObject'));
|
||||
await render(hbs`
|
||||
<JobPage::Parts::LatestDeployment @job={{job}} />
|
||||
`);
|
||||
|
||||
const deployment = await this.get('job.latestDeployment');
|
||||
const version = await deployment.get('version');
|
||||
|
||||
assert.ok(find('[data-test-active-deployment]'), 'Active deployment');
|
||||
assert.ok(
|
||||
find('[data-test-active-deployment]').classList.contains('is-info'),
|
||||
'Running deployment gets the is-info class'
|
||||
);
|
||||
assert.equal(
|
||||
find('[data-test-active-deployment-stat="id"]').textContent.trim(),
|
||||
deployment.get('shortId'),
|
||||
'The active deployment is the most recent running deployment'
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
find(
|
||||
'[data-test-active-deployment-stat="submit-time"]'
|
||||
).textContent.trim(),
|
||||
moment(version.get('submitTime')).fromNow(),
|
||||
'Time since the job was submitted is in the active deployment header'
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
find('[data-test-deployment-metric="canaries"]').textContent.trim(),
|
||||
`${deployment.get('placedCanaries')} / ${deployment.get(
|
||||
'desiredCanaries'
|
||||
)}`,
|
||||
'Canaries, both places and desired, are in the metrics'
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
find('[data-test-deployment-metric="placed"]').textContent.trim(),
|
||||
deployment.get('placedAllocs'),
|
||||
'Placed allocs aggregates across task groups'
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
find('[data-test-deployment-metric="desired"]').textContent.trim(),
|
||||
deployment.get('desiredTotal'),
|
||||
'Desired allocs aggregates across task groups'
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
find('[data-test-deployment-metric="healthy"]').textContent.trim(),
|
||||
deployment.get('healthyAllocs'),
|
||||
'Healthy allocs aggregates across task groups'
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
find('[data-test-deployment-metric="unhealthy"]').textContent.trim(),
|
||||
deployment.get('unhealthyAllocs'),
|
||||
'Unhealthy allocs aggregates across task groups'
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
find('[data-test-deployment-notification]').textContent.trim(),
|
||||
deployment.get('statusDescription'),
|
||||
'Status description is in the metrics block'
|
||||
);
|
||||
|
||||
await componentA11yAudit(this.element, assert);
|
||||
});
|
||||
|
||||
test('when there is no running deployment, the latest deployment section shows up for the last deployment', async function (assert) {
|
||||
this.server.create('job', {
|
||||
type: 'service',
|
||||
createAllocations: false,
|
||||
noActiveDeployment: true,
|
||||
});
|
||||
|
||||
await this.store.findAll('job');
|
||||
|
||||
this.set('job', this.store.peekAll('job').get('firstObject'));
|
||||
await render(hbs`
|
||||
<JobPage::Parts::LatestDeployment @job={{job}} />
|
||||
`);
|
||||
|
||||
assert.ok(find('[data-test-active-deployment]'), 'Active deployment');
|
||||
assert.notOk(
|
||||
find('[data-test-active-deployment]').classList.contains('is-info'),
|
||||
'Non-running deployment does not get the is-info class'
|
||||
);
|
||||
});
|
||||
|
||||
test('the latest deployment section can be expanded to show task groups and allocations', async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
this.server.create('node');
|
||||
this.server.create('job', { type: 'service', activeDeployment: true });
|
||||
|
||||
await this.store.findAll('job');
|
||||
|
||||
this.set('job', this.store.peekAll('job').get('firstObject'));
|
||||
await render(hbs`
|
||||
<JobPage::Parts::LatestDeployment @job={{job}} />
|
||||
`);
|
||||
|
||||
assert.notOk(
|
||||
find('[data-test-deployment-task-groups]'),
|
||||
'Task groups not found'
|
||||
);
|
||||
assert.notOk(
|
||||
find('[data-test-deployment-allocations]'),
|
||||
'Allocations not found'
|
||||
);
|
||||
|
||||
await click('[data-test-deployment-toggle-details]');
|
||||
|
||||
assert.ok(
|
||||
find('[data-test-deployment-task-groups]'),
|
||||
'Task groups found'
|
||||
);
|
||||
assert.ok(
|
||||
find('[data-test-deployment-allocations]'),
|
||||
'Allocations found'
|
||||
);
|
||||
|
||||
await componentA11yAudit(this.element, assert);
|
||||
});
|
||||
|
||||
test('each task group in the expanded task group section shows task group details', async function (assert) {
|
||||
this.server.create('node');
|
||||
this.server.create('job', { type: 'service', activeDeployment: true });
|
||||
|
||||
await this.store.findAll('job');
|
||||
|
||||
const job = this.store.peekAll('job').get('firstObject');
|
||||
|
||||
this.set('job', job);
|
||||
await render(hbs`
|
||||
<JobPage::Parts::LatestDeployment @job={{job}} />
|
||||
`);
|
||||
|
||||
await click('[data-test-deployment-toggle-details]');
|
||||
|
||||
const task = job.get('runningDeployment.taskGroupSummaries.firstObject');
|
||||
const findForTaskGroup = (selector) =>
|
||||
find(`[data-test-deployment-task-group-${selector}]`);
|
||||
assert.equal(
|
||||
findForTaskGroup('name').textContent.trim(),
|
||||
task.get('name')
|
||||
);
|
||||
assert.equal(
|
||||
findForTaskGroup('progress-deadline').textContent.trim(),
|
||||
moment(task.get('requireProgressBy')).format("MMM DD, 'YY HH:mm:ss ZZ")
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -303,8 +303,8 @@ module('Integration | Component | job-page/service', function (hooks) {
|
||||
this.setProperties(commonProperties(job));
|
||||
await render(commonTemplate);
|
||||
|
||||
await click('[data-test-active-deployment] [data-test-idle-button]');
|
||||
await click('[data-test-active-deployment] [data-test-confirm-button]');
|
||||
await click('.active-deployment [data-test-idle-button]');
|
||||
await click('.active-deployment [data-test-confirm-button]');
|
||||
|
||||
const requests = this.server.pretender.handledRequests;
|
||||
|
||||
@@ -331,8 +331,8 @@ module('Integration | Component | job-page/service', function (hooks) {
|
||||
this.setProperties(commonProperties(job));
|
||||
await render(commonTemplate);
|
||||
|
||||
await click('[data-test-active-deployment] [data-test-idle-button]');
|
||||
await click('[data-test-active-deployment] [data-test-confirm-button]');
|
||||
await click('.active-deployment [data-test-idle-button]');
|
||||
await click('.active-deployment [data-test-confirm-button]');
|
||||
|
||||
assert.equal(
|
||||
find('[data-test-job-error-title]').textContent,
|
||||
|
||||
Reference in New Issue
Block a user