backbone base of TS groups

fix backbone hash problem; some more formatting and API polishing

refactor group API controller; better format group detail view

more formating and refactoring

add column to group detail

update details, add some more info to API response
This commit is contained in:
Martin Cech
2015-06-09 16:13:10 -04:00
parent 7378e445c4
commit cfe9620192
28 changed files with 549 additions and 32 deletions
@@ -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
};
});
+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 )
+53 -29
View File
@@ -3,8 +3,10 @@ import os
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 as expose_api_anonymous
@@ -37,29 +39,12 @@ class GroupsController( BaseAPIController ):
Example: GET localhost:9009/api/groups
"""
model = trans.app.model
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 ):
group_dict = group.to_dict( view='collection', value_mapper=self.__get_value_mapper( trans ) )
group_members = []
for uga in group.users:
member = ( trans.sa_session.query( model.User ).filter( model.User.table.c.id == uga.user_id ).one() )
member_repositories = []
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 ):
member_repositories.append( { 'name': repo.name, 'times_downloaded': repo.times_downloaded } )
member_dict = { 'username' : member.username, 'repositories': member_repositories }
group_members.append( member_dict )
group_dict[ 'members' ] = group_members
group_dicts.append( group_dict )
for group in self.group_manager.list( trans, deleted ):
group_dicts.append( self._populate( trans, group ) )
return group_dicts
@expose_api
@@ -83,8 +68,7 @@ class GroupsController( BaseAPIController ):
description = payload.get( 'description', '' )
if not description:
description = ''
# TODO check existence
# if suc.get_category_by_name( trans.app, name ):
# TODO check group existence
# raise exceptions.Conflict( 'A category with that name already exists.' )
else:
# Create the group
@@ -98,7 +82,7 @@ class GroupsController( BaseAPIController ):
return group_dict
@expose_api_anonymous_and_sessionless
def show( self, trans, id, **kwd ):
def show( self, trans, encoded_id, **kwd ):
"""
GET /api/groups/{encoded_group_id}
Return a dictionary of information about a group.
@@ -107,12 +91,52 @@ class GroupsController( BaseAPIController ):
Example: GET localhost:9009/api/groups/f9cad7b01a472135
"""
# TODO write get group utility function
group = suc.get_group( trans.app, id )
decoded_id = trans.security.decode_id( encoded_id )
group = self.group_manager.get( trans, decoded_id )
if group is None:
group_dict = dict( message = 'Unable to locate group record for id %s.' % ( str( id ) ), status = 'error' )
return group_dict
group_dict = group.to_dict( view='element', value_mapper=self.__get_value_mapper( trans ) )
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
+5
View File
@@ -91,6 +91,11 @@ def app_factory( global_conf, **kwargs ):
controller='groups',
action='index',
conditions=dict( method=[ "GET" ] ) )
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 } )
@@ -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"}
@@ -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
@@ -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')
@@ -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>