From 1f1199f3bffd6b32905d86957bd090a5e9c4ae8b Mon Sep 17 00:00:00 2001 From: Brian Broll Date: Wed, 8 Jul 2020 12:49:27 -0500 Subject: [PATCH 1/2] Update artifact downloading and refactor UI storage helpers. Fix #1748 --- src/common/viz/StorageHelpers.js | 27 +++++++ .../ArtifactIndex/ArtifactIndexControl.js | 3 - .../panels/ForgeActionButton/Actions.js | 78 ++++++++++++------- .../ArtifactIndex/ArtifactIndexWidget.js | 21 +---- 4 files changed, 80 insertions(+), 49 deletions(-) create mode 100644 src/common/viz/StorageHelpers.js diff --git a/src/common/viz/StorageHelpers.js b/src/common/viz/StorageHelpers.js new file mode 100644 index 000000000..1ea1d6de4 --- /dev/null +++ b/src/common/viz/StorageHelpers.js @@ -0,0 +1,27 @@ +/*globals define*/ +define([ + 'deepforge/viz/ConfigDialog', + 'deepforge/storage/index', +], function( + ConfigDialog, + Storage, +) { + const StorageHelpers = {}; + + StorageHelpers.getAuthenticationConfig = async function (dataInfo) { + const {backend} = dataInfo; + const metadata = Storage.getStorageMetadata(backend); + metadata.configStructure = metadata.configStructure + .filter(option => option.isAuth); + if (metadata.configStructure.length) { + const configDialog = new ConfigDialog(); + const title = `Authenticate with ${metadata.name}`; + const iconClass = `glyphicon glyphicon-download-alt`; + const config = await configDialog.show(metadata, {title, iconClass}); + + return config[backend]; + } + }; + + return StorageHelpers; +}); diff --git a/src/visualizers/panels/ArtifactIndex/ArtifactIndexControl.js b/src/visualizers/panels/ArtifactIndex/ArtifactIndexControl.js index 56c539be5..41c5005f4 100644 --- a/src/visualizers/panels/ArtifactIndex/ArtifactIndexControl.js +++ b/src/visualizers/panels/ArtifactIndex/ArtifactIndexControl.js @@ -3,12 +3,10 @@ define([ 'deepforge/storage/index', - 'deepforge/viz/ConfigDialog', 'blob/BlobClient', 'js/Constants' ], function ( Storage, - ConfigDialog, BlobClient, CONSTANTS ) { @@ -70,7 +68,6 @@ define([ return await storage.getDownloadURL(dataInfo); }; - this._widget.getConfigDialog = () => new ConfigDialog(this._client); this._widget.onAttributeChange = (id, attr, newValue) => { const node = this._client.getNode(id); diff --git a/src/visualizers/panels/ForgeActionButton/Actions.js b/src/visualizers/panels/ForgeActionButton/Actions.js index 812916440..bd39b9b96 100644 --- a/src/visualizers/panels/ForgeActionButton/Actions.js +++ b/src/visualizers/panels/ForgeActionButton/Actions.js @@ -7,40 +7,19 @@ define([ 'q', 'js/RegistryKeys', 'deepforge/globals', - 'deepforge/viz/TextPrompter' + 'deepforge/viz/TextPrompter', + 'deepforge/viz/StorageHelpers', + 'deepforge/storage/index', ], function( LibraryDialog, Materialize, Q, REGISTRY_KEYS, DeepForge, - TextPrompter + TextPrompter, + StorageHelpers, + Storage, ) { - ////////////// Downloading files ////////////// - var downloadAttrs = [ - 'data', - 'execFiles' - ], - download = {}; - - downloadAttrs.forEach(attr => { - download[attr] = function() { - return downloadButton.call(this, attr); - }; - }); - - // Add download model button - var downloadButton = function(attr) { - var id = this._currentNodeId, - node = this.client.getNode(id), - hash = node.getAttribute(attr); - - if (hash) { - return '/rest/blob/download/' + hash; - } - return null; - }; - var returnToLast = (place) => { var returnId = DeepForge.last[place]; WebGMEGlobal.State.registerActiveObject(returnId); @@ -175,7 +154,39 @@ define([ { name: 'Download', icon: 'play_for_work', - href: download.data // function to create href url + action: async function() { + try { + const node = this.client.getNode(this._currentNodeId); + const dataInfo = JSON.parse(node.getAttribute('data')); + + const config = await StorageHelpers.getAuthenticationConfig(dataInfo); + const storageAdapter = await Storage.getClient(dataInfo.backend, null, config); + const storageName = Storage.getStorageMetadata(dataInfo.backend).name; + const artifactName = node.getAttribute('name'); + + Materialize.toast(`Fetching ${artifactName} from ${storageName}...`, 2000); + let reminders = setInterval( + () => Materialize.toast(`Still fetching ${artifactName} from ${storageName}...`, 5000), + 10000 + ); + const url = await storageAdapter.getDownloadURL(dataInfo); + clearInterval(reminders); + + const save = document.createElement('a'); + + save.href = url; + save.target = '_self'; + const hasExtension = artifactName.includes('.'); + const filename = hasExtension ? artifactName : + artifactName + '.dat'; + save.download = filename; + save.click(); + (window.URL || window.webkitURL).revokeObjectURL(save.href); + + } catch (err) { + Materialize.toast(`Unable to download: ${err.message}`); + } + } } ], Job: [ @@ -184,7 +195,16 @@ define([ name: 'Download Execution Files', icon: 'play_for_work', priority: 1, - href: download.execFiles + href: function() { + const id = this._currentNodeId; + const node = this.client.getNode(id); + const hash = node.getAttribute('execFiles'); + + if (hash) { + return '/rest/blob/download/' + hash; + } + return null; + } }, // Stop execution button { diff --git a/src/visualizers/widgets/ArtifactIndex/ArtifactIndexWidget.js b/src/visualizers/widgets/ArtifactIndex/ArtifactIndexWidget.js index fb21f681c..6ac71e294 100644 --- a/src/visualizers/widgets/ArtifactIndex/ArtifactIndexWidget.js +++ b/src/visualizers/widgets/ArtifactIndex/ArtifactIndexWidget.js @@ -7,6 +7,7 @@ define([ 'panel/FloatingActionButton/styles/Materialize', 'deepforge/storage/index', 'deepforge/viz/ConfirmDialog', + 'deepforge/viz/StorageHelpers', 'text!./Table.html', 'css!./styles/ArtifactIndexWidget.css' ], function ( @@ -15,6 +16,7 @@ define([ Materialize, Storage, ConfirmDialog, + StorageHelpers, TABLE_HTML ) { 'use strict'; @@ -56,13 +58,13 @@ define([ const {dataInfo} = desc; const deleteData = await this.askIfDeleteFromStorage(dataInfo); const config = deleteData ? - await this.getAuthenticationConfig(dataInfo) : null; + await StorageHelpers.getAuthenticationConfig(dataInfo) : null; this.onNodeDeleteClicked(desc.id, config); event.stopPropagation(); event.preventDefault(); }); node.$download.on('click', async event => { - const config = await this.getAuthenticationConfig(desc.dataInfo); + const config = await StorageHelpers.getAuthenticationConfig(desc.dataInfo); try { const url = await this.getDownloadURL(desc.id, config); const filename = desc.name.includes('.') ? desc.name : desc.name + '.dat'; @@ -115,21 +117,6 @@ define([ return await dialog.show(); }; - ArtifactIndexWidget.prototype.getAuthenticationConfig = async function (dataInfo) { - const {backend} = dataInfo; - const metadata = Storage.getStorageMetadata(backend); - metadata.configStructure = metadata.configStructure - .filter(option => option.isAuth); - if (metadata.configStructure.length) { - const configDialog = this.getConfigDialog(); - const title = `Authenticate with ${metadata.name}`; - const iconClass = `glyphicon glyphicon-download-alt`; - const config = await configDialog.show(metadata, {title, iconClass}); - - return config[backend]; - } - }; - ArtifactIndexWidget.prototype.removeNode = function (gmeId) { var node = this.nodes[gmeId]; if (node) { From 6e1a00985bd71573b365d221967b2842c8537d5f Mon Sep 17 00:00:00 2001 From: Brian Broll Date: Wed, 8 Jul 2020 14:34:25 -0500 Subject: [PATCH 2/2] Refactor download logic to StorageHelpers --- src/common/viz/StorageHelpers.js | 27 +++++++++++++++ .../ArtifactIndex/ArtifactIndexControl.js | 9 ----- .../panels/ForgeActionButton/Actions.js | 33 +++---------------- .../ArtifactIndex/ArtifactIndexWidget.js | 28 ++++------------ 4 files changed, 38 insertions(+), 59 deletions(-) diff --git a/src/common/viz/StorageHelpers.js b/src/common/viz/StorageHelpers.js index 1ea1d6de4..0319a5eb0 100644 --- a/src/common/viz/StorageHelpers.js +++ b/src/common/viz/StorageHelpers.js @@ -2,9 +2,11 @@ define([ 'deepforge/viz/ConfigDialog', 'deepforge/storage/index', + 'panel/FloatingActionButton/styles/Materialize', ], function( ConfigDialog, Storage, + Materialize, ) { const StorageHelpers = {}; @@ -23,5 +25,30 @@ define([ } }; + StorageHelpers.download = async function (dataInfo, dataName='data') { + const config = await StorageHelpers.getAuthenticationConfig(dataInfo); + const storageAdapter = await Storage.getClient(dataInfo.backend, null, config); + const storageName = Storage.getStorageMetadata(dataInfo.backend).name; + + Materialize.toast(`Fetching ${dataName} from ${storageName}...`, 2000); + let reminders = setInterval( + () => Materialize.toast(`Still fetching ${dataName} from ${storageName}...`, 5000), + 10000 + ); + const url = await storageAdapter.getDownloadURL(dataInfo); + clearInterval(reminders); + + const save = document.createElement('a'); + + save.href = url; + save.target = '_self'; + const hasExtension = dataName.includes('.'); + const filename = hasExtension ? dataName : + dataName + '.dat'; + save.download = filename; + save.click(); + (window.URL || window.webkitURL).revokeObjectURL(save.href); + }; + return StorageHelpers; }); diff --git a/src/visualizers/panels/ArtifactIndex/ArtifactIndexControl.js b/src/visualizers/panels/ArtifactIndex/ArtifactIndexControl.js index 41c5005f4..661c82c74 100644 --- a/src/visualizers/panels/ArtifactIndex/ArtifactIndexControl.js +++ b/src/visualizers/panels/ArtifactIndex/ArtifactIndexControl.js @@ -60,15 +60,6 @@ define([ this._client.completeTransaction(); }; - this._widget.getDownloadURL = async (id, config) => { - const node = this._client.getNode(id); - const dataInfo = this.getDataInfo(node); - const {backend} = dataInfo; - const storage = await Storage.getClient(backend, this._logger, config); - - return await storage.getDownloadURL(dataInfo); - }; - this._widget.onAttributeChange = (id, attr, newValue) => { const node = this._client.getNode(id); const name = node.getAttribute('name'); diff --git a/src/visualizers/panels/ForgeActionButton/Actions.js b/src/visualizers/panels/ForgeActionButton/Actions.js index bd39b9b96..518da5138 100644 --- a/src/visualizers/panels/ForgeActionButton/Actions.js +++ b/src/visualizers/panels/ForgeActionButton/Actions.js @@ -9,7 +9,6 @@ define([ 'deepforge/globals', 'deepforge/viz/TextPrompter', 'deepforge/viz/StorageHelpers', - 'deepforge/storage/index', ], function( LibraryDialog, Materialize, @@ -18,7 +17,6 @@ define([ DeepForge, TextPrompter, StorageHelpers, - Storage, ) { var returnToLast = (place) => { var returnId = DeepForge.last[place]; @@ -155,36 +153,13 @@ define([ name: 'Download', icon: 'play_for_work', action: async function() { + const node = this.client.getNode(this._currentNodeId); + const artifactName = node.getAttribute('name'); try { - const node = this.client.getNode(this._currentNodeId); const dataInfo = JSON.parse(node.getAttribute('data')); - - const config = await StorageHelpers.getAuthenticationConfig(dataInfo); - const storageAdapter = await Storage.getClient(dataInfo.backend, null, config); - const storageName = Storage.getStorageMetadata(dataInfo.backend).name; - const artifactName = node.getAttribute('name'); - - Materialize.toast(`Fetching ${artifactName} from ${storageName}...`, 2000); - let reminders = setInterval( - () => Materialize.toast(`Still fetching ${artifactName} from ${storageName}...`, 5000), - 10000 - ); - const url = await storageAdapter.getDownloadURL(dataInfo); - clearInterval(reminders); - - const save = document.createElement('a'); - - save.href = url; - save.target = '_self'; - const hasExtension = artifactName.includes('.'); - const filename = hasExtension ? artifactName : - artifactName + '.dat'; - save.download = filename; - save.click(); - (window.URL || window.webkitURL).revokeObjectURL(save.href); - + await StorageHelpers.download(dataInfo, artifactName); } catch (err) { - Materialize.toast(`Unable to download: ${err.message}`); + Materialize.toast(`Unable to download ${artifactName}: ${err.message}`); } } } diff --git a/src/visualizers/widgets/ArtifactIndex/ArtifactIndexWidget.js b/src/visualizers/widgets/ArtifactIndex/ArtifactIndexWidget.js index 6ac71e294..1bed73dd7 100644 --- a/src/visualizers/widgets/ArtifactIndex/ArtifactIndexWidget.js +++ b/src/visualizers/widgets/ArtifactIndex/ArtifactIndexWidget.js @@ -55,31 +55,28 @@ define([ var node = new ModelItem(this.$list, desc); this.nodes[desc.id] = node; node.$delete.on('click', async event => { + event.stopPropagation(); + event.preventDefault(); const {dataInfo} = desc; const deleteData = await this.askIfDeleteFromStorage(dataInfo); const config = deleteData ? await StorageHelpers.getAuthenticationConfig(dataInfo) : null; this.onNodeDeleteClicked(desc.id, config); - event.stopPropagation(); - event.preventDefault(); }); node.$download.on('click', async event => { - const config = await StorageHelpers.getAuthenticationConfig(desc.dataInfo); + event.stopPropagation(); + event.preventDefault(); try { - const url = await this.getDownloadURL(desc.id, config); - const filename = desc.name.includes('.') ? desc.name : desc.name + '.dat'; - this.download(filename, url); + await StorageHelpers.download(desc.dataInfo, desc.name); } catch (err) { - const msg = `Unable to fetch data: ${err.message}`; + const msg = `Unable to fetch ${desc.name}: ${err.message}`; Materialize.toast(msg, 4000); } - event.stopPropagation(); - event.preventDefault(); }); node.$el.on('click', event => { - this.onNodeClick(desc.id); event.stopPropagation(); event.preventDefault(); + this.onNodeClick(desc.id); }); node.$name.on('dblclick', event => this.editInPlace(event,{ nodeId : desc.id, @@ -167,16 +164,5 @@ define([ ArtifactIndexWidget.prototype.onDeactivate = function () { }; - ArtifactIndexWidget.prototype.download = function (filename, url) { - const element = document.createElement('a'); - element.style.display = 'none'; - document.body.appendChild(element); - element.href = url; - element.target = '_self'; - element.setAttribute('download', filename); - element.click(); - document.body.removeChild(element); - }; - return ArtifactIndexWidget; });