Merging with dev
@@ -5,3 +5,4 @@ database/
|
||||
doc/source/conf.py
|
||||
eggs/
|
||||
lib/galaxy/util/jstree.py
|
||||
lib/galaxy/web/proxy/js/node_modules/
|
||||
|
||||
@@ -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,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/>`__
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 } );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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>';
|
||||
}
|
||||
|
||||
@@ -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 ) );
|
||||
|
||||
@@ -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 + ' ' +
|
||||
'<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();
|
||||
|
||||
@@ -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",
|
||||
|
||||
});
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -221,6 +221,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
span.nametags {
|
||||
span.label {
|
||||
display: inline-block;
|
||||
margin-right: 2px;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -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)}
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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 |
@@ -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.
|
||||
@@ -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>
|
||||
@@ -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,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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
@@ -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/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ):
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()
|
||||
@@ -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'
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||