galaxy-commits
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
April 2014
- 1 participants
- 261 discussions
commit/galaxy-central: martenson: data libraries: don't allow adding dataset within deleted library; better error message handling
by commits-noreply@bitbucket.org 21 Apr '14
by commits-noreply@bitbucket.org 21 Apr '14
21 Apr '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/646c971309f3/
Changeset: 646c971309f3
User: martenson
Date: 2014-04-21 22:28:14
Summary: data libraries: don't allow adding dataset within deleted library; better error message handling
Affected #: 3 files
diff -r bba79c0856b4d195187f1883d5dc356b1b088c90 -r 646c971309f3fce14d5e95a709e9ca881e0ca0f0 lib/galaxy/webapps/galaxy/api/folder_contents.py
--- a/lib/galaxy/webapps/galaxy/api/folder_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/folder_contents.py
@@ -174,8 +174,11 @@
hda = self.get_dataset( trans, from_hda_id, check_ownership=True, check_accessible=True, check_state=True )
folder = self.get_library_folder( trans, encoded_folder_id_16, check_accessible=True )
+ library = folder.parent_library
+ if library.deleted:
+ raise exceptions.ObjectAttributeInvalidException()
if not self.can_current_user_add_to_library_item( trans, folder ):
- raise exceptions.InsufficientPermissionsException( 'You do not have proper permissions to add a dataset to a folder with id (%s)' % ( encoded_folder_id ) )
+ raise exceptions.InsufficientPermissionsException()
ldda = self.copy_hda_to_library_folder( trans, hda, folder, ldda_message=ldda_message )
update_time = ldda.update_time.strftime( "%Y-%m-%d %I:%M %p" )
@@ -183,6 +186,10 @@
rval = trans.security.encode_dict_ids( ldda_dict )
rval['update_time'] = update_time
+ except exceptions.ObjectAttributeInvalidException:
+ raise exceptions.ObjectAttributeInvalidException( 'You cannot add datasets into deleted library. Undelete it first.' )
+ except exceptions.InsufficientPermissionsException:
+ raise exceptions.exceptions.InsufficientPermissionsException( 'You do not have proper permissions to add a dataset to a folder with id (%s)' % ( encoded_folder_id ) )
except Exception, exc:
# TODO handle exceptions better within the mixins
if ( ( 'not accessible to the current user' in str( exc ) ) or ( 'You are not allowed to access this dataset' in str( exc ) ) ):
diff -r bba79c0856b4d195187f1883d5dc356b1b088c90 -r 646c971309f3fce14d5e95a709e9ca881e0ca0f0 static/scripts/mvc/library/library-foldertoolbar-view.js
--- a/static/scripts/mvc/library/library-foldertoolbar-view.js
+++ b/static/scripts/mvc/library/library-foldertoolbar-view.js
@@ -19,7 +19,11 @@
defaults: {
'can_add_library_item' : false,
- 'contains_file' : false
+ 'contains_file' : false,
+ 'adding_datasets' : {
+ 'total_number' : 0,
+ 'failed_number' : 0
+ }
},
modal : null,
@@ -301,8 +305,11 @@
// add all selected datasets from history into current folder
addAllDatasetsFromHistory : function (){
- //disable the button to prevent multiple submission
+ // disable the button to prevent multiple submission
this.modal.disableButton('Add');
+ // init the counters
+ this.options.adding_datasets.total_number = 0;
+ this.options.adding_datasets.failed_number = 0;
var history_dataset_ids = [];
this.modal.$el.find('#selected_history_content').find(':checked').each(function(){
@@ -328,6 +335,7 @@
folder_item.set({'from_hda_id':history_dataset_id});
hdas_to_add.push(folder_item);
}
+ this.options.adding_datasets.total_number = hdas_to_add.length;
// call the recursive function to call ajax one after each other (request FIFO queue)
this.chainCallAddingHdas(hdas_to_add);
},
@@ -337,8 +345,14 @@
this.added_hdas = new mod_library_model.Folder();
var popped_item = hdas_set.pop();
if (typeof popped_item === "undefined") {
- mod_toastr.success('Datasets from history added to the folder');
- this.modal.hide();
+ if (this.options.adding_datasets.failed_number === 0){
+ mod_toastr.success('Selected datasets from history added to the folder');
+ } else if (this.options.adding_datasets.failed_number === this.options.adding_datasets.total_number){
+ mod_toastr.error('There was an error and no datasets were added to the folder.');
+ } else if (this.options.adding_datasets.failed_number < this.options.adding_datasets.total_number){
+ mod_toastr.warning('Some of the datasets could not be added to the folder');
+ }
+ Galaxy.modal.hide();
return this.added_hdas;
}
var promise = $.when(popped_item.save({from_hda_id: popped_item.get('from_hda_id')}));
@@ -351,11 +365,12 @@
})
.fail(function(data){
// we have a problem
- if (data.status===403){
- mod_toastr.error('You are not allowed to access a dataset');
- } else {
- mod_toastr.error('An error occured :(');
- }
+ self.options.adding_datasets.failed_number += 1;
+ // if (typeof data.responseJSON !== "undefined"){
+ // mod_toastr.error(data.responseJSON.err_msg);
+ // } else {
+ // mod_toastr.error('An error ocurred :(');
+ // }
self.updateProgress();
self.chainCallAddingHdas(hdas_set);
});
diff -r bba79c0856b4d195187f1883d5dc356b1b088c90 -r 646c971309f3fce14d5e95a709e9ca881e0ca0f0 static/scripts/packed/mvc/library/library-foldertoolbar-view.js
--- a/static/scripts/packed/mvc/library/library-foldertoolbar-view.js
+++ b/static/scripts/packed/mvc/library/library-foldertoolbar-view.js
@@ -1,1 +1,1 @@
-define(["galaxy.masthead","utils/utils","libs/toastr","mvc/library/library-model"],function(b,d,e,c){var a=Backbone.View.extend({el:"#center",events:{"click #toolbtn_create_folder":"createFolderFromModal","click #toolbtn_bulk_import":"modalBulkImport","click .toolbtn_add_files":"addFilesToFolderModal"},defaults:{can_add_library_item:false,contains_file:false},modal:null,histories:null,initialize:function(f){this.options=_.defaults(f||{},this.defaults);this.render()},render:function(f){this.options=_.extend(this.options,f);var h=this.templateToolBar();var g=false;if(Galaxy.currUser){g=Galaxy.currUser.isAdmin()}this.$el.html(h({id:this.options.id,admin_user:g}))},configureElements:function(f){this.options=_.extend(this.options,f);if(this.options.can_add_library_item===true){$("#toolbtn_create_folder").show();$(".toolbtn_add_files").show()}if(this.options.contains_file===true){$("#toolbtn_bulk_import").show();$("#toolbtn_dl").show()}this.$el.find("[data-toggle]").tooltip()},createFolderFromModal:function(){event.preventDefault();event.stopPropagation();var f=this;var g=this.templateNewFolderInModal();this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Create New Folder",body:g(),buttons:{Create:function(){f.create_new_folder_event()},Close:function(){Galaxy.modal.hide()}}})},create_new_folder_event:function(){var f=this.serialize_new_folder();if(this.validate_new_folder(f)){var g=new c.FolderAsModel();url_items=Backbone.history.fragment.split("/");current_folder_id=url_items[url_items.length-1];g.url=g.urlRoot+"/"+current_folder_id;g.save(f,{success:function(h){Galaxy.modal.hide();e.success("Folder created");h.set({type:"folder"});Galaxy.libraries.folderListView.collection.add(h)},error:function(i,h){Galaxy.modal.hide();if(typeof h.responseJSON!=="undefined"){e.error(h.responseJSON.err_msg)}else{e.error("An error ocurred :(")}}})}else{e.error("Folder's name is missing")}return false},serialize_new_folder:function(){return{name:$("input[name='Name']").val(),description:$("input[name='Description']").val()}},validate_new_folder:function(f){return f.name!==""},modalBulkImport:function(){var f=$("#folder_table").find(":checked");if(f.length===0){e.info("You have to select some datasets first")}else{this.refreshUserHistoriesList(function(g){var h=g.templateBulkImportInModal();g.modal=Galaxy.modal;g.modal.show({closing_events:true,title:"Import into History",body:h({histories:g.histories.models}),buttons:{Import:function(){g.importAllIntoHistory()},Close:function(){Galaxy.modal.hide()}}})})}},refreshUserHistoriesList:function(g){var f=this;this.histories=new c.GalaxyHistories();this.histories.fetch({success:function(){g(f)},error:function(){}})},importAllIntoHistory:function(){this.modal.disableButton("Import");var j=$("select[name=dataset_import_bulk] option:selected").val();this.options.last_used_history_id=j;var m=$("select[name=dataset_import_bulk] option:selected").text();var o=[];$("#folder_table").find(":checked").each(function(){if(this.parentElement.parentElement.id!==""){o.push(this.parentElement.parentElement.id)}});var n=this.templateImportIntoHistoryProgressBar();this.modal.$el.find(".modal-body").html(n({history_name:m}));var k=100/o.length;this.initProgress(k);var f=[];for(var g=o.length-1;g>=0;g--){var h=o[g];var l=new c.HistoryItem();l.url=l.urlRoot+j+"/contents";l.content=h;l.source="library";f.push(l)}this.chainCall(f,m)},chainCall:function(g,j){var f=this;var h=g.pop();if(typeof h==="undefined"){e.success("Datasets were imported to history: "+j);this.modal.hide();return}var i=$.when(h.save({content:h.content,source:h.source}));i.done(function(k){f.updateProgress();f.chainCall(g,j)}).fail(function(k){e.error("An error occured :(");f.updateProgress();f.chainCall(g,j)})},initProgress:function(f){this.progress=0;this.progressStep=f},updateProgress:function(){this.progress+=this.progressStep;$(".progress-bar-import").width(Math.round(this.progress)+"%");txt_representation=Math.round(this.progress)+"% Complete";$(".completion_span").text(txt_representation)},download:function(f,j){var h=[];$("#folder_table").find(":checked").each(function(){if(this.parentElement.parentElement.id!==""){h.push(this.parentElement.parentElement.id)}});var g="/api/libraries/datasets/download/"+j;var i={ldda_ids:h};this.processDownload(g,i,"get")},processDownload:function(g,h,i){if(g&&h){h=typeof h==="string"?h:$.param(h);var f="";$.each(h.split("&"),function(){var j=this.split("=");f+='<input type="hidden" name="'+j[0]+'" value="'+j[1]+'" />'});$('<form action="'+g+'" method="'+(i||"post")+'">'+f+"</form>").appendTo("body").submit().remove();e.info("Your download will begin soon")}},addFilesToFolderModal:function(){this.refreshUserHistoriesList(function(f){f.modal=Galaxy.modal;var g=f.templateAddFilesInModal();f.modal.show({closing_events:true,title:"Add datasets from history to "+f.options.folder_name,body:g({histories:f.histories.models}),buttons:{Add:function(){f.addAllDatasetsFromHistory()},Close:function(){Galaxy.modal.hide()}}});if(f.histories.models.length>0){f.fetchAndDisplayHistoryContents(f.histories.models[0].id);$("#dataset_add_bulk").change(function(h){f.fetchAndDisplayHistoryContents(h.target.value)})}else{e.error("An error ocurred :(")}})},fetchAndDisplayHistoryContents:function(h){var g=new c.HistoryContents({id:h});var f=this;g.fetch({success:function(j){var i=f.templateHistoryContents();f.histories.get(h).set({contents:j});f.modal.$el.find("#selected_history_content").html(i({history_contents:j.models.reverse()}))},error:function(j,i){e.error("An error ocurred :(")}})},addAllDatasetsFromHistory:function(){this.modal.disableButton("Add");var f=[];this.modal.$el.find("#selected_history_content").find(":checked").each(function(){var i=$(this.parentElement).data("id");if(i){f.push(i)}});var l=this.options.folder_name;var k=this.templateAddingDatasetsProgressBar();this.modal.$el.find(".modal-body").html(k({folder_name:l}));this.progressStep=100/f.length;this.progress=0;var j=[];for(var h=f.length-1;h>=0;h--){history_dataset_id=f[h];var g=new c.Item();g.url="/api/folders/"+this.options.id+"/contents";g.set({from_hda_id:history_dataset_id});j.push(g)}this.chainCallAddingHdas(j)},chainCallAddingHdas:function(g){var f=this;this.added_hdas=new c.Folder();var h=g.pop();if(typeof h==="undefined"){e.success("Datasets from history added to the folder");this.modal.hide();return this.added_hdas}var i=$.when(h.save({from_hda_id:h.get("from_hda_id")}));i.done(function(j){Galaxy.libraries.folderListView.collection.add(j);f.updateProgress();f.chainCallAddingHdas(g)}).fail(function(j){if(j.status===403){e.error("You are not allowed to access a dataset")}else{e.error("An error occured :(")}f.updateProgress();f.chainCallAddingHdas(g)})},templateToolBar:function(){tmpl_array=[];tmpl_array.push('<div class="library_style_container">');tmpl_array.push('<h3>Data Libraries Beta Test. This is work in progress. Please report problems & ideas via <a href="mailto:galaxy-bugs@bx.psu.edu?Subject=DataLibrariesBeta_Feedback" target="_blank">email</a> and <a href="https://trello.com/c/nwYQNFPK/56-data-library-ui-progressive-display-of-fol…" target="_blank">Trello</a>.</h3>');tmpl_array.push('<div id="library_folder_toolbar" >');tmpl_array.push('<div class="btn-group">');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Create New Folder" id="toolbtn_create_folder" class="btn btn-default primary-button" type="button" style="display:none;"><span class="fa fa-plus"></span><span class="fa fa-folder"></span></button>');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Add Datasets to Current Folder" id="toolbtn_add_files" class="btn btn-default toolbtn_add_files primary-button" type="button" style="display:none;"><span class="fa fa-plus"></span><span class="fa fa-file"></span></span></button>');tmpl_array.push("</div>");tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button" style="margin-left: 0.5em; " type="button"><span class="fa fa-book"></span> to history</button>');tmpl_array.push(' <div id="toolbtn_dl" class="btn-group" style="margin-left: 0.5em; ">');tmpl_array.push(' <button title="Download selected datasets" id="drop_toggle" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');tmpl_array.push(' <span class="fa fa-download"></span> download <span class="caret"></span>');tmpl_array.push(" </button>");tmpl_array.push(' <ul class="dropdown-menu" role="menu">');tmpl_array.push(' <li id="download_archive"><a href="#/folders/<%= id %>/download/tgz">.tar.gz</a></li>');tmpl_array.push(' <li id="download_archive"><a href="#/folders/<%= id %>/download/tbz">.tar.bz</a></li>');tmpl_array.push(' <li id="download_archive"><a href="#/folders/<%= id %>/download/zip">.zip</a></li>');tmpl_array.push(" </ul>");tmpl_array.push(" </div>");tmpl_array.push(" </div>");tmpl_array.push(' <div id="folder_items_element">');tmpl_array.push(" </div>");tmpl_array.push("</div>");return _.template(tmpl_array.join(""))},templateNewFolderInModal:function(){tmpl_array=[];tmpl_array.push('<div id="new_folder_modal">');tmpl_array.push("<form>");tmpl_array.push('<input type="text" name="Name" value="" placeholder="Name">');tmpl_array.push('<input type="text" name="Description" value="" placeholder="Description">');tmpl_array.push("</form>");tmpl_array.push("</div>");return _.template(tmpl_array.join(""))},templateBulkImportInModal:function(){var f=[];f.push('<span id="history_modal_combo_bulk" style="width:90%; margin-left: 1em; margin-right: 1em; ">');f.push("Select history: ");f.push('<select id="dataset_import_bulk" name="dataset_import_bulk" style="width:50%; margin-bottom: 1em; "> ');f.push(" <% _.each(histories, function(history) { %>");f.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');f.push(" <% }); %>");f.push("</select>");f.push("</span>");return _.template(f.join(""))},templateImportIntoHistoryProgressBar:function(){var f=[];f.push('<div class="import_text">');f.push("Importing selected datasets to history <b><%= _.escape(history_name) %></b>");f.push("</div>");f.push('<div class="progress">');f.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');f.push(' <span class="completion_span">0% Complete</span>');f.push(" </div>");f.push("</div>");f.push("");return _.template(f.join(""))},templateAddingDatasetsProgressBar:function(){var f=[];f.push('<div class="import_text">');f.push("Adding selected datasets from history to library folder <b><%= _.escape(folder_name) %></b>");f.push("</div>");f.push('<div class="progress">');f.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');f.push(' <span class="completion_span">0% Complete</span>');f.push(" </div>");f.push("</div>");f.push("");return _.template(f.join(""))},templateAddFilesInModal:function(){var f=[];f.push('<div id="add_files_modal">');f.push('<div id="history_modal_combo_bulk">');f.push("Select history: ");f.push('<select id="dataset_add_bulk" name="dataset_add_bulk" style="width:66%; "> ');f.push(" <% _.each(histories, function(history) { %>");f.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');f.push(" <% }); %>");f.push("</select>");f.push("</div>");f.push('<div id="selected_history_content">');f.push("</div>");f.push("</div>");return _.template(f.join(""))},templateHistoryContents:function(){var f=[];f.push("Choose the datasets to import:");f.push("<ul>");f.push(" <% _.each(history_contents, function(history_item) { %>");f.push(' <li data-id="<%= _.escape(history_item.get("id")) %>">');f.push(' <input style="margin: 0;" type="checkbox"><%= _.escape(history_item.get("hid")) %>: <%= _.escape(history_item.get("name")) %>');f.push(" </li>");f.push(" <% }); %>");f.push("</ul>");return _.template(f.join(""))}});return{FolderToolbarView:a}});
\ No newline at end of file
+define(["galaxy.masthead","utils/utils","libs/toastr","mvc/library/library-model"],function(b,d,e,c){var a=Backbone.View.extend({el:"#center",events:{"click #toolbtn_create_folder":"createFolderFromModal","click #toolbtn_bulk_import":"modalBulkImport","click .toolbtn_add_files":"addFilesToFolderModal"},defaults:{can_add_library_item:false,contains_file:false,adding_datasets:{total_number:0,failed_number:0}},modal:null,histories:null,initialize:function(f){this.options=_.defaults(f||{},this.defaults);this.render()},render:function(f){this.options=_.extend(this.options,f);var h=this.templateToolBar();var g=false;if(Galaxy.currUser){g=Galaxy.currUser.isAdmin()}this.$el.html(h({id:this.options.id,admin_user:g}))},configureElements:function(f){this.options=_.extend(this.options,f);if(this.options.can_add_library_item===true){$("#toolbtn_create_folder").show();$(".toolbtn_add_files").show()}if(this.options.contains_file===true){$("#toolbtn_bulk_import").show();$("#toolbtn_dl").show()}this.$el.find("[data-toggle]").tooltip()},createFolderFromModal:function(){event.preventDefault();event.stopPropagation();var f=this;var g=this.templateNewFolderInModal();this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Create New Folder",body:g(),buttons:{Create:function(){f.create_new_folder_event()},Close:function(){Galaxy.modal.hide()}}})},create_new_folder_event:function(){var f=this.serialize_new_folder();if(this.validate_new_folder(f)){var g=new c.FolderAsModel();url_items=Backbone.history.fragment.split("/");current_folder_id=url_items[url_items.length-1];g.url=g.urlRoot+"/"+current_folder_id;g.save(f,{success:function(h){Galaxy.modal.hide();e.success("Folder created");h.set({type:"folder"});Galaxy.libraries.folderListView.collection.add(h)},error:function(i,h){Galaxy.modal.hide();if(typeof h.responseJSON!=="undefined"){e.error(h.responseJSON.err_msg)}else{e.error("An error ocurred :(")}}})}else{e.error("Folder's name is missing")}return false},serialize_new_folder:function(){return{name:$("input[name='Name']").val(),description:$("input[name='Description']").val()}},validate_new_folder:function(f){return f.name!==""},modalBulkImport:function(){var f=$("#folder_table").find(":checked");if(f.length===0){e.info("You have to select some datasets first")}else{this.refreshUserHistoriesList(function(g){var h=g.templateBulkImportInModal();g.modal=Galaxy.modal;g.modal.show({closing_events:true,title:"Import into History",body:h({histories:g.histories.models}),buttons:{Import:function(){g.importAllIntoHistory()},Close:function(){Galaxy.modal.hide()}}})})}},refreshUserHistoriesList:function(g){var f=this;this.histories=new c.GalaxyHistories();this.histories.fetch({success:function(){g(f)},error:function(){}})},importAllIntoHistory:function(){this.modal.disableButton("Import");var j=$("select[name=dataset_import_bulk] option:selected").val();this.options.last_used_history_id=j;var m=$("select[name=dataset_import_bulk] option:selected").text();var o=[];$("#folder_table").find(":checked").each(function(){if(this.parentElement.parentElement.id!==""){o.push(this.parentElement.parentElement.id)}});var n=this.templateImportIntoHistoryProgressBar();this.modal.$el.find(".modal-body").html(n({history_name:m}));var k=100/o.length;this.initProgress(k);var f=[];for(var g=o.length-1;g>=0;g--){var h=o[g];var l=new c.HistoryItem();l.url=l.urlRoot+j+"/contents";l.content=h;l.source="library";f.push(l)}this.chainCall(f,m)},chainCall:function(g,j){var f=this;var h=g.pop();if(typeof h==="undefined"){e.success("Datasets were imported to history: "+j);this.modal.hide();return}var i=$.when(h.save({content:h.content,source:h.source}));i.done(function(k){f.updateProgress();f.chainCall(g,j)}).fail(function(k){e.error("An error occured :(");f.updateProgress();f.chainCall(g,j)})},initProgress:function(f){this.progress=0;this.progressStep=f},updateProgress:function(){this.progress+=this.progressStep;$(".progress-bar-import").width(Math.round(this.progress)+"%");txt_representation=Math.round(this.progress)+"% Complete";$(".completion_span").text(txt_representation)},download:function(f,j){var h=[];$("#folder_table").find(":checked").each(function(){if(this.parentElement.parentElement.id!==""){h.push(this.parentElement.parentElement.id)}});var g="/api/libraries/datasets/download/"+j;var i={ldda_ids:h};this.processDownload(g,i,"get")},processDownload:function(g,h,i){if(g&&h){h=typeof h==="string"?h:$.param(h);var f="";$.each(h.split("&"),function(){var j=this.split("=");f+='<input type="hidden" name="'+j[0]+'" value="'+j[1]+'" />'});$('<form action="'+g+'" method="'+(i||"post")+'">'+f+"</form>").appendTo("body").submit().remove();e.info("Your download will begin soon")}},addFilesToFolderModal:function(){this.refreshUserHistoriesList(function(f){f.modal=Galaxy.modal;var g=f.templateAddFilesInModal();f.modal.show({closing_events:true,title:"Add datasets from history to "+f.options.folder_name,body:g({histories:f.histories.models}),buttons:{Add:function(){f.addAllDatasetsFromHistory()},Close:function(){Galaxy.modal.hide()}}});if(f.histories.models.length>0){f.fetchAndDisplayHistoryContents(f.histories.models[0].id);$("#dataset_add_bulk").change(function(h){f.fetchAndDisplayHistoryContents(h.target.value)})}else{e.error("An error ocurred :(")}})},fetchAndDisplayHistoryContents:function(h){var g=new c.HistoryContents({id:h});var f=this;g.fetch({success:function(j){var i=f.templateHistoryContents();f.histories.get(h).set({contents:j});f.modal.$el.find("#selected_history_content").html(i({history_contents:j.models.reverse()}))},error:function(j,i){e.error("An error ocurred :(")}})},addAllDatasetsFromHistory:function(){this.modal.disableButton("Add");this.options.adding_datasets.total_number=0;this.options.adding_datasets.failed_number=0;var f=[];this.modal.$el.find("#selected_history_content").find(":checked").each(function(){var i=$(this.parentElement).data("id");if(i){f.push(i)}});var l=this.options.folder_name;var k=this.templateAddingDatasetsProgressBar();this.modal.$el.find(".modal-body").html(k({folder_name:l}));this.progressStep=100/f.length;this.progress=0;var j=[];for(var h=f.length-1;h>=0;h--){history_dataset_id=f[h];var g=new c.Item();g.url="/api/folders/"+this.options.id+"/contents";g.set({from_hda_id:history_dataset_id});j.push(g)}this.options.adding_datasets.total_number=j.length;this.chainCallAddingHdas(j)},chainCallAddingHdas:function(g){var f=this;this.added_hdas=new c.Folder();var h=g.pop();if(typeof h==="undefined"){if(this.options.adding_datasets.failed_number===0){e.success("Selected datasets from history added to the folder")}else{if(this.options.adding_datasets.failed_number===this.options.adding_datasets.total_number){e.error("There was an error and no datasets were added to the folder.")}else{if(this.options.adding_datasets.failed_number<this.options.adding_datasets.total_number){e.warning("Some of the datasets could not be added to the folder")}}}Galaxy.modal.hide();return this.added_hdas}var i=$.when(h.save({from_hda_id:h.get("from_hda_id")}));i.done(function(j){Galaxy.libraries.folderListView.collection.add(j);f.updateProgress();f.chainCallAddingHdas(g)}).fail(function(j){f.options.adding_datasets.failed_number+=1;f.updateProgress();f.chainCallAddingHdas(g)})},templateToolBar:function(){tmpl_array=[];tmpl_array.push('<div class="library_style_container">');tmpl_array.push('<h3>Data Libraries Beta Test. This is work in progress. Please report problems & ideas via <a href="mailto:galaxy-bugs@bx.psu.edu?Subject=DataLibrariesBeta_Feedback" target="_blank">email</a> and <a href="https://trello.com/c/nwYQNFPK/56-data-library-ui-progressive-display-of-fol…" target="_blank">Trello</a>.</h3>');tmpl_array.push('<div id="library_folder_toolbar" >');tmpl_array.push('<div class="btn-group">');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Create New Folder" id="toolbtn_create_folder" class="btn btn-default primary-button" type="button" style="display:none;"><span class="fa fa-plus"></span><span class="fa fa-folder"></span></button>');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Add Datasets to Current Folder" id="toolbtn_add_files" class="btn btn-default toolbtn_add_files primary-button" type="button" style="display:none;"><span class="fa fa-plus"></span><span class="fa fa-file"></span></span></button>');tmpl_array.push("</div>");tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button" style="margin-left: 0.5em; " type="button"><span class="fa fa-book"></span> to history</button>');tmpl_array.push(' <div id="toolbtn_dl" class="btn-group" style="margin-left: 0.5em; ">');tmpl_array.push(' <button title="Download selected datasets" id="drop_toggle" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');tmpl_array.push(' <span class="fa fa-download"></span> download <span class="caret"></span>');tmpl_array.push(" </button>");tmpl_array.push(' <ul class="dropdown-menu" role="menu">');tmpl_array.push(' <li id="download_archive"><a href="#/folders/<%= id %>/download/tgz">.tar.gz</a></li>');tmpl_array.push(' <li id="download_archive"><a href="#/folders/<%= id %>/download/tbz">.tar.bz</a></li>');tmpl_array.push(' <li id="download_archive"><a href="#/folders/<%= id %>/download/zip">.zip</a></li>');tmpl_array.push(" </ul>");tmpl_array.push(" </div>");tmpl_array.push(" </div>");tmpl_array.push(' <div id="folder_items_element">');tmpl_array.push(" </div>");tmpl_array.push("</div>");return _.template(tmpl_array.join(""))},templateNewFolderInModal:function(){tmpl_array=[];tmpl_array.push('<div id="new_folder_modal">');tmpl_array.push("<form>");tmpl_array.push('<input type="text" name="Name" value="" placeholder="Name">');tmpl_array.push('<input type="text" name="Description" value="" placeholder="Description">');tmpl_array.push("</form>");tmpl_array.push("</div>");return _.template(tmpl_array.join(""))},templateBulkImportInModal:function(){var f=[];f.push('<span id="history_modal_combo_bulk" style="width:90%; margin-left: 1em; margin-right: 1em; ">');f.push("Select history: ");f.push('<select id="dataset_import_bulk" name="dataset_import_bulk" style="width:50%; margin-bottom: 1em; "> ');f.push(" <% _.each(histories, function(history) { %>");f.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');f.push(" <% }); %>");f.push("</select>");f.push("</span>");return _.template(f.join(""))},templateImportIntoHistoryProgressBar:function(){var f=[];f.push('<div class="import_text">');f.push("Importing selected datasets to history <b><%= _.escape(history_name) %></b>");f.push("</div>");f.push('<div class="progress">');f.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');f.push(' <span class="completion_span">0% Complete</span>');f.push(" </div>");f.push("</div>");f.push("");return _.template(f.join(""))},templateAddingDatasetsProgressBar:function(){var f=[];f.push('<div class="import_text">');f.push("Adding selected datasets from history to library folder <b><%= _.escape(folder_name) %></b>");f.push("</div>");f.push('<div class="progress">');f.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');f.push(' <span class="completion_span">0% Complete</span>');f.push(" </div>");f.push("</div>");f.push("");return _.template(f.join(""))},templateAddFilesInModal:function(){var f=[];f.push('<div id="add_files_modal">');f.push('<div id="history_modal_combo_bulk">');f.push("Select history: ");f.push('<select id="dataset_add_bulk" name="dataset_add_bulk" style="width:66%; "> ');f.push(" <% _.each(histories, function(history) { %>");f.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');f.push(" <% }); %>");f.push("</select>");f.push("</div>");f.push('<div id="selected_history_content">');f.push("</div>");f.push("</div>");return _.template(f.join(""))},templateHistoryContents:function(){var f=[];f.push("Choose the datasets to import:");f.push("<ul>");f.push(" <% _.each(history_contents, function(history_item) { %>");f.push(' <li data-id="<%= _.escape(history_item.get("id")) %>">');f.push(' <input style="margin: 0;" type="checkbox"><%= _.escape(history_item.get("hid")) %>: <%= _.escape(history_item.get("name")) %>');f.push(" </li>");f.push(" <% }); %>");f.push("</ul>");return _.template(f.join(""))}});return{FolderToolbarView:a}});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: martenson: data libraries: don't allow creating folders within deleted library
by commits-noreply@bitbucket.org 21 Apr '14
by commits-noreply@bitbucket.org 21 Apr '14
21 Apr '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/bba79c0856b4/
Changeset: bba79c0856b4
User: martenson
Date: 2014-04-21 21:48:19
Summary: data libraries: don't allow creating folders within deleted library
Affected #: 3 files
diff -r d2717865114c0c577fcd508201acf5eeac2cc54a -r bba79c0856b4d195187f1883d5dc356b1b088c90 lib/galaxy/webapps/galaxy/api/folders.py
--- a/lib/galaxy/webapps/galaxy/api/folders.py
+++ b/lib/galaxy/webapps/galaxy/api/folders.py
@@ -7,10 +7,8 @@
from galaxy.web import _future_expose_api as expose_api
from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous
from galaxy.web.base.controller import BaseAPIController,UsesLibraryMixin,UsesLibraryMixinItems
-# from galaxy.util.sanitize_html import sanitize_html
-
-# from cgi import escape, FieldStorage
-# from paste.httpexceptions import HTTPBadRequest
+from sqlalchemy.orm.exc import MultipleResultsFound
+from sqlalchemy.orm.exc import NoResultFound
import logging
log = logging.getLogger( __name__ )
@@ -47,7 +45,7 @@
check_accessible=True )
return self.encode_all_ids( trans, content.to_dict( view='element' ) )
- @web.expose_api
+ @expose_api
def create( self, trans, encoded_parent_folder_id, **kwd ):
"""
@@ -83,12 +81,24 @@
# encoded_parent_folder_id may be prefixed by 'F'
encoded_parent_folder_id = self.__cut_the_prefix( encoded_parent_folder_id )
-
try:
decoded_parent_folder_id = trans.security.decode_id( encoded_parent_folder_id )
except ValueError:
raise exceptions.MalformedId( "Malformed folder id ( %s ) specified, unable to decode" % ( str( id ) ) )
+ try:
+ parent_folder = trans.sa_session.query( trans.app.model.LibraryFolder ).filter( trans.app.model.LibraryFolder.table.c.id == decoded_parent_folder_id ).one()
+ except MultipleResultsFound:
+ raise exceptions.InconsistentDatabase( 'Multiple folders found with the same id.' )
+ except NoResultFound:
+ raise exceptions.RequestParameterInvalidException( 'No folder found with the id provided.' )
+ except Exception, e:
+ raise exceptions.InternalServerError( 'Error loading from the database.' + str(e))
+
+ library = parent_folder.parent_library
+ if library.deleted:
+ raise exceptions.ObjectAttributeInvalidException( 'You cannot create folder within a deleted library. Undelete it first.' )
+
# TODO: refactor the functionality for use here instead of calling another controller
params = dict( [ ( "name", name ), ( "description", description ) ] )
status, output = trans.webapp.controllers['library_common'].create_folder( trans, 'api', encoded_parent_folder_id, '', **params )
diff -r d2717865114c0c577fcd508201acf5eeac2cc54a -r bba79c0856b4d195187f1883d5dc356b1b088c90 static/scripts/mvc/library/library-foldertoolbar-view.js
--- a/static/scripts/mvc/library/library-foldertoolbar-view.js
+++ b/static/scripts/mvc/library/library-foldertoolbar-view.js
@@ -84,16 +84,20 @@
current_folder_id = url_items[url_items.length-1];
folder.url = folder.urlRoot + '/' + current_folder_id ;
- var self = this;
folder.save(folderDetails, {
success: function (folder) {
- self.modal.hide();
+ Galaxy.modal.hide();
mod_toastr.success('Folder created');
folder.set({'type' : 'folder'});
Galaxy.libraries.folderListView.collection.add(folder);
},
- error: function(){
- mod_toastr.error('An error occured :(');
+ error: function(model, response){
+ Galaxy.modal.hide();
+ if (typeof response.responseJSON !== "undefined"){
+ mod_toastr.error(response.responseJSON.err_msg);
+ } else {
+ mod_toastr.error('An error ocurred :(');
+ }
}
});
} else {
@@ -289,7 +293,7 @@
self.histories.get(history_id).set({'contents' : history_contents});
self.modal.$el.find('#selected_history_content').html(history_contents_template({history_contents: history_contents.models.reverse()}));
},
- error: function(){
+ error: function(model, response){
mod_toastr.error('An error ocurred :(');
}
});
diff -r d2717865114c0c577fcd508201acf5eeac2cc54a -r bba79c0856b4d195187f1883d5dc356b1b088c90 static/scripts/packed/mvc/library/library-foldertoolbar-view.js
--- a/static/scripts/packed/mvc/library/library-foldertoolbar-view.js
+++ b/static/scripts/packed/mvc/library/library-foldertoolbar-view.js
@@ -1,1 +1,1 @@
-define(["galaxy.masthead","utils/utils","libs/toastr","mvc/library/library-model"],function(b,d,e,c){var a=Backbone.View.extend({el:"#center",events:{"click #toolbtn_create_folder":"createFolderFromModal","click #toolbtn_bulk_import":"modalBulkImport","click .toolbtn_add_files":"addFilesToFolderModal"},defaults:{can_add_library_item:false,contains_file:false},modal:null,histories:null,initialize:function(f){this.options=_.defaults(f||{},this.defaults);this.render()},render:function(f){this.options=_.extend(this.options,f);var h=this.templateToolBar();var g=false;if(Galaxy.currUser){g=Galaxy.currUser.isAdmin()}this.$el.html(h({id:this.options.id,admin_user:g}))},configureElements:function(f){this.options=_.extend(this.options,f);if(this.options.can_add_library_item===true){$("#toolbtn_create_folder").show();$(".toolbtn_add_files").show()}if(this.options.contains_file===true){$("#toolbtn_bulk_import").show();$("#toolbtn_dl").show()}this.$el.find("[data-toggle]").tooltip()},createFolderFromModal:function(){event.preventDefault();event.stopPropagation();var f=this;var g=this.templateNewFolderInModal();this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Create New Folder",body:g(),buttons:{Create:function(){f.create_new_folder_event()},Close:function(){Galaxy.modal.hide()}}})},create_new_folder_event:function(){var f=this.serialize_new_folder();if(this.validate_new_folder(f)){var h=new c.FolderAsModel();url_items=Backbone.history.fragment.split("/");current_folder_id=url_items[url_items.length-1];h.url=h.urlRoot+"/"+current_folder_id;var g=this;h.save(f,{success:function(i){g.modal.hide();e.success("Folder created");i.set({type:"folder"});Galaxy.libraries.folderListView.collection.add(i)},error:function(){e.error("An error occured :(")}})}else{e.error("Folder's name is missing")}return false},serialize_new_folder:function(){return{name:$("input[name='Name']").val(),description:$("input[name='Description']").val()}},validate_new_folder:function(f){return f.name!==""},modalBulkImport:function(){var f=$("#folder_table").find(":checked");if(f.length===0){e.info("You have to select some datasets first")}else{this.refreshUserHistoriesList(function(g){var h=g.templateBulkImportInModal();g.modal=Galaxy.modal;g.modal.show({closing_events:true,title:"Import into History",body:h({histories:g.histories.models}),buttons:{Import:function(){g.importAllIntoHistory()},Close:function(){Galaxy.modal.hide()}}})})}},refreshUserHistoriesList:function(g){var f=this;this.histories=new c.GalaxyHistories();this.histories.fetch({success:function(){g(f)},error:function(){}})},importAllIntoHistory:function(){this.modal.disableButton("Import");var j=$("select[name=dataset_import_bulk] option:selected").val();this.options.last_used_history_id=j;var m=$("select[name=dataset_import_bulk] option:selected").text();var o=[];$("#folder_table").find(":checked").each(function(){if(this.parentElement.parentElement.id!==""){o.push(this.parentElement.parentElement.id)}});var n=this.templateImportIntoHistoryProgressBar();this.modal.$el.find(".modal-body").html(n({history_name:m}));var k=100/o.length;this.initProgress(k);var f=[];for(var g=o.length-1;g>=0;g--){var h=o[g];var l=new c.HistoryItem();l.url=l.urlRoot+j+"/contents";l.content=h;l.source="library";f.push(l)}this.chainCall(f,m)},chainCall:function(g,j){var f=this;var h=g.pop();if(typeof h==="undefined"){e.success("Datasets were imported to history: "+j);this.modal.hide();return}var i=$.when(h.save({content:h.content,source:h.source}));i.done(function(k){f.updateProgress();f.chainCall(g,j)}).fail(function(k){e.error("An error occured :(");f.updateProgress();f.chainCall(g,j)})},initProgress:function(f){this.progress=0;this.progressStep=f},updateProgress:function(){this.progress+=this.progressStep;$(".progress-bar-import").width(Math.round(this.progress)+"%");txt_representation=Math.round(this.progress)+"% Complete";$(".completion_span").text(txt_representation)},download:function(f,j){var h=[];$("#folder_table").find(":checked").each(function(){if(this.parentElement.parentElement.id!==""){h.push(this.parentElement.parentElement.id)}});var g="/api/libraries/datasets/download/"+j;var i={ldda_ids:h};this.processDownload(g,i,"get")},processDownload:function(g,h,i){if(g&&h){h=typeof h==="string"?h:$.param(h);var f="";$.each(h.split("&"),function(){var j=this.split("=");f+='<input type="hidden" name="'+j[0]+'" value="'+j[1]+'" />'});$('<form action="'+g+'" method="'+(i||"post")+'">'+f+"</form>").appendTo("body").submit().remove();e.info("Your download will begin soon")}},addFilesToFolderModal:function(){this.refreshUserHistoriesList(function(f){f.modal=Galaxy.modal;var g=f.templateAddFilesInModal();f.modal.show({closing_events:true,title:"Add datasets from history to "+f.options.folder_name,body:g({histories:f.histories.models}),buttons:{Add:function(){f.addAllDatasetsFromHistory()},Close:function(){Galaxy.modal.hide()}}});if(f.histories.models.length>0){f.fetchAndDisplayHistoryContents(f.histories.models[0].id);$("#dataset_add_bulk").change(function(h){f.fetchAndDisplayHistoryContents(h.target.value)})}else{e.error("An error ocurred :(")}})},fetchAndDisplayHistoryContents:function(h){var g=new c.HistoryContents({id:h});var f=this;g.fetch({success:function(j){var i=f.templateHistoryContents();f.histories.get(h).set({contents:j});f.modal.$el.find("#selected_history_content").html(i({history_contents:j.models.reverse()}))},error:function(){e.error("An error ocurred :(")}})},addAllDatasetsFromHistory:function(){this.modal.disableButton("Add");var f=[];this.modal.$el.find("#selected_history_content").find(":checked").each(function(){var i=$(this.parentElement).data("id");if(i){f.push(i)}});var l=this.options.folder_name;var k=this.templateAddingDatasetsProgressBar();this.modal.$el.find(".modal-body").html(k({folder_name:l}));this.progressStep=100/f.length;this.progress=0;var j=[];for(var h=f.length-1;h>=0;h--){history_dataset_id=f[h];var g=new c.Item();g.url="/api/folders/"+this.options.id+"/contents";g.set({from_hda_id:history_dataset_id});j.push(g)}this.chainCallAddingHdas(j)},chainCallAddingHdas:function(g){var f=this;this.added_hdas=new c.Folder();var h=g.pop();if(typeof h==="undefined"){e.success("Datasets from history added to the folder");this.modal.hide();return this.added_hdas}var i=$.when(h.save({from_hda_id:h.get("from_hda_id")}));i.done(function(j){Galaxy.libraries.folderListView.collection.add(j);f.updateProgress();f.chainCallAddingHdas(g)}).fail(function(j){if(j.status===403){e.error("You are not allowed to access a dataset")}else{e.error("An error occured :(")}f.updateProgress();f.chainCallAddingHdas(g)})},templateToolBar:function(){tmpl_array=[];tmpl_array.push('<div class="library_style_container">');tmpl_array.push('<h3>Data Libraries Beta Test. This is work in progress. Please report problems & ideas via <a href="mailto:galaxy-bugs@bx.psu.edu?Subject=DataLibrariesBeta_Feedback" target="_blank">email</a> and <a href="https://trello.com/c/nwYQNFPK/56-data-library-ui-progressive-display-of-fol…" target="_blank">Trello</a>.</h3>');tmpl_array.push('<div id="library_folder_toolbar" >');tmpl_array.push('<div class="btn-group">');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Create New Folder" id="toolbtn_create_folder" class="btn btn-default primary-button" type="button" style="display:none;"><span class="fa fa-plus"></span><span class="fa fa-folder"></span></button>');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Add Datasets to Current Folder" id="toolbtn_add_files" class="btn btn-default toolbtn_add_files primary-button" type="button" style="display:none;"><span class="fa fa-plus"></span><span class="fa fa-file"></span></span></button>');tmpl_array.push("</div>");tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button" style="margin-left: 0.5em; " type="button"><span class="fa fa-book"></span> to history</button>');tmpl_array.push(' <div id="toolbtn_dl" class="btn-group" style="margin-left: 0.5em; ">');tmpl_array.push(' <button title="Download selected datasets" id="drop_toggle" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');tmpl_array.push(' <span class="fa fa-download"></span> download <span class="caret"></span>');tmpl_array.push(" </button>");tmpl_array.push(' <ul class="dropdown-menu" role="menu">');tmpl_array.push(' <li id="download_archive"><a href="#/folders/<%= id %>/download/tgz">.tar.gz</a></li>');tmpl_array.push(' <li id="download_archive"><a href="#/folders/<%= id %>/download/tbz">.tar.bz</a></li>');tmpl_array.push(' <li id="download_archive"><a href="#/folders/<%= id %>/download/zip">.zip</a></li>');tmpl_array.push(" </ul>");tmpl_array.push(" </div>");tmpl_array.push(" </div>");tmpl_array.push(' <div id="folder_items_element">');tmpl_array.push(" </div>");tmpl_array.push("</div>");return _.template(tmpl_array.join(""))},templateNewFolderInModal:function(){tmpl_array=[];tmpl_array.push('<div id="new_folder_modal">');tmpl_array.push("<form>");tmpl_array.push('<input type="text" name="Name" value="" placeholder="Name">');tmpl_array.push('<input type="text" name="Description" value="" placeholder="Description">');tmpl_array.push("</form>");tmpl_array.push("</div>");return _.template(tmpl_array.join(""))},templateBulkImportInModal:function(){var f=[];f.push('<span id="history_modal_combo_bulk" style="width:90%; margin-left: 1em; margin-right: 1em; ">');f.push("Select history: ");f.push('<select id="dataset_import_bulk" name="dataset_import_bulk" style="width:50%; margin-bottom: 1em; "> ');f.push(" <% _.each(histories, function(history) { %>");f.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');f.push(" <% }); %>");f.push("</select>");f.push("</span>");return _.template(f.join(""))},templateImportIntoHistoryProgressBar:function(){var f=[];f.push('<div class="import_text">');f.push("Importing selected datasets to history <b><%= _.escape(history_name) %></b>");f.push("</div>");f.push('<div class="progress">');f.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');f.push(' <span class="completion_span">0% Complete</span>');f.push(" </div>");f.push("</div>");f.push("");return _.template(f.join(""))},templateAddingDatasetsProgressBar:function(){var f=[];f.push('<div class="import_text">');f.push("Adding selected datasets from history to library folder <b><%= _.escape(folder_name) %></b>");f.push("</div>");f.push('<div class="progress">');f.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');f.push(' <span class="completion_span">0% Complete</span>');f.push(" </div>");f.push("</div>");f.push("");return _.template(f.join(""))},templateAddFilesInModal:function(){var f=[];f.push('<div id="add_files_modal">');f.push('<div id="history_modal_combo_bulk">');f.push("Select history: ");f.push('<select id="dataset_add_bulk" name="dataset_add_bulk" style="width:66%; "> ');f.push(" <% _.each(histories, function(history) { %>");f.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');f.push(" <% }); %>");f.push("</select>");f.push("</div>");f.push('<div id="selected_history_content">');f.push("</div>");f.push("</div>");return _.template(f.join(""))},templateHistoryContents:function(){var f=[];f.push("Choose the datasets to import:");f.push("<ul>");f.push(" <% _.each(history_contents, function(history_item) { %>");f.push(' <li data-id="<%= _.escape(history_item.get("id")) %>">');f.push(' <input style="margin: 0;" type="checkbox"><%= _.escape(history_item.get("hid")) %>: <%= _.escape(history_item.get("name")) %>');f.push(" </li>");f.push(" <% }); %>");f.push("</ul>");return _.template(f.join(""))}});return{FolderToolbarView:a}});
\ No newline at end of file
+define(["galaxy.masthead","utils/utils","libs/toastr","mvc/library/library-model"],function(b,d,e,c){var a=Backbone.View.extend({el:"#center",events:{"click #toolbtn_create_folder":"createFolderFromModal","click #toolbtn_bulk_import":"modalBulkImport","click .toolbtn_add_files":"addFilesToFolderModal"},defaults:{can_add_library_item:false,contains_file:false},modal:null,histories:null,initialize:function(f){this.options=_.defaults(f||{},this.defaults);this.render()},render:function(f){this.options=_.extend(this.options,f);var h=this.templateToolBar();var g=false;if(Galaxy.currUser){g=Galaxy.currUser.isAdmin()}this.$el.html(h({id:this.options.id,admin_user:g}))},configureElements:function(f){this.options=_.extend(this.options,f);if(this.options.can_add_library_item===true){$("#toolbtn_create_folder").show();$(".toolbtn_add_files").show()}if(this.options.contains_file===true){$("#toolbtn_bulk_import").show();$("#toolbtn_dl").show()}this.$el.find("[data-toggle]").tooltip()},createFolderFromModal:function(){event.preventDefault();event.stopPropagation();var f=this;var g=this.templateNewFolderInModal();this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Create New Folder",body:g(),buttons:{Create:function(){f.create_new_folder_event()},Close:function(){Galaxy.modal.hide()}}})},create_new_folder_event:function(){var f=this.serialize_new_folder();if(this.validate_new_folder(f)){var g=new c.FolderAsModel();url_items=Backbone.history.fragment.split("/");current_folder_id=url_items[url_items.length-1];g.url=g.urlRoot+"/"+current_folder_id;g.save(f,{success:function(h){Galaxy.modal.hide();e.success("Folder created");h.set({type:"folder"});Galaxy.libraries.folderListView.collection.add(h)},error:function(i,h){Galaxy.modal.hide();if(typeof h.responseJSON!=="undefined"){e.error(h.responseJSON.err_msg)}else{e.error("An error ocurred :(")}}})}else{e.error("Folder's name is missing")}return false},serialize_new_folder:function(){return{name:$("input[name='Name']").val(),description:$("input[name='Description']").val()}},validate_new_folder:function(f){return f.name!==""},modalBulkImport:function(){var f=$("#folder_table").find(":checked");if(f.length===0){e.info("You have to select some datasets first")}else{this.refreshUserHistoriesList(function(g){var h=g.templateBulkImportInModal();g.modal=Galaxy.modal;g.modal.show({closing_events:true,title:"Import into History",body:h({histories:g.histories.models}),buttons:{Import:function(){g.importAllIntoHistory()},Close:function(){Galaxy.modal.hide()}}})})}},refreshUserHistoriesList:function(g){var f=this;this.histories=new c.GalaxyHistories();this.histories.fetch({success:function(){g(f)},error:function(){}})},importAllIntoHistory:function(){this.modal.disableButton("Import");var j=$("select[name=dataset_import_bulk] option:selected").val();this.options.last_used_history_id=j;var m=$("select[name=dataset_import_bulk] option:selected").text();var o=[];$("#folder_table").find(":checked").each(function(){if(this.parentElement.parentElement.id!==""){o.push(this.parentElement.parentElement.id)}});var n=this.templateImportIntoHistoryProgressBar();this.modal.$el.find(".modal-body").html(n({history_name:m}));var k=100/o.length;this.initProgress(k);var f=[];for(var g=o.length-1;g>=0;g--){var h=o[g];var l=new c.HistoryItem();l.url=l.urlRoot+j+"/contents";l.content=h;l.source="library";f.push(l)}this.chainCall(f,m)},chainCall:function(g,j){var f=this;var h=g.pop();if(typeof h==="undefined"){e.success("Datasets were imported to history: "+j);this.modal.hide();return}var i=$.when(h.save({content:h.content,source:h.source}));i.done(function(k){f.updateProgress();f.chainCall(g,j)}).fail(function(k){e.error("An error occured :(");f.updateProgress();f.chainCall(g,j)})},initProgress:function(f){this.progress=0;this.progressStep=f},updateProgress:function(){this.progress+=this.progressStep;$(".progress-bar-import").width(Math.round(this.progress)+"%");txt_representation=Math.round(this.progress)+"% Complete";$(".completion_span").text(txt_representation)},download:function(f,j){var h=[];$("#folder_table").find(":checked").each(function(){if(this.parentElement.parentElement.id!==""){h.push(this.parentElement.parentElement.id)}});var g="/api/libraries/datasets/download/"+j;var i={ldda_ids:h};this.processDownload(g,i,"get")},processDownload:function(g,h,i){if(g&&h){h=typeof h==="string"?h:$.param(h);var f="";$.each(h.split("&"),function(){var j=this.split("=");f+='<input type="hidden" name="'+j[0]+'" value="'+j[1]+'" />'});$('<form action="'+g+'" method="'+(i||"post")+'">'+f+"</form>").appendTo("body").submit().remove();e.info("Your download will begin soon")}},addFilesToFolderModal:function(){this.refreshUserHistoriesList(function(f){f.modal=Galaxy.modal;var g=f.templateAddFilesInModal();f.modal.show({closing_events:true,title:"Add datasets from history to "+f.options.folder_name,body:g({histories:f.histories.models}),buttons:{Add:function(){f.addAllDatasetsFromHistory()},Close:function(){Galaxy.modal.hide()}}});if(f.histories.models.length>0){f.fetchAndDisplayHistoryContents(f.histories.models[0].id);$("#dataset_add_bulk").change(function(h){f.fetchAndDisplayHistoryContents(h.target.value)})}else{e.error("An error ocurred :(")}})},fetchAndDisplayHistoryContents:function(h){var g=new c.HistoryContents({id:h});var f=this;g.fetch({success:function(j){var i=f.templateHistoryContents();f.histories.get(h).set({contents:j});f.modal.$el.find("#selected_history_content").html(i({history_contents:j.models.reverse()}))},error:function(j,i){e.error("An error ocurred :(")}})},addAllDatasetsFromHistory:function(){this.modal.disableButton("Add");var f=[];this.modal.$el.find("#selected_history_content").find(":checked").each(function(){var i=$(this.parentElement).data("id");if(i){f.push(i)}});var l=this.options.folder_name;var k=this.templateAddingDatasetsProgressBar();this.modal.$el.find(".modal-body").html(k({folder_name:l}));this.progressStep=100/f.length;this.progress=0;var j=[];for(var h=f.length-1;h>=0;h--){history_dataset_id=f[h];var g=new c.Item();g.url="/api/folders/"+this.options.id+"/contents";g.set({from_hda_id:history_dataset_id});j.push(g)}this.chainCallAddingHdas(j)},chainCallAddingHdas:function(g){var f=this;this.added_hdas=new c.Folder();var h=g.pop();if(typeof h==="undefined"){e.success("Datasets from history added to the folder");this.modal.hide();return this.added_hdas}var i=$.when(h.save({from_hda_id:h.get("from_hda_id")}));i.done(function(j){Galaxy.libraries.folderListView.collection.add(j);f.updateProgress();f.chainCallAddingHdas(g)}).fail(function(j){if(j.status===403){e.error("You are not allowed to access a dataset")}else{e.error("An error occured :(")}f.updateProgress();f.chainCallAddingHdas(g)})},templateToolBar:function(){tmpl_array=[];tmpl_array.push('<div class="library_style_container">');tmpl_array.push('<h3>Data Libraries Beta Test. This is work in progress. Please report problems & ideas via <a href="mailto:galaxy-bugs@bx.psu.edu?Subject=DataLibrariesBeta_Feedback" target="_blank">email</a> and <a href="https://trello.com/c/nwYQNFPK/56-data-library-ui-progressive-display-of-fol…" target="_blank">Trello</a>.</h3>');tmpl_array.push('<div id="library_folder_toolbar" >');tmpl_array.push('<div class="btn-group">');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Create New Folder" id="toolbtn_create_folder" class="btn btn-default primary-button" type="button" style="display:none;"><span class="fa fa-plus"></span><span class="fa fa-folder"></span></button>');tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Add Datasets to Current Folder" id="toolbtn_add_files" class="btn btn-default toolbtn_add_files primary-button" type="button" style="display:none;"><span class="fa fa-plus"></span><span class="fa fa-file"></span></span></button>');tmpl_array.push("</div>");tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button" style="margin-left: 0.5em; " type="button"><span class="fa fa-book"></span> to history</button>');tmpl_array.push(' <div id="toolbtn_dl" class="btn-group" style="margin-left: 0.5em; ">');tmpl_array.push(' <button title="Download selected datasets" id="drop_toggle" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');tmpl_array.push(' <span class="fa fa-download"></span> download <span class="caret"></span>');tmpl_array.push(" </button>");tmpl_array.push(' <ul class="dropdown-menu" role="menu">');tmpl_array.push(' <li id="download_archive"><a href="#/folders/<%= id %>/download/tgz">.tar.gz</a></li>');tmpl_array.push(' <li id="download_archive"><a href="#/folders/<%= id %>/download/tbz">.tar.bz</a></li>');tmpl_array.push(' <li id="download_archive"><a href="#/folders/<%= id %>/download/zip">.zip</a></li>');tmpl_array.push(" </ul>");tmpl_array.push(" </div>");tmpl_array.push(" </div>");tmpl_array.push(' <div id="folder_items_element">');tmpl_array.push(" </div>");tmpl_array.push("</div>");return _.template(tmpl_array.join(""))},templateNewFolderInModal:function(){tmpl_array=[];tmpl_array.push('<div id="new_folder_modal">');tmpl_array.push("<form>");tmpl_array.push('<input type="text" name="Name" value="" placeholder="Name">');tmpl_array.push('<input type="text" name="Description" value="" placeholder="Description">');tmpl_array.push("</form>");tmpl_array.push("</div>");return _.template(tmpl_array.join(""))},templateBulkImportInModal:function(){var f=[];f.push('<span id="history_modal_combo_bulk" style="width:90%; margin-left: 1em; margin-right: 1em; ">');f.push("Select history: ");f.push('<select id="dataset_import_bulk" name="dataset_import_bulk" style="width:50%; margin-bottom: 1em; "> ');f.push(" <% _.each(histories, function(history) { %>");f.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');f.push(" <% }); %>");f.push("</select>");f.push("</span>");return _.template(f.join(""))},templateImportIntoHistoryProgressBar:function(){var f=[];f.push('<div class="import_text">');f.push("Importing selected datasets to history <b><%= _.escape(history_name) %></b>");f.push("</div>");f.push('<div class="progress">');f.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');f.push(' <span class="completion_span">0% Complete</span>');f.push(" </div>");f.push("</div>");f.push("");return _.template(f.join(""))},templateAddingDatasetsProgressBar:function(){var f=[];f.push('<div class="import_text">');f.push("Adding selected datasets from history to library folder <b><%= _.escape(folder_name) %></b>");f.push("</div>");f.push('<div class="progress">');f.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');f.push(' <span class="completion_span">0% Complete</span>');f.push(" </div>");f.push("</div>");f.push("");return _.template(f.join(""))},templateAddFilesInModal:function(){var f=[];f.push('<div id="add_files_modal">');f.push('<div id="history_modal_combo_bulk">');f.push("Select history: ");f.push('<select id="dataset_add_bulk" name="dataset_add_bulk" style="width:66%; "> ');f.push(" <% _.each(histories, function(history) { %>");f.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');f.push(" <% }); %>");f.push("</select>");f.push("</div>");f.push('<div id="selected_history_content">');f.push("</div>");f.push("</div>");return _.template(f.join(""))},templateHistoryContents:function(){var f=[];f.push("Choose the datasets to import:");f.push("<ul>");f.push(" <% _.each(history_contents, function(history_item) { %>");f.push(' <li data-id="<%= _.escape(history_item.get("id")) %>">');f.push(' <input style="margin: 0;" type="checkbox"><%= _.escape(history_item.get("hid")) %>: <%= _.escape(history_item.get("name")) %>');f.push(" </li>");f.push(" <% }); %>");f.push("</ul>");return _.template(f.join(""))}});return{FolderToolbarView:a}});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: davebgx: Fix functional tests for history functions.
by commits-noreply@bitbucket.org 21 Apr '14
by commits-noreply@bitbucket.org 21 Apr '14
21 Apr '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d2717865114c/
Changeset: d2717865114c
User: davebgx
Date: 2014-04-21 21:42:22
Summary: Fix functional tests for history functions.
Affected #: 2 files
diff -r 9856484a0dcf784ff4bf9e087c14de2e4d6d9506 -r d2717865114c0c577fcd508201acf5eeac2cc54a test/base/twilltestcase.py
--- a/test/base/twilltestcase.py
+++ b/test/base/twilltestcase.py
@@ -270,11 +270,31 @@
return from_json_string( self.last_page() )
# Functions associated with histories
- def get_history_from_api( self, encoded_history_id=None ):
+ def get_history_from_api( self, encoded_history_id=None, show_deleted=None, show_details=False ):
if encoded_history_id is None:
history = self.get_latest_history()
encoded_history_id = history[ 'id' ]
- return self.json_from_url( '/api/histories/%s/contents' % encoded_history_id )
+ params = dict()
+ if show_deleted is not None:
+ params[ 'deleted' ] = show_deleted
+ api_url = '/api/histories/%s/contents?%s' % ( encoded_history_id, urllib.urlencode( params ) )
+ json_data = self.json_from_url( api_url )
+ if show_deleted is not None:
+ hdas = []
+ for hda in json_data:
+ if show_deleted:
+ hdas.append( hda )
+ else:
+ if not hda[ 'deleted' ]:
+ hdas.append( hda )
+ json_data = hdas
+ if show_details:
+ params[ 'details' ] = ','.join( [ hda[ 'id' ] for hda in json_data ] )
+ api_url = '/api/histories/%s/contents?%s' % ( encoded_history_id, urllib.urlencode( params ) )
+ json_data = self.json_from_url( api_url )
+ log.debug( 'detailed url: %s' % api_url )
+ log.debug( 'detailed json data: %s' % json_data )
+ return json_data
def get_latest_history( self ):
return self.json_from_url( '/api/histories' )[ 0 ]
@@ -325,33 +345,21 @@
raise AssertionError( errmsg )
self.home()
- def check_history_json( self, pattern, check_fn, show_deleted=None, multiline=True ):
+ def check_history_json( self, check_fn, show_deleted=None ):
"""
Tries to find a JSON string in the history page using the regex pattern,
parse it, and assert check_fn returns True when called on that parsed
data.
"""
- self.home()
- if show_deleted:
- self.visit_page( "history?show_deleted=True" )
- elif show_deleted == False:
- self.visit_page( "history?show_deleted=False" )
- else:
- self.visit_page( "history" )
- json_data = {}
try:
- tc.find( pattern, flags=( 'm' if multiline else '' ) )
- # twill stores the regex match in a special stack variable
- match = twill.namespaces.get_twill_glocals()[1][ '__match__' ]
- json_data = from_json_string( match )
- assert check_fn( json_data ), 'failed check_fn: %s' % ( check_fn.func_name )
-
- except Exception, exc:
- log.error( exc, exc_info=True )
+ json_data = self.get_history_from_api( show_deleted=show_deleted, show_details=True )
+ check_result = check_fn( json_data )
+ assert check_result, 'failed check_fn: %s (got %s)' % ( check_fn.func_name, str( check_result ) )
+ except Exception, e:
+ log.exception( e )
log.debug( 'json_data: %s', ( '\n' + pprint.pformat( json_data ) if json_data else '(no match)' ) )
fname = self.write_temp_file( tc.browser.get_html() )
- errmsg = ( "json '%s' could not be found or failed check_fn" % ( pattern ) +
- "\npage content written to '%s'" % ( fname ) )
+ errmsg = ( "json could not be read\npage content written to '%s'" % ( fname ) )
raise AssertionError( errmsg )
self.home()
diff -r 9856484a0dcf784ff4bf9e087c14de2e4d6d9506 -r d2717865114c0c577fcd508201acf5eeac2cc54a test/functional/test_history_functions.py
--- a/test/functional/test_history_functions.py
+++ b/test/functional/test_history_functions.py
@@ -665,7 +665,7 @@
if hda[ 'id' ] == self.security.encode_id( hda_2_bed.id ):
return ( not hda[ 'accessible' ] )
return False
- self.check_history_json( r'\bhdaJSON\s*=\s*(.*);', hda_2_bed_is_inaccessible )
+ self.check_history_json( hda_2_bed_is_inaccessible )
# Admin users can view all datasets ( using the history/view feature ), so make sure 2.bed is accessible to the admin
self.logout()
@@ -738,28 +738,26 @@
.order_by( desc( galaxy.model.HistoryDatasetAssociation.table.c.create_time ) )
.first() )
- # delete that item and make sure the 'history empty' message shows
+ # delete that item and make sure the history is not empty
self.home()
log.info( 'deleting last hda' )
self.delete_history_item( str( latest_hda.id ) )
- # check the historyPanel settings.show_deleted for a null json value (no show_deleted in query string)
- self.check_history_json( r'\bshow_deleted\s*:\s*(.*),', lambda x: x == None )
+ # check the number of items returned from the api
+ self.check_history_json( lambda x: len( x ) != 0 )
# reload this history with the show_deleted flag set in the query string
# the deleted dataset should be there with the proper 'deleted' text
- self.home()
log.info( 'turning show_deleted on' )
- #self.visit_url( "%s/history/?show_deleted=True" % self.url )
- # check the historyPanel settings.show_deleted for a true json value
- self.check_history_json( r'\bshow_deleted\s*:\s*(.*),', lambda x: x == True, show_deleted=True )
+ #self.visit_url( "/api/histories/<id>/contents?deleted=True" )
+ # check the number of items returned from the api
+ self.check_history_json( lambda x: len( x ) != 0, show_deleted=True )
# reload this history again with the show_deleted flag set TO FALSE in the query string
- # make sure the 'history empty' message shows
- self.home()
+ # make sure the history is empty
log.info( 'turning show_deleted off' )
- #self.visit_url( "%s/history/?show_deleted=False" % self.url )
- # check the historyPanel settings.show_deleted for a false json value
- self.check_history_json( r'\bshow_deleted\s*:\s*(.*),', lambda x: x == False, show_deleted=False )
+ #self.visit_url( "/api/histories/<id>/contents?deleted=False" )
+ # check the number of items returned from the api
+ self.check_history_json( lambda x: len( x ) == 0, show_deleted=False )
# delete this history
self.delete_history( self.security.encode_id( latest_history.id ) )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
21 Apr '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9856484a0dcf/
Changeset: 9856484a0dcf
User: jmchilton
Date: 2014-04-21 21:28:47
Summary: Pack scripts.
Affected #: 1 file
diff -r 4df5e43d865176cdeb929db7fbf18c3b9af98591 -r 9856484a0dcf784ff4bf9e087c14de2e4d6d9506 static/scripts/packed/galaxy.workflow_editor.canvas.js
--- a/static/scripts/packed/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/packed/galaxy.workflow_editor.canvas.js
@@ -1,1 +1,1 @@
-var Terminal=Backbone.Model.extend({initialize:function(a){this.element=a.element;this.connectors=[]},connect:function(a){this.connectors.push(a);if(this.node){this.node.markChanged()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.markChanged()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}});var OutputTerminal=Terminal.extend({initialize:function(a){Terminal.prototype.initialize.call(this,a);this.datatypes=a.datatypes}});var InputTerminal=Terminal.extend({initialize:function(a){Terminal.prototype.initialize.call(this,a);this.datatypes=a.datatypes;this.multiple=a.multiple},can_accept:function(a){if(this.connectors.length<1||this.multiple){for(var c in this.datatypes){var f=new Array();f=f.concat(a.datatypes);if(a.node.post_job_actions){for(var d in a.node.post_job_actions){var g=a.node.post_job_actions[d];if(g.action_type=="ChangeDatatypeAction"&&(g.output_name==""||g.output_name==a.name)&&g.action_arguments){f.push(g.action_arguments.newtype)}}}for(var b in f){if(f[b]=="input"||issubtype(f[b],this.datatypes[c])){return true}}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a){this.connect(b,a)}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;if(this.handle1){this.handle1.connect(this)}this.handle2=a;if(this.handle2){this.handle2.connect(this)}},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var n=function(c){return $(c).offset().left-d.offset().left};var i=function(c){return $(c).offset().top-d.offset().top};if(!this.handle1||!this.handle2){return}var h=n(this.handle1.element)+5;var g=i(this.handle1.element)+5;var p=n(this.handle2.element)+5;var m=i(this.handle2.element)+5;var f=100;var k=Math.min(h,p);var a=Math.max(h,p);var j=Math.min(g,m);var t=Math.max(g,m);var b=Math.min(Math.max(Math.abs(t-j)/2,100),300);var o=k-f;var s=j-f;var q=a-k+2*f;var l=t-j+2*f;this.canvas.style.left=o+"px";this.canvas.style.top=s+"px";this.canvas.setAttribute("width",q);this.canvas.setAttribute("height",l);h-=o;g-=s;p-=o;m-=s;var r=this.canvas.getContext("2d");r.lineCap="round";r.strokeStyle=this.outer_color;r.lineWidth=7;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke();r.strokeStyle=this.inner_color;r.lineWidth=5;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke()}});var Node=Backbone.Model.extend({initialize:function(a){this.element=a.element;this.input_terminals={};this.output_terminals={};this.tool_errors={}},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(b){if(b.type){this.type=b.type}this.name=b.name;this.form_html=b.form_html;this.tool_state=b.tool_state;this.tool_errors=b.tool_errors;this.tooltip=b.tooltip?b.tooltip:"";this.annotation=b.annotation;this.post_job_actions=b.post_job_actions?b.post_job_actions:{};this.workflow_outputs=b.workflow_outputs?b.workflow_outputs:[];var a=this;var c=new NodeView({el:this.element[0],node:a,});a.nodeView=c;$.each(b.data_inputs,function(f,d){c.addDataInput(d)});if((b.data_inputs.length>0)&&(b.data_outputs.length>0)){c.addRule()}$.each(b.data_outputs,function(f,d){c.addDataOutput(d)});c.render();workflow.node_changed(this)},update_field_data:function(c){var b=this;nodeView=b.nodeView;this.tool_state=c.tool_state;this.form_html=c.form_html;this.tool_errors=c.tool_errors;this.annotation=c.annotation;var d=$.parseJSON(c.post_job_actions);this.post_job_actions=d?d:{};b.nodeView.renderToolErrors();var f=nodeView.$("div.inputs");var a=nodeView.newInputsDiv();$.each(c.data_inputs,function(h,g){b.nodeView.replaceDataInput(g,a)});f.replaceWith(a);f.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.markChanged();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},markChanged:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false;this.active_form_has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},rectify_workflow_outputs:function(){var b=false;var a=false;$.each(this.nodes,function(c,d){if(d.workflow_outputs&&d.workflow_outputs.length>0){b=true}$.each(d.post_job_actions,function(g,f){if(f.action_type==="HideDatasetAction"){a=true}})});if(b!==false||a!==false){$.each(this.nodes,function(c,g){if(g.type==="tool"){var f=false;if(g.post_job_actions==null){g.post_job_actions={};f=true}var d=[];$.each(g.post_job_actions,function(i,h){if(h.action_type=="HideDatasetAction"){d.push(i)}});if(d.length>0){$.each(d,function(h,j){f=true;delete g.post_job_actions[j]})}if(b){$.each(g.output_terminals,function(i,j){var h=true;$.each(g.workflow_outputs,function(l,m){if(j.name===m){h=false}});if(h===true){f=true;var k={action_type:"HideDatasetAction",output_name:j.name,action_arguments:{}};g.post_job_actions["HideDatasetAction"+j.name]=null;g.post_job_actions["HideDatasetAction"+j.name]=k}})}if(workflow.active_node==g&&f===true){workflow.reload_active_node()}}})}},to_simple:function(){var a={};$.each(this.nodes,function(c,f){var g={};$.each(f.input_terminals,function(i,j){g[j.name]=null;var h=[];$.each(j.connectors,function(k,l){h[k]={id:l.handle1.node.id,output_name:l.handle1.name};g[j.name]=h})});var b={};if(f.post_job_actions){$.each(f.post_job_actions,function(j,h){var k={action_type:h.action_type,output_name:h.output_name,action_arguments:h.action_arguments};b[h.action_type+h.output_name]=null;b[h.action_type+h.output_name]=k})}if(!f.workflow_outputs){f.workflow_outputs=[]}var d={id:f.id,type:f.type,tool_id:f.tool_id,tool_state:f.tool_state,tool_errors:f.tool_errors,input_connections:g,position:$(f.element).position(),annotation:f.annotation,post_job_actions:f.post_job_actions,workflow_outputs:f.workflow_outputs};a[f.id]=d});return{steps:a}},from_simple:function(b){wf=this;var c=0;wf.name=b.name;var a=false;$.each(b.steps,function(g,f){var d=prebuild_node(f.type,f.name,f.tool_id);d.init_field_data(f);if(f.position){d.element.css({top:f.position.top,left:f.position.left})}d.id=f.id;wf.nodes[d.id]=d;c=Math.max(c,parseInt(g));if(!a&&d.type==="tool"){if(d.workflow_outputs.length>0){a=true}else{$.each(d.post_job_actions,function(i,h){if(h.action_type==="HideDatasetAction"){a=true}})}}});wf.id_counter=c+1;$.each(b.steps,function(g,f){var d=wf.nodes[g];$.each(f.input_connections,function(i,h){if(h){if(!$.isArray(h)){h=[h]}$.each(h,function(k,j){var m=wf.nodes[j.id];var n=new Connector();n.connect(m.output_terminals[j.output_name],d.input_terminals[i]);n.redraw()})}});if(a&&d.type==="tool"){$.each(d.output_terminals,function(h,i){if(d.post_job_actions["HideDatasetAction"+i.name]===undefined){d.workflow_outputs.push(i.name);callout=$(d.element).find(".callout."+i.name);callout.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png");workflow.has_changes=true}})}})},check_changes_in_active_form:function(){if(this.active_form_has_changes){this.has_changes=true;$("#right-content").find("form").submit();this.active_form_has_changes=false}},reload_active_node:function(){if(this.active_node){var a=this.active_node;this.clear_active_node();this.activate_node(a)}},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.check_changes_in_active_form();this.clear_active_node();parent.show_form_for_tool(a.form_html+a.tooltip,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){this.check_changes_in_active_form();parent.show_form_for_tool(a.form_html+a.tooltip,a)}},layout:function(){this.check_changes_in_active_form();this.has_changes=true;var i={};var b={};$.each(this.nodes,function(l,k){if(i[l]===undefined){i[l]=0}if(b[l]===undefined){b[l]=[]}});$.each(this.nodes,function(l,k){$.each(k.input_terminals,function(m,n){$.each(n.connectors,function(p,q){var o=q.handle1.node;i[k.id]+=1;b[o.id].push(k.id)})})});node_ids_by_level=[];while(true){level_parents=[];for(var a in i){if(i[a]==0){level_parents.push(a)}}if(level_parents.length==0){break}node_ids_by_level.push(level_parents);for(var f in level_parents){var j=level_parents[f];delete i[j];for(var g in b[j]){i[b[j][g]]-=1}}}if(i.length){return}var d=this.nodes;var h=80;v_pad=30;var c=h;$.each(node_ids_by_level,function(k,l){l.sort(function(p,o){return $(d[p].element).position().top-$(d[o].element).position().top});var m=0;var n=v_pad;$.each(l,function(o,r){var q=d[r];var p=$(q.element);$(p).css({top:n,left:c});m=Math.max(m,$(p).width());n+=$(p).height()+v_pad});c+=m+h});$.each(d,function(k,l){l.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(h,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var i=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var h=fix_delta(a.ymin,100);d=Math.max(d,f.left);h=Math.max(h,f.top);var c=f.left-d;var g=f.top-h;var b=round_up(a.xmax+100,100)+d;var j=round_up(a.ymax+100,100)+h;b=Math.max(b,-c+i.width());j=Math.max(j,-g+i.height());this.canvas_container.css({left:c,top:g,width:b,height:j});this.canvas_container.children().each(function(){var k=$(this).position();$(this).css("left",k.left+d);$(this).css("top",k.top+h)})}});function fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(l,j,r){var i=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node({element:i});g.type=l;if(l=="tool"){g.tool_id=r}var n=$("<div class='toolFormTitle unselectable'>"+j+"</div>");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("<div class='toolFormBody'></div>");var h="<div><img height='16' align='middle' src='"+galaxy_config.root+"static/images/loading_small_white_bg.gif'/> loading tool info...</div>";m.append(h);g.form_html=h;i.append(m);var k=$("<div class='buttons' style='float: right;'></div>");k.append($("<div>").addClass("fa-icon-button fa fa-times").click(function(b){g.destroy()}));i.appendTo("#canvas-container");var d=$("#canvas-container").position();var c=$("#canvas-container").parent();var a=i.width();var q=i.height();i.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(q/2)});k.prependTo(n);a+=(k.width()+10);i.css("width",a);$(i).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o,p){var f=$(this).offsetParent().offset(),b=p.offsetX-f.left,s=p.offsetY-f.top;$(this).css({left:b,top:s});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}function add_node(b,d,a){var c=prebuild_node(b,d,a);workflow.add_node(c);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview();workflow.activate_node(c);return c}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}var NodeView=Backbone.View.extend({initialize:function(a){this.node=a.node;this.output_width=Math.max(150,this.$el.width());this.tool_body=this.$el.find(".toolFormBody");this.tool_body.find("div").remove();this.newInputsDiv().appendTo(this.tool_body)},render:function(){this.renderToolErrors();this.$el.css("width",Math.min(250,Math.max(this.$el.width(),this.output_width)))},renderToolErrors:function(){if(this.node.tool_errors){this.$el.addClass("tool-node-error")}else{this.$el.removeClass("tool-node-error")}},newInputsDiv:function(){return $("<div class='inputs'></div>")},updateMaxWidth:function(a){this.output_width=Math.max(this.output_width,a)},addRule:function(){this.tool_body.append($("<div class='rule'></div>"))},addDataInput:function(c){var d=new InputTerminalView({node:this.node,input:c});var f=d.el;var b=new DataInputView({terminalElement:f,input:c,nodeView:this,});var a=b.$el;var f=b.terminalElement;this.$(".inputs").append(a.prepend(f))},replaceDataInput:function(c,f){var g=new InputTerminalView({node:this.node,input:c});var d=g.el;this.$("div[name='"+c.name+"']").each(function(){$(this).find(".input-terminal").each(function(){var h=this.terminal.connectors[0];if(h){d.terminal.connectors[0]=h;h.handle2=d.terminal}});$(this).remove()});var b=new DataInputView({terminalElement:d,input:c,nodeView:this,skipResize:true,});var a=b.$el;f.append(a.prepend(d))},addDataOutput:function(a){var c=new OutputTerminalView({node:this.node,output:a});var b=new DataOutputView({output:a,terminalElement:c.el,nodeView:this,});this.tool_body.append(b.$el.append(b.terminalElement))}});var DataInputView=Backbone.View.extend({className:"form-row dataRow input-data-row",initialize:function(a){this.input=a.input;this.nodeView=a.nodeView;this.terminalElement=a.terminalElement;this.$el.attr("name",this.input.name).html(this.input.label);if(!a.skipResize){this.$el.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(this.el);this.nodeView.updateMaxWidth(this.$el.outerWidth());this.$el.css({position:"",left:"",top:"",display:""});this.$el.remove()}},});var OutputCalloutView=Backbone.View.extend({tagName:"div",initialize:function(b){this.label=b.label;this.node=b.node;this.output=b.output;var a=this;this.$el.attr("class","callout "+this.label).css({display:"none"}).append($("<div class='buttons'></div>").append($("<img/>").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png").click(function(){if($.inArray(a.output.name,a.node.workflow_outputs)!=-1){a.node.workflow_outputs.splice($.inArray(a.output.name,a.node.workflow_outputs),1);a.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{a.node.workflow_outputs.push(a.output.name);a.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}workflow.has_changes=true;canvas_manager.draw_overview()}))).tooltip({delay:500,title:"Mark dataset as a workflow output. All unmarked datasets will be hidden."});this.$el.css({top:"50%",margin:"-8px 0px 0px 0px",right:8});this.$el.show();this.resetImage()},resetImage:function(){if($.inArray(this.output.name,this.node.workflow_outputs)===-1){this.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{this.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}},hoverImage:function(){this.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-yellow.png")}});var DataOutputView=Backbone.View.extend({className:"form-row dataRow",initialize:function(c){this.output=c.output;this.terminalElement=c.terminalElement;this.nodeView=c.nodeView;var a=this.output;var b=a.name;var d=this.nodeView.node;if(a.extensions.indexOf("input")<0){b=b+" ("+a.extensions.join(", ")+")"}this.$el.html(b);if(d.type=="tool"){var f=new OutputCalloutView({label:b,output:a,node:d,});this.$el.append(f.el);this.$el.hover(function(){f.hoverImage()},function(){f.resetImage()})}this.$el.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(this.el);this.nodeView.updateMaxWidth(this.$el.outerWidth()+17);this.$el.css({position:"",left:"",top:"",display:""}).detach()}});var InputTerminalView=Backbone.View.extend({className:"terminal input-terminal",initialize:function(d){var h=d.node;var b=d.input;var c=b.name;var g=b.extensions;var a=b.multiple;var f=this.el.terminal=new InputTerminal({element:this.el,datatypes:g,multiple:a});f.node=h;f.name=c;h.input_terminals[c]=f},events:{dropinit:"onDropInit",dropstart:"onDropStart",dropend:"onDropEnd",drop:"onDrop",hover:"onHover",},onDropInit:function(b,c){var a=this.el.terminal;return $(c.drag).hasClass("output-terminal")&&a.can_accept(c.drag.terminal)},onDropStart:function(a,b){if(b.proxy.terminal){b.proxy.terminal.connectors[0].inner_color="#BBFFBB"}},onDropEnd:function(a,b){if(b.proxy.terminal){b.proxy.terminal.connectors[0].inner_color="#FFFFFF"}},onDrop:function(b,c){var a=this.el.terminal;new Connector(c.drag.terminal,a).redraw()},onHover:function(){var c=this.el;var b=c.terminal;if(b.connectors.length>0){var a=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='button'></div>").append($("<div/>").addClass("fa-icon-button fa fa-times").click(function(){$.each(b.connectors,function(f,d){if(d){d.destroy()}});a.remove()}))).bind("mouseleave",function(){$(this).remove()});a.css({top:$(c).offset().top-2,left:$(c).offset().left-a.width(),"padding-right":$(c).width()}).show()}},});var OutputTerminalView=Backbone.View.extend({className:"terminal output-terminal",initialize:function(c){var i=c.node;var a=c.output;var b=a.name;var h=a.extensions;var g=this.el;var f=g;var d=g.terminal=new OutputTerminal({element:g,datatypes:h});d.node=i;d.name=b;i.output_terminals[b]=d},events:{drag:"onDrag",dragstart:"onDragStart",dragend:"onDragEnd",},onDrag:function(b,c){var a=function(){var f=$(c.proxy).offsetParent().offset(),d=c.offsetX-f.left,g=c.offsetY-f.top;$(c.proxy).css({left:d,top:g});c.proxy.terminal.redraw();canvas_manager.update_viewport_overlay()};a();$("#canvas-container").get(0).scroll_panel.test(b,a)},onDragStart:function(b,f){$(f.available).addClass("input-terminal-active");workflow.check_changes_in_active_form();var a=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);a.terminal=new OutputTerminal({element:a});var g=new Connector();g.dragging=true;g.connect(this.el.terminal,a.terminal);return a},onDragEnd:function(a,b){b.proxy.terminal.connectors[0].destroy();$(b.proxy).remove();$(b.available).removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()}});function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(v,d){clearTimeout(this.timeout);var k=v.pageX,j=v.pageY,l=$(this.panel),c=l.position(),b=l.width(),i=l.height(),w=l.parent(),s=w.width(),a=w.height(),r=w.offset(),p=r.left,m=r.top,A=p+w.width(),u=m+w.height(),B=-(b-(s/2)),z=-(i-(a/2)),g=(s/2),f=(a/2),h=false,q=5,o=23;if(k-q<p){if(c.left<g){var n=Math.min(o,g-c.left);l.css("left",c.left+n);h=true}}else{if(k+q>A){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-q<m){if(c.top<f){var n=Math.min(o,f-c.top);l.css("top",c.top+n);h=true}}else{if(j+q>u){if(c.top>z){var n=Math.min(o,c.top-B);l.css("top",(c.top-n)+"px");h=true}}}}}if(h){d();var l=this;this.timeout=setTimeout(function(){l.test(v,d)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(){var g=$(this).offset();var f=b.cc.position();c=f.top-g.top;d=f.left-g.left}).bind("drag",function(f,g){a(g.offsetX+d,g.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("drag",function(k,l){var h=b.cc.width(),n=b.cc.height(),m=b.oc.width(),j=b.oc.height(),f=$(this).offsetParent().offset(),i=l.offsetX-f.left,g=l.offsetY-f.top;a(-(i/m*h),-(g/j*n))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g,i){var j=$(this).offsetParent();var h=j.offset();var f=Math.max(j.width()-(i.offsetX-h.left),j.height()-(i.offsetY-h.top));$(this).css({width:f,height:f});b.draw_overview()});$("#overview-border div").bind("drag",function(){})},update_viewport_overlay:function(){var b=this.cc,f=this.cv,a=this.oc,c=this.ov,d=b.width(),j=b.height(),i=a.width(),g=a.height(),h=b.position();c.css({left:-(h.left/d*i),top:-(h.top/j*g),width:(f.width()/d*i)-2,height:(f.height()/j*g)-2})},draw_overview:function(){var j=$("#overview-canvas"),m=j.parent().parent().width(),i=j.get(0).getContext("2d"),d=$("#canvas-container").width(),l=$("#canvas-container").height();var g,a,k,f;var h=this.cv.width();var b=this.cv.height();if(d<h&&l<b){k=d/h*m;f=(m-k)/2;g=l/b*m;a=(m-g)/2}else{if(d<l){a=0;g=m;k=Math.ceil(g*d/l);f=(m-k)/2}else{k=m;f=0;g=Math.ceil(k*l/d);a=(m-g)/2}}j.parent().css({left:f,top:a,width:k,height:g});j.attr("width",k);j.attr("height",g);$.each(workflow.nodes,function(t,q){i.fillStyle="#D2C099";i.strokeStyle="#D8B365";i.lineWidth=1;var s=$(q.element),n=s.position(),c=n.left/d*k,r=n.top/l*g,o=s.width()/d*k,p=s.height()/l*g;if(q.tool_errors){i.fillStyle="#FFCCCC";i.strokeStyle="#AA6666"}else{if(q.workflow_outputs!=undefined&&q.workflow_outputs.length>0){i.fillStyle="#E8A92D";i.strokeStyle="#E8A92D"}}i.fillRect(c,r,o,p);i.strokeRect(c,r,o,p)});this.update_viewport_overlay()}});
\ No newline at end of file
+var Terminal=Backbone.Model.extend({initialize:function(a){this.element=a.element;this.connectors=[]},connect:function(a){this.connectors.push(a);if(this.node){this.node.markChanged()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.markChanged()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}});var OutputTerminal=Terminal.extend({initialize:function(a){Terminal.prototype.initialize.call(this,a);this.datatypes=a.datatypes}});var InputTerminal=Terminal.extend({initialize:function(a){Terminal.prototype.initialize.call(this,a);this.datatypes=a.datatypes;this.multiple=a.multiple},canAccept:function(a){if(this._inputFilled()){return false}else{return this.attachable(a)}},_inputFilled:function(){return !(this.connectors.length<1||this.multiple)},attachable:function(a){for(var c in this.datatypes){var f=new Array();f=f.concat(a.datatypes);if(a.node.post_job_actions){for(var d in a.node.post_job_actions){var g=a.node.post_job_actions[d];if(g.action_type=="ChangeDatatypeAction"&&(g.output_name==""||g.output_name==a.name)&&g.action_arguments){f.push(g.action_arguments.newtype)}}}for(var b in f){if(f[b]=="input"||issubtype(f[b],this.datatypes[c])){return true}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a){this.connect(b,a)}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;if(this.handle1){this.handle1.connect(this)}this.handle2=a;if(this.handle2){this.handle2.connect(this)}},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var n=function(c){return $(c).offset().left-d.offset().left};var i=function(c){return $(c).offset().top-d.offset().top};if(!this.handle1||!this.handle2){return}var h=n(this.handle1.element)+5;var g=i(this.handle1.element)+5;var p=n(this.handle2.element)+5;var m=i(this.handle2.element)+5;var f=100;var k=Math.min(h,p);var a=Math.max(h,p);var j=Math.min(g,m);var t=Math.max(g,m);var b=Math.min(Math.max(Math.abs(t-j)/2,100),300);var o=k-f;var s=j-f;var q=a-k+2*f;var l=t-j+2*f;this.canvas.style.left=o+"px";this.canvas.style.top=s+"px";this.canvas.setAttribute("width",q);this.canvas.setAttribute("height",l);h-=o;g-=s;p-=o;m-=s;var r=this.canvas.getContext("2d");r.lineCap="round";r.strokeStyle=this.outer_color;r.lineWidth=7;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke();r.strokeStyle=this.inner_color;r.lineWidth=5;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke()}});var Node=Backbone.Model.extend({initialize:function(a){this.element=a.element;this.input_terminals={};this.output_terminals={};this.tool_errors={}},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(b){if(b.type){this.type=b.type}this.name=b.name;this.form_html=b.form_html;this.tool_state=b.tool_state;this.tool_errors=b.tool_errors;this.tooltip=b.tooltip?b.tooltip:"";this.annotation=b.annotation;this.post_job_actions=b.post_job_actions?b.post_job_actions:{};this.workflow_outputs=b.workflow_outputs?b.workflow_outputs:[];var a=this;var c=new NodeView({el:this.element[0],node:a,});a.nodeView=c;$.each(b.data_inputs,function(f,d){c.addDataInput(d)});if((b.data_inputs.length>0)&&(b.data_outputs.length>0)){c.addRule()}$.each(b.data_outputs,function(f,d){c.addDataOutput(d)});c.render();workflow.node_changed(this)},update_field_data:function(c){var b=this;nodeView=b.nodeView;this.tool_state=c.tool_state;this.form_html=c.form_html;this.tool_errors=c.tool_errors;this.annotation=c.annotation;var d=$.parseJSON(c.post_job_actions);this.post_job_actions=d?d:{};b.nodeView.renderToolErrors();var f=nodeView.$("div.inputs");var a=nodeView.newInputsDiv();$.each(c.data_inputs,function(h,g){b.nodeView.replaceDataInput(g,a)});f.replaceWith(a);f.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.markChanged();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},markChanged:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false;this.active_form_has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},rectify_workflow_outputs:function(){var b=false;var a=false;$.each(this.nodes,function(c,d){if(d.workflow_outputs&&d.workflow_outputs.length>0){b=true}$.each(d.post_job_actions,function(g,f){if(f.action_type==="HideDatasetAction"){a=true}})});if(b!==false||a!==false){$.each(this.nodes,function(c,g){if(g.type==="tool"){var f=false;if(g.post_job_actions==null){g.post_job_actions={};f=true}var d=[];$.each(g.post_job_actions,function(i,h){if(h.action_type=="HideDatasetAction"){d.push(i)}});if(d.length>0){$.each(d,function(h,j){f=true;delete g.post_job_actions[j]})}if(b){$.each(g.output_terminals,function(i,j){var h=true;$.each(g.workflow_outputs,function(l,m){if(j.name===m){h=false}});if(h===true){f=true;var k={action_type:"HideDatasetAction",output_name:j.name,action_arguments:{}};g.post_job_actions["HideDatasetAction"+j.name]=null;g.post_job_actions["HideDatasetAction"+j.name]=k}})}if(workflow.active_node==g&&f===true){workflow.reload_active_node()}}})}},to_simple:function(){var a={};$.each(this.nodes,function(c,f){var g={};$.each(f.input_terminals,function(i,j){g[j.name]=null;var h=[];$.each(j.connectors,function(k,l){h[k]={id:l.handle1.node.id,output_name:l.handle1.name};g[j.name]=h})});var b={};if(f.post_job_actions){$.each(f.post_job_actions,function(j,h){var k={action_type:h.action_type,output_name:h.output_name,action_arguments:h.action_arguments};b[h.action_type+h.output_name]=null;b[h.action_type+h.output_name]=k})}if(!f.workflow_outputs){f.workflow_outputs=[]}var d={id:f.id,type:f.type,tool_id:f.tool_id,tool_state:f.tool_state,tool_errors:f.tool_errors,input_connections:g,position:$(f.element).position(),annotation:f.annotation,post_job_actions:f.post_job_actions,workflow_outputs:f.workflow_outputs};a[f.id]=d});return{steps:a}},from_simple:function(b){wf=this;var c=0;wf.name=b.name;var a=false;$.each(b.steps,function(g,f){var d=prebuild_node(f.type,f.name,f.tool_id);d.init_field_data(f);if(f.position){d.element.css({top:f.position.top,left:f.position.left})}d.id=f.id;wf.nodes[d.id]=d;c=Math.max(c,parseInt(g));if(!a&&d.type==="tool"){if(d.workflow_outputs.length>0){a=true}else{$.each(d.post_job_actions,function(i,h){if(h.action_type==="HideDatasetAction"){a=true}})}}});wf.id_counter=c+1;$.each(b.steps,function(g,f){var d=wf.nodes[g];$.each(f.input_connections,function(i,h){if(h){if(!$.isArray(h)){h=[h]}$.each(h,function(k,j){var m=wf.nodes[j.id];var n=new Connector();n.connect(m.output_terminals[j.output_name],d.input_terminals[i]);n.redraw()})}});if(a&&d.type==="tool"){$.each(d.output_terminals,function(h,i){if(d.post_job_actions["HideDatasetAction"+i.name]===undefined){d.workflow_outputs.push(i.name);callout=$(d.element).find(".callout."+i.name);callout.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png");workflow.has_changes=true}})}})},check_changes_in_active_form:function(){if(this.active_form_has_changes){this.has_changes=true;$("#right-content").find("form").submit();this.active_form_has_changes=false}},reload_active_node:function(){if(this.active_node){var a=this.active_node;this.clear_active_node();this.activate_node(a)}},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.check_changes_in_active_form();this.clear_active_node();parent.show_form_for_tool(a.form_html+a.tooltip,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){this.check_changes_in_active_form();parent.show_form_for_tool(a.form_html+a.tooltip,a)}},layout:function(){this.check_changes_in_active_form();this.has_changes=true;var i={};var b={};$.each(this.nodes,function(l,k){if(i[l]===undefined){i[l]=0}if(b[l]===undefined){b[l]=[]}});$.each(this.nodes,function(l,k){$.each(k.input_terminals,function(m,n){$.each(n.connectors,function(p,q){var o=q.handle1.node;i[k.id]+=1;b[o.id].push(k.id)})})});node_ids_by_level=[];while(true){level_parents=[];for(var a in i){if(i[a]==0){level_parents.push(a)}}if(level_parents.length==0){break}node_ids_by_level.push(level_parents);for(var f in level_parents){var j=level_parents[f];delete i[j];for(var g in b[j]){i[b[j][g]]-=1}}}if(i.length){return}var d=this.nodes;var h=80;v_pad=30;var c=h;$.each(node_ids_by_level,function(k,l){l.sort(function(p,o){return $(d[p].element).position().top-$(d[o].element).position().top});var m=0;var n=v_pad;$.each(l,function(o,r){var q=d[r];var p=$(q.element);$(p).css({top:n,left:c});m=Math.max(m,$(p).width());n+=$(p).height()+v_pad});c+=m+h});$.each(d,function(k,l){l.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(h,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var i=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var h=fix_delta(a.ymin,100);d=Math.max(d,f.left);h=Math.max(h,f.top);var c=f.left-d;var g=f.top-h;var b=round_up(a.xmax+100,100)+d;var j=round_up(a.ymax+100,100)+h;b=Math.max(b,-c+i.width());j=Math.max(j,-g+i.height());this.canvas_container.css({left:c,top:g,width:b,height:j});this.canvas_container.children().each(function(){var k=$(this).position();$(this).css("left",k.left+d);$(this).css("top",k.top+h)})}});function fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(l,j,r){var i=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node({element:i});g.type=l;if(l=="tool"){g.tool_id=r}var n=$("<div class='toolFormTitle unselectable'>"+j+"</div>");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("<div class='toolFormBody'></div>");var h="<div><img height='16' align='middle' src='"+galaxy_config.root+"static/images/loading_small_white_bg.gif'/> loading tool info...</div>";m.append(h);g.form_html=h;i.append(m);var k=$("<div class='buttons' style='float: right;'></div>");k.append($("<div>").addClass("fa-icon-button fa fa-times").click(function(b){g.destroy()}));i.appendTo("#canvas-container");var d=$("#canvas-container").position();var c=$("#canvas-container").parent();var a=i.width();var q=i.height();i.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(q/2)});k.prependTo(n);a+=(k.width()+10);i.css("width",a);$(i).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o,p){var f=$(this).offsetParent().offset(),b=p.offsetX-f.left,s=p.offsetY-f.top;$(this).css({left:b,top:s});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}function add_node(b,d,a){var c=prebuild_node(b,d,a);workflow.add_node(c);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview();workflow.activate_node(c);return c}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}var NodeView=Backbone.View.extend({initialize:function(a){this.node=a.node;this.output_width=Math.max(150,this.$el.width());this.tool_body=this.$el.find(".toolFormBody");this.tool_body.find("div").remove();this.newInputsDiv().appendTo(this.tool_body)},render:function(){this.renderToolErrors();this.$el.css("width",Math.min(250,Math.max(this.$el.width(),this.output_width)))},renderToolErrors:function(){if(this.node.tool_errors){this.$el.addClass("tool-node-error")}else{this.$el.removeClass("tool-node-error")}},newInputsDiv:function(){return $("<div class='inputs'></div>")},updateMaxWidth:function(a){this.output_width=Math.max(this.output_width,a)},addRule:function(){this.tool_body.append($("<div class='rule'></div>"))},addDataInput:function(c){var d=new InputTerminalView({node:this.node,input:c});var f=d.el;var b=new DataInputView({terminalElement:f,input:c,nodeView:this,});var a=b.$el;var f=b.terminalElement;this.$(".inputs").append(a.prepend(f))},replaceDataInput:function(c,f){var g=new InputTerminalView({node:this.node,input:c});var d=g.el;this.$("div[name='"+c.name+"']").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){var h=d.terminal;if(i.handle1&&!h.attachable(i.handle1)){i.destroy()}else{h.connectors[0]=i;i.handle2=h}}});$(this).remove()});var b=new DataInputView({terminalElement:d,input:c,nodeView:this,skipResize:true,});var a=b.$el;f.append(a.prepend(d))},addDataOutput:function(a){var c=new OutputTerminalView({node:this.node,output:a});var b=new DataOutputView({output:a,terminalElement:c.el,nodeView:this,});this.tool_body.append(b.$el.append(b.terminalElement))}});var DataInputView=Backbone.View.extend({className:"form-row dataRow input-data-row",initialize:function(a){this.input=a.input;this.nodeView=a.nodeView;this.terminalElement=a.terminalElement;this.$el.attr("name",this.input.name).html(this.input.label);if(!a.skipResize){this.$el.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(this.el);this.nodeView.updateMaxWidth(this.$el.outerWidth());this.$el.css({position:"",left:"",top:"",display:""});this.$el.remove()}},});var OutputCalloutView=Backbone.View.extend({tagName:"div",initialize:function(b){this.label=b.label;this.node=b.node;this.output=b.output;var a=this;this.$el.attr("class","callout "+this.label).css({display:"none"}).append($("<div class='buttons'></div>").append($("<img/>").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png").click(function(){if($.inArray(a.output.name,a.node.workflow_outputs)!=-1){a.node.workflow_outputs.splice($.inArray(a.output.name,a.node.workflow_outputs),1);a.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{a.node.workflow_outputs.push(a.output.name);a.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}workflow.has_changes=true;canvas_manager.draw_overview()}))).tooltip({delay:500,title:"Mark dataset as a workflow output. All unmarked datasets will be hidden."});this.$el.css({top:"50%",margin:"-8px 0px 0px 0px",right:8});this.$el.show();this.resetImage()},resetImage:function(){if($.inArray(this.output.name,this.node.workflow_outputs)===-1){this.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{this.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}},hoverImage:function(){this.$("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-yellow.png")}});var DataOutputView=Backbone.View.extend({className:"form-row dataRow",initialize:function(c){this.output=c.output;this.terminalElement=c.terminalElement;this.nodeView=c.nodeView;var a=this.output;var b=a.name;var d=this.nodeView.node;if(a.extensions.indexOf("input")<0){b=b+" ("+a.extensions.join(", ")+")"}this.$el.html(b);if(d.type=="tool"){var f=new OutputCalloutView({label:b,output:a,node:d,});this.$el.append(f.el);this.$el.hover(function(){f.hoverImage()},function(){f.resetImage()})}this.$el.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(this.el);this.nodeView.updateMaxWidth(this.$el.outerWidth()+17);this.$el.css({position:"",left:"",top:"",display:""}).detach()}});var InputTerminalView=Backbone.View.extend({className:"terminal input-terminal",initialize:function(d){var h=d.node;var b=d.input;var c=b.name;var g=b.extensions;var a=b.multiple;var f=this.el.terminal=new InputTerminal({element:this.el,datatypes:g,multiple:a});f.node=h;f.name=c;h.input_terminals[c]=f},events:{dropinit:"onDropInit",dropstart:"onDropStart",dropend:"onDropEnd",drop:"onDrop",hover:"onHover",},onDropInit:function(b,c){var a=this.el.terminal;return $(c.drag).hasClass("output-terminal")&&a.canAccept(c.drag.terminal)},onDropStart:function(a,b){if(b.proxy.terminal){b.proxy.terminal.connectors[0].inner_color="#BBFFBB"}},onDropEnd:function(a,b){if(b.proxy.terminal){b.proxy.terminal.connectors[0].inner_color="#FFFFFF"}},onDrop:function(b,c){var a=this.el.terminal;new Connector(c.drag.terminal,a).redraw()},onHover:function(){var c=this.el;var b=c.terminal;if(b.connectors.length>0){var a=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='button'></div>").append($("<div/>").addClass("fa-icon-button fa fa-times").click(function(){$.each(b.connectors,function(f,d){if(d){d.destroy()}});a.remove()}))).bind("mouseleave",function(){$(this).remove()});a.css({top:$(c).offset().top-2,left:$(c).offset().left-a.width(),"padding-right":$(c).width()}).show()}},});var OutputTerminalView=Backbone.View.extend({className:"terminal output-terminal",initialize:function(c){var i=c.node;var a=c.output;var b=a.name;var h=a.extensions;var g=this.el;var f=g;var d=g.terminal=new OutputTerminal({element:g,datatypes:h});d.node=i;d.name=b;i.output_terminals[b]=d},events:{drag:"onDrag",dragstart:"onDragStart",dragend:"onDragEnd",},onDrag:function(b,c){var a=function(){var f=$(c.proxy).offsetParent().offset(),d=c.offsetX-f.left,g=c.offsetY-f.top;$(c.proxy).css({left:d,top:g});c.proxy.terminal.redraw();canvas_manager.update_viewport_overlay()};a();$("#canvas-container").get(0).scroll_panel.test(b,a)},onDragStart:function(b,f){$(f.available).addClass("input-terminal-active");workflow.check_changes_in_active_form();var a=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);a.terminal=new OutputTerminal({element:a});var g=new Connector();g.dragging=true;g.connect(this.el.terminal,a.terminal);return a},onDragEnd:function(a,b){b.proxy.terminal.connectors[0].destroy();$(b.proxy).remove();$(b.available).removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()}});function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(v,d){clearTimeout(this.timeout);var k=v.pageX,j=v.pageY,l=$(this.panel),c=l.position(),b=l.width(),i=l.height(),w=l.parent(),s=w.width(),a=w.height(),r=w.offset(),p=r.left,m=r.top,A=p+w.width(),u=m+w.height(),B=-(b-(s/2)),z=-(i-(a/2)),g=(s/2),f=(a/2),h=false,q=5,o=23;if(k-q<p){if(c.left<g){var n=Math.min(o,g-c.left);l.css("left",c.left+n);h=true}}else{if(k+q>A){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-q<m){if(c.top<f){var n=Math.min(o,f-c.top);l.css("top",c.top+n);h=true}}else{if(j+q>u){if(c.top>z){var n=Math.min(o,c.top-B);l.css("top",(c.top-n)+"px");h=true}}}}}if(h){d();var l=this;this.timeout=setTimeout(function(){l.test(v,d)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(){var g=$(this).offset();var f=b.cc.position();c=f.top-g.top;d=f.left-g.left}).bind("drag",function(f,g){a(g.offsetX+d,g.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("drag",function(k,l){var h=b.cc.width(),n=b.cc.height(),m=b.oc.width(),j=b.oc.height(),f=$(this).offsetParent().offset(),i=l.offsetX-f.left,g=l.offsetY-f.top;a(-(i/m*h),-(g/j*n))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g,i){var j=$(this).offsetParent();var h=j.offset();var f=Math.max(j.width()-(i.offsetX-h.left),j.height()-(i.offsetY-h.top));$(this).css({width:f,height:f});b.draw_overview()});$("#overview-border div").bind("drag",function(){})},update_viewport_overlay:function(){var b=this.cc,f=this.cv,a=this.oc,c=this.ov,d=b.width(),j=b.height(),i=a.width(),g=a.height(),h=b.position();c.css({left:-(h.left/d*i),top:-(h.top/j*g),width:(f.width()/d*i)-2,height:(f.height()/j*g)-2})},draw_overview:function(){var j=$("#overview-canvas"),m=j.parent().parent().width(),i=j.get(0).getContext("2d"),d=$("#canvas-container").width(),l=$("#canvas-container").height();var g,a,k,f;var h=this.cv.width();var b=this.cv.height();if(d<h&&l<b){k=d/h*m;f=(m-k)/2;g=l/b*m;a=(m-g)/2}else{if(d<l){a=0;g=m;k=Math.ceil(g*d/l);f=(m-k)/2}else{k=m;f=0;g=Math.ceil(k*l/d);a=(m-g)/2}}j.parent().css({left:f,top:a,width:k,height:g});j.attr("width",k);j.attr("height",g);$.each(workflow.nodes,function(t,q){i.fillStyle="#D2C099";i.strokeStyle="#D8B365";i.lineWidth=1;var s=$(q.element),n=s.position(),c=n.left/d*k,r=n.top/l*g,o=s.width()/d*k,p=s.height()/l*g;if(q.tool_errors){i.fillStyle="#FFCCCC";i.strokeStyle="#AA6666"}else{if(q.workflow_outputs!=undefined&&q.workflow_outputs.length>0){i.fillStyle="#E8A92D";i.strokeStyle="#E8A92D"}}i.fillRect(c,r,o,p);i.strokeRect(c,r,o,p)});this.update_viewport_overlay()}});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
5 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/bf3c4ce994bf/
Changeset: bf3c4ce994bf
User: jmchilton
Date: 2014-04-21 21:26:56
Summary: Fix comment in lib/galaxy/workflow/run.py
Affected #: 1 file
diff -r 64ae9dc170214097c419febe12e52b86bea12020 -r bf3c4ce994bf25c3744338a3d8edbdb5da847fe4 lib/galaxy/workflow/run.py
--- a/lib/galaxy/workflow/run.py
+++ b/lib/galaxy/workflow/run.py
@@ -66,9 +66,10 @@
workflow_invocation = model.WorkflowInvocation()
workflow_invocation.workflow = self.workflow
- # Web controller will populate stateful modules on each step before calling invoke
- # but not API controller. More work should be done to further harmonize these methods
- # going forward if possible - if possible moving more web controller logic here.
+ # Web controller will populate state on each step before calling
+ # invoke but not API controller. More work should be done to further
+ # harmonize these methods going forward if possible - if possible
+ # moving more web controller logic here.
state_populated = not self.workflow.steps or hasattr( self.workflow.steps[ 0 ], "state" )
if not state_populated:
self._populate_state( )
https://bitbucket.org/galaxy/galaxy-central/commits/6d1b5997e85b/
Changeset: 6d1b5997e85b
User: jmchilton
Date: 2014-04-21 21:27:01
Summary: Workflow Editor: Rename can_accept to canAccept.
Affected #: 2 files
diff -r bf3c4ce994bf25c3744338a3d8edbdb5da847fe4 -r 6d1b5997e85b9bdb75308fdb5db6cb5fa7e09941 static/scripts/galaxy.workflow_editor.canvas.js
--- a/static/scripts/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/galaxy.workflow_editor.canvas.js
@@ -41,7 +41,7 @@
this.datatypes = attr.datatypes;
this.multiple = attr.multiple;
},
- can_accept: function ( other ) {
+ canAccept: function ( other ) {
if ( this.connectors.length < 1 || this.multiple) {
for ( var t in this.datatypes ) {
var cat_outputs = new Array();
@@ -989,7 +989,7 @@
var terminal = this.el.terminal;
// Accept a dragable if it is an output terminal and has a
// compatible type
- return $(d.drag).hasClass( "output-terminal" ) && terminal.can_accept( d.drag.terminal );
+ return $(d.drag).hasClass( "output-terminal" ) && terminal.canAccept( d.drag.terminal );
},
onDropStart: function( e, d ) {
diff -r bf3c4ce994bf25c3744338a3d8edbdb5da847fe4 -r 6d1b5997e85b9bdb75308fdb5db6cb5fa7e09941 test/qunit/tests/workflow_editor_tests.js
--- a/test/qunit/tests/workflow_editor_tests.js
+++ b/test/qunit/tests/workflow_editor_tests.js
@@ -76,7 +76,7 @@
},
test_accept: function( other ) {
other = other || { node: {}, datatypes: [ "txt" ] };
- return this.input_terminal.can_accept( other );
+ return this.input_terminal.canAccept( other );
}
} );
https://bitbucket.org/galaxy/galaxy-central/commits/a1d1f25181f4/
Changeset: a1d1f25181f4
User: jmchilton
Date: 2014-04-21 21:27:01
Summary: Workflow Editor: Improve tests related to input terminal canAccept/datatypes.
Elminate stub, create mock tree off inputs (demonstrates what server is feeding), add test for direct and subtype. Add tests for PJA changing output connection datatypes.
Affected #: 1 file
diff -r 6d1b5997e85b9bdb75308fdb5db6cb5fa7e09941 -r a1d1f25181f4689de3e946ed1ce1aa5494e7d781 test/qunit/tests/workflow_editor_tests.js
--- a/test/qunit/tests/workflow_editor_tests.js
+++ b/test/qunit/tests/workflow_editor_tests.js
@@ -16,20 +16,25 @@
window.workflow = null;
window.canvas_manager = null;
- // Stub used over stubbing issubtype for unit testing datatype comparisons.
- var issubtypeStub = null;
QUnit.moduleStart(function() {
- if( issubtypeStub === null) {
- issubtypeStub = sinon.stub( window, "issubtype" );
- }
- });
- QUnit.moduleDone(function() {
- if( issubtypeStub !== null) {
- issubtypeStub.restore();
- issubtypeStub = null;
- }
- });
+ window.populate_datatype_info({
+ ext_to_class_name: {
+ 'txt': 'Text',
+ 'data': 'Data',
+ 'tabular': 'Tabular',
+ 'binary': 'Binary',
+ 'bam': 'Bam'
+ },
+ class_to_classes: {
+ 'Data': { 'Data': true },
+ 'Text': { 'Text': true, 'Data': true },
+ 'Tabular': { 'Tabular': true, 'Text': true, 'Data': true },
+ 'Binary': { 'Data': true, 'Binary': true },
+ 'Bam': { 'Data': true, 'Binary': true, 'Bam': true }
+ }
+ } );
+ } );
var with_canvas_container = function( f ) {
var canvas_container = $("<div id='canvas-container'>");
@@ -77,6 +82,11 @@
test_accept: function( other ) {
other = other || { node: {}, datatypes: [ "txt" ] };
return this.input_terminal.canAccept( other );
+ },
+ pja_change_datatype_node: function( output_name, newtype ) {
+ var pja = { action_type: "ChangeDatatypeAction", output_name: output_name, action_arguments: { newtype: newtype } };
+ var otherNode = { post_job_actions: [ pja ] };
+ return otherNode;
}
} );
@@ -119,18 +129,46 @@
ok( connector.destroy.called );
} );
- test( "can accept correct datatype", function() {
- issubtypeStub.returns(true);
+ test( "can accept exact datatype", function() {
+ var other = { node: {}, datatypes: [ "txt" ] }; // input also txt
+
ok( this.test_accept() ) ;
} );
- test( "cannot accept incorrect datatypes", function() {
- issubtypeStub.returns(false);
- ok( ! this.test_accept() );
+ test( "can accept subclass datatype", function() {
+ var other = { node: {}, datatypes: [ "tabular" ] }; // tabular subclass of input txt
+
+ ok( this.test_accept() ) ;
+ } );
+
+ test( "cannot accept incorrect datatype", function() {
+ var other = { node: {}, datatypes: [ "binary" ] }; // binary is not txt
+
+ ok( ! this.test_accept( other ) );
+ } );
+
+ test( "can accept incorrect datatype if converted with PJA", function() {
+ var otherNode = this.pja_change_datatype_node( "out1", "txt" );
+ var other = { node: otherNode, datatypes: [ "binary" ], name: "out1" }; // Was binary but converted to txt
+
+ ok( this.test_accept( other ) );
+ } );
+
+ test( "cannot accept incorrect datatype if converted with PJA to incompatible type", function() {
+ var otherNode = this.pja_change_datatype_node( "out1", "bam" ); // bam's are not txt
+ var other = { node: otherNode, datatypes: [ "binary" ], name: "out1" };
+
+ ok( ! this.test_accept( other ) );
+ } );
+
+ test( "cannot accept incorrect datatype if some other output converted with PJA to compatible type", function() {
+ var otherNode = this.pja_change_datatype_node( "out2", "txt" );
+ var other = { node: otherNode, datatypes: [ "binary" ], name: "out1" };
+
+ ok( ! this.test_accept( other ) );
} );
test( "can accept inputs", function() {
- issubtypeStub.returns(false);
// Other is data input module - always accept (currently - could be
// more intelligent by looking at what else input is connected to.
var other = { node: {}, datatypes: [ "input" ] };
@@ -138,7 +176,6 @@
} );
test( "cannot accept when already connected", function() {
- issubtypeStub.returns(true);
var self = this;
// If other is subtype but already connected, cannot accept
this.with_test_connector( {}, function() {
@@ -379,12 +416,22 @@
/* global NodeView */
module( "Node view ", {
setup: function() {
- this.set_for_node( {} );
+ this.set_for_node( { input_terminals: {}, output_terminals: {}, markChanged: function() {} } );
},
set_for_node: function( node ) {
- var element = $("<div>");
+ var element = $("<div><div class='toolFormBody'></div></div>");
this.view = new NodeView( { node: node, el: element[ 0 ] } );
},
+ connectAttachedTerminal: function( inputType, outputType ) {
+ this.view.addDataInput( { name: "TestName", extensions: [ inputType ] } );
+ var terminal = this.view.node.input_terminals[ "TestName" ];
+
+ var outputTerminal = new OutputTerminal( { name: "TestOuptut", datatypes: [ outputType ] } );
+ outputTerminal.node = { markChanged: function() {}, post_job_actions: [] };
+ var c = new Connector( outputTerminal, terminal );
+
+ return c;
+ }
} );
test( "tool error styling", function() {
@@ -413,6 +460,14 @@
} );
+ test( "replacing terminal on data input update preserves connections", function() {
+ var connector = this.connectAttachedTerminal( "txt", "txt" );
+ var newElement = $("<div class='inputs'></div>");
+ this.view.replaceDataInput( { name: "TestName", extensions: ["txt"] }, newElement );
+ var terminal = newElement.find(".input-terminal")[ 0 ].terminal;
+ ok( connector.handle2 === terminal );
+ } );
+
/* global InputTerminalView */
module( "Input terminal view", {
setup: function() {
https://bitbucket.org/galaxy/galaxy-central/commits/69a77f2783fc/
Changeset: 69a77f2783fc
User: jmchilton
Date: 2014-04-21 21:27:01
Summary: Workflow Editor: Break canAccept into smaller pieces (inputFilled and attachable).
Want to reuse attachable right away to fix a bug - and the smaller pieces are good refactoring to support different kinds of input types in dataset collections downstream.
Affected #: 1 file
diff -r a1d1f25181f4689de3e946ed1ce1aa5494e7d781 -r 69a77f2783fcd9317f1da329c3f7a5512762ce99 static/scripts/galaxy.workflow_editor.canvas.js
--- a/static/scripts/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/galaxy.workflow_editor.canvas.js
@@ -42,23 +42,31 @@
this.multiple = attr.multiple;
},
canAccept: function ( other ) {
- if ( this.connectors.length < 1 || this.multiple) {
- for ( var t in this.datatypes ) {
- var cat_outputs = new Array();
- cat_outputs = cat_outputs.concat(other.datatypes);
- if (other.node.post_job_actions){
- for (var pja_i in other.node.post_job_actions){
- var pja = other.node.post_job_actions[pja_i];
- if (pja.action_type == "ChangeDatatypeAction" && (pja.output_name == '' || pja.output_name == other.name) && pja.action_arguments){
- cat_outputs.push(pja.action_arguments['newtype']);
- }
+ if( this._inputFilled() ) {
+ return false;
+ } else {
+ return this.attachable( other );
+ }
+ },
+ _inputFilled: function( ) {
+ return ! ( this.connectors.length < 1 || this.multiple );
+ },
+ attachable: function( other ) {
+ for ( var t in this.datatypes ) {
+ var cat_outputs = new Array();
+ cat_outputs = cat_outputs.concat(other.datatypes);
+ if (other.node.post_job_actions){
+ for (var pja_i in other.node.post_job_actions){
+ var pja = other.node.post_job_actions[pja_i];
+ if (pja.action_type == "ChangeDatatypeAction" && (pja.output_name == '' || pja.output_name == other.name) && pja.action_arguments){
+ cat_outputs.push(pja.action_arguments['newtype']);
}
}
- // FIXME: No idea what to do about case when datatype is 'input'
- for ( var other_datatype_i in cat_outputs ) {
- if ( cat_outputs[other_datatype_i] == "input" || issubtype( cat_outputs[other_datatype_i], this.datatypes[t] ) ) {
- return true;
- }
+ }
+ // FIXME: No idea what to do about case when datatype is 'input'
+ for ( var other_datatype_i in cat_outputs ) {
+ if ( cat_outputs[other_datatype_i] == "input" || issubtype( cat_outputs[other_datatype_i], this.datatypes[t] ) ) {
+ return true;
}
}
}
https://bitbucket.org/galaxy/galaxy-central/commits/4df5e43d8651/
Changeset: 4df5e43d8651
User: jmchilton
Date: 2014-04-21 21:27:01
Summary: Bugfix: Workflow editor could get in invalid state when trying to preserve connections.
Workflow editor would preserve connections when a tool would update its state (for instance switching a conditional or adding repeat) - but conditional switching can result in connections being invalid (wouldn't have passed can_accept previously). Consider the following tool for instance which changes datatypes of an input based on a conditional (https://gist.github.com/jmchilton/11152628)
Affected #: 2 files
diff -r 69a77f2783fcd9317f1da329c3f7a5512762ce99 -r 4df5e43d865176cdeb929db7fbf18c3b9af98591 static/scripts/galaxy.workflow_editor.canvas.js
--- a/static/scripts/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/galaxy.workflow_editor.canvas.js
@@ -806,8 +806,14 @@
$(this).find( ".input-terminal" ).each( function() {
var c = this.terminal.connectors[0];
if ( c ) {
- t.terminal.connectors[0] = c;
- c.handle2 = t.terminal;
+ var terminal = t.terminal;
+ if( c.handle1 && ! terminal.attachable( c.handle1 ) ) {
+ // connection no longer valid, destroy it
+ c.destroy();
+ } else {
+ terminal.connectors[0] = c;
+ c.handle2 = terminal;
+ }
}
});
$(this).remove();
diff -r 69a77f2783fcd9317f1da329c3f7a5512762ce99 -r 4df5e43d865176cdeb929db7fbf18c3b9af98591 test/qunit/tests/workflow_editor_tests.js
--- a/test/qunit/tests/workflow_editor_tests.js
+++ b/test/qunit/tests/workflow_editor_tests.js
@@ -468,6 +468,16 @@
ok( connector.handle2 === terminal );
} );
+ test( "replacing terminal on data input destroys invalid connections", function() {
+ var connector = this.connectAttachedTerminal( "txt", "txt" );
+ var newElement = $("<div class='inputs'></div>");
+ var connector_destroy_spy = sinon.spy( connector, "destroy" );
+ // Replacing input with same name - but now of type bam should destroy connection.
+ this.view.replaceDataInput( { name: "TestName", extensions: ["bam"] }, newElement );
+ var terminal = newElement.find(".input-terminal")[ 0 ].terminal;
+ ok( connector_destroy_spy.called );
+ } );
+
/* global InputTerminalView */
module( "Input terminal view", {
setup: function() {
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: Client app: use in /base.mako, rework app init to use AMD definition
by commits-noreply@bitbucket.org 21 Apr '14
by commits-noreply@bitbucket.org 21 Apr '14
21 Apr '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/64ae9dc17021/
Changeset: 64ae9dc17021
User: carlfeberhard
Date: 2014-04-21 20:44:34
Summary: Client app: use in /base.mako, rework app init to use AMD definition
Affected #: 5 files
diff -r a247bdaecba956f1a1b74713ba7fd9ec100e0342 -r 64ae9dc170214097c419febe12e52b86bea12020 templates/base.mako
--- a/templates/base.mako
+++ b/templates/base.mako
@@ -1,3 +1,6 @@
+<%namespace name="galaxy_client" file="/galaxy_client_app.mako" />
+<% self.js_app = None %>
+
<% _=n_ %><!DOCTYPE HTML><html>
@@ -80,6 +83,8 @@
});
</script>
+ ${ galaxy_client.load( app=self.js_app ) }
+
%if not form_input_auto_focus is UNDEFINED and form_input_auto_focus:
<script type="text/javascript">
$(document).ready( function() {
diff -r a247bdaecba956f1a1b74713ba7fd9ec100e0342 -r 64ae9dc170214097c419febe12e52b86bea12020 templates/base/base_panels.mako
--- a/templates/base/base_panels.mako
+++ b/templates/base/base_panels.mako
@@ -60,8 +60,6 @@
"mvc/ui"
)}
- ${ galaxy_client.load() }
-
<script type="text/javascript">
## global configuration object
var galaxy_config =
@@ -92,6 +90,10 @@
}
});
</script>
+
+ ## load the Galaxy global js var
+ ${ galaxy_client.load() }
+
</%def>
## Default late-load javascripts
diff -r a247bdaecba956f1a1b74713ba7fd9ec100e0342 -r 64ae9dc170214097c419febe12e52b86bea12020 templates/galaxy_client_app.mako
--- a/templates/galaxy_client_app.mako
+++ b/templates/galaxy_client_app.mako
@@ -1,8 +1,10 @@
## ============================================================================
<%def name="bootstrap( **kwargs )">
- ## Bootstap dictionaries for GalaxyApp object's JSON, create GalaxyApp,
- ## and steal existing attributes from plain objects already created
+ ## 1) Bootstap all kwargs to json, assigning to:
+ ## global 'bootstrapped' var
+ ## named require module 'bootstrapped-data'
+ ## 2) and automatically include json for config and user in bootstapped data
<%
kwargs.update({
'config' : get_config_dict(),
@@ -10,6 +12,7 @@
})
%><script type="text/javascript">
+ //TODO: global...
%for key in kwargs:
( window.bootstrapped = window.bootstrapped || {} )[ '${key}' ] = (
${ h.to_json_string( kwargs[ key ], indent=( 2 if trans.debug else 0 ) )} );
@@ -20,7 +23,8 @@
</script></%def>
-<%def name="load( init_fn=None, **kwargs )">
+<%def name="load( app=None, **kwargs )">
+ ## 1) bootstrap kwargs (as above), 2) build Galaxy global var, 3) load 'app' by AMD (optional)
${ self.bootstrap( **kwargs ) }
<script type="text/javascript">
require([ 'require', 'galaxy-app-base' ], function( require, galaxy ){
@@ -31,10 +35,9 @@
loggerOptions : {}
});
- var initFn = ${ 'window[ "%s" ]' %( init_fn ) if init_fn else 'undefined' };
- if( typeof initFn === 'function' ){
- initFn();
- }
+ %if app:
+ require([ '${app}' ]);
+ %endif
});
</script></%def>
diff -r a247bdaecba956f1a1b74713ba7fd9ec100e0342 -r 64ae9dc170214097c419febe12e52b86bea12020 templates/webapps/galaxy/galaxy.panels.mako
--- a/templates/webapps/galaxy/galaxy.panels.mako
+++ b/templates/webapps/galaxy/galaxy.panels.mako
@@ -55,9 +55,6 @@
## make sure console exists
<script type="text/javascript">
- // start a Galaxy namespace for objects created
- window.Galaxy = window.Galaxy || {};
-
// console protection
window.console = window.console ||
{
@@ -91,7 +88,6 @@
%endif
</style>
-
## default script wrapper
<script type="text/javascript">
## configure require
@@ -103,25 +99,33 @@
"libs/backbone/backbone": { exports: "Backbone" },
}
});
+ var galaxy_config = ${ h.to_json_string( self.galaxy_config ) };
// load any app configured
- var galaxy_config = ${ h.to_json_string( self.galaxy_config ) };
- window.init = function(){
+ define( 'app', function(){
var jscript = galaxy_config.app.jscript;
if( jscript ){
require([ jscript ], function( js_lib ){
$( function(){
- ## load galaxy module application
+ // load galaxy module application
var module = new js_lib.GalaxyApp();
});
});
} else {
console.log("'galaxy_config.app.jscript' missing.");
}
- }
+ });
</script>
- ${ galaxy_client.load( init_fn='init' ) }
+ ## load the Galaxy global js var and run 'app' from above
+ ${ galaxy_client.load( app='app' ) }
+
+ ## alternate call where the module calls itself when included (no call to GalaxyApp()) - the above won't be needed
+ ##precondition: module must call jq onready itself
+ ##<% app_config = self.galaxy_config[ 'app' ]; print app_config %>
+ ##${ galaxy_client.load( app=( app_config[ 'jscript' ] if 'jscript' in app_config else None )) }
+ ##TODO: at that point, we can think about optimizing the various apps
+
</%def>
## default late-load javascripts
diff -r a247bdaecba956f1a1b74713ba7fd9ec100e0342 -r 64ae9dc170214097c419febe12e52b86bea12020 templates/webapps/galaxy/root/history.mako
--- a/templates/webapps/galaxy/root/history.mako
+++ b/templates/webapps/galaxy/root/history.mako
@@ -6,26 +6,16 @@
</%def>
## -----------------------------------------------------------------------------
-<%def name="stylesheets()">
- ${ parent.stylesheets() }
- <style>
- body.historyPage {
- margin: 0px;
- padding: 0px;
- }
- </style>
-</%def>
-
-## -----------------------------------------------------------------------------
<%def name="javascripts()">
${ parent.javascripts() }
<script type="text/javascript">
$(function(){
- $( 'body' ).addClass( 'historyPage' ).addClass( 'history-panel' );
+ $( 'body' ).addClass( 'historyPage' ).addClass( 'history-panel' )
+ .css({ margin: '0px', padding: '0px' });
});
-window.app = function(){
+define( 'app', function(){
require([
'mvc/history/current-history-panel'
], function( historyPanel ){
@@ -38,13 +28,13 @@
el : $( "body" ),
model : new historyModel.History( bootstrapped.history, bootstrapped.hdas ),
onready : function(){
- this.render( 0 );
+ this.render();
}
});
});
});
-}
+})
</script>
-${ galaxy_client.load( 'app', history=history, hdas=hdas, show_deleted=show_deleted, show_hidden=show_hidden ) }
+${ galaxy_client.load( app='app', history=history, hdas=hdas, show_deleted=show_deleted, show_hidden=show_hidden ) }
</%def>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: davebgx: Fix for registering an account with custom user information when only one custom user info form is defined. Fix editing user info when custom user info forms are defined. Fix functional tests for user info.
by commits-noreply@bitbucket.org 21 Apr '14
by commits-noreply@bitbucket.org 21 Apr '14
21 Apr '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a247bdaecba9/
Changeset: a247bdaecba9
User: davebgx
Date: 2014-04-21 18:41:05
Summary: Fix for registering an account with custom user information when only one custom user info form is defined. Fix editing user info when custom user info forms are defined. Fix functional tests for user info.
Affected #: 5 files
diff -r 990979ee295e919be24b112a7cad215641c729ad -r a247bdaecba956f1a1b74713ba7fd9ec100e0342 lib/galaxy/webapps/galaxy/controllers/user.py
--- a/lib/galaxy/webapps/galaxy/controllers/user.py
+++ b/lib/galaxy/webapps/galaxy/controllers/user.py
@@ -623,7 +623,6 @@
@web.expose
def create( self, trans, cntrller='user', redirect_url='', refresh_frames=[], **kwd ):
params = util.Params( kwd )
-
# If the honeypot field is not empty we are dealing with a bot.
honeypot_field = params.get( 'bear_field', '' )
if honeypot_field != '':
@@ -927,6 +926,7 @@
user_type_fd_id_select_field=user_type_fd_id_select_field,
user_info_forms=user_info_forms,
user_type_form_definition=user_type_form_definition,
+ user_type_fd_id=user_type_fd_id,
widgets=widgets,
addresses=addresses,
show_filter=show_filter,
diff -r 990979ee295e919be24b112a7cad215641c729ad -r a247bdaecba956f1a1b74713ba7fd9ec100e0342 templates/user/register.mako
--- a/templates/user/register.mako
+++ b/templates/user/register.mako
@@ -139,7 +139,7 @@
all Galaxy project mailing lists</a>.</p></div>
%endif
- %if user_type_fd_id_select_field and len( user_type_fd_id_select_field.options ) > 1:
+ %if user_type_fd_id_select_field and len( user_type_fd_id_select_field.options ) >= 1:
<div class="form-row"><label>User type</label>
${user_type_fd_id_select_field.get_html()}
diff -r 990979ee295e919be24b112a7cad215641c729ad -r a247bdaecba956f1a1b74713ba7fd9ec100e0342 templates/webapps/galaxy/user/manage_info.mako
--- a/templates/webapps/galaxy/user/manage_info.mako
+++ b/templates/webapps/galaxy/user/manage_info.mako
@@ -13,13 +13,13 @@
<div class="toolForm"><form name="user_info" id="user_info" action="${h.url_for( controller='user', action='edit_info', cntrller=cntrller, user_id=trans.security.encode_id( user.id ) )}" method="post" ><div class="toolFormTitle">User information</div>
- %if user_type_fd_id_select_field and len( user_type_fd_id_select_field.options ) > 1:
+ %if user_type_fd_id_select_field and len( user_type_fd_id_select_field.options ) >= 1:
<div class="form-row"><label>User type:</label>
${user_type_fd_id_select_field.get_html()}
</div>
%else:
- <input type="hidden" name="user_type_fd_id" value="${trans.security.encode_id( user_type_form_definition.id )}"/>
+ <input type="hidden" name="user_type_fd_id" value="${trans.security.encode_id( user_type_fd_id )}"/>
%endif
%for field in widgets:
<div class="form-row">
diff -r 990979ee295e919be24b112a7cad215641c729ad -r a247bdaecba956f1a1b74713ba7fd9ec100e0342 test/base/twilltestcase.py
--- a/test/base/twilltestcase.py
+++ b/test/base/twilltestcase.py
@@ -1039,17 +1039,17 @@
strings_displayed=[], strings_displayed_after_submit=[] ):
# This method creates a new user with associated info
self.visit_url( "%s/user/create?cntrller=%s&use_panels=False" % ( self.url, cntrller ) )
- tc.fv( "1", "email", email )
- tc.fv( "1", "password", password )
- tc.fv( "1", "confirm", password )
- tc.fv( "1", "username", username )
+ tc.fv( "registration", "email", email )
+ tc.fv( "registration", "password", password )
+ tc.fv( "registration", "confirm", password )
+ tc.fv( "registration", "username", username )
if user_type_fd_id:
# The user_type_fd_id SelectField requires a refresh_on_change
- self.refresh_form( 'user_type_fd_id', user_type_fd_id )
- tc.fv( "1", "password", password )
- tc.fv( "1", "confirm", password )
+ self.refresh_form( 'user_type_fd_id', user_type_fd_id, form_id='registration' )
+ tc.fv( "registration", "password", password )
+ tc.fv( "registration", "confirm", password )
for index, ( field_name, info_value ) in enumerate( user_info_values ):
- tc.fv( "1", field_name, info_value )
+ tc.fv( "registration", field_name, info_value )
for check_str in strings_displayed:
self.check_page_for_string( check_str)
tc.submit( "create_user_button" )
@@ -1345,12 +1345,12 @@
pass
tc.submit( button )
- def refresh_form( self, control_name, value, form_no=0, **kwd ):
+ def refresh_form( self, control_name, value, form_no=0, form_id=None, **kwd ):
"""Handles Galaxy's refresh_on_change for forms without ultimately submitting the form"""
# control_name is the name of the form field that requires refresh_on_change, and value is
# the value to which that field is being set.
for i, f in enumerate( self.showforms() ):
- if i == form_no:
+ if i == form_no or ( form_id is not None and f.id == form_id ):
break
try:
control = f.find_control( name=control_name )
@@ -1684,6 +1684,7 @@
num_fields=1, num_options=0, field_name='1_field_name', strings_displayed=[],
strings_displayed_after_submit=[] ):
"""Create a new form definition."""
+ strings_displayed_after_submit.extend( [ name, description, form_type ] )
self.visit_url( "%s/forms/create_form_definition" % self.url )
for check_str in strings_displayed:
self.check_page_for_string( check_str )
diff -r 990979ee295e919be24b112a7cad215641c729ad -r a247bdaecba956f1a1b74713ba7fd9ec100e0342 test/functional/test_user_info.py
--- a/test/functional/test_user_info.py
+++ b/test/functional/test_user_info.py
@@ -1,9 +1,8 @@
from base.twilltestcase import *
from base.test_db_util import *
+class TestUserInfo( TwillTestCase ):
-# TODO: Functional tests start failing at 020, fix or eliminate rest of tests.
-class TestUserInfo( TwillTestCase ):
def test_000_initiate_users( self ):
"""Ensuring all required user accounts exist"""
self.logout()
@@ -34,91 +33,65 @@
assert admin_user is not None, 'Problem retrieving user with email "test(a)bx.psu.edu" from the database'
global admin_user_private_role
admin_user_private_role = get_private_role( admin_user )
+
def test_005_create_user_info_forms( self ):
"""Testing creating a new user info form and editing it"""
# Logged in as admin_user
# Create a the first form
- name = "Student"
- desc = "This is Student user info form's description"
- form_type = get_user_info_form_definition()
- self.create_form( name=name,
- description=desc,
- form_type=form_type,
+ self.create_form( name='Student',
+ description="This is Student user info form's description",
+ form_type=get_user_info_form_definition(),
num_fields=0,
strings_displayed=[ 'Create a new form definition' ],
- strings_displayed_after_submit=[ name, desc, form_type ] )
- tmp_form = get_form( name )
- # field names
- global affiliation_field_name
- affiliation_field_name = 'affiliation'
- global organization_field_name
- organization_field_name = 'name_of_organization'
- global feedback_field_name
- feedback_field_name = 'contact_for_feedback'
+ strings_displayed_after_submit=[] )
+ tmp_form = get_form( 'Student' )
# Add fields to the form
field_dicts = [ dict( label='Affiliation',
desc='The type of organization you are affiliated with',
type='SelectField',
required='optional',
selectlist=[ 'Educational', 'Research', 'Commercial' ],
- name=affiliation_field_name ),
+ name='affiliation' ),
dict( label='Name of Organization',
desc='',
type='TextField',
required='optional',
- name=organization_field_name ),
+ name='name_of_oganization' ),
dict( label='Contact for feedback',
desc='',
type='CheckboxField',
required='optional',
- name=feedback_field_name ) ]
+ name='contact_for_feedback' ) ]
self.edit_form( id=self.security.encode_id( tmp_form.current.id ),
field_dicts=field_dicts,
field_index=len( tmp_form.fields ),
- strings_displayed=[ 'Edit form definition "%s"' % name ],
- strings_displayed_after_submit=[ "The form '%s' has been updated with the changes." % name ] )
+ strings_displayed=[ 'Edit form definition "Student"' ],
+ strings_displayed_after_submit=[ "The form 'Student' has been updated with the changes." ] )
# Get the form_definition object for later tests
global form_one
- form_one = get_form( name )
- assert form_one is not None, 'Problem retrieving form named "%s" from the database' % name
+ form_one = get_form( 'Student' )
+ assert form_one is not None, 'Problem retrieving form named "Student" from the database'
assert len( form_one.fields ) == len( tmp_form.fields ) + len( field_dicts )
# Create the second form
- name = "Researcher"
- desc = "This is Researcher user info form's description"
- self.create_form( name=name,
- description=desc,
- form_type=form_type,
+ self.create_form( name='Researcher',
+ description="This is Researcher user info form's description",
+ form_type=get_user_info_form_definition(),
num_fields=0,
strings_displayed=[ 'Create a new form definition' ],
- strings_displayed_after_submit=[ name, desc, form_type ] )
- tmp_form = get_form( name )
+ strings_displayed_after_submit=[] )
+ tmp_form = get_form( 'Researcher' )
# Add fields to the form
- field_dicts = [ dict( label='Affiliation',
- desc='The type of organization you are affiliated with',
- type='SelectField',
- required='optional',
- selectlist=[ 'Educational', 'Research', 'Commercial' ],
- name=affiliation_field_name ),
- dict( label='Name of Organization',
- desc='',
- type='TextField',
- required='optional',
- name=organization_field_name ),
- dict( label='Contact for feedback',
- desc='',
- type='CheckboxField',
- required='optional',
- name=feedback_field_name ) ]
self.edit_form( id=self.security.encode_id( tmp_form.current.id ),
field_dicts=field_dicts,
field_index=len( tmp_form.fields ),
- strings_displayed=[ 'Edit form definition "%s"' % name ],
- strings_displayed_after_submit=[ "The form '%s' has been updated with the changes." % name ] )
+ strings_displayed=[ 'Edit form definition "Researcher"' ],
+ strings_displayed_after_submit=[ "The form 'Researcher' has been updated with the changes." ] )
# Get the form_definition object for later tests
global form_two
- form_two = get_form( name )
- assert form_two is not None, 'Problem retrieving form named "%s" from the database' % name
+ form_two = get_form( 'Researcher' )
+ assert form_two is not None, 'Problem retrieving form named "Researcher" from the database'
assert len( form_two.fields ) == len( tmp_form.fields ) + len( field_dicts )
+
def test_010_user_reqistration_multiple_user_info_forms( self ):
"""Testing user registration with multiple user info forms"""
# Logged in as admin_user
@@ -129,9 +102,9 @@
email = 'test11(a)bx.psu.edu'
password = 'testuser'
username = 'test11'
- user_info_values=[ ( affiliation_field_name, 'Educational' ),
- ( organization_field_name, 'Penn State' ),
- ( feedback_field_name, '1' ) ]
+ user_info_values=[ ( 'affiliation', 'Educational' ),
+ ( 'name_of_oganization', 'Penn State' ),
+ ( 'contact_for_feedback', '1' ) ]
self.create_user_with_info( cntrller='admin',
email=email,
password=password,
@@ -147,12 +120,13 @@
self.logout()
self.login( email=regular_user11.email, username=username )
global form_checkbox_field3_string
- form_checkbox_field3_string = '<input type="checkbox" id="%s" name="%s" value="true" checked="checked">' % ( feedback_field_name, feedback_field_name )
+ form_checkbox_field3_string = '<input type="checkbox" id="contact_for_feedback" name="contact_for_feedback" value="true" checked="checked">'
self.edit_user_info( cntrller='user',
strings_displayed=[ "Manage User Information",
user_info_values[0][1],
user_info_values[1][1],
form_checkbox_field3_string ] )
+
def test_015_user_reqistration_single_user_info_forms( self ):
"""Testing user registration with a single user info form"""
# Logged in as regular_user_11
@@ -166,9 +140,9 @@
email = 'test12(a)bx.psu.edu'
password = 'testuser'
username = 'test12'
- user_info_values=[ ( affiliation_field_name, 'Educational' ),
- ( organization_field_name, 'Penn State' ),
- ( feedback_field_name, '1' ) ]
+ user_info_values=[ ( 'affiliation', 'Educational' ),
+ ( 'name_of_oganization', 'Penn State' ),
+ ( 'contact_for_feedback', '1' ) ]
self.create_user_with_info( cntrller='admin',
email=email,
password=password,
@@ -188,10 +162,12 @@
user_info_values[0][1],
user_info_values[1][1],
form_checkbox_field3_string ] )
+
def test_020_edit_user_info( self ):
"""Testing editing user info as a regular user"""
# Logged in as regular_user_12
# Test changing email and user name - first try an invalid user name
+ regular_user12 = get_user( 'test12(a)bx.psu.edu' )
self.edit_user_info( cntrller='user',
new_email='test12_new(a)bx.psu.edu',
new_username='test12_new',
@@ -214,11 +190,12 @@
# Test logging in with new email and password
self.login( email=regular_user12.email, password='testuser#' )
# Test editing the user info
- new_user_info_values=[ ( affiliation_field_name, 'Educational' ),
- ( organization_field_name, 'Penn State' ) ]
+ new_user_info_values=[ ( 'affiliation', 'Educational' ),
+ ( 'name_of_oganization', 'Penn State' ) ]
self.edit_user_info( cntrller='user',
info_values=new_user_info_values,
strings_displayed_after_submit=[ "The user information has been updated with the changes" ] )
+
def test_999_reset_data_for_later_test_runs( self ):
"""Reseting data to enable later test runs to pass"""
# Logged in as regular_user_12
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Fix for masthead link for biostar mainpage.
by commits-noreply@bitbucket.org 21 Apr '14
by commits-noreply@bitbucket.org 21 Apr '14
21 Apr '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/990979ee295e/
Changeset: 990979ee295e
User: dan
Date: 2014-04-21 18:12:03
Summary: Fix for masthead link for biostar mainpage.
Affected #: 3 files
diff -r 5d4d8c336e6d9d74865a8e5009fd5ccdbd99e94e -r 990979ee295e919be24b112a7cad215641c729ad static/scripts/galaxy.menu.js
--- a/static/scripts/galaxy.menu.js
+++ b/static/scripts/galaxy.menu.js
@@ -196,7 +196,7 @@
{
tab_help.add({
title : "Galaxy Q&A Site",
- content : this.options.biostar_url,
+ content : this.options.biostar_url_redirect,
target : "_blank"
});
tab_help.add({
diff -r 5d4d8c336e6d9d74865a8e5009fd5ccdbd99e94e -r 990979ee295e919be24b112a7cad215641c729ad static/scripts/packed/galaxy.menu.js
--- a/static/scripts/packed/galaxy.menu.js
+++ b/static/scripts/packed/galaxy.menu.js
@@ -1,1 +1,1 @@
-define(["galaxy.masthead"],function(b){var a=Backbone.Model.extend({options:null,masthead:null,initialize:function(c){this.options=c.config;this.masthead=c.masthead;this.create()},create:function(){var e=new b.GalaxyMastheadTab({id:"analysis",title:"Analyze Data",content:"root/index",title_attribute:"Analysis home view"});this.masthead.append(e);var g={id:"workflow",title:"Workflow",content:"workflow",title_attribute:"Chain tools into workflows"};if(!this.options.user.valid){g.disabled=true}var d=new b.GalaxyMastheadTab(g);this.masthead.append(d);var i=new b.GalaxyMastheadTab({id:"shared",title:"Shared Data",content:"library/index",title_attribute:"Access published resources"});i.add({title:"Data Libraries",content:"library/index"});i.add({title:"Data Libraries Beta",content:"library/list",divider:true});i.add({title:"Published Histories",content:"history/list_published"});i.add({title:"Published Workflows",content:"workflow/list_published"});i.add({title:"Published Visualizations",content:"visualization/list_published"});i.add({title:"Published Pages",content:"page/list_published"});this.masthead.append(i);if(this.options.user.requests){var j=new b.GalaxyMastheadTab({id:"lab",title:"Lab"});j.add({title:"Sequencing Requests",content:"requests/index"});j.add({title:"Find Samples",content:"requests/find_samples_index"});j.add({title:"Help",content:this.options.lims_doc_url});this.masthead.append(j)}var c={id:"visualization",title:"Visualization",content:"visualization/list",title_attribute:"Visualize datasets"};if(!this.options.user.valid){c.disabled=true}var m=new b.GalaxyMastheadTab(c);if(this.options.user.valid){m.add({title:"New Track Browser",content:"visualization/trackster",target:"_frame"});m.add({title:"Saved Visualizations",content:"visualization/list",target:"_frame"})}this.masthead.append(m);if(this.options.enable_cloud_launch){var f=new b.GalaxyMastheadTab({id:"cloud",title:"Cloud",content:"cloudlaunch/index"});f.add({title:"New Cloud Cluster",content:"cloudlaunch/index"});this.masthead.append(f)}if(this.options.is_admin_user){var h=new b.GalaxyMastheadTab({id:"admin",title:"Admin",content:"admin/index",extra_class:"admin-only",title_attribute:"Administer this Galaxy"});this.masthead.append(h)}var l=new b.GalaxyMastheadTab({id:"help",title:"Help",title_attribute:"Support, contact, and community hubs"});if(this.options.biostar_url){l.add({title:"Galaxy Q&A Site",content:this.options.biostar_url,target:"_blank"});l.add({title:"Ask a question",content:"biostar/biostar_question_redirect",target:"_blank"})}l.add({title:"Support",content:this.options.support_url,target:"_blank"});l.add({title:"Search",content:this.options.search_url,target:"_blank"});l.add({title:"Mailing Lists",content:this.options.mailing_lists,target:"_blank"});l.add({title:"Videos",content:this.options.screencasts_url,target:"_blank"});l.add({title:"Wiki",content:this.options.wiki_url,target:"_blank"});l.add({title:"How to Cite Galaxy",content:this.options.citation_url,target:"_blank"});if(this.options.terms_url){l.add({title:"Terms and Conditions",content:this.options.terms_url,target:"_blank"})}this.masthead.append(l);if(!this.options.user.valid){var k=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedout-only",title_attribute:"Account registration or login"});k.add({title:"Login",content:"user/login",target:"galaxy_main"});if(this.options.allow_user_creation){k.add({title:"Register",content:"user/create",target:"galaxy_main"})}this.masthead.append(k)}else{var k=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedin-only",title_attribute:"Account preferences and saved data"});k.add({title:"Logged in as "+this.options.user.email});if(this.options.use_remote_user&&this.options.remote_user_logout_href){k.add({title:"Logout",content:this.options.remote_user_logout_href,target:"_top"})}else{k.add({title:"Preferences",content:"user?cntrller=user",target:"galaxy_main"});k.add({title:"Custom Builds",content:"user/dbkeys",target:"galaxy_main"});k.add({title:"Logout",content:"user/logout",target:"_top",divider:true})}k.add({title:"Saved Histories",content:"history/list",target:"galaxy_main"});k.add({title:"Saved Datasets",content:"dataset/list",target:"galaxy_main"});k.add({title:"Saved Pages",content:"page/list",target:"_top"});k.add({title:"API Keys",content:"user/api_keys?cntrller=user",target:"galaxy_main"});if(this.options.use_remote_user){k.add({title:"Public Name",content:"user/edit_username?cntrller=user",target:"galaxy_main"})}this.masthead.append(k)}if(this.options.active_view){this.masthead.highlight(this.options.active_view)}}});return{GalaxyMenu:a}});
\ No newline at end of file
+define(["galaxy.masthead"],function(b){var a=Backbone.Model.extend({options:null,masthead:null,initialize:function(c){this.options=c.config;this.masthead=c.masthead;this.create()},create:function(){var e=new b.GalaxyMastheadTab({id:"analysis",title:"Analyze Data",content:"root/index",title_attribute:"Analysis home view"});this.masthead.append(e);var g={id:"workflow",title:"Workflow",content:"workflow",title_attribute:"Chain tools into workflows"};if(!this.options.user.valid){g.disabled=true}var d=new b.GalaxyMastheadTab(g);this.masthead.append(d);var i=new b.GalaxyMastheadTab({id:"shared",title:"Shared Data",content:"library/index",title_attribute:"Access published resources"});i.add({title:"Data Libraries",content:"library/index"});i.add({title:"Data Libraries Beta",content:"library/list",divider:true});i.add({title:"Published Histories",content:"history/list_published"});i.add({title:"Published Workflows",content:"workflow/list_published"});i.add({title:"Published Visualizations",content:"visualization/list_published"});i.add({title:"Published Pages",content:"page/list_published"});this.masthead.append(i);if(this.options.user.requests){var j=new b.GalaxyMastheadTab({id:"lab",title:"Lab"});j.add({title:"Sequencing Requests",content:"requests/index"});j.add({title:"Find Samples",content:"requests/find_samples_index"});j.add({title:"Help",content:this.options.lims_doc_url});this.masthead.append(j)}var c={id:"visualization",title:"Visualization",content:"visualization/list",title_attribute:"Visualize datasets"};if(!this.options.user.valid){c.disabled=true}var m=new b.GalaxyMastheadTab(c);if(this.options.user.valid){m.add({title:"New Track Browser",content:"visualization/trackster",target:"_frame"});m.add({title:"Saved Visualizations",content:"visualization/list",target:"_frame"})}this.masthead.append(m);if(this.options.enable_cloud_launch){var f=new b.GalaxyMastheadTab({id:"cloud",title:"Cloud",content:"cloudlaunch/index"});f.add({title:"New Cloud Cluster",content:"cloudlaunch/index"});this.masthead.append(f)}if(this.options.is_admin_user){var h=new b.GalaxyMastheadTab({id:"admin",title:"Admin",content:"admin/index",extra_class:"admin-only",title_attribute:"Administer this Galaxy"});this.masthead.append(h)}var l=new b.GalaxyMastheadTab({id:"help",title:"Help",title_attribute:"Support, contact, and community hubs"});if(this.options.biostar_url){l.add({title:"Galaxy Q&A Site",content:this.options.biostar_url_redirect,target:"_blank"});l.add({title:"Ask a question",content:"biostar/biostar_question_redirect",target:"_blank"})}l.add({title:"Support",content:this.options.support_url,target:"_blank"});l.add({title:"Search",content:this.options.search_url,target:"_blank"});l.add({title:"Mailing Lists",content:this.options.mailing_lists,target:"_blank"});l.add({title:"Videos",content:this.options.screencasts_url,target:"_blank"});l.add({title:"Wiki",content:this.options.wiki_url,target:"_blank"});l.add({title:"How to Cite Galaxy",content:this.options.citation_url,target:"_blank"});if(this.options.terms_url){l.add({title:"Terms and Conditions",content:this.options.terms_url,target:"_blank"})}this.masthead.append(l);if(!this.options.user.valid){var k=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedout-only",title_attribute:"Account registration or login"});k.add({title:"Login",content:"user/login",target:"galaxy_main"});if(this.options.allow_user_creation){k.add({title:"Register",content:"user/create",target:"galaxy_main"})}this.masthead.append(k)}else{var k=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedin-only",title_attribute:"Account preferences and saved data"});k.add({title:"Logged in as "+this.options.user.email});if(this.options.use_remote_user&&this.options.remote_user_logout_href){k.add({title:"Logout",content:this.options.remote_user_logout_href,target:"_top"})}else{k.add({title:"Preferences",content:"user?cntrller=user",target:"galaxy_main"});k.add({title:"Custom Builds",content:"user/dbkeys",target:"galaxy_main"});k.add({title:"Logout",content:"user/logout",target:"_top",divider:true})}k.add({title:"Saved Histories",content:"history/list",target:"galaxy_main"});k.add({title:"Saved Datasets",content:"dataset/list",target:"galaxy_main"});k.add({title:"Saved Pages",content:"page/list",target:"_top"});k.add({title:"API Keys",content:"user/api_keys?cntrller=user",target:"galaxy_main"});if(this.options.use_remote_user){k.add({title:"Public Name",content:"user/edit_username?cntrller=user",target:"galaxy_main"})}this.masthead.append(k)}if(this.options.active_view){this.masthead.highlight(this.options.active_view)}}});return{GalaxyMenu:a}});
\ No newline at end of file
diff -r 5d4d8c336e6d9d74865a8e5009fd5ccdbd99e94e -r 990979ee295e919be24b112a7cad215641c729ad templates/webapps/galaxy/galaxy.masthead.mako
--- a/templates/webapps/galaxy/galaxy.masthead.mako
+++ b/templates/webapps/galaxy/galaxy.masthead.mako
@@ -41,6 +41,7 @@
'enable_cloud_launch' : app.config.get_bool('enable_cloud_launch', False),
'lims_doc_url' : app.config.get("lims_doc_url", "http://main.g2.bx.psu.edu/u/rkchak/p/sts"),
'biostar_url' : app.config.biostar_url,
+ 'biostar_url_redirect' : h.url_for( controller='biostar', action='biostar_redirect', qualified=True ),
'support_url' : app.config.get("support_url", "http://wiki.galaxyproject.org/Support"),
'search_url' : app.config.get("search_url", "http://galaxyproject.org/search/usegalaxy/"),
'mailing_lists' : app.config.get("mailing_lists", "http://wiki.galaxyproject.org/MailingLists"),
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Prevent redirect misuse on user log in.
by commits-noreply@bitbucket.org 21 Apr '14
by commits-noreply@bitbucket.org 21 Apr '14
21 Apr '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5d4d8c336e6d/
Changeset: 5d4d8c336e6d
User: dan
Date: 2014-04-21 18:11:49
Summary: Prevent redirect misuse on user log in.
Affected #: 2 files
diff -r 6f8070735e6f36fd1cd7b79d7cef1d69ebf8c1d6 -r 5d4d8c336e6d9d74865a8e5009fd5ccdbd99e94e lib/galaxy/util/__init__.py
--- a/lib/galaxy/util/__init__.py
+++ b/lib/galaxy/util/__init__.py
@@ -29,6 +29,8 @@
from hashlib import md5
from itertools import izip
+from urlparse import urlparse
+
from galaxy import eggs
eggs.require( 'docutils' )
@@ -691,6 +693,17 @@
def string_to_object( s ):
return pickle.loads( binascii.unhexlify( s ) )
+def compare_urls( url1, url2, compare_scheme=True, compare_hostname=True, compare_path=True ):
+ url1 = urlparse( url1 )
+ url2 = urlparse( url2 )
+ if compare_scheme and url1.scheme and url2.scheme and url1.scheme != url2.scheme:
+ return False
+ if compare_hostname and url1.hostname and url2.hostname and url1.hostname != url2.hostname:
+ return False
+ if compare_path and url1.path and url2.path and url1.path != url2.path:
+ return False
+ return True
+
def get_ucsc_by_build(build):
sites = []
for site in ucsc_build_sites:
diff -r 6f8070735e6f36fd1cd7b79d7cef1d69ebf8c1d6 -r 5d4d8c336e6d9d74865a8e5009fd5ccdbd99e94e lib/galaxy/webapps/galaxy/controllers/user.py
--- a/lib/galaxy/webapps/galaxy/controllers/user.py
+++ b/lib/galaxy/webapps/galaxy/controllers/user.py
@@ -445,26 +445,35 @@
return self.user_openid_grid( trans, **kwd )
@web.expose
- def login( self, trans, redirect_url='', refresh_frames=[], **kwd ):
+ def login( self, trans, refresh_frames=[], **kwd ):
'''Handle Galaxy Log in'''
redirect = kwd.get( 'redirect', trans.request.referer ).strip()
+ root_url = url_for( '/', qualified=True )
+ redirect_url = '' #always start with redirect_url being empty
+ # compare urls, to prevent a redirect from pointing (directly) outside of galaxy
+ # or to enter a logout/login loop
+ if not util.compare_urls( root_url, redirect, compare_path=False ) or util.compare_urls( url_for( controller='user', action='logout', qualified=True ), redirect ):
+ redirect = root_url
use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
message = kwd.get( 'message', '' )
status = kwd.get( 'status', 'done' )
header = ''
- user = None
+ user = trans.user
email = kwd.get( 'email', '' )
- if kwd.get( 'login_button', False ):
+ if user:
+ #already logged in
+ redirect_url = redirect
+ message = 'You are already logged in.'
+ status = 'info'
+ elif kwd.get( 'login_button', False ):
if trans.webapp.name == 'galaxy' and not refresh_frames:
if trans.app.config.require_login:
refresh_frames = [ 'masthead', 'history', 'tools' ]
else:
refresh_frames = [ 'masthead', 'history' ]
message, status, user, success = self.__validate_login( trans, **kwd )
- if success and redirect and not redirect.startswith( trans.request.base + url_for( controller='user', action='logout' ) ):
+ if success:
redirect_url = redirect
- elif success:
- redirect_url = url_for( '/' )
if not user and trans.app.config.require_login:
if trans.app.config.allow_user_creation:
create_account_str = " If you don't already have an account, <a href='%s'>you may create one</a>." % \
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: Metrics: make the cache use localStorage for persistence
by commits-noreply@bitbucket.org 21 Apr '14
by commits-noreply@bitbucket.org 21 Apr '14
21 Apr '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6f8070735e6f/
Changeset: 6f8070735e6f
User: carlfeberhard
Date: 2014-04-21 17:37:26
Summary: Metrics: make the cache use localStorage for persistence
Affected #: 3 files
diff -r f1c9df0b5cabb998dd82dc6a154f66677173ffb8 -r 6f8070735e6f36fd1cd7b79d7cef1d69ebf8c1d6 static/scripts/packed/utils/metrics-logger.js
--- a/static/scripts/packed/utils/metrics-logger.js
+++ b/static/scripts/packed/utils/metrics-logger.js
@@ -1,1 +1,1 @@
-define([],function(){function h(z){z=z||{};var y=this;y.userId=window.bootstrapped?window.bootstrapped.user.id:null;y.userId=y.userId||z.userId||null;y.consoleLogger=z.consoleLogger||null;y._init(z);return y}h.ALL=0;h.DEBUG=10;h.INFO=20;h.WARN=30;h.ERROR=40;h.METRIC=50;h.NONE=100;h.defaultOptions={logLevel:h.NONE,consoleLevel:h.NONE,defaultNamespace:"Galaxy",clientPrefix:"client.",maxCacheSize:3000,postSize:1000,addTime:true,postUrl:"/api/metrics",getPingData:undefined,onServerResponse:undefined};h.prototype._init=function i(A){var z=this;z.options={};for(var y in h.defaultOptions){if(h.defaultOptions.hasOwnProperty(y)){z.options[y]=(A.hasOwnProperty(y))?(A[y]):(h.defaultOptions[y])}}z.options.logLevel=z._parseLevel(z.options.logLevel);z.options.consoleLevel=z._parseLevel(z.options.consoleLevel);z._sending=false;z._postSize=z.options.postSize;z._initCache();return z};h.prototype._initCache=function a(){this.cache=new w({maxSize:this.options.maxCacheSize})};h.prototype._parseLevel=function j(A){var z=typeof A;if(z==="number"){return A}if(z==="string"){var y=A.toUpperCase();if(h.hasOwnProperty(y)){return h[y]}}throw new Error("Unknown log level: "+A)};h.prototype.emit=function m(B,A,z){var y=this;A=A||y.options.defaultNamespace;if(!B||!z){return y}B=y._parseLevel(B);if(B>=y.options.logLevel){y._addToCache(B,A,z)}if(y.consoleLogger&&B>=y.options.consoleLevel){y._emitToConsole(B,A,z)}return y};h.prototype._addToCache=function b(D,A,z){this._emitToConsole("debug","MetricsLogger",["_addToCache:",arguments,this.options.addTime,this.cache.length()]);var y=this;try{var C=y.cache.add(y._buildEntry(D,A,z));if(C>=y._postSize){y._postCache()}}catch(B){y._emitToConsole("warn","MetricsLogger",["Metrics logger could not stringify logArguments:",A,z]);y._emitToConsole("error","MetricsLogger",[B])}return y};h.prototype._buildEntry=function r(B,z,y){this._emitToConsole("debug","MetricsLogger",["_buildEntry:",arguments]);var A={level:B,namespace:this.options.clientPrefix+z,args:y};if(this.options.addTime){A.time=new Date().toISOString()}return A};h.prototype._postCache=function s(B){B=B||{};this._emitToConsole("info","MetricsLogger",["_postCache",B,this._postSize]);if(!this.options.postUrl||this._sending){return jQuery.when({})}var A=this,D=B.count||A._postSize,y=A.cache.get(D),C=y.length,z=(typeof A.options.getPingData==="function")?(A.options.getPingData()):({});z.metrics=A._preprocessCache(y);A._sending=true;return jQuery.post(A.options.postUrl,z).always(function(){A._sending=false}).fail(function(){A._postSize=A.options.maxCacheSize}).done(function(E){if(typeof A.options.onServerResponse==="function"){A.options.onServerResponse(E)}A.cache.remove(C);A._postSize=A.options.postSize})};h.prototype._preprocessCache=function f(y){return["[",(y.join(",\n")),"]"].join("\n")};h.prototype._emitToConsole=function c(C,B,A){var y=this;if(!y.consoleLogger){return y}var z=Array.prototype.slice.call(A,0);z.unshift(B);if(C>=h.METRIC&&typeof(y.consoleLogger.info)==="function"){return y.consoleLogger.info.apply(y.consoleLogger,z)}else{if(C>=h.ERROR&&typeof(y.consoleLogger.error)==="function"){return y.consoleLogger.error.apply(y.consoleLogger,z)}else{if(C>=h.WARN&&typeof(y.consoleLogger.warn)==="function"){y.consoleLogger.warn.apply(y.consoleLogger,z)}else{if(C>=h.INFO&&typeof(y.consoleLogger.info)==="function"){y.consoleLogger.info.apply(y.consoleLogger,z)}else{if(C>=h.DEBUG&&typeof(y.consoleLogger.debug)==="function"){y.consoleLogger.debug.apply(y.consoleLogger,z)}else{if(typeof(y.consoleLogger.log)==="function"){y.consoleLogger.log.apply(y.consoleLogger,z)}}}}}}return y};h.prototype.log=function g(){this.emit(1,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};h.prototype.debug=function l(){this.emit(h.DEBUG,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};h.prototype.info=function u(){this.emit(h.INFO,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};h.prototype.warn=function t(){this.emit(h.WARN,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};h.prototype.error=function p(){this.emit(h.ERROR,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};h.prototype.metric=function n(){this.emit(h.METRIC,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};function w(z){var y=this;y._cache=[];return y._init(z||{})}w.defaultOptions={maxSize:5000};w.prototype._init=function i(y){this.maxSize=y.maxSize||w.defaultOptions.maxSize;return this};w.prototype.add=function k(A){var z=this,y=(z.length()+1)-z.maxSize;if(y>0){z.remove(y)}z._cache.push(z._preprocessEntry(A));return z.length()};w.prototype._preprocessEntry=function q(y){return JSON.stringify(y)};w.prototype.length=function e(){return this._cache.length};w.prototype.get=function v(y){return this._cache.slice(0,y)};w.prototype.remove=function x(y){return this._cache.splice(0,y)};w.prototype.stringify=function o(y){return["[",(this.get(y).join(",\n")),"]"].join("\n")};w.prototype.print=function d(){this._cache.forEach(function(y){console.log(y)})};return{MetricsLogger:h,LoggingCache:w}});
\ No newline at end of file
+define([],function(){function i(D){D=D||{};var C=this;C.userId=window.bootstrapped?window.bootstrapped.user.id:null;C.userId=C.userId||D.userId||null;C.consoleLogger=D.consoleLogger||null;C._init(D);return C}i.ALL=0;i.DEBUG=10;i.INFO=20;i.WARN=30;i.ERROR=40;i.METRIC=50;i.NONE=100;i.defaultOptions={logLevel:i.NONE,consoleLevel:i.NONE,defaultNamespace:"Galaxy",clientPrefix:"client.",maxCacheSize:3000,postSize:1000,addTime:true,cacheKeyPrefix:"logs-",postUrl:"/api/metrics",delayPostInMs:1000*60*10,getPingData:undefined,onServerResponse:undefined};i.prototype._init=function j(E){var D=this;D.options={};for(var C in i.defaultOptions){if(i.defaultOptions.hasOwnProperty(C)){D.options[C]=(E.hasOwnProperty(C))?(E[C]):(i.defaultOptions[C])}}D.options.logLevel=D._parseLevel(D.options.logLevel);D.options.consoleLevel=D._parseLevel(D.options.consoleLevel);D._sending=false;D._waiting=null;D._postSize=D.options.postSize;D._initCache();return D};i.prototype._initCache=function a(){try{this.cache=new z({maxSize:this.options.maxCacheSize,key:this.options.cacheKeyPrefix+this.userId})}catch(C){this._emitToConsole("warn","MetricsLogger",["Could not intitialize logging cache:",C]);this.options.logLevel=i.NONE}};i.prototype._parseLevel=function n(E){var D=typeof E;if(D==="number"){return E}if(D==="string"){var C=E.toUpperCase();if(i.hasOwnProperty(C)){return i[C]}}throw new Error("Unknown log level: "+E)};i.prototype.emit=function q(F,E,D){var C=this;E=E||C.options.defaultNamespace;if(!F||!D){return C}F=C._parseLevel(F);if(F>=C.options.logLevel){C._addToCache(F,E,D)}if(C.consoleLogger&&F>=C.options.consoleLevel){C._emitToConsole(F,E,D)}return C};i.prototype._addToCache=function b(H,E,D){this._emitToConsole("debug","MetricsLogger",["_addToCache:",arguments,this.options.addTime,this.cache.length()]);var C=this;try{var G=C.cache.add(C._buildEntry(H,E,D));if(G>=C._postSize){C._postCache()}}catch(F){C._emitToConsole("warn","MetricsLogger",["Metrics logger could not stringify logArguments:",E,D]);C._emitToConsole("error","MetricsLogger",[F])}return C};i.prototype._buildEntry=function u(F,D,C){this._emitToConsole("debug","MetricsLogger",["_buildEntry:",arguments]);var E={level:F,namespace:this.options.clientPrefix+D,args:C};if(this.options.addTime){E.time=new Date().toISOString()}return E};i.prototype._postCache=function v(F){F=F||{};this._emitToConsole("info","MetricsLogger",["_postCache",F,this._postSize]);if(!this.options.postUrl||this._sending){return jQuery.when({})}var E=this,H=F.count||E._postSize,C=E.cache.get(H),G=C.length,D=(typeof E.options.getPingData==="function")?(E.options.getPingData()):({});D.metrics=JSON.stringify(C);E._sending=true;return jQuery.post(E.options.postUrl,D).always(function(){E._sending=false}).fail(function(K,I,J){E._postSize=E.options.maxCacheSize;this.emit("error","MetricsLogger",["_postCache error:",K.readyState,K.status,K.responseJSON||K.responseText])}).done(function(I){if(typeof E.options.onServerResponse==="function"){E.options.onServerResponse(I)}E.cache.remove(G);E._postSize=E.options.postSize})};i.prototype._delayPost=function k(){var C=this;C._waiting=setTimeout(function(){C._waiting=null},C.options.delayPostInMs)};i.prototype._emitToConsole=function c(G,F,E){var C=this;if(!C.consoleLogger){return C}var D=Array.prototype.slice.call(E,0);D.unshift(F);if(G>=i.METRIC&&typeof(C.consoleLogger.info)==="function"){return C.consoleLogger.info.apply(C.consoleLogger,D)}else{if(G>=i.ERROR&&typeof(C.consoleLogger.error)==="function"){return C.consoleLogger.error.apply(C.consoleLogger,D)}else{if(G>=i.WARN&&typeof(C.consoleLogger.warn)==="function"){C.consoleLogger.warn.apply(C.consoleLogger,D)}else{if(G>=i.INFO&&typeof(C.consoleLogger.info)==="function"){C.consoleLogger.info.apply(C.consoleLogger,D)}else{if(G>=i.DEBUG&&typeof(C.consoleLogger.debug)==="function"){C.consoleLogger.debug.apply(C.consoleLogger,D)}else{if(typeof(C.consoleLogger.log)==="function"){C.consoleLogger.log.apply(C.consoleLogger,D)}}}}}}return C};i.prototype.log=function h(){this.emit(1,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.debug=function p(){this.emit(i.DEBUG,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.info=function x(){this.emit(i.INFO,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.warn=function w(){this.emit(i.WARN,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.error=function t(){this.emit(i.ERROR,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};i.prototype.metric=function r(){this.emit(i.METRIC,this.options.defaultNamespace,Array.prototype.slice.call(arguments,0))};function z(D){var C=this;return C._init(D||{})}z.defaultOptions={maxSize:5000};z.prototype._init=function j(C){if(!this._hasStorage()){throw new Error("LoggingCache needs localStorage")}if(!C.key){throw new Error("LoggingCache needs key for localStorage")}this.key=C.key;this._initStorage();this.maxSize=C.maxSize||z.defaultOptions.maxSize;return this};z.prototype._hasStorage=function A(){var D="test";try{localStorage.setItem(D,D);localStorage.removeItem(D);return true}catch(C){return false}};z.prototype._initStorage=function m(){if(localStorage.getItem(this.key)===null){return this.empty()}return this};z.prototype.add=function o(E){var D=this,F=D._fetchAndParse(),C=(F.length+1)-D.maxSize;if(C>0){F.splice(0,C)}F.push(E);D._unparseAndStore(F);return F.length};z.prototype._fetchAndParse=function g(){var C=this;return JSON.parse(localStorage.getItem(C.key))};z.prototype._unparseAndStore=function f(C){var D=this;return localStorage.setItem(D.key,JSON.stringify(C))};z.prototype.length=function e(){return this._fetchAndParse().length};z.prototype.get=function y(C){return this._fetchAndParse().slice(0,C)};z.prototype.remove=function B(C){var E=this._fetchAndParse(),D=E.splice(0,C);this._unparseAndStore(E);return D};z.prototype.empty=function l(){localStorage.setItem(this.key,"[]");return this};z.prototype.stringify=function s(C){return JSON.stringify(this.get(C))};z.prototype.print=function d(){console.log(JSON.stringify(this._fetchAndParse(),null," "))};return{MetricsLogger:i,LoggingCache:z}});
\ No newline at end of file
diff -r f1c9df0b5cabb998dd82dc6a154f66677173ffb8 -r 6f8070735e6f36fd1cd7b79d7cef1d69ebf8c1d6 static/scripts/utils/metrics-logger.js
--- a/static/scripts/utils/metrics-logger.js
+++ b/static/scripts/utils/metrics-logger.js
@@ -3,8 +3,10 @@
/*global window, jQuery, console */
/*=============================================================================
TODO:
- broken pipe due to onunload post in webkit, safari
- need to use persistence
+ while anon: logs saved to 'logs-null' - this will never post
+ unless we manually do so at/after login
+ OR prepend when userId and localStorage has 'logs-null'
+ wire up _delayPost and test
=============================================================================*/
/** @class MetricsLogger
@@ -31,8 +33,7 @@
options = options || {};
var self = this;
- //TODO: this might be used if we store the logs in browser storage
- ///** */
+ ///** get the current user's id from bootstrapped data or options */
self.userId = window.bootstrapped? window.bootstrapped.user.id: null;
self.userId = self.userId || options.userId || null;
@@ -73,9 +74,13 @@
postSize : 1000,
/** T/F whether to add a timestamp to incoming cached messages */
addTime : true,
+ /** string to prefix to userid for cache web storage */
+ cacheKeyPrefix : 'logs-',
/** the relative url to post messages to */
postUrl : '/api/metrics',
+ /** delay before trying post again after two failures */
+ delayPostInMs : 1000 * 60 * 10,
/** an (optional) function that should return an object; used to send additional data with the metrics */
getPingData : undefined,
@@ -97,8 +102,13 @@
self.options.consoleLevel = self._parseLevel( self.options.consoleLevel );
//self._emitToConsole( 'debug', 'MetricsLogger', 'MetricsLogger.options:', self.options );
+ /** is the logger currently sending? */
self._sending = false;
+ /** the setTimeout id if the logger POST has failed more than once */
+ self._waiting = null;
+ /** the current number of entries to send in a POST */
self._postSize = self.options.postSize;
+
self._initCache();
return self;
@@ -106,8 +116,15 @@
/** initialize the cache */
MetricsLogger.prototype._initCache = function _initCache(){
- this.cache = new LoggingCache({ maxSize : this.options.maxCacheSize });
-
+ try {
+ this.cache = new LoggingCache({
+ maxSize : this.options.maxCacheSize,
+ key : this.options.cacheKeyPrefix + this.userId
+ });
+ } catch( err ){
+ this._emitToConsole( 'warn', 'MetricsLogger', [ 'Could not intitialize logging cache:', err ] );
+ this.options.logLevel = MetricsLogger.NONE;
+ }
};
/** return the numeric log level if level in 'none, debug, log, info, warn, error' */
@@ -134,7 +151,7 @@
return self;
}
// add to cache if proper level
-//TODO: respect do not track?
+ //TODO: respect do not track?
//if( !navigator.doNotTrack && level >= self.options.logLevel ){
level = self._parseLevel( level );
if( level >= self.options.logLevel ){
@@ -192,7 +209,6 @@
MetricsLogger.prototype._postCache = function _postCache( options ){
options = options || {};
this._emitToConsole( 'info', 'MetricsLogger', [ '_postCache', options, this._postSize ]);
-//TODO: remove jq dependence
// short circuit if we're already sending
if( !this.options.postUrl || this._sending ){
@@ -209,15 +225,22 @@
//console.debug( postSize, entriesLength );
// add the metrics and send
- postData.metrics = self._preprocessCache( entries );
+ postData.metrics = JSON.stringify( entries );
+ //console.debug( postData.metrics );
self._sending = true;
return jQuery.post( self.options.postUrl, postData )
.always( function(){
self._sending = false;
})
- .fail( function(){
+ .fail( function( xhr, status, message ){
// if we failed the previous time, set the next post target to the max num of entries
self._postSize = self.options.maxCacheSize;
+//TODO:??
+ // log this failure to explain any gap in metrics
+ this.emit( 'error', 'MetricsLogger', [ '_postCache error:',
+ xhr.readyState, xhr.status, xhr.responseJSON || xhr.responseText ]);
+//TODO: still doesn't solve the problem that when cache == max, post will be tried on every emit
+//TODO: see _delayPost
})
.done( function( response ){
if( typeof self.options.onServerResponse === 'function' ){
@@ -232,10 +255,13 @@
// return the xhr promise
};
-/** Preprocess a number of cache entries for sending to the server (stringification) */
-MetricsLogger.prototype._preprocessCache = function _preprocessCache( entries ){
- return [ '[', ( entries.join( ',\n' ) ), ']' ].join( '\n' );
- //return [ '[', ( entries.join( ',' ) ), ']' ].join( '' );
+/** set _waiting to true and, after delayPostInMs, set it back to false */
+MetricsLogger.prototype._delayPost = function _delayPost(){
+//TODO: this won't work between pages
+ var self = this;
+ self._waiting = setTimeout( function(){
+ self._waiting = null;
+ }, self.options.delayPostInMs );
};
@@ -306,7 +332,11 @@
};
-//=============================================================================
+/* ============================================================================
+TODO:
+ need a performance pass - the JSON un/parsing is a bit much
+
+============================================================================ */
/** @class LoggingCache
* Simple implementation of cache wrapping an array.
*
@@ -315,7 +345,6 @@
*/
function LoggingCache( options ){
var self = this;
- self._cache = [];
return self._init( options || {} );
}
@@ -327,52 +356,104 @@
/** initialize with options */
LoggingCache.prototype._init = function _init( options ){
+ if( !this._hasStorage() ){
+ //TODO: fall back to jstorage
+ throw new Error( 'LoggingCache needs localStorage' );
+ }
+ if( !options.key ){
+ throw new Error( 'LoggingCache needs key for localStorage' );
+ }
+ this.key = options.key;
+ this._initStorage();
+
this.maxSize = options.maxSize || LoggingCache.defaultOptions.maxSize;
return this;
};
+/** tests for localStorage fns */
+LoggingCache.prototype._hasStorage = function _hasStorage(){
+//TODO: modernizr
+ var test = 'test';
+ try {
+ localStorage.setItem( test, test );
+ localStorage.removeItem( test );
+ return true;
+ } catch( e ){
+ return false;
+ }
+};
+
+/** if no localStorage set for key, initialize to empty array */
+LoggingCache.prototype._initStorage = function _initStorage(){
+ if( localStorage.getItem( this.key ) === null ){
+ return this.empty();
+ }
+ return this;
+};
+
/** add an entry to the cache, removing the oldest beforehand if size >= maxSize */
LoggingCache.prototype.add = function add( entry ){
var self = this,
- overage = ( self.length() + 1 ) - self.maxSize;
+ _cache = self._fetchAndParse(),
+ overage = ( _cache.length + 1 ) - self.maxSize;
if( overage > 0 ){
- self.remove( overage );
+ _cache.splice( 0, overage );
}
- self._cache.push( self._preprocessEntry( entry ) );
- return self.length();
+ _cache.push( entry );
+ self._unparseAndStore( _cache );
+ return _cache.length;
};
-/** process the entry before caching */
-LoggingCache.prototype._preprocessEntry = function _preprocessEntry( entry ){
- return JSON.stringify( entry );
+/** get the entries from localStorage and parse them */
+LoggingCache.prototype._fetchAndParse = function _fetchAndParse(){
+ var self = this;
+ return JSON.parse( localStorage.getItem( self.key ) );
};
+/** stringify the entries and put them in localStorage */
+LoggingCache.prototype._unparseAndStore = function _unparseAndStore( entries ){
+ var self = this;
+ return localStorage.setItem( self.key, JSON.stringify( entries ) );
+};
+
+///** process the entry before caching */
+//LoggingCache.prototype._preprocessEntry = function _preprocessEntry( entry ){
+// return JSON.stringify( entry );
+//};
+
/** return the length --- oh, getters where are you? */
LoggingCache.prototype.length = function length(){
- return this._cache.length;
+ return this._fetchAndParse().length;
};
/** get count number of entries starting with the oldest */
LoggingCache.prototype.get = function get( count ){
- return this._cache.slice( 0, count );
+ return this._fetchAndParse().slice( 0, count );
};
/** remove count number of entries starting with the oldest */
LoggingCache.prototype.remove = function remove( count ){
- return this._cache.splice( 0, count );
+ var _cache = this._fetchAndParse(),
+ removed = _cache.splice( 0, count );
+ this._unparseAndStore( _cache );
+ return removed;
+};
+
+/** empty/clear the entire cache */
+LoggingCache.prototype.empty = function empty(){
+ localStorage.setItem( this.key, '[]' );
+ return this;
};
/** stringify count number of entries (but do not remove) */
LoggingCache.prototype.stringify = function stringify( count ){
- return [ '[', ( this.get( count ).join( ',\n' ) ), ']' ].join( '\n' );
+ return JSON.stringify( this.get( count ) );
};
/** outputs entire cache to console */
LoggingCache.prototype.print = function print(){
// popup? (really, carl? a popup?) - easier to copy/paste
- this._cache.forEach( function( entry ){
- console.log( entry );
- });
+ console.log( JSON.stringify( this._fetchAndParse(), null, ' ' ) );
};
diff -r f1c9df0b5cabb998dd82dc6a154f66677173ffb8 -r 6f8070735e6f36fd1cd7b79d7cef1d69ebf8c1d6 test/qunit/tests/metrics-logger.js
--- a/test/qunit/tests/metrics-logger.js
+++ b/test/qunit/tests/metrics-logger.js
@@ -22,9 +22,51 @@
self.lastMessage = { level: fnName, args: args };
};
});
+ return self;
+ };
+
+ var MockLocalStorage = function(){
+ var self = this;
+ self._storage = {};
+ self.setItem = function( k, v ){
+ self._storage[ k ] = v + '';
+ return undefined;
+ };
+ self.getItem = function( k ){
+ return self._storage.hasOwnProperty( k )? self._storage[ k ]: null;
+ };
+ self.removeItem = function( k ){
+ if( self._storage.hasOwnProperty( k ) ){
+ delete self._storage[ k ];
+ }
+ return undefined;
+ };
+ self.key = function( i ){
+ var index = 0;
+ for( var k in self._storage ){
+ if( self._storage.hasOwnProperty( k ) ){
+ if( i === index ){ return k; }
+ index += 1;
+ }
+ }
+ return null;
+ };
+ self.clear = function(){
+ self._storage = {};
+ };
+ // property - not worth it
+ //self.length = function(){};
+
+ return self;
+ };
+ window.localStorage = new MockLocalStorage();
+
+ ( window.bootstrapped = {} ).user = {
+ id : 'test'
};
module( "Metrics logger tests" );
+ console.debug( '\n' );
// ======================================================================== MetricsLogger
test( "logger construction/initializiation defaults", function() {
var logger = new metrics.MetricsLogger({});
@@ -68,11 +110,14 @@
var logger = new metrics.MetricsLogger({
logLevel : 'metric'
});
+ logger.cache.empty();
+
equal( logger.options.logLevel, metrics.MetricsLogger.METRIC );
logger.emit( 'metric', 'test', [ 1, 2, { three: 3 }] );
equal( logger.cache.length(), 1 );
- var cached = JSON.parse( logger.cache.get( 1 ) );
+ var cached = logger.cache.get( 1 )[0];
+ //console.debug( 'cached:', JSON.stringify( cached ) );
equal( cached.level, metrics.MetricsLogger.METRIC );
equal( cached.namespace, 'client.test' );
equal( cached.args.length, 3 );
@@ -85,6 +130,8 @@
var logger = new metrics.MetricsLogger({
logLevel : 'metric'
});
+ logger.cache.empty();
+
logger.emit( 'error', 'test', [ 1, 2, { three: 3 }] );
equal( logger.cache.length(), 0 );
});
@@ -93,6 +140,8 @@
var logger = new metrics.MetricsLogger({
logLevel : 'metric'
});
+ logger.cache.empty();
+
logger.emit( 'metric', 'test', [{ window: window }] );
equal( logger.cache.length(), 0 );
});
@@ -108,11 +157,14 @@
logLevel : 'metric',
onServerResponse : function( response ){ callback(); }
});
+ logger.cache.empty();
var server = sinon.fakeServer.create(),
metricsOnServer;
server.respondWith( 'POST', '/api/metrics', function( request ){
metricsOnServer = metricsFromRequestBody( request );
+ //console.debug( 'requestBody:', request.requestBody );
+ //console.debug( 'metricsOnServer:', JSON.stringify( metricsOnServer, null, ' ' ) );
request.respond(
200,
{ "Content-Type": "application/json" },
@@ -125,6 +177,7 @@
logger.emit( 'metric', 'test', [ 1, 2, { three: 3 }] );
logger._postCache();
server.respond();
+
ok( callback.calledOnce, 'onServerResponse was called' );
equal( logger.cache.length(), 0, 'should have emptied cache (on success)' );
equal( logger._postSize, 1000, '_postSize still at default' );
@@ -148,6 +201,7 @@
logLevel : 'metric',
onServerResponse : function( response ){ callback(); }
});
+ logger.cache.empty();
var server = sinon.fakeServer.create();
server.respondWith( 'POST', '/api/metrics', function( request ){
@@ -168,8 +222,6 @@
equal( logger.cache.length(), 1, 'should NOT have emptied cache' );
equal( logger._postSize, logger.options.maxCacheSize, '_postSize changed to max' );
- //TODO: still doesn't solve the problem that when cache == max, post will be tried on every emit
-
server.restore();
});
@@ -207,6 +259,8 @@
var logger = new metrics.MetricsLogger({
logLevel : 'all'
});
+ logger.cache.empty();
+
equal( logger.options.logLevel, metrics.MetricsLogger.ALL );
logger.log( 0 );
logger.debug( 1 );
@@ -216,7 +270,7 @@
logger.metric( 5 );
equal( logger.cache.length(), 6 );
- var cached = logger.cache.remove( 6 ).map( JSON.parse ),
+ var cached = logger.cache.remove( 6 ),
entry;
cached.forEach( function( entry ){
@@ -240,22 +294,39 @@
// ======================================================================== LoggingCache
test( "cache construction/initializiation defaults", function() {
- var cache = new metrics.LoggingCache();
+ // use empty to prevent tests stepping on one another due to persistence
+ var cache = new metrics.LoggingCache({ key: 'logs-test' }).empty();
equal( cache.maxSize, 5000 );
- equal( $.type( cache._cache ), 'array' );
+ equal( window.localStorage.getItem( 'logs-test' ), '[]' );
+ });
+
+ test( "cache construction/initializiation failure", function() {
+ ////TODO: doesn't work - readonly
+ //window.localStorage = null;
+ //console.debug( 'localStorage:', window.localStorage );
+ var oldFn = metrics.LoggingCache.prototype._hasStorage;
+ metrics.LoggingCache.prototype._hasStorage = function(){ return false; };
+ throws( function(){
+ return new metrics.LoggingCache({ key: 'logs-test' });
+ }, /LoggingCache needs localStorage/, 'lack of localStorage throws error' );
+ metrics.LoggingCache.prototype._hasStorage = oldFn;
+
+ throws( function(){
+ return new metrics.LoggingCache();
+ }, /LoggingCache needs key for localStorage/, 'lack of key throws error' );
});
test( "cache construction/initializiation setting max cache size", function() {
var cache = new metrics.LoggingCache({
+ key : 'logs-test',
maxSize : 5
- });
+ }).empty();
equal( cache.maxSize, 5 );
});
test( "cache plays well with no data", function() {
- var cache = new metrics.LoggingCache();
+ var cache = new metrics.LoggingCache({ key: 'logs-test' }).empty();
- equal( cache._cache.length, 0 );
equal( cache.length(), 0 );
var get = cache.get( 10 );
ok( jQuery.type( get ) === 'array' && get.length === 0 );
@@ -266,42 +337,59 @@
test( "cache add properly adds and removes data", function() {
var cache = new metrics.LoggingCache({
+ key : 'logs-test',
maxSize : 5
- });
+ }).empty();
+
var entry1 = [{ one: 1 }, 'two' ];
cache.add( entry1 );
- equal( cache._cache.length, 1 );
equal( cache.length(), 1 );
- equal( cache._cache[0], JSON.stringify( entry1 ) );
- equal( cache.get( 1 ), JSON.stringify( entry1 ) );
+ equal( JSON.stringify( cache.get( 1 )[0] ), JSON.stringify( entry1 ) );
var entry2 = { blah: { one: 1 }, bler: [ 'three', { two: 2 } ] };
cache.add( entry2 );
equal( cache.length(), 2 );
- equal( cache.stringify( 2 ), '[\n' + JSON.stringify( entry1 ) + ',\n' + JSON.stringify( entry2 ) + '\n]' );
+ equal( cache.stringify( 2 ), '[' + JSON.stringify( entry1 ) + ',' + JSON.stringify( entry2 ) + ']' );
// FIFO
var returned = cache.remove( 1 );
equal( cache.length(), 1 );
ok( jQuery.type( returned ) === 'array' && returned.length === 1 );
var returned0 = returned[0];
- ok( jQuery.type( returned0 ) === 'string' && returned0 === JSON.stringify( entry1 ) );
+ ok( jQuery.type( returned0 ) === 'array' && JSON.stringify( returned0 ) === JSON.stringify( entry1 ) );
});
test( "cache past max loses oldest", function() {
var cache = new metrics.LoggingCache({
+ key : 'logs-test',
maxSize : 5
- });
+ }).empty();
+
for( var i=0; i<10; i+=1 ){
cache.add({ index: i });
}
equal( cache.length(), 5 );
var get = cache.get( 5 );
- ok( JSON.parse( get[0] ).index === 5 );
- ok( JSON.parse( get[1] ).index === 6 );
- ok( JSON.parse( get[2] ).index === 7 );
- ok( JSON.parse( get[3] ).index === 8 );
- ok( JSON.parse( get[4] ).index === 9 );
+ ok( get[0].index === 5 );
+ ok( get[1].index === 6 );
+ ok( get[2].index === 7 );
+ ok( get[3].index === 8 );
+ ok( get[4].index === 9 );
});
+
+ test( "cache is properly persistent", function() {
+ var cache1 = new metrics.LoggingCache({ key : 'logs-test' }).empty(),
+ entry = [{ one: 1 }, 'two' ];
+ cache1.add( entry );
+ equal( cache1.length(), 1 );
+
+ var cache2 = new metrics.LoggingCache({ key : 'logs-test' });
+ equal( cache2.length(), 1, 'old key gets previously stored' );
+ equal( JSON.stringify( cache2.get( 1 )[0] ), JSON.stringify( entry ) );
+
+ var cache3 = new metrics.LoggingCache({ key : 'logs-bler' });
+ equal( cache3.length(), 0, 'new key causes new storage' );
+ });
+
});
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0