');
+ this.$elem
+ .empty()
+ .append($mainElem
+ .append($dropzoneElem)
+ .append(this.$myFiles));
+
+ this.uploadWidget = new FileUploadWidget($dropzoneElem, {
+ path: this.path,
+ userInfo: userInfo,
+ userId: Jupyter.narrative.userId
});
- var $dropzoneElem = $('
');
- this.$elem
- .empty()
- .append($mainElem
- .append($dropzoneElem)
- .append(this.$myFiles));
- this.uploadWidget = new FileUploadWidget($dropzoneElem, {
- path: this.path,
- userInfo: userInfo,
- userId: Jupyter.narrative.userId
- });
+ this.uploadWidget.dropzone.on('complete', () => {
+ this.updateView();
+ });
- this.stagingAreaViewer = new StagingAreaViewer(this.$myFiles, {
- path: this.path,
- updatePathFn: this.updatePath.bind(this),
- userInfo: userInfo
- });
+ this.stagingAreaViewer = new StagingAreaViewer(this.$myFiles, {
+ path: this.path,
+ updatePathFn: this.updatePath.bind(this),
+ userInfo: userInfo
+ });
- this.updateView();
- });
+ this.updateView();
+ });
},
+ /**
+ * This updates the staging area viewer, and is called whenever an upload finishes.
+ * In addition, this should only fire a refresh event once per second (or some interval)
+ * to avoid spamming the staging area service and locking up the browser.
+ *
+ * So, when this is called the first time, it tracks the time it was called.
+ * If the next time this is called is less than some minRefreshTime apart, this
+ * makes a timeout with the time difference.
+ */
updateView: function() {
- this.stagingAreaViewer.render();
+ // this does the staging area re-render, then tracks the time
+ // it was last done.
+ const renderStagingArea = () => {
+ this.stagingAreaViewer.render();
+ this.lastRefresh = new Date().getTime();
+ };
+
+ // See how long it's been since the last refresh.
+ const refreshDiff = new Date().getTime() - this.lastRefresh;
+ if (refreshDiff < this.minRefreshTime) {
+ // if it's been under the minimum refresh time, and we're not already sitting on
+ // a pending timeout, then make one.
+ // If there IS a pending timeout, then do nothing, and it'll refresh when that fires.
+ if (!this.updateTimeout) {
+ this.updateTimeout = setTimeout(() => {
+ renderStagingArea();
+ this.updateTimeout = null;
+ }, refreshDiff);
+ }
+ }
+ else {
+ renderStagingArea();
+ }
}
});
});
diff --git a/src/config.json b/src/config.json
index f9268f2ab8..4edff1a286 100644
--- a/src/config.json
+++ b/src/config.json
@@ -103,7 +103,7 @@
"google_ad_conversion": "kR9OCLas4JgBEOy2pucC"
},
"comm_wait_timeout": 600000,
- "config": "narrative-refactor",
+ "config": "dev",
"data_panel": {
"initial_sort_limit": 10000,
"max_name_length": 33,
diff --git a/test/unit/spec/narrative_core/kbaseNarrativeStagingDataTab-spec.js b/test/unit/spec/narrative_core/kbaseNarrativeStagingDataTab-spec.js
index db68fc5acd..e104aade05 100644
--- a/test/unit/spec/narrative_core/kbaseNarrativeStagingDataTab-spec.js
+++ b/test/unit/spec/narrative_core/kbaseNarrativeStagingDataTab-spec.js
@@ -1,7 +1,5 @@
/*global define*/
-/*global describe, it, expect*/
-/*global jasmine*/
-/*global beforeEach, afterEach*/
+/*global jasmine, describe, it, expect, beforeEach, afterEach, spyOn*/
/*jslint white: true*/
define([
'jquery',
@@ -14,12 +12,10 @@ define([
) {
'use strict';
describe('Test the kbaseNarrativeStagingDataTab widget', () => {
- let $dummyNode = $('
'),
- stagingWidget,
- fakeUser = 'notAUser';
+ const fakeUser = 'notAUser';
beforeEach(() => {
jasmine.Ajax.install();
- jasmine.Ajax.stubRequest("https://ci.kbase.us/services/auth/api/V2/me").andReturn({
+ jasmine.Ajax.stubRequest(/\/auth\/api\/V2\/me$/).andReturn({
status: 200,
statusText: 'success',
contentType: 'application/json',
@@ -42,14 +38,14 @@ define([
responseHeaders: '',
responseText: JSON.stringify([
{
- name: "test_folder",
- path: fakeUser + "/test_folder",
+ name: 'test_folder',
+ path: fakeUser + '/test_folder',
mtime: 1532738637499,
size: 34,
isFolder: true
}, {
- name: "file_list.txt",
- path: fakeUser + "/test_folder/file_list.txt",
+ name: 'file_list.txt',
+ path: fakeUser + '/test_folder/file_list.txt',
mtime: 1532738637555,
size: 49233,
source: 'KBase upload'
@@ -60,30 +56,109 @@ define([
userId: fakeUser,
getAuthToken: () => { return 'fakeToken'; }
};
- stagingWidget = new StagingDataTab($dummyNode);
});
afterEach(() => {
jasmine.Ajax.uninstall();
- $dummyNode.remove();
});
- it('can load properly', (done) => {
- stagingWidget.render()
- .then(() => {
- expect(stagingWidget).not.toBeNull();
- done();
- });
+ it('can load properly', async () => {
+ const $dummyNode = $('
'),
+ stagingWidget = new StagingDataTab($dummyNode);
+ await stagingWidget.render();
+ expect(stagingWidget).not.toBeNull();
});
- it('can update its path properly', (done) => {
- stagingWidget.render()
- .then(() => {
- var newPath = 'a_new_path';
- stagingWidget.updatePath(newPath);
- expect(stagingWidget.path).toEqual(newPath);
- done();
- });
+ it('properly catches failed user profile lookups by returning a default unlinked profile', async () => {
+ jasmine.Ajax.stubRequest(/\/auth\/api\/V2\/me$/).andReturn({
+ status: 500,
+ statusText: 'error',
+ contentType: 'text/html',
+ responseHeaders: '',
+ responseText: 'error! no profile for you!'
+ });
+ const $dummyNode = $('
'),
+ stagingWidget = new StagingDataTab($dummyNode);
+ const userInfo = await stagingWidget.getUserInfo();
+ expect(userInfo).toEqual({user: fakeUser, globusLinked: false});
+ });
+
+ it('gets user info and parsed into whether or not the user is linked to globus', async () => {
+ const $dummyNode = $('
'),
+ stagingWidget = new StagingDataTab($dummyNode);
+ const userInfo = await stagingWidget.getUserInfo();
+ expect(userInfo).toEqual({user: fakeUser, globusLinked: true});
+ });
+
+ it('can update its path properly', async () => {
+ const $dummyNode = $('
'),
+ stagingWidget = new StagingDataTab($dummyNode);
+ await stagingWidget.render();
+ const newPath = 'a_new_path';
+ stagingWidget.updatePath(newPath);
+ expect(stagingWidget.path).toEqual(newPath);
+ });
+
+ it('can activate its staging area viewer', async () => {
+ const $dummyNode = $('
'),
+ stagingWidget = new StagingDataTab($dummyNode);
+ await stagingWidget.render();
+ spyOn(stagingWidget.stagingAreaViewer, 'activate');
+ stagingWidget.activate();
+ expect(stagingWidget.stagingAreaViewer.activate).toHaveBeenCalled();
+ });
+
+ it('can deactivate its staging area viewer', async () => {
+ const $dummyNode = $('
'),
+ stagingWidget = new StagingDataTab($dummyNode);
+ await stagingWidget.render();
+ spyOn(stagingWidget.stagingAreaViewer, 'deactivate');
+ stagingWidget.activate();
+ stagingWidget.deactivate();
+ expect(stagingWidget.stagingAreaViewer.deactivate).toHaveBeenCalled();
+ });
+
+ it('can be told to update its view', async () => {
+ jasmine.clock().install();
+
+ const $dummyNode = $('
'),
+ stagingWidget = new StagingDataTab($dummyNode);
+ await stagingWidget.render();
+ // kinda cheating - but to test that things are run, we know that this will call
+ // stagingAreaViewer.render
+ spyOn(stagingWidget.stagingAreaViewer, 'render');
+ stagingWidget.updateView();
+ jasmine.clock().tick(stagingWidget.minRefreshTime + 100);
+ expect(stagingWidget.stagingAreaViewer.render).toHaveBeenCalled();
+
+ jasmine.clock().uninstall();
+ });
+
+ it('can be triggered to update its view after a completed upload', async () => {
+ const $dummyNode = $('
'),
+ stagingWidget = new StagingDataTab($dummyNode);
+ await stagingWidget.render();
+ spyOn(stagingWidget, 'updateView');
+ // a little more cheating with implementation, this triggers the "upload complete" event
+ stagingWidget.uploadWidget.dropzone.emit('complete', {name: 'foo', size: 12345});
+ expect(stagingWidget.updateView).toHaveBeenCalled();
+ });
+
+ it('only updates its view once per interval on completed uploads', async () => {
+ jasmine.clock().install();
+
+ const $dummyNode = $('
'),
+ stagingWidget = new StagingDataTab($dummyNode);
+ await stagingWidget.render();
+ // run a bunch of triggers, should only call render on the staging area once
+ spyOn(stagingWidget.stagingAreaViewer, 'render');
+ for (let i = 0; i < 100; i++) {
+ stagingWidget.uploadWidget.dropzone.emit('complete', {name: 'foo', size: 12345});
+ }
+ jasmine.clock().tick(stagingWidget.minRefreshTime + 100);
+ expect(stagingWidget.stagingAreaViewer.render.calls.count()).toEqual(1);
+
+ jasmine.clock().uninstall();
});
});
});