Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ui] "Edit from Version" function added to Revert #24168

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/24168.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
ui: Add an Edit From Version button as an option when reverting from an older job version
```
4 changes: 2 additions & 2 deletions ui/app/adapters/job.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ export default class JobAdapter extends WatchableNamespaceIDs {
return this.ajax(url, 'GET');
}

fetchRawSpecification(job) {
fetchRawSpecification(job, version) {
const url = addToPath(
this.urlForFindRecord(job.get('id'), 'job', null, 'submission'),
'',
'version=' + job.get('version')
'version=' + (version || job.get('version'))
);
return this.ajax(url, 'GET');
}
Expand Down
50 changes: 50 additions & 0 deletions ui/app/components/job-version.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* SPDX-License-Identifier: BUSL-1.1
*/

// @ts-check

import Component from '@glimmer/component';
import { action, computed } from '@ember/object';
import { alias } from '@ember/object/computed';
Expand Down Expand Up @@ -80,6 +82,11 @@ export default class JobVersion extends Component {
this.isOpen = !this.isOpen;
}

/**
* @type {'idle' | 'confirming'}
*/
@tracked cloneButtonStatus = 'idle';

@task(function* () {
try {
const versionBeforeReversion = this.version.get('job.version');
Expand All @@ -88,6 +95,7 @@ export default class JobVersion extends Component {

const versionAfterReversion = this.version.get('job.version');
if (versionBeforeReversion === versionAfterReversion) {
// TODO: I don't think this is ever hit, we have template checks against it.
this.args.handleError({
level: 'warn',
title: 'Reversion Had No Effect',
Expand All @@ -108,6 +116,48 @@ export default class JobVersion extends Component {
})
revertTo;

@action async cloneAsNewVersion() {
try {
this.router.transitionTo(
'jobs.job.definition',
this.version.get('job.idWithNamespace'),
{
queryParams: {
isEditing: true,
version: this.version.number,
},
}
);
} catch (e) {
this.args.handleError({
level: 'danger',
title: 'Could Not Edit from Version',
});
}
}

@action async cloneAsNewJob() {
console.log('cloneAsNewJob');
try {
// TODO: copy the job definition over there.
console.log('Do I have submission info???', this.version);
let job = await this.version.get('job');
let specification = await job.fetchRawSpecification(this.version.number);
console.log('Do I have specification???', specification);
let specificationSourceString = specification.Source; // TODO: should do some Format checking here, at the very least.
this.router.transitionTo('jobs.run', {
queryParams: {
sourceString: specificationSourceString,
},
});
} catch (e) {
this.args.handleError({
level: 'danger',
title: 'Could Not Clone as New Job',
});
}
}

@action
handleKeydown(event) {
if (event.key === 'Escape') {
Expand Down
4 changes: 2 additions & 2 deletions ui/app/models/job.js
Original file line number Diff line number Diff line change
Expand Up @@ -541,8 +541,8 @@ export default class Job extends Model {
return this.store.adapterFor('job').fetchRawDefinition(this);
}

fetchRawSpecification() {
return this.store.adapterFor('job').fetchRawSpecification(this);
fetchRawSpecification(version) {
return this.store.adapterFor('job').fetchRawSpecification(this, version);
}

forcePeriodic() {
Expand Down
38 changes: 34 additions & 4 deletions ui/app/routes/jobs/job/definition.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,59 @@

// @ts-check
import Route from '@ember/routing/route';

import { inject as service } from '@ember/service';
/**
* Route for fetching and displaying a job's definition and specification.
*/
export default class DefinitionRoute extends Route {
@service notifications;

queryParams = {
version: {
refreshModel: true,
},
};

/**
* Fetch the job's definition, specification, and variables from the API.
*
* @returns {Promise<Object>} A promise that resolves to an object containing the job, definition, format,
* specification, variableFlags, and variableLiteral.
*/
async model() {
async model({ version }) {
version = +version; // query parameter is a string; convert to number
/** @type {import('../../../models/job').default} */
const job = this.modelFor('jobs.job');
if (!job) return;

const definition = await job.fetchRawDefinition();
let definition;

if (version) {
try {
const versionResponse = await job.getVersions();
const versions = versionResponse.Versions;
definition = versions.findBy('Version', version);
if (!definition) {
throw new Error('Version not found');
}
} catch (e) {
console.error('error fetching job version definition', e);
this.notifications.add({
title: 'Error Fetching Job Version Definition',
message: `There was an error fetching the versions for this job: ${e.message}`,
color: 'critical',
});
}
} else {
definition = await job.fetchRawDefinition();
}

let format = 'json'; // default to json in network request errors
let specification;
let variableFlags;
let variableLiteral;
try {
const specificationResponse = await job.fetchRawSpecification();
const specificationResponse = await job.fetchRawSpecification(version);
specification = specificationResponse?.Source ?? null;
variableFlags = specificationResponse?.VariableFlags ?? null;
variableLiteral = specificationResponse?.Variables ?? null;
Expand Down
11 changes: 10 additions & 1 deletion ui/app/routes/jobs/run/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export default class JobsRunIndexRoute extends Route {
template: {
refreshModel: true,
},
sourceString: {
refreshModel: true,
},
};

beforeModel(transition) {
Expand All @@ -33,7 +36,7 @@ export default class JobsRunIndexRoute extends Route {
}
}

async model({ template }) {
async model({ template, sourceString }) {
try {
// When jobs are created with a namespace attribute, it is verified against
// available namespaces to prevent redirecting to a non-existent namespace.
Expand All @@ -45,6 +48,12 @@ export default class JobsRunIndexRoute extends Route {
return this.store.createRecord('job', {
_newDefinition: templateRecord.items.template,
});
} else if (sourceString) {
console.log('elsif', sourceString);
// Add an alert to the page to let the user know that they are submitting a job from a template, and that they should change the name!
return this.store.createRecord('job', {
_newDefinition: sourceString,
});
} else {
return this.store.createRecord('job');
}
Expand Down
42 changes: 42 additions & 0 deletions ui/app/templates/components/job-version.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@
<div class="version-options">
{{#unless this.isCurrent}}
{{#if (can "run job" namespace=this.version.job.namespace)}}
{{#if (eq this.cloneButtonStatus 'idle')}}
<Hds::Button
data-test-clone-and-edit
@text="Clone and Edit"
@color="secondary"
@size="small"
@isInline={{true}}
{{!-- @disabled={{this.revertTo.isRunning}} --}}
{{on "click" (action (mut this.cloneButtonStatus) "confirming")}}
/>

<TwoStepButton
data-test-revert-to
@classes={{hash
Expand All @@ -95,6 +106,37 @@
@size="small"
@awaitingConfirmation={{this.revertTo.isRunning}}
@onConfirm={{perform this.revertTo}} />


{{else if (eq this.cloneButtonStatus 'confirming')}}
{{!-- <span data-test-confirmation-message class="confirmation-text is-right-aligned has-text-inline">
Are you sure you want to revert to this version?
</span> --}}
<Hds::Button
data-test-cancel-clone
@text="Cancel"
@color="secondary"
@size="small"
@isInline={{true}}
{{on "click" (action (mut this.cloneButtonStatus) "idle")}}
/>
<Hds::Button
data-test-clone-as-new-version
@text="Clone as New Version of {{this.version.job.name}}"
@color="secondary"
@size="small"
@isInline={{true}}
{{on "click" (action this.cloneAsNewVersion)}}
/>
<Hds::Button
data-test-clone-as-new-job
@text="Clone as New Job"
@color="secondary"
@size="small"
@isInline={{true}}
{{on "click" (action this.cloneAsNewJob)}}
/>
{{/if}}
{{else}}
<Hds::Button
data-test-revert-to
Expand Down
2 changes: 2 additions & 0 deletions ui/tests/unit/adapters/job-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,8 @@ module('Unit | Adapter | Job', function (hooks) {
assert.equal(request.method, 'GET');
});

// TODO: test that version requests work for fetchRawDefinition

test('forcePeriodic requests include the activeRegion', async function (assert) {
const region = 'region-2';
const job = await this.initializeWithJob({ region });
Expand Down
Loading