Skip to content

Commit 4176861

Browse files
Bypass blob storage in UploadArtifact. Closes #1704 (#1717)
* Bypass blob storage in UploadArtifact(Closes #1704) * WIP- Fix eslinting issues * WIP-Refactor CustomConfigEntries, Address PR suggestions * WIP- add spinner; fix unused imports * WIP- Gracefully handle dialog errors, rename BrowserAssetWidget->FileWidget * Fix widget name in components.json, Use toast to show errors
1 parent 062d1c9 commit 4176861

File tree

9 files changed

+431
-176
lines changed

9 files changed

+431
-176
lines changed

config/components.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
"container": "float",
101101
"DEBUG_ONLY": false
102102
}
103-
103+
104104
]
105105
},
106106
"RootViz": {
@@ -135,5 +135,14 @@
135135
},
136136
"Storage": {
137137
"backends": ["gme", "sciserver-files", "s3"]
138+
},
139+
"PropertyGridWidgets": {
140+
"widgets" : [
141+
{
142+
"name" : "FileWidget",
143+
"type": "file",
144+
"path" : "deepforge/viz/widgets/FileWidget"
145+
}
146+
]
138147
}
139148
}

src/common/globals.js

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -271,31 +271,39 @@ define([
271271
const allConfigs = await configDialog.show(metadata);
272272
const context = client.getCurrentPluginContext(pluginName);
273273
context.pluginConfig = allConfigs[pluginName];
274-
context.pluginConfig.storage.id = storageMetadata
275-
.find(metadata => metadata.name === context.pluginConfig.storage.name)
276-
.id;
274+
const hasStorageConfig = pluginConfig => !!pluginConfig.storage;
275+
if (hasStorageConfig(context.pluginConfig)){
276+
context.pluginConfig.storage.id = storageMetadata
277+
.find(metadata => metadata.name === context.pluginConfig.storage.name)
278+
.id;
279+
}
277280
return await Q.ninvoke(client, 'runBrowserPlugin', pluginName, context);
278281
};
279282

280283

281284
DeepForge.create.Artifact = async function() {
285+
const USER_ASSET_TYPE = 'userAsset';
282286
const metadata = copy(WebGMEGlobal.allPluginsMetadata[UPLOAD_PLUGIN]);
283-
const storageOpts = getStorageOptions();
287+
const hasUserAssetType = metadata.configStructure
288+
.map(config => config.valueType)
289+
.find(val => val === USER_ASSET_TYPE);
284290

285291
metadata.configStructure.unshift({
286292
name: 'artifactOptions',
287293
displayName: 'New Artifact',
288294
valueType: 'section'
289295
});
290296

291-
const storageHeader = {
292-
name: 'storageOptions',
293-
displayName: 'Storage',
294-
valueType: 'section'
295-
};
296-
metadata.configStructure.push(storageHeader);
297-
metadata.configStructure.push(storageOpts);
298-
297+
if(!hasUserAssetType){
298+
const storageOpts = getStorageOptions();
299+
const storageHeader = {
300+
name: 'storageOptions',
301+
displayName: 'Storage',
302+
valueType: 'section'
303+
};
304+
metadata.configStructure.push(storageHeader);
305+
metadata.configStructure.push(storageOpts);
306+
}
299307
await runArtifactPlugin(UPLOAD_PLUGIN, metadata);
300308
};
301309

src/common/storage/backends/sciserver-files/Client.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ define([
4646
const metadata = {
4747
filename: filename,
4848
volume: this.volume,
49-
size: content.byteLength,
49+
size: content.byteLength || content.size,
5050
volumePool: this.volumePool
5151
};
5252
return this.createDataInfo(metadata);

src/common/viz/ConfigDialog.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,18 @@
33
color: #888;
44
font-style: italic;
55
}
6+
7+
.glyphicon-refresh-animate {
8+
-animation: spin .7s infinite linear;
9+
-webkit-animation: spin2 .7s infinite linear;
10+
}
11+
12+
@-webkit-keyframes spin2 {
13+
from { -webkit-transform: rotate(0deg);}
14+
to { -webkit-transform: rotate(360deg);}
15+
}
16+
17+
@keyframes spin {
18+
from { transform: scale(1) rotate(0deg);}
19+
to { transform: scale(1) rotate(360deg);}
20+
}

src/common/viz/ConfigDialog.js

Lines changed: 67 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,20 @@
22
define([
33
'q',
44
'js/Dialogs/PluginConfig/PluginConfigDialog',
5+
'./ConfigDialogEntries/CustomConfigEntries',
56
'deepforge/utils',
7+
'js/Utils/ComponentSettings',
8+
'panel/FloatingActionButton/styles/Materialize',
69
'text!js/Dialogs/PluginConfig/templates/PluginConfigDialog.html',
710
'css!./ConfigDialog.css'
811
], function(
912
Q,
1013
PluginConfigDialog,
14+
CustomConfigEntries,
1115
utils,
12-
pluginConfigDialogTemplate,
16+
ComponentSettings,
17+
Materialize,
18+
pluginConfigDialogTemplate
1319
) {
1420
var SECTION_DATA_KEY = 'section',
1521
ATTRIBUTE_DATA_KEY = 'attribute',
@@ -18,38 +24,66 @@ define([
1824
ENTRY_BASE = $('<div class="form-group"><div class="row"><label class="col-sm-4 control-label">NAME</label><div class="col-sm-8 controls"></div></div><div class="row description"><div class="col-sm-4"></div></div></div>'),
1925
//jscs:enable maximumLineLength
2026
DESCRIPTION_BASE = $('<div class="desc muted col-sm-8"></div>'),
21-
SECTION_HEADER = $('<h6 class="config-section-header">');
27+
SPINNER_BASE = $('<span class="text-primary glyphicon glyphicon-refresh glyphicon-refresh-animate"></span>');
2228

2329
var ConfigDialog = function(client) {
2430
PluginConfigDialog.call(this, {client: client});
2531
this._widgets = {};
32+
this._customEntriesManager = new CustomConfigEntries();
33+
this._initCustomEntriesManagerMethods();
34+
this.imported = this._registerCustomPropertyGridWidgets();
2635
};
2736

2837
ConfigDialog.prototype = Object.create(PluginConfigDialog.prototype);
2938

39+
ConfigDialog.prototype._initCustomEntriesManagerMethods = function () {
40+
this._customEntriesManager.getEntryForProperty = this.getEntryForProperty.bind(this);
41+
this._customEntriesManager.getBaseStorageDir = this.getBaseStorageDir.bind(this);
42+
};
43+
44+
ConfigDialog.prototype._registerCustomPropertyGridWidgets = async function() {
45+
const self = this;
46+
const customWidgets = ComponentSettings.resolveWithWebGMEGlobal(
47+
{},
48+
'PropertyGridWidgets'
49+
).widgets || [];
50+
51+
const promises = customWidgets.map(widgetInfo => {
52+
return new Promise((resolve, reject) => {
53+
require([widgetInfo.path], function(customWidget) {
54+
const targetType = widgetInfo.type;
55+
self._propertyGridWidgetManager
56+
.registerWidgetForType(targetType, customWidget);
57+
resolve();
58+
}, reject);
59+
});
60+
});
61+
return Promise.all(promises);
62+
};
63+
3064
ConfigDialog.prototype.show = async function(pluginMetadata, options={}) {
3165
const deferred = Q.defer();
32-
3366
this._pluginMetadata = pluginMetadata;
3467
const prevConfig = await this.getSavedConfig();
68+
await this.imported;
3569
this._initDialog(pluginMetadata, prevConfig, options);
3670

3771
this._dialog.on('shown', () => {
3872
this._dialog.find('input').first().focus();
3973
});
4074

41-
this._btnSave.on('click', event => {
42-
this.submit(deferred.resolve);
75+
this._btnSave.on('click', async event => {
4376
event.stopPropagation();
4477
event.preventDefault();
78+
await this.submit(deferred.resolve);
4579
});
4680

4781
//save&run on CTRL + Enter
48-
this._dialog.on('keydown.PluginConfigDialog', event => {
82+
this._dialog.on('keydown.PluginConfigDialog', async event => {
4983
if (event.keyCode === 13 && (event.ctrlKey || event.metaKey)) {
5084
event.stopPropagation();
5185
event.preventDefault();
52-
this.submit(deferred.resolve);
86+
await this.submit(deferred.resolve);
5387
}
5488
});
5589
this._dialog.modal('show');
@@ -63,6 +97,7 @@ define([
6397
this._divContainer = this._dialog.find('.modal-body');
6498
this._saveConfigurationCb = this._dialog.find('.save-configuration');
6599
this._modalHeader = this._dialog.find('.modal-header');
100+
this._modalFooter = this._dialog.find('.modal-footer');
66101
this._saveConfigurationCb.find('input').prop('checked', true);
67102

68103
// Create the header
@@ -85,8 +120,10 @@ define([
85120
};
86121
};
87122

88-
ConfigDialog.prototype.submit = function (callback) {
89-
const config = this._getAllConfigValues();
123+
ConfigDialog.prototype.submit = async function (callback) {
124+
this._btnSave.attr('disabled', true);
125+
SPINNER_BASE.insertAfter(this._modalFooter.find('form'));
126+
const config = await this._getAllConfigValues();
90127
const saveConfig = this._saveConfigurationCb.find('input')
91128
.prop('checked');
92129

@@ -159,16 +196,23 @@ define([
159196
return response.status < 399 ? await response.json() : null;
160197
};
161198

162-
ConfigDialog.prototype._getAllConfigValues = function () {
199+
ConfigDialog.prototype._getAllConfigValues = async function () {
163200
var settings = {};
164-
165-
Object.keys(this._widgets).forEach(namespace => {
201+
for (const namespace of Object.keys(this._widgets)){
166202
settings[namespace] = {};
167203

168-
Object.keys(this._widgets[namespace]).forEach(name => {
169-
settings[namespace][name] = this._widgets[namespace][name].getValue();
170-
});
171-
});
204+
for(const name of Object.keys(this._widgets[namespace])){
205+
let value;
206+
try {
207+
value = await this._widgets[namespace][name].getValue();
208+
} catch (e) {
209+
Materialize.toast(e.message, 4000);
210+
this._dialog.modal('hide');
211+
throw e;
212+
}
213+
settings[namespace][name] = value;
214+
}
215+
}
172216

173217
return settings;
174218
};
@@ -224,8 +268,8 @@ define([
224268

225269
ConfigDialog.prototype.getEntryForProperty = function (configEntry, prevConfig = {}) {
226270
let entry = null;
227-
if (ConfigDialog.ENTRIES[configEntry.valueType]) {
228-
entry = ConfigDialog.ENTRIES[configEntry.valueType].call(this, configEntry, prevConfig);
271+
if (CustomConfigEntries.isCustomEntryValueType(configEntry.valueType)) {
272+
entry = this._customEntriesManager[configEntry.valueType](configEntry, prevConfig);
229273
} else {
230274
const widget = this.getWidgetForProperty(configEntry);
231275
const el = ENTRY_BASE.clone();
@@ -274,127 +318,15 @@ define([
274318
}
275319
};
276320

277-
ConfigDialog.WIDGETS = {};
278-
ConfigDialog.ENTRIES = {};
279-
ConfigDialog.ENTRIES.section = function(configEntry) {
280-
const sectionHeader = SECTION_HEADER.clone();
281-
sectionHeader.text(configEntry.displayName);
282-
return {el: sectionHeader};
321+
ConfigDialog.prototype.getBaseStorageDir = function() {
322+
return `${this._client.getActiveProjectId()}/artifacts`;
283323
};
284324

285-
ConfigDialog.ENTRIES.group = function(configEntry, config) {
286-
const widget = {el: null};
287-
widget.el = $('<div>', {class: configEntry.name});
288-
289-
const entries = configEntry.valueItems
290-
.map(item => this.getEntryForProperty(item, config));
291-
292-
entries.forEach(entry => widget.el.append(entry.el));
293-
294-
widget.getValue = () => {
295-
const config = {};
296-
entries.forEach(entry => {
297-
if (entry.widget) {
298-
config[entry.id || entry.name] = entry.widget.getValue();
299-
}
300-
});
301-
return config;
302-
};
303-
304-
widget.setValue = config => {
305-
entries.forEach(entry => {
306-
const value = config[entry.id || entry.name];
307-
if (entry.widget && value !== undefined) {
308-
entry.widget.setValue(value);
309-
}
310-
});
311-
return config;
312-
};
313-
314-
return {widget, el: widget.el};
325+
ConfigDialog.prototype.getComponentId = function() {
326+
return 'ConfigDialog';
315327
};
316328

317-
ConfigDialog.ENTRIES.dict = function(configEntry, config) {
318-
const widget = {el: null, active: null};
319-
widget.el = $('<div>', {class: configEntry.name});
320-
321-
const entriesForItem = {};
322-
const valueItemsDict = {};
323-
for (let i = 0; i < configEntry.valueItems.length; i++) {
324-
const valueItem = configEntry.valueItems[i];
325-
const entries = valueItem.configStructure
326-
.map(item => {
327-
const entry = this.getEntryForProperty(item, config);
328-
return entry;
329-
});
330-
331-
entries.forEach(entry => {
332-
if (i > 0) {
333-
entry.el.css('display', 'none');
334-
}
335-
widget.el.append(entry.el);
336-
});
337-
338-
const displayName = valueItem.displayName || valueItem.name;
339-
entriesForItem[displayName] = entries;
340-
valueItemsDict[displayName] = valueItem;
341-
}
342-
343-
const itemNames = Object.keys(valueItemsDict);
344-
const defaultValue = itemNames[0];
345-
346-
const configForKeys = {
347-
name: configEntry.name,
348-
displayName: configEntry.displayName,
349-
value: defaultValue,
350-
valueType: 'string',
351-
valueItems: itemNames
352-
};
353-
const selector = this.getEntryForProperty(configForKeys);
354-
355-
widget.active = defaultValue;
356-
widget.onSetSelector = value => {
357-
const oldEntries = entriesForItem[widget.active];
358-
oldEntries.forEach(entry => entry.el.css('display', 'none'));
359-
360-
widget.active = value;
361-
entriesForItem[widget.active]
362-
.forEach(entry => entry.el.css('display', ''));
363-
};
364-
365-
selector.el.find('select').on('change', event => {
366-
const {value} = event.target;
367-
widget.onSetSelector(value);
368-
});
369-
370-
widget.getValue = () => {
371-
const displayName = widget.active;
372-
const name = valueItemsDict[displayName].name;
373-
const config = {};
374-
entriesForItem[name].forEach(entry => {
375-
if (entry.widget) {
376-
config[entry.id] = entry.widget.getValue();
377-
}
378-
});
379-
return {name, config};
380-
};
381-
382-
widget.setValue = value => {
383-
const {name, config} = value;
384-
selector.widget.setValue(name);
385-
widget.onSetSelector(name);
386-
entriesForItem[name].forEach(entry => {
387-
if (entry.widget) {
388-
entry.widget.setValue(config[entry.id]);
389-
}
390-
});
391-
return {name, config};
392-
};
393-
394-
widget.el.prepend(selector.el);
395-
396-
return {widget, el: widget.el};
397-
};
329+
ConfigDialog.WIDGETS = {};
398330

399331
return ConfigDialog;
400332
});

0 commit comments

Comments
 (0)