Merge remote-tracking branch 'upstream/dev' into managers.history-contents

This commit is contained in:
carlfeberhard
2016-01-21 14:58:35 -05:00
262 changed files with 1955 additions and 2323 deletions
+1 -1
View File
@@ -86,7 +86,7 @@ tool-data/genome/*
tool-data/*.sample
tool-data/testtoolshed.g2.bx.psu.edu/
tool-data/toolshed.g2.bx.psu.edu/
tool-data/**/*.fa
# Test output
test-data-cache
+1 -1
View File
@@ -24,5 +24,5 @@ module.exports = function(grunt) {
// see the sub directory grunt-tasks/ for individual task definitions
grunt.loadTasks( 'grunt-tasks' );
// note: 'handlebars' *not* 'templates' since handlebars doesn't call uglify
grunt.registerTask( 'default', [ 'check-modules', 'handlebars', 'uglify' ] );
grunt.registerTask( 'default', [ 'check-modules', 'uglify', 'webpack' ] );
};
+19 -7
View File
@@ -46,19 +46,31 @@ This will:
1. compress the files in client/galaxy/scripts and place them in static/scripts
2. generate source maps and place them in static/maps
3. rebuild the webpack-based client apps
Templates
=========
Rebuilding Scripts Only
=======================
You can change and recompile the templates by using:
To re-minify all the individual javascript files:
grunt templates
grunt scripts
This will:
1. recompile the templates in client/galaxy/scripts/templates to client/galaxy/scripts/templates/compiled
2. minify and generate source maps for the compiled templates
Rebuilding Webpack Apps
=======================
To rebuild the webpack bundles for apps (compressed for production):
grunt webpack
To rebuild the apps without compression:
grunt webpack-dev
To rebuild without compression and watch and rebuild when scripts change:
grunt webpack-watch
Changing Styles/CSS
+1 -2
View File
@@ -14,7 +14,7 @@
"underscore": "~1.7.0",
"backbone": "~1.1.2",
"bootstrap": "~3.3.2",
"bootstrap-tour":"~0.10.2",
"bootstrap-tour": "~0.10.2",
"d3": "~3.5.3",
"farbtastic": "~2.0.0-alpha.1",
"toastr": "~2.1.0",
@@ -31,7 +31,6 @@
"jstree": "~3.0.9",
"jquery-ui": "git://github.com/jquery/jquery-ui.git#~1.11.2",
"threedubmedia.jquery.event": "*",
"handlebars": "~3.0.0",
"jquery-migrate": "~1.2.1",
"requirejs": "~2.1.17"
},
-1
View File
@@ -30,7 +30,6 @@ window.app = function app( options, bootstrapped ){
toolPanel = new ToolPanel({
el : '#left',
userIsAnonymous : Galaxy.user.isAnonymous(),
spinner_url : config.spinner_url,
search_url : config.search_url,
toolbox : config.toolbox,
toolbox_in_panel : config.toolbox_in_panel,
-1
View File
@@ -17,7 +17,6 @@ var ToolPanel = LeftPanel.extend({
// create tool search, tool panel, and tool panel view.
var tool_search = new Tools.ToolSearch({
spinner_url : options.spinner_url,
search_url : options.search_url,
hidden : false
});
+61 -79
View File
@@ -173,7 +173,7 @@ var Collection = Backbone.Collection.extend({
if ( !Galaxy.user.id ){
var userTab = {
id : 'user',
icon : 'fa-user',
title : 'User',
cls : 'loggedout-only',
tooltip : 'Account registration or login',
menu : [{
@@ -191,7 +191,7 @@ var Collection = Backbone.Collection.extend({
} else {
var userTab = {
id : 'user',
icon : 'fa-user',
title : 'User',
cls : 'loggedin-only',
tooltip : 'Account preferences and saved data',
menu : [{
@@ -243,77 +243,64 @@ var Collection = Backbone.Collection.extend({
/** Masthead tab **/
var Tab = Backbone.View.extend({
initialize: function ( options ) {
var self = this;
this.model = options.model;
this.setElement( this._template() );
this.$dropdown = this.$( '.dropdown' );
this.$toggle = this.$( '.dropdown-toggle' );
this.$menu = this.$( '.dropdown-menu' );
this.$note = this.$( '.dropdown-note' );
this.model = options.model;
this.$el.attr( 'id', this.model.id );
this.model.on( 'init change:title', function() {
this.get( 'title' ) && self.$toggle.html( this.get( 'title' ) );
}).on( 'init change:visible', function() {
self.$el.css( { visibility : this.get( 'visible' ) && 'visible' || 'hidden' } );
}).on( 'init change:note', function() {
self.$note.html( this.get( 'note' ) );
}).on( 'init change:note_cls', function() {
this._prevNoteCls && self.$note.removeClass( this._prevNoteCls );
this.get( 'note_cls' ) && self.$note.addClass( this._prevNoteCls = this.get( 'note_cls' ) );
}).on( 'init change:show_note', function() {
self.$note.css( { 'display' : this.get( 'show_note' ) && 'block' || 'none' } );
}).on( 'init change:target', function() {
self.$toggle.attr( 'target', this.get( 'target' ) );
}).on( 'init change:url', function() {
this.set( 'url', self._formatUrl( this.get( 'url' ) ) );
self.$toggle.attr( 'href', this.get( 'url' ) );
}).on( 'init change:tooltip', function() {
$( '.tooltip' ).remove();
self.$toggle.tooltip( 'destroy' ).attr( 'title', this.get( 'tooltip' ) );
this.get( 'tooltip' ) && self.$toggle.tooltip( { placement: 'bottom' } );
}).on( 'init change:cls', function() {
this._prevCls && self.$toggle.removeClass( this._prevCls );
this.get( 'cls' ) && self.$toggle.addClass( this._prevCls = this.get( 'cls' ) );
}).on( 'init change:icon', function() {
this._prevIcon && self.$toggle.removeClass( this._prevIcon );
this.get( 'icon' ) && self.$toggle.addClass( this._prevIcon = 'fa fa-2x ' + this.get( 'icon' ) );
}).on( 'init change:toggle', function() {
self.$toggle[ this.get( 'toggle' ) && 'addClass' || 'removeClass' ]( 'toggle' );
}).on( 'init change:disabled', function() {
self.$toggle[ this.get( 'disabled' ) && 'addClass' || 'removeClass' ]( 'disabled' );
self._configurePopover();
}).on( 'init change:active', function() {
self.$dropdown[ this.get( 'active' ) && 'addClass' || 'removeClass' ]( 'active' );
}).on( 'init change:show_menu', function() {
if ( this.get( 'menu' ) && this.get( 'show_menu' ) ) {
self.$menu.show();
$( '#dd-helper' ).show().off().on( 'click', function() {
$( '#dd-helper' ).hide();
self.model.set( 'show_menu', false );
});
} else {
self.$menu.hide();
$( '#dd-helper' ).hide();
}
}).on( 'init change:menu', function() {
self.$menu.empty().removeClass( 'dropdown-menu' );
self.$toggle.find( 'b' ).remove();
if ( this.get( 'menu' ) ) {
_.each( this.get( 'menu' ), function( menuItem ) {
self.$menu.append( self._buildMenuItem( menuItem ) );
menuItem.divider && self.$menu.append( $( '<li/>' ).addClass( 'divider' ) );
});
self.$menu.addClass( 'dropdown-menu' );
self.$toggle.append( $( '<b/>' ).addClass( 'caret' ) );
}
}).trigger( 'init' );
this.listenTo( this.model, 'change', this.render, this );
},
/** Attach events */
events: {
'click .dropdown-toggle' : '_toggleClick'
},
render: function() {
var self = this;
$( '.tooltip' ).remove();
this.$el.attr( 'id', this.model.id )
.css( { visibility : this.model.get( 'visible' ) && 'visible' || 'hidden' } );
this.model.set( 'url', this._formatUrl( this.model.get( 'url' ) ) );
this.$note.html( this.model.get( 'note' ) || '' )
.removeClass().addClass( 'dropdown-note' )
.addClass( this.model.get( 'note_cls' ) )
.css( { 'display' : this.model.get( 'show_note' ) && 'block' || 'none' } )
this.$toggle.html( this.model.get( 'title' ) || '' )
.removeClass().addClass( 'dropdown-toggle' )
.addClass( this.model.get( 'cls' ) )
.addClass( this.model.get( 'icon' ) && 'fa fa-2x ' + this.model.get( 'icon' ) )
.addClass( this.model.get( 'toggle' ) && 'toggle' )
.attr( 'target', this.model.get( 'target' ) )
.attr( 'href', this.model.get( 'url' ) )
.attr( 'title', this.model.get( 'tooltip' ) )
.tooltip( 'destroy' );
this.model.get( 'tooltip' ) && this.$toggle.tooltip( { placement: 'bottom' } );
this.$dropdown.removeClass().addClass( 'dropdown' )
.addClass( this.model.get( 'disabled' ) && 'disabled' )
.addClass( this.model.get( 'active' ) && 'active' );
if ( this.model.get( 'menu' ) && this.model.get( 'show_menu' ) ) {
this.$menu.show();
$( '#dd-helper' ).show().off().on( 'click', function() {
$( '#dd-helper' ).hide();
self.model.set( 'show_menu', false );
});
} else {
self.$menu.hide();
$( '#dd-helper' ).hide();
}
this.$menu.empty().removeClass( 'dropdown-menu' );
if ( this.model.get( 'menu' ) ) {
_.each( this.model.get( 'menu' ), function( menuItem ) {
self.$menu.append( self._buildMenuItem( menuItem ) );
menuItem.divider && self.$menu.append( $( '<li/>' ).addClass( 'divider' ) );
});
self.$menu.addClass( 'dropdown-menu' );
self.$toggle.append( $( '<b/>' ).addClass( 'caret' ) );
}
return this;
},
/** Add new menu item */
_buildMenuItem: function ( options ) {
var self = this;
@@ -354,26 +341,21 @@ var Tab = Backbone.View.extend({
} else {
model.set( 'show_menu', true );
}
} else {
function buildLink( label, url ) {
return $( '<div/>' ).append( $( '<a/>' ).attr( 'href', Galaxy.root + url ).html( label ) ).html()
}
this.$toggle.popover && this.$toggle.popover( 'destroy' );
this.$toggle.popover({
html : true,
placement : 'bottom',
content : 'Please ' + buildLink( 'login', 'user/login?use_panels=True' ) + ' or ' +
buildLink( 'register', 'user/create?use_panels=True' ) + ' to use this feature.'
}).popover( 'show' );
setTimeout( function() { self.$toggle.popover( 'destroy' ) }, 5000 );
}
},
/** Configures login notification/popover */
_configurePopover: function() {
var self = this;
function buildLink( label, url ) {
return $( '<div/>' ).append( $( '<a/>' ).attr( 'href', Galaxy.root + url ).html( label ) ).html()
}
this.$toggle.popover && this.$toggle.popover( 'destroy' );
this.model.get( 'disabled' ) && this.$toggle.popover({
html : true,
placement : 'bottom',
content : 'Please ' + buildLink( 'login', 'user/login?use_panels=True' ) + ' or ' +
buildLink( 'register', 'user/create?use_panels=True' ) + ' to use this feature.'
}).on( 'shown.bs.popover', function() {
setTimeout( function() { self.$toggle.popover( 'hide' ) }, 5000 );
});
},
/** Url formatting */
_formatUrl: function( url ) {
return typeof url == 'string' && url.indexOf( '//' ) === -1 && url.charAt( 0 ) != '/' ? Galaxy.root + url : url;
@@ -1,881 +0,0 @@
/*!
handlebars v3.0.3
Copyright (C) 2011-2014 by Yehuda Katz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@license
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define(factory);
else if(typeof exports === 'object')
exports["Handlebars"] = factory();
else
root["Handlebars"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var _interopRequireWildcard = __webpack_require__(7)['default'];
exports.__esModule = true;
var _import = __webpack_require__(1);
var base = _interopRequireWildcard(_import);
// Each of these augment the Handlebars object. No need to setup here.
// (This is done to easily share code between commonjs and browse envs)
var _SafeString = __webpack_require__(2);
var _SafeString2 = _interopRequireWildcard(_SafeString);
var _Exception = __webpack_require__(3);
var _Exception2 = _interopRequireWildcard(_Exception);
var _import2 = __webpack_require__(4);
var Utils = _interopRequireWildcard(_import2);
var _import3 = __webpack_require__(5);
var runtime = _interopRequireWildcard(_import3);
var _noConflict = __webpack_require__(6);
var _noConflict2 = _interopRequireWildcard(_noConflict);
// For compatibility and usage outside of module systems, make the Handlebars object a namespace
function create() {
var hb = new base.HandlebarsEnvironment();
Utils.extend(hb, base);
hb.SafeString = _SafeString2['default'];
hb.Exception = _Exception2['default'];
hb.Utils = Utils;
hb.escapeExpression = Utils.escapeExpression;
hb.VM = runtime;
hb.template = function (spec) {
return runtime.template(spec, hb);
};
return hb;
}
var inst = create();
inst.create = create;
_noConflict2['default'](inst);
inst['default'] = inst;
exports['default'] = inst;
module.exports = exports['default'];
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var _interopRequireWildcard = __webpack_require__(7)['default'];
exports.__esModule = true;
exports.HandlebarsEnvironment = HandlebarsEnvironment;
exports.createFrame = createFrame;
var _import = __webpack_require__(4);
var Utils = _interopRequireWildcard(_import);
var _Exception = __webpack_require__(3);
var _Exception2 = _interopRequireWildcard(_Exception);
var VERSION = '3.0.1';
exports.VERSION = VERSION;
var COMPILER_REVISION = 6;
exports.COMPILER_REVISION = COMPILER_REVISION;
var REVISION_CHANGES = {
1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
2: '== 1.0.0-rc.3',
3: '== 1.0.0-rc.4',
4: '== 1.x.x',
5: '== 2.0.0-alpha.x',
6: '>= 2.0.0-beta.1'
};
exports.REVISION_CHANGES = REVISION_CHANGES;
var isArray = Utils.isArray,
isFunction = Utils.isFunction,
toString = Utils.toString,
objectType = '[object Object]';
function HandlebarsEnvironment(helpers, partials) {
this.helpers = helpers || {};
this.partials = partials || {};
registerDefaultHelpers(this);
}
HandlebarsEnvironment.prototype = {
constructor: HandlebarsEnvironment,
logger: logger,
log: log,
registerHelper: function registerHelper(name, fn) {
if (toString.call(name) === objectType) {
if (fn) {
throw new _Exception2['default']('Arg not supported with multiple helpers');
}
Utils.extend(this.helpers, name);
} else {
this.helpers[name] = fn;
}
},
unregisterHelper: function unregisterHelper(name) {
delete this.helpers[name];
},
registerPartial: function registerPartial(name, partial) {
if (toString.call(name) === objectType) {
Utils.extend(this.partials, name);
} else {
if (typeof partial === 'undefined') {
throw new _Exception2['default']('Attempting to register a partial as undefined');
}
this.partials[name] = partial;
}
},
unregisterPartial: function unregisterPartial(name) {
delete this.partials[name];
}
};
function registerDefaultHelpers(instance) {
instance.registerHelper('helperMissing', function () {
if (arguments.length === 1) {
// A missing field in a {{foo}} constuct.
return undefined;
} else {
// Someone is actually trying to call something, blow up.
throw new _Exception2['default']('Missing helper: "' + arguments[arguments.length - 1].name + '"');
}
});
instance.registerHelper('blockHelperMissing', function (context, options) {
var inverse = options.inverse,
fn = options.fn;
if (context === true) {
return fn(this);
} else if (context === false || context == null) {
return inverse(this);
} else if (isArray(context)) {
if (context.length > 0) {
if (options.ids) {
options.ids = [options.name];
}
return instance.helpers.each(context, options);
} else {
return inverse(this);
}
} else {
if (options.data && options.ids) {
var data = createFrame(options.data);
data.contextPath = Utils.appendContextPath(options.data.contextPath, options.name);
options = { data: data };
}
return fn(context, options);
}
});
instance.registerHelper('each', function (context, options) {
if (!options) {
throw new _Exception2['default']('Must pass iterator to #each');
}
var fn = options.fn,
inverse = options.inverse,
i = 0,
ret = '',
data = undefined,
contextPath = undefined;
if (options.data && options.ids) {
contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.';
}
if (isFunction(context)) {
context = context.call(this);
}
if (options.data) {
data = createFrame(options.data);
}
function execIteration(field, index, last) {
if (data) {
data.key = field;
data.index = index;
data.first = index === 0;
data.last = !!last;
if (contextPath) {
data.contextPath = contextPath + field;
}
}
ret = ret + fn(context[field], {
data: data,
blockParams: Utils.blockParams([context[field], field], [contextPath + field, null])
});
}
if (context && typeof context === 'object') {
if (isArray(context)) {
for (var j = context.length; i < j; i++) {
execIteration(i, i, i === context.length - 1);
}
} else {
var priorKey = undefined;
for (var key in context) {
if (context.hasOwnProperty(key)) {
// We're running the iterations one step out of sync so we can detect
// the last iteration without have to scan the object twice and create
// an itermediate keys array.
if (priorKey) {
execIteration(priorKey, i - 1);
}
priorKey = key;
i++;
}
}
if (priorKey) {
execIteration(priorKey, i - 1, true);
}
}
}
if (i === 0) {
ret = inverse(this);
}
return ret;
});
instance.registerHelper('if', function (conditional, options) {
if (isFunction(conditional)) {
conditional = conditional.call(this);
}
// Default behavior is to render the positive path if the value is truthy and not empty.
// The `includeZero` option may be set to treat the condtional as purely not empty based on the
// behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative.
if (!options.hash.includeZero && !conditional || Utils.isEmpty(conditional)) {
return options.inverse(this);
} else {
return options.fn(this);
}
});
instance.registerHelper('unless', function (conditional, options) {
return instance.helpers['if'].call(this, conditional, { fn: options.inverse, inverse: options.fn, hash: options.hash });
});
instance.registerHelper('with', function (context, options) {
if (isFunction(context)) {
context = context.call(this);
}
var fn = options.fn;
if (!Utils.isEmpty(context)) {
if (options.data && options.ids) {
var data = createFrame(options.data);
data.contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]);
options = { data: data };
}
return fn(context, options);
} else {
return options.inverse(this);
}
});
instance.registerHelper('log', function (message, options) {
var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
instance.log(level, message);
});
instance.registerHelper('lookup', function (obj, field) {
return obj && obj[field];
});
}
var logger = {
methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' },
// State enum
DEBUG: 0,
INFO: 1,
WARN: 2,
ERROR: 3,
level: 1,
// Can be overridden in the host environment
log: function log(level, message) {
if (typeof console !== 'undefined' && logger.level <= level) {
var method = logger.methodMap[level];
(console[method] || console.log).call(console, message); // eslint-disable-line no-console
}
}
};
exports.logger = logger;
var log = logger.log;
exports.log = log;
function createFrame(object) {
var frame = Utils.extend({}, object);
frame._parent = object;
return frame;
}
/* [args, ]options */
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
// Build out our basic SafeString type
function SafeString(string) {
this.string = string;
}
SafeString.prototype.toString = SafeString.prototype.toHTML = function () {
return '' + this.string;
};
exports['default'] = SafeString;
module.exports = exports['default'];
/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
function Exception(message, node) {
var loc = node && node.loc,
line = undefined,
column = undefined;
if (loc) {
line = loc.start.line;
column = loc.start.column;
message += ' - ' + line + ':' + column;
}
var tmp = Error.prototype.constructor.call(this, message);
// Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
for (var idx = 0; idx < errorProps.length; idx++) {
this[errorProps[idx]] = tmp[errorProps[idx]];
}
if (Error.captureStackTrace) {
Error.captureStackTrace(this, Exception);
}
if (loc) {
this.lineNumber = line;
this.column = column;
}
}
Exception.prototype = new Error();
exports['default'] = Exception;
module.exports = exports['default'];
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
exports.extend = extend;
// Older IE versions do not directly support indexOf so we must implement our own, sadly.
exports.indexOf = indexOf;
exports.escapeExpression = escapeExpression;
exports.isEmpty = isEmpty;
exports.blockParams = blockParams;
exports.appendContextPath = appendContextPath;
var escape = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
'\'': '&#x27;',
'`': '&#x60;'
};
var badChars = /[&<>"'`]/g,
possible = /[&<>"'`]/;
function escapeChar(chr) {
return escape[chr];
}
function extend(obj /* , ...source */) {
for (var i = 1; i < arguments.length; i++) {
for (var key in arguments[i]) {
if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
obj[key] = arguments[i][key];
}
}
}
return obj;
}
var toString = Object.prototype.toString;
exports.toString = toString;
// Sourced from lodash
// https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
/*eslint-disable func-style, no-var */
var isFunction = function isFunction(value) {
return typeof value === 'function';
};
// fallback for older versions of Chrome and Safari
/* istanbul ignore next */
if (isFunction(/x/)) {
exports.isFunction = isFunction = function (value) {
return typeof value === 'function' && toString.call(value) === '[object Function]';
};
}
var isFunction;
exports.isFunction = isFunction;
/*eslint-enable func-style, no-var */
/* istanbul ignore next */
var isArray = Array.isArray || function (value) {
return value && typeof value === 'object' ? toString.call(value) === '[object Array]' : false;
};exports.isArray = isArray;
function indexOf(array, value) {
for (var i = 0, len = array.length; i < len; i++) {
if (array[i] === value) {
return i;
}
}
return -1;
}
function escapeExpression(string) {
if (typeof string !== 'string') {
// don't escape SafeStrings, since they're already safe
if (string && string.toHTML) {
return string.toHTML();
} else if (string == null) {
return '';
} else if (!string) {
return string + '';
}
// Force a string conversion as this will be done by the append regardless and
// the regex test will do this transparently behind the scenes, causing issues if
// an object's to string has escaped characters in it.
string = '' + string;
}
if (!possible.test(string)) {
return string;
}
return string.replace(badChars, escapeChar);
}
function isEmpty(value) {
if (!value && value !== 0) {
return true;
} else if (isArray(value) && value.length === 0) {
return true;
} else {
return false;
}
}
function blockParams(params, ids) {
params.path = ids;
return params;
}
function appendContextPath(contextPath, id) {
return (contextPath ? contextPath + '.' : '') + id;
}
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var _interopRequireWildcard = __webpack_require__(7)['default'];
exports.__esModule = true;
exports.checkRevision = checkRevision;
// TODO: Remove this line and break up compilePartial
exports.template = template;
exports.wrapProgram = wrapProgram;
exports.resolvePartial = resolvePartial;
exports.invokePartial = invokePartial;
exports.noop = noop;
var _import = __webpack_require__(4);
var Utils = _interopRequireWildcard(_import);
var _Exception = __webpack_require__(3);
var _Exception2 = _interopRequireWildcard(_Exception);
var _COMPILER_REVISION$REVISION_CHANGES$createFrame = __webpack_require__(1);
function checkRevision(compilerInfo) {
var compilerRevision = compilerInfo && compilerInfo[0] || 1,
currentRevision = _COMPILER_REVISION$REVISION_CHANGES$createFrame.COMPILER_REVISION;
if (compilerRevision !== currentRevision) {
if (compilerRevision < currentRevision) {
var runtimeVersions = _COMPILER_REVISION$REVISION_CHANGES$createFrame.REVISION_CHANGES[currentRevision],
compilerVersions = _COMPILER_REVISION$REVISION_CHANGES$createFrame.REVISION_CHANGES[compilerRevision];
throw new _Exception2['default']('Template was precompiled with an older version of Handlebars than the current runtime. ' + 'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').');
} else {
// Use the embedded version info since the runtime doesn't know about this revision yet
throw new _Exception2['default']('Template was precompiled with a newer version of Handlebars than the current runtime. ' + 'Please update your runtime to a newer version (' + compilerInfo[1] + ').');
}
}
}
function template(templateSpec, env) {
/* istanbul ignore next */
if (!env) {
throw new _Exception2['default']('No environment passed to template');
}
if (!templateSpec || !templateSpec.main) {
throw new _Exception2['default']('Unknown template object: ' + typeof templateSpec);
}
// Note: Using env.VM references rather than local var references throughout this section to allow
// for external users to override these as psuedo-supported APIs.
env.VM.checkRevision(templateSpec.compiler);
function invokePartialWrapper(partial, context, options) {
if (options.hash) {
context = Utils.extend({}, context, options.hash);
}
partial = env.VM.resolvePartial.call(this, partial, context, options);
var result = env.VM.invokePartial.call(this, partial, context, options);
if (result == null && env.compile) {
options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env);
result = options.partials[options.name](context, options);
}
if (result != null) {
if (options.indent) {
var lines = result.split('\n');
for (var i = 0, l = lines.length; i < l; i++) {
if (!lines[i] && i + 1 === l) {
break;
}
lines[i] = options.indent + lines[i];
}
result = lines.join('\n');
}
return result;
} else {
throw new _Exception2['default']('The partial ' + options.name + ' could not be compiled when running in runtime-only mode');
}
}
// Just add water
var container = {
strict: function strict(obj, name) {
if (!(name in obj)) {
throw new _Exception2['default']('"' + name + '" not defined in ' + obj);
}
return obj[name];
},
lookup: function lookup(depths, name) {
var len = depths.length;
for (var i = 0; i < len; i++) {
if (depths[i] && depths[i][name] != null) {
return depths[i][name];
}
}
},
lambda: function lambda(current, context) {
return typeof current === 'function' ? current.call(context) : current;
},
escapeExpression: Utils.escapeExpression,
invokePartial: invokePartialWrapper,
fn: function fn(i) {
return templateSpec[i];
},
programs: [],
program: function program(i, data, declaredBlockParams, blockParams, depths) {
var programWrapper = this.programs[i],
fn = this.fn(i);
if (data || depths || blockParams || declaredBlockParams) {
programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths);
} else if (!programWrapper) {
programWrapper = this.programs[i] = wrapProgram(this, i, fn);
}
return programWrapper;
},
data: function data(value, depth) {
while (value && depth--) {
value = value._parent;
}
return value;
},
merge: function merge(param, common) {
var obj = param || common;
if (param && common && param !== common) {
obj = Utils.extend({}, common, param);
}
return obj;
},
noop: env.VM.noop,
compilerInfo: templateSpec.compiler
};
function ret(context) {
var options = arguments[1] === undefined ? {} : arguments[1];
var data = options.data;
ret._setup(options);
if (!options.partial && templateSpec.useData) {
data = initData(context, data);
}
var depths = undefined,
blockParams = templateSpec.useBlockParams ? [] : undefined;
if (templateSpec.useDepths) {
depths = options.depths ? [context].concat(options.depths) : [context];
}
return templateSpec.main.call(container, context, container.helpers, container.partials, data, blockParams, depths);
}
ret.isTop = true;
ret._setup = function (options) {
if (!options.partial) {
container.helpers = container.merge(options.helpers, env.helpers);
if (templateSpec.usePartial) {
container.partials = container.merge(options.partials, env.partials);
}
} else {
container.helpers = options.helpers;
container.partials = options.partials;
}
};
ret._child = function (i, data, blockParams, depths) {
if (templateSpec.useBlockParams && !blockParams) {
throw new _Exception2['default']('must pass block params');
}
if (templateSpec.useDepths && !depths) {
throw new _Exception2['default']('must pass parent depths');
}
return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths);
};
return ret;
}
function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) {
function prog(context) {
var options = arguments[1] === undefined ? {} : arguments[1];
return fn.call(container, context, container.helpers, container.partials, options.data || data, blockParams && [options.blockParams].concat(blockParams), depths && [context].concat(depths));
}
prog.program = i;
prog.depth = depths ? depths.length : 0;
prog.blockParams = declaredBlockParams || 0;
return prog;
}
function resolvePartial(partial, context, options) {
if (!partial) {
partial = options.partials[options.name];
} else if (!partial.call && !options.name) {
// This is a dynamic partial that returned a string
options.name = partial;
partial = options.partials[partial];
}
return partial;
}
function invokePartial(partial, context, options) {
options.partial = true;
if (partial === undefined) {
throw new _Exception2['default']('The partial ' + options.name + ' could not be found');
} else if (partial instanceof Function) {
return partial(context, options);
}
}
function noop() {
return '';
}
function initData(context, data) {
if (!data || !('root' in data)) {
data = data ? _COMPILER_REVISION$REVISION_CHANGES$createFrame.createFrame(data) : {};
data.root = context;
}
return data;
}
/***/ },
/* 6 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global) {'use strict';
exports.__esModule = true;
/*global window */
exports['default'] = function (Handlebars) {
/* istanbul ignore next */
var root = typeof global !== 'undefined' ? global : window,
$Handlebars = root.Handlebars;
/* istanbul ignore next */
Handlebars.noConflict = function () {
if (root.Handlebars === Handlebars) {
root.Handlebars = $Handlebars;
}
};
};
module.exports = exports['default'];
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
/***/ },
/* 7 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
exports["default"] = function (obj) {
return obj && obj.__esModule ? obj : {
"default": obj
};
};
exports.__esModule = true;
/***/ }
/******/ ])
});
;
+3
View File
@@ -4,6 +4,9 @@ define([
'utils/add-logging',
'utils/localization'
], function( _, Backbone, addLogging, _l ){
'use strict';
//==============================================================================
/** @class Mixin to add logging capabilities to an object.
* Designed to allow switching an objects log output off/on at one central
@@ -4,7 +4,8 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( DC_LI, DATASET_LI_EDIT, BASE_MVC, _l ){
/* global Backbone */
'use strict';
//==============================================================================
var DCListItemView = DC_LI.DCListItemView;
/** @class Edit view for DatasetCollection.
@@ -4,7 +4,8 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( LIST_ITEM, DATASET_LI, BASE_MVC, _l ){
/* global Backbone */
'use strict';
//==============================================================================
var FoldoutListItemView = LIST_ITEM.FoldoutListItemView,
ListItemView = LIST_ITEM.ListItemView;
@@ -33,11 +34,11 @@ var DCListItemView = FoldoutListItemView.extend(
_setUpListeners : function(){
FoldoutListItemView.prototype._setUpListeners.call( this );
// re-rendering on deletion
this.model.on( 'change', function( model, options ){
this.listenTo( this.model, 'change', function( model, options ){
if( _.isEqual( _.keys( model.changed ), [ 'deleted' ] ) ){
this.render();
}
}, this );
});
},
// ......................................................................... rendering
@@ -4,6 +4,8 @@ define([
"utils/localization"
], function( DATASET_MODEL, BASE_MVC, _l ){
'use strict';
var logNamespace = 'collections';
//==============================================================================
/*
@@ -6,6 +6,8 @@ define([
"utils/localization",
"ui/editable-text",
], function( DC_VIEW, DC_MODEL, DC_EDIT, BASE_MVC, _l ){
'use strict';
/* =============================================================================
TODO:
@@ -6,6 +6,8 @@ define([
"utils/localization"
], function( LIST_VIEW, DC_MODEL, DC_LI, BASE_MVC, _l ){
'use strict';
var logNamespace = 'collections';
/* =============================================================================
TODO:
@@ -83,12 +85,14 @@ var CollectionView = _super.extend(
_super.prototype._setUpItemViewListeners.call( panel, view );
// use pub-sub to: handle drilldown expansion and collapse
view.on( 'expanded:drilldown', function( v, drilldown ){
this._expandDrilldownPanel( drilldown );
}, this );
view.on( 'collapsed:drilldown', function( v, drilldown ){
this._collapseDrilldownPanel( drilldown );
}, this );
panel.listenTo( view, {
'expanded:drilldown': function( v, drilldown ){
this._expandDrilldownPanel( drilldown );
},
'collapsed:drilldown': function( v, drilldown ){
this._collapseDrilldownPanel( drilldown );
}
});
return this;
},
@@ -9,6 +9,8 @@ define([
"ui/hoverhighlight"
], function( HDCA, STATES, BASE_MVC, UI_MODAL, naturalSort, _l ){
'use strict';
var logNamespace = 'collections';
/*==============================================================================
TODO:
@@ -7,6 +7,8 @@ define([
"ui/hoverhighlight"
], function( levenshteinDistance, naturalSort, LIST_COLLECTION_CREATOR, baseMVC, _l ){
'use strict';
var logNamespace = 'collections';
/* ============================================================================
TODO:
@@ -5,6 +5,8 @@ define([
"utils/localization"
], function( LIST_CREATOR, HDCA, BASE_MVC, _l ){
'use strict';
var logNamespace = 'collections';
/*==============================================================================
TODO:
@@ -5,6 +5,7 @@ define([
'mvc/base-mvc',
'utils/localization'
], function( DATASET, DATASET_LIST, MODAL, BASE_MVC, _l ){
'use strict';
var logNamespace = 'dataset';
/* ============================================================================
@@ -7,6 +7,8 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( STATES, DATASET_LI, TAGS, ANNOTATIONS, faIconButton, BASE_MVC, _l ){
'use strict';
//==============================================================================
var _super = DATASET_LI.DatasetListItemView;
/** @class Editing view for DatasetAssociation.
@@ -5,7 +5,7 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( LIST_ITEM, STATES, faIconButton, BASE_MVC, _l ){
/* global Backbone */
'use strict';
var logNamespace = 'dataset';
/*==============================================================================
@@ -44,7 +44,7 @@ var DatasetListItemView = _super.extend(
_super.prototype._setUpListeners.call( this );
// re-rendering on any model changes
this.model.on( 'change', function( model, options ){
this.listenTo( this.model, 'change', function( model, options ){
// if the model moved into the ready state and is expanded without details, fetch those details now
if( this.model.changedAttributes().state && this.model.inReadyState()
&& this.expanded && !this.model.hasDetails() ){
@@ -54,7 +54,7 @@ var DatasetListItemView = _super.extend(
} else {
this.render();
}
}, this );
});
},
// ......................................................................... expandable
@@ -4,6 +4,7 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( LIST_VIEW, DATASET_LI, BASE_MVC, _l ){
'use strict';
var logNamespace = 'dataset';
/* =============================================================================
@@ -3,6 +3,7 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( STATES, BASE_MVC, _l ){
'use strict';
var logNamespace = 'dataset';
//==============================================================================
@@ -1,5 +1,7 @@
define([
], function(){
'use strict';
//==============================================================================
/** Map of possible HDA/collection/job states to their string equivalents.
* A port of galaxy.model.Dataset.states.
+6 -6
View File
@@ -31,14 +31,14 @@ define([ 'utils/utils' ], function( Utils ) {
var dict = {};
this._iterate( this.app.section.$el, dict );
// add to result dictionary
// add to result dictionary, label elements
var result_dict = {};
this.flat_dict = {};
function add( flat_id, input_id, input_value ) {
self.flat_dict[ flat_id ] = input_id;
result_dict[ flat_id ] = input_value;
};
self.app.element_list[ input_id ] && self.app.element_list[ input_id ].$el.attr( 'tour_id', flat_id );
}
// converter between raw dictionary and job dictionary
function convert( identifier, head ) {
for ( var index in head ) {
@@ -73,7 +73,7 @@ define([ 'utils/utils' ], function( Utils ) {
break;
case 'conditional':
var value = self.app.field_list[ input.id ].value();
add ( flat_id + '|' + input.test_param.name, input.id, value );
add( flat_id + '|' + input.test_param.name, input.id, value );
var selectedCase = matchCase( input, value );
if ( selectedCase != -1 ) {
convert( flat_id, head[ input.id + '-section-' + selectedCase ] );
@@ -90,10 +90,10 @@ define([ 'utils/utils' ], function( Utils ) {
if ( field.collapsed && input.collapsible_value ) {
value = input.collapsible_value;
}
add ( flat_id, input.id, value );
add( flat_id, input.id, value );
if ( input.payload ) {
for ( var p_id in input.payload ) {
add ( p_id, input.id, input.payload[ p_id ] );
add( p_id, input.id, input.payload[ p_id ] );
}
}
}
+1 -1
View File
@@ -92,7 +92,7 @@ define([], function() {
/** Main Template
*/
_template: function(options) {
var tmp = '<div class="ui-form-element input-name-' + options.name + '">' +
var tmp = '<div class="ui-form-element">' +
'<div class="ui-form-error ui-error">' +
'<span class="fa fa-arrow-down"/><span class="ui-form-error-text"/>' +
'</div>' +
@@ -179,14 +179,13 @@ define(['utils/utils',
}
}
}
// create input element
var self = this;
return new Ui.Input({
id : 'field-' + input_def.id,
area : input_def.area,
onchange : function() {
self.app.trigger('change');
onchange : function( new_value ) {
input_def.onchange ? input_def.onchange( new_value ) : self.app.trigger( 'change' );
}
});
},
@@ -5,9 +5,8 @@ define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc']
/** This class creates a ui component which enables the dynamic creation of portlets
*/
var View = Backbone.View.extend({
/** Initialize
*/
initialize : function(options) {
var self = this;
this.options = Utils.merge(options, {
title : 'Section',
empty_text : 'Not available.',
@@ -15,13 +14,12 @@ var View = Backbone.View.extend({
min : null
});
this.setElement('<div/>');
var self = this;
// create button
this.button_new = new Ui.ButtonIcon({
icon : 'fa-plus',
title : 'Insert ' + options.title_new,
tooltip : 'Add new ' + options.title_new + ' block',
title : 'Insert ' + this.options.title_new,
tooltip : 'Add new ' + this.options.title_new + ' block',
floating: 'clear',
onclick : function() {
if (options.onnew) {
+1 -1
View File
@@ -190,7 +190,7 @@ define(['utils/utils', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc', 'mvc/form/form-sec
});
// append message
this.portlet.append(this.message.$el.addClass('ui-margin-top'));
this.portlet.append(this.message.$el);
// append tool section
this.portlet.append(this.section.$el);
@@ -3,7 +3,8 @@ define([
"utils/localization"
], function( MODAL, _l ){
"use strict";
'use strict';
//==============================================================================
/**
* A dialog/modal that allows copying a user history or 'importing' from user
@@ -4,6 +4,9 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( DATASET_LI_EDIT, HDA_LI, BASE_MVC, _l ){
'use strict';
//==============================================================================
var _super = DATASET_LI_EDIT.DatasetListItemEdit;
/** @class Editing view for HistoryDatasetAssociation.
+3 -1
View File
@@ -3,7 +3,9 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( DATASET_LI, BASE_MVC, _l ){
/* global Backbone */
'use strict';
//==============================================================================
var _super = DATASET_LI.DatasetListItemView;
/** @class Read only view for HistoryDatasetAssociation.
@@ -4,6 +4,9 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( DATASET, HISTORY_CONTENT, BASE_MVC, _l ){
'use strict';
//==============================================================================
var _super = DATASET.DatasetAssociation,
hcontentMixin = HISTORY_CONTENT.HistoryContentMixin;
@@ -4,6 +4,9 @@ define([
"ui/fa-icon-button",
"utils/localization"
], function( HDCA_LI, DC_VIEW_EDIT, faIconButton, _l ){
'use strict';
//==============================================================================
var _super = HDCA_LI.HDCAListItemView;
/** @class Editing view for HistoryDatasetCollectionAssociation.
+5 -3
View File
@@ -5,7 +5,9 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( STATES, DC_LI, DC_VIEW, BASE_MVC, _l ){
/* global Backbone */
'use strict';
//==============================================================================
var _super = DC_LI.DCListItemView;
/** @class Read only view for HistoryDatasetCollectionAssociation (a dataset collection inside a history).
@@ -22,9 +24,9 @@ var HDCAListItemView = _super.extend(
_setUpListeners : function(){
_super.prototype._setUpListeners.call( this );
this.model.on({
this.listenTo( this.model, {
'change:populated change:visible' : function( model, options ){ this.render(); },
}, this );
});
},
/** Override to provide the proper collections panels as the foldout */
@@ -3,6 +3,9 @@ define([
"mvc/history/history-content-model",
"utils/localization"
], function( DC_MODEL, HISTORY_CONTENT, _l ){
'use strict';
/*==============================================================================
Models for DatasetCollections contained within a history.
@@ -4,6 +4,8 @@ define([
"utils/localization"
], function( STATES, BASE_MVC, _l ){
'use strict';
var logNamespace = 'history';
//==============================================================================
/** How the type_id attribute is built for the history's mixed contents collection */
@@ -6,6 +6,8 @@ define([
"utils/localization"
], function( HISTORY_CONTENT, HDA_MODEL, HDCA_MODEL, BASE_MVC, _l ){
'use strict';
var logNamespace = 'history';
//==============================================================================
/** @class Backbone collection for history content.
@@ -6,6 +6,8 @@ define([
"utils/localization"
], function( HISTORY_CONTENTS, UTILS, BASE_MVC, _l ){
'use strict';
var logNamespace = 'history';
//==============================================================================
/** @class Model for a Galaxy history resource - both a record of user
@@ -78,7 +80,7 @@ var History = Backbone.Model
if( this.contents ){
this.contents.historyId = newId;
}
}, this );
});
},
//TODO: see base-mvc
@@ -540,7 +542,7 @@ var HistoryCollection = Backbone.Collection
this.trigger( 'no-longer-current', oldCurrentId );
this.currentHistoryId = history.id;
}
}, this );
});
},
/** override to allow passing options.order and setting the sort order to one of sortOrders */
@@ -9,6 +9,8 @@ define([
'libs/d3'
], function( JobDAG, JOB, JOB_LI, HISTORY_CONTENT, DATASET_LI, BASE_MVC, _l ){
'use strict';
var logNamespace = 'history';
// ============================================================================
/*
@@ -157,8 +159,8 @@ var HistoryStructureComponent = Backbone.View.extend( BASE_MVC.LoggableMixin ).e
// create the bbone view for the job (to be positioned later accrd. to the layout) and cache
var li = new view.JobItemClass({ model: job, tool: jobData.tool, jobData: jobData });
li.on( 'expanding expanded collapsing collapsed', view.renderGraph, view );
li.foldout.on( 'view:expanding view:expanded view:collapsing view:collapsed', view.renderGraph, view );
view.listenTo( li, 'expanding expanded collapsing collapsed', view.renderGraph );
view.listenTo( li.foldout, 'view:expanding view:expanded view:collapsing view:collapsed', view.renderGraph );
return li;
},
@@ -169,7 +171,7 @@ var HistoryStructureComponent = Backbone.View.extend( BASE_MVC.LoggableMixin ).e
typeId = HISTORY_CONTENT.typeIdStr( content.history_content_type, content.id );
content = view.model.contents.get( typeId );
var li = new view.ContentItemClass({ model: content });
li.on( 'expanding expanded collapsing collapsed', view.renderGraph, view );
view.listenTo( li, 'expanding expanded collapsing collapsed', view.renderGraph );
return li;
},
@@ -5,6 +5,9 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( HISTORY_VIEW, HDA_LI, HDCA_LI, BASE_MVC, _l ){
'use strict';
/* =============================================================================
TODO:
@@ -4,6 +4,9 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( HISTORY_MODEL, HISTORY_VIEW_EDIT, BASE_MVC, _l ){
'use strict';
// ============================================================================
/** session storage for history panel preferences (and to maintain state)
*/
@@ -158,12 +161,12 @@ var CurrentHistoryView = _super.extend(
//TODO:?? may not be needed? see history-view-edit, 369
// if a hidden item is created (gen. by a workflow), moves thru the updater to the ready state,
// then: remove it from the collection if the panel is set to NOT show hidden datasets
this.collection.on( 'state:ready', function( model, newState, oldState ){
this.listenTo( this.collection, 'state:ready', function( model, newState, oldState ){
if( ( !model.get( 'visible' ) )
&& ( !this.storage.get( 'show_hidden' ) ) ){
this.removeItemView( model );
}
}, this );
});
},
/** listening for history events */
@@ -257,27 +260,28 @@ var CurrentHistoryView = _super.extend(
_renderTags : function( $where ){
var panel = this;
// render tags and show/hide based on preferences
_super.prototype._renderTags.call( this, $where );
if( this.preferences.get( 'tagsEditorShown' ) ){
this.tagsEditor.toggle( true );
_super.prototype._renderTags.call( panel, $where );
if( panel.preferences.get( 'tagsEditorShown' ) ){
panel.tagsEditor.toggle( true );
}
// store preference when shown or hidden
this.tagsEditor.on( 'hiddenUntilActivated:shown hiddenUntilActivated:hidden',
panel.listenTo( panel.tagsEditor, 'hiddenUntilActivated:shown hiddenUntilActivated:hidden',
function( tagsEditor ){
panel.preferences.set( 'tagsEditorShown', tagsEditor.hidden );
});
}
);
},
/** In this override, get and set current panel preferences when editor is used */
_renderAnnotation : function( $where ){
var panel = this;
// render annotation and show/hide based on preferences
_super.prototype._renderAnnotation.call( this, $where );
if( this.preferences.get( 'annotationEditorShown' ) ){
this.annotationEditor.toggle( true );
_super.prototype._renderAnnotation.call( panel, $where );
if( panel.preferences.get( 'annotationEditorShown' ) ){
panel.annotationEditor.toggle( true );
}
// store preference when shown or hidden
this.annotationEditor.on( 'hiddenUntilActivated:shown hiddenUntilActivated:hidden',
panel.listenTo( panel.annotationEditor, 'hiddenUntilActivated:shown hiddenUntilActivated:hidden',
function( annotationEditor ){
panel.preferences.set( 'annotationEditorShown', annotationEditor.hidden );
}
@@ -325,12 +329,12 @@ var CurrentHistoryView = _super.extend(
_super.prototype._setUpItemViewListeners.call( panel, view );
// use pub-sub to: handle drilldown expansion and collapse
view.on( 'expanded:drilldown', function( v, drilldown ){
panel.listenTo( view, 'expanded:drilldown', function( v, drilldown ){
this._expandDrilldownPanel( drilldown );
}, this );
view.on( 'collapsed:drilldown', function( v, drilldown ){
});
panel.listenTo( view, 'collapsed:drilldown', function( v, drilldown ){
this._collapseDrilldownPanel( drilldown );
}, this );
});
// when content is manipulated, make it the current-content
// view.on( 'visualize', function( v, ev ){
@@ -376,7 +380,7 @@ var CurrentHistoryView = _super.extend(
// ........................................................................ external objects/MVC
listenToGalaxy : function( galaxy ){
// TODO: MEM: questionable reference island / closure practice
galaxy.on( 'galaxy_main:load', function( data ){
this.listenTo( galaxy, 'galaxy_main:load', function( data ){
var pathToMatch = data.fullpath,
useToURLRegexMap = {
'display' : /datasets\/([a-f0-9]+)\/display/,
@@ -401,7 +405,7 @@ var CurrentHistoryView = _super.extend(
// need to type mangle to go from web route to history contents
hdaId = 'dataset-' + hdaId;
this._setCurrentContentById( hdaId );
}, this );
});
},
//TODO: remove quota meter from panel and remove this
@@ -30,6 +30,9 @@ define([
PopupMenu,
_l
){
'use strict';
/* =============================================================================
TODO:
@@ -90,7 +93,7 @@ var HistoryViewEdit = _super.extend(
});
panel.on( 'view:attached view:removed', function(){
panel._renderCounts();
}, panel );
});
},
// ------------------------------------------------------------------------ listeners
@@ -98,19 +101,21 @@ var HistoryViewEdit = _super.extend(
_setUpCollectionListeners : function(){
_super.prototype._setUpCollectionListeners.call( this );
this.collection.on( 'change:deleted', this._handleHdaDeletionChange, this );
this.collection.on( 'change:visible', this._handleHdaVisibleChange, this );
this.collection.on( 'change:purged', function( model ){
// hafta get the new nice-size w/o the purged model
this.model.fetch();
}, this );
this.listenTo( this.collection, {
'change:deleted': this._handleHdaDeletionChange,
'change:visible': this._handleHdaVisibleChange,
'change:purged' : function( model ){
// hafta get the new nice-size w/o the purged model
this.model.fetch();
}
});
return this;
},
/** listening for history and HDA events */
_setUpModelListeners : function(){
_super.prototype._setUpModelListeners.call( this );
this.model.on( 'change:size', this.updateHistoryDiskSize, this );
this.listenTo( this.model, 'change:size', this.updateHistoryDiskSize );
return this;
},
@@ -23,6 +23,8 @@ define([
_l
){
'use strict';
var logNamespace = 'history';
// ============================================================================
@@ -377,11 +379,13 @@ var HistoryView = _super.extend(
//TODO:?? could use 'view:expanded' here?
// maintain a list of items whose bodies are expanded
view.on( 'expanded', function( v ){
panel.storage.addExpanded( v.model );
});
view.on( 'collapsed', function( v ){
panel.storage.removeExpanded( v.model );
panel.listenTo( view, {
'expanded': function( v ){
panel.storage.addExpanded( v.model );
},
'collapsed': function( v ){
panel.storage.removeExpanded( v.model );
}
});
return this;
},
@@ -2,6 +2,9 @@ define([
'utils/graph',
'utils/add-logging'
],function( GRAPH, addLogging ){
'use strict';
// ============================================================================
var _super = GRAPH.Graph;
/** A Directed acyclic Graph built from a history's job data.
@@ -8,6 +8,8 @@ define([
"ui/search-input"
], function( HISTORY_MODEL, HISTORY_VIEW_EDIT, historyCopyDialog, baseMVC, ajaxQueue ){
'use strict';
var logNamespace = 'history';
/* ==============================================================================
TODO:
@@ -5,7 +5,8 @@ define([
"utils/localization"
], function( PopupMenu, historyCopyDialog, BASE_MVC, _l ){
"use strict";
'use strict';
// ============================================================================
var menu = [
{
+3 -1
View File
@@ -3,6 +3,8 @@ define([
'utils/localization'
], function( BASE_MVC, _l ){
'use strict';
var logNamespace = 'list';
//==============================================================================
/** A view which, when first rendered, shows only summary data/attributes, but
@@ -475,7 +477,7 @@ var FoldoutListItemView = ListItemView.extend({
_expandByDrilldown : function(){
var view = this;
// attachment and rendering done by listener
view.foldout.on( 'close', function(){
view.listenTo( view.foldout, 'close', function(){
view.trigger( 'collapsed:drilldown', view, view.foldout );
});
view.trigger( 'expanded:drilldown', view, view.foldout );
+49 -43
View File
@@ -6,6 +6,8 @@ define([
"ui/search-input"
], function( LIST_ITEM, LoadingIndicator, BASE_MVC, _l ){
'use strict';
var logNamespace = 'list';
/* ============================================================================
TODO:
@@ -120,29 +122,30 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(/** @lends
//TODO: move errorHandler down into list-view from history-view or
// pass to global error handler (Galaxy)
this.on( 'error', function( model, xhr, options, msg, details ){
//this.errorHandler( model, xhr, options, msg, details );
console.error( model, xhr, options, msg, details );
}, this );
// show hide the loading indicator
this.on( 'loading', function(){
this._showLoadingIndicator( 'loading...', 40 );
}, this );
this.on( 'loading-done', function(){
this._hideLoadingIndicator( 40 );
}, this );
this.on({
error: function( model, xhr, options, msg, details ){
//this.errorHandler( model, xhr, options, msg, details );
console.error( model, xhr, options, msg, details );
},
// show hide the loading indicator
loading: function(){
this._showLoadingIndicator( 'loading...', 40 );
},
'loading-done': function(){
this._hideLoadingIndicator( 40 );
},
});
// throw the first render up as a diff namespace using once (for outside consumption)
this.once( 'rendered', function(){
this.trigger( 'rendered:initial', this );
}, this );
});
// debugging
if( this.logger ){
this.on( 'all', function( event ){
this.log( this + '', arguments );
}, this );
});
}
this._setUpCollectionListeners();
@@ -156,21 +159,22 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(/** @lends
this.collection.off();
// bubble up error events
this.collection.on( 'error', function( model, xhr, options, msg, details ){
this.trigger( 'error', model, xhr, options, msg, details );
}, this );
this.collection.on( 'reset', function(){
this.renderItems();
}, this );
this.collection.on( 'add', this.addItemView, this );
this.collection.on( 'remove', this.removeItemView, this );
this.listenTo( this.collection, {
error : function( model, xhr, options, msg, details ){
this.trigger( 'error', model, xhr, options, msg, details );
},
reset : function(){
this.renderItems();
},
add : this.addItemView,
remove : this.removeItemView
});
// debugging
if( this.logger ){
this.collection.on( 'all', function( event ){
this.listenTo( this.collection, 'all', function( event ){
this.info( this + '(collection)', arguments );
}, this );
});
}
return this;
},
@@ -180,23 +184,25 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(/** @lends
this.log( this + '._setUpViewListeners' );
// shift to select a range
this.on( 'view:selected', function( view, ev ){
if( ev && ev.shiftKey && this.lastSelected ){
var lastSelectedView = this.viewFromModelId( this.lastSelected );
if( lastSelectedView ){
this.selectRange( view, lastSelectedView );
this.on({
'view:selected': function( view, ev ){
if( ev && ev.shiftKey && this.lastSelected ){
var lastSelectedView = this.viewFromModelId( this.lastSelected );
if( lastSelectedView ){
this.selectRange( view, lastSelectedView );
}
} else if( ev && ev.altKey && !this.selecting ){
this.showSelectors();
}
} else if( ev && ev.altKey && !this.selecting ){
this.showSelectors();
}
this.selected.push( view.model.id );
this.lastSelected = view.model.id;
}, this );
this.selected.push( view.model.id );
this.lastSelected = view.model.id;
},
this.on( 'view:de-selected', function( view, ev ){
this.selected = _.without( this.selected, view.model.id );
//this.lastSelected = view.model.id;
}, this );
'view:de-selected': function( view, ev ){
this.selected = _.without( this.selected, view.model.id );
//this.lastSelected = view.model.id;
}
});
},
// ------------------------------------------------------------------------ rendering
@@ -426,14 +432,14 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(/** @lends
_setUpItemViewListeners : function( view ){
var panel = this;
// send all events to the panel, re-namspaceing them with the view prefix
view.on( 'all', function(){
this.listenTo( view, 'all', function(){
var args = Array.prototype.slice.call( arguments, 0 );
args[0] = 'view:' + args[0];
panel.trigger.apply( panel, args );
});
// drag multiple - hijack ev.setData to add all selected items
view.on( 'draggable:dragstart', function( ev, v ){
this.listenTo( view, 'draggable:dragstart', function( ev, v ){
//TODO: set multiple drag data here
var json = {},
selected = this.getSelectedModels();
@@ -912,7 +918,7 @@ var ModelListPanel = ListPanel.extend({
// override
this.log( this + '._setUpModelListeners', this.model );
// bounce model errors up to the panel
this.model.on( 'error', function(){
this.listenTo( this.model, 'error', function(){
var args = Array.prototype.slice.call( arguments, 0 );
//args.unshift( 'model:error' );
args.unshift( 'error' );
@@ -7,9 +7,8 @@ define(['utils/utils', 'mvc/tool/tool-form-base'],
// create form view
var View = ToolFormBase.extend({
initialize: function(options) {
// link this
var self = this;
this.hasLabelListeners = false;
this.workflow = options.workflow;
// link with node representation in workflow module
this.node = options.node;
@@ -40,7 +39,6 @@ define(['utils/utils', 'mvc/tool/tool-form-base'],
// module information for the tool to update the workflow
// state stored on the client with. User needs to save
// for this to take effect.
self.initializeLabelListener();
self.node.update_field_data(data);
self.errors(data && data.tool_model)
}
@@ -73,29 +71,6 @@ define(['utils/utils', 'mvc/tool/tool-form-base'],
ToolFormBase.prototype.initialize.call(this, options);
},
initializeLabelListener: function() {
var self = this;
if(this.hasLabelListeners !== false) {
return;
}
this.hasLabelListeners = [];
var outputSections = _.where(this.options.inputs, {outputSection: true});
var labelInputs = outputSections.map(function(entry) {
var sectionId = entry.id;
var outputId = entry.outputId;
var $section = $("#" + sectionId);
var $labelRow = $section.find(".section-row").first();
var labelTextInput = $labelRow.find("input")[0];
$(labelTextInput).bind('input propertychange', function() {
var newLabel = $(labelTextInput).val();
var workflow = self.node.app.workflow;
workflow.attemptUpdateOutputLabel( self.node, outputId, newLabel );
});
});
},
/** Builds all sub sections
*/
_makeSections: function(options){
@@ -150,6 +125,7 @@ define(['utils/utils', 'mvc/tool/tool-form-base'],
*/
_makeSection: function(output_id, datatypes){
// format datatypes
var self = this;
var extensions = [];
var input_terminal_names = [];
@@ -188,15 +164,14 @@ define(['utils/utils', 'mvc/tool/tool-form-base'],
title : 'Configure Output: \'' + output_id + '\'',
type : 'section',
flat : true,
outputSection: true,
outputId : output_id,
inputs : [{
action : 'Label',
label : 'Label',
type : 'text',
value : '',
ignore : '',
help : 'This will provide a short name to describe the output - this must be unique across workflows.'
value : ( output = this.node.getWorkflowOutput( output_id ) ) && output.label || '',
help : 'This will provide a short name to describe the output - this must be unique across workflows.',
onchange : function( new_value ) {
self.workflow.attemptUpdateOutputLabel( self.node, output_id, new_value );
}
},{
action : 'RenameDatasetAction',
pja_arg : 'newname',
@@ -267,21 +242,13 @@ define(['utils/utils', 'mvc/tool/tool-form-base'],
};
// visit input nodes and enrich by name/value pairs from server data
var self = this;
function visit (head, head_list) {
head_list = head_list || [];
head_list.push(head);
for (var i in head.inputs) {
var input = head.inputs[i];
var action = input.action;
if ( action == "Label") {
var workflowOutput = self.node.getWorkflowOutput(output_id);
if ( workflowOutput ) {
input.value = workflowOutput['label'] || '';
} else{
input.value = '';
}
} else if (action) {
if (action) {
// construct identifier as expected by backend
input.name = 'pja__' + output_id + '__' + input.action;
if (input.pja_arg) {
+74 -12
View File
@@ -6,13 +6,10 @@
"libs/underscore",
"viz/trackster/util",
"mvc/dataset/data",
"mvc/tool/tool-form",
"templates/tool_form.handlebars",
"templates/tool_link.handlebars",
"templates/panel_section.handlebars",
"templates/tool_search.handlebars",
"mvc/tool/tool-form"
], function(_, util, data, ToolForm, tool_form_template, tool_link_template, panel_section_template, tool_search_template) {
], function(_, util, data, ToolForm) {
'use strict';
/**
* Mixin for tracking model visibility.
@@ -353,7 +350,6 @@ var ToolSearch = Backbone.Model.extend({
defaults: {
search_hint_string: "search tools",
min_chars_for_search: 3,
spinner_url: "",
clear_btn_url: "",
search_url: "",
visible: true,
@@ -496,7 +492,7 @@ var ToolPanel = Backbone.Model.extend({
/**
* View classes for Galaxy tools and tool panel.
*
* Views use precompiled Handlebars templates for rendering. Views update as needed
* Views use the templates defined below for rendering. Views update as needed
* based on (a) model/collection events and (b) user interactions; in this sense,
* they are controllers are well and the HTML is the real view in the MVC architecture.
*/
@@ -523,7 +519,7 @@ var ToolLinkView = BaseView.extend({
render: function() {
// create element
var $link = $('<div/>');
$link.append(tool_link_template(this.model.toJSON()));
$link.append(templates.tool_link(this.model.toJSON()));
// open upload dialog for upload tool
if (this.model.id === 'upload1') {
@@ -576,7 +572,7 @@ var ToolSectionView = BaseView.extend({
render: function() {
// Build using template.
this.$el.append( panel_section_template(this.model.toJSON()) );
this.$el.append( templates.panel_section(this.model.toJSON()) );
// Add tools to section.
var section_body = this.$el.find(".toolSectionBody");
@@ -632,7 +628,7 @@ var ToolSearchView = Backbone.View.extend({
},
render: function() {
this.$el.append( tool_search_template(this.model.toJSON()) );
this.$el.append( templates.tool_search(this.model.toJSON()) );
if (!this.model.is_visible()) {
this.$el.hide();
}
@@ -736,7 +732,7 @@ var ToolFormView = Backbone.View.extend({
render: function() {
this.$el.children().remove();
this.$el.append( tool_form_template(this.model.toJSON()) );
this.$el.append( templates.tool_form(this.model.toJSON()) );
}
});
@@ -785,6 +781,72 @@ var IntegratedToolMenuAndView = Backbone.View.extend({
}
});
// TODO: move into relevant views
var templates = {
// the search bar at the top of the tool panel
tool_search : _.template([
'<input id="tool-search-query" class="search-query parent-width" name="query" ',
'placeholder="<%- search_hint_string %>" autocomplete="off" type="text" />',
'<a id="search-clear-btn" title="clear search (esc)"> </a>',
//TODO: replace with icon
'<span id="search-spinner" class="search-spinner fa fa-spinner fa-spin"></span>',
].join('')),
// the category level container in the tool panel (e.g. 'Get Data', 'Text Manipulation')
panel_section : _.template([
'<div class="toolSectionTitle" id="title_<%- id %>">',
'<a href="javascript:void(0)"><span><%- name %></span></a>',
'</div>',
'<div id="<%- id %>" class="toolSectionBody" style="display: none;">',
'<div class="toolSectionBg"></div>',
'<div>'
].join('')),
// a single tool's link in the tool panel; will load the tool form in the center panel
tool_link : _.template([
'<span class="labels">',
'<% _.each( labels, function( label ){ %>',
'<span class="label label-default label-<%- label %>">',
'<%- label %>',
'</span>',
'<% }); %>',
'</span>',
'<a class="<%- id %> tool-link" href="<%= link %>" target="<%- target %>" minsizehint="<%- min_width %>">',
'<%- name %>',
'</a>',
' <%- description %>'
].join('')),
// the tool form for entering tool parameters, viewing help and executing the tool
// loaded when a tool link is clicked in the tool panel
tool_form : _.template([
'<div class="toolFormTitle"><%- tool.name %> (version <%- tool.version %>)</div>',
'<div class="toolFormBody">',
'<% _.each( tool.inputs, function( input ){ %>',
'<div class="form-row">',
'<label for="<%- input.name %>"><%- input.label %>:</label>',
'<div class="form-row-input">',
'<%= input.html %>',
'</div>',
'<div class="toolParamHelp" style="clear: both;">',
'<%- input.help %>',
'</div>',
'<div style="clear: both;"></div>',
'</div>',
'<% }); %>',
'</div>',
'<div class="form-row form-actions">',
'<input type="submit" class="btn btn-primary" name="runtool_btn" value="Execute" />',
'</div>',
'<div class="toolHelp">',
'<div class="toolHelpBody"><% tool.help %></div>',
'</div>',
// TODO: we need scoping here because 'help' is the dom for the help menu in the masthead
// which implies a leaky variable that I can't find
].join(''), { variable: 'tool' }),
};
// Exports
return {
ToolParameter: ToolParameter,
+1 -1
View File
@@ -14,7 +14,7 @@ var View = Backbone.View.extend({
this.multiple = options.multiple || false;
// create message handler
this.message = new Ui.Message({ cls: 'ui-margin-top' });
this.message = new Ui.Message();
// create portlet
this.portlet = new Portlet.View({ cls: 'ui-portlet-section' });
+84 -201
View File
@@ -10,257 +10,141 @@ define(['utils/utils',
'mvc/ui/ui-modal'],
function( Utils, Select, Slider, Options, Drilldown, Buttons, Modal ) {
/** Image wrapper */
var Image = Backbone.View.extend({
initialize : function(options) {
this.options = Utils.merge(options, {
url : '',
cls : ''
});
this.setElement(this._template(this.options));
},
_template: function(options) {
return '<img class="ui-image ' + options.cls + '" src="' + options.url + '"/>';
}
});
/** Label wrapper */
var Label = Backbone.View.extend({
initialize : function(options) {
this.options = Utils.merge(options, {
title : '',
cls : '',
tagname : 'label'
});
this.setElement(this._template(this.options));
tagName: 'label',
initialize: function( options ) {
this.model = options && options.model || new Backbone.Model( options );
this.tagName = options.tagName || this.tagName;
this.setElement( $( '<' + this.tagName + '/>' ) );
this.listenTo( this.model, 'change', this.render, this );
this.render();
},
title: function(new_title) {
this.$el.html(new_title);
title: function( new_title ) {
this.model.set( 'title', new_title );
},
value: function() {
return options.title;
return this.model.get( 'title' );
},
_template: function(options) {
return $( '<' + options.tagname + '/>' ).addClass( 'ui-label' ).addClass( options.cls ).html( options.title );
}
});
/** Displays an icon with title */
var Icon = Backbone.View.extend({
initialize : function(options) {
this.options = Utils.merge(options, {
floating : 'right',
icon : '',
tooltip : '',
placement : 'bottom',
title : '',
cls : ''
});
this.setElement(this._template(this.options));
$(this.el).tooltip({title: options.tooltip, placement: 'bottom'});
},
_template: function(options) {
return '<div>' +
'<span class="fa ' + options.icon + '" class="ui-icon"/>&nbsp;' +
options.title +
'</div>';
}
});
/** Renders an anchor element */
var Anchor = Backbone.View.extend({
initialize : function(options) {
this.options = Utils.merge(options, {
title : '',
cls : ''
});
this.setElement(this._template(this.options));
$(this.el).on('click', options.onclick);
},
_template: function(options) {
return '<div><a href="javascript:void(0)" class="ui-anchor ' + options.cls + '">' + options.title + '</a></div>';
render: function() {
this.$el.removeClass()
.addClass( 'ui-label' )
.addClass( this.model.get( 'cls' ) )
.html( this.model.get( 'title' ) );
return this;
}
});
/** Displays messages used e.g. in the tool form */
var Message = Backbone.View.extend({
initialize : function(options) {
this.options = Utils.merge(options, {
initialize: function( options ) {
this.model = options && options.model || new Backbone.Model({
message : null,
status : 'info',
cls : '',
persistent : false
});
this.setElement('<div class="' + this.options.cls + '"/>');
this.options.message && this.update(this.options);
}).set( options );
this.listenTo( this.model, 'change', this.render, this );
this.render();
},
// update
update: function(options) {
// get options
this.options = Utils.merge(options, this.options);
// show message
if (options.message != '') {
this.$el.html(this._template(this.options));
update: function( options ) {
this.model.set( options );
},
render: function() {
this.$el.removeClass().addClass( 'ui-message' ).addClass( this.model.get( 'cls' ) );
var status = this.model.get( 'status' );
if ( this.model.get( 'large' ) ) {
this.$el.addClass((( status == 'success' && 'done' ) ||
( status == 'danger' && 'error' ) ||
status ) + 'messagelarge' );
} else {
this.$el.addClass( 'alert' ).addClass( 'alert-' + status );
}
if ( this.model.get( 'message' ) ) {
this.$el.html( this.model.get( 'message' ) );
this.$el.fadeIn();
// clear previous timeouts
if (this.timeout) {
window.clearTimeout(this.timeout);
}
// set timeout if message is not persistent
if (!options.persistent) {
this.timeout && window.clearTimeout( this.timeout );
if ( !this.model.get( 'persistent' ) ) {
var self = this;
this.timeout = window.setTimeout(function() {
if (self.$el.is(':visible')) {
self.$el.fadeOut();
} else {
self.$el.hide();
}
}, 3000);
this.timeout = window.setTimeout( function() {
self.$el.fadeOut();
}, 3000 );
}
} else {
this.$el.fadeOut();
}
},
// template
_template: function(options) {
var cls_status = 'ui-message alert alert-' + options.status;
if (options.large) {
cls_status = ( ( options.status == 'success' && 'done' ) ||
( options.status == 'danger' && 'error' ) ||
options.status ) + 'messagelarge';
}
return '<div class="' + cls_status + '" >' +
options.message +
'</div>';
}
});
/** Render a search box */
var Searchbox = Backbone.View.extend({
initialize : function(options) {
this.options = Utils.merge(options, {
onclick : null,
searchword : ''
});
this.setElement(this._template(this.options));
var self = this;
if (this.options.onclick) {
this.$el.on('submit', function(e) {
var search_field = self.$el.find('#search');
self.options.onclick(search_field.val());
});
}
},
_template: function(options) {
return '<div class="ui-search">' +
'<form onsubmit="return false;">' +
'<input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="' + options.searchword + '">' +
'<button type="submit" class="btn search-btn">' +
'<i class="fa fa-search"></i>' +
'</button>' +
'</form>' +
'</div>';
return this;
}
});
/** Renders an input element used e.g. in the tool form */
var Input = Backbone.View.extend({
initialize : function(options) {
// configure options
this.options = Utils.merge(options, {
initialize: function( options ) {
this.model = options && options.model || new Backbone.Model({
type : 'text',
placeholder : '',
disabled : false,
visible : true,
cls : '',
area : false
});
// create new element
this.setElement(this._template(this.options));
// set initial value
if (this.options.value !== undefined) {
this.value(this.options.value);
}
// disable input field
if (this.options.disabled) {
this.$el.prop('disabled', true);
}
// hide input field
if (!this.options.visible) {
this.$el.hide();
}
// onchange event handler. fires on user activity.
var self = this;
this.$el.on('input', function() {
if (self.options.onchange) {
self.options.onchange(self.$el.val());
}
});
}).set( options );
this.tagName = this.model.get( 'area' ) ? 'textarea' : 'input';
this.setElement( $( '<' + this.tagName + '/>' ) );
this.listenTo( this.model, 'change', this.render, this );
this.render();
},
// value
value : function (new_val) {
if (new_val !== undefined) {
this.$el.val( ( typeof new_val === 'string' && new_val ) || '' );
}
return this.$el.val();
events: {
'input': '_onchange'
},
// template
_template: function(options) {
if (options.area) {
return '<textarea id="' + options.id + '" class="ui-textarea ' + options.cls + '"></textarea>';
} else {
return '<input id="' + options.id + '" type="' + options.type + '" value="' + options.value + '" placeholder="' + options.placeholder + '" class="ui-input ' + options.cls + '">';
}
value: function( new_val ) {
new_val !== undefined && this.model.set( 'value', typeof new_val === 'string' ? new_val : '' );
return this.model.get( 'value' );
},
render: function() {
this.$el.removeClass()
.addClass( 'ui-' + this.tagName )
.addClass( this.model.get( 'cls' ) )
.attr( 'id', this.model.id )
.attr( 'type', this.model.get( 'type' ) )
.attr( 'placeholder', this.model.get( 'placeholder' ) )
.val( this.model.get( 'value' ) );
this.model.get( 'disabled' ) ? this.$el.attr( 'disabled', true ) : this.$el.removeAttr( 'disabled' );
this.$el[ this.model.get( 'visible' ) ? 'show' : 'hide' ]();
return this;
},
_onchange: function() {
this.value( this.$el.val() );
this.model.get( 'onchange' ) && this.model.get( 'onchange' )( this.model.get( 'value' ) );
}
});
/** Creates a hidden element input field used e.g. in the tool form */
var Hidden = Backbone.View.extend({
initialize : function(options) {
this.options = options;
this.setElement(this._template(this.options));
if (this.options.value !== undefined) {
this.value(this.options.value);
}
initialize: function( options ) {
this.model = options && options.model || new Backbone.Model( options );
this.setElement( $ ( '<div/>' ).append( this.$info = $( '<div/>' ) )
.append( this.$hidden = $( '<div/>' ) ) );
this.listenTo( this.model, 'change', this.render, this );
this.render();
},
value : function (new_val) {
if (new_val !== undefined) {
this.$('hidden').val(new_val);
}
return this.$('hidden').val();
value: function( new_val ) {
new_val !== undefined && this.model.set( 'value', new_val );
return this.model.get( 'value' );
},
_template: function(options) {
var tmpl = '<div id="' + options.id + '" >';
if (options.info) {
tmpl += '<div>' + options.info + '</div>';
}
tmpl += '<hidden value="' + options.value + '"/>' +
'</div>';
return tmpl;
render: function() {
this.$el.attr( 'id', this.model.id );
this.$hidden.val( this.model.get( 'value' ) );
this.model.get( 'info' ) ? this.$info.show().html( this.model.get( 'info' ) ) : this.$info.hide();
return this;
}
});
return {
Anchor : Anchor,
Button : Buttons.ButtonDefault,
ButtonIcon : Buttons.ButtonIcon,
ButtonCheck : Buttons.ButtonCheck,
ButtonMenu : Buttons.ButtonMenu,
ButtonLink : Buttons.ButtonLink,
Icon : Icon,
Image : Image,
Input : Input,
Label : Label,
Message : Message,
@@ -268,7 +152,6 @@ define(['utils/utils',
RadioButton : Options.RadioButton,
Checkbox : Options.Checkbox,
Radio : Options.Radio,
Searchbox : Searchbox,
Select : Select,
Hidden : Hidden,
Slider : Slider,
@@ -322,7 +322,7 @@ return Backbone.View.extend({
'<td>' +
'<div id="genome" class="upload-genome"/>' +
'</td>' +
'<td><div id="settings" class="upload-icon-button fa fa-gear"/></td>' +
'<td><div id="settings" class="upload-settings upload-icon-button fa fa-gear"/></td>' +
'<td>' +
'<div id="info" class="upload-info">' +
'<div class="progress">' +
@@ -1,93 +1,43 @@
/** This renders the content of the settings popup, allowing users to specify flags i.e. for space-to-tab conversion **/
define(['utils/utils'], function(Utils) {
define( [ 'utils/utils' ], function( Utils ) {
return Backbone.View.extend({
// options
options: {
class_check : 'upload-icon-button fa fa-check-square-o',
class_uncheck : 'upload-icon-button fa fa-square-o'
class_check : 'fa-check-square-o',
class_uncheck : 'fa-square-o',
parameters : [{
id : 'space_to_tab',
title : 'Convert spaces to tabs',
},{
id : 'to_posix_lines',
title : 'Use POSIX standard'
}]
},
// initialize
initialize: function(app) {
// link app
this.app = app;
// link this
initialize: function( options ) {
var self = this;
// set template
this.setElement(this._template());
// link model
this.model = this.app.model;
// ui event: space-to-tab
this.$('#upload-space-to-tab').on('click', function() {
self._switchState('#upload-space-to-tab', 'space_to_tab');
});
// ui event: to-posix-lines
this.$('#upload-to-posix-lines').on('click', function() {
self._switchState('#upload-to-posix-lines', 'to_posix_lines');
});
// render
this.render();
this.model = options.model;
this.setElement( $( '<div/>' ).addClass( 'upload-settings' ) );
this.$el.append( $( '<div/>' ).addClass( 'upload-settings-cover' ) );
this.$el.append( $( '<table/>' ).addClass( 'upload-settings-table ui-table-striped' ).append( '<tbody/>' ) );
this.$cover = this.$( '.upload-settings-cover' );
this.$table = this.$( '.upload-settings-table > tbody' );
this.listenTo ( this.model, 'change', this.render, this );
this.model.trigger( 'change' );
},
// render
render: function() {
// render states
this._renderState('#upload-space-to-tab', this.model.get('space_to_tab'));
this._renderState('#upload-to-posix-lines', this.model.get('to_posix_lines'));
// disable options
var $cover = this.$('#upload-settings-cover');
if (!this.model.get('enabled')) {
$cover.show();
} else {
$cover.hide();
}
},
// switch state
_switchState: function (element_id, parameter_id) {
if (this.model.get('enabled')) {
var checked = !this.model.get(parameter_id);
this.model.set(parameter_id, checked);
this._renderState(element_id, checked);
}
},
// render state
_renderState: function (element_id, checked) {
var $it = this.$(element_id);
$it.removeClass();
if (checked) {
$it.addClass(this.options.class_check);
} else {
$it.addClass(this.options.class_uncheck);
}
},
// load template
_template: function() {
return '<div class="upload-settings" style="position: relative;">' +
'<div id="upload-settings-cover" class="upload-settings-cover"/>' +
'<table class="ui-table-striped">' +
'<tbody>' +
'<tr>' +
'<td><div id="upload-space-to-tab"/></td>' +
'<td>Convert spaces to tabs</td>' +
'</tr>' +
'<tr>' +
'<td><div id="upload-to-posix-lines"/></td>' +
'<td>Use POSIX standard</td>' +
'</tr>' +
'</tbody>' +
'</table>' +
'</div>';
var self = this;
this.$table.empty();
_.each( this.options.parameters, function( parameter ) {
var $checkbox = $( '<div/>' ).addClass( 'upload-' + parameter.id + ' upload-icon-button fa' )
.addClass( self.model.get( parameter.id ) && self.options.class_check || self.options.class_uncheck )
.on( 'click', function() {
self.model.get( 'enabled' ) && self.model.set( parameter.id, !self.model.get( parameter.id ) )
});
self.$table.append( $( '<tr/>' ).append( $( '<td/>' ).append( $checkbox ) )
.append( $( '<td/>' ).append( parameter.title ) ) )
});
this.$cover[ this.model.get( 'enabled' ) && 'hide' || 'show' ]();
}
});
});
});
@@ -4,6 +4,7 @@ define([
'mvc/base-mvc',
'utils/localization'
], function( _, Backbone, baseMVC, _l ){
'use strict';
var logNamespace = 'user';
//==============================================================================
@@ -2,6 +2,7 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( baseMVC, _l ){
'use strict';
var logNamespace = 'user';
//==============================================================================
@@ -27,7 +28,7 @@ var UserQuotaMeter = Backbone.View.extend( baseMVC.LoggableMixin ).extend(
_.extend( this.options, options );
//this.bind( 'all', function( event, data ){ this.log( this + ' event:', event, data ); }, this );
this.model.bind( 'change:quota_percent change:total_disk_usage', this.render, this );
this.listenTo( this.model, 'change:quota_percent change:total_disk_usage', this.render );
},
/** Re-load user model data from the api */
@@ -617,9 +617,7 @@ EditorFormView = Backbone.View.extend({
// Global state for the whole workflow
reset: function() {
if ( this.workflow ) {
this.workflow.remove_all();
}
this.workflow && this.workflow.remove_all();
this.workflow = Globals.workflow = new Workflow( this, $("#canvas-container") );
},
@@ -795,6 +793,7 @@ EditorFormView = Backbone.View.extend({
if (node.type == 'tool' && Utils.isJSON(text)) {
var options = JSON.parse(text);
options.node = node;
options.workflow = this.workflow;
options.datatypes = this.datatypes;
formView = new ToolForm.View(options);
} else {
-1
View File
@@ -8,7 +8,6 @@ window[ 'jQuery' ] = jQuery; // a weird form to prevent webpack from sub'ing 'wi
window.$ = jQuery;
window._ = _;
window.Backbone = Backbone;
window.Handlebars = Handlebars;
// console.debug('globals loaded:', window.jQuery, window.Backbone, '...');
// these are galaxy globals not defined in the provider (although they could be - but why encourage that?)
@@ -1,15 +0,0 @@
define(['libs/handlebars.runtime'], function(Handlebars) {
return Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
var helper, alias1=helpers.helperMissing, alias2="function", alias3=this.escapeExpression;
return "<div class=\"toolSectionTitle\" id=\"title_"
+ alias3(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"id","hash":{},"data":data}) : helper)))
+ "\">\n <a href=\"javascript:void(0)\"><span>"
+ alias3(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"name","hash":{},"data":data}) : helper)))
+ "</span></a>\n</div>\n<div id=\""
+ alias3(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"id","hash":{},"data":data}) : helper)))
+ "\" class=\"toolSectionBody\" style=\"display: none; \">\n <div class=\"toolSectionBg\"></div>\n<div>";
},"useData":true})
});
@@ -1,29 +0,0 @@
define(['libs/handlebars.runtime'], function(Handlebars) {
return Handlebars.template({"1":function(depth0,helpers,partials,data) {
var stack1, helper, alias1=helpers.helperMissing, alias2="function", alias3=this.escapeExpression;
return " <div class=\"form-row\">\n <label for=\""
+ alias3(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"name","hash":{},"data":data}) : helper)))
+ "\">"
+ alias3(((helper = (helper = helpers.label || (depth0 != null ? depth0.label : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"label","hash":{},"data":data}) : helper)))
+ ":</label>\n <div class=\"form-row-input\">\n "
+ ((stack1 = ((helper = (helper = helpers.html || (depth0 != null ? depth0.html : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"html","hash":{},"data":data}) : helper))) != null ? stack1 : "")
+ "\n </div>\n <div class=\"toolParamHelp\" style=\"clear: both;\">\n "
+ alias3(((helper = (helper = helpers.help || (depth0 != null ? depth0.help : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"help","hash":{},"data":data}) : helper)))
+ "\n </div>\n <div style=\"clear: both;\"></div>\n </div>\n";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
var stack1, helper, alias1=helpers.helperMissing, alias2="function", alias3=this.escapeExpression;
return "<div class=\"toolFormTitle\">"
+ alias3(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"name","hash":{},"data":data}) : helper)))
+ " (version "
+ alias3(((helper = (helper = helpers.version || (depth0 != null ? depth0.version : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"version","hash":{},"data":data}) : helper)))
+ ")</div>\n <div class=\"toolFormBody\">\n"
+ ((stack1 = helpers.each.call(depth0,(depth0 != null ? depth0.inputs : depth0),{"name":"each","hash":{},"fn":this.program(1, data, 0),"inverse":this.noop,"data":data})) != null ? stack1 : "")
+ " </div>\n <div class=\"form-row form-actions\">\n <input type=\"submit\" class=\"btn btn-primary\" name=\"runtool_btn\" value=\"Execute\">\n</div>\n<div class=\"toolHelp\">\n <div class=\"toolHelpBody\">"
+ alias3(((helper = (helper = helpers.help || (depth0 != null ? depth0.help : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"help","hash":{},"data":data}) : helper)))
+ "</div>\n</div>";
},"useData":true})
});
@@ -1,31 +0,0 @@
define(['libs/handlebars.runtime'], function(Handlebars) {
return Handlebars.template({"1":function(depth0,helpers,partials,data) {
var alias1=this.lambda, alias2=this.escapeExpression;
return "<span class=\"label label-default label-"
+ alias2(alias1(depth0, depth0))
+ "\">"
+ alias2(alias1(depth0, depth0))
+ "</span> ";
},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
var stack1, helper, alias1=helpers.helperMissing, alias2="function", alias3=this.escapeExpression;
return "<span class=\"labels\">"
+ ((stack1 = helpers.each.call(depth0,(depth0 != null ? depth0.labels : depth0),{"name":"each","hash":{},"fn":this.program(1, data, 0),"inverse":this.noop,"data":data})) != null ? stack1 : "")
+ "</span>\n<a class=\""
+ alias3(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"id","hash":{},"data":data}) : helper)))
+ " tool-link\" href=\""
+ alias3(((helper = (helper = helpers.link || (depth0 != null ? depth0.link : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"link","hash":{},"data":data}) : helper)))
+ "\" target=\""
+ alias3(((helper = (helper = helpers.target || (depth0 != null ? depth0.target : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"target","hash":{},"data":data}) : helper)))
+ "\" minsizehint=\""
+ alias3(((helper = (helper = helpers.min_width || (depth0 != null ? depth0.min_width : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"min_width","hash":{},"data":data}) : helper)))
+ "\">"
+ alias3(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"name","hash":{},"data":data}) : helper)))
+ "</a>\n"
+ alias3(((helper = (helper = helpers.description || (depth0 != null ? depth0.description : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"description","hash":{},"data":data}) : helper)))
+ "\n";
},"useData":true})
});
@@ -1,13 +0,0 @@
define(['libs/handlebars.runtime'], function(Handlebars) {
return Handlebars.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
var helper, alias1=helpers.helperMissing, alias2="function", alias3=this.escapeExpression;
return "<input type=\"text\" name=\"query\" placeholder=\""
+ alias3(((helper = (helper = helpers.search_hint_string || (depth0 != null ? depth0.search_hint_string : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"search_hint_string","hash":{},"data":data}) : helper)))
+ "\" id=\"tool-search-query\" autocomplete=\"off\" class=\"search-query parent-width\" />\n<a id=\"search-clear-btn\" title=\"clear search (esc)\"> </a>\n<img src=\""
+ alias3(((helper = (helper = helpers.spinner_url || (depth0 != null ? depth0.spinner_url : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"spinner_url","hash":{},"data":data}) : helper)))
+ "\" id=\"search-spinner\" class=\"search-spinner\"/>\n";
},"useData":true})
});
@@ -1,6 +0,0 @@
<div class="toolSectionTitle" id="title_{{id}}">
<a href="javascript:void(0)"><span>{{name}}</span></a>
</div>
<div id="{{id}}" class="toolSectionBody" style="display: none; ">
<div class="toolSectionBg"></div>
<div>
@@ -1,21 +0,0 @@
<div class="toolFormTitle">{{name}} (version {{version}})</div>
<div class="toolFormBody">
{{#each inputs}}
<div class="form-row">
<label for="{{name}}">{{label}}:</label>
<div class="form-row-input">
{{{html}}}
</div>
<div class="toolParamHelp" style="clear: both;">
{{help}}
</div>
<div style="clear: both;"></div>
</div>
{{/each}}
</div>
<div class="form-row form-actions">
<input type="submit" class="btn btn-primary" name="runtool_btn" value="Execute">
</div>
<div class="toolHelp">
<div class="toolHelpBody">{{help}}</div>
</div>
@@ -1,3 +0,0 @@
<span class="labels">{{#each labels}}<span class="label label-default label-{{this}}">{{this}}</span> {{/each}}</span>
<a class="{{id}} tool-link" href="{{link}}" target="{{target}}" minsizehint="{{min_width}}">{{name}}</a>
{{description}}
@@ -1,3 +0,0 @@
<input type="text" name="query" placeholder="{{search_hint_string}}" id="tool-search-query" autocomplete="off" class="search-query parent-width" />
<a id="search-clear-btn" title="clear search (esc)"> </a>
<img src="{{spinner_url}}" id="search-spinner" class="search-spinner"/>
+3
View File
@@ -30,6 +30,7 @@
@import "library.less";
@import "toastr.less";
@import "jstree.less";
@import "tour.less";
// Mixins
.unselectable {
@@ -724,6 +725,8 @@ input[type="submit"], button {
display: none;
right: 6px;
top: 9px;
font-size: 1.4em;
color: #888;
}
#search-clear-btn {
+4
View File
@@ -0,0 +1,4 @@
.popover-title{
background-color: @base-color-1;
color: @white;
}
+5 -1
View File
@@ -64,7 +64,11 @@
.ui-message {
padding: 2px 10px 2px 10px;
margin: 0px;
margin-top: @ui-margin-vertical-large;
margin-bottom: 0px;
float: left;
width: 100%;
display: none;
}
.ui-modal {
+1
View File
@@ -227,6 +227,7 @@
}
.upload-settings {
position: relative;
.upload-settings-cover {
position: absolute;
width: 100%;
+1 -2
View File
@@ -15,7 +15,6 @@ module.exports = function( grunt ){
'traceKit': [ 'tracekit.js', 'tracekit.js' ],
'ravenjs': [ 'dist/raven.js', 'raven.js' ],
'underscore': [ 'underscore.js', 'underscore.js' ],
'handlebars': [ 'handlebars.runtime.js', 'handlebars.runtime.js' ],
'backbone': [ 'backbone.js', 'backbone.js' ],
'requirejs': [ 'require.js', 'require.js' ],
'd3': [ 'd3.js', 'd3.js' ],
@@ -86,7 +85,7 @@ module.exports = function( grunt ){
}
}
grunt.loadNpmTasks( 'grunt-bower-install-simple');
grunt.loadNpmTasks( 'grunt-bower-install-simple' );
grunt.registerTask( 'copy-libs', 'copy external libraries to src', copyLibs );
grunt.registerTask( 'install-libs', 'fetch external libraries and copy to src',
-1
View File
@@ -17,7 +17,6 @@ module.exports = function( grunt ){
'autocomplete_tagging',
'embed_item',
'iphone',
'masthead',
'library',
'trackster',
'circster',
-56
View File
@@ -1,56 +0,0 @@
/**
* Grunt task to compile templates.
* @param {Object} grunt main grunt file
* @return {Function} callback to build this task
*/
module.exports = function( grunt ){
"use strict";
var app = grunt.config.get( 'app' ),
paths = grunt.config.get( 'paths' );
grunt.config( 'handlebars', {
'default' : {
files: [{
expand : true,
cwd : paths.srcSymlink + '/templates',
src : '**/*.handlebars',
dest : paths.srcSymlink + '/templates/compiled',
ext : '.js'
}],
options : {
// namespace needs to be false to return a fn (instead of adding to a global namespace)
namespace : false,
// define truthy amd here - if string, this will be the modules require'd
amd : 'libs/handlebars.runtime',
}
}
});
grunt.registerTask( 'templates', function(){
// compile then compress
grunt.task.run( 'handlebars' );
grunt.config( 'uglify.target.files', [{
expand : true,
cwd : paths.srcSymlink + '/templates/compiled',
src : '**/*.js',
dest : paths.dist + '/templates/compiled'
}]);
grunt.task.run( 'uglify' );
});
// -------------------------------------------------------------------------- watch & compile
// grunt.config( 'watch', {
// watch: {
// // watch for changes in the src dir
// files: [ paths.srcSymlink + '/**' ],
// tasks: [ 'uglify' ],
// options: {
// spawn: false
// }
// }
// });
// --------------------------------------------------------------------------
grunt.loadNpmTasks( 'grunt-contrib-handlebars' );
};
+38
View File
@@ -0,0 +1,38 @@
/**
* Grunt task to bundle apps using webpack (see also ../webpack.config.js).
*/
module.exports = function( grunt ){
"use strict";
var path = require( 'path' );
// there is a taskrunner specifically for this - but it's not straightforward
// and duplicates some of the config/code in webpack.config,
// https://github.com/webpack/grunt-webpack
// http://webpack.github.io/docs/usage-with-grunt.html
// so we'll use grunt-exec and call the webpack cli instead (until CLI and runner are unified a bit more?)
grunt.loadNpmTasks( 'grunt-exec' );
function webpackCLI(){
var args = Array.prototype.slice.call( arguments );
args.unshift( path.join( __dirname, '../node_modules/webpack/bin/webpack.js' ) );
return args.join( ' ' );
}
grunt.registerTask( 'webpack', function(){
grunt.log.writeln( 'bundling webpack apps for production...' );
grunt.config( 'exec.webpack-production.command', webpackCLI( '-p' ) );
grunt.task.run( 'exec:webpack-production' );
});
grunt.registerTask( 'webpack-dev', function(){
grunt.log.writeln( 'bundling webpack apps for development...' );
grunt.config( 'exec.webpack-dev.command', webpackCLI( '-d' ) );
grunt.task.run( 'exec:webpack-dev' );
});
grunt.registerTask( 'webpack-watch', function(){
grunt.log.writeln( 'bundling webpack apps for development and watching for changes...' );
grunt.config( 'exec.webpack-watch.command', webpackCLI( '-d', '--watch' ) );
grunt.task.run( 'exec:webpack-watch' );
});
};
-4
View File
@@ -13,15 +13,11 @@
"grunt-cli": "^0.1.13",
"grunt-contrib-clean": "^0.6.0",
"grunt-contrib-copy": "^0.5.0",
"grunt-contrib-handlebars": "^0.10.2",
"grunt-contrib-less": "^1.1.0",
"grunt-contrib-uglify": "^0.8.0",
"grunt-contrib-watch": "^0.6.1",
"grunt-exec": "^0.4.6",
"grunt-spritesmith": "^4.7.1",
"grunt-webpack": "^1.0.8",
"handlebars": "^4.0.4",
"handlebars-loader": "^1.1.4",
"i18n-webpack-plugin": "^0.2.7",
"webpack": "^1.10.1",
"webpack-dev-server": "^1.7.0"
-3
View File
@@ -23,7 +23,6 @@ var webpack = require( 'webpack' ),
// mvc
'libs/underscore',
'libs/backbone',
'libs/handlebars.runtime',
// all pages get these
'ui/autocom_tagging',
'layout/modal',
@@ -54,7 +53,6 @@ module.exports = {
},
module : {
loaders : [
{ test : /\.handlebars$/, loader : 'handlebars-loader' },
],
},
resolveLoader : {
@@ -74,7 +72,6 @@ module.exports = {
'window.jQuery': 'jquery',
_: "underscore",
Backbone: 'libs/backbone',
Handlebars: 'libs/handlebars.runtime'
}),
// new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 })
],
+24 -3
View File
@@ -172,7 +172,7 @@ paste.app_factory = galaxy.web.buildapp:app_factory
# from the Tool Shed will fail.
#tool_dependency_dir = None
# The dependency resolves config file specifies an ordering and options for how
# The dependency resolves config file specifies an ordering and options for how
# Galaxy resolves tool dependencies (requirement tags in Tool XML). The default
# ordering is to the use the tool shed for tools installed that way, use local
# Galaxy packages, and then use conda if available.
@@ -301,6 +301,19 @@ paste.app_factory = galaxy.web.buildapp:app_factory
# Set to false to disable various checks Galaxy will do to ensure it
# can run job scripts before attempting to execute or submit them.
#check_job_script_integrity = True
# Number of checks to execute if check_job_script_integrity is enabled.
#check_job_script_integrity_count = 35
# Time to sleep between checks if check_job_script_integrity is enabled (in seconds).
#check_job_script_integrity_sleep = .25
# Set the default shell used by jobs Galaxy-wide. This defaults to
# sh and can be overidden at the destination level for
# heterogenous clusters. conda job resolution requires bash or zsh
# so if this is not switched to /bin/bash for instance - conda resolution
# should be disabled. (16.01 will likely be the last release with a
# default of /bin/sh instead of /bin/bash).
#default_job_shell = /bin/sh
# Citation related caching. Tool citations information maybe fetched from
# external sources such as http://dx.doi.org/ by Galaxy - the following
@@ -662,6 +675,14 @@ nglims_config_file = tool-data/nglims.yaml
# by setting the following option to True.
#serve_xss_vulnerable_mimetypes = False
# Return a Access-Control-Allow-Origin response header that matches the Origin
# header of the request if that Origin hostname matches one of the strings or
# regular expressions listed here. This is a comma separated list of hostname
# strings or regular expressions beginning and ending with /.
# E.g. mysite.com,google.com,usegalaxy.org,/^[\w\.]*example\.com/
# See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
#allowed_origin_hostnames = None
# Set the following to True to use IPython nbconvert to build HTML from IPython
# notebooks in Galaxy histories. This process may allow users to execute
# arbitrary code or serve arbitrary HTML. If enabled, IPython must be
@@ -878,8 +899,8 @@ use_interactive = True
# Set the following to a number of threads greater than 1 to spawn
# a Python task queue for dealing with large tool submissions (either
# through the tool form or as part of an individual workflow step across
# large collection). The size of a "large" tool request is controlled by
# the second parameter below and defaults to 10. This affects workflow
# large collection). The size of a "large" tool request is controlled by
# the second parameter below and defaults to 10. This affects workflow
# scheduling and web processes, not job handlers.
#tool_submission_burst_threads = 1
#tool_submission_burst_at = 10
@@ -0,0 +1,77 @@
name: Scratchbook - Introduction
title_default: "Scratchbook Introduction"
description: "An introduction on how to display multiple datasets and visualizations next to each other."
steps:
- content: "This short tour will walk you through <b>Galaxy's Scratchbook</b> feature"
- element: "#tool-panel-upload-button"
intro: "Before using the Scratchbook, we will upload some tabular data."
position: "right"
postclick:
- "#tool-panel-upload-button"
- element: "#btn-new"
intro: "We will be using the paste feature to create a new dataset."
position: "top"
postclick:
- "#btn-new"
- element: ".text-content:first"
intro: "...and paste content into the text area field."
position: "top"
textinsert: |
1 0.039 0.000
2 0.455 0.000
3 0.472 0.000
4 0.030 0.000
5 0.000 0.000
6 0.000 0.000
7 0.000 0.000
8 0.000 0.000
- element: ".upload-settings:first"
intro: "Now, we may further configure the upload content."
position: "right"
postclick:
- ".upload-settings:first"
- element: ".upload-space_to_tab:first"
intro: "...by specifying that all spaces in our table should be converted into tabs."
position: "left"
postclick:
- ".upload-space_to_tab:first"
- element: "#btn-start"
intro: "Upload the data into your Galaxy history."
position: "top"
postclick:
- "#btn-start"
- element: "#btn-close"
intro: "Hit the close button to close the upload dialog."
position: "top"
postclick:
- "#btn-close"
- element: "#enable-scratchbook > .dropdown > .dropdown-toggle"
intro: "Clicking this button will enable Galaxy's Scratchbook mode."
position: "right"
postclick:
- "#enable-scratchbook > .dropdown > .dropdown-toggle"
- element: "#right"
intro: "This is your history. It contains all datasets you are currently working with including our uploaded table."
position: "left"
- element: ".fa-eye:first"
intro: "Clicking the eye-icon usually displays a dataset in the center panel."
position: "left"
postclick:
- ".fa-eye:first"
- element: "#frame-0"
intro: "However while in Scratchbook mode, the dataset will be shown as resizable window."
position: "right"
- title: "Done."
intro: "You have created a Scratchbook view. Click on the background and select more datasets."
File diff suppressed because one or more lines are too long
@@ -5,29 +5,13 @@ module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON( 'package.json' ),
handlebars: {
// compile all hb templates into a single file in the build dir
compile: {
options: {
namespace: 'scatterplot',
processName : function( filepath ){
return filepath.match( /\w*\.handlebars/ )[0].replace( '.handlebars', '' );
}
},
files: {
"build/compiled-templates.js" : "src/handlebars/*.handlebars"
}
}
},
concat: {
// concat the template file and any js files in the src dir into a single file in the build dir
// concat any js files in the src dir into a single file in the build dir
options: {
separator: ';\n'
},
dist: {
//NOTE: mvc references templates - templates must be cat'd first
src : [ 'build/compiled-templates.js', 'src/**/*.js' ],
src : [ 'src/**/*.js' ],
dest: 'build/scatterplot-concat.js'
}
},
@@ -47,17 +31,16 @@ module.exports = function(grunt) {
watch: {
// watch for changes in the src dir
files: [ 'src/**.js', 'src/handlebars/*.handlebars' ],
files: [ 'src/**.js' ],
tasks: [ 'default' ]
}
});
grunt.loadNpmTasks( 'grunt-contrib-handlebars' );
grunt.loadNpmTasks( 'grunt-contrib-concat' );
grunt.loadNpmTasks( 'grunt-contrib-uglify' );
grunt.loadNpmTasks( 'grunt-contrib-watch' );
grunt.registerTask( 'default', [ 'handlebars', 'concat', 'uglify' ]);
grunt.registerTask( 'default', [ 'concat', 'uglify' ]);
// you can run grunt watch directly:
// grunt watch
};
@@ -17,7 +17,6 @@
"grunt": "~0.4.1",
"grunt-cli": "~0.1.9",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-handlebars": "^0.9.3",
"grunt-contrib-uglify": "~0.2.2",
"grunt-contrib-watch": "~0.5.3"
}
@@ -1,47 +0,0 @@
<p class="help-text">
Use the following controls to how the chart is displayed.
The slide controls can be moved by the mouse or, if the 'handle' is in focus, your keyboard's arrow keys.
Move the focus between controls by using the tab or shift+tab keys on your keyboard.
Use the 'Draw' button to render (or re-render) the chart with the current settings.
</p>
<div data-config-key="datapointSize" class="form-input numeric-slider-input">
<label for="datapointSize">Size of data point: </label>
<div class="slider-output">{{datapointSize}}</div>
<div class="slider"></div>
<p class="form-help help-text-small">
Size of the graphic representation of each data point
</p>
</div>
<div data-config-key="width" class="form-input numeric-slider-input">
<label for="width">Chart width: </label>
<div class="slider-output">{{width}}</div>
<div class="slider"></div>
<p class="form-help help-text-small">
(not including chart margins and axes)
</p>
</div>
<div data-config-key="height" class="form-input numeric-slider-input">
<label for="height">Chart height: </label>
<div class="slider-output">{{height}}</div>
<div class="slider"></div>
<p class="form-help help-text-small">
(not including chart margins and axes)
</p>
</div>
<div data-config-key="X-axis-label"class="text-input form-input">
<label for="X-axis-label">Re-label the X axis: </label>
<input type="text" name="X-axis-label" id="X-axis-label" value="{{xLabel}}" />
<p class="form-help help-text-small"></p>
</div>
<div data-config-key="Y-axis-label" class="text-input form-input">
<label for="Y-axis-label">Re-label the Y axis: </label>
<input type="text" name="Y-axis-label" id="Y-axis-label" value="{{yLabel}}" />
<p class="form-help help-text-small"></p>
</div>
<button class="render-button btn btn-primary active">Draw</button>
@@ -1,24 +0,0 @@
<p class="help-text">
Use the following control to change which columns are used by the chart. Click any cell
from the last three rows of the table to select the column for the appropriate data.
Use the 'Draw' button to render (or re-render) the chart with the current settings.
</p>
<ul class="help-text" style="margin-left: 8px">
<li><b>X Column</b>: which column values will be used for the x axis of the chart.</li>
<li><b>Y Column</b>: which column values will be used for the y axis of the chart.</li>
<li><b>ID Column</b>: an additional column value displayed when the user hovers over a data point.
It may be useful to select unique or categorical identifiers here (such as gene ids).
</li>
</ul>
<div class="column-selection">
<pre class="peek">{{{ peek }}}</pre>
</div>
<p class="help-text help-text-small">
<b>Note</b>: If it can be determined from the dataset's filetype that a column is not numeric,
that column choice may be disabled for either the x or y axis.
</p>
<button class="render-button btn btn-primary active">Draw</button>
@@ -1,42 +0,0 @@
<div class="scatterplot-editor tabbable tabs-left">
{{! tab buttons/headers using Bootstrap }}
<ul class="nav nav-tabs">
{{! start with the data controls as the displayed tab }}
<li class="active">
<a title="Use this tab to change which data are used"
href="#data-control" data-toggle="tab">Data Controls</a>
</li>
<li>
<a title="Use this tab to change how the chart is drawn"
href="#chart-control" data-toggle="tab" >Chart Controls</a>
</li>
{{! chart starts as disabled since there's no info yet }}
<li class="disabled">
<a title="This tab will display the chart"
href="#chart-display" data-toggle="tab">Chart</a>
</li>
{{! ... }}
<li class="file-controls">
<!-- <button class="copy-btn btn btn-default"
title="Save this as a new visualization">Save to new</button>-->
<button class="save-btn btn btn-default">Save</button>
</li>
</ul>
{{! data form, chart config form, chart all get their own tab }}
<div class="tab-content">
{{! ---------------------------- tab for data settings form }}
<div id="data-control" class="scatterplot-config-control tab-pane active">
{{! rendered separately }}
</div>
{{! ---------------------------- tab for chart graphics control form }}
<div id="chart-control" class="scatterplot-config-control tab-pane">
{{! rendered separately }}
</div>
{{! ---------------------------- tab for actual chart }}
<div id="chart-display" class="scatterplot-display tab-pane"></div>
</div>{{! end .tab-content }}
</div>{{! end .chart-control }}
@@ -18,7 +18,7 @@ todo:
Drag & Drop other splots onto current (redraw with new axis and differentiate the datasets)
Remove 'chart' namessave
Somehow link out from info box?
Subclass on specific datatypes? (vcf, cuffdiff, etc.)
What can be common/useful to other visualizations?
@@ -33,7 +33,7 @@ var ScatterplotConfigEditor = Backbone.View.extend({
//TODO: !should be a view on a visualization model
//logger : console,
className : 'scatterplot-control-form',
/** initialize requires a configuration Object containing a dataset Object */
initialize : function( attributes ){
if( !this.model ){
@@ -139,7 +139,7 @@ var ScatterplotConfigEditor = Backbone.View.extend({
$dataControl.find( '[title]' ).tooltip();
return $dataControl;
},
/** tab content to control how the chart is rendered (data glyph size, chart size, etc.) */
_render_chartControls : function( $where ){
//TODO: as controls on actual chart
@@ -147,7 +147,7 @@ var ScatterplotConfigEditor = Backbone.View.extend({
var editor = this,
config = this.model.get( 'config' ),
$chartControls = $where.find( '#chart-control' );
// ---- skeleton/form for controls
$chartControls.html( ScatterplotConfigEditor.templates.chartControl( config ) );
//console.debug( '$chartControl:', $chartControls );
@@ -258,9 +258,130 @@ var ScatterplotConfigEditor = Backbone.View.extend({
});
ScatterplotConfigEditor.templates = {
mainLayout : scatterplot.editor,
dataControl : scatterplot.datacontrol,
chartControl : scatterplot.chartcontrol
// tabbed, main layout for the editor (not used for scatterplot-display)
mainLayout : _.template([
'<div class="scatterplot-editor tabbable tabs-left">',
// tab buttons/headers using Bootstrap
'<ul class="nav nav-tabs">',
// start with the data controls as the displayed tab
'<li class="active">',
'<a title="Use this tab to change which data are used"',
'href="#data-control" data-toggle="tab">Data Controls</a>',
'</li>',
'<li>',
'<a title="Use this tab to change how the chart is drawn"',
'href="#chart-control" data-toggle="tab" >Chart Controls</a>',
'</li>',
// chart starts as disabled since there's no info yet
'<li class="disabled">',
'<a title="This tab will display the chart"',
'href="#chart-display" data-toggle="tab">Chart</a>',
'</li>',
// button for saving the visualization config on the server
'<li class="file-controls">',
'<button class="save-btn btn btn-default">Save</button>',
'</li>',
'</ul>',
// data form, chart config form, chart all get their own tab
'<div class="tab-content">',
// tab for data settings form
'<div id="data-control" class="scatterplot-config-control tab-pane active"></div>',
// tab for chart graphics control form
'<div id="chart-control" class="scatterplot-config-control tab-pane"></div>',
// tab for actual chart
'<div id="chart-display" class="scatterplot-display tab-pane"></div>',
'</div>',
'</div>',
].join('')),
// the controls for data selection (this is mostly done with column selector now)
// TODO: this could be moved to the main template above
// TODO: localize
dataControl : _.template([
'<p class="help-text">',
'Use the following control to change which columns are used by the chart. Click any cell ',
'from the last three rows of the table to select the column for the appropriate data. ',
'Use the \'Draw\' button to render (or re-render) the chart with the current settings. ',
'</p>',
'<ul class="help-text" style="margin-left: 8px">',
'<li><b>X Column</b>: which column values will be used for the x axis of the chart.</li>',
'<li><b>Y Column</b>: which column values will be used for the y axis of the chart.</li>',
'<li><b>ID Column</b>: an additional column value displayed when the user hovers over a data point. ',
'It may be useful to select unique or categorical identifiers here (such as gene ids).',
'</li>',
'</ul>',
'<div class="column-selection">',
// the only dynamic thing
'<pre class="peek"><%= peek %></pre>',
'</div>',
'<p class="help-text help-text-small">',
'<b>Note</b>: If it can be determined from the dataset\'s filetype that a column is not numeric, ',
'that column choice may be disabled for either the x or y axis.',
'</p>',
'<button class="render-button btn btn-primary active">Draw</button>',
].join('')),
chartControl : _.template([
'<p class="help-text">',
'Use the following controls to how the chart is displayed. The slide controls can be moved ',
'by the mouse or, if the \'handle\' is in focus, your keyboard\'s arrow keys. ',
'Move the focus between controls by using the tab or shift+tab keys on your keyboard. ',
'Use the \'Draw\' button to render (or re-render) the chart with the current settings. ',
'</p>',
'<div data-config-key="datapointSize" class="form-input numeric-slider-input">',
'<label for="datapointSize">Size of data point: </label>',
'<div class="slider-output"><%- datapointSize %></div>',
'<div class="slider"></div>',
'<p class="form-help help-text-small">',
'Size of the graphic representation of each data point',
'</p>',
'</div>',
'<div data-config-key="width" class="form-input numeric-slider-input">',
'<label for="width">Chart width: </label>',
'<div class="slider-output"><%- width %></div>',
'<div class="slider"></div>',
'<p class="form-help help-text-small">',
'(not including chart margins and axes)',
'</p>',
'</div>',
'<div data-config-key="height" class="form-input numeric-slider-input">',
'<label for="height">Chart height: </label>',
'<div class="slider-output"><%- height %></div>',
'<div class="slider"></div>',
'<p class="form-help help-text-small">',
'(not including chart margins and axes)',
'</p>',
'</div>',
'<div data-config-key="X-axis-label"class="text-input form-input">',
'<label for="X-axis-label">Re-label the X axis: </label>',
'<input type="text" name="X-axis-label" id="X-axis-label" value="<%- xLabel %>" />',
'<p class="form-help help-text-small"></p>',
'</div>',
'<div data-config-key="Y-axis-label" class="text-input form-input">',
'<label for="Y-axis-label">Re-label the Y axis: </label>',
'<input type="text" name="Y-axis-label" id="Y-axis-label" value="<%- yLabel %>" />',
'<p class="form-help help-text-small"></p>',
'</div>',
'<button class="render-button btn btn-primary active">Draw</button>',
].join('')),
// mainLayout : scatterplot.editor,
// dataControl : scatterplot.datacontrol,
// chartControl : scatterplot.chartcontrol
};
//==============================================================================
File diff suppressed because one or more lines are too long
@@ -30,7 +30,6 @@ ${h.js( 'libs/jquery/jquery',
'libs/underscore',
'libs/backbone/backbone',
'libs/d3',
'libs/handlebars.runtime',
'ui/peek-column-selector',
'ui/pagination',
'mvc/visualization/visualization-model' )}
+20
View File
@@ -169,6 +169,7 @@ class Configuration( object ):
self.job_queue_cleanup_interval = int( kwargs.get("job_queue_cleanup_interval", "5") )
self.cluster_files_directory = os.path.abspath( kwargs.get( "cluster_files_directory", "database/pbs" ) )
self.job_working_directory = resolve_path( kwargs.get( "job_working_directory", "database/job_working_directory" ), self.root )
self.default_job_shell = kwargs.get( "default_job_shell", "/bin/sh" )
self.cleanup_job = kwargs.get( "cleanup_job", "always" )
self.container_image_cache_path = self.resolve_path( kwargs.get( "container_image_cache_path", "database/container_images" ) )
self.outputs_to_working_directory = string_as_bool( kwargs.get( 'outputs_to_working_directory', False ) )
@@ -262,6 +263,7 @@ class Configuration( object ):
if kwargs.get('sanitize_whitelist_file', None) is not None:
self.reload_sanitize_whitelist()
self.serve_xss_vulnerable_mimetypes = string_as_bool( kwargs.get( 'serve_xss_vulnerable_mimetypes', False ) )
self.allowed_origin_hostnames = self._parse_allowed_origin_hostnames( kwargs )
self.trust_ipython_notebook_conversion = string_as_bool( kwargs.get( 'trust_ipython_notebook_conversion', False ) )
self.enable_old_display_applications = string_as_bool( kwargs.get( "enable_old_display_applications", "True" ) )
self.brand = kwargs.get( 'brand', None )
@@ -671,6 +673,24 @@ class Configuration( object ):
port = None
return port
def _parse_allowed_origin_hostnames( self, kwargs ):
"""
Parse a CSV list of strings/regexp of hostnames that should be allowed
to use CORS and will be sent the Access-Control-Allow-Origin header.
"""
allowed_origin_hostnames = listify( kwargs.get( 'allowed_origin_hostnames', None ) )
if not allowed_origin_hostnames:
return None
def parse( string ):
# a string enclosed in fwd slashes will be parsed as a regexp: e.g. /<some val>/
if string[0] == '/' and string[-1] == '/':
string = string[1:-1]
return re.compile( string, flags=( re.UNICODE | re.LOCALE ) )
return string
return [ parse( v ) for v in allowed_origin_hostnames if v ]
def get_database_engine_options( kwargs, model_prefix='' ):
"""
+1
View File
@@ -81,6 +81,7 @@ class TabularData( data.Text ):
# For now, default to the old behavior, ugly as it is. Remove this after adding 'matrix'.
max_peek_size = 1000000 # 1 MB
if os.stat( dataset.file_name ).st_size < max_peek_size:
self._clean_and_set_mime_type( trans, dataset.get_mime() )
return open( dataset.file_name )
else:
trans.response.set_content_type( "text/html" )
@@ -0,0 +1,170 @@
# packages with C extensions
bx-python==0.7.3 --hash:sha256=0a0fd962edd0f9afdf5d7ccbdf46dc220a0cb652073a93411dd6f7f649f07d91 \
--hash:sha256=46dc3042c7e475363830fa92d4a613ae10b58db7f114ff8193d2ee0bc3c4607e \
--hash:sha256=b93a9378a5d0e29ea8a13e026c170f48bf1f8316a39c342b1eb54f557b4fb3c4 \
--hash:sha256=d06c7bf0ae7f019521aeb5ffe4df48bb5fdd4d75d7ad00e0059b997c4f13ca3a \
--hash:sha256=05d0ab8fd13319d5ef9edb246dc6805640ea7574bb885a0b8607474271ac5793 \
--hash:sha256=5a026869227a6464eba23835765a36ffc2910f7af51b81f672a97c0d005e04a3 \
--hash:sha256=85be43a6b94f0c841d9954f820133db35067854504c1de87dd0089bb06eca18d \
--hash:sha256=d085824eb33c54d333b99dca29b49890457a8263f431b54b17ae3052be191d2b \
--hash:sha256=41bcf85b9be9f61ba7c7bae48c5a5ae3251868a1b25f02b6eb93b29bcabfd00c \
--hash:sha256=c9b71aee26ee85fbcbb3060109d79531bfa8991f4924bdcfed63d909a5937290
MarkupSafe==0.23 --hash:sha256=3a79d9650b7e79943be51a045c7c39a77ebbe9a337e8af51a5575e39332dce87 \
--hash:sha256=e0a4155493d1cfa72e985dbe1660a44d64a173282801563956e061b24371266a \
--hash:sha256=147013ed157f1423a0d0047043c6bbccbef31a52d82e2a10dfc3c6de9392765c \
--hash:sha256=d25d14cb01284aed33690b85bfde8de206ffcfdc52351588bcf17480839bef6f \
--hash:sha256=29958f81958e0dd9f5dd36d52f2ac549d875dde3559b783578118c9005693852 \
--hash:sha256=287a1c6b0d2a08cb76be6e584bf119649405f015598cf8b78d4a592cc80700a0 \
--hash:sha256=973cadf7b9907f9c81d9b898817d6a485b37325176befec2389fa2ced4c61a51 \
--hash:sha256=a365fd3468c86741aec5901f4b07990aaa0b458fb79e9f3557378a63e6d627e9 \
--hash:sha256=ba7af558b18ba9c05bb0d36f22a5ea65ee11ba44a6cf8a2950f2f80c08260e11 \
--hash:sha256=51bf7f077938c64dd00de6732996ccee8ceba2206c69acfb07f66430ca76372f
PyYAML==3.11 --hash:sha256=2912c1fb56c316461d003a8b8f1f41e1ed8387b2e47a4523f8a4eec8aa85e241 \
--hash:sha256=f4437443dc014c04ceee8cc94d4165f01ba23643991fd2c6b919f26cf9997474 \
--hash:sha256=b62cde962d41377c175831fa3fd6ac41585d2e2111ca4c45a6ee80a832457e92 \
--hash:sha256=aad37be9d524ba2dba9a3114b620b2800b40e67e455c9741a5cb81a6a0e882f6 \
--hash:sha256=03e0f4ac96599c1d687b080f1610ab0469e8785bb48cfdf860f2076a08ea6406 \
--hash:sha256=7dc97b5b1b920f6bbe0e47cfa6ff112f6eede35924a63354f80d672354f25160 \
--hash:sha256=ceb5dccec2045d4a864c6e808b397b10830476c44bdc64b80c18bf29e481ba07 \
--hash:sha256=9b184a4a7d3d383b39cb73429d3798370facaee4263465b575f243c7ede3f9c3 \
--hash:sha256=f90314e2ed46ea2da980aff88b91c3cc8ce93edd4658011dd462a8f28399533b \
--hash:sha256=80936dca10b611cd54ca52939aac938d59653830a6a6265bef5d11896de8e249
SQLAlchemy==1.0.8 --hash:sha256=3c357f36c141205cea2b5ec4c4e9885602452fea06428d6c20596c66c9a43243 \
--hash:sha256=17fad7f37f902dbec37ca2777af3021f9a4ed31079d64f7f888e7b29517240a3 \
--hash:sha256=e177904a384b9bc68914afb32a6ed2cc73ed7787444e3e1fdf85e3b9cfe5f847 \
--hash:sha256=91ed10baf56b6e29665f2b9fcb0c690afc6cc2c2e8e19c7f92b58092a4002e14 \
--hash:sha256=f5d6156d1d7865cd23b76ddad3f53ec07a3009a2cd8082a829cd1f24b366db5c \
--hash:sha256=3c3f3baf07f868c1c3f86d63dc2efa4455e95d76745f1af561f1ccf0fd9e8c81 \
--hash:sha256=a9fb8061aa767ca2ad22983a11e074ac231f44a56709721c60cc1992f2a92350 \
--hash:sha256=884b522d2d067cffd103f4e1a5342c678803cd6903da24a3f757b57b00eb188b \
--hash:sha256=d5dde66c1603853aebbfbbd74d79c60678f7d98c17abce4be4ebbb697dfd7265 \
--hash:sha256=42346d5e91c5e0a5a975352d8af3cfd8b2dad602dd07ec41b6b848ac5205cf5b
# Mercurial >= 3.5 changed the bundle format, which breaks hg push of TS repositories
mercurial==3.4.2 --hash:sha256=7851864b03929c09e07670bf8ab7d59f3529650c935a70d09fb6ce7f6a84e2a5 \
--hash:sha256=c23b02b4c32edc2d0799221a9d35abd916fb8a1acd1c07d64c16a235ef677b9e \
--hash:sha256=ca72ddfaea681a070b62edcb8e41d58bd24a2b04f73e66658565d189a76f3819 \
--hash:sha256=fdad4496f3d7f3e7eced771fa46e21c074989f8437ddf3e0ff6c0eee964e4c29 \
--hash:sha256=964a10ec1114dbee3696134bafed676f66038759b73de8593f92616f0e53f371 \
--hash:sha256=c6ca6fbe56a8919dfc521e80ab781ab565760d87f4a6170e788d67eb6d69d30f \
--hash:sha256=69540318fa9f7a3a0428647003d4f1fa8865d29648e73999b921cae039145ce9 \
--hash:sha256=b3de0ee851cf8750f53102437c9a04c7217a8c6f7411030ab3bb5534885f3315 \
--hash:sha256=46f67af52c7b1aed68b67daa33c26eafc0fb1d371954d3266fce739446cfcb1d \
--hash:sha256=000afb932f0ae45c365cbc0457044e8800811fdad7eee9332b6403b83423ab0a
numpy==1.9.2 --hash:sha256=931ce6fd1180a10d58a925b614775706c05de35bca5805e705e1da17e1326862 \
--hash:sha256=2340c4b72fdab79ac0fc04bb6629b26eeb93d10f4945b6b1f07d9be8663cab84 \
--hash:sha256=83fe34ff67653a639c57cfd04a0d48dda5913250fd95c8466af1d8416b58af59 \
--hash:sha256=aeb182d95ddb2dfd81683907be193cfc11c4d0ba744faf457013499fa14a131e \
--hash:sha256=d6f1eec7ae250892a2b142af406e43760042badae8e2f168136eace5dd9f05c3 \
--hash:sha256=0b0883cac08e3c0999159ba7f34c9b94d26d7d1a2be4017b792145d722646fb7 \
--hash:sha256=a124d11b1bec5c517d60ad9414564b5af0828421112d2a00771d22715eab1c3c \
--hash:sha256=fabc2f76266de7396e2752baabf287cdd0cc2ed23c1f36ca3c3e8b094e86b87c \
--hash:sha256=f83a667d3a38643b3bf6361904cd6c4f2a18d1420c2204c7f269cd36b730c404 \
--hash:sha256=dab9bd8c867403340b370ea383c8eda3dc984dd5efc91904a5695e00b1762fc9
pycrypto==2.6.1 --hash:sha256=44c20785a1057b8d5e190d6a1847f7c62a8180b9b27a3aca7c3ec920bfb8e7b7 \
--hash:sha256=785ba61251cda6e574e0affc4412c346ef615455b81287fe0d6a2e1c5aed5172 \
--hash:sha256=5ec40d95520a665843915763c8cbbf40457330bd7ebf2a55ffea1b10a519d12b \
--hash:sha256=2cb43f0b293a18e6d5818287150994cf6083b1a9cdff65c19d1150a34aa813bc \
--hash:sha256=d48e46f4ccd5c21f3e01bbdbd8e7a86443fc7abdf3f93829c3d04ed684ec22c5 \
--hash:sha256=30312bd39f45c91f287f3e6e54c40988d30b1be9a9f332585e3cc00ee5f91554 \
--hash:sha256=d129d6d3441efecf2bc7e6b36cb35e99642248d72dbf59b992e6940b9359dabc \
--hash:sha256=8884b92835a1c0c763099981d19c990fdc3ae2b7011eb93b1f96e34a346b2d2f \
--hash:sha256=7e7e9abc0ae522ae86772d98b7144e0d2ef7791d124936f283680f84fe8cce6c \
--hash:sha256=61d3b42eaf89108b8a24c3736fb770f768efb89b1efaf0825efb5c316f0bffdc
# Install python_lzo if you want to support indexed access to lzo-compressed
# locally cached maf files via bx-python
#python_lzo==1.8 --hash:sha256=638b38bc1d83561a9807365676f5b2ba6f18491753a673e6a9c5913bd542fe1a \
# --hash:sha256=cda3d6c27e69a9d04eb96db6b4b96fbe7facdd11dc2b9a82fe3c65b84b40fe44 \
# --hash:sha256=7ededfdb65b4eb282a7cc1600c6f5b4f483b39a70b3460c2f4651ee8fc431f77 \
# --hash:sha256=86a61008a8ab5f8ca973bd7e7b1d031c89637257dcf7215bff1913f17d3c596f \
# --hash:sha256=1d6af33e40383dba0c3ee26eee3e501e805fe42537dd0096788190bbc8fd7aae \
# --hash:sha256=6d08ad35322a5969dfd8ef5af7ff4cdf625d6a7bfa8e915b77f5935f58e1c7b1 \
# --hash:sha256=99b7e0c186c5b84d80de6e7b70359b6fc456c02bd2b31fc598140fbc6618d651 \
# --hash:sha256=be967c38c4e33f66823d10fb5efca42a0a23269459ce41239c173ccc114b603e \
# --hash:sha256=a34d7431e30c6d61c22b92d51224ea34d68be51aa42ec95a053b7f19be3fef0d \
# --hash:sha256=be76281c1c7f24d44e3415787d2a05688f6bbda2dc9bba92155ae3ca0d6716e7
# pure Python packages
Paste==2.0.2 --hash:sha256=4e7bb2d8cbdc47ab46e4af0cb61d2af91fccc620a08415d9c4da9e499f0455fd
PasteDeploy==1.5.2 --hash:sha256=3922127d3acc6e274a800978b9293c874b3ef4ac2eb8bf485e2c85b22d1f260a
docutils==0.12 --hash:sha256=732dfc2d706ea390c264bc69110d3d6c7c3a520628a052ccc5998466f95d5c29
wchartype==0.1 --hash:sha256=2932471fe3a4e5cac4539c1b49bbc2bbd24ec3f00532c7f27c80b7756fdc177d
repoze.lru==0.6 --hash:sha256=731cc0b0a184c9fd270a4f29d9635099bb0398823e9a1a39bf4f488d1ead57b3
Routes==2.2 --hash:sha256=1d61dc9f1bbd86504de221568743133fbdfeb70f11cee4222cef72aa108e834c
WebOb==1.4.1 --hash:sha256=dc3c45ac0b56a3c65f47f1da6c23760dfe0139e8a84caaf1cfc9276b3e10875a
WebHelpers==1.3 --hash:sha256=8969ec3fb851872096067a805d512c3bed1952e6fc66f1ef1d1c6a7470937688
Mako==1.0.2 --hash:sha256=d3f372cbc2e7de080b5f7056d160f3ac8279353a2ea8f1ef8fd5b0cf0a6a3b17
pytz==2015.4 --hash:sha256=3bec70eef120ad0bf9143e59bbf36715ec1232fb0550ae2b8aa6c107aacfa6f2
Babel==2.0 --hash:sha256=aa725635ef189f77b6b0579efe1e91602d7cf63a31f6dd719a88ee53642bb5ab
Beaker==1.7.0 --hash:sha256=334427853ac291e4ecd1e03addb48e231681ab9b6c2bc793c0f0fb98024b70b1
# Cheetah and dependencies
Cheetah==2.4.4 --hash:sha256=24cf67789b7a9f1e0a55cba266b6aad16e97aaf25810fd6f2f7e7b36005c1161 \
--hash:sha256=30c6dd32c066f483462cebc7fc37feb454d6a3d35e8b599da17624b2541761ab \
--hash:sha256=fcbff7d96509419cbcefa231d6fee4aca98d2f04f8339848c19da3e82aebcf27 \
--hash:sha256=5c758550b8170b01e016b75ec05dbd2c32b56513d6e1ef9177c5290f4e166ad2 \
--hash:sha256=6aaeef7f742df6a23c4132bb33000196053b661a150fdd98311f25f09d3730c1 \
--hash:sha256=469e7ddc2f4a9b147b2b5c258fc9f97cee9842790c1849b941bae165b390da92 \
--hash:sha256=75f05eda3b16c621b5b570f9c5b317f6ea94b01296b9e1ef2583560d153578bd \
--hash:sha256=6da983e9d189a3c389e98506871ff836a83df1792dba5e4a684d27d948402d7a \
--hash:sha256=55b0c2696eb321415a9eca86303e3c359dee550d7f6fc719bc960f23422d2290 \
--hash:sha256=2caf567b6cdd54f806ce12d98302e380d4bbbed8990663f9bce52d69358fc488
Markdown==2.6.3 --hash:sha256=59417f5eb3dace08309d81e48fc903217d12d66677f367674b22c317b0f04284
# BioBlend and dependencies
bioblend==0.6.1 --hash:sha256=f5eea1f6c31264ef7bfab8c70deac2b9229a10e5c56508a6542f5643ad9e2a5b
boto==2.38.0 --hash:sha256=1760584368da0c3861dbed448dcb439334ce831044262a5ca5188167f8bba585
requests==2.8.1 --hash:sha256=70e285122c97b1d104824482cb929246b2b8a2b9858897c4fab3acec83f1e03c
requests-toolbelt==0.4.0 --hash:sha256=94694e32845b84ed2186fdf56219b949582ebd08dc3abc55c0549958f2029643
# kombu and dependencies
kombu==3.0.30 --hash:sha256=562010f0deb1f04e3abd154b0ef5e246d606b54cb2c5f29e8c4651b354d0b082 \
--hash:sha256=5baff23a2b2d78eecb7c97700ea359ab80744c719e311fb446513d7b72ddbc96
amqp==1.4.8 --hash:sha256=c7874d845c9bdffbf754ce84f105a1b8c7a6cffb61f362ac67591536ba8c0c1a \
--hash:sha256=caada1c29d5e73e13ed8706442ee0fbb1440de9b6fca4df12fc8ff59dd61f6f6
anyjson==0.3.3 --hash:sha256=2c84f23be20e3c465151a55917b8e38a04c579394057e232c16fb5ca0c6ae108
# sqlalchemy-migrate and dependencies
sqlalchemy-migrate==0.10.0 --hash:sha256=2aaa4e7070c8447d564f1c173937c2c5a45f889eb31a0fc80add5fc175c45a5e
decorator==4.0.2 --hash:sha256=d8c3f7e18efba558084648d6dd6c6b0850e6f5c08c392975ae196c4b4eb7be2a
Tempita==0.5.3dev --hash:sha256=df0c6513e565b213733b3f8bf7bcca75998f166042692e1712e3fe36568db234
sqlparse==0.1.16 --hash:sha256=221d383f1236f9c05aadd2c4edf4274144279ad06821d7d9bf5a70751157f75d
pbr==1.8.0 --hash:sha256=355a0c2ba71120dce1c522387e494c60eb4f44fa9d03067cb9816187e6e803e9
# six is also a Pulsar client dep
six==1.9.0 --hash:sha256=cf806ab65d5e16561df30c2cea2fb2cf3e6aa82e48f22036dff177e20f61e188
Parsley==1.3 --hash:sha256=32fd648334146e4005dae41d559d32edfff9f3d5f503f8b5d233dbfe3a15a28b
nose==1.3.7 --hash:sha256=f36054c5786e84ff6b131f3249a3cce82787f1a930ab053287c0edaa9f840d0f
SVGFig==1.1.6 --hash:sha256=300cf4b37b4773498d4ea96c703cdb5f09215978b02828dadb786fb248e0b54b
# Fabric and dependencies
Fabric==1.10.2 --hash:sha256=8fe1eb0b0f271e2d41445e7da4470548d3bdf882aab1c1f143505c599996793b
paramiko==1.15.2 --hash:sha256=c92b168c8db94a9e1362f3fc27bc21e8c20794885bf2f7d303b5ad717c044ebc
ecdsa==0.13 --hash:sha256=89f149066e4a1e419892cef830fd0db85c227d5d427f7075422ace83429e2d26
# pycrypto, but it is a direct Galaxy dependency as well
# Can't use Whoosh latest due to a bug but need to backport a bugfix from a
# newer release.
#
# https://bitbucket.org/mchaput/whoosh/pull-requests/50/fix-lru-thread-safety/diff
Whoosh==2.4.1+gx1 --hash:sha256=98897e796c048810d71f7f4fc174914869f1b3b77f44e5a19a5e649b078d5e0e \
--hash:sha256=5ec3c22e782c86e981fab62a24ac9feea09e42c43b763a6493c78b82a3b6e3fd
# Flexible BAM index naming
pysam==0.8.3+gx1 --hash:sha256=020aa9101579ac1e82a194fdb08f49f517c634911409e9a2cda4d0a1c72a8c7c \
--hash:sha256=1a3d86849b9bd962979b65aaa9af236030dcc1db40296c88d2aa436a0c9df79b \
--hash:sha256=0fc55fb252eb0e7914679e9e22672fdc6a1e09804cbcc62769f004ebbed9b4c1 \
--hash:sha256=dde8f5037661d7be42e2c3f50c01566dcaedbf2f88133a3bb50c6ae3f75e6e13 \
--hash:sha256=7809fd926a071519c0a2b220346e45c094577877e5b2adba2903e7b52490c736 \
--hash:sha256=021070ed70a89e19eee6a989933d69d0bdb076c02342e2987bb5fab43f63ad17 \
--hash:sha256=374ea868bf64daa4665e8743db1be2e88712953a923020225f57a589b790537c \
--hash:sha256=9884b6904face1977649847261e7c984120adaa169a0d62e07820a44c71e18c5 \
--hash:sha256=873b81951e9d572b53ab4c7a0d3ef915f7d0e1db5f75603d8861cf1d3810491e \
--hash:sha256=37d0ba3880b5a517f354281159f6751f6f9f1c1074ea48bf5f4c424e6ec488dd \
--hash:sha256=db99cb20cb5e07998b2acfd29e34c367ef408a184a7b3150586212175a0719bf \
--hash:sha256=a1fcb2a6459b799bff7a046e190452b151c5985dea404eaee82bd645b1bfe34d \
--hash:sha256=306e4d900dfb582cf87bc21904e2193ef81db76173e976b74152c95ddd93bdc6 \
--hash:sha256=2341438d636b8e3cb51b219aab1cc909142d3af176042d12b128d4177682b1ab \
--hash:sha256=0f33df9eba7b079b7489ac3dd908a6e44b0e98d094e633b29035d33bfc990b9e \
--hash:sha256=faa8aae3f8f105c5c823a7d570dd3caba31ece69b8f3325106435b9f1fcb68d2 \
--hash:sha256=2db995758d666c51fecf11cbee1afda357477e01077aacf68ae0c00304c7bc51 \
--hash:sha256=2de7a2098f64672d0396ac727633285f3562f804e7845e105ee19da544d7da8a
+43 -144
View File
@@ -1,170 +1,69 @@
# packages with C extensions
bx-python==0.7.3 --hash:sha256=0a0fd962edd0f9afdf5d7ccbdf46dc220a0cb652073a93411dd6f7f649f07d91 \
--hash:sha256=46dc3042c7e475363830fa92d4a613ae10b58db7f114ff8193d2ee0bc3c4607e \
--hash:sha256=b93a9378a5d0e29ea8a13e026c170f48bf1f8316a39c342b1eb54f557b4fb3c4 \
--hash:sha256=d06c7bf0ae7f019521aeb5ffe4df48bb5fdd4d75d7ad00e0059b997c4f13ca3a \
--hash:sha256=05d0ab8fd13319d5ef9edb246dc6805640ea7574bb885a0b8607474271ac5793 \
--hash:sha256=5a026869227a6464eba23835765a36ffc2910f7af51b81f672a97c0d005e04a3 \
--hash:sha256=85be43a6b94f0c841d9954f820133db35067854504c1de87dd0089bb06eca18d \
--hash:sha256=d085824eb33c54d333b99dca29b49890457a8263f431b54b17ae3052be191d2b \
--hash:sha256=41bcf85b9be9f61ba7c7bae48c5a5ae3251868a1b25f02b6eb93b29bcabfd00c \
--hash:sha256=c9b71aee26ee85fbcbb3060109d79531bfa8991f4924bdcfed63d909a5937290
MarkupSafe==0.23 --hash:sha256=3a79d9650b7e79943be51a045c7c39a77ebbe9a337e8af51a5575e39332dce87 \
--hash:sha256=e0a4155493d1cfa72e985dbe1660a44d64a173282801563956e061b24371266a \
--hash:sha256=147013ed157f1423a0d0047043c6bbccbef31a52d82e2a10dfc3c6de9392765c \
--hash:sha256=d25d14cb01284aed33690b85bfde8de206ffcfdc52351588bcf17480839bef6f \
--hash:sha256=29958f81958e0dd9f5dd36d52f2ac549d875dde3559b783578118c9005693852 \
--hash:sha256=287a1c6b0d2a08cb76be6e584bf119649405f015598cf8b78d4a592cc80700a0 \
--hash:sha256=973cadf7b9907f9c81d9b898817d6a485b37325176befec2389fa2ced4c61a51 \
--hash:sha256=a365fd3468c86741aec5901f4b07990aaa0b458fb79e9f3557378a63e6d627e9 \
--hash:sha256=ba7af558b18ba9c05bb0d36f22a5ea65ee11ba44a6cf8a2950f2f80c08260e11 \
--hash:sha256=51bf7f077938c64dd00de6732996ccee8ceba2206c69acfb07f66430ca76372f
PyYAML==3.11 --hash:sha256=2912c1fb56c316461d003a8b8f1f41e1ed8387b2e47a4523f8a4eec8aa85e241 \
--hash:sha256=f4437443dc014c04ceee8cc94d4165f01ba23643991fd2c6b919f26cf9997474 \
--hash:sha256=b62cde962d41377c175831fa3fd6ac41585d2e2111ca4c45a6ee80a832457e92 \
--hash:sha256=aad37be9d524ba2dba9a3114b620b2800b40e67e455c9741a5cb81a6a0e882f6 \
--hash:sha256=03e0f4ac96599c1d687b080f1610ab0469e8785bb48cfdf860f2076a08ea6406 \
--hash:sha256=7dc97b5b1b920f6bbe0e47cfa6ff112f6eede35924a63354f80d672354f25160 \
--hash:sha256=ceb5dccec2045d4a864c6e808b397b10830476c44bdc64b80c18bf29e481ba07 \
--hash:sha256=9b184a4a7d3d383b39cb73429d3798370facaee4263465b575f243c7ede3f9c3 \
--hash:sha256=f90314e2ed46ea2da980aff88b91c3cc8ce93edd4658011dd462a8f28399533b \
--hash:sha256=80936dca10b611cd54ca52939aac938d59653830a6a6265bef5d11896de8e249
SQLAlchemy==1.0.8 --hash:sha256=3c357f36c141205cea2b5ec4c4e9885602452fea06428d6c20596c66c9a43243 \
--hash:sha256=17fad7f37f902dbec37ca2777af3021f9a4ed31079d64f7f888e7b29517240a3 \
--hash:sha256=e177904a384b9bc68914afb32a6ed2cc73ed7787444e3e1fdf85e3b9cfe5f847 \
--hash:sha256=91ed10baf56b6e29665f2b9fcb0c690afc6cc2c2e8e19c7f92b58092a4002e14 \
--hash:sha256=f5d6156d1d7865cd23b76ddad3f53ec07a3009a2cd8082a829cd1f24b366db5c \
--hash:sha256=3c3f3baf07f868c1c3f86d63dc2efa4455e95d76745f1af561f1ccf0fd9e8c81 \
--hash:sha256=a9fb8061aa767ca2ad22983a11e074ac231f44a56709721c60cc1992f2a92350 \
--hash:sha256=884b522d2d067cffd103f4e1a5342c678803cd6903da24a3f757b57b00eb188b \
--hash:sha256=d5dde66c1603853aebbfbbd74d79c60678f7d98c17abce4be4ebbb697dfd7265 \
--hash:sha256=42346d5e91c5e0a5a975352d8af3cfd8b2dad602dd07ec41b6b848ac5205cf5b
bx-python==0.7.3
MarkupSafe==0.23
PyYAML==3.11
SQLAlchemy==1.0.8
# Mercurial >= 3.5 changed the bundle format, which breaks hg push of TS repositories
mercurial==3.4.2 --hash:sha256=7851864b03929c09e07670bf8ab7d59f3529650c935a70d09fb6ce7f6a84e2a5 \
--hash:sha256=c23b02b4c32edc2d0799221a9d35abd916fb8a1acd1c07d64c16a235ef677b9e \
--hash:sha256=ca72ddfaea681a070b62edcb8e41d58bd24a2b04f73e66658565d189a76f3819 \
--hash:sha256=fdad4496f3d7f3e7eced771fa46e21c074989f8437ddf3e0ff6c0eee964e4c29 \
--hash:sha256=964a10ec1114dbee3696134bafed676f66038759b73de8593f92616f0e53f371 \
--hash:sha256=c6ca6fbe56a8919dfc521e80ab781ab565760d87f4a6170e788d67eb6d69d30f \
--hash:sha256=69540318fa9f7a3a0428647003d4f1fa8865d29648e73999b921cae039145ce9 \
--hash:sha256=b3de0ee851cf8750f53102437c9a04c7217a8c6f7411030ab3bb5534885f3315 \
--hash:sha256=46f67af52c7b1aed68b67daa33c26eafc0fb1d371954d3266fce739446cfcb1d \
--hash:sha256=000afb932f0ae45c365cbc0457044e8800811fdad7eee9332b6403b83423ab0a
numpy==1.9.2 --hash:sha256=931ce6fd1180a10d58a925b614775706c05de35bca5805e705e1da17e1326862 \
--hash:sha256=2340c4b72fdab79ac0fc04bb6629b26eeb93d10f4945b6b1f07d9be8663cab84 \
--hash:sha256=83fe34ff67653a639c57cfd04a0d48dda5913250fd95c8466af1d8416b58af59 \
--hash:sha256=aeb182d95ddb2dfd81683907be193cfc11c4d0ba744faf457013499fa14a131e \
--hash:sha256=d6f1eec7ae250892a2b142af406e43760042badae8e2f168136eace5dd9f05c3 \
--hash:sha256=0b0883cac08e3c0999159ba7f34c9b94d26d7d1a2be4017b792145d722646fb7 \
--hash:sha256=a124d11b1bec5c517d60ad9414564b5af0828421112d2a00771d22715eab1c3c \
--hash:sha256=fabc2f76266de7396e2752baabf287cdd0cc2ed23c1f36ca3c3e8b094e86b87c \
--hash:sha256=f83a667d3a38643b3bf6361904cd6c4f2a18d1420c2204c7f269cd36b730c404 \
--hash:sha256=dab9bd8c867403340b370ea383c8eda3dc984dd5efc91904a5695e00b1762fc9
pycrypto==2.6.1 --hash:sha256=44c20785a1057b8d5e190d6a1847f7c62a8180b9b27a3aca7c3ec920bfb8e7b7 \
--hash:sha256=785ba61251cda6e574e0affc4412c346ef615455b81287fe0d6a2e1c5aed5172 \
--hash:sha256=5ec40d95520a665843915763c8cbbf40457330bd7ebf2a55ffea1b10a519d12b \
--hash:sha256=2cb43f0b293a18e6d5818287150994cf6083b1a9cdff65c19d1150a34aa813bc \
--hash:sha256=d48e46f4ccd5c21f3e01bbdbd8e7a86443fc7abdf3f93829c3d04ed684ec22c5 \
--hash:sha256=30312bd39f45c91f287f3e6e54c40988d30b1be9a9f332585e3cc00ee5f91554 \
--hash:sha256=d129d6d3441efecf2bc7e6b36cb35e99642248d72dbf59b992e6940b9359dabc \
--hash:sha256=8884b92835a1c0c763099981d19c990fdc3ae2b7011eb93b1f96e34a346b2d2f \
--hash:sha256=7e7e9abc0ae522ae86772d98b7144e0d2ef7791d124936f283680f84fe8cce6c \
--hash:sha256=61d3b42eaf89108b8a24c3736fb770f768efb89b1efaf0825efb5c316f0bffdc
mercurial==3.4.2
numpy==1.9.2
pycrypto==2.6.1
# Install python_lzo if you want to support indexed access to lzo-compressed
# locally cached maf files via bx-python
#python_lzo==1.8 --hash:sha256=638b38bc1d83561a9807365676f5b2ba6f18491753a673e6a9c5913bd542fe1a \
# --hash:sha256=cda3d6c27e69a9d04eb96db6b4b96fbe7facdd11dc2b9a82fe3c65b84b40fe44 \
# --hash:sha256=7ededfdb65b4eb282a7cc1600c6f5b4f483b39a70b3460c2f4651ee8fc431f77 \
# --hash:sha256=86a61008a8ab5f8ca973bd7e7b1d031c89637257dcf7215bff1913f17d3c596f \
# --hash:sha256=1d6af33e40383dba0c3ee26eee3e501e805fe42537dd0096788190bbc8fd7aae \
# --hash:sha256=6d08ad35322a5969dfd8ef5af7ff4cdf625d6a7bfa8e915b77f5935f58e1c7b1 \
# --hash:sha256=99b7e0c186c5b84d80de6e7b70359b6fc456c02bd2b31fc598140fbc6618d651 \
# --hash:sha256=be967c38c4e33f66823d10fb5efca42a0a23269459ce41239c173ccc114b603e \
# --hash:sha256=a34d7431e30c6d61c22b92d51224ea34d68be51aa42ec95a053b7f19be3fef0d \
# --hash:sha256=be76281c1c7f24d44e3415787d2a05688f6bbda2dc9bba92155ae3ca0d6716e7
#python_lzo==1.8
# pure Python packages
Paste==2.0.2 --hash:sha256=4e7bb2d8cbdc47ab46e4af0cb61d2af91fccc620a08415d9c4da9e499f0455fd
PasteDeploy==1.5.2 --hash:sha256=3922127d3acc6e274a800978b9293c874b3ef4ac2eb8bf485e2c85b22d1f260a
docutils==0.12 --hash:sha256=732dfc2d706ea390c264bc69110d3d6c7c3a520628a052ccc5998466f95d5c29
wchartype==0.1 --hash:sha256=2932471fe3a4e5cac4539c1b49bbc2bbd24ec3f00532c7f27c80b7756fdc177d
repoze.lru==0.6 --hash:sha256=731cc0b0a184c9fd270a4f29d9635099bb0398823e9a1a39bf4f488d1ead57b3
Routes==2.2 --hash:sha256=1d61dc9f1bbd86504de221568743133fbdfeb70f11cee4222cef72aa108e834c
WebOb==1.4.1 --hash:sha256=dc3c45ac0b56a3c65f47f1da6c23760dfe0139e8a84caaf1cfc9276b3e10875a
WebHelpers==1.3 --hash:sha256=8969ec3fb851872096067a805d512c3bed1952e6fc66f1ef1d1c6a7470937688
Mako==1.0.2 --hash:sha256=d3f372cbc2e7de080b5f7056d160f3ac8279353a2ea8f1ef8fd5b0cf0a6a3b17
pytz==2015.4 --hash:sha256=3bec70eef120ad0bf9143e59bbf36715ec1232fb0550ae2b8aa6c107aacfa6f2
Babel==2.0 --hash:sha256=aa725635ef189f77b6b0579efe1e91602d7cf63a31f6dd719a88ee53642bb5ab
Beaker==1.7.0 --hash:sha256=334427853ac291e4ecd1e03addb48e231681ab9b6c2bc793c0f0fb98024b70b1
Paste==2.0.2
PasteDeploy==1.5.2
docutils==0.12
wchartype==0.1
repoze.lru==0.6
Routes==2.2
WebOb==1.4.1
WebHelpers==1.3
Mako==1.0.2
pytz==2015.4
Babel==2.0
Beaker==1.7.0
# Cheetah and dependencies
Cheetah==2.4.4 --hash:sha256=24cf67789b7a9f1e0a55cba266b6aad16e97aaf25810fd6f2f7e7b36005c1161 \
--hash:sha256=30c6dd32c066f483462cebc7fc37feb454d6a3d35e8b599da17624b2541761ab \
--hash:sha256=fcbff7d96509419cbcefa231d6fee4aca98d2f04f8339848c19da3e82aebcf27 \
--hash:sha256=5c758550b8170b01e016b75ec05dbd2c32b56513d6e1ef9177c5290f4e166ad2 \
--hash:sha256=6aaeef7f742df6a23c4132bb33000196053b661a150fdd98311f25f09d3730c1 \
--hash:sha256=469e7ddc2f4a9b147b2b5c258fc9f97cee9842790c1849b941bae165b390da92 \
--hash:sha256=75f05eda3b16c621b5b570f9c5b317f6ea94b01296b9e1ef2583560d153578bd \
--hash:sha256=6da983e9d189a3c389e98506871ff836a83df1792dba5e4a684d27d948402d7a \
--hash:sha256=55b0c2696eb321415a9eca86303e3c359dee550d7f6fc719bc960f23422d2290 \
--hash:sha256=2caf567b6cdd54f806ce12d98302e380d4bbbed8990663f9bce52d69358fc488
Markdown==2.6.3 --hash:sha256=59417f5eb3dace08309d81e48fc903217d12d66677f367674b22c317b0f04284
Cheetah==2.4.4
Markdown==2.6.3
# BioBlend and dependencies
bioblend==0.6.1 --hash:sha256=f5eea1f6c31264ef7bfab8c70deac2b9229a10e5c56508a6542f5643ad9e2a5b
boto==2.38.0 --hash:sha256=1760584368da0c3861dbed448dcb439334ce831044262a5ca5188167f8bba585
requests==2.8.1 --hash:sha256=70e285122c97b1d104824482cb929246b2b8a2b9858897c4fab3acec83f1e03c
requests-toolbelt==0.4.0 --hash:sha256=94694e32845b84ed2186fdf56219b949582ebd08dc3abc55c0549958f2029643
bioblend==0.6.1
boto==2.38.0
requests==2.8.1
requests-toolbelt==0.4.0
# kombu and dependencies
kombu==3.0.30 --hash:sha256=562010f0deb1f04e3abd154b0ef5e246d606b54cb2c5f29e8c4651b354d0b082 \
--hash:sha256=5baff23a2b2d78eecb7c97700ea359ab80744c719e311fb446513d7b72ddbc96
amqp==1.4.8 --hash:sha256=c7874d845c9bdffbf754ce84f105a1b8c7a6cffb61f362ac67591536ba8c0c1a \
--hash:sha256=caada1c29d5e73e13ed8706442ee0fbb1440de9b6fca4df12fc8ff59dd61f6f6
anyjson==0.3.3 --hash:sha256=2c84f23be20e3c465151a55917b8e38a04c579394057e232c16fb5ca0c6ae108
kombu==3.0.30
amqp==1.4.8
anyjson==0.3.3
# sqlalchemy-migrate and dependencies
sqlalchemy-migrate==0.10.0 --hash:sha256=2aaa4e7070c8447d564f1c173937c2c5a45f889eb31a0fc80add5fc175c45a5e
decorator==4.0.2 --hash:sha256=d8c3f7e18efba558084648d6dd6c6b0850e6f5c08c392975ae196c4b4eb7be2a
Tempita==0.5.3dev --hash:sha256=df0c6513e565b213733b3f8bf7bcca75998f166042692e1712e3fe36568db234
sqlparse==0.1.16 --hash:sha256=221d383f1236f9c05aadd2c4edf4274144279ad06821d7d9bf5a70751157f75d
pbr==1.8.0 --hash:sha256=355a0c2ba71120dce1c522387e494c60eb4f44fa9d03067cb9816187e6e803e9
sqlalchemy-migrate==0.10.0
decorator==4.0.2
Tempita==0.5.3dev
sqlparse==0.1.16
pbr==1.8.0
# six is also a Pulsar client dep
six==1.9.0 --hash:sha256=cf806ab65d5e16561df30c2cea2fb2cf3e6aa82e48f22036dff177e20f61e188
Parsley==1.3 --hash:sha256=32fd648334146e4005dae41d559d32edfff9f3d5f503f8b5d233dbfe3a15a28b
nose==1.3.7 --hash:sha256=f36054c5786e84ff6b131f3249a3cce82787f1a930ab053287c0edaa9f840d0f
SVGFig==1.1.6 --hash:sha256=300cf4b37b4773498d4ea96c703cdb5f09215978b02828dadb786fb248e0b54b
six==1.9.0
Parsley==1.3
nose==1.3.7
SVGFig==1.1.6
# Fabric and dependencies
Fabric==1.10.2 --hash:sha256=8fe1eb0b0f271e2d41445e7da4470548d3bdf882aab1c1f143505c599996793b
paramiko==1.15.2 --hash:sha256=c92b168c8db94a9e1362f3fc27bc21e8c20794885bf2f7d303b5ad717c044ebc
ecdsa==0.13 --hash:sha256=89f149066e4a1e419892cef830fd0db85c227d5d427f7075422ace83429e2d26
Fabric==1.10.2
paramiko==1.15.2
ecdsa==0.13
# pycrypto, but it is a direct Galaxy dependency as well
# Can't use Whoosh latest due to a bug but need to backport a bugfix from a
# newer release.
#
# https://bitbucket.org/mchaput/whoosh/pull-requests/50/fix-lru-thread-safety/diff
Whoosh==2.4.1+gx1 --hash:sha256=98897e796c048810d71f7f4fc174914869f1b3b77f44e5a19a5e649b078d5e0e \
--hash:sha256=5ec3c22e782c86e981fab62a24ac9feea09e42c43b763a6493c78b82a3b6e3fd
Whoosh==2.4.1+gx1
# Flexible BAM index naming
pysam==0.8.3+gx1 --hash:sha256=020aa9101579ac1e82a194fdb08f49f517c634911409e9a2cda4d0a1c72a8c7c \
--hash:sha256=1a3d86849b9bd962979b65aaa9af236030dcc1db40296c88d2aa436a0c9df79b \
--hash:sha256=0fc55fb252eb0e7914679e9e22672fdc6a1e09804cbcc62769f004ebbed9b4c1 \
--hash:sha256=dde8f5037661d7be42e2c3f50c01566dcaedbf2f88133a3bb50c6ae3f75e6e13 \
--hash:sha256=7809fd926a071519c0a2b220346e45c094577877e5b2adba2903e7b52490c736 \
--hash:sha256=021070ed70a89e19eee6a989933d69d0bdb076c02342e2987bb5fab43f63ad17 \
--hash:sha256=374ea868bf64daa4665e8743db1be2e88712953a923020225f57a589b790537c \
--hash:sha256=9884b6904face1977649847261e7c984120adaa169a0d62e07820a44c71e18c5 \
--hash:sha256=873b81951e9d572b53ab4c7a0d3ef915f7d0e1db5f75603d8861cf1d3810491e \
--hash:sha256=37d0ba3880b5a517f354281159f6751f6f9f1c1074ea48bf5f4c424e6ec488dd \
--hash:sha256=db99cb20cb5e07998b2acfd29e34c367ef408a184a7b3150586212175a0719bf \
--hash:sha256=a1fcb2a6459b799bff7a046e190452b151c5985dea404eaee82bd645b1bfe34d \
--hash:sha256=306e4d900dfb582cf87bc21904e2193ef81db76173e976b74152c95ddd93bdc6 \
--hash:sha256=2341438d636b8e3cb51b219aab1cc909142d3af176042d12b128d4177682b1ab \
--hash:sha256=0f33df9eba7b079b7489ac3dd908a6e44b0e98d094e633b29035d33bfc990b9e \
--hash:sha256=faa8aae3f8f105c5c823a7d570dd3caba31ece69b8f3325106435b9f1fcb68d2 \
--hash:sha256=2db995758d666c51fecf11cbee1afda357477e01077aacf68ae0c00304c7bc51 \
--hash:sha256=2de7a2098f64672d0396ac727633285f3562f804e7845e105ee19da544d7da8a
pysam==0.8.3+gx1
+8
View File
@@ -43,6 +43,9 @@ log = logging.getLogger( __name__ )
# and should eventually become API'd
TOOL_PROVIDED_JOB_METADATA_FILE = 'galaxy.json'
# Override with config.default_job_shell.
DEFAULT_JOB_SHELL = '/bin/sh'
class JobDestination( Bunch ):
"""
@@ -55,6 +58,7 @@ class JobDestination( Bunch ):
self['runner'] = None
self['legacy'] = False
self['converted'] = False
self['shell'] = None
self['env'] = []
self['resubmit'] = []
# dict is appropriate (rather than a bunch) since keys may not be valid as attributes
@@ -785,6 +789,10 @@ class JobWrapper( object ):
def get_parallelism(self):
return self.tool.parallelism
@property
def shell(self):
return self.job_destination.shell or getattr(self.app.config, 'default_job_shell', DEFAULT_JOB_SHELL)
@property
def commands_in_new_shell(self):
return self.app.config.commands_in_new_shell
+16 -11
View File
@@ -1,16 +1,19 @@
from os import getcwd
from os import chmod
from os.path import join
from os.path import abspath
from galaxy import util
from galaxy.jobs.runners.util.job_script import (
INTEGRITY_INJECTION,
write_script,
check_script_integrity,
)
from logging import getLogger
log = getLogger( __name__ )
CAPTURE_RETURN_CODE = "return_code=$?"
YIELD_CAPTURED_CODE = 'sh -c "exit $return_code"'
DEFAULT_SHELL = "/bin/sh"
def build_command(
@@ -19,7 +22,7 @@ def build_command(
container=None,
include_metadata=False,
include_work_dir_outputs=True,
remote_command_params={}
remote_command_params={},
):
"""
Compose the sequence of commands necessary to execute a job. This will
@@ -30,6 +33,7 @@ def build_command(
- command line taken from job wrapper
- commands to set metadata (if include_metadata is True)
"""
shell = job_wrapper.shell
base_command_line = job_wrapper.get_command_line()
# job_id = job_wrapper.job_id
# log.debug( 'Tool evaluation for job (%s) produced command-line: %s' % ( job_id, base_command_line ) )
@@ -52,7 +56,7 @@ def build_command(
__handle_dependency_resolution(commands_builder, job_wrapper, remote_command_params)
if container or job_wrapper.commands_in_new_shell:
externalized_commands = __externalize_commands(job_wrapper, commands_builder, remote_command_params)
externalized_commands = __externalize_commands(job_wrapper, shell, commands_builder, remote_command_params)
if container:
# Stop now and build command before handling metadata and copying
# working directory files back. These should always happen outside
@@ -76,17 +80,18 @@ def build_command(
return commands_builder.build()
def __externalize_commands(job_wrapper, commands_builder, remote_command_params, script_name="tool_script.sh"):
def __externalize_commands(job_wrapper, shell, commands_builder, remote_command_params, script_name="tool_script.sh"):
local_container_script = join( job_wrapper.working_directory, script_name )
tool_commands = commands_builder.build()
with open( local_container_script, "w" ) as f:
script_contents = u"#!%s\n%s" % (DEFAULT_SHELL, tool_commands)
f.write(script_contents.encode(util.DEFAULT_ENCODING))
chmod( local_container_script, 0755 )
config = job_wrapper.app.config
integrity_injection = ""
if check_script_integrity(config):
integrity_injection = INTEGRITY_INJECTION
script_contents = u"#!%s\n%s%s" % (shell, integrity_injection, tool_commands)
write_script(local_container_script, script_contents, config)
commands = local_container_script
if 'working_directory' in remote_command_params:
commands = "%s %s" % (DEFAULT_SHELL, join(remote_command_params['working_directory'], script_name))
commands = "%s %s" % (shell, join(remote_command_params['working_directory'], script_name))
log.info("Built script [%s] for tool command[%s]" % (local_container_script, tool_commands))
return commands
+4 -36
View File
@@ -20,6 +20,7 @@ from galaxy.util import in_directory
from galaxy.util import ParamsWithSpecs
from galaxy.util import ExecutionTimer
from galaxy.util.bunch import Bunch
from galaxy.jobs.runners.util.job_script import write_script
from galaxy.jobs.runners.util.job_script import job_script
from galaxy.jobs.runners.util.env import env_to_statement
@@ -166,7 +167,7 @@ class BaseJobRunner( object ):
job_wrapper.runner_command_line = self.build_command_line(
job_wrapper,
include_metadata=include_metadata,
include_work_dir_outputs=include_work_dir_outputs
include_work_dir_outputs=include_work_dir_outputs,
)
except:
log.exception("(%s) Failure preparing job" % job_id)
@@ -297,6 +298,7 @@ class BaseJobRunner( object ):
env_setup_commands=env_setup_commands,
working_directory=os.path.abspath( job_wrapper.working_directory ),
command=command_line,
shell=job_wrapper.shell,
)
# Additional logging to enable if debugging from_work_dir handling, metadata
# commands, etc... (or just peak in the job script.)
@@ -306,41 +308,7 @@ class BaseJobRunner( object ):
return job_script(**options)
def write_executable_script( self, path, contents, mode=0o755 ):
with open( path, 'w' ) as f:
if isinstance(contents, unicode):
contents = contents.encode("UTF-8")
f.write( contents )
os.chmod( path, mode )
self._handle_script_integrity( path )
def _handle_script_integrity( self, path ):
if not getattr( self.app.config, "check_job_script_integrity", True ):
return
script_integrity_verified = False
for i in range(10):
try:
proc = subprocess.Popen( [path], shell=True, env={"ABC_TEST_JOB_SCRIPT_INTEGRITY_XYZ": "1"} )
proc.wait()
if proc.returncode == 42:
script_integrity_verified = True
break
# Else we will sync and wait to see if the script becomes
# executable.
try:
# sync file system to avoid "Text file busy" problems.
# These have occurred both in Docker containers and on EC2 clusters
# under high load.
subprocess.check_call(["/bin/sync"])
except Exception:
pass
time.sleep( .25 )
except Exception:
pass
if not script_integrity_verified:
raise Exception("Failed to write job script, could not verify job script integrity.")
write_script( path, contents, self.app.config, mode=mode )
def _complete_terminal_job( self, ajs, **kwargs ):
if ajs.job_wrapper.get_state() != model.Job.states.DELETED:
@@ -1,12 +1,6 @@
#!/bin/sh
# The following block can be used by the job creation system
# to ensure this script is runnable before running it directly
# or submitting it to a cluster manager.
if [ -n "$ABC_TEST_JOB_SCRIPT_INTEGRITY_XYZ" ]; then
exit 42
fi
#!$shell
$integrity_injection
$headers
$slots_statement
export GALAXY_SLOTS
@@ -1,7 +1,14 @@
import os
from string import Template
import subprocess
import time
from pkg_resources import resource_string
from six import text_type
from galaxy.util import unicodify
DEFAULT_SHELL = '/bin/sh'
DEFAULT_JOB_FILE_TEMPLATE = Template(
resource_string(__name__, 'DEFAULT_JOB_FILE_TEMPLATE.sh').decode('UTF-8')
)
@@ -13,6 +20,19 @@ SLOTS_STATEMENT_SINGLE = """
GALAXY_SLOTS="1"
"""
INTEGRITY_INJECTION = """
# The following block can be used by the job system
# to ensure this script is runnable before actually attempting
# to run it.
if [ -n "$ABC_TEST_JOB_SCRIPT_INTEGRITY_XYZ" ]; then
exit 42
fi
"""
INTEGRITY_SYNC_COMMAND = "/bin/sync"
DEFAULT_INTEGRITY_CHECK = True
DEFAULT_INTEGRITY_COUNT = 35
DEFAULT_INTEGRITY_SLEEP = .25
REQUIRED_TEMPLATE_PARAMS = ['working_directory', 'command', 'exit_code_path']
OPTIONAL_TEMPLATE_PARAMS = {
'galaxy_lib': None,
@@ -22,6 +42,8 @@ OPTIONAL_TEMPLATE_PARAMS = {
'slots_statement': SLOTS_STATEMENT_CLUSTER_DEFAULT,
'instrument_pre_commands': '',
'instrument_post_commands': '',
'integrity_injection': INTEGRITY_INJECTION,
'shell': DEFAULT_SHELL,
}
@@ -67,3 +89,56 @@ def job_script(template=DEFAULT_JOB_FILE_TEMPLATE, **kwds):
if not isinstance(template, Template):
template = Template(template)
return template.safe_substitute(template_params)
def check_script_integrity(config):
return getattr(config, "check_job_script_integrity", DEFAULT_INTEGRITY_CHECK)
def write_script(path, contents, config, mode=0o755):
with open(path, 'w') as f:
if isinstance(contents, text_type):
contents = contents.encode("UTF-8")
f.write(contents)
os.chmod(path, mode)
_handle_script_integrity(path, config)
def _handle_script_integrity(path, config):
if not check_script_integrity(config):
return
script_integrity_verified = False
count = getattr(config, "check_job_script_integrity_count", DEFAULT_INTEGRITY_COUNT)
sleep_amt = getattr(config, "check_job_script_integrity_sleep", DEFAULT_INTEGRITY_SLEEP)
for i in range(count):
try:
proc = subprocess.Popen([path], shell=True, env={"ABC_TEST_JOB_SCRIPT_INTEGRITY_XYZ": "1"})
proc.wait()
if proc.returncode == 42:
script_integrity_verified = True
break
# Else we will sync and wait to see if the script becomes
# executable.
try:
# sync file system to avoid "Text file busy" problems.
# These have occurred both in Docker containers and on EC2 clusters
# under high load.
subprocess.check_call(INTEGRITY_SYNC_COMMAND)
except Exception:
pass
time.sleep(sleep_amt)
except Exception:
pass
if not script_integrity_verified:
raise Exception("Failed to write job script, could not verify job script integrity.")
__all__ = [
'check_script_integrity',
'job_script',
'write_script',
'INTEGRITY_INJECTION',
]
+74 -7
View File
@@ -1398,7 +1398,6 @@ class History( object, Dictifiable, UsesAnnotations, HasName ):
assert db_session is not None
query = db_session.query( content_class ).filter( content_class.table.c.history_id == self.id )
query = query.order_by( content_class.table.c.hid.asc() )
python_filter = None
deleted = galaxy.util.string_as_bool_or_none( kwds.get( 'deleted', None ) )
if deleted is not None:
query = query.filter( content_class.deleted == deleted )
@@ -1411,11 +1410,8 @@ class History( object, Dictifiable, UsesAnnotations, HasName ):
if len(ids) < max_in_filter_length:
query = query.filter( content_class.id.in_(ids) )
else:
python_filter = lambda content: content.id in ids
if python_filter:
return ifilter(python_filter, query)
else:
return query
query = ifilter(lambda content: content.id in ids, query)
return query
def __collection_contents_iter( self, **kwds ):
return self.__filter_contents( HistoryDatasetCollectionAssociation, **kwds )
@@ -3561,6 +3557,28 @@ class Workflow( object, Dictifiable ):
"""
return self.top_level_workflow.stored_workflow
def copy(self):
""" Copy a workflow (without user information) for a new
StoredWorkflow object.
"""
copied_workflow = Workflow()
copied_workflow.name = self.name
copied_workflow.has_cycles = self.has_cycles
copied_workflow.has_errors = self.has_errors
# Map old step ids to new steps
step_mapping = {}
copied_steps = []
for step in self.steps:
copied_step = WorkflowStep()
copied_steps.append(copied_step)
step_mapping[step.id] = copied_step
for old_step, new_step in zip(self.steps, copied_steps):
old_step.copy_to(new_step, step_mapping)
copied_workflow.steps = copied_steps
return copied_workflow
def log_str(self):
extra = ""
if self.stored_workflow:
@@ -3579,8 +3597,9 @@ class WorkflowStep( object ):
self.position = None
self.input_connections = []
self.config = None
self.label = None
self.uuid = uuid4()
self.worklfow_outputs = []
self.workflow_outputs = []
self._input_connections_by_name = None
@property
@@ -3630,6 +3649,34 @@ class WorkflowStep( object ):
break
return target_output
def copy_to(self, copied_step, step_mapping):
copied_step.order_index = self.order_index
copied_step.type = self.type
copied_step.tool_id = self.tool_id
copied_step.tool_inputs = self.tool_inputs
copied_step.tool_errors = self.tool_errors
copied_step.position = self.position
copied_step.config = self.config
copied_step.label = self.label
copied_step.input_connections = copy_list(self.input_connections)
subworkflow_step_mapping = {}
subworkflow = self.subworkflow
if subworkflow:
copied_subworkflow = subworkflow.copy()
copied_step.subworkflow = copied_subworkflow
for subworkflow_step, copied_subworkflow_step in zip(subworkflow.steps, copied_subworkflow.steps):
subworkflow_step_mapping[subworkflow_step.id] = copied_subworkflow_step
for old_conn, new_conn in zip(self.input_connections, copied_step.input_connections):
# new_conn.input_step = new_
new_conn.input_step = step_mapping[old_conn.input_step_id]
new_conn.output_step = step_mapping[old_conn.output_step_id]
if old_conn.input_subworkflow_step_id:
new_conn.input_subworkflow_step = subworkflow_step_mapping[old_conn.input_subworkflow_step_id]
copied_step.workflow_outputs = copy_list(self.workflow_outputs, copied_step)
def log_str(self):
return "WorkflowStep[index=%d,type=%s]" % (self.order_index, self.type)
@@ -3657,6 +3704,13 @@ class WorkflowStepConnection( object ):
return (self.output_name == WorkflowStepConnection.NON_DATA_CONNECTION and
self.input_name == WorkflowStepConnection.NON_DATA_CONNECTION)
def copy(self):
# TODO: handle subworkflow ids...
copied_connection = WorkflowStepConnection()
copied_connection.output_name = self.output_name
copied_connection.input_name = self.input_name
return copied_connection
class WorkflowOutput(object):
@@ -3669,6 +3723,12 @@ class WorkflowOutput(object):
else:
self.uuid = UUID(str(uuid))
def copy(self, copied_step):
copied_output = WorkflowOutput(copied_step)
copied_output.output_name = self.output_name
copied_output.label = self.label
return copied_output
class StoredWorkflowUserShareAssociation( object ):
@@ -5021,3 +5081,10 @@ class APIKeys( object ):
self.id = id
self.user_id = user_id
self.key = key
def copy_list(lst, *args, **kwds):
if lst is None:
return lst
else:
return list(map(lambda el: el.copy(*args, **kwds), lst))
+2 -1
View File
@@ -232,7 +232,8 @@ def total_size(o, handlers={}, verbose=False):
Recipe from: https://code.activestate.com/recipes/577504-compute-memory-footprint-of-an-object-and-its-cont/
"""
dict_handler = lambda d: chain.from_iterable(d.items())
def dict_handler(d):
return chain.from_iterable(d.items())
all_handlers = { tuple: iter,
list: iter,
deque: iter,
+3
View File
@@ -2154,6 +2154,9 @@ class Tool( object, Dictifiable ):
def jsonify(v):
if isinstance(v, UnvalidatedValue):
v = v.value
while isinstance( v, UnvalidatedValue ):
v = v.value
return v
# check if value is numeric
isnumber = False
+5 -2
View File
@@ -350,7 +350,7 @@ def create_paramfile( trans, uploaded_datasets ):
return json_file_path
def create_job( trans, params, tool, json_file_path, data_list, folder=None, history=None ):
def create_job( trans, params, tool, json_file_path, data_list, folder=None, history=None, job_params=None ):
"""
Create the upload job.
"""
@@ -395,7 +395,10 @@ def create_job( trans, params, tool, json_file_path, data_list, folder=None, his
# open( dataset.file_name, "w" ).close()
job.object_store_id = object_store_id
job.set_state( job.states.NEW )
job.set_handler(tool.get_job_handler(None))
job.set_handler( tool.get_job_handler( None ) )
if job_params:
for name, value in job_params.iteritems():
job.add_parameter( name, value )
trans.sa_session.add( job )
trans.sa_session.flush()

Some files were not shown because too many files have changed in this diff Show More