diff --git a/.changelog/17752.txt b/.changelog/17752.txt new file mode 100644 index 000000000..227f74279 --- /dev/null +++ b/.changelog/17752.txt @@ -0,0 +1,3 @@ +```release-note:improvement +ui: Adds a Download as .nomad.hcl button to jobspec editing in the UI +``` diff --git a/ui/app/components/job-editor.js b/ui/app/components/job-editor.js index 980b9e9bb..c03b4666e 100644 --- a/ui/app/components/job-editor.js +++ b/ui/app/components/job-editor.js @@ -21,6 +21,7 @@ import { tracked } from '@glimmer/tracking'; export default class JobEditor extends Component { @service config; @service store; + @service notifications; @tracked error = null; @tracked planOutput = null; @@ -199,6 +200,42 @@ export default class JobEditor extends Component { reader.readAsText(file); } + /** + * Download the job's definition or specification as .nomad.hcl file locally + */ + @action + async handleSaveAsFile() { + try { + const blob = new Blob([this.args.job._newDefinition], { + type: 'text/plain', + }); + const url = window.URL.createObjectURL(blob); + const downloadAnchor = document.createElement('a'); + + downloadAnchor.href = url; + downloadAnchor.target = '_blank'; + downloadAnchor.rel = 'noopener noreferrer'; + downloadAnchor.download = 'jobspec.nomad.hcl'; + + downloadAnchor.click(); + downloadAnchor.remove(); + + window.URL.revokeObjectURL(url); + this.notifications.add({ + title: 'jobspec.nomad.hcl has been downloaded', + color: 'success', + icon: 'download', + }); + } catch (err) { + this.notifications.add({ + title: 'Error downloading file', + message: err.message, + color: 'critical', + sticky: true, + }); + } + } + /** * Get the definition or specification based on the view type. * @@ -253,6 +290,7 @@ export default class JobEditor extends Component { onPlan: this.plan, onReset: this.reset, onSaveAs: this.args.handleSaveAsTemplate, + onSaveFile: this.handleSaveAsFile, onSubmit: this.submit, onSelect: this.args.onSelect, onUpdate: this.updateCode, diff --git a/ui/app/styles/components/codemirror.scss b/ui/app/styles/components/codemirror.scss index ac752e16b..e2605bb68 100644 --- a/ui/app/styles/components/codemirror.scss +++ b/ui/app/styles/components/codemirror.scss @@ -140,6 +140,7 @@ header.run-job-header { grid-template-columns: 1fr auto; margin-bottom: 2rem; gap: 0 1rem; + align-items: end; & > h1 { grid-column: -1 / 1; } @@ -166,6 +167,10 @@ header.run-job-header { bottom: 0; background: white; padding: 0.5rem 0; + + &.pull-left { + justify-content: flex-start; + } } } diff --git a/ui/app/templates/components/job-editor.hbs b/ui/app/templates/components/job-editor.hbs index 7b3498a65..cb22d2f8f 100644 --- a/ui/app/templates/components/job-editor.hbs +++ b/ui/app/templates/components/job-editor.hbs @@ -15,6 +15,28 @@
Paste or author HCL or JSON to submit to your cluster, or select from a list of templates. A plan will be requested before the job is submitted. You can also attach a job spec by uploading a job file or dragging & dropping a file to the editor.
+ + {{#if (can "write variable" path="*" namespace="*")}} +