Merge branch 'dev' of https://github.com/galaxyproject/galaxy into workflow_form_002

Conflicts:
	client/galaxy/scripts/galaxy.workflows.js
	static/maps/galaxy.workflows.js.map
	static/scripts/galaxy.workflows.js
This commit is contained in:
guerler
2015-06-15 04:01:26 -04:00
56 changed files with 1300 additions and 59 deletions
+73 -3
View File
@@ -27,9 +27,8 @@ the [development mailing list](http://dev.list.galaxyproject.org/).
## How to Contribute
* All changes to the [core galaxy project](https://github.com/galaxyproject/galaxy)
should be made through pull requests to this repository except when
serious security vulnerabilities must simulatenously be made to multiple
previously released versions of Galaxy.
should be made through pull requests to this repository (with just two
exceptions outlined below).
* If you are new to Git - please check out the very useful tutorials on the [GitHub training hub](https://training.github.com/kit/)
@@ -102,3 +101,74 @@ developers.
More information about tool development can be found [on the
wiki](https://wiki.galaxyproject.org/Develop).
## Handling Pull Requests
Everyone is encouraged to express opinions and issue non-binding votes on pull
requests, but only members of the *committers* group may issue binding votes
on pull requests. Information on the *committers* group can be found in the
[organization document](https://github.com/galaxyproject/galaxy/blob/dev/doc/source/project/organization.rst)
describing governance of the core Galaxy code base.
Votes on pull requests should take the form of
[+1, 0, -1, and fractions](http://www.apache.org/foundation/voting.html)
as outlined by the Apache Foundation.
Pull requests modifying pre-existing releases should be restricted to bug fixes
and require at least 2 *+1* binding votes from someone other than the author of
the pull request with no *-1* binding votes.
Pull requests changing or clarifying the procedures governing this repository:
- Must be made to the ``dev`` branch of this repository.
- Must remain open for at least 192 hours (unless every qualified committer has
voted).
- Require binding *+1* votes from at least 25% of qualified *committers* with no
*-1* binding votes.
- Should be titled with the prefix *[PROCEDURES]* and tagged with
the *procedures* tag in Github.
- Should not be modified once open. If changes are needed, the pull request
should be closed, re-opened with modifications, and votes reset.
- Should be restricted to just modifying the procedures and generally should not
contain code modifications.
- If the pull request adds or removes committers, there must be a separate
pull request for each person added or removed.
Any other pull request requires at least 1 *+1* binding vote from someone other
than the author of the pull request.
### Timelines
Except in the case of pull requests modifying governance procedures, there are
generally no objective guidelines defining how long pull requests must remain
open for comment. Subjectively speaking though - larger and more potentially
controversial pull requests containing enhancements should remain open for a at
least a few days to give everyone the opportunity to weigh in.
### Vetos
A note on vetos (*-1* votes) taken verbatim from the
[Apache Foundation](http://www.apache.org/foundation/voting.html):
>"A code-modification proposal may be stopped dead in its tracks by a -1 vote
by a qualified voter. This constitutes a veto, and it cannot be overruled nor
overridden by anyone. Vetos stand until and unless withdrawn by their casters.
>
>To prevent vetos from being used capriciously, they must be accompanied by a
technical justification showing why the change is bad (opens a security
exposure, negatively affects performance, etc. ). A veto without a
justification is invalid and has no weight."
For votes regarding non-coding issues such as procedure changes, the requirement
that a veto is accompanied by a *technical* justification is relaxed somewhat,
though a well reasoned justification must still be included.
### Direct Commit Access
The Galaxy *committers* group may only commit directly to Galaxy (i.e. outside
of a pull request and not following the procedures described here) the
following two categories of patches:
* Patches for serious security vulnerabilities.
* Cherry-picking and/or merging of existing approved commits to other
branches.
+19
View File
@@ -1,6 +1,25 @@
module.exports = function(grunt) {
"use strict";
var GALAXY_PATHS = {
dist : '../static/scripts',
maps : '../static/maps',
// this symlink allows us to serve uncompressed scripts in DEV_PATH for use with sourcemaps
srcSymlink : '../static/src',
},
TOOLSHED_PATHS = {
dist : '../static/toolshed/scripts',
maps : '../static/toolshed/maps',
srcSymlink : '../static/toolshed/src',
};
grunt.config.set( 'app', 'galaxy' );
grunt.config.set( 'paths', GALAXY_PATHS );
if( grunt.option( 'app' ) === 'toolshed' ){
grunt.config.set( 'app', grunt.option( 'app' ) );
grunt.config.set( 'paths', TOOLSHED_PATHS );
}
// see the sub directory grunt-tasks/ for individual task definitions
grunt.loadTasks( 'grunt-tasks' );
grunt.registerTask( 'default', [ 'uglify' ] );
+10
View File
@@ -69,3 +69,13 @@ version, you'll need to use the full, local path when calling it:
./node_modules/.bin/grunt
# or
./node_modules/.bin/grunt watch
The Toolshed Client Build
=========================
The commands mentioned above in 'Rebuilding' and 'Grunt watch' also can be applied to toolshed scripts by using the
`--app=toolshed` option:
grunt watch --app=toolshed
grunt --app=toolshed
@@ -0,0 +1,134 @@
define([
"libs/toastr",
"mvc/groups/group-model"
],
function(
mod_toastr,
mod_group_model
) {
// toolshed group detail view
var GroupDetailView = Backbone.View.extend({
el: "#groups_element",
options: {},
app: null,
initialize : function( options ){
this.options = _.extend( this.options, options );
this.app = window.globalTS.groups;
if ( this.app.collection !== null ){
this.model = this.app.collection.get( this.options.group_id );
this.render();
} else {
this.fetchGroup();
}
},
fetchGroup: function( options ){
var that = this;
this.options = _.extend( this.options, options );
this.model = new mod_group_model.Group( { id: this.options.group_id } );
this.model.fetch({
success: function( model ){
console.log( 'received data: ' );
console.log( model );
that.render();
},
error: function( model, response ){
if ( typeof response.responseJSON !== "undefined" ){
mod_toastr.error( response.responseJSON.err_msg );
} else {
mod_toastr.error( 'An error ocurred.' );
}
}
});
},
render: function(){
var template = this.templateRow();
this.$el.html( template( { group: this.model } ) );
$("#center [data-toggle]").tooltip();
},
templateRow: function() {
return _.template([
'<div>',
'<h3><%= group.get("name") %></h3>',
'<p class="" style="color:gray;">',
'A group of <%= group.get("members").length %> members with <%= group.get("repositories").length %> repositories and a total of <%= group.get("total_downloads") %> combined tool downloads.</p>',
'<h3>Members</h3>',
'<table class="grid table table-condensed">',
'<thead>',
'<th>Name</th>',
'<th>Repositories</th>',
'<th>Registered</th>',
'</thead>',
'<tbody>',
'<% _.each(group.get("members"), function(member) { %>',
'<tr>',
'<td>',
'<%= member.username %>',
'</td>',
'<td>',
'<a data-toggle="tooltip" data-placement="top" title="Repositories of <%= member.username %>" href="/repository/browse_repositories_by_user?user_id=<%= member.id %>&use_panels=true" id="<%= member.id %>"><%= member.user_repos_count %></a>',
'</td>',
'<td>',
'<%= member.time_created %>',
'</td>',
'</tr>',
'<% }); %>',
'</tbody>',
'</table>',
'<h3>Repositories</h3>',
'<table class="grid table table-condensed">',
'<thead>',
'<th>Name</th>',
'<th>Description</th>',
'<th>Downloads</th>',
'<th>Owner</th>',
'<th>Created</th>',
'<th>Rating</th>',
'<th>Verified</th>',
'</thead>',
'<tbody>',
'<% _.each(group.get("repositories"), function(repo) { %>',
'<tr>',
'<td>',
'<a data-toggle="tooltip" data-placement="top" title="Details of <%= repo.name %>" href="/view/<%= repo.owner %>/<%= repo.name %>" id="<%= repo.id %>"><%= repo.name %></a>',
'</td>',
'<td>',
'<%= repo.description %>',
'</td>',
'<td>',
'<%= repo.times_downloaded %>',
'</td>',
'<td>',
'<%= repo.owner %>',
'</td>',
'<td>',
'<%= repo.time_created %>',
'</td>',
'<td>',
'<%= repo.ratings_mean %>',
'</td>',
'<td>',
'<%= repo.approved %>',
'</td>',
'</tr>',
'<% }); %>',
'</tbody>',
'</table>',
'</div>'
].join(''));
}
});
return {
GroupDetailView: GroupDetailView
};
});
@@ -0,0 +1,148 @@
define([
"libs/toastr",
"mvc/groups/group-model",
"mvc/groups/group-listrow-view"
], function(
mod_toastr,
mod_group_model,
mod_group_listrow_view
){
var GroupListView = Backbone.View.extend({
el: '#groups_element',
defaults: {},
/**
* Initialize and fetch the groups from server.
* Async render afterwards.
* @param {object} options an object with options
*/
initialize : function( options ){
this.options = _.defaults( this.options || {}, this.defaults, options );
var that = this;
window.globalTS.groups.collection = new mod_group_model.Groups();
window.globalTS.groups.collection.fetch({
success: function( model ){
console.log( 'received data: ' );
console.log( model );
that.render();
},
error: function( model, response ){
if ( typeof response.responseJSON !== "undefined" ){
mod_toastr.error( response.responseJSON.err_msg );
} else {
mod_toastr.error( 'An error ocurred.' );
}
}
});
},
fetch: function(){
},
/**
* Render the groups table from the object's own collection.
*/
render: function ( options ) {
this.options = _.extend( this.options, options );
$( ".tooltip" ).hide();
var template = this.templateGroupsList();
this.$el.html( template( { length: 10, order: 'asc' } ) );
this.renderRows( window.globalTS.groups.collection.models );
$( "#center [data-toggle]" ).tooltip();
$( "#center" ).css( 'overflow','auto' );
},
/**
* Render all given models as rows in the groups list
* @param {array} groups_to_render array of group models to render
*/
renderRows: function( groups_to_render ){
for ( var i = 0; i < groups_to_render.length; i++ ) {
var group = groups_to_render[i];
this.renderOne( { group: group } )
}
},
/**
* Create a view for the given model and add it to the groups view.
* @param {Group} model of the view that will be rendered
*/
renderOne: function( options ){
var rowView = new mod_group_listrow_view.GroupListRowView( options );
this.$el.find( '#group_list_body' ).append( rowView.el );
},
/**
* Table heading was clicked, update sorting preferences and re-render.
* @return {[type]} [description]
*/
// sort_clicked : function(){
// if (Galaxy.libraries.preferences.get('sort_order') === 'asc'){
// Galaxy.libraries.preferences.set({'sort_order': 'desc'});
// } else {
// Galaxy.libraries.preferences.set({'sort_order': 'asc'});
// }
// this.render();
// },
/**
* Sort the underlying collection according to the parameters received.
* Currently supports only sorting by name.
*/
// sortLibraries: function(){
// if (Galaxy.libraries.preferences.get('sort_by') === 'name'){
// if (Galaxy.libraries.preferences.get('sort_order') === 'asc'){
// this.collection.sortByNameAsc();
// } else if (Galaxy.libraries.preferences.get('sort_order') === 'desc'){
// this.collection.sortByNameDesc();
// }
// }
// },
// redirectToHome: function(){
// window.location = '../';
// },
// redirectToLogin: function(){
// window.location = '/user/login';
// },
// MMMMMMMMMMMMMMMMMM
// === TEMPLATES ====
// MMMMMMMMMMMMMMMMMM
templateGroupsList: function(){
tmpl_array = [];
tmpl_array.push('<div id="groups">');
tmpl_array.push('</div>');
tmpl_array.push('<div class="groups_container table-responsive">');
tmpl_array.push('<% if(length === 0) { %>');
tmpl_array.push('<div>There are no groups yet.</div>');
tmpl_array.push('<% } else{ %>');
tmpl_array.push('<table class="grid table table-condensed">');
tmpl_array.push(' <thead>');
tmpl_array.push(' <th style="width:30%;"><a class="sort-groups-link" title="Click to reverse order" href="#">name</a> <span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>');
tmpl_array.push(' <th style="width:22%;">description</th>');
tmpl_array.push(' <th style="width:22%;">members</th> ');
tmpl_array.push(' <th style="width:26%;">repositories</th>');
tmpl_array.push(' </thead>');
tmpl_array.push(' <tbody id="group_list_body">');
// group item views will attach here
tmpl_array.push(' </tbody>');
tmpl_array.push('</table>');
tmpl_array.push('<% }%>');
tmpl_array.push('</div>');
return _.template(tmpl_array.join(''));
},
});
return {
GroupListView: GroupListView
};
});
@@ -0,0 +1,36 @@
define([],
function() {
// toolshed group row view
var GroupListRowView = Backbone.View.extend({
events: {},
initialize : function( options ){
this.render( options.group );
},
render: function( group ){
var tmpl = this.templateRow();
this.setElement(tmpl( { group:group } ));
this.$el.show();
return this;
},
templateRow: function() {
return _.template([
'<tr class="" data-id="<%- group.get("id") %>">',
'<td><a href="groups#/<%= group.get("id") %>"><%= group.get("name") %></a></td>',
'<td>description</td>',
'<td><%= group.get("total_members") %></td>',
'<td><%= group.get("total_repos") %></td>',
'</tr>'
].join(''));
}
});
return {
GroupListRowView: GroupListRowView
};
});
@@ -0,0 +1,22 @@
define([], function() {
// ============================================================================
// LIBRARY RELATED MODELS
var Group = Backbone.Model.extend({
urlRoot: '/api/groups',
});
var Groups = Backbone.Collection.extend({
url: '/api/groups',
model: Group,
});
return {
Group: Group,
Groups: Groups
};
});
+51
View File
@@ -0,0 +1,51 @@
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// === MAIN TOOLSHED GROUP MODULE ====
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
define([
"mvc/groups/group-list-view",
"mvc/groups/group-detail-view",
"mvc/groups/group-model"
],
function(
mod_group_list,
mod_group_detail,
mod_group_model
) {
// ============================================================================
// ROUTER
var ToolshedRouter = Backbone.Router.extend({
routes: {
"" : "groups",
":group_id" : "group_page"
}
});
var ToolshedGroups = Backbone.View.extend({
groupListView: null,
groupDetailView: null,
collection: null,
initialize : function(){
window.globalTS.groups = this;
this.ts_router = new ToolshedRouter();
this.ts_router.on( 'route:groups', function() {
window.globalTS.groups.groupListView = new mod_group_list.GroupListView();
});
this.ts_router.on( 'route:group_page', function( group_id ) {
window.globalTS.groups.groupDetailView = new mod_group_detail.GroupDetailView( { group_id: group_id } );
});
Backbone.history.start({pushState: false});
}
});
return {
ToolshedGroups: ToolshedGroups
};
});
+8
View File
@@ -134,6 +134,14 @@ body {
#left-border {
left: 250px;
}
.reports-panel-container {
position: absolute;
top: @panel_header_height;
bottom: 10px;
overflow: scroll;
width: 100%;
padding: 10px;
}
#center {
left:250 + @border-default-color_padding;
right: 250 + @border-default-color_padding;
+26 -33
View File
@@ -6,25 +6,22 @@
module.exports = function( grunt ){
"use strict";
var DIST_PATH = '../static/scripts',
MAPS_PATH = '../static/maps',
// this symlink allows us to serve uncompressed scripts in DEV_PATH for use with sourcemaps
SRC_SYMLINK = '../static/src';
var app = grunt.config.get( 'app' ),
paths = grunt.config.get( 'paths' );
// compress javascript
grunt.config( 'uglify', {
target : {
files: [{
expand : true,
cwd : SRC_SYMLINK,
cwd : paths.srcSymlink,
src : '**/*.js',
dest : DIST_PATH
dest : paths.dist
}],
options : {
sourceMap : true,
sourceMapName : function( path ){
// rewrite name to have all source maps in 'static/maps'
return path.replace( DIST_PATH, MAPS_PATH ) + '.map';
return path.replace( paths.dist, paths.maps ) + '.map';
}
}
},
@@ -53,19 +50,6 @@ module.exports = function( grunt ){
}
});
// use 'grunt watch' (from a new tab in your terminal) to have grunt re-copy changed files automatically
grunt.config( 'watch', {
watch: {
// watch for changes in the src dir
files: [ SRC_SYMLINK + '/**' ],
tasks: [ 'uglify' ],
// tasks: [ 'copy', 'pack' ],
options: {
spawn: false
}
},
});
// -------------------------------------------------------------------------- decompress for easier debugging
grunt.registerTask( 'decompress', function(){
grunt.log.writeln( "decompressing... (don't forget to call 'grunt' again before committing)" );
@@ -76,10 +60,18 @@ module.exports = function( grunt ){
// alias for symmetry
grunt.registerTask( 'compress', [ 'uglify' ] );
// -------------------------------------------------------------------------- copy,pack only those changed
// adapted from grunt-contrib-watch jslint example
//TODO: a bit hacky and there's prob. a better way
//NOTE: copy will fail silently if a file isn't found
// -------------------------------------------------------------------------- watch & copy,pack only those changed
// use 'grunt watch' (from a new tab in your terminal) to have grunt re-copy changed files automatically
grunt.config( 'watch', {
watch: {
// watch for changes in the src dir
files: [ paths.srcSymlink + '/**' ],
tasks: [ 'uglify' ],
options: {
spawn: false
}
}
});
// outer scope variable for the event handler and onChange fn - begin with empty hash
var changedFiles = Object.create(null);
@@ -89,23 +81,24 @@ module.exports = function( grunt ){
grunt.log.writeln( 'onChange, changedFiles:', Object.keys( changedFiles ) );
grunt.config( 'uglify.target.files', [{
expand : true,
cwd : SRC_SYMLINK,
cwd : paths.srcSymlink,
src : Object.keys( changedFiles ),
dest : DIST_PATH
dest : paths.dist
}]);
changedFiles = Object.create(null);
}, 200);
grunt.event.on( 'watch', function( action, filepath ) {
var addChangedFile = function( action, filepath ) {
// store each filepath in a Files obj, the debounced fn above will use it as an aggregate list for copying
// we need to take galaxy/scripts out of the filepath or it will be copied to the wrong loc
filepath = filepath.replace( SRC_SYMLINK + '/', '' );
grunt.log.writeln( 'on.watch, filepath:', filepath );
changedFiles[filepath] = action;
filepath = filepath.replace( paths.srcSymlink + '/', '' );
// grunt.log.writeln( 'on.watch, filepath:', filepath );
changedFiles[ filepath ] = action;
onChange();
});
};
grunt.event.on( 'watch', addChangedFile );
// --------------------------------------------------------------------------
grunt.loadNpmTasks( 'grunt-contrib-watch' );
grunt.loadNpmTasks( 'grunt-contrib-uglify' );
};
+3
View File
@@ -0,0 +1,3 @@
define( [], function() {
return 'Remove this file';
});
+96
View File
@@ -272,6 +272,102 @@
<datatype extension="rdf" type="galaxy.datatypes.graph:Rdf" display_in_upload="true"/>
<!-- Excel datatypes -->
<datatype extension="xlsx" type="galaxy.datatypes.binary:Xlsx" display_in_upload="true" />
<datatype extension="btwisted" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="cai" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="charge" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="checktrans" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="chips" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="codcmp" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="coderet" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="compseq" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="cpgplot" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="cpgreport" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="cusp" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="cut" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="dan" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="digest" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="dreg" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="einverted" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="epestfind" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="equicktandem" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="est2genome" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="etandem" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="freak" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="fuzznuc" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="fuzzpro" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="fuzztran" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="garnier" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="geecee" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="helixturnhelix" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="hmoment" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="isochore" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="match" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="nametable" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="needle" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="newcpgreport" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="newcpgseek" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="noreturn" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="palindrome" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="pepcoil" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="pepinfo" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="pepstats" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="polydot" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="preg" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="prettyseq" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="primersearch" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="showfeat" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="showorf" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="sixpack" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="strider" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="supermatcher" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="syco" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="textsearch" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="vectorstrip" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="wobble" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="wordcount" type="galaxy.datatypes.data:Text" subclass="True"/>
<!-- Report formats http://emboss.sourceforge.net/docs/themes/ReportFormats.html -->
<datatype extension="dbmotif" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="diffseq" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="excel" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="feattable" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="motif" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="regions" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="seqtable" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="simple" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="table" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="tagseq" type="galaxy.datatypes.data:Text" subclass="True"/>
<!-- Sequence formats http://emboss.sourceforge.net/docs/themes/SequenceFormats.html -->
<datatype extension="acedb" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="clustal" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="codata" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="embl" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="fitch" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="gcg" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="genbank" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="hennig86" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="ig" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="jackknifer" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="jackknifernon" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="mega" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="meganon" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="ncbi" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="nexus" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="nexusnon" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="phylip" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="phylipnon" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="pir" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="staden" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="swiss" type="galaxy.datatypes.data:Text" subclass="True"/>
<!-- Alignment Formats http://emboss.sourceforge.net/docs/themes/AlignFormats.html -->
<datatype extension="markx0" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="markx1" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="markx10" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="markx2" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="markx3" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="pair" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="score" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="srs" type="galaxy.datatypes.data:Text" subclass="True"/>
<datatype extension="srspair" type="galaxy.datatypes.data:Text" subclass="True"/>
<!-- MSA Datatypes -->
<datatype extension="hmm2" type="galaxy.datatypes.msa:Hmmer2" display_in_upload="true" />
<datatype extension="hmm3" type="galaxy.datatypes.msa:Hmmer3" display_in_upload="true" />
+86
View File
@@ -0,0 +1,86 @@
==================================
Galaxy Core Governance
==================================
This document informally outlines the organizational structure governing the
Galaxy core code base hosted at https://github.com/galaxyproject/galaxy. This
governance extends to code-related activities of this repository such as
releases and packaging. This governance does not include infrastructure such
as Galaxy's Trello board, the Galaxy mailing lists, etc... or other Galaxy-
related projects belonging to the ``galaxyproject`` organization on GitHub.
Committers
==========
The `committers` group is the group of trusted developers and advocates who
manage the core Galaxy code base. They assume many roles required to achieve
the project's goals, especially those that require a high level of trust.
Galaxy Project `committers` are the only individuals who may commit to the
core Galaxy code base. All commits must be made in accordance with procedures
outlined in Galaxy's CONTRIBUTING_ document. In particular, in most cases
direct commit access is not allowed and this access is restricted to merging
pull requests issued by others.
Committers may participate in formal votes - these votes typically include
votes to modify team membership, merge pull requests, and modify or clarify
the procedures outlined in this document and CONTRIBUTING_.
Members
----------
- Enis Afgan (@afgane)
- Dannon Baker (@dannon)
- Daniel Blankenberg (@blankenberg)
- Dave Bouvier (@davebx)
- Martin Čech (@martenson)
- John Chilton (@jmchilton)
- Dave Clements (@tnabtaf)
- Nate Coraor (@natefoo)
- Carl Eberhard (@carlfeberhard)
- Jeremy Goecks (@jgoecks)
- Björn Grüning (@bgruening)
- Aysam Guerler (@guerler)
- Jennifer Hillman Jackson (@jennaj)
- Ross Lazarus (@fubar2)
- Anton Nekrutenko (@nekrut)
- Eric Rasche (@erasche)
- Nicola Soranzo (@nsoranzo)
- James Taylor (@jxtx)
- Nitesh Turaga (@nitesh1989)
Membership
----------
The `committers` group was seeded with the group of active developers and
advocates with commit access to the repository as of May 2015. This group
subsequently voted in new members.
Any member of the `committers` group may nominate an individual for membership
to the `committers` group. Such individuals must have demonstrated:
- Good grasp of the design of Galaxy core project.
- Solid track record of being constructive and helpful.
- Significant contributions to the project.
- Willingness to dedicate some time to improving Galaxy.
The above list of `committers` is the canonical source used to determine
membership to the `committers` group - as such new members may be added to
this group by opening a pull request adding a qualified person to this list.
Pull requests modifying the membership of this list are subject to the normal
rules for pull requests that modify governance procedures outlined in Galaxy's
CONTRIBUTING_ document - with one exception - a `commmitter` may not vote
against their own removal from the group (for obvious reasons).
Given the responsibilities and power invested in this group - it is important
that individuals not actively working on Galaxy in some fashion are removed
the group. If individuals in this group intend to change jobs or reallocate
volunteer activities and will no longer be active in the Galaxy community,
they should withdraw from membership of this group. Periodically, active
members may review this group and request inactive members are removed - this
should not be interpreted as a condemnation of these inactive members but
merely as a reflection of a desire to keep this group focused enough to remain
effective.
.. _LICENSE: https://github.com/galaxyproject/galaxy/blob/dev/LICENSE.txt
.. _CONTRIBUTING: https://github.com/galaxyproject/galaxy/blob/dev/CONTRIBUTING.md
+21
View File
@@ -114,6 +114,27 @@ class Ab1( Binary ):
Binary.register_unsniffable_binary_ext("ab1")
class Idat( Binary ):
"""Binary data in idat format"""
file_ext = "idat"
def __init__( self, **kwd ):
Binary.__init__( self, **kwd )
def sniff( self, filename ):
try:
header = open( filename ).read(4)
if binascii.b2a_hex( header ) == binascii.hexlify( 'IDAT' ):
return True
return False
except:
return False
Binary.register_sniffable_binary_format("idat", "idat", Idat)
class CompressedArchive( Binary ):
"""
Class describing an compressed binary file
+1 -1
View File
@@ -208,7 +208,7 @@ class Registry( object ):
for mod in fields:
module = getattr( module, mod )
datatype_class = getattr( module, datatype_class_name )
self.log.debug( 'Retrieved datatype module %s from the datatype registry.' % str( datatype_module ) )
self.log.debug( 'Retrieved datatype module %s:%s from the datatype registry.' % ( str( datatype_module ), datatype_class_name ) )
except Exception, e:
self.log.exception( 'Error importing datatype module %s: %s' % ( str( datatype_module ), str( e ) ) )
ok = False
+1 -1
View File
@@ -2144,7 +2144,7 @@ class Library( object, Dictifiable, HasName ):
"""
rval = super( Library, self ).to_dict( view=view, value_mapper=value_mapper )
if 'root_folder_id' in rval:
rval[ 'root_folder_id' ] = 'F' + rval[ 'root_folder_id' ]
rval[ 'root_folder_id' ] = 'F' + str(rval[ 'root_folder_id' ])
return rval
def get_active_folders( self, folder, folders=None ):
# TODO: should we make sure the library is not deleted?
+31 -2
View File
@@ -13,6 +13,8 @@ import threading
import types
import urllib
import copy
import traceback
from datetime import datetime
from galaxy import eggs, util
@@ -80,6 +82,24 @@ JOB_RESOURCE_CONDITIONAL_XML = """<conditional name="__job_resource">
HELP_UNINITIALIZED = threading.Lock()
class ToolErrorLog:
def __init__(self):
self.error_stack = []
self.max_errors = 100
def add_error(self, file, phase, exception):
self.error_stack.insert(0, {
"file" : file,
"time" : str(datetime.now()),
"phase" : phase,
"error" : str(exception)
} )
if len(self.error_stack) > self.max_errors:
self.error_stack.pop()
global_tool_errors = ToolErrorLog()
class ToolNotFoundException( Exception ):
pass
@@ -103,7 +123,12 @@ class ToolBox( AbstractToolBox ):
return self._tools_by_id
def create_tool( self, config_file, repository_id=None, guid=None, **kwds ):
tool_source = get_tool_source( config_file, getattr( self.app.config, "enable_beta_tool_formats", False ) )
try:
tool_source = get_tool_source( config_file, getattr( self.app.config, "enable_beta_tool_formats", False ) )
except Exception, e:
#capture and log parsing errors
global_tool_errors.add_error(config_file, "Tool XML parsing", e)
raise e
# Allow specifying a different tool subclass to instantiate
tool_module = tool_source.parse_tool_module()
if tool_module is not None:
@@ -460,7 +485,11 @@ class Tool( object, Dictifiable ):
#populate toolshed repository info, if available
self.populate_tool_shed_info()
# Parse XML element containing configuration
self.parse( tool_source, guid=guid )
try:
self.parse( tool_source, guid=guid )
except Exception, e:
global_tool_errors.add_error(config_file, "Tool Loading", e)
raise e
self.external_runJob_script = app.config.drmaa_external_runjob_script
self.history_manager = histories.HistoryManager( app )
+20 -4
View File
@@ -21,6 +21,7 @@ from galaxy.tools.parameters.basic import (
SelectToolParameter,
)
from galaxy.tools.parameters.grouping import Conditional, Repeat, Section
from galaxy.tools import global_tool_errors
from galaxy.jobs.datasets import dataset_path_rewrites
import logging
@@ -400,10 +401,25 @@ class ToolEvaluator( object ):
self.extra_filenames = []
self.command_line = None
self.__build_config_files( )
self.__build_param_file( )
self.__build_command_line( )
try:
self.__build_config_files( )
except Exception, e:
#capture and log parsing errors
global_tool_errors.add_error(self.tool.config_file, "Building Config Files", e)
raise e
try:
self.__build_param_file( )
except Exception, e:
#capture and log parsing errors
global_tool_errors.add_error(self.tool.config_file, "Building Param File", e)
raise e
try:
self.__build_command_line( )
except Exception, e:
#capture and log parsing errors
global_tool_errors.add_error(self.tool.config_file, "Building Command Line", e)
raise e
return self.command_line, self.extra_filenames
def __build_command_line( self ):
+2 -1
View File
@@ -48,7 +48,7 @@ class ToolTestBuilder( object ):
self.name = name
self.maxseconds = maxseconds
self.required_files = []
self.inputs = []
self.inputs = {}
self.outputs = []
# By default do not making assertions on number of outputs - but to
# test filtering allow explicitly state number of outputs.
@@ -134,6 +134,7 @@ class ToolTestBuilder( object ):
self.expect_failure = test_dict.get("expect_failure", False)
self.md5 = test_dict.get("md5", None)
except Exception, e:
self.inputs = {}
self.error = True
self.exception = e
+1 -2
View File
@@ -818,8 +818,7 @@ class GalaxyWebTransaction( base.DefaultWebTransaction,
template = template_lookup.get_template( filename )
template.output_encoding = 'utf-8'
data = dict( caller=self, t=self, trans=self, h=helpers, util=util,
request=self.request, response=self.response, app=self.app )
data = dict( caller=self, t=self, trans=self, h=helpers, util=util, request=self.request, response=self.response, app=self.app )
data.update( self.template_context )
data.update( kwargs )
return template.render( **data )
+32 -4
View File
@@ -2,11 +2,15 @@
Provides factory methods to assemble the Galaxy web application
"""
import atexit
import os
import sys
import atexit
try:
import configparser
except:
import ConfigParser as configparser
from paste import httpexceptions
import pkg_resources
import galaxy.app
from galaxy.config import process_is_uwsgi
@@ -19,6 +23,10 @@ from galaxy import util
from galaxy.util import asbool
from galaxy.util.properties import load_app_properties
from galaxy import eggs
eggs.require('Paste')
from paste import httpexceptions
import logging
log = logging.getLogger( __name__ )
@@ -37,6 +45,10 @@ class GalaxyWebApplication( galaxy.web.framework.webapp.WebApplication ):
def app_factory( global_conf, **kwargs ):
return paste_app_factory( global_conf, **kwargs )
def paste_app_factory( global_conf, **kwargs ):
"""
Return a wsgi application serving the root object
"""
@@ -119,6 +131,22 @@ def app_factory( global_conf, **kwargs ):
return webapp
def uwsgi_app_factory():
import uwsgi
root = os.path.abspath(uwsgi.opt.get('galaxy_root', os.getcwd()))
config_file = uwsgi.opt.get('galaxy_config_file', os.path.join(root, 'config', 'galaxy.ini'))
global_conf = {
'__file__' : config_file if os.path.exists(__file__) else None,
'here' : root }
parser = configparser.ConfigParser()
parser.read(config_file)
try:
kwargs = dict(parser.items('app:main'))
except configparser.NoSectionError:
kwargs = {}
return app_factory(global_conf, **kwargs)
@postfork
def postfork_setup():
from galaxy.app import app
@@ -635,7 +663,7 @@ def wrap_in_middleware( app, global_conf, **local_conf ):
# Interactive exception debugging, scary dangerous if publicly
# accessible, if not enabled we'll use the regular error printing
# middleware.
pkg_resources.require( "WebError" )
eggs.require( "WebError" )
from weberror import evalexception
app = evalexception.EvalException( app, conf,
templating_formatters=build_template_error_formatters() )
@@ -18,6 +18,7 @@ from galaxy.web.base.controller import BaseUIController, UsesQuotaMixin
from galaxy.web.base.controllers.admin import Admin
from galaxy.web.framework.helpers import grids, time_ago
from galaxy.web.params import QuotaParamParser
from galaxy.tools import global_tool_errors
from tool_shed.util import common_util
from tool_shed.util import encoding_util
from tool_shed.util.web_util import escape
@@ -824,6 +825,11 @@ class AdminGalaxy( BaseUIController, Admin, AdminActions, UsesQuotaMixin, QuotaP
message=message,
status=status )
@web.expose
@web.require_admin
def tool_errors( self, trans, **kwd ):
return trans.fill_template('admin/tool_errors.mako', tool_errors=global_tool_errors.error_stack)
@web.expose
@web.require_admin
def view_datatypes_registry( self, trans, **kwd ):
+132
View File
@@ -0,0 +1,132 @@
import logging
from galaxy import util
from galaxy import web
from galaxy.util import pretty_print_time_interval
from galaxy.exceptions import RequestParameterMissingException
from galaxy.exceptions import AdminRequiredException
from galaxy.exceptions import ObjectNotFound
from galaxy.web import require_admin as require_admin
from galaxy.web import _future_expose_api as expose_api
from galaxy.web import _future_expose_api_anonymous_and_sessionless as expose_api_anonymous_and_sessionless
from galaxy.web.base.controller import BaseAPIController
from tool_shed.managers import groups
log = logging.getLogger( __name__ )
class GroupsController( BaseAPIController ):
"""RESTful controller for interactions with groups in the Tool Shed."""
def __init__( self, app ):
super( GroupsController, self ).__init__( app )
self.group_manager = groups.GroupManager()
def __get_value_mapper( self, trans ):
value_mapper = { 'id' : trans.security.encode_id }
return value_mapper
@expose_api_anonymous_and_sessionless
def index( self, trans, deleted=False, **kwd ):
"""
GET /api/groups
Return a list of dictionaries that contain information about each Group.
:param deleted: flag used to include deleted groups
Example: GET localhost:9009/api/groups
"""
group_dicts = []
deleted = util.asbool( deleted )
if deleted and not trans.user_is_admin():
raise AdminRequiredException( 'Only administrators can query deleted groups.' )
for group in self.group_manager.list( trans, deleted ):
group_dicts.append( self._populate( trans, group ) )
return group_dicts
@expose_api
@require_admin
def create( self, trans, payload, **kwd ):
"""
POST /api/groups
Return a dictionary of information about the created group.
The following parameters are included in the payload:
:param name (required): the name of the group
:param description (optional): the description of the group
Example: POST /api/groups/?key=XXXYYYXXXYYY
Content-Disposition: form-data; name="name" Group_Name
Content-Disposition: form-data; name="description" Group_Description
"""
group_dict = dict( message='', status='ok' )
name = payload.get( 'name', '' )
if name:
description = payload.get( 'description', '' )
if not description:
description = ''
else:
# TODO add description field to the model
group_dict = self.group_manager.create( trans, name=name ).to_dict( view='element', value_mapper=self.__get_value_mapper( trans ) )
else:
raise RequestParameterMissingException( 'Missing required parameter "name".' )
return group_dict
@expose_api_anonymous_and_sessionless
def show( self, trans, encoded_id, **kwd ):
"""
GET /api/groups/{encoded_group_id}
Return a dictionary of information about a group.
:param id: the encoded id of the Group object
Example: GET localhost:9009/api/groups/f9cad7b01a472135
"""
decoded_id = trans.security.decode_id( encoded_id )
group = self.group_manager.get( trans, decoded_id )
if group is None:
raise ObjectNotFound( 'Unable to locate group record for id %s.' % ( str( encoded_id ) ) )
return self._populate( trans, group )
def _populate( self, trans, group ):
"""
Turn the given group information from DB into a dict
and add other characteristics like members and repositories.
"""
model = trans.app.model
group_dict = group.to_dict( view='collection', value_mapper=self.__get_value_mapper( trans ) )
group_members = []
group_repos = []
total_downloads = 0
for uga in group.users:
user = trans.sa_session.query( model.User ).filter( model.User.table.c.id == uga.user_id ).one()
user_repos_count = 0
for repo in trans.sa_session.query( model.Repository ) \
.filter( model.Repository.table.c.user_id == uga.user_id ) \
.join( model.RepositoryMetadata.table ) \
.join( model.User.table ) \
.outerjoin( model.RepositoryCategoryAssociation.table ) \
.outerjoin( model.Category.table ):
time_repo_created = pretty_print_time_interval( repo.create_time, True )
approved = ''
ratings = []
for review in repo.reviews:
if review.rating:
ratings.append( review.rating )
if review.approved == 'yes':
approved = 'yes'
# TODO add user ratings
ratings_mean = str( float( sum( ratings ) ) / len( ratings ) ) if len( ratings ) > 0 else ''
total_downloads += repo.times_downloaded
group_repos.append( { 'name': repo.name, 'times_downloaded': repo.times_downloaded, 'owner': repo.user.username, 'time_created': time_repo_created, 'description': repo.description, 'approved': approved, 'ratings_mean': ratings_mean, 'tools': 'unknown' } )
user_repos_count += 1
encoded_user_id = trans.app.security.encode_id( repo.user.id )
user_repos_url = web.url_for( controller='repository', action='browse_repositories_by_user', user_id=encoded_user_id )
time_created = pretty_print_time_interval( user.create_time, True )
member_dict = { 'id': encoded_user_id, 'username': user.username, 'user_repos_url': user_repos_url, 'user_repos_count': user_repos_count, 'user_tools_count': 'unknown', 'time_created': time_created }
group_members.append( member_dict )
group_dict[ 'members' ] = group_members
group_dict[ 'total_members' ] = len( group_members )
group_dict[ 'repositories' ] = group_repos
group_dict[ 'total_repos' ] = len( group_repos )
group_dict[ 'total_downloads' ] = total_downloads
return group_dict
+15
View File
@@ -86,6 +86,21 @@ def app_factory( global_conf, **kwargs ):
controller='authenticate',
action='get_tool_shed_api_key',
conditions=dict( method=[ "GET" ] ) )
webapp.mapper.connect( 'group',
'/api/groups/',
controller='groups',
action='index',
conditions=dict( method=[ "GET" ] ) )
webapp.mapper.connect( 'group',
'/api/groups/',
controller='groups',
action='create',
conditions=dict( method=[ "POST" ] ) )
webapp.mapper.connect( 'group',
'/api/groups/:encoded_id',
controller='groups',
action='show',
conditions=dict( method=[ "GET" ] ) )
webapp.mapper.connect( 'repo_search',
'/api/search/',
controller='search',
@@ -0,0 +1,22 @@
import logging
from galaxy import model, util
from galaxy import web
from galaxy.model.orm import and_, not_, or_
from galaxy.web.base.controller import BaseUIController
from galaxy.web.framework.helpers import escape, grids
log = logging.getLogger( __name__ )
class Group( BaseUIController ):
@web.expose
def index( self, trans, **kwd ):
# define app configuration for generic mako template
app = {
'jscript' : "toolshed.groups"
}
return trans.fill_template( '/webapps/tool_shed/group/index.mako',
config = {
'title': 'Tool Shed Groups',
'app': app } )
@@ -30,7 +30,7 @@ class TagAttributeHandler( object ):
elem_index=sub_index,
elem=sub_elem,
message=message )
if error_message:
if error_message and error_message not in message:
message += error_message
if altered:
if not self.altered:
@@ -68,7 +68,7 @@ class TagAttributeHandler( object ):
altered, new_sub_elem, error_message = self.rdd.handle_sub_elem( parent_elem=elem,
elem_index=sub_index,
elem=sub_elem )
if error_message:
if error_message and error_message not in message:
message += error_message
if altered:
if not self.altered:
@@ -98,7 +98,7 @@ class TagAttributeHandler( object ):
altered, new_sub_elem, error_message = \
self.process_actions_tag_set( elem=sub_elem,
message=message )
if error_message:
if error_message and error_message not in message:
message += error_message
if altered:
if not self.altered:
@@ -150,7 +150,7 @@ class TagAttributeHandler( object ):
( str( package_version ), str( package_name ) )
error_message += 'the recipe for installing the package is missing either an '
error_message += '&lt;actions&gt; tag set or an &lt;actions_group&gt; tag set.'
if error_message:
if error_message and error_message not in message:
message += error_message
if altered:
if not self.altered:
@@ -176,7 +176,7 @@ class TagAttributeHandler( object ):
elem_index=sub_index,
elem=sub_elem,
message=message )
if error_message:
if error_message and error_message not in message:
message += error_message
if altered:
if not self.altered:
@@ -191,7 +191,7 @@ class TagAttributeHandler( object ):
altered, new_elem, error_message = self.rdd.handle_complex_dependency_elem( parent_elem=parent_elem,
elem_index=elem_index,
elem=elem )
if error_message:
if error_message and error_message not in message:
message += error_message
if altered:
if not self.altered:
View File
+120
View File
@@ -0,0 +1,120 @@
"""
Manager and Serializer for TS groups.
"""
from galaxy.exceptions import InconsistentDatabase
from galaxy.exceptions import RequestParameterInvalidException
from galaxy.exceptions import ObjectNotFound
from galaxy.exceptions import InternalServerError
from galaxy.exceptions import ItemAccessibilityException
from galaxy.exceptions import Conflict
from sqlalchemy.orm.exc import MultipleResultsFound
from sqlalchemy.orm.exc import NoResultFound
import logging
log = logging.getLogger( __name__ )
# =============================================================================
class GroupManager( object ):
"""
Interface/service object for interacting with TS groups.
"""
def __init__( self, *args, **kwargs ):
super( GroupManager, self ).__init__( *args, **kwargs )
def get( self, trans, decoded_group_id=None, name=None ):
"""
Get the group from the DB based on its ID or name.
:param decoded_group_id: decoded group id
:type decoded_group_id: int
:returns: the requested group
:rtype: Group
"""
if decoded_group_id is None and name is None:
raise RequestParameterInvalidException( 'You must supply either ID or a name of the group.' )
name_query = trans.sa_session.query( trans.app.model.Group ).filter( trans.app.model.Group.table.c.name == name )
id_query = trans.sa_session.query( trans.app.model.Group ).filter( trans.app.model.Group.table.c.id == decoded_group_id )
try:
group = id_query.one() if decoded_group_id else name_query.one()
except MultipleResultsFound:
raise InconsistentDatabase( 'Multiple groups found with the same id.' )
except NoResultFound:
raise ObjectNotFound( 'No group found with the id provided.' )
except Exception:
raise InternalServerError( 'Error loading from the database.' )
return group
def create( self, trans, name, description=''):
"""
Create a new group.
"""
if not trans.user_is_admin:
raise ItemAccessibilityException( 'Only administrators can create groups.' )
else:
if self.get( trans, name=name ):
raise Conflict( 'Group with the given name already exists. Name: ' + str( name ) )
# TODO add description field to the model
group = trans.app.model.Group( name=name )
trans.sa_session.add( group )
trans.sa_session.flush()
return group
def update( self, trans, group, name=None, description=None ):
"""
Update the given group
"""
changed = False
if not trans.user_is_admin():
raise ItemAccessibilityException( 'Only administrators can update groups.' )
if group.deleted:
raise RequestParameterInvalidException( 'You cannot modify a deleted group. Undelete it first.' )
if name is not None:
group.name = name
changed = True
if description is not None:
group.description = description
changed = True
if changed:
trans.sa_session.add( group )
trans.sa_session.flush()
return group
def delete( self, trans, group, undelete=False ):
"""
Mark given group deleted/undeleted based on the flag.
"""
if not trans.user_is_admin():
raise ItemAccessibilityException( 'Only administrators can delete and undelete groups.' )
if undelete:
group.deleted = False
else:
group.deleted = True
trans.sa_session.add( group )
trans.sa_session.flush()
return group
def list( self, trans, deleted=False ):
"""
Return a list of groups from the DB.
:returns: query that will emit all groups
:rtype: sqlalchemy query
"""
is_admin = trans.user_is_admin()
query = trans.sa_session.query( trans.app.model.Group )
if is_admin:
if deleted is None:
# Flag is not specified, do not filter on it.
pass
elif deleted:
query = query.filter( trans.app.model.Group.table.c.deleted == True )
else:
query = query.filter( trans.app.model.Group.table.c.deleted == False )
else:
query = query.filter( trans.app.model.Group.table.c.deleted == False )
return query
+66
View File
@@ -0,0 +1,66 @@
"""
Manager and Serializer for TS repositories.
"""
from galaxy.exceptions import InconsistentDatabase
from galaxy.exceptions import RequestParameterInvalidException
from galaxy.exceptions import InternalServerError
from sqlalchemy.orm.exc import MultipleResultsFound
from sqlalchemy.orm.exc import NoResultFound
import logging
log = logging.getLogger( __name__ )
# =============================================================================
class RepoManager( object ):
"""
Interface/service object for interacting with TS repositories.
"""
def __init__( self, *args, **kwargs ):
super( RepoManager, self ).__init__( *args, **kwargs )
def get( self, trans, decoded_repo_id ):
"""
Get the repo from the DB.
:param decoded_repo_id: decoded repo id
:type decoded_repo_id: int
:returns: the requested repo
:rtype: Repository
"""
try:
repo = trans.sa_session.query( trans.app.model.Repository ).filter( trans.app.model.Repository.table.c.id == decoded_repo_id ).one()
except MultipleResultsFound:
raise InconsistentDatabase( 'Multiple repositories found with the same id.' )
except NoResultFound:
raise RequestParameterInvalidException( 'No repository found with the id provided.' )
except Exception:
raise InternalServerError( 'Error loading from the database.' )
return repo
def list_by_owner( self, trans, user_id ):
"""
Return a list of of repositories owned by a given TS user from the DB.
:returns: query that will emit repositories owned by given user
:rtype: sqlalchemy query
"""
query = trans.sa_session.query( trans.app.model.Repository ).filter( trans.app.model.Repository.table.c.user_id == user_id )
return query
def create( self, trans, name, description=''):
"""
Create a new group.
"""
def update( self, trans, group, name=None, description=None ):
"""
Update the given group
"""
def delete( self, trans, group, undelete=False ):
"""
Mark given group deleted/undeleted based on the flag.
"""
+1
View File
@@ -17,6 +17,7 @@ cat <<EOF
'${0##*/} -api (test_path)' for running all the test scripts in the ./test/api directory
'${0##*/} -toolshed (test_path)' for running all the test scripts in the ./test/tool_shed/functional directory
'${0##*/} -workflow test.xml' for running a workflow test case as defined by supplied workflow xml test file (experimental)
'${0##*/} -installed' for running tests of Tool Shed installed tools
'${0##*/} -framework' for running through example tool tests testing framework features in test/functional/tools"
'${0##*/} -framework -id toolid' for testing one framework tool (in test/functional/tools/) with id 'toolid'
'${0##*/} -data_managers -id data_manager_id' for testing one Data Manager with id 'data_manager_id'
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"version":3,"file":"group-detail-view.js","sources":["../../../src/mvc/groups/group-detail-view.js"],"names":["define","mod_toastr","mod_group_model","GroupDetailView","Backbone","View","extend","el","options","app","initialize","this","_","window","globalTS","groups","collection","model","get","group_id","render","fetchGroup","that","Group","id","fetch","success","console","log","error","response","responseJSON","err_msg","template","templateRow","$el","html","group","$","tooltip","join"],"mappings":"AAAAA,QACI,cACA,0BAEJ,SACIC,EACAC,GAIJ,GAAIC,GAAkBC,SAASC,KAAKC,QAChCC,GAAI,kBACJC,WACAC,IAAK,KAELC,WAAa,SAAUF,GACnBG,KAAKH,QAAUI,EAAEN,OAAQK,KAAKH,QAASA,GACvCG,KAAKF,IAAMI,OAAOC,SAASC,OAEE,OAAxBJ,KAAKF,IAAIO,YACVL,KAAKM,MAAQN,KAAKF,IAAIO,WAAWE,IAAKP,KAAKH,QAAQW,UACnDR,KAAKS,UAELT,KAAKU,cAKbA,WAAY,SAAUb,GAClB,GAAIc,GAAOX,IACXA,MAAKH,QAAUI,EAAEN,OAAQK,KAAKH,QAASA,GACvCG,KAAKM,MAAQ,GAAIf,GAAgBqB,OAASC,GAAIb,KAAKH,QAAQW,WAC3DR,KAAKM,MAAMQ,OACTC,QAAS,SAAUT,GACjBU,QAAQC,IAAK,mBACbD,QAAQC,IAAKX,GACbK,EAAKF,UAEPS,MAAO,SAAUZ,EAAOa,GAElB7B,EAAW4B,MADyB,mBAA1BC,GAASC,aACDD,EAASC,aAAaC,QAEtB,yBAM9BZ,OAAQ,WACJ,GAAIa,GAAWtB,KAAKuB,aACpBvB,MAAKwB,IAAIC,KAAMH,GAAYI,MAAO1B,KAAKM,SACvCqB,EAAE,yBAAyBC,WAG/BL,YAAa,WACT,MAAOtB,GAAEqB,UACD,QACI,oCACA,mCACA,kMAEA,mBACA,6CACI,UACI,gBACA,wBACA,sBACJ,WACA,UACI,wDACA,OACI,OACI,yBACJ,QACA,OACI,gPACJ,QACA,OACI,6BACJ,QACJ,QACA,YACJ,WACJ,WAEA,wBACA,6CACI,UACI,gBACA,uBACA,qBACA,iBACA,mBACA,kBACA,oBACJ,WACA,UACI,2DACA,OACI,OACI,6KACJ,QACA,OACI,0BACJ,QACA,OACI,+BACJ,QACA,OACI,oBACJ,QACA,OACI,2BACJ,QACA,OACI,2BACJ,QACA,OACI,uBACJ,QACJ,QACA,YACJ,WACJ,WACJ,UACNO,KAAK,OAGf,QACIrC,gBAAiBA"}
@@ -0,0 +1 @@
{"version":3,"file":"group-groupdetail-view.js","sources":["../../../src/mvc/groups/group-groupdetail-view.js"],"names":["define","GroupDetailView","Backbone","View","extend","events","initialize","group","this","render","tmpl","templateRow","setElement","$el","show","_","template","join"],"mappings":"AAAAA,UACA,WAGA,GAAIC,GAAkBC,SAASC,KAAKC,QAChCC,UAGAC,WAAa,SAAUC,GACnBC,KAAKC,OAAQF,IAGjBE,OAAQ,SAAUF,GACd,GAAIG,GAAOF,KAAKG,aAGhB,OAFAH,MAAKI,WAAWF,GAAQH,MAAMA,KAC9BC,KAAKK,IAAIC,OACFN,MAGXG,YAAa,WACT,MAAOI,GAAEC,UACD,8BACNC,KAAK,OAKf,QACIhB,gBAAiBA"}
@@ -0,0 +1 @@
{"version":3,"file":"group-grouprow-view.js","sources":["../../../src/mvc/groups/group-grouprow-view.js"],"names":["define","GroupRowView","Backbone","View","extend","events","initialize","group","this","render","tmpl","templateRow","setElement","$el","show","_","template","join"],"mappings":"AAAAA,UACA,WAGA,GAAIC,GAAeC,SAASC,KAAKC,QAC7BC,UAGAC,WAAa,SAAUC,GACnBC,KAAKC,OAAOF,IAGhBE,OAAQ,SAAUF,GACd,GAAIG,GAAOF,KAAKG,aAIhB,OAFAH,MAAKI,WAAWF,GAAQH,MAAMA,KAC9BC,KAAKK,IAAIC,OACFN,MAaXG,YAAa,WACT,MAAOI,GAAEC,UACD,iDACA,iFACA,uBACA,6CACA,2CACA,SACNC,KAAK,OAKf,QACIhB,aAAcA"}
@@ -0,0 +1 @@
{"version":3,"file":"group-list-view.js","sources":["../../../src/mvc/groups/group-list-view.js"],"names":["define","mod_toastr","mod_group_model","mod_group_listrow_view","GroupListView","Backbone","View","extend","el","defaults","initialize","options","this","_","that","window","globalTS","groups","collection","Groups","fetch","success","model","console","log","render","error","response","responseJSON","err_msg","$","hide","template","templateGroupsList","$el","html","length","order","renderRows","models","tooltip","css","groups_to_render","i","group","renderOne","rowView","GroupListRowView","find","append","tmpl_array","push","join"],"mappings":"AAAAA,QACI,cACA,yBACA,iCAED,SACCC,EACAC,EACAC,GAGJ,GAAIC,GAAgBC,SAASC,KAAKC,QAC9BC,GAAI,kBACJC,YAOAC,WAAa,SAAUC,GACnBC,KAAKD,QAAUE,EAAEJ,SAAUG,KAAKD,YAAeC,KAAKH,SAAUE,EAC9D,IAAIG,GAAOF,IACXG,QAAOC,SAASC,OAAOC,WAAa,GAAIhB,GAAgBiB,OACxDJ,OAAOC,SAASC,OAAOC,WAAWE,OAChCC,QAAS,SAAUC,GACjBC,QAAQC,IAAK,mBACbD,QAAQC,IAAKF,GACbR,EAAKW,UAEPC,MAAO,SAAUJ,EAAOK,GAElB1B,EAAWyB,MADyB,mBAA1BC,GAASC,aACDD,EAASC,aAAaC,QAEtB,yBAO9BT,MAAO,aAMPK,OAAQ,SAAWd,GACfC,KAAKD,QAAUE,EAAEN,OAAQK,KAAKD,QAASA,GACvCmB,EAAG,YAAaC,MAChB,IAAIC,GAAWpB,KAAKqB,oBACpBrB,MAAKsB,IAAIC,KAAMH,GAAYI,OAAQ,GAAIC,MAAO,SAC9CzB,KAAK0B,WAAYvB,OAAOC,SAASC,OAAOC,WAAWqB,QACnDT,EAAG,yBAA0BU,UAC7BV,EAAG,WAAYW,IAAK,WAAW,SAOnCH,WAAY,SAAUI,GAClB,IAAM,GAAIC,GAAI,EAAGA,EAAID,EAAiBN,OAAQO,IAAM,CAChD,GAAIC,GAAQF,EAAiBC,EAC7B/B,MAAKiC,WAAaD,MAAOA,MAQjCC,UAAW,SAAUlC,GACjB,GAAImC,GAAU,GAAI3C,GAAuB4C,iBAAkBpC,EAC3DC,MAAKsB,IAAIc,KAAM,oBAAqBC,OAAQH,EAAQtC,KAyCxDyB,mBAAoB,WAuBhB,MAtBAiB,eAEAA,WAAWC,KAAK,qBAChBD,WAAWC,KAAK,UAChBD,WAAWC,KAAK,mDAChBD,WAAWC,KAAK,4BAChBD,WAAWC,KAAK,uCAChBD,WAAWC,KAAK,iBAChBD,WAAWC,KAAK,8CAChBD,WAAWC,KAAK,cAChBD,WAAWC,KAAK,mMAChBD,WAAWC,KAAK,gDAChBD,WAAWC,KAAK,6CAChBD,WAAWC,KAAK,iDAChBD,WAAWC,KAAK,eAChBD,WAAWC,KAAK,mCAEhBD,WAAWC,KAAK,eAChBD,WAAWC,KAAK,YAChBD,WAAWC,KAAK,UAChBD,WAAWC,KAAK,UAETtC,EAAEmB,SAASkB,WAAWE,KAAK,OAK1C,QACIhD,cAAeA"}
@@ -0,0 +1 @@
{"version":3,"file":"group-listrow-view.js","sources":["../../../src/mvc/groups/group-listrow-view.js"],"names":["define","GroupListRowView","Backbone","View","extend","events","initialize","options","this","render","group","tmpl","templateRow","setElement","$el","show","_","template","join"],"mappings":"AAAAA,UACA,WAGA,GAAIC,GAAmBC,SAASC,KAAKC,QACjCC,UAEAC,WAAa,SAAUC,GACnBC,KAAKC,OAAQF,EAAQG,QAGzBD,OAAQ,SAAUC,GACd,GAAIC,GAAOH,KAAKI,aAGhB,OAFAJ,MAAKK,WAAWF,GAAQD,MAAMA,KAC9BF,KAAKM,IAAIC,OACFP,MAGXI,YAAa,WACT,MAAOI,GAAEC,UACD,iDACA,iFACA,uBACA,6CACA,2CACA,SACNC,KAAK,OAKf,QACIjB,iBAAkBA"}
@@ -0,0 +1 @@
{"version":3,"file":"group-model.js","sources":["../../../src/mvc/groups/group-model.js"],"names":["define","Group","Backbone","Model","extend","urlRoot","Groups","Collection","url","model"],"mappings":"AAAAA,UAAW,WAKP,GAAIC,GAAQC,SAASC,MAAMC,QACzBC,QAAS,gBAGPC,EAASJ,SAASK,WAAWH,QAC/BI,IAAK,cAELC,MAAOR,GAIb,QACIA,MAAOA,EACPK,OAAQA"}
@@ -0,0 +1 @@
{"version":3,"file":"group.model.js","sources":["../../../src/mvc/groups/group.model.js"],"names":["define","Group","Backbone","Model","extend","urlRoot","Groups","Collection","url","model"],"mappings":"AAAAA,UAAW,WAKP,GAAIC,GAAQC,SAASC,MAAMC,QACzBC,QAAS,iBAGPC,EAASJ,SAASK,WAAWH,QAC/BI,IAAK,cAELC,MAAOR,GAIb,QACIA,MAAOA,EACPK,OAAQA"}
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"toolshed.groups.js","sources":["../src/toolshed.groups.js"],"names":["define","mod_group_list","mod_group_detail","ToolshedRouter","Backbone","Router","extend","routes",":group_id","ToolshedGroups","View","groupListView","groupDetailView","collection","initialize","window","globalTS","groups","this","ts_router","on","GroupListView","group_id","GroupDetailView","history","start","pushState"],"mappings":"AAIAA,QACQ,6BACA,+BACA,0BAEJ,SACIC,EACAC,GAMR,GAAIC,GAAiBC,SAASC,OAAOC,QACjCC,QACI,GAA4B,SAC5BC,YAA4B,gBAKhCC,EAAiBL,SAASM,KAAKJ,QAC/BK,cAAe,KACfC,gBAAiB,KACjBC,WAAY,KAEZC,WAAa,WACTC,OAAOC,SAASC,OAASC,KAEzBA,KAAKC,UAAY,GAAIhB,GACrBe,KAAKC,UAAUC,GAAI,eAAgB,WAC/BL,OAAOC,SAASC,OAAON,cAAgB,GAAIV,GAAeoB,gBAG9DH,KAAKC,UAAUC,GAAI,mBAAoB,SAAUE,GAC7CP,OAAOC,SAASC,OAAOL,gBAAkB,GAAIV,GAAiBqB,iBAAmBD,SAAUA,MAG/FlB,SAASoB,QAAQC,OAAOC,WAAW,MAI3C,QACIjB,eAAgBA"}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
define(["libs/toastr","mvc/groups/group-model"],function(a,b){var c=Backbone.View.extend({el:"#groups_element",options:{},app:null,initialize:function(a){this.options=_.extend(this.options,a),this.app=window.globalTS.groups,null!==this.app.collection?(this.model=this.app.collection.get(this.options.group_id),this.render()):this.fetchGroup()},fetchGroup:function(c){var d=this;this.options=_.extend(this.options,c),this.model=new b.Group({id:this.options.group_id}),this.model.fetch({success:function(a){console.log("received data: "),console.log(a),d.render()},error:function(b,c){a.error("undefined"!=typeof c.responseJSON?c.responseJSON.err_msg:"An error ocurred.")}})},render:function(){var a=this.templateRow();this.$el.html(a({group:this.model})),$("#center [data-toggle]").tooltip()},templateRow:function(){return _.template(["<div>",'<h3><%= group.get("name") %></h3>','<p class="" style="color:gray;">','A group of <%= group.get("members").length %> members with <%= group.get("repositories").length %> repositories and a total of <%= group.get("total_downloads") %> combined tool downloads.</p>',"<h3>Members</h3>",'<table class="grid table table-condensed">',"<thead>","<th>Name</th>","<th>Repositories</th>","<th>Registered</th>","</thead>","<tbody>",'<% _.each(group.get("members"), function(member) { %>',"<tr>","<td>","<%= member.username %>","</td>","<td>",'<a data-toggle="tooltip" data-placement="top" title="Repositories of <%= member.username %>" href="/repository/browse_repositories_by_user?user_id=<%= member.id %>&use_panels=true" id="<%= member.id %>"><%= member.user_repos_count %></a>',"</td>","<td>","<%= member.time_created %>","</td>","</tr>","<% }); %>","</tbody>","</table>","<h3>Repositories</h3>",'<table class="grid table table-condensed">',"<thead>","<th>Name</th>","<th>Description</th>","<th>Downloads</th>","<th>Owner</th>","<th>Created</th>","<th>Rating</th>","<th>Verified</th>","</thead>","<tbody>",'<% _.each(group.get("repositories"), function(repo) { %>',"<tr>","<td>",'<a data-toggle="tooltip" data-placement="top" title="Details of <%= repo.name %>" href="/view/<%= repo.owner %>/<%= repo.name %>" id="<%= repo.id %>"><%= repo.name %></a>',"</td>","<td>","<%= repo.description %>","</td>","<td>","<%= repo.times_downloaded %>","</td>","<td>","<%= repo.owner %>","</td>","<td>","<%= repo.time_created %>","</td>","<td>","<%= repo.ratings_mean %>","</td>","<td>","<%= repo.approved %>","</td>","</tr>","<% }); %>","</tbody>","</table>","</div>"].join(""))}});return{GroupDetailView:c}});
//# sourceMappingURL=../../../maps/mvc/groups/group-detail-view.js.map
@@ -0,0 +1,2 @@
define([],function(){var a=Backbone.View.extend({events:{},initialize:function(a){this.render(a)},render:function(a){var b=this.templateRow();return this.setElement(b({group:a})),this.$el.show(),this},templateRow:function(){return _.template(["<div>TEST GROUP PAGE</div>"].join(""))}});return{GroupDetailView:a}});
//# sourceMappingURL=../../../maps/mvc/groups/group-groupdetail-view.js.map
@@ -0,0 +1,2 @@
define([],function(){var a=Backbone.View.extend({events:{},initialize:function(a){this.render(a)},render:function(a){var b=this.templateRow();return this.setElement(b({group:a})),this.$el.show(),this},templateRow:function(){return _.template(['<tr class="" data-id="<%- group.get("id") %>">','<td><a href="/groups/<%= group.get("id") %>"><%= group.get("name") %></a></td>',"<td>description</td>",'<td><%= group.get("total_members") %></td>','<td><%= group.get("total_repos") %></td>',"</tr>"].join(""))}});return{GroupRowView:a}});
//# sourceMappingURL=../../../maps/mvc/groups/group-grouprow-view.js.map
@@ -0,0 +1,2 @@
define(["libs/toastr","mvc/groups/group-model","mvc/groups/group-listrow-view"],function(a,b,c){var d=Backbone.View.extend({el:"#groups_element",defaults:{},initialize:function(c){this.options=_.defaults(this.options||{},this.defaults,c);var d=this;window.globalTS.groups.collection=new b.Groups,window.globalTS.groups.collection.fetch({success:function(a){console.log("received data: "),console.log(a),d.render()},error:function(b,c){a.error("undefined"!=typeof c.responseJSON?c.responseJSON.err_msg:"An error ocurred.")}})},fetch:function(){},render:function(a){this.options=_.extend(this.options,a),$(".tooltip").hide();var b=this.templateGroupsList();this.$el.html(b({length:10,order:"asc"})),this.renderRows(window.globalTS.groups.collection.models),$("#center [data-toggle]").tooltip(),$("#center").css("overflow","auto")},renderRows:function(a){for(var b=0;b<a.length;b++){var c=a[b];this.renderOne({group:c})}},renderOne:function(a){var b=new c.GroupListRowView(a);this.$el.find("#group_list_body").append(b.el)},templateGroupsList:function(){return tmpl_array=[],tmpl_array.push('<div id="groups">'),tmpl_array.push("</div>"),tmpl_array.push('<div class="groups_container table-responsive">'),tmpl_array.push("<% if(length === 0) { %>"),tmpl_array.push("<div>There are no groups yet.</div>"),tmpl_array.push("<% } else{ %>"),tmpl_array.push('<table class="grid table table-condensed">'),tmpl_array.push(" <thead>"),tmpl_array.push(' <th style="width:30%;"><a class="sort-groups-link" title="Click to reverse order" href="#">name</a> <span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>'),tmpl_array.push(' <th style="width:22%;">description</th>'),tmpl_array.push(' <th style="width:22%;">members</th> '),tmpl_array.push(' <th style="width:26%;">repositories</th>'),tmpl_array.push(" </thead>"),tmpl_array.push(' <tbody id="group_list_body">'),tmpl_array.push(" </tbody>"),tmpl_array.push("</table>"),tmpl_array.push("<% }%>"),tmpl_array.push("</div>"),_.template(tmpl_array.join(""))}});return{GroupListView:d}});
//# sourceMappingURL=../../../maps/mvc/groups/group-list-view.js.map
@@ -0,0 +1,2 @@
define([],function(){var a=Backbone.View.extend({events:{},initialize:function(a){this.render(a.group)},render:function(a){var b=this.templateRow();return this.setElement(b({group:a})),this.$el.show(),this},templateRow:function(){return _.template(['<tr class="" data-id="<%- group.get("id") %>">','<td><a href="groups#/<%= group.get("id") %>"><%= group.get("name") %></a></td>',"<td>description</td>",'<td><%= group.get("total_members") %></td>','<td><%= group.get("total_repos") %></td>',"</tr>"].join(""))}});return{GroupListRowView:a}});
//# sourceMappingURL=../../../maps/mvc/groups/group-listrow-view.js.map
+2
View File
@@ -0,0 +1,2 @@
define([],function(){var a=Backbone.Model.extend({urlRoot:"/api/groups"}),b=Backbone.Collection.extend({url:"/api/groups",model:a});return{Group:a,Groups:b}});
//# sourceMappingURL=../../../maps/mvc/groups/group-model.js.map
+2
View File
@@ -0,0 +1,2 @@
define([],function(){var a=Backbone.Model.extend({urlRoot:"/api/groups/"}),b=Backbone.Collection.extend({url:"/api/groups",model:a});return{Group:a,Groups:b}});
//# sourceMappingURL=../../../maps/mvc/groups/group.model.js.map
+2
View File
@@ -0,0 +1,2 @@
define(["mvc/groups/group-list-view","mvc/groups/group-detail-view","mvc/groups/group-model"],function(a,b){var c=Backbone.Router.extend({routes:{"":"groups",":group_id":"group_page"}}),d=Backbone.View.extend({groupListView:null,groupDetailView:null,collection:null,initialize:function(){window.globalTS.groups=this,this.ts_router=new c,this.ts_router.on("route:groups",function(){window.globalTS.groups.groupListView=new a.GroupListView}),this.ts_router.on("route:group_page",function(a){window.globalTS.groups.groupDetailView=new b.GroupDetailView({group_id:a})}),Backbone.history.start({pushState:!1})}});return{ToolshedGroups:d}});
//# sourceMappingURL=../maps/toolshed.groups.js.map
+1
View File
@@ -1761,6 +1761,7 @@ body{background:#fff;color:#000;margin:10px}body.full-content{overflow:hidden;ma
#left,#left-border,#center,#right-border,#right{position:absolute;top:34px;bottom:0px;overflow:hidden;background:#fff}
#left{left:0px;width:250px;z-index:200;border-right:solid #999 1px}
#left-border{left:250px}
.reports-panel-container{position:absolute;top:30px;bottom:10px;overflow:scroll;width:100%;padding:10px}
#center{left:250px;right:250px;overflow:hidden;z-index:1}
#right-border{right:250px}
#right{width:250px;right:0px;z-index:200;border-left:solid #999 1px}
+1
View File
@@ -0,0 +1 @@
../../client/toolshed/scripts/
+27
View File
@@ -0,0 +1,27 @@
<%inherit file="/base.mako"/>
<%def name="title()">Tool Errors</%def>
<h2>Tool Errors</h2>
<p>
Internal Tool Error log
</p>
<table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr class="header">
<td>Time</td>
<td>Phase</td>
<td>File</td>
<td>Error</td>
</tr>
%for error in tool_errors:
<tr>
<td>${error['time']}</td>
<td>${error['phase']}</td>
<td>${error['file']}</td>
<td>${error['error']}</td>
</tr>
%endfor
</table>
-1
View File
@@ -6,7 +6,6 @@
if kwargs.get( 'embedded', False ):
# No inheritance - using only embeddable content (self.body)
return None
if context.get('use_panels'):
if context.get('webapp'):
app_name = context.get('webapp')
@@ -73,6 +73,7 @@
<div class="toolTitle"><a href="${h.url_for( controller='admin', action='tool_versions' )}" target="galaxy_main">Tool lineage</a></div>
<div class="toolTitle"><a href="${h.url_for( controller='admin', action='reload_tool' )}" target="galaxy_main">Reload a tool's configuration</a></div>
<div class="toolTitle"><a href="${h.url_for( controller='admin', action='review_tool_migration_stages' )}" target="galaxy_main">Review tool migration stages</a></div>
<div class="toolTitle"><a href="${h.url_for( controller='admin', action='tool_errors' )}" target="galaxy_main">View Tool Error Logs</a></div>
</div>
</div>
<div class="toolSectionPad"></div>
+1 -1
View File
@@ -36,7 +36,7 @@
<div class="unified-panel-header" unselectable="on">
<div class='unified-panel-header-inner'>Reports</div>
</div>
<div class="page-container" style="padding: 10px;">
<div class="page-container reports-panel-container">
<div class="toolMenu">
<div class="toolSectionList">
<div class="toolSectionPad"></div>
@@ -80,6 +80,9 @@
## Repositories tab.
${tab( "repositories", "Repositories", h.url_for( controller='/repository', action='index' ) )}
## Groups tab.
${tab( "groups", "Groups", h.url_for( controller='/groups', action='index' ) )}
## Admin tab.
${tab( "admin", "Admin", h.url_for( controller='/admin', action='index' ), extra_class="admin-only", visible=( trans.user and app.config.is_admin_user( trans.user ) ) )}
@@ -0,0 +1,50 @@
<%inherit file="/webapps/tool_shed/base_panels.mako"/>
<%namespace file="/message.mako" import="render_msg" />
<%def name="stylesheets()">
## Include "base.css" for styling tool menu and forms (details)
${h.css( "base", "autocomplete_tagging", "tool_menu" )}
## But make sure styles for the layout take precedence
${parent.stylesheets()}
<style type="text/css">
body { margin: 0; padding: 0; overflow: hidden; }
#left {
background: #C1C9E5 url(${h.url_for('/static/style/menu_bg.png')}) top repeat-x;
}
.unified-panel-body {
overflow: auto;
}
.toolMenu {
margin-left: 10px;
}
</style>
</%def>
<%def name="javascripts()">
${parent.javascripts()}
</%def>
<%def name="init()">
%if trans.app.config.require_login and not trans.user:
<script type="text/javascript">
if ( window != top ) {
top.location.href = location.href;
}
</script>
%endif
</%def>
<%def name="center_panel()">
<script type="text/javascript">
window.globalTS = new Object();
$( function(){
require([ '${config.get( "app" ).get( "jscript" )}' ], function( groups ){
app = new groups.ToolshedGroups();
});
});
</script>
<div id="groups_element" style="width: 95%; margin:auto; margin-top:2em; "></div>
</%def>