Skip to content

Commit

Permalink
Merge pull request #1194 from briehl/import-refactor
Browse files Browse the repository at this point in the history
Small refactor to import panel
  • Loading branch information
briehl committed Oct 31, 2017
2 parents daf4acd + 65b8bd9 commit f6f57e3
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 139 deletions.
65 changes: 59 additions & 6 deletions kbase-extension/static/kbase/js/api/fileStaging.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,68 @@ define([
/**
* @method
* @public
* Lists files in the user's directory. A given subdirectory can be
* used to list files there.
* Lists files in the given directory path.
* options -
* userId {boolean|string} - if true, prepend with the current userId (if a string, use that string)
* deep {boolean} - if true, list deeply by getting the whole file tree from that point
*
* So now there's options. Our FTP service expects to see the userId at the front of the path.
* Other consumers of this (for other reasons) want to include that in the path submitted to
* this client. Optionally, it can be separated and set as a boolean. So these all do the
* same search (assuming the client was instantiated with user wjriehl):
*
* list('wjriehl/some_dir')
* list('some_dir', { userId: 'wjriehl' })
* list('some_dir', { userId: true })
*
* It also tries to be smart about constructing a path with slashes in the right place.
* All of these should reduce down to a GET call against /list/wjriehl/some_dir:
*
* list('/wjriehl/some_dir')
* list('some_dir', {userId: true})
* list('/some_dir', {userId: true})
* list('wjriehl/some_dir/')
*
* Note that if options.userId is set, it will ALWAYS be used, even if redundant. You
* never know if a crazy user made a top-level subdirectory with their own username in it.
*/
var list = function(directory, deep) {
var path = 'list/' + userId;
if (directory) {
if (directory[0] !== '/') {
var list = function(directory, options) {
options = options || {};
var path = 'list/';
if (options.userId) {
if (typeof options.userId === 'boolean') {
path += userId;
}
else if (typeof options.userId === 'string') {
path += options.userId;
}
if (!path.endsWith('/')) {
path += '/';
}
}
if (directory) {
if (directory[0] === '/') {
directory = directory.substring(1);
}
path += directory;
}
return makeFtpCall('GET', path);
};

/**
* @method
* @public
* Makes the /search call to the FTP service. This should return a list of files, similar to
* the list() function.
*
* This goes on to create a subdir attribute in each file before returning. This subdir
* is relative to the user's directory, as opposed to the FTP service root (which is the
* usually returned value).
* That is, it'll go from
* /data/bulk/some_user/some_directory/some_file
* to
* some_user/some_directory/some_file
*/
var search = function(term) {
var path = 'search/' + encodeURIComponent(term);
return makeFtpCall('GET', path)
Expand All @@ -51,6 +99,11 @@ define([
});
};

/**
* Wraps up the actual AJAX REST call. Given a method and path, it will populate headers
* as needed, then return a Promise with the call.
* It's pretty simple right now, we can adjust as needed.
*/
var makeFtpCall = function(method, path) {
return Promise.resolve($.ajax({
url: url + path,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ define([
this.$elem
.empty()
.append($mainElem
.append($dropzoneElem)
.append(this.$myFiles));
.append($dropzoneElem)
.append(this.$myFiles));

this.uploadWidget = new FileUploadWidget($dropzoneElem, {
path: this.path,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ define([
DropzoneAreaHtml,
DropFileHtml
) {
'use strict';
return new KBWidget({
name: 'fileUploadWidget',

Expand Down Expand Up @@ -56,63 +57,63 @@ define([
parallelUploads: 10,
maxFilesize: 20480 //20GB
})
.on('totaluploadprogress', function(progress) {
$($dropzoneElem.find('#total-progress .progress-bar')).css({'width': progress + '%'});
}.bind(this))
.on('addedFile', function(file) {
$dropzoneElem.find('#global-info').css({'display': 'inline'});
$dropzoneElem.find('#upload-message').text(this.makeUploadMessage());
}.bind(this))
.on('success', function(file, serverResponse) {
$dropzoneElem.find('#clear-completed').css({'display': 'inline'});
$dropzoneElem.find('#upload-message').text(this.makeUploadMessage());
file.previewElement.querySelector('#status-message').textContent = 'Completed';
file.previewElement.querySelector('.progress').style.display = 'none';
file.previewElement.querySelector('#status-message').style.display = 'inline';
$(file.previewElement.querySelector('.fa-ban')).removeClass('fa-ban').addClass('fa-check');
$(file.previewElement.querySelector('.btn-danger')).removeClass('btn-danger').addClass('btn-success');
if (this.dropzone.getQueuedFiles().length === 0 &&
this.dropzone.getUploadingFiles().length === 0) {
$($dropzoneElem.find('#total-progress')).fadeOut(1000, function() {
$($dropzoneElem.find('#total-progress .progress-bar')).css({'width': '0%'});
.on('totaluploadprogress', function(progress) {
$($dropzoneElem.find('#total-progress .progress-bar')).css({'width': progress + '%'});
}.bind(this))
.on('addedFile', function(file) {
$dropzoneElem.find('#global-info').css({'display': 'inline'});
$dropzoneElem.find('#upload-message').text(this.makeUploadMessage());
}.bind(this))
.on('success', function(file, serverResponse) {
$dropzoneElem.find('#clear-completed').css({'display': 'inline'});
$dropzoneElem.find('#upload-message').text(this.makeUploadMessage());
file.previewElement.querySelector('#status-message').textContent = 'Completed';
file.previewElement.querySelector('.progress').style.display = 'none';
file.previewElement.querySelector('#status-message').style.display = 'inline';
$(file.previewElement.querySelector('.fa-ban')).removeClass('fa-ban').addClass('fa-check');
$(file.previewElement.querySelector('.btn-danger')).removeClass('btn-danger').addClass('btn-success');
if (this.dropzone.getQueuedFiles().length === 0 &&
this.dropzone.getUploadingFiles().length === 0) {
$($dropzoneElem.find('#total-progress')).fadeOut(1000, function() {
$($dropzoneElem.find('#total-progress .progress-bar')).css({'width': '0%'});
});
}
$(file.previewElement).fadeOut(1000, function() {
$(file.previewElement.querySelector('.btn')).trigger('click');
});
}
$(file.previewElement).fadeOut(1000, function() {
$(file.previewElement.querySelector('.btn')).trigger('click');
}.bind(this))
.on('sending', function(file) {
$dropzoneElem.find('#global-info').css({'display': 'inline'});
$($dropzoneElem.find('#total-progress')).show();
$dropzoneElem.find('#upload-message').text(this.makeUploadMessage());
}.bind(this))
.on('reset', function() {
$dropzoneElem.find('#global-info').css({'display': 'none'});
$($dropzoneElem.find('#total-progress .progress-bar')).css({'width': '0%'});
});
}.bind(this))
.on('sending', function(file) {
$dropzoneElem.find('#global-info').css({'display': 'inline'});
$($dropzoneElem.find('#total-progress')).show();
$dropzoneElem.find('#upload-message').text(this.makeUploadMessage());
}.bind(this))
.on('reset', function() {
$dropzoneElem.find('#global-info').css({'display': 'none'});
$($dropzoneElem.find('#total-progress .progress-bar')).css({'width': '0%'});
});
},

makeUploadMessage: function() {
if (!this.dropzone) {
return "No files uploading.";
return 'No files uploading.';
}
var numUploading = this.dropzone.getUploadingFiles().length;
var numQueued = this.dropzone.getQueuedFiles().length;
if (numUploading === 0 && numQueued === 0) {
return "No files uploading.";
return 'No files uploading.';
}
var queuedText = numQueued ? ("(" + numQueued + " queued)") : "";
var pluralFiles = numUploading > 1 ? "s" : "";
var queuedText = numQueued ? ('(' + numQueued + ' queued)') : '';
var pluralFiles = numUploading > 1 ? 's' : '';
return [
"Uploading ",
'Uploading ',
numUploading,
" file",
' file',
pluralFiles,
" ",
' ',
queuedText,
" to ",
' to ',
this.getPath()
].join("");
].join('');
},

setPath: function(path) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ define([
'./uploadTour',
'util/kbaseApiUtil',
'util/bootstrapDialog',
'api/fileStaging',
'text!kbase/templates/data_staging/ftp_file_table.html',
'text!kbase/templates/data_staging/ftp_file_header.html',
'text!kbase/templates/data_staging/file_path.html',
Expand All @@ -29,10 +30,12 @@ define([
UploadTour,
APIUtil,
BootstrapDialog,
FileStaging,
FtpFileTableHtml,
FtpFileHeaderHtml,
FilePathHtml
) {
'use strict';
return new KBWidget({
name: 'StagingAreaViewer',

Expand All @@ -44,8 +47,13 @@ define([
this.ftpUrl = Config.url('ftp_api_url');
this.updatePathFn = options.updatePathFn || this.setPath;
this.uploaders = Config.get('uploaders');
this.setPath(options.path);
var runtime = Runtime.make();
this.userId = runtime.userId();
this.fileStagingClient = new FileStaging(
this.ftpUrl, this.userId, {token: runtime.authToken()});

// Get this party started.
this.setPath(options.path);
return this;
},

Expand All @@ -54,17 +62,26 @@ define([
},

updateView: function() {
this.fetchFtpFiles()
.then(function(files) {
this.$elem.empty();
this.renderFileHeader();
this.renderFiles(files);
}.bind(this))
.catch(function(error) {
console.error(error);
});
this.fileStagingClient.list(this.path)
.then(function(files) {
files.forEach(function(f) {
if (!f.isFolder) {
f.imported = {};
}
});
this.$elem.empty();
this.renderFileHeader();
this.renderFiles(files);
}.bind(this))
.catch(function(error) {
console.error(error);
});
},

/**
* Expect that 'path' is only any subdirectories. The root directory is still the
* user id.
*/
setPath: function(path) {
this.path = path;
// factor out the current subdirectory path into its own variable
Expand All @@ -77,33 +94,6 @@ define([
this.updateView();
},

fetchFtpFiles: function() {
var token = Runtime.make().authToken();
return Promise.resolve($.ajax({
url: this.ftpUrl + '/list' + this.path,
headers: {
'Authorization': token
}
}))
.then(function(files) {
return Promise.try(function() {
files.forEach(function(file) {
if (file.isFolder) {
return;
}
file.imported = {
narName: 'narrative',
narUrl: '/narrative/ws.123.obj.456',
objUrl: '/#dataview/123/objectName',
objName: 'myObject',
reportRef: 'reportRef'
};
});
return files;
});
});
},

renderFileHeader: function() {
this.$elem.append(this.ftpFileHeaderTmpl());
this.$elem.find('button#help').click(function() {
Expand Down Expand Up @@ -205,9 +195,9 @@ define([
var importType = $(e.currentTarget).prevAll('#import-type').val();
var importFile = $(e.currentTarget).data().import;
this.initImportApp(importType, importFile)
.then(function() {
this.updateView();
}.bind(this));
.then(function() {
this.updateView();
}.bind(this));
}.bind(this));
$('td:eq(0)', nRow).find('button[data-name]').on('click', function(e) {
this.updatePathFn(this.path += '/' + $(e.currentTarget).data().name);
Expand All @@ -221,44 +211,27 @@ define([
},

initImportApp: function(type, file) {
return Promise.try(function() {
var appInfo = this.uploaders.app_info[type];
if (appInfo) {
var tag = APIUtil.getAppVersionTag();
APIUtil.getAppSpec(appInfo.app_id)
.then(function(spec) {
var newCell = Jupyter.narrative.narrController.buildAppCodeCell(spec, tag);
var meta = newCell.metadata;
var fileParam = file;
if (this.subpath) {
fileParam = this.subpath + '/' + file;
}
if (appInfo.app_input_param_type === 'list') {
fileParam = [fileParam];
}
meta.kbase.appCell.params[appInfo.app_input_param] = fileParam;
meta.kbase.appCell.params[appInfo.app_output_param] = file.replace(/\s/g, '_') + appInfo.app_output_suffix;
for (var p in appInfo.app_static_params) {
if (appInfo.app_static_params.hasOwnProperty(p)) {
meta.kbase.appCell.params[p] = appInfo.app_static_params[p];
}
}
newCell.metadata = meta;
Jupyter.narrative.scrollToCell(newCell);
Jupyter.narrative.hideOverlay();
}.bind(this))
.catch(function(err) {
new BootstrapDialog({
title: 'Can\'t create uploader app!',
body: 'Sorry, unable to create App Cell to start your upload. You may need to set your Apps panel to \'dev\' or \'beta\'.',
buttons: [ $('<button class="btn btn-primary" data-dismiss="modal">OK</button>') ],
closeButton: true,
enterToTrigger: true
}).show();
console.error(err);
});
var appInfo = this.uploaders.app_info[type];
if (appInfo) {
var tag = APIUtil.getAppVersionTag(),
fileParam = file,
inputs = {};
if (this.subpath) {
fileParam = this.subpath + '/' + file;
}
}.bind(this));
if (appInfo.app_input_param_type === 'list') {
fileParam = [fileParam];
}
inputs[appInfo.app_input_param] = fileParam;
inputs[appInfo.app_output_param] = file.replace(/\s/g, '_') + appInfo.app_output_suffix;
for (var p in appInfo.app_static_params) {
if (appInfo.app_static_params.hasOwnProperty(p)) {
inputs[p] = appInfo.app_static_params[p];
}
}
Jupyter.narrative.addAndPopulateApp(appInfo.app_id, tag, inputs);
Jupyter.narrative.hideOverlay();
}
},

startTour: function() {
Expand Down
Loading

0 comments on commit f6f57e3

Please sign in to comment.