Merging with dev

This commit is contained in:
anuprulez
2017-03-26 13:33:41 +02:00
278 changed files with 6557 additions and 2136 deletions
+1
View File
@@ -5,3 +5,4 @@ database/
doc/source/conf.py
eggs/
lib/galaxy/util/jstree.py
lib/galaxy/web/proxy/js/node_modules/
+2
View File
@@ -47,6 +47,8 @@ lib/galaxy/tours/
lib/galaxy/util/
lib/galaxy/visualization/
lib/galaxy/web/buildapp.py
lib/galaxy/web/framework/base.py
lib/galaxy/web/framework/decorators.py
lib/galaxy/web/framework/__init__.py
lib/galaxy/web/framework/middleware/error.py
lib/galaxy/web/framework/middleware/static.py
+1 -1
View File
@@ -1,4 +1,4 @@
.. figure:: https://wiki.galaxyproject.org/Images/GalaxyLogo?action=AttachFile&do=get&target=galaxy_project_logo.jpg
.. figure:: https://galaxyproject.org/images/galaxy-logos/galaxy_project_logo.jpg
:alt: Galaxy Logo
The latest information about Galaxy is available via `https://galaxyproject.org/ <https://galaxyproject.org/>`__
+18 -11
View File
@@ -68,15 +68,6 @@ window.app = function app( options, bootstrapped ){
Galaxy.currHistoryPanel = historyPanel.historyView;
Galaxy.currHistoryPanel.listenToGalaxy( Galaxy );
//HACK: move there
Galaxy.app = {
display : function( view, target ){
// TODO: Remove this line after select2 update
$( '.select2-hidden-accessible' ).remove();
centerPanel.display( view );
},
};
// .................................................... routes
/** */
Galaxy.router = new ( Backbone.Router.extend({
@@ -86,6 +77,17 @@ window.app = function app( options, bootstrapped ){
this.options = options;
},
/** helper to push a new navigation state */
push: function( url, data ) {
data = data || {};
data.__identifer = Math.random().toString( 36 ).substr( 2 );
if ( !$.isEmptyObject( data ) ) {
url += url.indexOf( '?' ) == -1 ? '?' : '&';
url += $.param( data , true );
}
this.navigate( url, { 'trigger': true } );
},
/** override to parse query string into obj and send to each route */
execute: function( callback, args, name ){
Galaxy.debug( 'router execute:', callback, args, name );
@@ -101,7 +103,8 @@ window.app = function app( options, bootstrapped ){
// TODO: remove annoying 'root' from root urls
'(/)root*' : 'home',
'(/)tours(/)(:tour_id)' : 'show_tours',
'(/)users(/)' : 'show_users',
'(/)user(/)' : 'show_user',
'(/)user(/)(:form_id)' : 'show_user_form',
},
show_tours : function( tour_id ){
@@ -112,10 +115,14 @@ window.app = function app( options, bootstrapped ){
}
},
show_users : function(){
show_user : function(){
centerPanel.display( new UserPreferences.View() );
},
show_user_form : function( form_id ) {
centerPanel.display( new UserPreferences.Forms( { form_id: form_id, user_id: Galaxy.params.id } ) );
},
/** */
home : function( params ){
// TODO: to router, remove Globals
@@ -17,6 +17,59 @@ function display_spinner(){
$('#main').append('<img id="spinner" src="' + galaxy_root + 'static/style/largespinner.gif" style="position:absolute;margin:auto;top:0;left:0;right:0;bottom:0;">');
}
/**
* Check a URL for a boolean true/false and call a callback when done.
*/
function load_when_ready(url, success_callback){
var request_count = 0;
var timeout_time = 1000;
var timeout_time_max = 15000;
var timeout_time_step = 1000;
var timeout = function(){
$.ajax({
url: url,
xhrFields: {
withCredentials: true
},
type: "GET",
timeout: 500,
dataType: "json",
success: function(data){
if(data == true){
console.log("Galaxy reports IE container ready, returning");
clear_main_area();
toastr.clear();
success_callback();
}else if(data == false){
if(request_count == 0){
display_spinner();
toastr.info(
"Galaxy is launching a container in which to run this interactive environment. Please wait...",
{'closeButton': true, 'tapToDismiss': false}
);
}
request_count++;
if(timeout_time < timeout_time_max){
timeout_time += timeout_time_step;
}
console.log("Readiness request " + request_count + " sleeping " + timeout_time / 1000 + "s");
window.setTimeout(timeout, timeout_time)
}else{
clear_main_area();
toastr.clear();
toastr.error(
"Galaxy failed to launch a container in which to run this interactive environment, contact your administrator.",
"Error",
{'closeButton': true, 'tapToDismiss': false}
);
}
}
});
}
window.setTimeout(timeout, timeout_time);
}
/**
* Test availability of a URL, and call a callback when done.
@@ -43,7 +96,7 @@ function test_ie_availability(url, success_callback){
},
error: function(jqxhr, status, error){
request_count++;
console.log("Request " + request_count);
console.log("Availability request " + request_count);
if(request_count > 30){
clearInterval(interval);
clear_main_area();
+42 -38
View File
@@ -1,5 +1,5 @@
/** Masthead Collection **/
define(['layout/generic-nav-view', 'mvc/webhooks'], function( GenericNav, Webhooks ) {
define(['layout/generic-nav-view', 'mvc/webhooks', 'utils/localization'], function( GenericNav, Webhooks, _l ) {
var Collection = Backbone.Collection.extend({
model: Backbone.Model.extend({
defaults: {
@@ -22,7 +22,7 @@ var Collection = Backbone.Collection.extend({
//
this.add({
id : 'analysis',
title : 'Analyze Data',
title : _l('Analyze Data'),
url : '',
tooltip : 'Analysis home view'
});
@@ -32,7 +32,7 @@ var Collection = Backbone.Collection.extend({
//
this.add({
id : 'workflow',
title : 'Workflow',
title : _l('Workflow'),
url : 'workflow',
tooltip : 'Chain tools into workflows',
disabled : !Galaxy.user.id
@@ -43,23 +43,23 @@ var Collection = Backbone.Collection.extend({
//
this.add({
id : 'shared',
title : 'Shared Data',
title : _l('Shared Data'),
url : 'library/index',
tooltip : 'Access published resources',
menu : [{
title : 'Data Libraries',
title : _l('Data Libraries'),
url : 'library/list'
},{
title : 'Histories',
title : _l('Histories'),
url : 'history/list_published'
},{
title : 'Workflows',
title : _l('Workflows'),
url : 'workflow/list_published'
},{
title : 'Visualizations',
title : _l('Visualizations'),
url : 'visualization/list_published'
},{
title : 'Pages',
title : _l('Pages'),
url : 'page/list_published'
}]
});
@@ -87,20 +87,20 @@ var Collection = Backbone.Collection.extend({
//
this.add({
id : 'visualization',
title : 'Visualization',
title : _l('Visualization'),
url : 'visualization/list',
tooltip : 'Visualize datasets',
disabled : !Galaxy.user.id,
menu : [{
title : 'New Track Browser',
title : _l('New Track Browser'),
url : 'visualization/trackster',
target : '_frame'
},{
title : 'Saved Visualizations',
title : _l('Saved Visualizations'),
url : 'visualization/list',
target : '_frame'
},{
title : 'Interactive Environments',
title : _l('Interactive Environments'),
url : 'visualization/gie_list',
target : 'galaxy_main'
}
@@ -147,7 +147,7 @@ var Collection = Backbone.Collection.extend({
//
Galaxy.user.get( 'is_admin' ) && this.add({
id : 'admin',
title : 'Admin',
title : _l('Admin'),
url : 'admin',
tooltip : 'Administer this Galaxy',
cls : 'admin-only'
@@ -158,34 +158,34 @@ var Collection = Backbone.Collection.extend({
//
var helpTab = {
id : 'help',
title : 'Help',
title : _l('Help'),
tooltip : 'Support, contact, and community',
menu : [{
title : 'Support',
title : _l('Support'),
url : options.support_url,
target : '_blank'
},{
title : 'Search',
title : _l('Search'),
url : options.search_url,
target : '_blank'
},{
title : 'Mailing Lists',
title : _l('Mailing Lists'),
url : options.mailing_lists,
target : '_blank'
},{
title : 'Videos',
title : _l('Videos'),
url : options.screencasts_url,
target : '_blank'
},{
title : 'Wiki',
title : _l('Wiki'),
url : options.wiki_url,
target : '_blank'
},{
title : 'How to Cite Galaxy',
title : _l('How to Cite Galaxy'),
url : options.citation_url,
target : '_blank'
},{
title : 'Interactive Tours',
title : _l('Interactive Tours'),
url : 'tours',
onclick : function(){
if (Galaxy.router){
@@ -198,17 +198,17 @@ var Collection = Backbone.Collection.extend({
}]
};
options.terms_url && helpTab.menu.push({
title : 'Terms and Conditions',
title : _l('Terms and Conditions'),
url : options.terms_url,
target : '_blank'
});
options.biostar_url && helpTab.menu.unshift({
title : 'Ask a question',
title : _l('Ask a question'),
url : 'biostar/biostar_question_redirect',
target : '_blank'
});
options.biostar_url && helpTab.menu.unshift({
title : 'Galaxy Biostar',
title : _l('Galaxy Biostar'),
url : options.biostar_url_redirect,
target : '_blank'
});
@@ -220,18 +220,18 @@ var Collection = Backbone.Collection.extend({
if ( !Galaxy.user.id ){
var userTab = {
id : 'user',
title : 'User',
title : _l('User'),
cls : 'loggedout-only',
tooltip : 'Account registration or login',
menu : [{
title : 'Login',
title : _l('Login'),
url : 'user/login',
target : 'galaxy_main',
noscratchbook : true
}]
};
options.allow_user_creation && userTab.menu.push({
title : 'Register',
title : _l('Register'),
url : 'user/create',
target : 'galaxy_main',
noscratchbook : true
@@ -240,37 +240,41 @@ var Collection = Backbone.Collection.extend({
} else {
var userTab = {
id : 'user',
title : 'User',
title : _l('User'),
cls : 'loggedin-only',
tooltip : 'Account and saved data',
menu : [{
title : 'Logged in as ' + Galaxy.user.get( 'email' )
title : _l('Logged in as') + ' ' + Galaxy.user.get( 'email' )
},{
title : 'Preferences',
url : 'users',
title : _l('Preferences'),
url : 'user',
target : 'galaxy_main',
onclick : function() {
window.location = Galaxy.root + 'users';
if ( Galaxy.router ) {
Galaxy.router.push( 'user' );
} else {
window.location = Galaxy.root + 'user';
}
}
},{
title : 'Custom Builds',
title : _l('Custom Builds'),
url : 'user/dbkeys',
target : 'galaxy_main'
},{
title : 'Logout',
title : _l('Logout'),
url : 'user/logout',
target : '_top',
divider : true
},{
title : 'Saved Histories',
title : _l('Saved Histories'),
url : 'history/list',
target : 'galaxy_main'
},{
title : 'Saved Datasets',
title : _l('Saved Datasets'),
url : 'dataset/list',
target : 'galaxy_main'
},{
title : 'Saved Pages',
title : _l('Saved Pages'),
url : 'page/list',
target : '_top'
}]
@@ -0,0 +1,106 @@
define([
], function( ){
/* For presentation-related functionality shared across collection creators.
Particularily overlapping functionality related to name processing and help.
*/
var CollectionCreatorMixin = {
/** add (or clear if clear is truthy) a validation warning to the DOM element described in what */
_validationWarning : function( what, clear ){
var VALIDATION_CLASS = 'validation-warning';
if( what === 'name' ){
what = this.$( '.collection-name' ).add( this.$( '.collection-name-prompt' ) );
this.$( '.collection-name' ).focus().select();
}
if( clear ){
what = what || this.$( '.' + VALIDATION_CLASS );
what.removeClass( VALIDATION_CLASS );
} else {
what.addClass( VALIDATION_CLASS );
}
},
// ........................................................................ footer
/** handle a collection name change */
_changeName : function( ev ){
this._validationWarning( 'name', !!this._getName() );
},
/** check for enter key press when in the collection name and submit */
_nameCheckForEnter : function( ev ){
if( ev.keyCode === 13 && !this.blocking ){
this._clickCreate();
}
},
/** get the current collection name */
_getName : function(){
return _.escape( this.$( '.collection-name' ).val() );
},
// ........................................................................ header
/** expand help */
_clickMoreHelp : function( ev ){
ev.stopPropagation();
this.$( '.main-help' ).addClass( 'expanded' );
this.$( '.more-help' ).hide();
},
/** collapse help */
_clickLessHelp : function( ev ){
ev.stopPropagation();
this.$( '.main-help' ).removeClass( 'expanded' );
this.$( '.more-help' ).show();
},
/** toggle help */
_toggleHelp : function( ev ){
ev.stopPropagation();
this.$( '.main-help' ).toggleClass( 'expanded' );
this.$( '.more-help' ).toggle();
},
/** show an alert on the top of the interface containing message (alertClass is bootstrap's alert-*) */
_showAlert : function( message, alertClass ){
alertClass = alertClass || 'alert-danger';
this.$( '.main-help' ).hide();
this.$( '.header .alert' )
.attr( 'class', 'alert alert-dismissable' ).addClass( alertClass ).show()
.find( '.alert-message' ).html( message );
},
/** hide the alerts at the top */
_hideAlert : function( message ){
this.$( '.main-help' ).show();
this.$( '.header .alert' ).hide();
},
_cancelCreate: function( ev ){
if( typeof this.oncancel === 'function' ){
this.oncancel.call( this );
}
},
/** attempt to create the current collection */
_clickCreate : function( ev ){
var name = this._getName();
if( !name ){
this._validationWarning( 'name' );
} else if( !this.blocking ){
this.createList( name );
}
},
_creatorTemplates: {
main : _.template([
'<div class="header flex-row no-flex"></div>',
'<div class="middle flex-row flex-row-container"></div>',
'<div class="footer flex-row no-flex"></div>'
].join('')),
}
}
//==============================================================================
return {
CollectionCreatorMixin: CollectionCreatorMixin
};
});
@@ -3,15 +3,17 @@ define([
"mvc/history/hdca-model",
"mvc/dataset/states",
"mvc/base-mvc",
"mvc/collection/base-creator",
"mvc/ui/ui-modal",
"utils/natural-sort",
"utils/localization",
"ui/hoverhighlight"
], function( HDCA, STATES, BASE_MVC, UI_MODAL, naturalSort, _l ){
], function( HDCA, STATES, BASE_MVC, baseCreator, UI_MODAL, naturalSort, _l ){
'use strict';
var logNamespace = 'collections';
/*==============================================================================
TODO:
use proper Element model and not just json
@@ -151,7 +153,7 @@ var DatasetCollectionElementView = Backbone.View.extend( BASE_MVC.LoggableMixin
// ============================================================================
/** An interface for building collections.
*/
var ListCollectionCreator = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend({
var ListCollectionCreator = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( baseCreator.CollectionCreatorMixin ).extend({
_logNamespace : logNamespace,
/** the class used to display individual elements */
@@ -367,21 +369,6 @@ var ListCollectionCreator = Backbone.View.extend( BASE_MVC.LoggableMixin ).exten
this._showAlert( this.templates.invalidElements({ problems: this.invalidElements }), 'alert-warning' );
},
/** add (or clear if clear is truthy) a validation warning to the DOM element described in what */
_validationWarning : function( what, clear ){
var VALIDATION_CLASS = 'validation-warning';
if( what === 'name' ){
what = this.$( '.collection-name' ).add( this.$( '.collection-name-prompt' ) );
this.$( '.collection-name' ).focus().select();
}
if( clear ){
what = what || this.$( '.' + VALIDATION_CLASS );
what.removeClass( VALIDATION_CLASS );
} else {
what.addClass( VALIDATION_CLASS );
}
},
_disableNameAndCreate : function( disable ){
disable = !_.isUndefined( disable )? disable : true;
if( disable ){
@@ -624,48 +611,10 @@ var ListCollectionCreator = Backbone.View.extend( BASE_MVC.LoggableMixin ).exten
// footer
'change .collection-name' : '_changeName',
'keydown .collection-name' : '_nameCheckForEnter',
'click .cancel-create' : function( ev ){
if( typeof this.oncancel === 'function' ){
this.oncancel.call( this );
}
},
'click .cancel-create' : '_cancelCreate',
'click .create-collection' : '_clickCreate'//,
},
// ........................................................................ header
/** expand help */
_clickMoreHelp : function( ev ){
ev.stopPropagation();
this.$( '.main-help' ).addClass( 'expanded' );
this.$( '.more-help' ).hide();
},
/** collapse help */
_clickLessHelp : function( ev ){
ev.stopPropagation();
this.$( '.main-help' ).removeClass( 'expanded' );
this.$( '.more-help' ).show();
},
/** toggle help */
_toggleHelp : function( ev ){
ev.stopPropagation();
this.$( '.main-help' ).toggleClass( 'expanded' );
this.$( '.more-help' ).toggle();
},
/** show an alert on the top of the interface containing message (alertClass is bootstrap's alert-*) */
_showAlert : function( message, alertClass ){
alertClass = alertClass || 'alert-danger';
this.$( '.main-help' ).hide();
this.$( '.header .alert' )
.attr( 'class', 'alert alert-dismissable' ).addClass( alertClass ).show()
.find( '.alert-message' ).html( message );
},
/** hide the alerts at the top */
_hideAlert : function( message ){
this.$( '.main-help' ).show();
this.$( '.header .alert' ).hide();
},
// ........................................................................ elements
/** reset all data to the initial state */
reset : function(){
@@ -789,46 +738,12 @@ var ListCollectionCreator = Backbone.View.extend( BASE_MVC.LoggableMixin ).exten
this.$dragging = null;
},
// ........................................................................ footer
/** handle a collection name change */
_changeName : function( ev ){
this._validationWarning( 'name', !!this._getName() );
},
/** check for enter key press when in the collection name and submit */
_nameCheckForEnter : function( ev ){
if( ev.keyCode === 13 && !this.blocking ){
this._clickCreate();
}
},
/** get the current collection name */
_getName : function(){
return _.escape( this.$( '.collection-name' ).val() );
},
/** attempt to create the current collection */
_clickCreate : function( ev ){
var name = this._getName();
if( !name ){
this._validationWarning( 'name' );
} else if( !this.blocking ){
this.createList( name );
}
},
// ------------------------------------------------------------------------ templates
//TODO: move to require text plugin and load these as text
//TODO: underscore currently unnecc. bc no vars are used
//TODO: better way of localizing text-nodes in long strings
/** underscore template fns attached to class */
templates : {
/** the skeleton */
main : _.template([
'<div class="header flex-row no-flex"></div>',
'<div class="middle flex-row flex-row-container"></div>',
'<div class="footer flex-row no-flex"></div>'
].join('')),
templates : _.extend({}, baseCreator.CollectionCreatorMixin._creatorTemplates, {
/** the header (not including help text) */
header : _.template([
@@ -974,7 +889,7 @@ var ListCollectionCreator = Backbone.View.extend( BASE_MVC.LoggableMixin ).exten
'</div>',
'</div>'
].join('')),
},
}),
// ------------------------------------------------------------------------ misc
/** string rep */
@@ -1,11 +1,11 @@
define([
"utils/levenshtein",
"utils/natural-sort",
"mvc/collection/list-collection-creator",
"mvc/collection/base-creator",
"mvc/base-mvc",
"utils/localization",
"ui/hoverhighlight"
], function( levenshteinDistance, naturalSort, LIST_COLLECTION_CREATOR, baseMVC, _l ){
], function( levenshteinDistance, naturalSort, baseCreator, baseMVC, _l ){
'use strict';
@@ -190,7 +190,7 @@ function autoPairFnBuilder( options ){
// ============================================================================
/** An interface for building collections of paired datasets.
*/
var PairedCollectionCreator = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
var PairedCollectionCreator = Backbone.View.extend( baseMVC.LoggableMixin ).extend( baseCreator.CollectionCreatorMixin ).extend({
_logNamespace : logNamespace,
className: 'list-of-pairs-collection-creator collection-creator flex-row-container',
@@ -942,6 +942,7 @@ var PairedCollectionCreator = Backbone.View.extend( baseMVC.LoggableMixin ).exte
// header
'click .more-help' : '_clickMoreHelp',
'click .less-help' : '_clickLessHelp',
'click .main-help' : '_toggleHelp',
'click .header .alert button' : '_hideAlert',
'click .forward-column .column-title' : '_clickShowOnlyUnpaired',
'click .reverse-column .column-title' : '_clickShowOnlyUnpaired',
@@ -981,39 +982,10 @@ var PairedCollectionCreator = Backbone.View.extend( baseMVC.LoggableMixin ).exte
'change .remove-extensions' : function( ev ){ this.toggleExtensions(); },
'change .collection-name' : '_changeName',
'keydown .collection-name' : '_nameCheckForEnter',
'click .cancel-create' : function( ev ){
if( typeof this.oncancel === 'function' ){
this.oncancel.call( this );
}
},
'click .cancel-create' : '_cancelCreate',
'click .create-collection' : '_clickCreate'//,
},
// ........................................................................ header
/** expand help */
_clickMoreHelp : function( ev ){
this.$( '.main-help' ).addClass( 'expanded' );
this.$( '.more-help' ).hide();
},
/** collapse help */
_clickLessHelp : function( ev ){
this.$( '.main-help' ).removeClass( 'expanded' );
this.$( '.more-help' ).show();
},
/** show an alert on the top of the interface containing message (alertClass is bootstrap's alert-*)*/
_showAlert : function( message, alertClass ){
alertClass = alertClass || 'alert-danger';
this.$( '.main-help' ).hide();
this.$( '.header .alert' ).attr( 'class', 'alert alert-dismissable' ).addClass( alertClass ).show()
.find( '.alert-message' ).html( message );
},
/** hide the alerts at the top */
_hideAlert : function( message ){
this.$( '.main-help' ).show();
this.$( '.header .alert' ).hide();
},
/** toggle between showing only unpaired and split view */
_clickShowOnlyUnpaired : function( ev ){
//this.debug( 'click unpaired', ev.currentTarget );
@@ -1419,33 +1391,6 @@ var PairedCollectionCreator = Backbone.View.extend( baseMVC.LoggableMixin ).exte
creator._renderFooter();
},
/** handle a collection name change */
_changeName : function( ev ){
this._validationWarning( 'name', !!this._getName() );
},
/** check for enter key press when in the collection name and submit */
_nameCheckForEnter : function( ev ){
if( ev.keyCode === 13 && !this.blocking ){
this._clickCreate();
}
},
/** get the current collection name */
_getName : function(){
return _.escape( this.$( '.collection-name' ).val() );
},
/** attempt to create the current collection */
_clickCreate : function( ev ){
var name = this._getName();
if( !name ){
this._validationWarning( 'name' );
} else if( !this.blocking ){
this.createList();
}
},
// ------------------------------------------------------------------------ misc
/** debug a dataset list */
_printList : function( list ){
@@ -1473,14 +1418,7 @@ var PairedCollectionCreator = Backbone.View.extend( baseMVC.LoggableMixin ).exte
//TODO: underscore currently unnecc. bc no vars are used
//TODO: better way of localizing text-nodes in long strings
/** underscore template fns attached to class */
PairedCollectionCreator.templates = PairedCollectionCreator.templates || {
/** the skeleton */
main : _.template([
'<div class="header flex-row no-flex"></div>',
'<div class="middle flex-row flex-row-container"></div>',
'<div class="footer flex-row no-flex">'
].join('')),
PairedCollectionCreator.templates = _.extend(PairedCollectionCreator.templates || {}, baseCreator.CollectionCreatorMixin._creatorTemplates, {
/** the header (not including help text) */
header : _.template([
@@ -1665,7 +1603,7 @@ PairedCollectionCreator.templates = PairedCollectionCreator.templates || {
'(Note: you do not have to pair all unpaired datasets to finish.)'
].join( '' )), '</p>'
].join(''))
};
});
//=============================================================================
@@ -218,14 +218,7 @@ var DatasetListItemEdit = _super.extend(
faIcon : 'fa-refresh',
onclick : function( ev ) {
ev.preventDefault();
// create webpack split point in order to load the tool form async
// TODO: split not working (tool loads fine)
require([ 'mvc/tool/tool-form' ], function( ToolForm ){
var form = new ToolForm.View({ 'job_id' : creating_job });
form.deferred.execute( function(){
Galaxy.app.display( form );
});
});
Galaxy.router.push( '/', { job_id : creating_job } );
}
});
}
+4 -7
View File
@@ -46,22 +46,19 @@ define([], function() {
});
},
/** Set backdrop for input element
*/
/** Set backdrop for input element */
backdrop: function() {
this.model.set( 'backdrop', true );
},
/** Set error text
*/
/** Set error text */
error: function( text ) {
this.model.set( 'error_text', text );
},
/** Reset this view
*/
/** Reset this view */
reset: function() {
this.model.set( 'error_text', null );
!this.model.get( 'fixed' ) && this.model.set( 'error_text', null );
},
render: function() {
@@ -156,6 +156,7 @@ function( Utils, Ui, Portlet, Repeat, InputElement, Parameters ) {
style : input_def.style,
backdrop : input_def.backdrop,
hidden : input_def.hidden,
fixed : input_def.fixed,
field : field
});
this.app.element_list[ id ] = input_element;
@@ -63,7 +63,7 @@ return {
for (i in options.global_actions) {
var action = options.global_actions[i];
var label_cls = '';
if (action.inbound) {
if (action.target == 'inbound') {
label_cls = 'use-inbound'
} else {
label_cls = 'use-outbound'
@@ -179,7 +179,7 @@ return {
// load attributes
var link = column_settings.link;
var value = column_settings.value;
var inbound = column_settings.inbound;
var target = column_settings.target;
// unescape value
if (jQuery.type( value ) === 'string') {
@@ -206,14 +206,7 @@ return {
if (options.operations.length != 0) {
tmpl += '<div id="' + id + '" class="' + cls + '" style="float: left;">';
}
var label_class = '';
if (inbound) {
label_class = 'use-inbound';
} else {
label_class = 'use-outbound';
}
tmpl += '<a class="menubutton-label ' + label_class + '" href="' + link + '" onclick="return false;">' + value + '</a>';
tmpl += '<a class="menubutton-label use-target" target="' + target + '" href="' + link + '" onclick="return false;">' + value + '</a>';
if (options.operations.length != 0) {
tmpl += '</div>';
}
+24 -43
View File
@@ -155,18 +155,6 @@ return Backbone.View.extend({
});
});
// Initialize autocomplete for text inputs in search UI.
var t1 = this.$el.find('#input-tags-filter');
if (t1.length) {
t1.autocomplete(this.grid.history_tag_autocomplete_url,
{ selectFirst: false, autoFill: false, highlight: false, mustMatch: false });
}
var t2 = this.$el.find('#input-name-filter');
if (t2.length) {
t2.autocomplete(this.grid.history_name_autocomplete_url,
{ selectFirst: false, autoFill: false, highlight: false, mustMatch: false });
}
// Initialize standard, advanced search toggles.
this.$el.find('.advanced-search-toggle').each( function() {
$(this).off();
@@ -221,26 +209,17 @@ return Backbone.View.extend({
//
// add inbound/outbound events
//
this.$el.find('.use-inbound').each( function() {
this.$el.find('.use-target').each( function() {
$(this).click( function(e) {
self.execute({
href : $(this).attr('href'),
inbound : true
target : $(this).attr('target')
});
return false;
});
});
this.$el.find('.use-outbound').each( function() {
$(this).click( function(e) {
self.execute({
href : $(this).attr('href')
});
return false;
});
});
// empty grid?
var items_length = options.items.length;
if (items_length == 0) {
@@ -278,8 +257,7 @@ return Backbone.View.extend({
html : operation['label'],
href : operation_settings['url_args'],
target : operation_settings['target'],
confirmation_text : operation['confirm'],
inbound : operation['inbound']
confirmation_text : operation['confirm']
};
// add popup function
@@ -518,17 +496,16 @@ return Backbone.View.extend({
var href = null;
var operation = null;
var confirmation_text = null;
var inbound = null;
var target = null;
// check for options
if (options)
{
if (options) {
// get options
href = options.href;
operation = options.operation;
id = options.id;
confirmation_text = options.confirmation_text;
inbound = options.inbound;
target = options.target;
// check if input contains the operation tag
if (href !== undefined && href.indexOf('operation=') != -1) {
@@ -571,7 +548,7 @@ return Backbone.View.extend({
if (this.grid.can_async_op(operation)) {
this.update_grid();
} else {
this.go_to(inbound, href);
this.go_to(target, href);
}
// done
@@ -580,7 +557,7 @@ return Backbone.View.extend({
// refresh grid
if (href) {
this.go_to(inbound, href);
this.go_to(target, href);
return false;
}
@@ -588,7 +565,7 @@ return Backbone.View.extend({
if (this.grid.get('async')) {
this.update_grid();
} else {
this.go_to(inbound, href);
this.go_to(target, href);
}
// done
@@ -596,7 +573,7 @@ return Backbone.View.extend({
},
// go to url
go_to: function (inbound, href) {
go_to: function (target, href) {
// get aysnc status
var async = this.grid.get('async');
this.grid.set('async', false);
@@ -616,17 +593,21 @@ return Backbone.View.extend({
item_ids: undefined,
async: async
});
if (inbound) {
// this currently assumes that there is only a single grid shown at a time
var $div = $('.grid-header').closest('.inbound');
if ($div.length !== 0) {
$div.load(href);
return;
}
switch (target) {
case 'inbound':
// this currently assumes that there is only a single grid shown at a time
var $div = $('.grid-header').closest('.inbound');
if ($div.length !== 0) {
$div.load(href);
return;
}
break;
case 'top':
window.top.location = href;
break;
default:
window.location = href;
}
window.location = href;
},
// Update grid.
@@ -43,6 +43,12 @@ HDAListItemView.prototype.templates = (function(){
'<span class="hid"><%- dataset.hid %></span> ',
'<span class="name"><%- dataset.name %></span>',
'</div>',
'</br>',
'<span class="nametags">',
'<% _.each(dataset.nametags, function(tag){ %>',
'<span class="label label-info"><%- tag %></span>',
'<% }); %>',
'</span>',
'</div>'
], 'dataset' );
@@ -729,27 +729,34 @@ var FolderToolbarView = Backbone.View.extend({
*/
addAllDatasetsFromHistory : function (){
var checked_hdas = this.modal.$el.find( '#selected_history_content' ).find( ':checked' );
var history_dataset_ids = [];
var hdas_to_add = [];
var history_item_ids = []; // can be hda or hdca
var history_item_types = [];
var items_to_add = [];
if ( checked_hdas.length < 1 ){
mod_toastr.info( 'You must select some datasets first.' );
} else {
this.modal.disableButton( 'Add' );
checked_hdas.each(function(){
var hid = $( this.parentElement ).data( 'id' );
if ( hid ) {
history_dataset_ids.push( hid );
}
if ( hid ) {
var item_type = $( this.parentElement ).data( 'name' );
history_item_ids.push( hid );
history_item_types.push( item_type );
}
});
for ( var i = history_dataset_ids.length - 1; i >= 0; i-- ) {
history_dataset_id = history_dataset_ids[i];
for ( var i = history_item_ids.length - 1; i >= 0; i-- ) {
history_item_id = history_item_ids[i];
var folder_item = new mod_library_model.Item();
folder_item.url = Galaxy.root + 'api/folders/' + this.options.id + '/contents';
folder_item.set( { 'from_hda_id':history_dataset_id } );
hdas_to_add.push( folder_item );
if (history_item_types[i] === 'collection') {
folder_item.set({'from_hdca_id': history_item_id});
} else {
folder_item.set({'from_hda_id': history_item_id});
}
items_to_add.push(folder_item);
}
this.initChainCallControl( { length: hdas_to_add.length, action: 'adding_datasets' } );
this.chainCallAddingHdas( hdas_to_add );
this.initChainCallControl( { length: items_to_add.length, action: 'adding_datasets' } );
this.chainCallAddingHdas( items_to_add );
}
},
@@ -1387,9 +1394,26 @@ var FolderToolbarView = Backbone.View.extend({
'<strong>Choose the datasets to import:</strong>',
'<ul>',
'<% _.each(history_contents, function(history_item) { %>',
'<li data-id="<%= _.escape(history_item.get("id")) %>">',
'<input style="margin: 0;" type="checkbox"> <%= _.escape(history_item.get("hid")) %>: <%= _.escape(history_item.get("name")) %>',
'</li>',
'<% if (history_item.get("deleted") != true ) { %>',
'<% if (history_item.get("type") === "collection") { %>',
'<% var collection_type = history_item.get("collection_type") %>',
'<% if (collection_type === "list") { %>',
'<li data-id="<%= _.escape(history_item.get("id")) %>" data-name="<%= _.escape(history_item.get("type")) %>">',
'<input style="margin: 0;" type="checkbox"> <%= _.escape(history_item.get("hid")) %>: <%= _.escape(history_item.get("name")) %> (Dataset Collection)',
'</li>',
'<% } else { %>',
'<li><input style="margin: 0;" type="checkbox" onclick="return false;" disabled="disabled">',
'<span title="You can convert this collection into a collection of type list using the Collection Tools">',
' <%= _.escape(history_item.get("hid")) %>: <%= _.escape(history_item.get("name")) %> (Dataset Collection of type <%= _.escape(collection_type) %> not supported.)',
'</span>',
'</li>',
'<% } %>',
'<% } else if (history_item.get("visible") === true && history_item.get("state") === "ok") { %>',
'<li data-id="<%= _.escape(history_item.get("id")) %>" data-name="<%= _.escape(history_item.get("type")) %>">',
'<input style="margin: 0;" type="checkbox"> <%= _.escape(history_item.get("hid")) %>: <%= _.escape(history_item.get("name")) %>',
'</li>',
'<% } %>',
'<% } %>',
'<% }); %>',
'</ul>'
].join(''));
@@ -306,7 +306,7 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
var is_simple_input = ([ 'data_input', 'data_collection_input' ]).indexOf( step.step_type ) != -1;
_.each( step.inputs, function( input ) { input.flavor = 'module'; input.hide_label = is_simple_input; } );
form = new Form( Utils.merge({
title : '<b>' + step.name + '</b>' + step.description,
title : step.title,
onchange : function() { _.each( self.links[ step.index ], function( link ) { self._refreshStep( link ) } ) },
inputs : step.inputs && step.inputs.length > 0 ? step.inputs : [ { type: 'hidden', name: 'No options available.', ignore: null } ]
}, step ) );
+1 -4
View File
@@ -532,10 +532,7 @@ var ToolLinkView = BaseView.extend({
var self = this;
$link.find('a').on('click', function(e) {
e.preventDefault();
var form = new ToolForm.View( { id : self.model.id, version : self.model.get('version') } );
form.deferred.execute(function() {
Galaxy.app.display( form );
});
Galaxy.router.push( '/', { tool_id : self.model.id, version : self.model.get('version') } );
});
}
@@ -221,7 +221,8 @@ var View = Backbone.View.extend({
hid : item.hid,
keep : item.keep,
label: item.hid + ': ' + item.name,
value: item.id
value: item.id,
tags : item.tags
});
self.history[ item.id + '_' + src ] = item;
});
@@ -109,6 +109,11 @@ var View = Backbone.View.extend({
}
},
/** Matches a search term with a given text */
_match: function( term, text ) {
return !term || term == '' || String( text ).toUpperCase().indexOf( term.toUpperCase() ) >= 0
},
/** Updates the selection options */
_changeData: function() {
var self = this;
@@ -125,22 +130,44 @@ var View = Backbone.View.extend({
if ( this.model.get( 'searchable' ) ) {
this.data2 = [];
_.each( this.data, function( option, index ) {
self.data2.push( { order: index, id: option.value, text: option.label } );
self.data2.push( { order: index, id: option.value, text: option.label, tags: option.tags } );
});
this.$select.data( 'select2' ) && this.$select.select2( 'destroy' );
this.matched_tags = {};
this.$select.select2({
data : self.data2,
closeOnSelect : !this.model.get( 'multiple' ),
multiple : this.model.get( 'multiple' ),
query : function( q ) {
self.matched_tags = {};
var pagesize = self.model.get( 'pagesize' );
var results = _.filter( self.data2, function ( e ) {
return !q.term || q.term == '' || e.text.toUpperCase().indexOf( q.term.toUpperCase() ) >= 0;
var found = false;
_.each( e.tags, function( tag ) {
if ( self._match( q.term, tag ) ) {
found = self.matched_tags[ tag ] = true;
}
});
return found || self._match( q.term, e.text );
});
q.callback({
results: results.slice( ( q.page - 1 ) * pagesize, q.page * pagesize ),
more : results.length >= q.page * pagesize
});
},
formatResult : function( result ) {
return _.escape( result.text ) +
'<div class="ui-tags">' +
_.reduce( result.tags, function( memo, tag ) {
if ( self.matched_tags[ tag ] ) {
return memo + '&nbsp;' +
'<div class="label label-info">' +
_.escape( tag ) +
'</div>'
}
return memo;
}, '' ) +
'</div>';
}
});
this.$( '.select2-container .select2-search input' ).off( 'blur' );
@@ -106,7 +106,7 @@ define( [ 'utils/utils' ], function( Utils ) {
_templateRow: function( options ) {
return '<tr class="upload-ftp-row">' +
'<td class="_has_collection" style="display: none;"><div class="icon"/></td>' +
'<td class="ftp-name">' + options.path + '</td>' +
'<td class="ftp-name">' + _.escape(options.path) + '</td>' +
'<td class="ftp-size">' + Utils.bytesToString( options.size ) + '</td>' +
'<td class="ftp-time">' + options.ctime + '</td>' +
'</tr>';
@@ -1,40 +1,43 @@
/** User Preferences view */
define( [ 'mvc/form/form-view', 'mvc/ui/ui-misc' ], function( Form, Ui ) {
var View = Backbone.View.extend({
initialize: function() {
this.defs = {
/** Contains descriptive dictionaries describing user forms */
var Model = Backbone.Model.extend({
initialize: function( options ) {
options = options || {};
options.user_id = options.user_id || Galaxy.user.id;
this.set({
'user_id' : options.user_id,
'information': {
title : 'Manage information',
description : 'Edit your email, addresses and custom parameters or change your username.',
url : 'api/users/' + Galaxy.user.id + '/information/inputs',
url : 'api/users/' + options.user_id + '/information/inputs',
icon : 'fa-user'
},
'password': {
title : 'Change password',
description : 'Allows you to change your login credentials.',
icon : 'fa-unlock-alt',
url : 'api/users/' + Galaxy.user.id + '/password/inputs',
url : 'api/users/' + options.user_id + '/password/inputs',
submit_title : 'Save password',
},
'communication': {
title : 'Change communication settings',
description : 'Enable or disable the communication feature to chat with other users.',
url : 'api/users/' + Galaxy.user.id + '/communication/inputs',
url : 'api/users/' + options.user_id + '/communication/inputs',
icon : 'fa-comments-o'
},
'permissions': {
title : 'Set dataset permissions for new histories',
description : 'Grant others default access to newly created histories. Changes made here will only affect histories created after these settings have been stored.',
url : 'api/users/' + Galaxy.user.id + '/permissions/inputs',
url : 'api/users/' + options.user_id + '/permissions/inputs',
icon : 'fa-users',
submit_title : 'Save permissions'
},
'api_key': {
title : 'Manage API key',
description : 'Access your current API key or create a new one.',
url : 'api/users/' + Galaxy.user.id + '/api_key/inputs',
url : 'api/users/' + options.user_id + '/api_key/inputs',
icon : 'fa-key',
submit_title : 'Create a new key',
submit_icon : 'fa-check'
@@ -42,7 +45,7 @@ define( [ 'mvc/form/form-view', 'mvc/ui/ui-misc' ], function( Form, Ui ) {
'toolbox_filters': {
title : 'Manage Toolbox filters',
description : 'Customize your Toolbox by displaying or omitting sets of Tools.',
url : 'api/users/' + Galaxy.user.id + '/toolbox_filters/inputs',
url : 'api/users/' + options.user_id + '/toolbox_filters/inputs',
icon : 'fa-filter',
submit_title : 'Save filters'
},
@@ -69,7 +72,15 @@ define( [ 'mvc/form/form-view', 'mvc/ui/ui-misc' ], function( Form, Ui ) {
});
}
}
}
});
}
});
/** View of the main user preference panel with links to individual user forms */
var View = Backbone.View.extend({
initialize: function() {
this.model = new Model();
this.message = new Ui.Message();
this.setElement( '<div/>' );
this.render();
@@ -85,93 +96,39 @@ define( [ 'mvc/form/form-view', 'mvc/ui/ui-misc' ], function( Form, Ui ) {
.append( $( '<p/>' ).append( 'You are logged in as <strong>' + _.escape( data.email ) + '</strong>.' ) )
.append( self.$table = $( '<table/>' ).addClass( 'ui-panel-table' ) );
if( !config.use_remote_user ) {
self._link( self.defs.information );
self._link( self.defs.password );
self._addLink( 'information' );
self._addLink( 'password' );
}
if( config.enable_communication_server ) {
self._link( self.defs.communication );
self._addLink( 'communication' );
}
self._link( self.defs.permissions );
self._link( self.defs.api_key );
self._addLink( 'permissions' );
self._addLink( 'api_key' );
if( config.has_user_tool_filters ) {
self._link( self.defs.toolbox_filters );
self._addLink( 'toolbox_filters' );
}
if( config.enable_openid && !config.use_remote_user ) {
self._link( self.defs.openids );
self._addLink( 'openids' );
}
self._link( self.defs.logout );
self._addLink( 'logout' );
self.$preferences.append( self._templateFooter( data ) );
self.$el.empty().append( self.$preferences );
});
},
_link: function( page ) {
var self = this;
var $page_item = $( this._templateRow( page ) );
this.$table.append( $page_item );
$page_item.find( 'a' ).on( 'click', function() {
if ( page.url ) {
$.ajax({
url : Galaxy.root + page.url,
type : 'GET'
}).done( function( response ) {
var options = $.extend( {}, page, response );
var form = new Form({
title : options.title,
icon : options.icon,
inputs : options.inputs,
operations: {
'submit': new Ui.ButtonIcon({
tooltip : options.submit_tooltip,
title : options.submit_title || 'Save settings',
icon : options.submit_icon || 'fa-save',
onclick : function() { self._submit( form, options ) }
}),
'back': new Ui.ButtonIcon({
icon : 'fa-caret-left',
tooltip : 'Return to user preferences',
title : 'Preferences',
onclick : function() { form.remove(); self.$preferences.show(); }
})
}
});
self.$preferences.hide();
self.$el.append( form.$el );
}).fail( function( response ) {
self.message.update( { message: 'Failed to load resource ' + page.url + '.', status: 'danger' } );
})
} else {
page.onclick();
}
});
_addLink: function( action ) {
var options = this.model.get( action );
var $row = $( this._templateLink( options ) );
var $a = $row.find( 'a' );
if ( options.onclick ) {
$a.on( 'click', function() { options.onclick() } );
} else {
$a.attr( 'href', Galaxy.root + 'user/' + action );
}
this.$table.append( $row );
},
_submit: function( form, options ) {
var self = this;
$.ajax( {
url : options.url,
data : JSON.stringify(form.data.create()),
type : 'PUT',
contentType : 'application/json'
}).done( function( response ) {
var updated_values = false;
form.data.matchModel( response, function ( input, input_id ) {
form.field_list[ input_id ].value( input.value );
updated_values = true;
});
if ( updated_values ) {
form.message.update( { message: response.message, status: 'success' } );
} else {
form.remove();
self.$preferences.show();
self.message.update( { message: response.message, status: 'success' } );
}
}).fail( function( response ) {
form.message.update( { message: response.responseJSON.err_msg, status: 'danger' } );
});
},
_templateRow: function( options ) {
_templateLink: function( options ) {
return '<tr>' +
'<td>' +
'<div class="ui-panel-icon fa ' + options.icon + '">' +
@@ -192,7 +149,69 @@ define( [ 'mvc/form/form-view', 'mvc/ui/ui-misc' ], function( Form, Ui ) {
}
});
/** View of individual user forms */
var Forms = Backbone.View.extend({
initialize: function( options ) {
this.model = new Model( options );
this.page = this.model.get( options.form_id );
this.setElement( '<div/>' );
this.render();
},
render: function() {
var self = this;
$.ajax({
url : Galaxy.root + this.page.url,
type : 'GET'
}).done( function( response ) {
var options = $.extend( {}, self.page, response );
var form = new Form({
title : options.title,
icon : options.icon,
inputs : options.inputs,
operations: {
'submit': new Ui.ButtonIcon({
tooltip : options.submit_tooltip,
title : options.submit_title || 'Save settings',
icon : options.submit_icon || 'fa-save',
onclick : function() { self._submit( form, options ) }
})
}
});
self.$el.empty().append( form.$el );
}).fail( function( response ) {
self.$el.empty().append( new Ui.Message({
message : 'Failed to load resource ' + self.page.url + '.',
status : 'danger',
persistent : true
}).$el );
});
},
_submit: function( form, options ) {
var self = this;
$.ajax( {
url : Galaxy.root + options.url,
data : JSON.stringify( form.data.create() ),
type : 'PUT',
contentType : 'application/json'
}).done( function( response ) {
var updated_values = false;
form.data.matchModel( response, function ( input, input_id ) {
form.field_list[ input_id ].value( input.value );
updated_values = true;
});
form.message.update( { message: response.message, status: 'success' } );
}).fail( function( response ) {
window.console.log( response );
form.message.update( { message: response.responseJSON.err_msg, status: 'danger' } );
});
}
});
return {
View: View
View : View,
Forms : Forms
};
});
@@ -1,12 +1,18 @@
/** This is the workflow tool form. */
define( [ 'utils/utils', 'mvc/tool/tool-form-base' ],
function( Utils, ToolFormBase ) {
var View = Backbone.View.extend({
define( [ 'utils/utils', 'mvc/form/form-view', 'mvc/tool/tool-form-base' ], function( Utils, Form, ToolFormBase ) {
/** Default form wrapper for non-tool modules in the workflow editor. */
var Default = Backbone.View.extend({
initialize: function( options ) {
this.form = new Form( options );
}
});
/** Tool form wrapper for the workflow editor. */
var Tool = Backbone.View.extend({
initialize: function( options ) {
var self = this;
this.workflow = options.workflow;
this.node = options.node;
this.setElement( '<div/>' );
if ( this.node ) {
this.post_job_actions = this.node.post_job_actions || {};
Utils.deepeach( options.inputs, function( input ) {
@@ -15,7 +21,7 @@ define( [ 'utils/utils', 'mvc/tool/tool-form-base' ],
input.type = 'hidden';
input.info = 'Data input \'' + input.name + '\' (' + Utils.textify( input.extensions ) + ')';
input.value = { '__class__': 'RuntimeValue' };
} else {
} else if ( !input.fixed ) {
input.collapsible_value = { '__class__': 'RuntimeValue' };
input.is_workflow = ( input.options && input.options.length == 0 ) ||
( [ 'integer', 'float' ].indexOf( input.type ) != -1 );
@@ -64,7 +70,6 @@ define( [ 'utils/utils', 'mvc/tool/tool-form-base' ],
});
},
}));
this.$el.append( this.form.$el );
} else {
Galaxy.emit.debug('tool-form-workflow::initialize()', 'Node not found in workflow.');
}
@@ -74,14 +79,6 @@ define( [ 'utils/utils', 'mvc/tool/tool-form-base' ],
_makeSections: function( options ){
var inputs = options.inputs;
var datatypes = options.datatypes;
inputs.push({
label : 'Annotation / Notes',
name : '__annotation',
type : 'text',
area : true,
help : 'Add an annotation or note for this step. It will be shown with the workflow.',
value : this.node.annotation
});
var output_id = this.node.output_terminals && Object.keys( this.node.output_terminals )[ 0 ];
if ( output_id ) {
inputs.push({
@@ -256,6 +253,7 @@ define( [ 'utils/utils', 'mvc/tool/tool-form-base' ],
});
return {
View: View
Default: Default,
Tool: Tool
};
});
@@ -6,13 +6,12 @@ define([
'mvc/workflow/workflow-canvas',
'mvc/workflow/workflow-node',
'mvc/workflow/workflow-icons',
'mvc/tool/tool-form-workflow',
'mvc/form/form-view',
'mvc/workflow/workflow-forms',
'mvc/ui/ui-misc',
'utils/async-save-text',
'libs/toastr',
'ui/editable-text'
], function( Utils, Globals, Workflow, WorkflowCanvas, Node, WorkflowIcons, ToolForm, Form, Ui, async_save_text, Toastr ){
], function( Utils, Globals, Workflow, WorkflowCanvas, Node, WorkflowIcons, FormWrappers, Ui, async_save_text, Toastr ){
// Reset tool search to start state.
function reset_tool_search( initValue ) {
@@ -661,62 +660,64 @@ define([
var $container = $( '#' + cls );
if ( content && $container.find( '#' + id ).length == 0 ) {
var $el = $( '<div id="' + id + '" class="' + cls + '"/>' );
var form = null;
var form_wrapper = null;
content.node = node;
content.workflow = this.workflow;
content.datatypes = this.datatypes;
content.icon = WorkflowIcons[ node.type ];
content.cls = 'ui-portlet-narrow';
if ( node.type == 'tool' ) {
content.node = node;
content.workflow = this.workflow;
content.datatypes = this.datatypes;
form = new ToolForm.View( content );
} else {
content.inputs.unshift({
type : 'text',
name : '__label',
label : 'Label',
value : node.label,
help : 'Add a step label.',
onchange: function( new_label ) {
var duplicate = false;
for ( var i in self.workflow.nodes ) {
var n = self.workflow.nodes[ i ];
if ( n.label && n.label == new_label && n.id != node.id ) {
duplicate = true;
break;
}
content.inputs.unshift({
type : 'text',
name : '__annotation',
label : 'Annotation',
fixed : true,
value : node.annotation,
area : true,
help : 'Add an annotation or notes to this step. Annotations are available when a workflow is viewed.'
});
content.inputs.unshift({
type : 'text',
name : '__label',
label : 'Label',
value : node.label,
help : 'Add a step label.',
fixed : true,
onchange: function( new_label ) {
var duplicate = false;
for ( var i in self.workflow.nodes ) {
var n = self.workflow.nodes[ i ];
if ( n.label && n.label == new_label && n.id != node.id ) {
duplicate = true;
break;
}
var input_id = form.data.match( '__label' );
var input_element = form.element_list[ input_id ];
input_element.model.set( 'error_text', duplicate && 'Duplicate label. Please fix this before saving the workflow.' );
form.trigger( 'change' );
}
var input_id = form_wrapper.form.data.match( '__label' );
var input_element = form_wrapper.form.element_list[ input_id ];
input_element.model.set( 'error_text', duplicate && 'Duplicate label. Please fix this before saving the workflow.' );
form_wrapper.form.trigger( 'change' );
}
});
content.onchange = function() {
Utils.request({
type : 'POST',
url : Galaxy.root + 'api/workflows/build_module',
data : {
id : node.id,
type : node.type,
content_id : node.content_id,
inputs : form_wrapper.form.data.create()
},
success : function( data ) {
node.update_field_data( data );
}
});
content.inputs.push({
type : 'text',
name : '__annotation',
label : 'Annotation',
value : node.annotation,
area : true,
help : 'Add an annotation or notes to this step. Annotations are available when a workflow is viewed.'
});
content.onchange = function() {
Utils.request({
type : 'POST',
url : Galaxy.root + 'api/workflows/build_module',
data : {
id : node.id,
type : node.type,
content_id : node.content_id,
inputs : form.data.create()
},
success : function( data ) {
node.update_field_data( data );
}
});
};
form = new Form( content );
};
if ( node.type == 'tool' ) {
form_wrapper = new FormWrappers.Tool( content );
} else {
form_wrapper = new FormWrappers.Default( content );
}
$el.append( form.$el );
$el.append( form_wrapper.form.$el );
$container.append( $el );
}
$( '.' + cls ).hide();
+331
View File
@@ -0,0 +1,331 @@
/** fr localization */
define({
// ----------------------------------------------------------------------------- masthead
"Analyze Data":
"Analyse de données",
"Workflow":
"Workflow",
"Shared Data":
"Données partagées",
"Data Libraries":
"Bibliothèque de données",
"Histories":
"Historiques",
"Workflows":
"Workflows",
"Visualizations":
"Visualisations",
"Pages":
"Pages",
"Visualization":
"Visualisation",
"New Track Browser":
"Nouveau Navigateur de Tracks/Pistes",
"Saved Visualizations":
"Visualisations sauvegardés",
"Interactive Environments":
"Environnements interactifs",
"Admin":
"Admin",
"Help":
"Aide",
"Support":
"Assistance",
"Search":
"Recherche",
"Mailing Lists":
"Liste de diffusion",
"Videos":
"Vidéos",
"Wiki":
"Documentations",
"How to Cite Galaxy":
"Comment citer Galaxy",
"Interactive Tours":
"Guides interactifs",
"User":
"Utilisateur",
"Login":
"Authentification",
"Register":
"Enregistrement",
"Logged in as":
"Authentifié en tant que",
"Preferences":
"Préférences",
"Custom Builds":
"Mes génomes Builds de référence",
"Logout":
"Déconnection",
"Saved Histories":
"Historiques sauvegardés",
"Saved Datasets":
"Jeux de données sauvegardés",
"Saved Pages":
"Pages sauvegardées",
// ---------------------------------------------------------------------------- histories
// ---- history/options-menu
"History Lists":
"Tableaux des historiques",
// Saved histories is defined above.
// "Saved Histories":
// false,
"Histories Shared with Me":
"Historiques partagés avec moi",
"Current History":
"Cet Historique",
"Create New":
"Créer un nouveau",
"Copy History":
"Copier l'Historique",
"Share or Publish":
"Partager et publier",
"Show Structure":
"Montrer la structure",
"Extract Workflow":
"Extraire un Workflow",
// Delete is defined elsewhere, but is also in this menu.
// "Delete":
// false,
"Delete Permanently":
"Supprimer définitivement",
"Dataset Actions":
"Actions sur les jeux de données",
"Copy Datasets":
"Copier des jeux de données",
"Dataset Security":
"Permissions/Sécurité",
"Resume Paused Jobs":
"Reprendre les processus en pause",
"Collapse Expanded Datasets":
"Réduire les données étendus",
"Unhide Hidden Datasets":
"Afficher les données cachés",
"Delete Hidden Datasets":
"Supprimer les données cachés",
"Purge Deleted Datasets":
"Purger les données supprimer",
"Downloads":
"Télécharger",
"Export Tool Citations":
"Exporter les citations des outils",
"Export History to File":
"Exporter l'Historique dans un fichier",
"Other Actions":
"Autres actions",
"Import from File":
"Importer depuis un fichier",
"Webhooks":
"Webhooks",
// ---- history-model
// ---- history-view
"This history is empty" :
"Cet historique est vide",
"No matching datasets found" :
"Aucunes données correspondantes n'a été trouvées",
"An error occurred while getting updates from the server" :
"Une erreur s'est produite lors de la réception des données depuis le serveur",
"Please contact a Galaxy administrator if the problem persists" :
"Veuillez contacter un administrateur de l'instance Galaxy si ce problème persiste",
//TODO:
//"An error was encountered while <% where %>" :
//false,
"search datasets" :
"Rechercher des données",
"You are currently viewing a deleted history!" :
"Vous consultez actuellement un historique supprimé!",
"You are over your disk quota" :
"Vous avez dépassé votre quota d'espace disque",
"Tool execution is on hold until your disk usage drops below your allocated quota" :
"L'exécution de l'outil est en attente tant que votre utilisation d'espace disque dépasse le quota attribué",
"All" :
"Tout",
"None" :
"Aucun",
"For all selected" :
"Pour toute la sélection",
// // ---- history-view-edit
"Edit history tags" :
"Editer les mots-clés de l'historique",
"Edit history Annotation" :
"Editer l'annotation de l'historique",
"Click to rename history" :
"Cliquer pour renommer l'historique",
// multi operations
"Operations on multiple datasets" :
"Opérer sur plusieurs jeux de données en même temps",
"Hide datasets" :
"Cacher les jeux de données",
"Unhide datasets" :
"Afficher les jeux de données cachés",
"Delete datasets" :
"Supprimer les jeux de données",
"Undelete datasets" :
"Restaurer les jeux de données supprimés",
"Permanently delete datasets" :
"Supprimer définitivement les jeux de données",
"This will permanently remove the data in your datasets. Are you sure?" :
"Cela supprimera de manière permanente les données de votre historique. Êtes-vous certain?",
// menu operations
// // ---- history-view-annotated
"Dataset" :
"Jeu de données",
"Annotation" :
"Annotation",
// ---- history-view-edit-current
"This history is empty. Click 'Get Data' on the left tool menu to start" :
"Cet historique est vide. Cliquer sur 'Get Data' au niveau du menu d'outils à gauche pour démarrer",
"You must be logged in to create histories" :
"Vous devez être connecté pour créer un historique",
//TODO:
//"You can <% loadYourOwn %> or <% externalSource %>" :
//"Vous pouvez <% loadYourOwn %> ou <% externalSource %>",
"load your own data" :
"Charger vos propres données",
"get data from an external source" :
"Charger des données depuis une source externe",
// these aren't in zh/ginga.po and the template doesn't localize
"Include Deleted Datasets" :
"Inclure les jeux de données supprimés",
"Include Hidden Datasets" :
"Inclure les jeux de données cachés",
// ---------------------------------------------------------------------------- datasets
// ---- hda-model
"Unable to purge dataset" :
"Impossible de purger le jeu de données",
// ---- hda-base
// display button
"Cannot display datasets removed from disk" :
"Impossible de visualiser les jeux de données supprimés du disque",
"This dataset must finish uploading before it can be viewed" :
"Le jeu de données doit être totalement téléversé avant de pouvoir être visualiser",
"This dataset is not yet viewable" :
"Ce jeu de données n'est pas visualisable",
"View data" :
"Voir les données",
// download button
"Download" :
"Télécharger",
"Download dataset" :
"Télécharger le jeu de données",
"Additional files" :
"Fichiers additionnels",
// info/show_params
"View details" :
"Voir les détails",
// dataset states
// state: new
"This is a new dataset and not all of its data are available yet" :
"Il s'agit d'un nouveau jeu de données et seule une partie des données est accessible pour le moment",
// state: noPermission
"You do not have permission to view this dataset" :
"Vous n'avez pas la permission de voir ce jeu de données",
// state: discarded
"The job creating this dataset was cancelled before completion" :
"Le processus à l'origine de ce jeu de données a été annulé prématurément",
// state: queued
"This job is waiting to run" :
"Ce calcul est en attente de traitement",
// state: upload
"This dataset is currently uploading" :
"Ce jeu de données est en cours de téléversement",
// state: setting_metadata
"Metadata is being auto-detected" :
"Les métadonnées sont auto-détectées",
// state: running
"This job is currently running" :
"Le traitement est en cours",
// state: paused
"This job is paused. Use the \"Resume Paused Jobs\" in the history menu to resume" :
"Ce traitement est en pause. Utilisez le \"Relancer les traitements en pause\" dans le menu d'historique pour le relancer",
// state: error
"An error occurred with this dataset" :
"Un erreur est survenue avec ce jeu de données",
// state: empty
"No data" :
"Aucune donnée",
// state: failed_metadata
"An error occurred setting the metadata for this dataset" :
"Une erreur est survenue pendant la récupération des métadonnées de ce jeu de données",
// ajax error prefix
"There was an error getting the data for this dataset" :
"Il est survenu une erreur durant la récupération du contenu de ce jeu de données",
// purged'd/del'd msg
"This dataset has been deleted and removed from disk" :
"Ce jeu de données a été supprimé et effacé du disque",
"This dataset has been deleted" :
"Ce jeu de données a été supprimé",
"This dataset has been hidden" :
"Ce jeu de données a été caché",
"format" :
"format",
"database" :
"génome de référence",
// ---- hda-edit
"Edit attributes" :
"Editer les attributs",
"Cannot edit attributes of datasets removed from disk" :
"Impossible d'éditer les attributs de jeux de données effacés du disque",
"Undelete dataset to edit attributes" :
"Restaurer le jeu de données pour en éditer les attributs",
"This dataset must finish uploading before it can be edited" :
"Ce jeu de données doit être entièrement téléversé avant toute modification",
"This dataset is not yet editable" :
"Ce jeu de données n'est pas encore éditable",
"Delete" :
"Supprimer",
"Dataset is already deleted" :
"Le jeu de données est déjà supprimé",
"View or report this error" :
"Voir ou remonter cette erreur",
"Run this job again" :
"Exécuter ce traitement à nouveau",
"Visualize" :
"Visualiser",
"Visualize in" :
"Visualiser via",
"Undelete it" :
"Restaurer",
"Permanently remove it from disk" :
"Supprimer définitivement du disque",
"Unhide it" :
"Rendre visible",
"You may be able to" :
"Vous devriez être en mesure de",
"set it manually or retry auto-detection" :
"Traitez le manuellement ou retenter la détection automatique",
"Edit dataset tags" :
"Editer les mots-clés du jeu de données",
"Edit dataset annotation" :
"Editer les annotations du jeu de données",
// ---------------------------------------------------------------------------- misc. MVC
"Tags" :
"Mots-clés",
"Edit annotation" :
"Editer les annotations",
});
+36 -38
View File
@@ -5,9 +5,9 @@ define({
// ---- history-model
// ---- history-view
"This history is empty" :
"ヒストリーは空です",
"ヒストリーは空です",
"No matching datasets found" :
"一致するデータセットが見つかりませんでした",
"一致するデータセットが見つかりませんでした",
//"An error occurred while getting updates from the server" :
//false,
//"Please contact a Galaxy administrator if the problem persists" :
@@ -16,19 +16,19 @@ define({
//"An error was encountered while <% where %>" :
//false,
"Search datasets" :
"データセットを検索する",
"データセットを検索する",
"You are currently viewing a deleted history!" :
"消去したヒストリーをみています。",
"消去したヒストリーをみています。",
"You are over your disk quota" :
"あなたはディスククォータを超えている",
"あなたはディスククォータを超えている",
//"Tool execution is on hold until your disk usage drops below your allocated quota" :
//false,
"All" :
"一式",
"一式",
"None" :
"なし",
"なし",
"For all selected" :
"各項目を",
"各項目を",
// ---- history-view-edit
//"Edit history tags" :
@@ -36,10 +36,10 @@ define({
//"Edit history Annotation" :
//false,
"Click to rename history" :
"ヒストリーの名前を変更するにはクリック",
"ヒストリーの名前を変更するにはクリック",
// multi operations
"Operations on multiple datasets" :
"複数のデータセットに対する操作",
"複数のデータセットに対する操作",
//"Hide datasets" :
//false,
//"Unhide datasets" :
@@ -49,23 +49,21 @@ define({
//"Undelete datasets" :
//false,
"Permanently delete datasets" :
"永久にデータセットを削除",
"永久にデータセットを削除",
"This will permanently remove the data in your datasets. Are you sure?" :
"これは永久にあなたのデータセット内のデータを削除します。本当に?",
"これは永久にあなたのデータセット内のデータを削除します。本当に?",
// ---- history-view-annotated
"Dataset" :
"データセット",
"データセット",
//"Annotation" :
//false,
// ---- history-view-edit-current
"This history is empty. Click 'Get Data' on the left tool menu to start" :
"ヒストリーは空です。解析をはじめるには、左パネルの 'データ取得' をクリック",
"No matching datasets found" :
"一致するデータセットが見つかりませんでした",
"ヒストリーは空です。解析をはじめるには、左パネルの 'データ取得' をクリック",
"You must be logged in to create histories" :
"ヒストリーを作成するためにはログインする必要があります",
"ヒストリーを作成するためにはログインする必要があります",
//TODO:
//"You can <% loadYourOwn %> or <% externalSource %>" :
//false,
@@ -95,17 +93,17 @@ define({
//"This dataset is not yet viewable" :
//false,
"View data" :
"データを表示",
"データを表示",
// download button
"Download" :
"ダウンロード",
"ダウンロード",
"Download dataset" :
"データセットをダウンロード",
"データセットをダウンロード",
//"Additional files" :
//false,
// info/show_params
"View details" :
"細部を表示",
"細部を表示",
// dataset states
// state: new
@@ -119,7 +117,7 @@ define({
//false,
// state: queued
"This job is waiting to run" :
"ジョブは実行待ちです",
"ジョブは実行待ちです",
// state: upload
//"This dataset is currently uploading" :
//false,
@@ -128,16 +126,16 @@ define({
//false,
// state: running
"This job is currently running" :
"ジョブは実行中です",
"ジョブは実行中です",
// state: paused
//"This job is paused. Use the \"Resume Paused Jobs\" in the history menu to resume" :
//false,
// state: error
"An error occurred with this dataset" :
"このジョブの実行中に発生したエラー",
"このジョブの実行中に発生したエラー",
// state: empty
"No data" :
"データ無し",
"データ無し",
// state: failed_metadata
//"An error occurred setting the metadata for this dataset" :
//false,
@@ -148,20 +146,20 @@ define({
// purged'd/del'd msg
"This dataset has been deleted and removed from disk" :
"このデータセットは、永続的にディスクから削除されました",
"このデータセットは、永続的にディスクから削除されました",
"This dataset has been deleted" :
"このデータセットは削除されました",
"このデータセットは削除されました",
"This dataset has been hidden" :
"このデータセットは、非表示にされた",
"このデータセットは、非表示にされた",
"format" :
"フォーマット",
"フォーマット",
"database" :
"データベース",
"データベース",
// ---- hda-edit
"Edit attributes" :
"変数を編集する",
"変数を編集する",
//"Cannot edit attributes of datasets removed from disk" :
//false,
//"Undelete dataset to edit attributes" :
@@ -172,27 +170,27 @@ define({
//false,
"Delete" :
"削除する",
"削除する",
//"Dataset is already deleted" :
//false,
"View or report this error" :
"このエラーを届け出る",
"このエラーを届け出る",
"Run this job again" :
"もう一度このジョブを実行する",
"もう一度このジョブを実行する",
"Visualize" :
"可視化する",
"可視化する",
//"Visualize in" :
//false,
"Undelete it" :
"復元する",
"復元する",
"Permanently remove it from disk" :
"永久にディスクから削除",
"永久にディスクから削除",
"Unhide it" :
"非表示解除する",
"非表示解除する",
//"You may be able to" :
//false,
+191 -78
View File
@@ -1,72 +1,186 @@
/** en/main localization hash - for use with requirejs' i18n plugin */
define({
root : {
// ----------------------------------------------------------------------------- masthead
"Analyze Data":
false,
"Workflow":
false,
"Shared Data":
false,
"Data Libraries":
false,
"Histories":
false,
"Workflows":
false,
"Visualizations":
false,
"Pages":
false,
"Visualization":
false,
"New Track Browser":
false,
"Saved Visualizations":
false,
"Interactive Environments":
false,
"Admin":
false,
"Help":
false,
"Support":
false,
"Search":
false,
"Mailing Lists":
false,
"Videos":
false,
"Wiki":
false,
"How to Cite Galaxy":
false,
"Interactive Tours":
false,
"User":
false,
"Login":
false,
"Register":
false,
"Logged in as":
false,
"Preferences":
false,
"Custom Builds":
false,
"Logout":
false,
"Saved Histories":
false,
"Saved Datasets":
false,
"Saved Pages":
false,
// ---------------------------------------------------------------------------- histories
// ---- history/options-menu
"History Lists":
false,
// Saved histories is defined above.
// "Saved Histories":
// false,
"Histories Shared with Me":
false,
"Current History":
false,
"Create New":
false,
"Copy History":
false,
"Share or Publish":
false,
"Show Structure":
false,
"Extract Workflow":
false,
// Delete is defined elsewhere, but is also in this menu.
// "Delete":
// false,
"Delete Permanently":
false,
"Dataset Actions":
false,
"Copy Datasets":
false,
"Dataset Security":
false,
"Resume Paused Jobs":
false,
"Collapse Expanded Datasets":
false,
"Unhide Hidden Datasets":
false,
"Delete Hidden Datasets":
false,
"Purge Deleted Datasets":
false,
"Downloads":
false,
"Export Tool Citations":
false,
"Export History to File":
false,
"Other Actions":
false,
"Import from File":
false,
"Webhooks":
false,
// ---- history-model
// ---- history-view
"This history is empty" :
false,
false,
"No matching datasets found" :
false,
false,
"An error occurred while getting updates from the server" :
false,
false,
"Please contact a Galaxy administrator if the problem persists" :
false,
false,
//TODO:
//"An error was encountered while <% where %>" :
//false,
"Search datasets" :
false,
"search datasets" :
false,
"You are currently viewing a deleted history!" :
false,
false,
"You are over your disk quota" :
false,
false,
"Tool execution is on hold until your disk usage drops below your allocated quota" :
false,
false,
"All" :
false,
false,
"None" :
false,
false,
"For all selected" :
false,
false,
// ---- history-view-edit
"Edit history tags" :
false,
false,
"Edit history Annotation" :
false,
false,
"Click to rename history" :
false,
false,
// multi operations
"Operations on multiple datasets" :
false,
false,
"Hide datasets" :
false,
false,
"Unhide datasets" :
false,
false,
"Delete datasets" :
false,
false,
"Undelete datasets" :
false,
false,
"Permanently delete datasets" :
false,
false,
"This will permanently remove the data in your datasets. Are you sure?" :
false,
false,
// ---- history-view-annotated
"Dataset" :
false,
false,
"Annotation" :
false,
// ---- history-view-edit-current
"This history is empty. Click 'Get Data' on the left tool menu to start" :
false,
"No matching datasets found" :
false,
false,
"You must be logged in to create histories" :
false,
false,
//TODO:
//"You can <% loadYourOwn %> or <% externalSource %>" :
//false,
@@ -85,138 +199,137 @@ false,
// ---------------------------------------------------------------------------- datasets
// ---- hda-model
"Unable to purge dataset" :
false,
false,
// ---- hda-base
// display button
"Cannot display datasets removed from disk" :
false,
false,
"This dataset must finish uploading before it can be viewed" :
false,
false,
"This dataset is not yet viewable" :
false,
false,
"View data" :
false,
false,
// download button
"Download" :
false,
false,
"Download dataset" :
false,
false,
"Additional files" :
false,
false,
// info/show_params
"View details" :
false,
false,
// dataset states
// state: new
"This is a new dataset and not all of its data are available yet" :
false,
false,
// state: noPermission
"You do not have permission to view this dataset" :
false,
false,
// state: discarded
"The job creating this dataset was cancelled before completion" :
false,
false,
// state: queued
"This job is waiting to run" :
false,
false,
// state: upload
"This dataset is currently uploading" :
false,
false,
// state: setting_metadata
"Metadata is being auto-detected" :
false,
false,
// state: running
"This job is currently running" :
false,
false,
// state: paused
"This job is paused. Use the \"Resume Paused Jobs\" in the history menu to resume" :
false,
false,
// state: error
"An error occurred with this dataset" :
false,
false,
// state: empty
"No data" :
false,
false,
// state: failed_metadata
"An error occurred setting the metadata for this dataset" :
false,
false,
// ajax error prefix
"There was an error getting the data for this dataset" :
false,
false,
// purged'd/del'd msg
"This dataset has been deleted and removed from disk" :
false,
false,
"This dataset has been deleted" :
false,
false,
"This dataset has been hidden" :
false,
false,
"format" :
false,
false,
"database" :
false,
false,
// ---- hda-edit
"Edit attributes" :
false,
false,
"Cannot edit attributes of datasets removed from disk" :
false,
false,
"Undelete dataset to edit attributes" :
false,
false,
"This dataset must finish uploading before it can be edited" :
false,
false,
"This dataset is not yet editable" :
false,
false,
"Delete" :
false,
false,
"Dataset is already deleted" :
false,
false,
"View or report this error" :
false,
false,
"Run this job again" :
false,
false,
"Visualize" :
false,
false,
"Visualize in" :
false,
false,
"Undelete it" :
false,
false,
"Permanently remove it from disk" :
false,
false,
"Unhide it" :
false,
false,
"You may be able to" :
false,
false,
"set it manually or retry auto-detection" :
false,
false,
"Edit dataset tags" :
false,
false,
"Edit dataset annotation" :
false,
false,
// ---------------------------------------------------------------------------- misc. MVC
"Tags" :
false,
"Annotation" :
false,
false,
"Edit annotation" :
false,
false,
// ----------------------------------------------------------------------------
},
'ja' : true,
'zh' : true
'ja' : true,
'fr' : true,
'zh' : true
});
+35 -37
View File
@@ -4,9 +4,9 @@ define({
// ---- history-model
// ---- history-view
"This history is empty" :
"历史已空",
"历史已空",
"No matching datasets found" :
"未找到匹配的数据集",
"未找到匹配的数据集",
//"An error occurred while getting updates from the server" :
//false,
//"Please contact a Galaxy administrator if the problem persists" :
@@ -15,19 +15,19 @@ define({
//"An error was encountered while <% where %>" :
//false,
"Search datasets" :
"搜索数据集",
"搜索数据集",
"You are currently viewing a deleted history!" :
"正在查看已删除的历史",
"正在查看已删除的历史",
"You are over your disk quota" :
"您已超过磁盘配额",
"您已超过磁盘配额",
//"Tool execution is on hold until your disk usage drops below your allocated quota" :
//false,
"All" :
"皆",
"皆",
"None" :
"一个也没有",
"一个也没有",
"For all selected" :
"为每个选定",
"为每个选定",
// ---- history-view-edit
//"Edit history tags" :
@@ -35,10 +35,10 @@ define({
//"Edit history Annotation" :
//false,
"Click to rename history" :
"单击要重命名的历史",
"单击要重命名的历史",
// multi operations
"Operations on multiple datasets" :
"编辑多个数据集",
"编辑多个数据集",
//"Hide datasets" :
//false,
//"Unhide datasets" :
@@ -48,23 +48,21 @@ define({
//"Undelete datasets" :
//false,
"Permanently delete datasets" :
"永久删除数据集",
"永久删除数据集",
"This will permanently remove the data in your datasets. Are you sure?" :
"这将永久在你的数据集删除数据。你确定?",
"这将永久在你的数据集删除数据。你确定?",
// ---- history-view-annotated
"Dataset" :
"数据集",
"数据集",
//"Annotation" :
//false,
// ---- history-view-edit-current
"This history is empty. Click 'Get Data' on the left tool menu to start" :
"历史已空,请单击左边窗格中‘获取数据’",
"No matching datasets found" :
"没有发现",
"历史已空,请单击左边窗格中‘获取数据’",
"You must be logged in to create histories" :
"你必须登录后才能创建历史",
"你必须登录后才能创建历史",
//TODO:
//"You can <% loadYourOwn %> or <% externalSource %>" :
//false,
@@ -88,17 +86,17 @@ define({
//"This dataset is not yet viewable" :
//false,
"View data" :
"数据",
"数据",
// download button
"Download" :
"下载",
"下载",
"Download dataset" :
"下载数据集",
"下载数据集",
//"Additional files" :
//false,
// info/show_params
"View details" :
"查看详情",
"查看详情",
// dataset states
// state: new
@@ -112,7 +110,7 @@ define({
//false,
// state: queued
"This job is waiting to run" :
"等待运行的进程",
"等待运行的进程",
// state: upload
//"This dataset is currently uploading" :
//false,
@@ -121,16 +119,16 @@ define({
//false,
// state: running
"This job is currently running" :
"正在运行的进程",
"正在运行的进程",
// state: paused
//"This job is paused. Use the \"Resume Paused Jobs\" in the history menu to resume" :
//false,
// state: error
"An error occurred with this dataset" :
"进程运行时出错",
"进程运行时出错",
// state: empty
"No data" :
"没有数据",
"没有数据",
// state: failed_metadata
//"An error occurred setting the metadata for this dataset" :
//false,
@@ -143,18 +141,18 @@ define({
//"This dataset has been deleted and removed from disk" :
//false,
"This dataset has been deleted" :
"此数据集已被删除",
"此数据集已被删除",
"This dataset has been hidden" :
"此数据集已隐藏",
"此数据集已隐藏",
"format" :
"格式",
"格式",
"database" :
"数据库",
"数据库",
// ---- hda-edit
"Edit attributes" :
"编辑属性",
"编辑属性",
//"Cannot edit attributes of datasets removed from disk" :
//false,
//"Undelete dataset to edit attributes" :
@@ -165,27 +163,27 @@ define({
//false,
"Delete" :
"删除",
"删除",
//"Dataset is already deleted" :
//false,
"View or report this error" :
"报告错误",
"报告错误",
"Run this job again" :
"重新运行",
"重新运行",
"Visualize" :
"图形",
"图形",
//"Visualize in" :
//false,
"Undelete it" :
"反删除",
"反删除",
"Permanently remove it from disk" :
"从磁盘中永久删除",
"从磁盘中永久删除",
"Unhide it" :
"取消隐藏",
"取消隐藏",
//"You may be able to" :
//false,
+7
View File
@@ -221,6 +221,13 @@
}
}
}
span.nametags {
span.label {
display: inline-block;
margin-right: 2px;
text-decoration: none;
}
}
}
}
+5
View File
@@ -68,6 +68,11 @@
font-weight: bold;
}
.ui-tags {
word-wrap: break-word;
padding-right: 25px;
}
.ui-message {
padding: 2px 10px 2px 10px;
margin-top: @ui-margin-vertical-large;
+8 -1
View File
@@ -218,6 +218,7 @@
<datatype extension="mgf" type="galaxy.datatypes.proteomics:Mgf" display_in_upload="true" />
<datatype extension="wiff" type="galaxy.datatypes.proteomics:Wiff" display_in_upload="true" />
<datatype extension="mzxml" type="galaxy.datatypes.proteomics:MzXML" mimetype="application/xml" display_in_upload="true" />
<datatype extension="mzdata" type="galaxy.datatypes.proteomics:MzData" mimetype="application/xml" display_in_upload="true" />
<datatype extension="ms2" type="galaxy.datatypes.proteomics:Ms2" display_in_upload="true" />
<datatype extension="mzq" type="galaxy.datatypes.proteomics:MzQuantML" mimetype="application/xml" display_in_upload="true" />
<datatype extension="mz.sqlite" type="galaxy.datatypes.binary:MzSQlite" mimetype="application/octet-stream" display_in_upload="true" />
@@ -235,6 +236,8 @@
<datatype extension="ct" type="galaxy.datatypes.tabular:ConnectivityTable" display_in_upload="true"/>
<datatype extension="searchgui_archive" type="galaxy.datatypes.binary:SearchGuiArchive" display_in_upload="true"/>
<datatype extension="peptideshaker_archive" type="galaxy.datatypes.binary:CompressedArchive" subclass="true" display_in_upload="true"/>
<datatype extension="percin" type="galaxy.datatypes.tabular:Tabular" subclass="true" />
<datatype extension="percout" type="galaxy.datatypes.xml:GenericXml" subclass="true" />
<!-- End Proteomics Datatypes -->
<datatype extension="netcdf" type="galaxy.datatypes.binary:NetCDF" mimetype="application/octet-stream" display_in_upload="true" description="Format used by netCDF software library for writing and reading chromatography-MS data files." />
<datatype extension="eps" type="galaxy.datatypes.images:Eps" mimetype="image/eps"/>
@@ -479,7 +482,7 @@
<datatype extension="stockholm" type="galaxy.datatypes.msa:Stockholm_1_0" display_in_upload="true" />
<datatype extension="xmfa" type="galaxy.datatypes.msa:MauveXmfa" display_in_upload="true" />
<datatype extension="cel" type="galaxy.datatypes.binary:Cel" display_in_upload="true" />
<datatype extension="RData" type="galaxy.datatypes.binary:RData" display_in_upload="true" description="Stored data from an R session"/>
<datatype extension="rdata" type="galaxy.datatypes.binary:RData" display_in_upload="true" description="Stored data from an R session"/>
<datatype extension="oxlicg" type="galaxy.datatypes.binary:OxliCountGraph" mimetype="application/octet-stream" display_in_upload="true"/>
<datatype extension="oxling" type="galaxy.datatypes.binary:OxliNodeGraph" mimetype="application/octet-stream" display_in_upload="true"/>
<datatype extension="oxlits" type="galaxy.datatypes.binary:OxliTagSet" mimetype="application/octet-stream" display_in_upload="true"/>
@@ -597,6 +600,10 @@
<datatype extension="maskinfo-asn1-binary" type="galaxy.datatypes.binary:GenericAsn1Binary" mimetype="application/octet-stream" subclass="true" display_in_upload="true" />
<datatype extension="pssm-asn1" type="galaxy.datatypes.data:GenericAsn1" mimetype="text/plain" subclass="true" display_in_upload="true" />
<!-- PlantTribes datatypes -->
<datatype extension="ptalign" type="galaxy.datatypes.text:PlantTribesMultipleSequenceAlignment" />
<datatype extension="ptortho" type="galaxy.datatypes.text:PlantTribesOrtho" />
<datatype extension="ptorthocs" type="galaxy.datatypes.text:PlantTribesOrthoCodingSequence" />
<datatype extension="pttree" type="galaxy.datatypes.text:PlantTribesPhylogeneticTree" />
<datatype extension="smat" type="galaxy.datatypes.text:Smat" display_in_upload="true" />
</registration>
<sniffers>
+22 -18
View File
@@ -1,28 +1,32 @@
<dependency_resolvers>
<!-- the default configuration, first look for dependencies installed from the toolshed -->
<!-- the default configuration, first look for dependencies installed from the toolshed -->
<tool_shed_packages />
<!-- then look for env.sh files in directories according to the "galaxy packages" schema.
These resolvers can take a base_path attribute to specify where to look for
package definitions, but by default look in the directory specified by tool_dependency_dir
in Galaxy's config/galaxy.ini -->
<!-- then look for env.sh files in directories according to the "galaxy packages" schema.
These resolvers can take a base_path attribute to specify where to look for
package definitions, but by default look in the directory specified by tool_dependency_dir
in Galaxy's config/galaxy.ini -->
<galaxy_packages />
<galaxy_packages versionless="true" />
<!-- check whether the correct version has been installed via conda -->
<conda />
<!-- look for a "default" symlink pointing to a directory containing an
env.sh file for the package in the "galaxy packages" schema -->
<galaxy_packages versionless="true" />
<!-- look for any version of the dependency installed via conda -->
<conda versionless="true" />
<!-- Example configuration of modules dependency resolver, uses Environment Modules -->
<!--
<!-- Example configuration of modules dependency resolver, uses Environment Modules -->
<!--
<modules modulecmd="/opt/Modules/3.2.9/bin/modulecmd" />
<modules modulecmd="/opt/Modules/3.2.9/bin/modulecmd" versionless="true" default_indicator="default" />
Attributes are:
* modulecmd - path to modulecmd
* versionless - default: false - whether to resolve tools using a version number or not
* find_by - directory or avail - use the DirectoryModuleChecker or AvailModuleChecker
* prefetch - default: true - in the AvailModuleChecker prefetch module info with 'module avail'
* default_indicator - default: '(default)' - what indicate to the AvailModuleChecker that a module is the default version
-->
<!-- other resolvers
Attributes are:
* modulecmd - path to modulecmd
* versionless - default: false - whether to resolve tools using a version number or not
* find_by - directory or avail - use the DirectoryModuleChecker or AvailModuleChecker
* prefetch - default: true - in the AvailModuleChecker prefetch module info with 'module avail'
* default_indicator - default: '(default)' - what indicate to the AvailModuleChecker that a module is the default version
-->
<!-- other resolvers
<tool_shed_tap />
<homebrew />
-->
</dependency_resolvers>
-->
</dependency_resolvers>
+16 -1
View File
@@ -355,6 +355,21 @@ paste.app_factory = galaxy.web.buildapp:app_factory
# separated list.
#interactive_environment_plugins_directory =
# To run interactive environment containers in Docker Swarm mode (on an
# existing swarm), set this option to True and set `docker_connect_port` in the
# IE plugin config (ini) file(s) of any IE plugins you have enabled and ensure
# that you are not using any `docker run`-specific options in your plugins'
# `command_inject` options (swarm mode services run using `docker service
# create`, which has a different and more limited set of options). This option
# can be overridden on a per-plugin basis by using the `swarm_mode` option in
# the plugin's ini config file.
#interactive_environment_swarm_mode = False
# Galaxy can run a "swarm manager" service that will monitor utilization of the
# swarm and provision/deprovision worker nodes as necessary. The service has
# its own configuration file.
#swarm_manager_config_file = config/swarm_manager_conf.yml
# Interactive tour directory: where to store interactive tour definition files.
# Galaxy ships with several basic interface tours enabled, though a different
# directory with custom tours can be specified here. The path is relative to the
@@ -1191,7 +1206,7 @@ use_interactive = True
# walltime limits but did fail quickly (either while queueing or running). The
# commented out default below results in no default job resubmission condition,
# failing jobs are just failed outright.
#default_job_resubmission_condition =
#default_job_resubmission_condition =
# In multiprocess configurations, notification between processes about new jobs
# must be done via the database. In single process configurations, this can be
@@ -41,3 +41,15 @@ image = qiaoy/iobio-bundle.bam-iobio:1.0-ondemand
# share data between the IE and Galaxy.
#docker_galaxy_temp_dir = None
# If your Docker container exposes more then one port, Galaxy needs to know to
# which ports it needs to connect. With this option you can specify the port number
# inside your container to which Galaxy should connect the UI.
#docker_connect_port = None
# To run containers in Docker Swarm mode on (an existing swarm), set the
# following option to True *and*:
# - set docker_connect_port above. For qiaoy/iobio-bundle.bam-iobio the port
# should most likely be 8000.
# - If command_inject is uncommented and includes `--sig-proxy`, that option should
# be removed.
#swarm_mode = False
@@ -22,12 +22,10 @@ function message_failed_connection(){
*
*/
function load_notebook(notebook_access_url){
$( document ).ready(function() {
// Test notebook_login_url for accessibility, executing the login+load function whenever
// we've successfully connected to the IE.
test_ie_availability(notebook_access_url, function(){
_handle_notebook_loading(notebook_access_url);
});
// Test notebook_login_url for accessibility, executing the login+load function whenever
// we've successfully connected to the IE.
test_ie_availability(notebook_access_url, function(){
_handle_notebook_loading(notebook_access_url);
});
}
@@ -46,7 +46,9 @@ root = h.url_for( '/' )
var startup = function(){
// Load notebook
requirejs(['interactive_environments', 'plugin/bam_iobio'], function(){
load_notebook(notebook_access_url);
load_when_ready(ie_readiness_url, function(){
load_notebook(notebook_access_url);
});
});
};
@@ -9,6 +9,7 @@ ie_password = '${ ie_request.notebook_pw }';
var galaxy_root = '${ ie_request.attr.root }';
var app_root = '${ ie_request.attr.app_root }';
var ie_readiness_url = '${ ie_request.url_template("${PROXY_PREFIX}/interactive_environments/ready") }';
</%def>
@@ -0,0 +1,44 @@
[main]
# Unused
[docker]
# Command to launch docker container. For example `sudo docker` or `docker-lxc`.
# If you need to use a command like `sg` you can do that here, just be sure to
# wrap all of the docker portion in single quotes. E.g. `sg 'docker' 'docker {docker_args}'`
#
# It is recommended that you use command_inject if you need to inject
# additional parameters. This command string is re-used for a `docker inspect`
# command and will likely cause errors if it is extensively modified, past the
# usual group/sudo changes.
#command = docker {docker_args}
# The docker image name that should be started.
image = shiltemann/ethercalc-galaxy-ie:17.05
# Additional arguments that are passed to the `docker run` command.
#command_inject = --sig-proxy=true -e DEBUG=false
# URL to access the Galaxy API with from the spawn Docker containter, if empty
# this falls back to galaxy.ini's galaxy_infrastructure_url and finally to the
# Docker host of the spawned container if that is also not set.
#galaxy_url =
# The Docker hostname. It can be useful to run the Docker daemon on a different
# host than Galaxy.
#docker_hostname = localhost
# Try to set the tempdirectory to world execute - this can fix the issue
# where 'sudo docker' is not able to mount the folder otherwise.
# "finalize namespace chdir to /import permission denied"
#wx_tempdir = False
# Overwride the IE tempdirectory. This can be useful if you regular tempdir is
# located on an NFS share, which does not work well as Docker volume. In this case
# you can have a shared sshfs share which you can use as temporary directory to
# share data between the IE and Galaxy.
#docker_galaxy_temp_dir = None
# If your Docker container exposes more then one port, Galaxy needs to know to
# which ports it needs to connect. With this option you can specify the port number
# inside your container to which Galaxy should connect the UI.
docker_connect_port = 80
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE interactive_environment SYSTEM "../../interactive_environments.dtd">
<interactive_environment name="Ethercalc">
<data_sources>
<data_source>
<model_class>HistoryDatasetAssociation</model_class>
<test type="isinstance" test_attr="datatype" result_type="datatype">tabular.Tabular</test>
<test type="isinstance" test_attr="datatype" result_type="datatype">tabular.CSV</test>
<to_param param_attr="id">dataset_id</to_param>
</data_source>
</data_sources>
<params>
<param type="dataset" var_name_in_template="hda" required="true">dataset_id</param>
</params>
<entry_point entry_point_type="mako">ethercalc.mako</entry_point>
</interactive_environment>
@@ -0,0 +1,43 @@
function load_notebook(url){
$( document ).ready(function() {
test_ie_availability(url, function(){
append_notebook(url)
});
});
}
function keep_alive(notebook_access_url){
/**
* This is needed to keep the container alive. If the user leaves this site
* this function is not constantly pinging the container, the container will
* terminate itself.
*/
var request_count = 0;
interval = setInterval(function(){
$.ajax({
url: notebook_access_url,
xhrFields: {
withCredentials: true
},
type: "GET",
timeout: 500,
success: function(){
console.log("Connected to IE, returning");
},
error: function(jqxhr, status, error){
request_count++;
console.log("Request " + request_count);
if(request_count > 30){
clearInterval(interval);
clear_main_area();
toastr.error(
"Could not connect to IE, contact your administrator",
"Error",
{'closeButton': true, 'timeOut': 20000, 'tapToDismiss': false}
);
}
}
});
}, 10000);
}
@@ -0,0 +1,40 @@
<%namespace name="ie" file="ie.mako" />
<%
# Sets ID and sets up a lot of other variables
ie_request.load_deploy_config()
# Launch the IE. This builds and runs the docker command in the background.
ie_request.launch(
env_override={
'dataset_hid': hda.hid
}
)
# Only once the container is launched can we template our URLs. The ie_request
# doesn't have all of the information needed until the container is running.
url = ie_request.url_template('${PROXY_URL}/ethercalc/')
%>
<html>
<head>
${ ie.load_default_js() }
</head>
<body>
<script type="text/javascript">
${ ie.default_javascript_variables() }
var url = '${ url }';
${ ie.plugin_require_config() }
// Keep container running
requirejs(['interactive_environments', 'plugin/ethercalc'], function(){
keep_alive(url);
});
requirejs(['interactive_environments', 'plugin/ethercalc'], function(){
load_notebook(url);
});
</script>
<div id="main" width="100%" height="100%">
</div>
</body>
</html>
@@ -6,7 +6,7 @@
# appropriate `apt-get/pip install` statements.
---
-
image: bgruening/docker-jupyter-notebook:16.01
image: bgruening/docker-jupyter-notebook:16.01.1
description: |
The Jupyter notebook is the next iteration of IPython, allowing
analysis in many different languages. This image features the Python,
@@ -18,7 +18,7 @@
# The image argument was moved to "allowed_images.yml.sample"
# Additional arguments that are passed to the `docker run` command.
command_inject = --sig-proxy=true -e DEBUG=false -e DEFAULT_CONTAINER_RUNTIME=120
#command_inject = --sig-proxy=true -e DEBUG=false -e DEFAULT_CONTAINER_RUNTIME=120
# URL to access the Galaxy API with from the spawn Docker containter, if empty
# this falls back to galaxy.ini's galaxy_infrastructure_url and finally to the
@@ -43,4 +43,12 @@ command_inject = --sig-proxy=true -e DEBUG=false -e DEFAULT_CONTAINER_RUNTIME=12
# If your Docker container exposes more then one port, Galaxy needs to know to
# which ports it needs to connect. With this option you can specify the port number
# inside your container to which Galaxy should connect the UI.
# docker_connect_port = None
#docker_connect_port = None
# To run containers in Docker Swarm mode on (an existing swarm), set the
# following option to True *and*:
# - set docker_connect_port above. For Jupyter the # port should most likely be
# 8888.
# - If command_inject is uncommented and includes `--sig-proxy`, that option should
# be removed.
#swarm_mode = False
@@ -34,12 +34,10 @@ function message_no_auth(){
*
*/
function load_notebook(password, notebook_login_url, notebook_access_url){
$( document ).ready(function() {
// Test notebook_login_url for accessibility, executing the login+load function whenever
// we've successfully connected to the IE.
test_ie_availability(notebook_login_url, function(){
_handle_notebook_loading(password, notebook_login_url, notebook_access_url);
});
// Test notebook_login_url for accessibility, executing the login+load function whenever
// we've successfully connected to the IE.
test_ie_availability(notebook_login_url, function(){
_handle_notebook_loading(password, notebook_login_url, notebook_access_url);
});
}
@@ -60,7 +60,9 @@ requirejs(['interactive_environments', 'plugin/jupyter'], function(){
// Load notebook
requirejs(['interactive_environments', 'plugin/jupyter'], function(){
load_notebook(ie_password, notebook_login_url, notebook_access_url);
load_when_ready(ie_readiness_url, function(){
load_notebook(ie_password, notebook_login_url, notebook_access_url);
});
});
@@ -40,3 +40,16 @@ command_inject = --sig-proxy=true -e DEBUG=false -e DEFAULT_CONTAINER_RUNTIME=12
# you can have a shared sshfs share which you can use as temporary directory to
# share data between the IE and Galaxy.
#docker_galaxy_temp_dir = None
# If your Docker container exposes more then one port, Galaxy needs to know to
# which ports it needs to connect. With this option you can specify the port number
# inside your container to which Galaxy should connect the UI.
#docker_connect_port = None
# To run containers in Docker Swarm mode on (an existing swarm), set the
# following option to True *and*:
# - set docker_connect_port above. For thoba/neo4j_galaxy_ie the port
# should most likely be 7474.
# - If command_inject is uncommented and includes `--sig-proxy`, that option should
# be removed.
#swarm_mode = False
@@ -1,12 +1,9 @@
// Load an interactive environment (IE) from a remote URL
// @param {String} notebook_access_url: the URL embeded in the page and loaded
function load_notebook(notebook_access_url){
// When the page has completely loaded...
$( document ).ready(function() {
// Test if we can access the GIE, and if so, execute the function
// to load the GIE for the user.
test_ie_availability(notebook_access_url, function(){
append_notebook(notebook_access_url);
});
// Test if we can access the GIE, and if so, execute the function
// to load the GIE for the user.
test_ie_availability(notebook_access_url, function(){
append_notebook(notebook_access_url);
});
}
@@ -33,7 +33,9 @@
requirejs(['interactive_environments', 'plugin/neo'], function () {
load_notebook(url);
load_when_ready(ie_readiness_url, function(){
load_notebook(url);
});
});
</script>
@@ -19,3 +19,16 @@ image = shiltemann/docker-phinch-galaxy:16.04
# The Docker hostname. It can be useful to run the Docker daemon on a different
# host than Galaxy.
#docker_hostname = localhost
# If your Docker container exposes more then one port, Galaxy needs to know to
# which ports it needs to connect. With this option you can specify the port number
# inside your container to which Galaxy should connect the UI.
#docker_connect_port = None
# To run containers in Docker Swarm mode on (an existing swarm), set the
# following option to True *and*:
# - set docker_connect_port above. For shiltemann/docker-phinch-galaxy the port
# should most likely be 80.
# - If command_inject is uncommented and includes `--sig-proxy`, that option should
# be removed.
#swarm_mode = False
@@ -1,8 +1,6 @@
function load_notebook(url){
$( document ).ready(function() {
test_ie_availability(url, function(){
append_notebook(url)
});
test_ie_availability(url, function(){
append_notebook(url)
});
}
@@ -36,7 +36,9 @@ requirejs(['interactive_environments', 'plugin/phinch'], function(){
// Load notebook
requirejs(['interactive_environments', 'plugin/phinch'], function(){
load_notebook(url);
load_when_ready(ie_readiness_url, function(){
load_notebook(url);
});
});
</script>
@@ -41,3 +41,16 @@ password_auth = True
# you can have a shared sshfs share which you can use as temporary directory to
# share data between the IE and Galaxy.
#docker_galaxy_temp_dir = None
# If your Docker container exposes more then one port, Galaxy needs to know to
# which ports it needs to connect. With this option you can specify the port number
# inside your container to which Galaxy should connect the UI.
#docker_connect_port = None
# To run containers in Docker Swarm mode on (an existing swarm), set the
# following option to True *and*:
# - set docker_connect_port above. For erasche/docker-rstudio-notebook the port
# should most likely be 80.
# - If command_inject is uncommented and includes `--sig-proxy`, that option should
# be removed.
#swarm_mode = False
@@ -15,58 +15,56 @@ function message_failed_connection(){
*
*/
function load_notebook(notebook_login_url, notebook_access_url, notebook_pubkey_url, username){
$( document ).ready(function() {
// Test notebook_login_url for accessibility, executing the login+load function whenever
// we've successfully connected to the IE.
test_ie_availability(notebook_pubkey_url, function(){
var payload = username + "\n" + ie_password;
$.ajax({
type: 'GET',
url: notebook_pubkey_url,
xhrFields: {
// Test notebook_login_url for accessibility, executing the login+load function whenever
// we've successfully connected to the IE.
test_ie_availability(notebook_pubkey_url, function(){
var payload = username + "\n" + ie_password;
$.ajax({
type: 'GET',
url: notebook_pubkey_url,
xhrFields: {
withCredentials: true
},
success: function(response_text){
var chunks = response_text.split(':', 2);
var exp = chunks[0];
var mod = chunks[1];
console.log("Found " + exp +" and " + mod);
var rsa = new RSAKey();
rsa.setPublic(mod, exp);
console.log("Encrypting '" + username + "', '" + ie_password + "'");
var enc_hex = rsa.encrypt(payload);
var encrypted = hex2b64(enc_hex);
console.log("E: " + encrypted);
// Now we can login
$.ajax({
type: "POST",
// to the Login URL
url: notebook_login_url,
// With our password
data: {
'v': encrypted,
'persist': 1,
'clientPath': '/rstudio/auth-sign-in',
'appUri': '',
},
contentType: "application/x-www-form-urlencoded",
xhrFields: {
withCredentials: true
},
success: function(response_text){
var chunks = response_text.split(':', 2);
var exp = chunks[0];
var mod = chunks[1];
console.log("Found " + exp +" and " + mod);
var rsa = new RSAKey();
rsa.setPublic(mod, exp);
console.log("Encrypting '" + username + "', '" + ie_password + "'");
var enc_hex = rsa.encrypt(payload);
var encrypted = hex2b64(enc_hex);
console.log("E: " + encrypted);
// Now we can login
$.ajax({
type: "POST",
// to the Login URL
url: notebook_login_url,
// With our password
data: {
'v': encrypted,
'persist': 1,
'clientPath': '/rstudio/auth-sign-in',
'appUri': '',
},
contentType: "application/x-www-form-urlencoded",
xhrFields: {
withCredentials: true
},
// If that is successful, load the notebook
success: function(){
append_notebook(notebook_access_url);
},
error: function(jqxhr, status, error){
message_failed_connection();
// Do we want to try and load the notebook anyway? Just in case?
append_notebook(notebook_access_url);
}
});
}
});
},
// If that is successful, load the notebook
success: function(){
append_notebook(notebook_access_url);
},
error: function(jqxhr, status, error){
message_failed_connection();
// Do we want to try and load the notebook anyway? Just in case?
append_notebook(notebook_access_url);
}
});
}
});
});
}
@@ -64,7 +64,9 @@ requirejs([
'crypto/base64',
'plugin/rstudio'
], function(){
load_notebook(notebook_login_url, notebook_access_url, notebook_pubkey_url, "${ USERNAME }");
load_when_ready(ie_readiness_url, function(){
load_notebook(notebook_login_url, notebook_access_url, notebook_pubkey_url, "${ USERNAME }");
});
});
</script>
<div id="main">
@@ -65,7 +65,6 @@ define( [], function() {
{ label : 'Incomers', value : 'incomers' },
{ label : 'Roots', value : 'roots' },
{ label : 'Leaves', value : 'leaves' },
{ label : 'None', value : '' } ]
},
choose_red : {
@@ -0,0 +1,22 @@
name: searchover
type:
- masthead
activate: true
icon: fa-search
tooltip: Click to activate search and press Ctrl + Alt + q to open the overlay
function: >
$.getJSON("/api/webhooks", function( data ) {
for( var item in data ) {
var webhook = data[item];
if( webhook.name === "searchover" ) {
if( webhook.script && !window.static_search ) {
$( '<script/>', { type: 'text/javascript' } ).text( webhook.script ).appendTo( 'head' );
$( '<style/>', { type: 'text/css' } ).text( webhook.styles ).appendTo( 'head' );
window.static_search = true;
}
break;
}
}
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,177 @@
.overlay-wrapper {
margin-top: -5%;
}
.search-screen {
position: fixed;
z-index: 202;
width:100%;
height:100%;
display:none;
}
.search-screen-overlay {
position: fixed;
top:0;
left:0;
background: rgba(224, 224, 224, 0.75);
z-index: 201;
width:100%;
height:100%;
display:none;
opacity: 2;
}
.overlay-filters {
display: table;
margin: 0 auto 5px;
}
.overlay-filters ul {
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
}
.overlay-filters li {
float: left;
}
.overlay-filters li a {
display: block;
text-decoration: none;
cursor: pointer;
font-weight: bold;
padding: 5px 5px;
}
.overlay-filters li a:hover i {
color: #212121;
}
.overlay-filters li a i {
font-size: 1.5em;
}
.search-header {
background-color: #e1e1e1;
background: -moz-linear-gradient(top, rgba(225, 225, 225, 1) 0%, rgba(238, 238, 238, 1) 37%, rgba(225, 225, 225, 1) 100%);
background: linear-gradient(to bottom, rgba(225, 225, 225, 1) 0%, rgba(238, 238, 238, 1) 37%, rgba(225, 225, 225, 1) 100%);
-moz-box-shadow: 0px 2px 5px 0px rgba(158, 158, 158, 0.75);
box-shadow: 0px 2px 5px 0px rgba(158, 158, 158, 0.75);
position: fixed;
top: 34px;
width: 100%;
z-index: 203;
}
.txtbx-search-data {
font-size: 12px;
text-align: center;
border-radius: 14px;
border: 1px solid #2c3143;
margin: 20px auto 10px;
width: 300px;
padding: 11px;
}
.search-section {
color: #007AB5;
margin-top: 20px;
font-weight: bold;
}
.search-section .section-title {
margin-left: 7px;
}
.link-tile {
background-color: #0070A8;
border: 1px solid #005A85;
border-radius: 5px;
font-size: 12px;
width: 19%;
height: 75px;
margin: 0.5%;
padding: 5px;
}
.link-tile.btn-primary:hover,
.link-tile.btn-primary:hover {
background-color: #005A85;
border-color: #005A85;
}
.link-tile.btn-primary:active,
.link-tile.btn-primary:focus {
background-color: #005A85;
border-color: #005A85;
}
.search-results,
.removed-items {
position: fixed;
top: 125px;
overflow-x: hidden;
overflow-y: auto;
padding: 0 15px;
width: 100%;
height: 83%;
display: none;
}
.item-actions {
padding: 5px;
}
.item-actions:hover {
color: gold;
}
.pin-item {
float: left;
}
.restore-item,
.remove-fav,
.remove-item {
float: right;
}
.filter-active i {
/*color: gold;*/
color: #616161;
}
.filter-active i:hover {
color: #212121;
}
.filter-inactive i {
font-size: 0.875em;
color: #9e9e9e;
}
.rotate {
transform: rotate(90deg);
}
.pinned-item {
color: gold;
transform: rotate(60deg);
}
.hide {
display: none;
}
.show {
display: block;
}
.no-results {
color: white;
margin-top: 0.8%;
}
@@ -0,0 +1,38 @@
name: tool_list
type:
- masthead
activate: true
icon: fa-list
tooltip: Generate tool list
function: >
setTimeout(function() {
alert('The tool file will be created and opened in a new window. Please ' +
'be patient, this might take a moment.');
}, 1);
$.getJSON("/api/webhooks/tool_list/get_data", function(data) {
var popup = window.open('tool_list.html');
var html = '<!DOCTYPE html><body><h2>' +
'Create a Docker flavour of this instance:</h2>' +
'<table style="width:100%"><tr><td width="50%">The textarea on ' +
'the right shows the list of installed tools on this Galaxy instance.' +
'You can use it to build a custom Galaxy flavour based on the same ' +
'tools. Keep in mind that this list only contains tools which can be ' +
'installed from a toolshed. <br><br> 1. Save this list as a <i>.yaml</i> ' +
'file and edit it according to your needs. You might want to add or ' +
'remove tools.<br>2. Follow ' +
'<a href="https://github.com/bgruening/docker-galaxy-stable' +
'#Extending-the-Docker-Image">this guide</a> on how to create a new ' +
'Galaxy Docker flavour. Dont forget to add and install the tool list ' +
'with <br><br><b>ADD my_tool_list.yml $GALAXY_ROOT/my_tool_list.yml' +
'</b> <br><br> and <br><br><b>' +
'RUN install-tools $GALAXY_ROOT/my_tool_list.yml</b></td>' +
'<td width="50%"><textarea rows="30" cols="78">' +
data.yaml +
'</textarea></td></tr></table></body>';
popup.document.write(html);
});
@@ -0,0 +1,39 @@
import yaml
def main(trans, webhook):
data = {}
data['tools'] = []
unique_tools = []
tools = trans.app.toolbox.tools()
for tool in tools:
try:
ts_data = tool[1].tool_shed_repository.to_dict()
panel = tool[1].get_panel_section()
except AttributeError:
continue
if (ts_data['name'] + ts_data['installed_changeset_revision'] not in
unique_tools):
unique_tools.append(
ts_data['name'] + ts_data['installed_changeset_revision']
)
data['tools'].append({
'name': ts_data['name'],
'owner': ts_data['owner'],
'tool_panel_section_label': panel[1],
'tool_shed_url': ts_data['tool_shed'],
'install_tool_dependencies': True,
'install_repository_dependencies': True,
'install_resolver_dependencies': True,
'revisions': [ts_data['installed_changeset_revision']]
})
if panel[0]:
data['tools'][-1]['tool_panel_section_id'] = panel[0]
return {'yaml': yaml.safe_dump(data, default_flow_style=False)}
+84
View File
@@ -0,0 +1,84 @@
---
# Galaxy docker swarm manager configuration file
#
# To configure the location of this file, use the `swarm_manager_config_file`
# setting in galaxy.ini
# When the swarm manager daemonizes, it writes a pid file so that only one
# manager will run at a time. This is the path to that pid file.
# {xdg_data_home} will be templated automatically and defaults to
# ~/.local/share as per the XDG specification
#pid_file: '{xdg_data_home}/galaxy_swarm_manager.pid'
# Program output will be written to the log
#log_file: '{xdg_data_home}/galaxy_swarm_manager.log'
# As with GIE plugins, you can modify the base docker command ({docker_args}
# must be present and will be filled in with the docker subcommand and
# arguments)
#command: 'docker {docker_args}'
# Managed services should be started with this string at the beginning of their
# name. It should match the value of CONTAINER_NAME_PREFIX in
# lib/galaxy/web/base/interactive_environments.py, so you should not change
# this unless you change both.
#service_prefix: galaxy_gie_
# Limits:
#
# - max_waiting_services: number of services that should be waiting of each
# "CPU class" (number of CPUs requested e.g. with --reserve-cpu) before
# attempting to spawn a node
# - max_wait_time: number of seconds a service should be waiting before
# attempting to spawn a node
# - max_node_idle_time: number of seconds a node should be idle before
# terminating it
# - max_node_counts: a dictionary controlling the maximum number of nodes of
# each CPU class that the swarm manager will attempt to spawn, e.g.:
# max_node_counts:
# 1: 10 # spawn up to 10 x 1-CPU nodes
# 2: 3 # spawn up to 3 x 2-CPU nodes
# 4: 1 # spawn up to 1 x 4-CPU nodes
#max_waiting_services: 0
#max_wait_time: 5
#max_node_idle_time: 120
#max_node_counts: {}
# If set, only manage nodes whose swarm hostnames begin with this prefix.
# Otherwise, attempt to manage all nodes
#node_prefix: null
# Amount of time to wait for a spawning node to appear in `docker node ls`
# before considering it failed
#spawn_wait_time: 30
# Command to run to spawn new nodes. This command should join the node to the
# swarm. Can include template variables:
# - {cpu_class}: CPU class as explained above (the value of --reserve-cpu)
# - {cpus_needed}: Total number of CPUs of the given class needed to run the
# waiting services
# If this command does not block until the node is joined to the swarm, make
# sure it at least completes that step in `spawn_wait_time` once it returns
# control. This command should return a space-separated list of nodes. If the
# nodes have a different number of CPUs than the class that they were started
# for, you can include that number after a colon (e.g. `node1:4`).
#spawn_command: /bin/true
# Command to run to destroy idle nodes. Can include template variables:
# - {nodes}: Space-separated list of node names to destroy
# This command should block until at least the point at which any nodes being
# deallocated no longer appear in `docker node ls`.
#destroy_command: /bin/true
# Command to run if either of the above commands failed (e.g. to notify an
# administrator). Can include template variables:
# - {failed_command}: Command line of the command that failed
#command_failure_command: /bin/true
# Number of times to retry spawn/destroy commands before considering them to
# have failed, and seconds to wait between retries
#command_retries: 0
#command_retry_wait: 10
# Stop the swarm manager daemon when there are no services or nodes to manage
#terminate_when_idle: True
+210
View File
@@ -0,0 +1,210 @@
# Authentication
Galaxy supports the following authentication mechanisms:
* [Galaxy Database](#galaxy-database) - Galaxy-specific login using e-mail address and password (the default)
* [Authentication Framework](#authentication-framework) - A plugin-driven framework supporting LDAP/Active Directory and PAM.
* [OpenID](#openid) - authentication with Galaxy as a relying party
* [Proxy Authentication](#proxy_authentication) - HTTP [remote user](http://httpd.apache.org/docs/current/mod/mod_cgi.html#env) provided by any front-end Web server
## Galaxy Database
Without any additional configuration Galaxy will simply use its database to maintain usernames and passwords. The
Galaxy user interface and API provide functions allowing users to register accounts, change passwords, etc....
If deploying Galaxy using the default authentication option, user activation can be enabled also. This is documented
[below](#user-activation).
## Authentication Framework
Galaxy is distributed with a plugin-driven authentication framework for which the default database authentication is
just one (and the default plugin). This framework can be used to allow Galaxy to delegate authentication to
an LDAP server, an Active Directory server, or to PAM.
These same mechanisms can also be configured by proxies serving Galaxy (e.g. nginx or Apache), but configuring them
within Galaxy allows users to use the Galaxy UI for logging in instead of relying on a proxy.
To configure one or more authentication plugins, simply copy ``config/auth_conf.xml.sample`` to ``config/auth_conf.xml``.
The provided sample configuration file has numerous commented out examples and serves as the most up-to-date source
of documentation on configuring these plugins.
## OpenID
[OpenID](https://en.wikipedia.org/wiki/OpenID) is becoming less popular and probably shouldn't be used the primary mechanism
for authentication in Galaxy but it is an available option.
Enabling OpenID requires you to edit Galaxy's configuration file and set `enable_openid` to `True`. This file is
likely located in `config/galaxy.ini` and can be created by copying Galaxy's sample `config/galaxy.ini.sample`.
Enabling this option enables OpenID and causes the OpenID form to be displayed on the login screen.
## Remote User Authentication
If Galaxy is deployed with either nginx or Apache serving as a front-end proxy for Galaxy requests, they can be configured
to authenticate users and pass this authentication information along to Galaxy using the HTTP remote user mechanism. See, for
example, the [authentication and authorization guide for the Apache Web server](http://httpd.apache.org/docs/2.4/howto/auth.html)
for an impression of the possibilities. Thus, by the time Galaxy is aware of a request, the user identity will have been determined
and there will be no need for Galaxy to do any additional authentication work, such as showing a login screen or checking user
credentials.
However, accepting an identity asserted by the Web server does not relieve Galaxy from having to create a user account for
such an identity. Thus, Galaxy automatically creates a user for each identity of this kind, recording that the user is
"external" and also creating a random password in order to effectively disable traditionally performed logins for the user,
although the remote user mechanism should normally prohibit any login mechanism other than that imposed by the Web server,
and the "external" flag should itself prohibit the traditional mechanism being used with the user concerned. When a remote
user returns to Galaxy and is not already logged in, the details of the user are retrieved according to the identity
information supplied by the Web server.
Enabling remote user authentication requires you to edit Galaxy's configuration file and set `use_remote_user` to `True`.
This file is likely located in `config/galaxy.ini` and can be created by copying Galaxy's sample `config/galaxy.ini.sample`.
Additional Galaxy configuration options related to remote user authentication are documented in Galaxy's sample
configuration file. The options ``remote_user_maildomain``, ``remote_user_header``, and ``normalize_remote_user_email`` can
adapt Galaxy to different responses from the proxy, while ``remote_user_secret`` can be used to provide added
security, and ``remote_user_logout_href`` can be used to fix Galaxy's logout for the deployed setup.
## User Activation
Galaxy admins using the default authentication mechanism have an option to turn on the email verification feature
to force users to provide working email during the registration. You can also turn on the disposable email domains
filter to disable registration for users using known disposable email provider.
How to set up this config is presented here.
*Note: SQLite database is not supported with this feature. Please use PostgreSQL.*
### Account activation feature
In the Galaxy config file **config/galaxy.ini** there is the user activation setting that you have to turn on.
```
user_activation_on = True
```
There is also the option for tracking jobs in database that is required to be turned on for the account activation to be effective. By default it is off.
```
track_jobs_in_database = True
```
After you turn on both of these every user that will try to register after this configuration file takes effect will have the verification email sent to the email address provided. Unless the Grace period (see below) is set, the user won't be able to login before the verification happens.
Furthermore in order for this to work correctly smtp server and admin email should be set:
```
#smtp_server = some.server.edu:587
#smtp_username = example_username
#smtp_password = example_passsword
#activation_email = activation-noreply@example.com
#error_email_to = admin@example.com
```
Smtp server takes care of the email sending and the activation_email email is used as the *From* address in the verification email. Furthermore the error_email_to is being shown to the user if the Galaxy detects its own misconfiguration.
You can also set the instance_resource_url which is shown in the activation emails so you can point users to your wiki or other materials.
```
instance_resource_url = http://wiki.galaxyproject.org/
```
The final activation email looks like this:
```
Hello <user_name>,
In order to complete the activation process for <user_email> begun on <date> at <hostname>, please click on the following link to verify your account:
test.galaxyproject.org/activate?activation_token=46701ecdbbf2a79a7348ddae33062774edadef59&email=example%40example.com
By clicking on the above link and opening a Galaxy account you are also confirming that you have read and agreed to Galaxy's Terms and Conditions for use of this service (<link_to_terms_config>). This includes a quota limit of one account per user. Attempts to subvert this limit by creating multiple accounts or through any other method may result in termination of all associated accounts and data.
Please contact us if you need help with your account at: <error_email_to_config>. You can also browse resources available at: <instance_resources_url_config>.
More about the Galaxy Project can be found at galaxyproject.org
Your Galaxy Team
```
### Changing email address
If an activated user changes email address in user settings, his/her account will be deactivated. A new activation link will be sent and the user will have to visit it to activate the account again.
### Grace period
In case you want the account activation feature but don't want to disable login completely you can set the **activation_grace_period** parameter. It specifies, in hours, the period in between registration time and the login time that the user will be allowed to log in even with an inactive account.
```
# Activation grace period. Activation is not forced (login is not disabled) until
# grace period has passed. Users under grace period can't run jobs (see inactivity_box_content).
# In hours. Default is 3. Enter 0 to disable grace period.
# Users with OpenID logins have grace period forever.
#activation_grace_period = 3
```
However with inactive account the user won't be able to run jobs and warning message will be shown to him at the top of the page. It is customizable via the **inactivity_box_content** parameter.
```
# Used for warning box for inactive accounts (unable to run jobs).
# In use only if activation_grace_period is set.
#inactivity_box_content = Your account has not been activated yet. Please activate your account by verifying your email address. For now you can access everything at Galaxy but your jobs won't run.
```
### Disposable email address filtering
<a name="disposable_email_filter"></a>
To prevent users from using disposable email addresses as a workaround for the email verification the domain blacklist can be turned on through the **blacklist_file** path parameter. Users that use disposable email domains defined at the file in this provided path will be refused registration.
```
# E-mail domains blacklist is used for filtering out users that are using disposable email address
# during the registration. If their address domain matches any domain in the BL they are refused the registration.
blacklist_file = config/disposable_email_blacklist.conf
```
Disposable domains blacklist file for download and modification is [at GitHub](https://github.com/martenson/disposable-email-domains/blob/master/disposable_email_blacklist.conf)
In the file each domain is on its own line and without the *@* sign. Example of the blacklist file format:
```
drdrb.com
mailinator.com
sogetthis.com
spamgourmet.com
trashmail.net
kurzepost.de
objectmail.com
proxymail.eu
rcpt.at
trash-mail.at
trashmail.at
trashmail.me
wegwerfmail.de
wegwerfmail.net
wegwerfmail.org
```
## Authentication Related Code
The `lib/galaxy/webapps/galaxy/controllers/user.py` file provides much of the authentication-related logic in the `User` class. Of the supported mechanisms, only those needing to perform actual authentication work require any substantial amount of code in this file; the integration of "remote user" information is performed in the `lib/galaxy/web/framework/__init__.py` file.
Within the `User` class, code supporting authentication mechanisms will need to provide the following things:
* Support within the `login` method for any additional information shown in the login screen. Since the login screen is likely to be modified to show alternative authentication methods alongside the conventional e-mail and password fields, it is possible that information such as identity providers will also need to be made available in order to simplify the experience for users.
* A separate method to handle the initial stage of authentication for the mechanism. For example, OpenID authentication requests are handled by the `openid_auth` method initially.
* Additional methods to handle any subsequent stages of authentication. For example, OpenID authentication involves the handling of subsequent requests in the `openid_process`, `openid_associate` and `openid_manage` methods.
### Database Tables
The database employs a `galaxy_user` table which records the details of all registered users, and this table is exposed to the code through the `User` abstraction found in `lib/galaxy/model/mapping.py`. Each logged-in user is assigned a session which references the user in the `galaxy_session` table (exposed via `GalaxySession`).
User information from external sources, such as OpenID, is found in peripheral tables such as `galaxy_user_openid` (exposed by `UserOpenID`) and references the registered user and session of that user.
### Authenticating a User
The following steps are followed in any code that seeks to recognise a user within Galaxy and allow access to the application:
1. The identity credential, currently the e-mail address of the user, is used to find any previously-registered user in the database.
1. Where no user exists and the login mechanism requires explicit registration, authentication fails at this point. Otherwise, a user is automatically created for previously unknown identities.
1. For conventional accounts requiring a password, authentication fails at this point if a valid password is not specified. Otherwise, an alternative mechanism for completing authentication may be invoked.
1. Upon completion of the authentication of a user's identity, any association of that identity with the Galaxy user instance may be performed. For example, an OpenID identity may be associated with a user created for that identity.
1. Finally, the login is handled using the `handle_user_login` method on the `GalaxyWebTransaction` object, associating the user with a new session.
+22 -19
View File
@@ -6,10 +6,12 @@ Dependency Resolvers in Galaxy
There are two parts to building a link between Galaxy and command line bioinformatics tools: the tool XML that
specifies a mapping between the Galaxy web user interface and the tool command line and tool dependencies that specify
how to source the actual packages that implement the tool’s commands. The final script that Galaxy submits to run a
job uses includes commands, such as changes to the ``PATH`` environment variable, that are generated by *dependency
resolvers*. There is a default dependency resolver configuration but administrators can provide their own configuration
using the ``dependency_resolvers_conf.xml`` configuration file in the Galaxy ``config/`` directory.
how to source the actual packages that implement the tool’s commands. The final script that Galaxy submits to run a job
uses includes commands, such as changes to the ``PATH`` environment variable, that are generated by *dependency
resolvers*. These same dependency resolvers are used by the Galaxy administrative UI to display whether an installed
tool's dependencies have been installed on the Galaxy server, and to show how they will be resolved at job runtime.
There is a default dependency resolver configuration but administrators can provide their own configuration using the
``dependency_resolvers_conf.xml`` configuration file in the Galaxy ``config/`` directory.
The binding between tool XML and the tools they need to run is specified in the tool XML using ``<requirement>``
tags, for example
@@ -34,30 +36,31 @@ The default configuration of dependency resolvers is equivalent to the following
.. code-block:: xml
<dependency_resolvers>
<!-- the default configuration, first look for legacy dependencies installed from the toolshed -->
<tool_shed_packages />
<!-- then look for env.sh files profile according to the "galaxy packages" schema -->
<galaxy_packages />
<galaxy_packages versionless="true" />
<!-- finally look for Conda dependencies. -->
<conda />
<galaxy_packages versionless="true" />
<conda versionless="true" />
</dependency_resolvers>
This default dependency resolver configuration contains five items. First, the *tool shed dependency resolver* is used,
then the *Galaxy packages dependency resolver* is used (initially looking for packages by name and version string and then looking for the package just by name), and finally it checks *Conda* for a versioned or unversioned match.
The default configuration thus prefers packages installed from the Galaxy Tool Shed using legacy ``tool_dependencies.xml``
files, before trying to find a "Galaxy package" satisfying the specific version the dependency requires before
falling back to looking for a Galaxy package with merely the correct name, and then looking for Conda recipes with
matching name and version, and finally just for a Conda package with the correct name. If any of the dependency
resolvers succeeds a dependency resolution object is returned and no more resolvers are called. This dependency
resolution object provides shell commands to prepend to the shell script that runs the tool.
This default dependency resolver configuration contains five items:
1. First, the *Tool Shed dependency resolver* is used, which resolves packages installed from the Galaxy Tool Shed
using legacy ``tool_dependencies.xml`` files,
2. then the *Galaxy packages dependency resolver* is checked for a package matching the requirement name and version,
3. then the *Conda dependency resolver* is checked for a package matching the requirement name and version. If no
versioned match can be found, it then moves on to searching for unversioned matches, that is,
4. the *Galaxy packages dependency resolver* is checked for a package matching the required name only, and
5. finally the *Conda dependency resolver* is checked for a package matching the required name only.
If any of the dependency resolvers succeeds a dependency resolution object is returned and no more resolvers are
called. This dependency resolution object provides shell commands to prepend to the shell script that runs the tool.
This order can be thought of as a descending order of deliberation. Tool Shed dependencies must be declared next to the
tool by the tool author and must be selected for installation at tool installation time - this requires specific actions
by both the tool author and the deployer who installed the tools. The dependency is therefore expected to highly craft
to the individual tool. If Galaxy packages have been setup, the deployer of a Galaxy tool has purposely crafted tool
dependency statements for a specific installation - this is slightly less deliberate than tool shed packages but
by both the tool author and the deployer who installed the tools. The dependency is therefore expected to highly
crafted to the individual tool. If Galaxy packages have been setup, the deployer of a Galaxy tool has purposely crafted
tool dependency statements for a specific installation - this is slightly less deliberate than tool shed packages but
such requirements are less likely to be incidentally resolved than Conda packages. Conda recipes are neither tied to
tools or a specific installation and are maintained in Conda channels such as Bioconda.
+10 -23
View File
@@ -1,27 +1,14 @@
Special Topics in Galaxy Administration & Deployment Documentation
==================================================================
Galaxy Deployment & Administration
==================================
This documentation intends to function as a version-specific supplement to the
`wiki <https://wiki.galaxyproject.org/Admin/>`__, not the primary admin
documentation. These resources should be used together.
This documentation is in the midst of being ported and unified based on resources from `old wiki <https://moin.galaxyproject.org/Admin/>`__ and `new hub <https://galaxyproject.org/admin/>`__. These resources should be used together for now.
.. toctree::
:maxdepth: 3
:maxdepth: 2
dependency_resolvers.rst
conda_faq.rst
mulled_containers.rst
interactive_environments.rst
framework_dependencies.rst
useful_scripts.rst
grt.rst
chat.rst
webhooks.rst
tool_panel
authentication
dependency_resolvers
conda_faq
framework_dependencies
useful_scripts

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 203 KiB

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 152 KiB

Before

Width:  |  Height:  |  Size: 334 KiB

After

Width:  |  Height:  |  Size: 334 KiB

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 246 KiB

+12
View File
@@ -0,0 +1,12 @@
Special Topics
==============
.. toctree::
:maxdepth: 2
interactive_environments
mulled_containers
grt
chat
webhooks

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 246 KiB

@@ -1,5 +1,5 @@
Galaxy Interactive Environments (GIEs)
======================================
Galaxy Interactive Environments
===============================
A GIE is a Docker container, launched by Galaxy, proxied by Galaxy, with some
extra sugar inside the container to allow users to interact easily with their
@@ -201,7 +201,8 @@ You might want to run your IEs on a host different to the one that hosts your
Galaxy webserver, since IEs on the same host as the webserver compete for
resources with that webserver and introduce some security considerations which
could be mitigated by moving containers to a separate host. This feature has
been available since 15.07 and is used in production at the University of Freiburg.
been available since 15.07 and is used in production at the University of
Freiburg and on usegalaxy.org.
First you need to configure a second host to be Docker enabled. In the
following we call this host ``gx-docker`` You need to start the Docker daemon
@@ -213,9 +214,9 @@ you can start the daemon with
$ docker -H 0.0.0.0:4243 -d
On your client, the Galaxy webserver, you can now install a Docker client. This
can also be done on older Systems like Scientific-Linux, CentOS 6, which does
not have Docker support by default. The client just talks to the Docker daemon
on host ``gx-docker``, and does not run anything itself, locally. You can test
can also be done on older systems like Scientific-Linux, CentOS 6, which do not
have Docker support by default. The client just talks to the Docker daemon on
host ``gx-docker``, and does not run anything itself, locally. You can test
your configuration for example by starting busybox from your client on the
Docker host with
@@ -223,7 +224,13 @@ Docker host with
$ docker -H tcp://gx-docker:4243 run -it busybox sh
So far so good! Now we need to configure Galaxy to use our new Docker host
So far so good! Note, however, that unless restricted by a firewall, this mode
of operation is insecure, as any client could connect and run containers on
``gx-docker``. If this is a concern at your site, follow the instructions in
the Docker documentation to `Protect the Docker daemon socket
<https://docs.docker.com/engine/security/https/>`__.
Now we need to configure Galaxy to use our new Docker host
to start the Interactive Environments. For that we need to edit the Jupyter GIE
configuration, ``jupyter.ini`` to use our custom docker host
@@ -233,14 +240,18 @@ configuration, ``jupyter.ini`` to use our custom docker host
[docker]
command = docker -H tcp://gx-docker:4243 {docker_args}
image = bgruening/docker-ipython-notebook:dev
docker_hostname = gx-docker
Please adapt your ``command`` and the ``image`` as needed.
Please adapt your ``command`` as needed.
As next step we need to configure a share mount point between the Docker host
and Galaxy. Unfortunately, this can not be a NFS mount. Docker does not like
NFS yet. You could for example use a sshfs mount with the following script
The Jupyter GIE supports getting and fetching Galaxy history datasets entirely
through the Galaxy API so it is not necessary to share a filesystem with
``gx-docker``. However, other GIE plugins may still require this.
For those GIE plugins, we need to configure a share mount point between the
Docker host and Galaxy. Unfortunately, this can not be a NFS mount. Docker does
not like NFS yet. You could for example use a sshfs mount with the following
script
.. code-block:: bash
@@ -252,3 +263,56 @@ NFS yet. You could for example use a sshfs mount with the following script
fi
This will let Galaxy and the Docker host share temporary files.
Docker Engine Swarm Mode
^^^^^^^^^^^^^^^^^^^^^^^^
As of Docker Engine version 1.12, Docker Engine can be configured to provide a
cluster of Docker Engines in a configuration known as *Docker Engine swarm
mode*. This replaces the previous and similarly named *Docker Swarm*
clustering solution, which is not compatible with swarm mode.
`The Docker Engine swarm mode documentation
<https://docs.docker.com/engine/swarm/>`__ fully explains the differences, but
the major difference is that whereas under Docker Swarm one could run commands
on the swarm with ``docker run``, Docker Engine swarm mode requires one to
create persistent services with ``docker service create`` and to remove those
services once no longer in use with ``docker service rm``.
Galaxy supports both Docker Engine swarm mode and the legacy Docker Swarm
system. Legacy Docker Swarm is supported without any special configuration,
because the containers are still run with ``docker run`` as before. To support
Docker Engine swarm mode, additional configuration is required. Begin by
editing your GIE plugin's ini configuration file (e.g. ``jupyter.ini``) and set
the ``docker_connect_port`` and ``swarm_mode options`` in addition to any other
relevant options. Unless you are using a non-standard Docker image, the correct
value for ``docker_connect_port`` should be suggested to you in the sample
configuration file:
.. code-block:: ini
[docker]
docker_connect_port = 8888
swarm_mode = True
You can also enable swarm mode for *all* GIE plugins by setting
``interactive_environment_swarm_mode`` in ``galaxy.ini`` to ``True``. If using
this setting, you must still set ``docker_connect_port`` in each GIE plugin's
ini configuration file. The ``swarm_mode`` setting in individual GIE plugin
config files will override the value set in ``galaxy.ini``.
Note that your Galaxy server does not need to be a member of the swarm itself.
It can use the method outlined above in the `Docker on Another Host`_ section
to connect as a client to a Docker daemon acting as a swarm mode manager.
Once configured, you should see that your GIE containers are started and run as
services, which you can inspect using the ``docker service ls`` command and
other ``docker service`` subcommands.
**Galaxy swarm manager**
Galaxy will start a "swarm manager" process when the first swarm mode GIE is
launched. You can control this daemon with the config file
``config/swarm_mode_manager.yml``. Consult the sample configuration at
``config/swarm_mode_manager.yml.sample`` for syntax. It will automatically shut
down when no services or nodes remain to be managed.

Before

Width:  |  Height:  |  Size: 175 KiB

After

Width:  |  Height:  |  Size: 175 KiB

@@ -1,4 +1,4 @@
Galaxy webhooks
Galaxy Webhooks
===============
Tiny plugin interface to extend the Galaxy client.
+51
View File
@@ -0,0 +1,51 @@
Tool Panel Administration
=========================
Galaxy tool panel is located in the left of the 'Analysis page' and offers the following ways of modification.
Configuration
-------------
The contents of the tool panel are defined by the following configuration files.
Local tools
~~~~~~~~~~~
In the past, the file named by your ``tool_config_file`` configuration setting in your ``config/galaxy.ini`` file was the only file used to populate your Galaxy tool panel. The default name for this file is ``tool_conf.xml``. Since this was the only file involved in populating your Galaxy tool panel, it defined the items (tools, workflows, sections and labels) that would be displayed and the way in which they would be arranged.
Tool Shed tools
~~~~~~~~~~~~~~~
For purposes of the Galaxy [Tool Shed](/src/toolshed/index.md) the ``tool_config_file`` setting allows for a comma-separated list of files (e.g., ``tool_config_file = tool_conf.xml,shed_tool_conf.xml``,etc.). The additional shed-related tool panel configuration files (``shed_tool_conf.xml``, etc.) are automatically modified when you install or uninstall a Tool Shed repository (that contains tools) to your Galaxy.
Migrated tools
~~~~~~~~~~~~~~
Another configuration file named ``migrated_tools_conf.xml.sample`` is in the Galaxy installation directory. If you start your Galaxy server using ``sh run.sh`` or something similar, this sample file will automatically be copied to a file named ``migrated_tools_conf.xml`` in the same directory. You'll be required to manually copy this file if you start your Galaxy server differently. The migrated_tools_conf.xml file is reserved to contain the XML tag sets for repositories that contain tools that were once included in the Galaxy distribution but have been moved to the Tool Shed. Similar to the approach used with the other shed-related tool panel configuration files describe above, this file's contents will be changed automatically for certain tools contained in repositories that are installed into your local Galaxy instance. More information about this process is described in the following sections.
Layout
------
The 3 or more files described in the previous section (``tool_conf.xml``, one or more ``shed_tool_conf.xml`` files, and ``migrated_tools_conf.xml``) are all used to load tool panel items (tools, sections, labels and workflows). A file named ``integrated_tool_panel.xml`` defines the arrangement for displaying these loaded items in your Galaxy tool panel.
If this file does not exist in your Galaxy installation directory, it will be automatically created and populated when you start your Galaxy server. It is initially populated based on the order in which the tool panel items are loaded. The items are loaded as each tool panel configuration file is parsed and its items are loaded. The order in which these configuration files are parsed is the order of the comma-separated list of files defined in your ``tool_config_file`` setting in your ``config/galaxy.ini`` configuration file. The ``migrated_tools_conf.xml`` file is always parsed and loaded last. Let's look at an example to help clarify how this works.
If you uninstall a repository that contains tools, entries for those tools will automatically be removed from the shed-related tool panel config file and the integrated_tool_panel.xml file.
The best approach for managing the new integrated_tool_panel.xml file is to allow Galaxy to add or remove entries as manually adding or removing them will likely result in undesired behavior. Manual changes to the file should simply be moving entries around to produce the desired arrangement of your tool panel.
Sections & Labels
~~~~~~~~~~~~~~~~~
* You can add ``labels="updated"`` to the ``<tool>`` XML element to render a label next to the tool in the tool panel.
* You can add ``<section>`` tag as a child of``<toolbox>`` to create a section that can contains tools.
.. code-block:: xml
<?xml version="1.0"?>
<toolbox tool_path="../shed_tools">
<section id="mts" name="MTS" version="">
<tool file="toolshed.g2.bx.psu.edu/repos/devteam/fastqc/a00a6402d09a/fastqc/rgFastQC.xml" guid="toolshed.g2.bx.psu.edu/repos/devteam/fastqc/fastqc/0.67" labels="new">
<tool_shed>toolshed.g2.bx.psu.edu</tool_shed>
<repository_name>fastqc</repository_name>
<repository_owner>devteam</repository_owner>
<installed_changeset_revision>a00a6402d09a</installed_changeset_revision>
<id>toolshed.g2.bx.psu.edu/repos/devteam/fastqc/fastqc/0.67</id>
<version>0.67</version>
</tool>
</section>
</toolbox>
+13 -6
View File
@@ -15,6 +15,8 @@ import datetime
import os
import sys
import sphinx_rtd_theme
# Library to make .md to slideshow
from recommonmark.parser import CommonMarkParser
@@ -67,8 +69,8 @@ source_suffix = ['.rst', '.md']
master_doc = 'index'
# General information about the project.
project = u'Galaxy Code'
copyright = str( datetime.datetime.now().year ) + u', Galaxy Team'
project = u'Galaxy Project'
copyright = str( datetime.datetime.now().year ) + u', Galaxy Committers'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -123,10 +125,15 @@ html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
html_theme_options = {
'collapse_navigation': False,
'display_version': True,
'navigation_depth': 2,
'canonical_url': 'https://docs.galaxyproject.org/en/master/',
}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
@@ -240,7 +247,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'galaxy', u'Galaxy Code Documentation',
('index', 'galaxy', u'Galaxy Documentation',
[u'Galaxy Team'], 1)
]
@@ -254,7 +261,7 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'Galaxy', u'Galaxy Code Documentation',
('index', 'Galaxy', u'Galaxy Documentation',
u'Galaxy Team', 'Galaxy', 'Data intensive biology for everyone.',
'Miscellaneous'),
]
+1 -9
View File
@@ -1,4 +1,4 @@
Developer Documentation
Development Documentation
=======================
.. toctree::
@@ -8,11 +8,3 @@ Developer Documentation
interactive_environments
build_a_job_runner
faq
These are other primary areas of documentation developers will be interested in:
- `Codebase Documentation`_ for developers of Galaxy
- `API Documentation`_ for developers of third party tools interacting with Galaxy
.. _Codebase Documentation: ../lib/modules.html
.. _API Documentation: ../api_doc.html
+3 -3
View File
@@ -1,7 +1,7 @@
Interactive Environments in Detail (and How to Build Your Own)
==============================================================
Build an Interactive Environment
================================
Unfortunately building a GIE isn't completely straightforward, and it's
Unfortunately building a Galaxy Interactive Environment (GIE) isn't completely straightforward, and it's
certainly not as simple as picking out an existing container and plugging it
in. Here we'll go through build a "Hello, World" GIE which just displays a file
from a user's history.
+38 -34
View File
@@ -1,47 +1,51 @@
Galaxy Code Documentation
*************************
Galaxy Documentation
********************
Galaxy_ is an open, web-based platform for accessible, reproducible, and
transparent computational biomedical research.
Galaxy is an open, web-based platform for accessible, reproducible, and transparent computational biomedical research.
- *Accessible:* Users without programming experience can easily specify parameters and run tools and workflows.
- *Reproducible:* Galaxy captures information so that any user can repeat and understand a complete computational analysis.
- *Transparent:* Users share and publish analyses via the web and create Pages, interactive, web-based documents that describe a complete analysis.
Things to know:
- There are multiple choices_ when it comes to using Galaxy.
- You can explore the `current code in the development branch`_ on GitHub.
- This documentation is hosted at readthedocs_.
For more information on the Galaxy Project, please visit the `project home page`_.
.. _Galaxy: http://galaxyproject.org
.. _choices: https://wiki.galaxyproject.org/BigPicture/Choices
.. _current code in the development branch: https://github.com/galaxyproject/galaxy
.. _readthedocs: http://galaxy.readthedocs.org
.. _project home page: http://galaxyproject.org
For more information on the Galaxy Project, please visit the https://galaxyproject.org
Contents
========
* :ref:`release-docs`
* :ref:`admin-docs`
* :ref:`dev-docs`
* :ref:`about-docs`
.. _release-docs:
.. toctree::
:maxdepth: 5
Galaxy API Documentation <api_doc>
Tool Shed API Documentation <ts_api_doc>
Application Documentation <lib/modules>
:maxdepth: 2
:caption: Release Notes
Releases <releases/index>
Developer Documentation <dev/index>
.. _admin-docs:
Special topics in Administration <admin/index>
.. toctree::
:maxdepth: 2
:caption: Admin Documentation
Administration <admin/index>
Special topics <admin/special_topics/index>
.. _dev-docs:
.. toctree::
:maxdepth: 1
:caption: Developer Documentation
Development <dev/index>
Galaxy API <api_doc>
Tool Shed API <ts_api_doc>
Application Documentation <lib/modules>
.. _about-docs:
.. toctree::
:maxdepth: 2
:caption: About Project
Project Governance <project/organization>
Issue Management <project/issues>
Indices and tables
@@ -60,4 +64,4 @@ If you have your own copy of the Galaxy source code, you can also generate your
$ make -C doc/ html
The generated documentation will be in ``doc/build/html/`` and can be viewed with a web browser. Note that you will need to install Sphinx and a fair number of module dependencies before this will produce output.
The generated documentation will be in ``doc/build/html/`` and can be viewed with a web browser. Note that you will need to install Sphinx and a fair number of module dependencies before this will produce output.
+8
View File
@@ -9,6 +9,12 @@ guidelines for longer term planning for various Galaxy related projects.
Some inspiration taken from the way the
`Docker <https://github.com/docker/docker>`__ project labels issues.
Issue Reporting
===============
Issues (bugs, feature requests, etc.) should be reported at `GitHub issues`_, and
handling of issues follows the procedures described in the `issues document`_.
Milestones
==========
@@ -232,3 +238,5 @@ For now, we will rely on a few simple automation rules:
``triage`` to indicate that they require attention prior to merge.
.. _ORGANIZATION: https://github.com/galaxyproject/galaxy/blob/dev/doc/source/project/organization.rst
.. _issues document: https://github.com/galaxyproject/galaxy/blob/dev/doc/source/project/issues.rst
.. _Github issues: https://github.com/galaxyproject/galaxy/issues/
+6 -4
View File
@@ -29,15 +29,17 @@ Highlights
Thanks to `@abretaud <https://github.com/abretaud>`__, `@ashvark <https://github.com/ashvark>`__, `@jvolkening <https://github.com/jvolkening>`__, and `@mvdbeek <https://github.com/mvdbeek>`__.
Implemented in `Pull Request 3145`_, `PullRequest 3510`_ and `PullRequest 3514`_.
`Github <https://github.com/galaxyproject/galaxy>`__
===========================================================
Get Galaxy
==========
New Galaxy repository
The code lives at `Github <https://github.com/galaxyproject/galaxy>`__ and you should have `Git <https://git-scm.com/>`__ to obtain it.
To get a new Galaxy repository run:
.. code-block:: shell
$ git clone -b release_17.01 https://github.com/galaxyproject/galaxy.git
Update of existing Galaxy repository
To update an existing Galaxy repository run:
.. code-block:: shell
$ git checkout release_17.01 && git pull --ff-only origin release_17.01
+4 -3
View File
@@ -23,9 +23,9 @@ from galaxy.openid.providers import OpenIDProviders
from galaxy.tools.data_manager.manager import DataManagers
from galaxy.jobs import metrics as job_metrics
from galaxy.web.proxy import ProxyManager
from galaxy.web.stack import application_stack_instance
from galaxy.queue_worker import GalaxyQueueWorker
from galaxy.util import heartbeat
from galaxy.util.postfork import register_postfork_function
from tool_shed.galaxy_install import update_repository_manager
@@ -44,6 +44,7 @@ class UniverseApplication( object, config.ConfiguresGalaxyMixin ):
log.debug( "python path is: %s", ", ".join( sys.path ) )
self.name = 'galaxy'
self.new_installation = False
self.application_stack = application_stack_instance()
# Read config file and check for errors
self.config = config.Configuration( **kwargs )
self.config.check()
@@ -151,7 +152,7 @@ class UniverseApplication( object, config.ConfiguresGalaxyMixin ):
fname=self.config.heartbeat_log
)
self.heartbeat.daemon = True
register_postfork_function(self.heartbeat.start)
self.application_stack.register_postfork_function(self.heartbeat.start)
self.sentry_client = None
if self.config.sentry_dsn:
@@ -159,7 +160,7 @@ class UniverseApplication( object, config.ConfiguresGalaxyMixin ):
import raven
self.sentry_client = raven.Client(self.config.sentry_dsn)
register_postfork_function(postfork_sentry_client)
self.application_stack.register_postfork_function(postfork_sentry_client)
# Transfer manager client
if self.config.get_bool( 'enable_beta_job_managers', False ):
+16 -20
View File
@@ -15,7 +15,7 @@ log = logging.getLogger(__name__)
def _get_subs(d, k, params):
if k not in d:
if k not in d or not d[k]:
raise ConfigurationError("Missing '%s' parameter in LDAP options" % k)
return str(d[k]).format(**params)
@@ -25,17 +25,17 @@ def _parse_ldap_options(ldap, options_unparsed):
if not options_unparsed:
return []
if "=" not in options_unparsed:
log.error("LDAP authenticate: Invalid syntax in <ldap-options>. Syntax should be option1=value1,option2=value2")
return []
ldap_options = []
# Valid options must start with this prefix. See help(ldap)
prefix = "OPT_"
for opt in options_unparsed.split(","):
key, value = opt.split("=")
try:
key, value = opt.split("=")
except ValueError:
log.warning("LDAP authenticate: Invalid syntax '%s' inside <ldap-options> element. Syntax should be option1=value1,option2=value2" % opt)
continue
try:
pair = []
@@ -109,14 +109,18 @@ class LDAP(AuthProvider):
else:
ldap_options = _parse_ldap_options(ldap, ldap_options_raw)
try:
# setup connection
ldap.set_option(ldap.OPT_REFERRALS, 0)
for opt in ldap_options:
ldap.set_option(*opt)
except Exception:
log.exception('LDAP authenticate: set_option exception')
return (failure_mode, '', '')
if 'search-fields' in options:
try:
# setup connection
ldap.set_option(ldap.OPT_REFERRALS, 0)
for opt in ldap_options:
ldap.set_option(*opt)
l = ldap.initialize(_get_subs(options, 'server', params))
l.protocol_version = 3
@@ -155,17 +159,9 @@ class LDAP(AuthProvider):
# bind as user to check their credentials
try:
# setup connection
ldap.set_option(ldap.OPT_REFERRALS, 0)
for opt in ldap_options:
ldap.set_option(*opt)
l = ldap.initialize(_get_subs(options, 'server', params))
l.protocol_version = 3
bind_password = _get_subs(options, 'bind-password', params)
if not bind_password:
raise RuntimeError('LDAP authenticate: empty password')
l.simple_bind_s(_get_subs(
options, 'bind-user', params), bind_password)
try:
+14 -20
View File
@@ -25,8 +25,8 @@ from galaxy.exceptions import ConfigurationError
from galaxy.util import listify
from galaxy.util import string_as_bool
from galaxy.util.dbkeys import GenomeBuilds
from galaxy.util.postfork import register_postfork_function
from galaxy.web.formatting import expand_pretty_datetime_format
from galaxy.web.stack import register_postfork_function
from .version import VERSION_MAJOR
log = logging.getLogger( __name__ )
@@ -52,6 +52,7 @@ PATH_DEFAULTS = dict(
workflow_schedulers_config_file=['config/workflow_schedulers_conf.xml', 'config/workflow_schedulers_conf.xml.sample'],
modules_mapping_files=['config/environment_modules_mapping.yml', 'config/environment_modules_mapping.yml.sample'],
local_conda_mapping_file=['config/local_conda_mapping.yml', 'config/local_conda_mapping.yml.sample'],
swarm_manager_config_file=['config/swarm_manager_conf.yml', 'config/swarm_manager_conf.yml.sample'],
)
PATH_LIST_DEFAULTS = dict(
@@ -577,6 +578,8 @@ class Configuration( object ):
elif ie_dirs:
self.visualization_plugins_directory += ",%s" % ie_dirs
self.gie_swarm_mode = string_as_bool( kwargs.get( 'interactive_environment_swarm_mode', False ) )
self.proxy_session_map = self.resolve_path( kwargs.get( "dynamic_proxy_session_map", "database/session_map.sqlite" ) )
self.manage_dynamic_proxy = string_as_bool( kwargs.get( "dynamic_proxy_manage", "True" ) ) # Set to false if being launched externally
self.dynamic_proxy_debug = string_as_bool( kwargs.get( "dynamic_proxy_debug", "False" ) )
@@ -901,34 +904,25 @@ class ConfiguresGalaxyMixin:
time.sleep(1)
def reload_toolbox(self):
# Initialize the tools, making sure the list of tool configs includes the reserved migrated_tools_conf.xml file.
tool_configs = self.config.tool_configs
if self.config.migrated_tools_config not in tool_configs:
tool_configs.append( self.config.migrated_tools_config )
from galaxy import tools
old_toolbox = self.toolbox
self.toolbox = tools.ToolBox( tool_configs, self.config.tool_path, self )
self.reindex_tool_search()
if old_toolbox:
old_toolbox.shutdown()
def _configure_toolbox( self ):
from galaxy import tools
from galaxy.managers.citations import CitationsManager
self.citations_manager = CitationsManager( self )
from galaxy.tools.deps import containers
from galaxy.tools.toolbox.cache import ToolCache
from galaxy.tools.toolbox.lineages.tool_shed import ToolVersionCache
self.citations_manager = CitationsManager( self )
self.tool_cache = ToolCache()
self.tool_version_cache = ToolVersionCache(self)
self._toolbox_lock = threading.RLock()
self.toolbox = None
self.reload_toolbox()
# Initialize the tools, making sure the list of tool configs includes the reserved migrated_tools_conf.xml file.
tool_configs = self.config.tool_configs
if self.config.migrated_tools_config not in tool_configs:
tool_configs.append( self.config.migrated_tools_config )
self.toolbox = tools.ToolBox( tool_configs, self.config.tool_path, self )
self.reindex_tool_search()
from galaxy.tools.deps import containers
galaxy_root_dir = os.path.abspath(self.config.root)
file_path = os.path.abspath(getattr(self.config, "file_path"))
app_info = containers.AppInfo(
+552
View File
@@ -0,0 +1,552 @@
"""
Docker Swarm mode management
"""
import argparse
import errno
import json
import logging
import os
import subprocess
import sys
import time
try:
import daemon
import daemon.pidfile
import lockfile
except ImportError:
daemon = None
import yaml
try:
import galaxy # noqa: F401 this is a test import
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(
os.path.dirname(__file__),
os.pardir,
os.pardir)))
from galaxy.config import (
configure_logging,
find_path,
find_root,
)
from galaxy.util.properties import find_config_file, load_app_properties
DESCRIPTION = "Daemon to manage a Docker Swarm (running in Docker Swarm mode)."
SWARM_MANAGER_CONF_DEFAULTS = {
'pid_file': '{xdg_data_home}/galaxy_swarm_manager.pid',
'log_file': '{xdg_data_home}/galaxy_swarm_manager.log',
'command': 'docker {docker_args}',
'service_prefix': 'galaxy_gie_',
'max_waiting_services': 0,
'max_wait_time': 5,
'max_node_counts': {}, # max number of nodes per class to spawn
'max_node_idle_time': 120,
'node_prefix': None,
'spawn_wait_time': 30,
'spawn_command': '/bin/true',
'destroy_command': '/bin/true',
'command_failure_command': '/bin/true',
'command_retries': 0,
'command_retry_wait': 10,
'terminate_when_idle': True,
}
OK_NODE_STATE = 'ready-active'
NODE_CPU_CLASS_LABEL = '_galaxy_cpu_class'
log = lambda *x: None # noqa: E731
# TODO: pass around instances or at least namedtuples rather than these
# arbitrary dictionaries
class DockerInterface(object):
def __init__(self, swarm_manager_conf):
self.swarm_manager_conf = swarm_manager_conf
self.command = swarm_manager_conf['command']
self.service_prefix = swarm_manager_conf['service_prefix']
def _run_docker(self, docker_args):
raw_cmd = self.command.format(docker_args=docker_args)
p = subprocess.Popen(raw_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, shell=True)
stdout, stderr = p.communicate()
if p.returncode != 0:
log.error("%s\n%s" % (stdout, stderr))
return None
else:
return stdout
def _parse_docker_column_output(self, output):
"""Many docker commands do not provide an option to format the output
or output in a machine-readily-parseable format (e.g. json). In order
to deal with such output and hopefully stay compatible with future
column order changes, key returned rows based on column headers.
An assumption is made that a single space in the header row does not
separate columns - column names can have spaces in them, and columns
are separated by at least 2 spaces. This seems to be true as of Docker
1.13.1.
"""
parsed = []
output = output.splitlines()
header = output[0]
colstarts = [0]
colidx = 0
spacect = 0
if not output:
return parsed
for i, c in enumerate(header):
if c != ' ' and spacect > 1:
colidx += 1
colstarts.append(i)
spacect = 0
elif c == ' ':
spacect += 1
colstarts.append(None)
colheadings = []
for i in range(0, len(colstarts) - 1):
colheadings.append(header[colstarts[i]:colstarts[i + 1]].strip())
for line in output[1:]:
row = {}
for i, key in enumerate(colheadings):
row[key] = line[colstarts[i]:colstarts[i + 1]].strip()
parsed.append(row)
return parsed
def _service_inspect(self, service_id):
return self._run_docker(docker_args='service inspect {service_id}'.format(service_id=service_id))
def _get_reserved_cpu_count(self, service_id=None, inspect_output=None):
assert service_id or inspect_output, "Either `service_id` or `inspect_output` is required"
if not inspect_output:
inspect_output = self._service_inspect(service_id)
try:
return json.loads(inspect_output)[0]['Spec']['Resources']['Reservations']['NanoCPUs'] / 1000000000
except KeyError:
return 1
def _node_inspect(self, node_name):
return self._run_docker(docker_args='node inspect {node_name}'.format(node_name=node_name))
def _get_node_cpu_class(self, node_name=None, inspect_output=None):
assert node_name or inspect_output, "Either `node_name` or `inspect_output` is required"
if not inspect_output:
inspect_output = self._node_inspect(node_name)
try:
return json.loads(inspect_output)[0]['Spec']['Labels'][NODE_CPU_CLASS_LABEL]
except KeyError:
return None
def waiting_services_by_cpu_class(self):
rval = {}
service_ids = self._services_in_state('Running', 'Pending')
for service_id in service_ids:
cpu_class = self._get_reserved_cpu_count(service_id=service_id)
if cpu_class not in rval:
rval[cpu_class] = []
rval[cpu_class].append(service_id)
return rval
def active_nodes_by_cpu_class(self):
rval = {}
ls_output = self._run_docker(docker_args='node ls')
for node in self._parse_docker_column_output(ls_output):
cpu_class = self._get_node_cpu_class(node_name=node['HOSTNAME'])
if cpu_class:
cpu_class = int(cpu_class)
rval[cpu_class] = rval.get(cpu_class, 0) + 1
return rval
def completed_services(self):
return self._services_in_state('Shutdown', 'Complete')
def _services_in_state(self, desired, current):
service_ids = []
for service_detail in self._service_details():
if service_detail['DESIRED STATE'] == desired and service_detail['CURRENT STATE'].startswith(current):
service_ids.append(service_detail['ID'])
return service_ids
def _service_details(self):
ls_output = self._run_docker(docker_args='service ls')
for service in self._parse_docker_column_output(ls_output):
if not service['NAME'].startswith(self.service_prefix):
continue
ps_output = self._run_docker(docker_args='service ps --no-trunc {service_id}'.format(
service_id=service['ID']))
service_details = self._parse_docker_column_output(ps_output)[0]
for col in ('ID', 'NAME'):
service_details['PROCESS ' + col] = service_details[col]
service_details[col] = service[col]
yield service_details
def clean_services(self):
cleaned_services = []
services = self.completed_services()
if services:
cleaned_services = self._run_docker(docker_args='service rm {service_ids}'.format(
service_ids=' '.join(services))).splitlines()
return cleaned_services
def node_states(self):
nodes = {}
ls_output = self._run_docker(docker_args='node ls')
for node in self._parse_docker_column_output(ls_output):
nodes[node['HOSTNAME']] = {
'state': ('%s-%s' % (node['STATUS'], node['AVAILABILITY'])).lower(),
'manager': True if node['MANAGER STATUS'] else False,
}
return nodes
def node_job_count(self, node_name):
ps_output = self._run_docker(docker_args='node ps --no-trunc {node_name}'.format(
node_name=node_name))
jobs = filter(lambda x: x['NAME'].startswith(self.service_prefix), self._parse_docker_column_output(ps_output))
return len(jobs)
def ensure_node_cpu_class(self, node, cpu_class):
cur_cpu_class = self._get_node_cpu_class(node_name=node)
if str(cpu_class) != cur_cpu_class:
log.info("setting node '%s' cpu class from '%s' to '%s'", node, cur_cpu_class, cpu_class)
self._run_docker(docker_args='node update --label-add {label_name}={label_val} {node}'.format(
label_name=NODE_CPU_CLASS_LABEL,
label_val=cpu_class,
node=node))
else:
log.debug("node '%s' cpu class is '%s'", node, cur_cpu_class)
def node_cpu_class(self, node):
return self._get_node_cpu_class(node_name=node)
class SwarmManager(object):
def __init__(self, conf):
self.conf = conf
self.docker_interface = DockerInterface(conf)
self.state = SwarmState(conf)
self.spawn_wait_time = conf['spawn_wait_time']
self.spawn_command = conf['spawn_command']
self.destroy_command = conf['destroy_command']
self.command_retries = conf['command_retries']
self.command_retry_wait = conf['command_retry_wait']
self.node_prefix = conf['node_prefix']
self.terminate_when_idle = conf['terminate_when_idle']
def run(self):
while True:
node_states = None
self._spawn_if_waiting()
self._check_for_new_nodes(node_states=node_states)
self._destroy_if_surplus(node_states=node_states)
self._clean_services()
self._terminate_if_idle()
time.sleep(1)
def _run_command(self, command, command_retries=None, **kwargs):
stdout = None
attempt = 0
if not command_retries:
command_retries = self.command_retries
raw_cmd = command.format(**kwargs)
log.debug('running command: %s', raw_cmd)
while not stdout and attempt < command_retries + 1:
attempt += 1
p = subprocess.Popen(raw_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, shell=True)
stdout, stderr = p.communicate()
if p.returncode != 0:
msg = "error running '%s'" % raw_cmd
if attempt < command_retries + 1:
msg += ', waiting %s seconds' % self.command_retry_wait
time.sleep(self.command_retry_wait)
log.warning(msg + "\nstdout: %s\nstderr: %s\n", stdout, stderr)
else:
msg += ' (final attempt)'
log.error(msg + "\nstdout: %s\nstderr: %s\n", stdout, stderr)
self._run_command(self.conf['command_failure_command'].format(failed_command=raw_cmd), command_retries=0)
stdout = None
else:
stdout = stdout.strip()
return stdout
def _spawn_if_waiting(self):
waiting = self.docker_interface.waiting_services_by_cpu_class()
active = self.docker_interface.active_nodes_by_cpu_class()
cpus_needed = self.state.need_nodes(waiting, active)
for cpu_class in cpus_needed.keys():
log.info("requesting node(s) for services requesting %d CPUs total (%d CPUs each): %s", cpus_needed[cpu_class], cpu_class, ' '.join(waiting[cpu_class]))
command = '{spawn_command}'.format(spawn_command=self.spawn_command).format(
cpu_class=cpu_class,
cpus_needed=cpus_needed[cpu_class])
new_nodes = self._run_command(command)
if not new_nodes:
log.warning('spawn_command returned no new nodes, cannot manage nodes')
else:
log.info("node allocator will spawn: %s", new_nodes)
self.state.nodes_requested(cpu_class, new_nodes.split(), waiting[cpu_class])
self.state.mark_services_handled(waiting[cpu_class])
def _check_for_new_nodes(self, node_states=None):
for node_name, elapsed, cpu_class, node in self.state.spawning_nodes():
if not node_states:
node_states = self.docker_interface.node_states()
if node_name not in node_states:
if elapsed > self.spawn_wait_time:
log.warning("spawning node '%s' not found in `docker node ls` and spawn_wait_time exceeded! %d seconds have elapsed", node_name, elapsed)
self._run_command(self.conf['command_failure_command'].format(failed_command='wait_for_spawning_node %s' % node_name), command_retries=0)
self.mark_spawning_node_timeout(node_name)
elif node_states[node_name]['state'] == OK_NODE_STATE:
self.docker_interface.ensure_node_cpu_class(node_name, cpu_class)
self.state.mark_spawning_node_ready(node_name)
log.info("spawning node '%s' is ready!", node_name)
elif node_states[node_name]['state'] != node['state']:
log.info("spawning node '%s' state changed from '%s' to '%s'", node_name, node['state'], node_states[node_name]['state'])
self.docker_interface.ensure_node_cpu_class(node_name, cpu_class)
self.state.mark_spawning_node_state(node_name, node_states[node_name]['state'])
elif elapsed > self.spawn_wait_time:
log.warning("spawning node '%s' state is '%s' after %s seconds", node_name, node_states[node_name]['state'], elapsed)
def _destroy_if_surplus(self, node_states=None):
destroy_nodes = []
if not node_states:
node_states = self.docker_interface.node_states()
for node_name, node_state in node_states.items():
if self._node_ready_for_destruction(node_name, node_state):
destroy_nodes.append(node_name)
if destroy_nodes:
command = '{destroy_command}'.format(destroy_command=self.destroy_command).format(
nodes=' '.join(destroy_nodes))
destroyed_nodes = self._run_command(command)
if not destroyed_nodes:
log.warning('destroy_command returned no destroyed nodes')
else:
log.info("destroyed nodes: %s", destroyed_nodes)
def _node_is_managed(self, node_name, node_state):
return (not self.node_prefix or node_name.startswith(self.node_prefix)) and not node_state['manager']
def _node_ready_for_destruction(self, node_name, node_state):
ready = False
if (self._node_is_managed(node_name, node_state) and
node_state['state'] == 'ready-active'):
if self.docker_interface.node_job_count(node_name) == 0:
self.state.mark_node_idle(node_name)
ready = self.state.is_destruction_time(node_name)
else:
self.state.clear_node_idle(node_name)
return ready
def _clean_services(self):
cleaned_services = self.docker_interface.clean_services()
if cleaned_services:
self.state.clean_services(cleaned_services)
log.info("cleaned services: %s", ', '.join(cleaned_services))
def _terminate_if_idle(self):
if not self.terminate_when_idle:
return
node_states = self.docker_interface.node_states()
for node_name, node_state in node_states.items():
if self._node_is_managed(node_name, node_state):
return # nonterminated managed nodes remain
elif self.docker_interface.node_job_count(node_name) > 0:
return # unmanaged nodes are running a galaxy service
# FIXME: there's a race condition here
if self.docker_interface.waiting_services_by_cpu_class():
return # waiting jobs remain
log.info('nothing to manage, shutting down')
sys.exit(0)
class SwarmState(object):
def __init__(self, conf):
self._handled_services = set()
self._waiting_since = {}
self._spawning_nodes = {}
self._surplus_nodes = {}
self.max_waiting_services = conf['max_waiting_services']
self.max_wait_time = conf['max_wait_time']
self.max_node_idle_time = conf['max_node_idle_time']
self.max_node_counts = conf['max_node_counts']
def need_nodes(self, waiting_services, active_nodes):
rval = {}
need_cpus = self._needed_cpu_counts(waiting_services)
spawning_cpus = self._spawning_cpu_counts()
for cpu_class in need_cpus.keys():
cpus_needed = need_cpus[cpu_class] - spawning_cpus.get(cpu_class, 0)
if cpus_needed > 0 and active_nodes.get(cpu_class, 0) < self.max_node_counts.get(cpu_class, sys.maxint):
rval[cpu_class] = cpus_needed
return rval
def _needed_cpu_counts(self, waiting_services):
"""Given a count of services waiting of each cpu class, return the
count of nodes needed of each node type if the maximum wait times and
waiting service count thresholds have been reached.
"""
rval = {}
new_waiting_since = {}
for cpu_class in waiting_services.keys():
new_waiting_since[cpu_class] = self._waiting_since.get(cpu_class, time.time())
# filter out any services that have already been handled
unhandled_waiting_services = [ s for s in waiting_services[cpu_class] if s not in self._handled_services ]
if (len(unhandled_waiting_services) > self.max_waiting_services and
time.time() - new_waiting_since[cpu_class] > self.max_wait_time):
# need waiting[cpu_class] nodes of this class
rval[cpu_class] = len(unhandled_waiting_services)
# drop any cpu_classes from waiting_since that are no longer waiting
self._waiting_since = new_waiting_since
return rval
def spawning_nodes(self):
now = time.time()
for cpu_class in self._spawning_nodes.keys():
for node_name in self._spawning_nodes[cpu_class].keys():
node = self._spawning_nodes[cpu_class][node_name]
yield (node_name, now - node['time_requested'], cpu_class, node)
def _spawning_cpu_counts(self):
rval = {}
for cpu_class in self._spawning_nodes.keys():
rval[cpu_class] = sum([ v['cpu_count'] for k, v in self._spawning_nodes[cpu_class].items() ])
return rval
def nodes_requested(self, cpu_class, nodes, services):
if cpu_class not in self._spawning_nodes:
self._spawning_nodes[cpu_class] = {}
for node in nodes:
node_name = node.split(':')[0]
try:
cpu_count = node.split(':')[1]
except IndexError:
cpu_count = cpu_class
self._spawning_nodes[cpu_class][node_name] = {
'state': 'requested',
'cpu_count': cpu_count,
'time_requested': time.time(),
}
def mark_services_handled(self, services):
self._handled_services.update(services)
def mark_spawning_node_ready(self, node_name):
self._delete_spawning_node(node_name)
def mark_spawning_node_timeout(self, node_name):
self._delete_spawning_node(node_name)
def _delete_spawning_node(self, node_name):
for cpu_class in self._spawning_nodes.keys():
if node_name in self._spawning_nodes[cpu_class]:
del self._spawning_nodes[cpu_class][node_name]
def mark_spawning_node_state(self, node_name, state):
for cpu_class in self._spawning_nodes.keys():
if node_name in self._spawning_nodes[cpu_class]:
self._spawning_nodes[cpu_class][node_name]['state'] = state
def is_destruction_time(self, node_name):
now = time.time()
return now - self._surplus_nodes.get(node_name, now) > self.max_node_idle_time
def mark_node_idle(self, node_name):
if node_name not in self._surplus_nodes:
self._surplus_nodes[node_name] = time.time()
def clear_node_idle(self, node_name):
if node_name in self._surplus_nodes:
del self._surplus_nodes[node_name]
def clean_services(self, services):
self._handled_services.difference_update(services)
def main(argv=None, fork=False):
if not daemon:
log.warning('The daemon module is required to use the swarm manager, install it with `pip install python-daemon`')
return
if argv is None:
argv = sys.argv[1:]
if fork:
p = subprocess.Popen([sys.executable, __file__] + argv)
p.wait()
else:
args = _arg_parser().parse_args(argv)
kwargs = _app_properties(args)
_run_swarm_manager(kwargs, args)
def _app_properties(args):
galaxy_config_file = find_config_file("config/galaxy.ini", "universe_wsgi.ini", args.galaxy_config_file)
app_properties = load_app_properties(ini_file=galaxy_config_file)
return app_properties
def _arg_parser():
parser = argparse.ArgumentParser(description=DESCRIPTION)
parser.add_argument("-c", "--galaxy-config-file", default=None)
return parser
def _run_swarm_manager(kwargs, args):
configure_logging(kwargs)
global log
log = logging.getLogger(__name__)
root = find_root(kwargs)
swarm_manager_config_file = find_path(kwargs, "swarm_manager_config_file", root)
swarm_manager_conf = _parse_swarm_manager_conf(swarm_manager_config_file)
try:
os.makedirs(os.path.dirname(swarm_manager_conf['pid_file']))
except (IOError, OSError) as exc:
if exc.errno != errno.EEXIST:
raise
log.debug("daemonizing, logs will be written to '%s'", swarm_manager_conf['log_file'])
pidfile = daemon.pidfile.PIDLockFile(swarm_manager_conf['pid_file'])
with open(swarm_manager_conf['log_file'], 'a') as logfh:
try:
with daemon.DaemonContext(
pidfile=pidfile,
stdout=logfh,
stderr=logfh,
):
_swarm_manager(swarm_manager_conf)
except lockfile.AlreadyLocked:
log.debug("attempt to daemonize with swarm manager already running ignored")
def _load_xdg_environment():
return dict(
data_home=os.path.expanduser(os.environ.get('XDG_DATA_HOME', '~/.local/share')),
)
def _parse_swarm_manager_conf(swarm_manager_config_file):
conf = SWARM_MANAGER_CONF_DEFAULTS.copy()
xdg_env = _load_xdg_environment()
try:
with open(swarm_manager_config_file) as fh:
conf.update(yaml.load(fh))
except (OSError, IOError) as exc:
if exc.errno == errno.ENOENT:
log.warning("config file '%s' does not exist, running with default config", swarm_manager_config_file)
else:
raise
for opt in ('pid_file', 'log_file'):
conf[opt] = conf[opt].format(xdg_data_home=xdg_env['data_home'])
return conf
def _swarm_manager(conf):
swarm_manager = SwarmManager(conf)
log.debug("swarm manager loaded, running...")
swarm_manager.run()
if __name__ == '__main__':
__name__ = 'swarm_manager'
main()
+1 -1
View File
@@ -1148,7 +1148,7 @@ Binary.register_sniffable_binary_format('sra', 'sra', Sra)
class RData( Binary ):
"""Generic R Data file datatype implementation"""
file_ext = 'RData'
file_ext = 'rdata'
def sniff( self, filename ):
rdata_header = b'RDX2\nX\n'
+4 -2
View File
@@ -270,7 +270,8 @@ class AlignCheck(Tabular):
dataset.metadata.column_names = self.column_names
dataset.metadata.column_types = self.column_types
dataset.metadata.comment_lines = self.comment_lines
dataset.metadata.data_lines -= self.comment_lines
if isinstance(dataset.metadata.data_lines, int):
dataset.metadata.data_lines -= self.comment_lines
class AlignReport(Tabular):
@@ -735,7 +736,8 @@ class CountTable(Tabular):
dataset.metadata.groups = colnames[2:]
dataset.metadata.comment_lines = 1
dataset.metadata.data_lines -= 1
if isinstance(dataset.metadata.data_lines, int):
dataset.metadata.data_lines -= 1
class RefTaxonomy(Tabular):
+8
View File
@@ -152,6 +152,14 @@ class MzXML(ProteomicsXml):
root = "mzXML"
class MzData(ProteomicsXml):
"""mzData data"""
edam_format = "format_3245"
file_ext = "mzdata"
blurb = "mzData Mass Spectrometry data"
root = "mzData"
class MzIdentML(ProteomicsXml):
edam_format = "format_3247"
file_ext = "mzid"
+47
View File
@@ -605,3 +605,50 @@ class Smat(Text):
if re.match(r"[-+]?\d+$", item) is None:
return False
return True
class PlantTribesOrtho(Html):
"""
PlantTribes sequences classified into precomputed, orthologous gene family
clusters.
"""
file_ext = "ptortho"
def set_peek(self, dataset, is_multi_byte=False):
super(PlantTribesOrtho, self).set_peek(dataset, is_multi_byte=is_multi_byte)
dataset.blurb = "PlantTribes gene family clusters: %d files" % dataset.metadata.data_lines
class PlantTribesOrthoCodingSequence(Html):
"""
PlantTribes sequences classified into precomputed, orthologous gene family
clusters and corresponding coding sequences.
"""
file_ext = "ptorthocs"
def set_peek(self, dataset, is_multi_byte=False):
super(PlantTribesOrthoCodingSequence, self).set_peek(dataset, is_multi_byte=is_multi_byte)
dataset.blurb = "PlantTribes gene family clusters with corresponding coding sequences: %d files" % dataset.metadata.data_lines
class PlantTribesPhylogeneticTree(Html):
"""
PlantTribes multiple sequence alignments and inferred maximum likelihood
phylogenies for orthogroups.
"""
file_ext = "pttree"
def set_peek(self, dataset, is_multi_byte=False):
super(PlantTribesPhylogeneticTree, self).set_peek(dataset, is_multi_byte=is_multi_byte)
dataset.blurb = "PlantTribes phylogenetic trees: %d files" % dataset.metadata.data_lines
class PlantTribesMultipleSequenceAlignment(Html):
"""
PlantTribes multiple sequence alignments for orthogroups.
"""
file_ext = "ptalign"
def set_peek(self, dataset, is_multi_byte=False):
super(PlantTribesMultipleSequenceAlignment, self).set_peek(dataset, is_multi_byte=is_multi_byte)
dataset.blurb = "PlantTribes multiple sequence alignments: %d files" % dataset.metadata.data_lines

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