diff options
-rw-r--r-- | static/panes/tool.js | 33 | ||||
-rw-r--r-- | types/compilation/compilation.interfaces.ts | 8 | ||||
-rw-r--r-- | views/templates/panes/tool-output.pug | 3 |
3 files changed, 42 insertions, 2 deletions
diff --git a/static/panes/tool.js b/static/panes/tool.js index eafa859c0..3bb123d68 100644 --- a/static/panes/tool.js +++ b/static/panes/tool.js @@ -36,6 +36,7 @@ var monacoConfig = require('../monaco-config'); var ceoptions = require('../options').options; var utils = require('../utils'); var PaneRenaming = require('../widgets/pane-renaming').PaneRenaming; +var saveAs = require('file-saver').saveAs; function makeAnsiToHtml(color) { return new AnsiToHtml({ @@ -317,12 +318,14 @@ Tool.prototype.initButtons = function (state) { this.hideable = this.domRoot.find('.hideable'); - this.initToggleButtons(state); + this.initButtonsVisibility(state); }; -Tool.prototype.initToggleButtons = function (state) { +Tool.prototype.initButtonsVisibility = function (state) { this.toggleArgs = this.domRoot.find('.toggle-args'); this.toggleStdin = this.domRoot.find('.toggle-stdin'); + this.artifactBtn = this.domRoot.find('.artifact-btn'); + this.artifactText = this.domRoot.find('.artifact-text'); if (state.argsPanelShown === true) { this.showPanel(this.toggleArgs, this.panelArgs); @@ -337,6 +340,7 @@ Tool.prototype.initToggleButtons = function (state) { } } } + this.artifactBtn.addClass('d-none'); }; Tool.prototype.showPanel = function (button, panel) { @@ -511,6 +515,31 @@ Tool.prototype.onCompileResult = function (id, compiler, result) { if (toolResult.sourcechanged && this.editorId) { this.eventHub.emit('newSource', this.editorId, toolResult.newsource); } + this.artifactBtn.off('click'); + if (toolResult.artifact) { + this.artifactBtn.removeClass('d-none'); + this.artifactText.text('Download ' + toolResult.artifactGenerated.title); + this.artifactBtn.click( + _.bind(function () { + // The artifact content can be passed either as plain text or as a base64 encoded binary file + if (toolResult.artifactGenerated.type === 'application/octet-stream') { + // Fetch is the most convenient non ES6 way to build a binary blob out of a base64 string + fetch('data:application/octet-stream;base64,' + toolResult.artifactGenerated.content) + .then(res => res.blob()) + .then(blob => saveAs(blob, toolResult.artifact.name)); + } else { + saveAs( + new Blob([toolResult.artifact.content], { + type: toolResult.artifact.type, + }), + toolResult.artifact.name + ); + } + }, this) + ); + } else { + this.artifactBtn.addClass('d-none'); + } } else { this.setEditorContent('No tool result'); } diff --git a/types/compilation/compilation.interfaces.ts b/types/compilation/compilation.interfaces.ts index c63c6e11e..235b86a63 100644 --- a/types/compilation/compilation.interfaces.ts +++ b/types/compilation/compilation.interfaces.ts @@ -99,6 +99,13 @@ export type BuildResult = { compilationOptions: any[]; }; +export type Artifact = { + content: string; + type: string; + name: string; + title: string; +}; + export type ToolResult = { id: string; name: string; @@ -106,4 +113,5 @@ export type ToolResult = { languageId: string; stderr: ResultLine[]; stdout: ResultLine[]; + artifact?: Artifact; }; diff --git a/views/templates/panes/tool-output.pug b/views/templates/panes/tool-output.pug index 437bf74ad..d4aa8cde2 100644 --- a/views/templates/panes/tool-output.pug +++ b/views/templates/panes/tool-output.pug @@ -15,6 +15,9 @@ button.btn.btn-sm.btn-light.toggle-stdin span.fas.fa-sign-in-alt span.hideable Stdin + button.btn.btn-sm.btn-light.artifact-btn(title="Download generated artifact" aria-label="Download generated artifact") + span.fa.fa-download + span.hideable.artifact-text Download .top-bar.btn-toolbar.bg-light.panel-args.d-none(role="toolbar") input.options.form-control(type="text" placeholder="Tool arguments..." size="256" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false") .top-bar.btn-toolbar.bg-light.panel-stdin.d-none(role="toolbar") |