Merge pull request #14879 from hashicorp/mnomitch/job-purge-ui

Adds purge job button to UI
This commit is contained in:
Mike Nomitch 2022-10-14 12:46:20 -07:00 committed by GitHub
commit 91d32bb8df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 113 additions and 0 deletions

View File

@ -29,6 +29,11 @@ export default class JobAdapter extends WatchableNamespaceIDs {
return this.ajax(url, 'DELETE');
}
purge(job) {
const url = this.urlForFindRecord(job.get('id'), 'job') + '?purge=true';
return this.ajax(url, 'DELETE');
}
parse(spec) {
const url = addToPath(this.urlForFindAll('job'), '/parse?namespace=*');
return this.ajax(url, 'POST', {

View File

@ -1,5 +1,6 @@
import Component from '@ember/component';
import { task } from 'ember-concurrency';
import { inject as service } from '@ember/service';
import messageFromAdapterError from 'nomad-ui/utils/message-from-adapter-error';
import { tagName } from '@ember-decorators/component';
import classic from 'ember-classic-decorator';
@ -7,6 +8,8 @@ import classic from 'ember-classic-decorator';
@classic
@tagName('')
export default class Title extends Component {
@service router;
job = null;
title = null;
@ -27,6 +30,27 @@ export default class Title extends Component {
})
stopJob;
@task(function* () {
try {
const job = this.job;
yield job.purge();
this.flashMessages.add({
title: 'Job Purged',
message: `You have purged ${this.job.name}`,
type: 'success',
destroyOnClick: false,
timeout: 5000,
});
this.router.transitionTo('jobs');
} catch (err) {
this.handleError({
title: 'Error purging job',
description: messageFromAdapterError(err, 'purge jobs'),
});
}
})
purgeJob;
@task(function* () {
const job = this.job;
const definition = yield job.fetchRawDefinition();

View File

@ -227,6 +227,10 @@ export default class Job extends Model {
return this.store.adapterFor('job').stop(this);
}
purge() {
return this.store.adapterFor('job').purge(this);
}
plan() {
assert('A job must be parsed before planned', this._newDefinitionJSON);
return this.store.adapterFor('job').plan(this);

View File

@ -25,6 +25,15 @@
@awaitingConfirmation={{this.stopJob.isRunning}}
@onConfirm={{perform this.stopJob}} />
{{else}}
<TwoStepButton
data-test-purge
@alignRight={{true}}
@idleText="Purge Job"
@cancelText="Cancel"
@confirmText="Yes, Purge Job"
@confirmationMessage="Are you sure? You cannot undo this action."
@awaitingConfirmation={{this.purgeJob.isRunning}}
@onConfirm={{perform this.purgeJob}} />
<TwoStepButton
data-test-start
@alignRight={{true}}

View File

@ -102,10 +102,12 @@ export default function moduleForJob(
test('the title buttons are dependent on job status', async function (assert) {
if (job.status === 'dead') {
assert.ok(JobDetail.start.isPresent);
assert.ok(JobDetail.purge.isPresent);
assert.notOk(JobDetail.stop.isPresent);
assert.notOk(JobDetail.execButton.isPresent);
} else {
assert.notOk(JobDetail.start.isPresent);
assert.notOk(JobDetail.purge.isPresent);
assert.ok(JobDetail.stop.isPresent);
assert.ok(JobDetail.execButton.isPresent);
}

View File

@ -20,6 +20,11 @@ export async function startJob() {
await click('[data-test-start] [data-test-confirm-button]');
}
export async function purgeJob() {
await click('[data-test-purge] [data-test-idle-button]');
await click('[data-test-purge] [data-test-confirm-button]');
}
export function expectStartRequest(assert, server, job) {
const expectedURL = jobURL(job);
const request = server.pretender.handledRequests
@ -63,3 +68,14 @@ export function expectDeleteRequest(assert, server, job) {
'DELETE URL was made correctly'
);
}
export function expectPurgeRequest(assert, server, job) {
const expectedURL = jobURL(job) + '?purge=true';
assert.ok(
server.pretender.handledRequests
.filterBy('method', 'DELETE')
.find((req) => req.url === expectedURL),
'DELETE URL was made correctly'
);
}

View File

@ -11,9 +11,11 @@ import {
jobURL,
stopJob,
startJob,
purgeJob,
expectError,
expectDeleteRequest,
expectStartRequest,
expectPurgeRequest,
} from './helpers';
import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit';
@ -226,6 +228,25 @@ module('Integration | Component | job-page/periodic', function (hooks) {
await expectError(assert, 'Could Not Start Job');
});
test('Purging a job sends a purge request for the job', async function (assert) {
assert.expect(1);
const mirageJob = this.server.create('job', 'periodic', {
childrenCount: 0,
createAllocations: false,
status: 'dead',
});
await this.store.findAll('job');
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
await purgeJob();
expectPurgeRequest(assert, this.server, job);
});
test('Each job row includes the submitted time', async function (assert) {
this.server.create('job', 'periodic', {
id: 'parent',

View File

@ -7,9 +7,11 @@ import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage';
import {
startJob,
stopJob,
purgeJob,
expectError,
expectDeleteRequest,
expectStartRequest,
expectPurgeRequest,
} from './helpers';
import Job from 'nomad-ui/tests/pages/jobs/detail';
import { initialize as fragmentSerializerInitializer } from 'nomad-ui/initializers/fragment-serializer';
@ -128,6 +130,21 @@ module('Integration | Component | job-page/service', function (hooks) {
await expectError(assert, 'Could Not Start Job');
});
test('Purging a job sends a purge request for the job', async function (assert) {
assert.expect(1);
const mirageJob = makeMirageJob(this.server, { status: 'dead' });
await this.store.findAll('job');
const job = this.store.peekAll('job').findBy('plainId', mirageJob.id);
this.setProperties(commonProperties(job));
await render(commonTemplate);
await purgeJob();
expectPurgeRequest(assert, this.server, job);
});
test('Recent allocations shows allocations in the job context', async function (assert) {
assert.expect(3);

View File

@ -37,6 +37,7 @@ export default create({
stop: twoStepButton('[data-test-stop]'),
start: twoStepButton('[data-test-start]'),
purge: twoStepButton('[data-test-purge]'),
packTag: isPresent('[data-test-pack-tag]'),
metaTable: isPresent('[data-test-meta]'),

View File

@ -515,6 +515,20 @@ module('Unit | Adapter | Job', function (hooks) {
assert.equal(request.method, 'DELETE');
});
test('purge requests include the activeRegion', async function (assert) {
const region = 'region-2';
const job = await this.initializeWithJob({ region });
await this.subject().purge(job);
const request = this.server.pretender.handledRequests[0];
assert.equal(
request.url,
`/v1/job/${job.plainId}?purge=true&region=${region}`
);
assert.equal(request.method, 'DELETE');
});
test('parse requests include the activeRegion', async function (assert) {
const region = 'region-2';
await this.initializeUI({ region });