PageRenderTime 58ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/static/scripts/mvc/history/history-model.js

https://bitbucket.org/hbc/galaxy-central-hbc/
JavaScript | 298 lines | 160 code | 36 blank | 102 comment | 29 complexity | 2bf722438537486d31a5d1dd34cdcb97 MD5 | raw file
Possible License(s): CC-BY-3.0
  1. define([
  2. "mvc/history/history-contents",
  3. "mvc/base-mvc",
  4. "utils/localization"
  5. ], function( HISTORY_CONTENTS, BASE_MVC, _l ){
  6. //==============================================================================
  7. /** @class Model for a Galaxy history resource - both a record of user
  8. * tool use and a collection of the datasets those tools produced.
  9. * @name History
  10. *
  11. * @augments Backbone.Model
  12. * @borrows LoggableMixin#logger as #logger
  13. * @borrows LoggableMixin#log as #log
  14. * @constructs
  15. */
  16. var History = Backbone.Model.extend( BASE_MVC.LoggableMixin ).extend(
  17. /** @lends History.prototype */{
  18. /** logger used to record this.log messages, commonly set to console */
  19. // comment this out to suppress log output
  20. //logger : console,
  21. // values from api (may need more)
  22. defaults : {
  23. model_class : 'History',
  24. id : null,
  25. name : 'Unnamed History',
  26. state : 'new',
  27. diskSize : 0,
  28. deleted : false
  29. },
  30. // ........................................................................ urls
  31. urlRoot: galaxy_config.root + 'api/histories',
  32. // ........................................................................ set up/tear down
  33. /** Set up the model
  34. * @param {Object} historyJSON model data for this History
  35. * @param {Object[]} hdaJSON array of model data for this History's HDAs
  36. * @param {Object} options any extra settings including logger
  37. */
  38. initialize : function( historyJSON, hdaJSON, options ){
  39. options = options || {};
  40. this.logger = options.logger || null;
  41. this.log( this + ".initialize:", historyJSON, hdaJSON, options );
  42. /** HistoryContents collection of the HDAs contained in this history. */
  43. this.log( 'creating history contents:', hdaJSON );
  44. this.hdas = new HISTORY_CONTENTS.HistoryContents( hdaJSON || [], { historyId: this.get( 'id' )});
  45. //// if we've got hdas passed in the constructor, load them
  46. //if( hdaJSON && _.isArray( hdaJSON ) ){
  47. // this.log( 'resetting history contents:', hdaJSON );
  48. // this.hdas.reset( hdaJSON );
  49. //}
  50. this._setUpListeners();
  51. /** cached timeout id for the HDA updater */
  52. this.updateTimeoutId = null;
  53. // set up update timeout if needed
  54. //this.checkForUpdates();
  55. },
  56. /** set up any event listeners for this history including those to the contained HDAs
  57. * events: error:hdas if an error occurred with the HDA collection
  58. */
  59. _setUpListeners : function(){
  60. this.on( 'error', function( model, xhr, options, msg, details ){
  61. this.errorHandler( model, xhr, options, msg, details );
  62. });
  63. // hda collection listening
  64. if( this.hdas ){
  65. this.listenTo( this.hdas, 'error', function(){
  66. this.trigger.apply( this, [ 'error:hdas' ].concat( jQuery.makeArray( arguments ) ) );
  67. });
  68. }
  69. // if the model's id changes ('current' or null -> an actual id), update the hdas history_id
  70. this.on( 'change:id', function( model, newId ){
  71. if( this.hdas ){
  72. this.hdas.historyId = newId;
  73. }
  74. }, this );
  75. },
  76. //TODO: see base-mvc
  77. //onFree : function(){
  78. // if( this.hdas ){
  79. // this.hdas.free();
  80. // }
  81. //},
  82. /** event listener for errors. Generally errors are handled outside this model */
  83. errorHandler : function( model, xhr, options, msg, details ){
  84. // clear update timeout on model err
  85. this.clearUpdateTimeout();
  86. },
  87. // ........................................................................ common queries
  88. /** T/F is this history owned by the current user (Galaxy.currUser)
  89. * Note: that this will return false for an anon user even if the history is theirs.
  90. */
  91. ownedByCurrUser : function(){
  92. // no currUser
  93. if( !Galaxy || !Galaxy.currUser ){
  94. return false;
  95. }
  96. // user is anon or history isn't owned
  97. if( Galaxy.currUser.isAnonymous() || Galaxy.currUser.id !== this.get( 'user_id' ) ){
  98. return false;
  99. }
  100. return true;
  101. },
  102. hdaCount : function(){
  103. return _.reduce( _.values( this.get( 'state_details' ) ), function( memo, num ){ return memo + num; }, 0 );
  104. },
  105. // ........................................................................ ajax
  106. /** does the HDA collection indicate they're still running and need to be updated later? delay + update if needed
  107. * @param {Function} onReadyCallback function to run when all HDAs are in the ready state
  108. * events: ready
  109. */
  110. checkForUpdates : function( onReadyCallback ){
  111. //this.info( 'checkForUpdates' )
  112. // get overall History state from collection, run updater if History has running/queued hdas
  113. // boiling it down on the client to running/not
  114. if( this.hdas.running().length ){
  115. this.setUpdateTimeout();
  116. } else {
  117. this.trigger( 'ready' );
  118. if( _.isFunction( onReadyCallback ) ){
  119. onReadyCallback.call( this );
  120. }
  121. }
  122. return this;
  123. },
  124. /** create a timeout (after UPDATE_DELAY or delay ms) to refetch the HDA collection. Clear any prev. timeout */
  125. setUpdateTimeout : function( delay ){
  126. delay = delay || History.UPDATE_DELAY;
  127. var history = this;
  128. // prevent buildup of updater timeouts by clearing previous if any, then set new and cache id
  129. this.clearUpdateTimeout();
  130. this.updateTimeoutId = setTimeout( function(){
  131. history.refresh();
  132. }, delay );
  133. return this.updateTimeoutId;
  134. },
  135. /** clear the timeout and the cached timeout id */
  136. clearUpdateTimeout : function(){
  137. if( this.updateTimeoutId ){
  138. clearTimeout( this.updateTimeoutId );
  139. this.updateTimeoutId = null;
  140. }
  141. },
  142. /* update the HDA collection getting full detailed model data for any hda whose id is in detailIds
  143. * set up to run this again in some interval of time
  144. * @param {String[]} detailIds list of HDA ids to get detailed model data for
  145. * @param {Object} options std. backbone fetch options map
  146. */
  147. refresh : function( detailIds, options ){
  148. //this.info( 'refresh:', detailIds, this.hdas );
  149. detailIds = detailIds || [];
  150. options = options || {};
  151. var history = this;
  152. // add detailIds to options as CSV string
  153. options.data = options.data || {};
  154. if( detailIds.length ){
  155. options.data.details = detailIds.join( ',' );
  156. }
  157. var xhr = this.hdas.fetch( options );
  158. xhr.done( function( hdaModels ){
  159. history.checkForUpdates( function(){
  160. // fetch the history inside onReadyCallback in order to recalc history size
  161. this.fetch();
  162. });
  163. });
  164. return xhr;
  165. },
  166. // ........................................................................ misc
  167. toString : function(){
  168. return 'History(' + this.get( 'id' ) + ',' + this.get( 'name' ) + ')';
  169. }
  170. });
  171. //------------------------------------------------------------------------------ CLASS VARS
  172. /** When the history has running hdas,
  173. * this is the amount of time between update checks from the server
  174. */
  175. History.UPDATE_DELAY = 4000;
  176. /** Get data for a history then its hdas using a sequential ajax call, return a deferred to receive both */
  177. History.getHistoryData = function getHistoryData( historyId, options ){
  178. options = options || {};
  179. var hdaDetailIds = options.hdaDetailIds || [];
  180. var hdcaDetailIds = options.hdcaDetailIds || [];
  181. //this.debug( 'getHistoryData:', historyId, options );
  182. var df = jQuery.Deferred(),
  183. historyJSON = null;
  184. function getHistory( id ){
  185. // get the history data
  186. return jQuery.ajax( galaxy_config.root + 'api/histories/' + historyId );
  187. }
  188. function isEmpty( historyData ){
  189. // get the number of hdas accrd. to the history
  190. return historyData && historyData.empty;
  191. }
  192. function getHdas( historyData ){
  193. // get the hda data
  194. // if no hdas accrd. to history: return empty immed.
  195. if( isEmpty( historyData ) ){ return []; }
  196. // if there are hdas accrd. to history: get those as well
  197. if( _.isFunction( hdaDetailIds ) ){
  198. hdaDetailIds = hdaDetailIds( historyData );
  199. }
  200. if( _.isFunction( hdcaDetailIds ) ){
  201. hdcaDetailIds = hdcaDetailIds( historyData );
  202. }
  203. var data = {};
  204. if( hdaDetailIds.length ) {
  205. data.dataset_details = hdaDetailIds.join( ',' );
  206. }
  207. if( hdcaDetailIds.length ) {
  208. // for symmetry, not actually used by backend of consumed
  209. // by frontend.
  210. data.dataset_collection_details = hdcaDetailIds.join( ',' );
  211. }
  212. return jQuery.ajax( galaxy_config.root + 'api/histories/' + historyData.id + '/contents', { data: data });
  213. }
  214. // getting these concurrently is 400% slower (sqlite, local, vanilla) - so:
  215. // chain the api calls - getting history first then hdas
  216. var historyFn = options.historyFn || getHistory,
  217. hdaFn = options.hdaFn || getHdas;
  218. // chain ajax calls: get history first, then hdas
  219. var historyXHR = historyFn( historyId );
  220. historyXHR.done( function( json ){
  221. // set outer scope var here for use below
  222. historyJSON = json;
  223. df.notify({ status: 'history data retrieved', historyJSON: historyJSON });
  224. });
  225. historyXHR.fail( function( xhr, status, message ){
  226. // call reject on the outer deferred to allow its fail callback to run
  227. df.reject( xhr, 'loading the history' );
  228. });
  229. var hdaXHR = historyXHR.then( hdaFn );
  230. hdaXHR.then( function( hdaJSON ){
  231. df.notify({ status: 'dataset data retrieved', historyJSON: historyJSON, hdaJSON: hdaJSON });
  232. // we've got both: resolve the outer scope deferred
  233. df.resolve( historyJSON, hdaJSON );
  234. });
  235. hdaXHR.fail( function( xhr, status, message ){
  236. // call reject on the outer deferred to allow its fail callback to run
  237. df.reject( xhr, 'loading the datasets', { history: historyJSON } );
  238. });
  239. return df;
  240. };
  241. //==============================================================================
  242. /** @class A collection of histories (per user).
  243. * (stub) currently unused.
  244. * @name HistoryCollection
  245. *
  246. * @borrows LoggableMixin#logger as #logger
  247. * @borrows LoggableMixin#log as #log
  248. * @constructs
  249. */
  250. var HistoryCollection = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).extend(
  251. /** @lends HistoryCollection.prototype */{
  252. model : History,
  253. urlRoot : galaxy_config.root + 'api/histories'
  254. ///** logger used to record this.log messages, commonly set to console */
  255. //// comment this out to suppress log output
  256. //logger : console,
  257. });
  258. //==============================================================================
  259. return {
  260. History : History,
  261. HistoryCollection : HistoryCollection
  262. };});