Error messages for job submit

This commit is contained in:
Michael Lange
2018-08-15 15:18:38 -07:00
parent f2128872ce
commit f29f4351f1
4 changed files with 89 additions and 26 deletions

View File

@@ -1,46 +1,61 @@
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import { task } from 'ember-concurrency';
import { qpBuilder } from 'nomad-ui/utils/classes/query-params';
import { next } from '@ember/runloop';
import messageFromAdapterError from 'nomad-ui/utils/message-from-adapter-error';
import localStorageProperty from 'nomad-ui/utils/properties/local-storage';
export default Controller.extend({
parseError: null,
planError: null,
runError: null,
showPlanMessage: localStorageProperty('nomadMessageJobPlan', true),
showEditorMessage: localStorageProperty('nomadMessageJobEditor', true),
stage: computed('planOutput', function() {
return this.get('planOutput') ? 'plan' : 'editor';
}),
plan: task(function*() {
this.cancel();
this.reset();
try {
yield this.get('model').parse();
} catch (err) {
this.set('parseError', err);
const error = messageFromAdapterError(err) || 'Could not parse input';
this.set('parseError', error);
return;
}
try {
const planOutput = yield this.get('model').plan();
this.set('planOutput', planOutput);
} catch (err) {
this.set('planError', err);
const error = messageFromAdapterError(err) || 'Could not plan job';
this.set('planError', error);
}
}).drop(),
submit: task(function*() {
try {
yield this.get('model').run();
const id = this.get('model.plainId');
const namespace = this.get('model.namespace.name') || 'default';
this.reset();
// navigate to the new job page
this.transitionToRoute('jobs.job', id, {
queryParams: { jobNamespace: namespace },
});
} catch (err) {
this.set('runError', err);
const error = messageFromAdapterError(err) || 'Could not submit job';
this.set('runError', error);
}
}),
cancel() {
reset() {
this.set('planOutput', null);
this.set('planError', null);
this.set('parseError', null);

View File

@@ -1,16 +1,37 @@
<section class="section">
{{#if parseError}}
<div data-test-parse-error class="notification is-danger">
<h3 class="title is-4">Parse Error</h3>
<p>{{parseError}}</p>
</div>
{{/if}}
{{#if planError}}
<div data-test-plan-error class="notification is-danger">
<h3 class="title is-4">Plan Error</h3>
<p>{{planError}}</p>
</div>
{{/if}}
{{#if runError}}
<div data-test-run-error class="notification is-danger">
<h3 class="title is-4">Run Error</h3>
<p>{{runError}}</p>
</div>
{{/if}}
{{#if (eq stage "editor")}}
<div class="notification is-info">
<div class="columns">
<div class="column">
<h3 class="title is-4">Run a Job</h3>
<p>Paste or author HCL or JSON to submit to your cluster. A plan will be requested before the job is submitted.</p>
</div>
<div class="column is-centered is-minimum">
<button class="button is-info">Okay</button>
{{#if showEditorMessage}}
<div class="notification is-info">
<div class="columns">
<div class="column">
<h3 class="title is-4">Run a Job</h3>
<p>Paste or author HCL or JSON to submit to your cluster. A plan will be requested before the job is submitted.</p>
</div>
<div class="column is-centered is-minimum">
<button class="button is-info" onclick={{toggle-action "showEditorMessage" this}}>Okay</button>
</div>
</div>
</div>
</div>
{{/if}}
<div class="boxed-section">
<div class="boxed-section-head">
Job Definition
@@ -33,17 +54,19 @@
{{/if}}
{{#if (eq stage "plan")}}
<div class="notification is-info">
<div class="columns">
<div class="column">
<h3 class="title is-4">Job Plan</h3>
<p>This is the impact running this job will have on your cluster.</p>
</div>
<div class="column is-centered is-minimum">
<button class="button is-info">Okay</button>
{{#if showPlanMessage}}
<div class="notification is-info">
<div class="columns">
<div class="column">
<h3 class="title is-4">Job Plan</h3>
<p>This is the impact running this job will have on your cluster.</p>
</div>
<div class="column is-centered is-minimum">
<button class="button is-info" onclick={{toggle-action "showPlanMessage" this}}>Okay</button>
</div>
</div>
</div>
</div>
{{/if}}
<div class="boxed-section">
<div class="boxed-section-head">Job Plan</div>
<div class="boxed-section-body is-dark">
@@ -52,7 +75,7 @@
</div>
<div class="content is-associative">
<button class="button is-primary {{if submit.isRunning "is-loading"}}" onclick={{perform submit}}>Submit</button>
<button class="button is-light" onclick={{action cancel}}>Cancel</button>
<button class="button is-light" onclick={{action reset}}>Cancel</button>
</div>
{{/if}}
</section>

View File

@@ -0,0 +1,6 @@
// Returns a single string based on the response the adapter received
export default function messageFromAdapterError(error) {
if (error.errors) {
return error.errors.mapBy('detail').join('\n\n');
}
}

View File

@@ -0,0 +1,19 @@
import { computed } from '@ember/object';
// An Ember.Computed property that persists set values in localStorage
// and will attempt to get its initial value from localStorage before
// falling back to a default.
//
// ex. showTutorial: localStorageProperty('nomadTutorial', true),
export default function localStorageProperty(localStorageKey, defaultValue) {
return computed({
get() {
const persistedValue = window.localStorage.getItem(localStorageKey);
return persistedValue ? JSON.parse(persistedValue) : defaultValue;
},
set(key, value) {
window.localStorage.setItem(localStorageKey, JSON.stringify(value));
return value;
},
});
}