Histories: move order parsing into managers; View multi: allow and pass ordering into bootstrapped histories, limit to 10; View multi, client: allow better collection setting and addition

This commit is contained in:
Carl Eberhard
2015-08-21 10:15:38 -04:00
parent 1b64bea779
commit ea130e2c00
9 changed files with 138 additions and 84 deletions
@@ -387,12 +387,16 @@ var HistoryCollection = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).ext
//logger : console,
urlRoot : ( window.galaxy_config? galaxy_config.root : '/' ) + 'api/histories',
//url : function(){ return this.urlRoot; },
url : function(){ return this.urlRoot; },
initialize : function( models, options ){
options = options || {};
this.log( 'HistoryCollection.initialize', arguments );
this.includeDeleted = options.includeDeleted || false;
this.offset = options.offset;
this.limit = options.limit;
this.order = options.order;
//this.on( 'all', function(){
// console.info( 'event:', arguments );
@@ -401,6 +405,17 @@ var HistoryCollection = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).ext
this.setUpListeners();
},
fetch : function( options ){
options = options || {};
if( !this.includeDeleted ){
var data = options.data || {};
data.q = 'deleted';
data.qv = 'False';
options.data = data;
}
Backbone.Collection.prototype.fetch.call( this, options );
},
setUpListeners : function setUpListeners(){
var collection = this;
@@ -414,7 +429,9 @@ var HistoryCollection = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).ext
// listen for a history copy, adding it to the beginning of the collection
this.on( 'copied', function( original, newData ){
this.unshift( new History( newData, [] ) );
var history = new History( newData, [] );
this.unshift( history );
this.trigger( 'new-current', history, this );
});
},
@@ -426,7 +443,7 @@ var HistoryCollection = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).ext
// new histories go in the front
//TODO: (implicit ordering by update time...)
collection.unshift( history );
collection.trigger( 'new-current' );
collection.trigger( 'new-current', history, this );
});
//TODO: move back to using history.save (via Deferred.then w/ set_as_current)
},
@@ -411,12 +411,12 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
// --- set up models, sub-views, and listeners
/** the original unfiltered and unordered collection of histories */
this.collection = null;
this.setCollection( options.histories || [] );
/** model id to column map */
this.columnMap = {};
//TODO: why create here?
this.createColumns( options.columnOptions );
/** model id to column map */
this.columnOptions = options.columnOptions || {};
this.setCollection( options.histories );
this.setUpListeners();
},
@@ -471,14 +471,31 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
/** Set up a (new) history collection, sorting and adding listeners
* @fires 'new-collection' when set with this view as the arg
*/
setCollection : function setCollection( models ){
setCollection : function setCollection( collection ){
this.stopListening( this.collection );
this.collection = collection || new HISTORY_MODEL.HistoryCollection();
this.setUpCollectionListeners();
this.sortCollection( this.order, { silent: true });
this.createColumns();
// multipanel.addModels( collection, { silent: true });
this.trigger( 'new-collection', this );
return this;
},
/** Set up a (new) history collection, sorting and adding listeners
* @fires 'new-collection' when set with this view as the arg
*/
addModels : function setCollection( models, collection, options ){
// options = options || {};
var multipanel = this;
multipanel.stopListening( multipanel.collection );
multipanel.collection = models;
multipanel.sortCollection( multipanel.order, { silent: true });
multipanel.setUpCollectionListeners();
multipanel.trigger( 'new-collection', multipanel );
return multipanel;
models = _.isArray( models )? models : [ models ];
models.forEach( function( model ){
multipanel.addColumn( model, false );
});
// render?
return this;
},
/** Set up listeners for the collection - handling: added histories, change of current, deletion, and sorting */
@@ -486,13 +503,13 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
var multipanel = this,
collection = multipanel.collection;
multipanel.listenTo( collection, {
// handle addition of histories, triggered by column copy and create new
'add': multipanel.addAsCurrentColumn,
'add': multipanel.addModels,
// handle setting a history as current, triggered by history.setAsCurrent
'set-as-current': multipanel.setCurrentHistory,
// handle deleting a history (depends on whether panels is including deleted or not)
'change:deleted change:purged': multipanel.handleDeletedHistory,
// handle addition of histories, triggered by column copy and create new
'new-current': multipanel.addAsCurrentColumn,
'sort' : function(){ multipanel.renderColumns( 0 ); }
});
},
@@ -563,6 +580,7 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
this.collection.sort( options );
return this.collection;
},
//TODO: to setOrder
/** create a new history and set it to current */
create : function( ev ){
@@ -571,11 +589,12 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
// ------------------------------------------------------------------------ columns
/** create columns from collection */
createColumns : function createColumns( columnOptions ){
columnOptions = columnOptions || {};
createColumns : function createColumns( models, columnOptions ){
columnOptions = columnOptions || this.options.columnOptions;
var multipanel = this;
// clear column map
this.columnMap = {};
// TODO: make cummulative
multipanel.columnMap = {};
multipanel.collection.each( function( model, i ){
var column = multipanel.createColumn( model, columnOptions );
multipanel.columnMap[ model.id ] = column;
@@ -595,36 +614,10 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
return column;
},
/** return array of Columns filtered by filters and sorted to match the collection
* @param: filters Function[] array of filter fns
*/
sortedFilteredColumns : function( filters ){
filters = filters || this.filters;
if( !filters || !filters.length ){
return this.sortedColumns();
}
var multipanel = this;
return multipanel.sortedColumns().filter( function( column, index ){
var filtered = column.currentHistory || _.every( filters.map( function( filter ){
return filter.call( column );
}));
return filtered;
});
},
/** return array of Columns sorted to match the collection */
sortedColumns : function(){
var multipanel = this;
var sorted = this.collection.map( function( history, index ){
return multipanel.columnMap[ history.id ];
});
return sorted;
},
/** add a new column for history and render all columns if render is true */
addColumn : function add( history, render ){
//this.debug( 'adding column for:', history );
render = render !== undefined? render: true;
render = render !== undefined? render : true;
var newColumn = this.createColumn( history );
this.columnMap[ history.id ] = newColumn;
if( render ){
@@ -634,7 +627,8 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
},
/** add a new column for history and make it the current history/column */
addAsCurrentColumn : function add( history ){
addAsCurrentColumn : function add( history, collection, options ){
// console.debug( 'addAsCurrentColumn:', history, collection, options );
//this.log( 'adding current column for:', history );
var multipanel = this,
newColumn = this.addColumn( history, false );
@@ -674,7 +668,7 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
multipanel.listenTo( column, {
//'all': function(){ console.info( 'column ' + column + ':', arguments ) },
'in-view': multipanel.queueHdaFetch
});
});
multipanel.listenTo( column.panel, {
//'all': function(){ console.info( 'panel ' + column.panel + ':', arguments ) },
@@ -716,6 +710,32 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
return Object.keys( this.columnMap ).length;
},
/** return array of Columns filtered by filters and sorted to match the collection
* @param: filters Function[] array of filter fns
*/
sortedFilteredColumns : function( filters ){
filters = filters || this.filters;
if( !filters || !filters.length ){
return this.sortedColumns();
}
var multipanel = this;
return multipanel.sortedColumns().filter( function( column, index ){
var filtered = column.currentHistory || _.every( filters.map( function( filter ){
return filter.call( column );
}));
return filtered;
});
},
/** return array of Columns sorted to match the collection */
sortedColumns : function(){
var multipanel = this;
var sorted = this.collection.map( function( history, index ){
return multipanel.columnMap[ history.id ];
});
return sorted;
},
// ------------------------------------------------------------------------ render
/** Render this view, columns, and set up view plugins */
render : function render( speed ){
@@ -969,7 +989,9 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
// when scrolling - check for histories now in view: they will fire 'in-view' and queueHdaLoading if necc.
//TODO:?? might be able to simplify and not use pub-sub
var debouncedInView = _.debounce( function _debouncedInner(){
multipanel.checkColumnsInView();
var viewport = multipanel._viewport();
multipanel.checkColumnsInView( viewport );
multipanel.checkForEndOfScroll( viewport );
}, 100 );
this.$( '.middle' ).parent().scroll( debouncedInView );
},
@@ -994,15 +1016,20 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
/** Get the left and right pixel coords of the middle element */
_viewport : function(){
var viewLeft = this.$( '.middle' ).parent().offset().left;
return { left: viewLeft, right: viewLeft + this.$( '.middle' ).parent().width() };
var $outerMiddle = this.$( '.middle' ).parent(),
viewLeft = $outerMiddle.offset().left,
width = $outerMiddle.width();
return {
left : viewLeft,
right : viewLeft + width
};
},
/** returns the columns currently in the viewport */
columnsInView : function(){
columnsInView : function( viewport ){
//TODO: uses offset which is render intensive
//TODO: 2N - could use arg filter (sortedFilteredColumns( filter )) instead
var vp = this._viewport();
var vp = viewport || this._viewport();
return this.sortedFilteredColumns().filter( function( column ){
return column.currentHistory || column.inView( vp.left, vp.right );
});
@@ -1017,6 +1044,17 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
});
},
/** */
checkForEndOfScroll : function( viewport ){
viewport = viewport || this._viewport();
var END_PADDING = 16,
$middle = this.$( '.middle' ),
scrollRight = $middle.parent().scrollLeft() + viewport.right;
if( scrollRight >= ( $middle.width() - END_PADDING ) ){
this.trigger( 'end-of-scroll' );
}
},
/** Show and enable the current columns drop target */
currentColumnDropTargetOn : function(){
var currentColumn = this.columnMap[ this.currentHistoryId ];
+8 -8
View File
@@ -8,7 +8,7 @@ import pkg_resources
pkg_resources.require( "Paste" )
pkg_resources.require( "SQLAlchemy >= 0.4" )
from sqlalchemy import true, false, desc, asc
from sqlalchemy import true, false
from galaxy import exceptions
from galaxy.web import _future_expose_api as expose_api
@@ -166,6 +166,13 @@ class HistoriesController( BaseAPIController, ExportsHistoryMixin, ImportsHistor
# otherwise, do the default filter of removing the deleted histories
return [ self.app.model.History.deleted == false() ]
def _parse_order_by( self, order_by_string ):
ORDER_BY_SEP_CHAR = ','
manager = self.history_manager
if ORDER_BY_SEP_CHAR in order_by_string:
return [ manager.parse_order_by( o ) for o in order_by_string.split( ORDER_BY_SEP_CHAR ) ]
return manager.parse_order_by( order_by_string )
@expose_api_anonymous
def show( self, trans, id, deleted='False', **kwd ):
"""
@@ -418,10 +425,3 @@ class HistoriesController( BaseAPIController, ExportsHistoryMixin, ImportsHistor
raise exceptions.MessageException( "Export not available or not yet ready." )
return self.serve_ready_history_export( trans, jeha )
def _parse_order_by( self, order_by_string ):
ORDER_BY_SEP_CHAR = ','
manager = self.history_manager
if ORDER_BY_SEP_CHAR in order_by_string:
return [ manager.parse_order_by( o ) for o in order_by_string.split( ORDER_BY_SEP_CHAR ) ]
return manager.parse_order_by( order_by_string )
@@ -628,7 +628,7 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesI
show_deleted=show_deleted, show_hidden=show_hidden, use_panels=use_panels )
@web.expose
def view_multiple( self, trans, include_deleted_histories=False, order='update' ):
def view_multiple( self, trans, include_deleted_histories=False, limit=10, order='update' ):
"""
"""
if not trans.user:
@@ -641,7 +641,9 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesI
# TODO: allow specifying user_id for admin?
include_deleted_histories = galaxy.util.string_as_bool( include_deleted_histories )
order = order if order in ( 'update', 'name', 'size' ) else 'update'
limit = limit if limit != 'None' else None
order = order if order in ( 'update_time', 'name', 'size' ) else 'update_time'
order_by = self.history_manager.parse_order_by( order )
deleted_filter = None
if not include_deleted_histories:
@@ -651,14 +653,15 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesI
current_history_id = trans.security.encode_id( current_history.id ) if current_history else None
history_dictionaries = []
for history in self.history_manager.by_user( trans.user, filters=deleted_filter ):
histories = self.history_manager.by_user( trans.user, filters=deleted_filter, limit=limit, order_by=order_by )
for history in histories:
history_dictionary = self.history_serializer.serialize_to_view( history,
view='detailed', user=trans.user, trans=trans )
view='detailed', user=trans.user, trans=trans )
history_dictionaries.append( history_dictionary )
return trans.fill_template_mako( "history/view_multiple.mako",
current_history_id=current_history_id, histories=history_dictionaries,
include_deleted_histories=include_deleted_histories, order=order )
current_history_id=current_history_id, histories=history_dictionaries,
include_deleted_histories=include_deleted_histories, order=order, limit=limit )
@web.expose
def display_by_username_and_slug( self, trans, username, slug ):
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -29,17 +29,13 @@ define( 'app', function(){
'mvc/history/multi-panel'
], function( HISTORY_MODEL, MULTI_PANEL ){
$(function(){
window.historyJSONArray = bootstrapped.historyJSONArray;
bootstrapped.histories.forEach( function( h ){
console.debug( h.name, h.update_time, h.size );
})
histories = new HISTORY_MODEL.HistoryCollection( bootstrapped.histories, {
includeDeleted : bootstrapped.includingDeleted
});
var historyModels = [];
historyJSONArray.forEach( function( historyJSON ){
if( !historyJSON.purged ){
historyModels.push( new HISTORY_MODEL.History( historyJSON ) );
}
});
histories = new HISTORY_MODEL.HistoryCollection( historyModels, {
includeDeleted : bootstrapped.includingDeleted
});
multipanel = new MULTI_PANEL.MultiPanelColumns({
el : $( '#center' ).get(0),
histories : histories,
@@ -50,6 +46,6 @@ define( 'app', function(){
});
});
</script>
${ galaxy_client.load( app='app', historyJSONArray=histories,
includingDeleted=include_deleted_histories, order=order ) }
${ galaxy_client.load( app='app', histories=histories,
includingDeleted=include_deleted_histories, order=order, limit=limit ) }
</%def>