PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/client/galaxy/scripts/mvc/library/library-foldertoolbar-view.js

https://bitbucket.org/remy_d1/galaxy-central-manageapi
JavaScript | 1250 lines | 1001 code | 114 blank | 135 comment | 99 complexity | d8af295ef692e220faabe60f955c4125 MD5 | raw file
Possible License(s): CC-BY-3.0

Large files files are truncated, but you can click here to view the full file

  1. define([
  2. "galaxy.masthead",
  3. "utils/utils",
  4. "libs/toastr",
  5. "mvc/library/library-model",
  6. "mvc/ui/ui-select"
  7. ],
  8. function( mod_masthead,
  9. mod_utils,
  10. mod_toastr,
  11. mod_library_model,
  12. mod_select
  13. ){
  14. var FolderToolbarView = Backbone.View.extend({
  15. el: '#center',
  16. events: {
  17. 'click #toolbtn_create_folder' : 'createFolderFromModal',
  18. 'click #toolbtn_bulk_import' : 'modalBulkImport',
  19. 'click #include_deleted_datasets_chk' : 'checkIncludeDeleted',
  20. 'click #toolbtn_show_libinfo' : 'showLibInfo',
  21. 'click #toolbtn_bulk_delete' : 'deleteSelectedDatasets'
  22. },
  23. defaults: {
  24. 'can_add_library_item' : false,
  25. 'contains_file' : false,
  26. 'chain_call_control' : {
  27. 'total_number' : 0,
  28. 'failed_number' : 0
  29. },
  30. 'disabled_jstree_element' : 'folders'
  31. },
  32. modal : null,
  33. // directory browsing object
  34. jstree: null,
  35. // user's histories
  36. histories : null,
  37. // genome select
  38. select_genome : null,
  39. // extension select
  40. select_extension : null,
  41. // extension types
  42. list_extensions :[],
  43. // datatype placeholder for extension auto-detection
  44. auto: {
  45. id : 'auto',
  46. text : 'Auto-detect',
  47. description : 'This system will try to detect the file type automatically.' +
  48. ' If your file is not detected properly as one of the known formats,' +
  49. ' it most likely means that it has some format problems (e.g., different' +
  50. ' number of columns on different rows). You can still coerce the system' +
  51. ' to set your data to the format you think it should be.' +
  52. ' You can also upload compressed files, which will automatically be decompressed.'
  53. },
  54. // genomes
  55. list_genomes : [],
  56. initialize: function(options){
  57. this.options = _.defaults( options || {}, this.defaults );
  58. this.fetchExtAndGenomes();
  59. this.render();
  60. },
  61. render: function(options){
  62. this.options = _.extend( this.options, options );
  63. var toolbar_template = this.templateToolBar();
  64. var template_defaults = {
  65. id: this.options.id,
  66. is_admin: false,
  67. is_anonym: true,
  68. mutiple_add_dataset_options: false
  69. }
  70. if (Galaxy.currUser){
  71. template_defaults.is_admin = Galaxy.currUser.isAdmin();
  72. template_defaults.is_anonym = Galaxy.currUser.isAnonymous();
  73. if ( Galaxy.config.user_library_import_dir !== null || Galaxy.config.allow_library_path_paste !== false || Galaxy.config.library_import_dir !== null ){
  74. template_defaults.mutiple_add_dataset_options = true;
  75. }
  76. }
  77. this.$el.html(toolbar_template(template_defaults));
  78. },
  79. configureElements: function(options){
  80. this.options = _.extend(this.options, options);
  81. if (this.options.can_add_library_item === true){
  82. $('.add-library-items').show();
  83. } else{
  84. $('.add-library-items').hide();
  85. }
  86. if (this.options.contains_file === true){
  87. if (Galaxy.currUser){
  88. if (!Galaxy.currUser.isAnonymous()){
  89. $('.logged-dataset-manipulation').show();
  90. $('.dataset-manipulation').show();
  91. } else {
  92. $('.dataset-manipulation').show();
  93. $('.logged-dataset-manipulation').hide();
  94. }
  95. } else {
  96. $('.logged-dataset-manipulation').hide();
  97. $('.dataset-manipulation').hide();
  98. }
  99. } else {
  100. $('.logged-dataset-manipulation').hide();
  101. $('.dataset-manipulation').hide();
  102. }
  103. this.$el.find('[data-toggle]').tooltip();
  104. },
  105. // shows modal for creating folder
  106. createFolderFromModal: function( event ){
  107. event.preventDefault();
  108. event.stopPropagation();
  109. // create modal
  110. var self = this;
  111. var template = this.templateNewFolderInModal();
  112. this.modal = Galaxy.modal;
  113. this.modal.show({
  114. closing_events : true,
  115. title : 'Create New Folder',
  116. body : template(),
  117. buttons : {
  118. 'Create' : function() {self.create_new_folder_event();},
  119. 'Close' : function() {Galaxy.modal.hide();}
  120. }
  121. });
  122. },
  123. // create the new folder from modal
  124. create_new_folder_event: function(){
  125. var folderDetails = this.serialize_new_folder();
  126. if (this.validate_new_folder(folderDetails)){
  127. var folder = new mod_library_model.FolderAsModel();
  128. url_items = Backbone.history.fragment.split('/');
  129. current_folder_id = url_items[url_items.length-1];
  130. folder.url = folder.urlRoot + '/' + current_folder_id ;
  131. folder.save(folderDetails, {
  132. success: function (folder) {
  133. Galaxy.modal.hide();
  134. mod_toastr.success('Folder created.');
  135. folder.set({'type' : 'folder'});
  136. Galaxy.libraries.folderListView.collection.add(folder);
  137. },
  138. error: function(model, response){
  139. Galaxy.modal.hide();
  140. if (typeof response.responseJSON !== "undefined"){
  141. mod_toastr.error(response.responseJSON.err_msg);
  142. } else {
  143. mod_toastr.error('An error ocurred.');
  144. }
  145. }
  146. });
  147. } else {
  148. mod_toastr.error('Folder\'s name is missing.');
  149. }
  150. return false;
  151. },
  152. // serialize data from the modal
  153. serialize_new_folder : function(){
  154. return {
  155. name: $("input[name='Name']").val(),
  156. description: $("input[name='Description']").val()
  157. };
  158. },
  159. // validate new folder info
  160. validate_new_folder: function(folderDetails){
  161. return folderDetails.name !== '';
  162. },
  163. // show bulk import modal
  164. modalBulkImport : function(){
  165. var checkedValues = $('#folder_table').find(':checked');
  166. if(checkedValues.length === 0){
  167. mod_toastr.info('You must select some datasets first.');
  168. } else {
  169. this.refreshUserHistoriesList(function(that){
  170. var template = that.templateBulkImportInModal();
  171. that.modal = Galaxy.modal;
  172. that.modal.show({
  173. closing_events : true,
  174. title : 'Import into History',
  175. body : template({histories : that.histories.models}),
  176. buttons : {
  177. 'Import' : function() {that.importAllIntoHistory();},
  178. 'Close' : function() {Galaxy.modal.hide();}
  179. }
  180. });
  181. });
  182. }
  183. },
  184. refreshUserHistoriesList: function(callback){
  185. var that = this;
  186. this.histories = new mod_library_model.GalaxyHistories();
  187. this.histories.fetch({
  188. success: function (){
  189. callback(that);
  190. },
  191. error: function(model, response){
  192. if (typeof response.responseJSON !== "undefined"){
  193. mod_toastr.error(response.responseJSON.err_msg);
  194. } else {
  195. mod_toastr.error('An error ocurred.');
  196. }
  197. }
  198. });
  199. },
  200. /**
  201. * Import all selected datasets into history.
  202. */
  203. importAllIntoHistory : function (){
  204. this.modal.disableButton('Import');
  205. var history_id = $("select[name=dataset_import_bulk] option:selected").val();
  206. var history_name = $("select[name=dataset_import_bulk] option:selected").text();
  207. // we can save last used history to pre-select it next time
  208. this.options.last_used_history_id = history_id;
  209. var dataset_ids = [];
  210. $('#folder_table').find(':checked').each(function(){
  211. if (this.parentElement.parentElement.id !== '') {
  212. dataset_ids.push(this.parentElement.parentElement.id);
  213. }
  214. });
  215. // prepare the dataset objects to be imported
  216. var datasets_to_import = [];
  217. for (var i = dataset_ids.length - 1; i >= 0; i--) {
  218. var library_dataset_id = dataset_ids[i];
  219. var historyItem = new mod_library_model.HistoryItem();
  220. historyItem.url = historyItem.urlRoot + history_id + '/contents';
  221. historyItem.content = library_dataset_id;
  222. historyItem.source = 'library';
  223. datasets_to_import.push(historyItem);
  224. }
  225. this.initChainCallControl( { length: datasets_to_import.length, action: 'to_history', history_name: history_name } );
  226. // set the used history as current so user will see the last one
  227. // that he imported into in the history panel on the 'analysis' page
  228. jQuery.getJSON( galaxy_config.root + 'history/set_as_current?id=' + history_id );
  229. this.chainCallImportingIntoHistory( datasets_to_import, history_name );
  230. },
  231. /**
  232. * Update the progress bar in modal window.
  233. */
  234. updateProgress: function(){
  235. this.progress += this.progressStep;
  236. $( '.progress-bar-import' ).width( Math.round( this.progress ) + '%' );
  237. txt_representation = Math.round( this.progress ) + '% Complete';
  238. $( '.completion_span' ).text( txt_representation );
  239. },
  240. /**
  241. * download selected datasets
  242. * @param {str} folder_id id of the current folder
  243. * @param {str} format requested archive format
  244. */
  245. download : function( folder_id, format ){
  246. var dataset_ids = [];
  247. $( '#folder_table' ).find( ':checked' ).each( function(){
  248. if ( this.parentElement.parentElement.id !== '' ) {
  249. dataset_ids.push( this.parentElement.parentElement.id );
  250. }
  251. } );
  252. var url = '/api/libraries/datasets/download/' + format;
  253. var data = { 'ld_ids' : dataset_ids };
  254. this.processDownload( url, data, 'get' );
  255. },
  256. /**
  257. * Create hidden form and submit it through POST
  258. * to initialize the download.
  259. * @param {str} url url to call
  260. * @param {obj} data data to include in the request
  261. * @param {str} method method of the request
  262. */
  263. processDownload: function( url, data, method ){
  264. if ( url && data ){
  265. // data can be string of parameters or array/object
  266. data = typeof data === 'string' ? data : $.param( data );
  267. // split params into form inputs
  268. var inputs = '';
  269. $.each( data.split( '&' ), function(){
  270. var pair = this.split( '=' );
  271. inputs+='<input type="hidden" name="'+ pair[0] +'" value="'+ pair[1] +'" />';
  272. });
  273. // send request
  274. $('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>')
  275. .appendTo( 'body' ).submit().remove();
  276. mod_toastr.info( 'Your download will begin soon.' );
  277. } else {
  278. mod_toastr.error( 'An error occurred.' );
  279. }
  280. },
  281. addFilesFromHistoryModal: function(){
  282. this.refreshUserHistoriesList( function( self ){
  283. self.modal = Galaxy.modal;
  284. var template_modal = self.templateAddFilesFromHistory();
  285. var folder_name = self.options.full_path[self.options.full_path.length - 1][1]
  286. self.modal.show({
  287. closing_events : true,
  288. title : 'Adding datasets from your history to folder ' + folder_name,
  289. body : template_modal({histories: self.histories.models}),
  290. buttons : {
  291. 'Add' : function() {self.addAllDatasetsFromHistory();},
  292. 'Close' : function() {Galaxy.modal.hide();}
  293. },
  294. closing_callback: function(){
  295. Galaxy.libraries.library_router.back();
  296. }
  297. });
  298. // user should always have a history, even anonymous user
  299. if (self.histories.models.length > 0){
  300. self.fetchAndDisplayHistoryContents(self.histories.models[0].id);
  301. $( "#dataset_add_bulk" ).change(function(event) {
  302. self.fetchAndDisplayHistoryContents(event.target.value);
  303. });
  304. } else {
  305. mod_toastr.error( 'An error ocurred.' );
  306. }
  307. });
  308. },
  309. /**
  310. * Create modal for importing from Galaxy path.
  311. * This feature is admin-only.
  312. */
  313. importFilesFromPathModal: function(){
  314. var that = this;
  315. this.modal = Galaxy.modal;
  316. var template_modal = this.templateImportPathModal();
  317. this.modal.show({
  318. closing_events : true,
  319. title : 'Please enter paths to import',
  320. body : template_modal({}),
  321. buttons : {
  322. 'Import' : function() { that.importFromPathsClicked(that); },
  323. 'Close' : function() { Galaxy.modal.hide(); }
  324. },
  325. closing_callback: function(){
  326. // TODO: should not trigger routes outside of the router
  327. Galaxy.libraries.library_router.navigate( 'folders/' + that.id, { trigger: true } );
  328. }
  329. });
  330. this.renderSelectBoxes();
  331. },
  332. /**
  333. * Request all extensions and genomes from Galaxy
  334. * and save them sorted in arrays.
  335. */
  336. fetchExtAndGenomes: function(){
  337. var that = this;
  338. mod_utils.get({
  339. url : galaxy_config.root + "api/datatypes?extension_only=False",
  340. success : function( datatypes ) {
  341. for (key in datatypes) {
  342. that.list_extensions.push({
  343. id : datatypes[key].extension,
  344. text : datatypes[key].extension,
  345. description : datatypes[key].description,
  346. description_url : datatypes[key].description_url
  347. });
  348. }
  349. that.list_extensions.sort(function(a, b) {
  350. return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
  351. });
  352. that.list_extensions.unshift(that.auto);
  353. }
  354. });
  355. mod_utils.get({
  356. url: galaxy_config.root + "api/genomes",
  357. success: function( genomes ) {
  358. for ( key in genomes ) {
  359. that.list_genomes.push({
  360. id : genomes[key][1],
  361. text : genomes[key][0]
  362. });
  363. }
  364. that.list_genomes.sort(function(a, b) {
  365. return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
  366. });
  367. }
  368. });
  369. },
  370. renderSelectBoxes: function(){
  371. // This won't work properly unlesss we already have the data fetched.
  372. // See this.fetchExtAndGenomes()
  373. // TODO switch to common resources:
  374. // https://trello.com/c/dIUE9YPl/1933-ui-common-resources-and-data-into-galaxy-object
  375. var that = this;
  376. this.select_genome = new mod_select.View( {
  377. css: 'library-genome-select',
  378. data: that.list_genomes,
  379. container: Galaxy.modal.$el.find( '#library_genome_select' ),
  380. value: '?'
  381. } );
  382. this.select_extension = new mod_select.View({
  383. css: 'library-extension-select',
  384. data: that.list_extensions,
  385. container: Galaxy.modal.$el.find( '#library_extension_select' ),
  386. value: 'auto'
  387. });
  388. },
  389. /**
  390. * Create modal for importing from given directory
  391. * on Galaxy. Bind jQuery events.
  392. */
  393. importFilesFromGalaxyFolderModal: function( options ){
  394. var that = this;
  395. var template_modal = this.templateBrowserModal();
  396. this.modal = Galaxy.modal;
  397. this.modal.show({
  398. closing_events : true,
  399. title : 'Please select folders or files',
  400. body : template_modal({}),
  401. buttons : {
  402. 'Import' : function() {
  403. that.importFromJstreePath( that, options );
  404. },
  405. 'Close' : function() {
  406. Galaxy.modal.hide();
  407. }
  408. },
  409. closing_callback: function(){
  410. // TODO: should not trigger routes outside of the router
  411. Galaxy.libraries.library_router.navigate('folders/' + that.id, {trigger: true});
  412. }
  413. });
  414. this.renderSelectBoxes();
  415. options.disabled_jstree_element = 'folders';
  416. this.renderJstree( options );
  417. $( 'input[type=radio]' ).change( function( event ){
  418. if (event.target.value ==='jstree-disable-folders') {
  419. options.disabled_jstree_element = 'folders';
  420. that.renderJstree( options );
  421. $('.jstree-folders-message').hide();
  422. $('.jstree-preserve-structure').hide();
  423. $('.jstree-link-files').hide();
  424. $('.jstree-files-message').show();
  425. } else if ( event.target.value ==='jstree-disable-files' ){
  426. $('.jstree-files-message').hide();
  427. $('.jstree-folders-message').show();
  428. $('.jstree-link-files').show();
  429. $('.jstree-preserve-structure').show();
  430. options.disabled_jstree_element = 'files';
  431. that.renderJstree( options );
  432. }
  433. }
  434. );
  435. },
  436. /**
  437. * Fetch the contents of user directory on Galaxy
  438. * and render jstree component based on received
  439. * data.
  440. * @param {[type]} options [description]
  441. */
  442. renderJstree: function( options ){
  443. var that = this;
  444. this.options = _.extend( this.options, options );
  445. var target = options.source || 'userdir';
  446. var disabled_jstree_element = this.options.disabled_jstree_element;
  447. this.jstree = new mod_library_model.Jstree();
  448. this.jstree.url = this.jstree.urlRoot +
  449. '?target=' + target +
  450. '&format=jstree' +
  451. '&disable=' + disabled_jstree_element;
  452. this.jstree.fetch({
  453. success: function(model, response){
  454. // This is to prevent double jquery load. I think. Carl is magician.
  455. define( 'jquery', function(){ return jQuery; });
  456. // Now we need jstree, time to lazy load it.
  457. require([ 'libs/jquery/jstree' ], function(jstree){
  458. $('#jstree_browser').jstree("destroy");
  459. $('#jstree_browser').jstree({
  460. 'core':{
  461. 'data': model
  462. },
  463. 'plugins': ['types', 'checkbox'],
  464. 'types': {
  465. "folder": {
  466. "icon": "jstree-folder"
  467. },
  468. "file": {
  469. "icon": "jstree-file"
  470. }
  471. },
  472. 'checkbox': {
  473. three_state: false
  474. }
  475. });
  476. });
  477. },
  478. error: function(model, response){
  479. if (typeof response.responseJSON !== "undefined"){
  480. mod_toastr.error(response.responseJSON.err_msg);
  481. } else {
  482. mod_toastr.error('An error ocurred.');
  483. }
  484. }
  485. })
  486. },
  487. /**
  488. * Take the paths from the textarea, split it, create
  489. * a request queue and call a function that starts sending
  490. * one by one to be imported on the server.
  491. */
  492. importFromPathsClicked: function(){
  493. var preserve_dirs = this.modal.$el.find('.preserve-checkbox').is(':checked');
  494. var link_data = this.modal.$el.find('.link-checkbox').is(':checked');
  495. var file_type = this.select_extension.value();
  496. var dbkey = this.select_genome.value();
  497. var paths = $('textarea#import_paths').val();
  498. var valid_paths = [];
  499. if (!paths){
  500. mod_toastr.info('Please enter a path relative to Galaxy root.');
  501. } else {
  502. this.modal.disableButton('Import');
  503. paths = paths.split('\n');
  504. for (var i = paths.length - 1; i >= 0; i--) {
  505. trimmed = paths[i].trim();
  506. if (trimmed.length!==0){
  507. valid_paths.push(trimmed);
  508. }
  509. };
  510. this.initChainCallControl( { length: valid_paths.length, action: 'adding_datasets' } );
  511. this.chainCallImportingFolders( { paths: valid_paths,
  512. preserve_dirs: preserve_dirs,
  513. link_data: link_data,
  514. source: 'admin_path',
  515. file_type: file_type,
  516. dbkey: dbkey } );
  517. }
  518. },
  519. /**
  520. * Initialize the control of chaining requests
  521. * in the current modal.
  522. * @param {int} length The number of items in the chain call.
  523. */
  524. initChainCallControl: function( options ){
  525. var template;
  526. switch( options.action ){
  527. case "adding_datasets":
  528. template = this.templateAddingDatasetsProgressBar();
  529. this.modal.$el.find( '.modal-body' ).html( template( { folder_name : this.options.folder_name } ) );
  530. break;
  531. case "deleting_datasets":
  532. template = this.templateDeletingDatasetsProgressBar();
  533. this.modal.$el.find( '.modal-body' ).html( template() );
  534. break;
  535. case "to_history":
  536. template = this.templateImportIntoHistoryProgressBar();
  537. this.modal.$el.find( '.modal-body' ).html( template( { history_name : options.history_name } ) );
  538. break;
  539. default:
  540. console.error( 'Wrong action specified.')
  541. break;
  542. }
  543. // var progress_bar_tmpl = this.templateAddingDatasetsProgressBar();
  544. // this.modal.$el.find( '.modal-body' ).html( progress_bar_tmpl( { folder_name : this.options.folder_name } ) );
  545. this.progress = 0;
  546. this.progressStep = 100 / options.length;
  547. this.options.chain_call_control.total_number = options.length;
  548. this.options.chain_call_control.failed_number = 0;
  549. },
  550. /**
  551. * Take the selected items from the jstree, create a request queue
  552. * and send them one by one to the server for importing into
  553. * the current folder.
  554. *
  555. * jstree.js has to be loaded before
  556. * @see renderJstree
  557. */
  558. importFromJstreePath: function ( that, options ){
  559. var selected_nodes = $( '#jstree_browser' ).jstree().get_selected( true );
  560. var preserve_dirs = this.modal.$el.find( '.preserve-checkbox' ).is( ':checked' );
  561. var link_data = this.modal.$el.find( '.link-checkbox' ).is( ':checked' );
  562. var file_type = this.select_extension.value();
  563. var dbkey = this.select_genome.value();
  564. var selection_type = selected_nodes[0].type;
  565. var paths = [];
  566. if ( selected_nodes.length < 1 ){
  567. mod_toastr.info( 'Please select some items first.' );
  568. } else {
  569. this.modal.disableButton( 'Import' );
  570. for ( var i = selected_nodes.length - 1; i >= 0; i-- ){
  571. if ( selected_nodes[i].li_attr.full_path !== undefined ){
  572. paths.push( selected_nodes[i].li_attr.full_path );
  573. }
  574. }
  575. this.initChainCallControl( { length: paths.length, action: 'adding_datasets' } );
  576. if ( selection_type === 'folder' ){
  577. var full_source = options.source + '_folder';
  578. this.chainCallImportingFolders( { paths: paths,
  579. preserve_dirs: preserve_dirs,
  580. link_data: link_data,
  581. source: full_source,
  582. file_type: file_type,
  583. dbkey: dbkey } );
  584. } else if ( selection_type === 'file' ){
  585. var full_source = options.source + '_file';
  586. this.chainCallImportingUserdirFiles( { paths : paths,
  587. file_type: file_type,
  588. dbkey: dbkey,
  589. source: full_source } );
  590. }
  591. }
  592. },
  593. fetchAndDisplayHistoryContents: function(history_id){
  594. var history_contents = new mod_library_model.HistoryContents({id:history_id});
  595. var self = this;
  596. history_contents.fetch({
  597. success: function(history_contents){
  598. var history_contents_template = self.templateHistoryContents();
  599. self.histories.get(history_id).set({'contents' : history_contents});
  600. self.modal.$el.find('#selected_history_content').html(history_contents_template({history_contents: history_contents.models.reverse()}));
  601. },
  602. error: function(model, response){
  603. if (typeof response.responseJSON !== "undefined"){
  604. mod_toastr.error(response.responseJSON.err_msg);
  605. } else {
  606. mod_toastr.error('An error ocurred.');
  607. }
  608. }
  609. });
  610. },
  611. /**
  612. * Import all selected datasets from history into the current folder.
  613. */
  614. addAllDatasetsFromHistory : function (){
  615. var checked_hdas = this.modal.$el.find( '#selected_history_content' ).find( ':checked' );
  616. var history_dataset_ids = [];
  617. var hdas_to_add = [];
  618. if ( checked_hdas.length < 1 ){
  619. mod_toastr.info( 'You must select some datasets first.' );
  620. } else {
  621. this.modal.disableButton( 'Add' );
  622. checked_hdas.each(function(){
  623. var hid = $( this.parentElement ).data( 'id' );
  624. if ( hid ) {
  625. history_dataset_ids.push( hid );
  626. }
  627. });
  628. for ( var i = history_dataset_ids.length - 1; i >= 0; i-- ) {
  629. history_dataset_id = history_dataset_ids[i];
  630. var folder_item = new mod_library_model.Item();
  631. folder_item.url = '/api/folders/' + this.options.id + '/contents';
  632. folder_item.set( { 'from_hda_id':history_dataset_id } );
  633. hdas_to_add.push( folder_item );
  634. }
  635. this.initChainCallControl( { length: hdas_to_add.length, action: 'adding_datasets' } );
  636. this.chainCallAddingHdas( hdas_to_add );
  637. }
  638. },
  639. /**
  640. * Take array of empty history items and make request for each of them
  641. * to create it on server. Update progress in between calls.
  642. * @param {array} history_item_set array of empty history items
  643. * @param {str} history_name name of the history to import to
  644. */
  645. chainCallImportingIntoHistory: function( history_item_set, history_name ){
  646. var self = this;
  647. var popped_item = history_item_set.pop();
  648. if ( typeof popped_item == "undefined" ) {
  649. if ( this.options.chain_call_control.failed_number === 0 ){
  650. mod_toastr.success( 'Selected datasets imported into history. Click this to start analysing it.', '', { onclick: function() { window.location='/' } } );
  651. } else if ( this.options.chain_call_control.failed_number === this.options.chain_call_control.total_number ){
  652. mod_toastr.error( 'There was an error and no datasets were imported into history.' );
  653. } else if ( this.options.chain_call_control.failed_number < this.options.chain_call_control.total_number ){
  654. mod_toastr.warning( 'Some of the datasets could not be imported into history. Click this to see what was imported.', '', { onclick: function() { window.location='/' } } );
  655. }
  656. Galaxy.modal.hide();
  657. return true;
  658. }
  659. var promise = $.when( popped_item.save( { content: popped_item.content, source: popped_item.source } ) );
  660. promise.done( function(){
  661. self.updateProgress();
  662. self.chainCallImportingIntoHistory( history_item_set, history_name );
  663. } )
  664. .fail( function(){
  665. self.options.chain_call_control.failed_number += 1;
  666. self.updateProgress();
  667. self.chainCallImportingIntoHistory( history_item_set, history_name );
  668. } );
  669. },
  670. /**
  671. * Take the array of paths and createa request for each of them
  672. * calling them in chain. Update the progress bar in between each.
  673. * @param {array} paths paths relative to user folder on Galaxy
  674. */
  675. chainCallImportingUserdirFiles: function( options ){
  676. var that = this;
  677. var popped_item = options.paths.pop();
  678. if ( typeof popped_item === "undefined" ) {
  679. if ( this.options.chain_call_control.failed_number === 0 ){
  680. mod_toastr.success( 'Selected files imported into the current folder' );
  681. Galaxy.modal.hide();
  682. } else {
  683. mod_toastr.error( 'An error occured.' );
  684. }
  685. return true;
  686. }
  687. var promise = $.when( $.post( '/api/libraries/datasets?encoded_folder_id=' + that.id +
  688. '&source=' + options.source +
  689. '&path=' + popped_item +
  690. '&file_type=' + options.file_type +
  691. '&dbkey=' + options.dbkey ) )
  692. promise.done( function( response ){
  693. that.updateProgress();
  694. that.chainCallImportingUserdirFiles( options );
  695. } )
  696. .fail( function(){
  697. that.options.chain_call_control.failed_number += 1;
  698. that.updateProgress();
  699. that.chainCallImportingUserdirFiles( options );
  700. } );
  701. },
  702. /**
  703. * Take the array of paths and createa request for each of them
  704. * calling them in chain. Update the progress bar in between each.
  705. * @param {array} paths paths relative to Galaxy root folder
  706. * @param {boolean} preserve_dirs indicates whether to preserve folder structure
  707. * @param {boolean} link_data copy files to Galaxy or link instead
  708. * @param {str} source string representing what type of folder
  709. * is the source of import
  710. */
  711. chainCallImportingFolders: function( options ){
  712. // TODO need to check which paths to call
  713. var that = this;
  714. var popped_item = options.paths.pop();
  715. if (typeof popped_item == "undefined") {
  716. if (this.options.chain_call_control.failed_number === 0){
  717. mod_toastr.success('Selected folders and their contents imported into the current folder.');
  718. Galaxy.modal.hide();
  719. } else {
  720. // TODO better error report
  721. mod_toastr.error('An error occured.');
  722. }
  723. return true;
  724. }
  725. var promise = $.when( $.post( '/api/libraries/datasets?encoded_folder_id=' + that.id +
  726. '&source=' + options.source +
  727. '&path=' + popped_item +
  728. '&preserve_dirs=' + options.preserve_dirs +
  729. '&link_data=' + options.link_data +
  730. '&file_type=' + options.file_type +
  731. '&dbkey=' + options.dbkey ) )
  732. promise.done(function(response){
  733. that.updateProgress();
  734. that.chainCallImportingFolders( options );
  735. })
  736. .fail(function(){
  737. that.options.chain_call_control.failed_number += 1;
  738. that.updateProgress();
  739. that.chainCallImportingFolders( options );
  740. });
  741. },
  742. /**
  743. * Take the array of hdas and create a request for each.
  744. * Call them in chain and update progress bar in between each.
  745. * @param {array} hdas_set array of empty hda objects
  746. */
  747. chainCallAddingHdas: function( hdas_set ){
  748. var self = this;
  749. this.added_hdas = new mod_library_model.Folder();
  750. var popped_item = hdas_set.pop();
  751. if ( typeof popped_item == "undefined" ) {
  752. if ( this.options.chain_call_control.failed_number === 0 ){
  753. mod_toastr.success( 'Selected datasets from history added to the folder' );
  754. } else if ( this.options.chain_call_control.failed_number === this.options.chain_call_control.total_number ){
  755. mod_toastr.error( 'There was an error and no datasets were added to the folder.' );
  756. } else if ( this.options.chain_call_control.failed_number < this.options.chain_call_control.total_number ){
  757. mod_toastr.warning( 'Some of the datasets could not be added to the folder' );
  758. }
  759. Galaxy.modal.hide();
  760. return this.added_hdas;
  761. }
  762. var promise = $.when( popped_item.save( { from_hda_id: popped_item.get( 'from_hda_id' ) } ) );
  763. promise.done( function( model ){
  764. Galaxy.libraries.folderListView.collection.add( model );
  765. self.updateProgress();
  766. self.chainCallAddingHdas( hdas_set );
  767. })
  768. .fail( function(){
  769. self.options.chain_call_control.failed_number += 1;
  770. self.updateProgress();
  771. self.chainCallAddingHdas( hdas_set );
  772. });
  773. },
  774. /**
  775. * Take the array of lddas, create request for each and
  776. * call them in chain. Update progress bar in between each.
  777. * @param {array} lddas_set array of lddas to delete
  778. */
  779. chainCallDeletingHdas: function( lddas_set ){
  780. var self = this;
  781. this.deleted_lddas = new mod_library_model.Folder();
  782. var popped_item = lddas_set.pop();
  783. if ( typeof popped_item === "undefined" ) {
  784. if ( this.options.chain_call_control.failed_number === 0 ){
  785. mod_toastr.success( 'Selected datasets deleted' );
  786. } else if ( this.options.chain_call_control.failed_number === this.options.chain_call_control.total_number ){
  787. mod_toastr.error( 'There was an error and no datasets were deleted.' );
  788. } else if ( this.options.chain_call_control.failed_number < this.options.chain_call_control.total_number ){
  789. mod_toastr.warning( 'Some of the datasets could not be deleted' );
  790. }
  791. Galaxy.modal.hide();
  792. return this.deleted_lddas;
  793. }
  794. var promise = $.when( popped_item.destroy() );
  795. promise.done( function( dataset ){
  796. Galaxy.libraries.folderListView.collection.remove( popped_item.id );
  797. self.updateProgress();
  798. // add the deleted dataset to collection, triggers rendering
  799. if ( Galaxy.libraries.folderListView.options.include_deleted ){
  800. var updated_dataset = new mod_library_model.Item( dataset );
  801. Galaxy.libraries.folderListView.collection.add( updated_dataset );
  802. }
  803. self.chainCallDeletingHdas( lddas_set );
  804. })
  805. .fail( function(){
  806. self.options.chain_call_control.failed_number += 1;
  807. self.updateProgress();
  808. self.chainCallDeletingHdas( lddas_set );
  809. });
  810. },
  811. /**
  812. * Handles the click on 'show deleted' checkbox
  813. */
  814. checkIncludeDeleted: function(event){
  815. if (event.target.checked){
  816. Galaxy.libraries.folderListView.fetchFolder({include_deleted: true});
  817. } else{
  818. Galaxy.libraries.folderListView.fetchFolder({include_deleted: false});
  819. }
  820. },
  821. /**
  822. * Deletes the selected datasets. Atomic. One by one.
  823. */
  824. deleteSelectedDatasets: function(){
  825. var checkedValues = $('#folder_table').find(':checked');
  826. if(checkedValues.length === 0){
  827. mod_toastr.info('You must select at least one dataset for deletion.');
  828. } else {
  829. var template = this.templateDeletingDatasetsProgressBar();
  830. this.modal = Galaxy.modal;
  831. this.modal.show({
  832. closing_events : true,
  833. title : 'Deleting selected datasets',
  834. body : template({}),
  835. buttons : {
  836. 'Close' : function() {Galaxy.modal.hide();}
  837. }
  838. });
  839. // init the control counters
  840. this.options.chain_call_control.total_number = 0;
  841. this.options.chain_call_control.failed_number = 0;
  842. var dataset_ids = [];
  843. checkedValues.each(function(){
  844. if (this.parentElement.parentElement.id !== '') {
  845. dataset_ids.push(this.parentElement.parentElement.id);
  846. }
  847. });
  848. // init the progress bar
  849. this.progressStep = 100 / dataset_ids.length;
  850. this.progress = 0;
  851. // prepare the dataset items to be added
  852. var lddas_to_delete = [];
  853. for (var i = dataset_ids.length - 1; i >= 0; i--) {
  854. var dataset = new mod_library_model.Item({id:dataset_ids[i]});
  855. lddas_to_delete.push(dataset);
  856. }
  857. this.options.chain_call_control.total_number = dataset_ids.length;
  858. // call the recursive function to call ajax one after each other (request FIFO queue)
  859. this.chainCallDeletingHdas(lddas_to_delete);
  860. }
  861. },
  862. showLibInfo: function(){
  863. var library_id = Galaxy.libraries.folderListView.folderContainer.attributes.metadata.parent_library_id;
  864. var library = null;
  865. var that = this;
  866. if (Galaxy.libraries.libraryListView !== null){
  867. library = Galaxy.libraries.libraryListView.collection.get(library_id);
  868. this.showLibInfoModal(library);
  869. } else {
  870. library = new mod_library_model.Library({id: library_id});
  871. library.fetch({
  872. success: function(){
  873. that.showLibInfoModal(library);
  874. },
  875. error: function(model, response){
  876. if (typeof response.responseJSON !== "undefined"){
  877. mod_toastr.error(response.responseJSON.err_msg);
  878. } else {
  879. mod_toastr.error('An error ocurred.');
  880. }
  881. }
  882. })
  883. }
  884. },
  885. showLibInfoModal: function(library){
  886. var template = this.templateLibInfoInModal();
  887. this.modal = Galaxy.modal;
  888. this.modal.show({
  889. closing_events : true,
  890. title : 'Library Information',
  891. body : template({library:library}),
  892. buttons : {
  893. 'Close' : function() {Galaxy.modal.hide();}
  894. }
  895. });
  896. },
  897. showImportModal: function(options){
  898. switch(options.source){
  899. case "history":
  900. this.addFilesFromHistoryModal();
  901. break;
  902. case "importdir":
  903. this.importFilesFromGalaxyFolderModal( { source: 'importdir' } );
  904. break;
  905. case "path":
  906. this.importFilesFromPathModal();
  907. break;
  908. case "userdir":
  909. this.importFilesFromGalaxyFolderModal( { source: 'userdir' } );
  910. break;
  911. default:
  912. Galaxy.libraries.library_router.back();
  913. mod_toastr.error('Invalid import source.');
  914. break;
  915. }
  916. },
  917. templateToolBar: function(){
  918. tmpl_array = [];
  919. // CONTAINER START
  920. tmpl_array.push('<div class="library_style_container">');
  921. // TOOLBAR START
  922. tmpl_array.push(' <div id="library_toolbar">');
  923. tmpl_array.push(' <span><strong>DATA LIBRARIES</strong></span>');
  924. tmpl_array.push(' <span data-toggle="tooltip" data-placement="top" class="logged-dataset-manipulation" title="Include deleted datasets" style="display:none;"> | <input id="include_deleted_datasets_chk" style="margin: 0;" type="checkbox"> include deleted | </input></span>');
  925. tmpl_array.push(' <button style="display:none;" data-toggle="tooltip" data-placement="top" title="Create New Folder" id="toolbtn_create_folder" class="btn btn-default primary-button add-library-items" type="button"><span class="fa fa-plus"></span> <span class="fa fa-folder"></span></button>');
  926. tmpl_array.push('<% if(mutiple_add_dataset_options) { %>');
  927. tmpl_array.push(' <div class="btn-group add-library-items" style="display:none;">');
  928. tmpl_array.push(' <button title="Add Datasets to Current Folder" id="" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');
  929. tmpl_array.push(' <span class="fa fa-plus"></span> <span class="fa fa-file"></span> <span class="caret"></span>');
  930. tmpl_array.push(' </button>');
  931. tmpl_array.push(' <ul class="dropdown-menu" role="menu">');
  932. tmpl_array.push(' <li><a href="#folders/<%= id %>/import/history"> from History</a></li>');
  933. tmpl_array.push('<% if(Galaxy.config.user_library_import_dir !== null) { %>');
  934. tmpl_array.push(' <li><a href="#folders/<%= id %>/import/userdir"> from User Directory</a></li>');
  935. tmpl_array.push('<% } %>');
  936. tmpl_array.push('<% if(Galaxy.config.allow_library_path_paste) { %>');
  937. tmpl_array.push(' <li class="divider"></li>');
  938. tmpl_array.push(' <li class="dropdown-header">Admins only</li>');
  939. tmpl_array.push('<% if(Galaxy.config.library_import_dir !== null) { %>');
  940. tmpl_array.push(' <li><a href="#folders/<%= id %>/import/importdir">from Import Directory</a></li>');
  941. tmpl_array.push('<% } %>');
  942. tmpl_array.push('<% if(Galaxy.config.allow_library_path_paste) { %>');
  943. tmpl_array.push(' <li><a href="#folders/<%= id %>/import/path">from Path</a></li>');
  944. tmpl_array.push('<% } %>');
  945. tmpl_array.push('<% } %>');
  946. tmpl_array.push(' </ul>');
  947. tmpl_array.push(' </div>');
  948. tmpl_array.push('<% } else { %>');
  949. tmpl_array.push(' <button style="display:none;" 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 add-library-items" type="button"><span class="fa fa-plus"></span> <span class="fa fa-file"></span></span></button>');
  950. tmpl_array.push('<% } %>');
  951. tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button dataset-manipulation" style="margin-left: 0.5em; display:none;" type="button"><span class="fa fa-book"></span> to History</button>');
  952. tmpl_array.push(' <div id="toolbtn_dl" class="btn-group dataset-manipulation" style="margin-left: 0.5em; display:none; ">');
  953. tmpl_array.push(' <button title="Download selected datasets as archive" id="drop_toggle" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');
  954. tmpl_array.push(' <span class="fa fa-download"></span> Download <span class="caret"></span>');
  955. tmpl_array.push(' </button>');
  956. tmpl_array.push(' <ul class="dropdown-menu" role="menu">');
  957. tmpl_array.push(' <li><a href="#/folders/<%= id %>/download/tgz">.tar.gz</a></li>');
  958. tmpl_array.push(' <li><a href="#/folders/<%= id %>/download/tbz">.tar.bz</a></li>');
  959. tmpl_array.push(' <li><a href="#/folders/<%= id %>/download/zip">.zip</a></li>');
  960. tmpl_array.push(' </ul>');
  961. tmpl_array.push(' </div>');
  962. tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Mark selected datasets deleted" id="toolbtn_bulk_delete" class="primary-button logged-dataset-manipulation" style="margin-left: 0.5em; display:none; " type="button"><span class="fa fa-times"></span> Delete</button>');
  963. tmpl_array.push(' <button data-id="<%- id %>" data-toggle="tooltip" data-placement="top" title="Show library information" id="toolbtn_show_libinfo" class="primary-button" style="margin-left: 0.5em;" type="button"><span class="fa fa-info-circle"></span> Library Info</button>');
  964. tmpl_array.push(' <span class="help-button" data-toggle="tooltip" data-placement="top" title="Visit Libraries Wiki"><a href="https://wiki.galaxyproject.org/DataLibraries/screen/FolderContents" target="_blank"><button class="primary-button" type="button"><span class="fa fa-question-circle"></span> Help</button></a></span>');
  965. tmpl_array.push(' </div>');
  966. // TOOLBAR END
  967. tmpl_array.push(' <div id="folder_items_element">');
  968. tmpl_array.push(' </div>');
  969. tmpl_array.push('</div>');
  970. // CONTAINER END
  971. return _.template(tmpl_array.join(''));
  972. },
  973. templateLibInfoInModal: function(){
  974. tmpl_array = [];
  975. tmpl_array.push('<div id="lif_info_modal">');
  976. tmpl_array.push('<h2>Library name:</h2>');
  977. tmpl_array.push('<p><%- library.get("name") %></p>');
  978. tmpl_array.push('<h3>Library description:</h3>');
  979. tmpl_array.push('<p><%- library.get("description") %></p>');
  980. tmpl_array.push('<h3>Library synopsis:</h3>');
  981. tmpl_array.push('<p><%- library.get("synopsis") %></p>');
  982. tmpl_array.push('</div>');
  983. return _.template(tmpl_array.join(''));
  984. },
  985. templateNewFolderInModal: function(){
  986. tmpl_array = [];
  987. tmpl_array.push('<div id="new_folder_modal">');
  988. tmpl_array.push('<form>');
  989. tmpl_array.push('<input type="text" name="Name" value="" placeholder="Name">');
  990. tmpl_array.push('<input type="text" name="Description" value="" placeholder="Description">');
  991. tmpl_array.push('</form>');
  992. tmpl_array.push('</div>');
  993. return _.template(tmpl_array.join(''));
  994. },
  995. templateBulkImportInModal : function(){
  996. var tmpl_array = [];
  997. tmpl_array.push('<span id="history_modal_combo_bulk" style="width:90%; margin-left: 1em; margin-right: 1em; ">');
  998. tmpl_array.push('Select history: ');
  999. tmpl_array.push('<select id="dataset_import_bulk" name="dataset_import_bulk" style="width:50%; margin-bottom: 1em; "> ');
  1000. tmpl_array.push(' <% _.each(histories, function(history) { %>'); //history select box
  1001. tmpl_array.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');
  1002. tmpl_array.push(' <% }); %>');
  1003. tmpl_array.push('</select>');
  1004. tmpl_array.push('</span>');
  1005. return _.template(tmpl_array.join(''));
  1006. },
  1007. templateImportIntoHistoryProgressBar : function (){
  1008. var tmpl_array = [];
  1009. tmpl_array.push('<div class="import_text">');
  1010. tmpl_array.push('Importing selected datasets to history <b><%= _.escape(history_name) %></b>');
  1011. tmpl_array.push('</div>');
  1012. tmpl_array.push('<div class="progress">');
  1013. tmpl_array.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');
  1014. tmpl_array.push(' <span class="completion_span">0% Complete</span>');
  1015. tmpl_array.push(' </div>');
  1016. tmpl_array.push('</div>');
  1017. tmpl_array.push('');
  1018. return _.template(tmpl_array.join(''));
  1019. },
  1020. templateAddingDatasetsProgressBar: function (){
  1021. var tmpl_array = [];
  1022. tmpl_array.push('<div class="import_text">');
  1023. tmpl_array.push('Adding selected datasets to library folder <b><%= _.escape(folder_name) %></b>');
  1024. tmpl_array.push('</div>');
  1025. tmpl_array.push('<div class="progress">');
  1026. tmpl_array.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');
  1027. tmpl_array.push(' <span class="completion_span">0% Complete</span>');
  1028. tmpl_array.push(' </div>');
  1029. tmpl_array.push('</div>');
  1030. tmpl_array.push('');
  1031. return _.template(tmpl_array.join(''));
  1032. },
  1033. templateDeletingDatasetsProgressBar: function (){
  1034. var tmpl_array = [];
  1035. tmpl_array.push('<div class="import_text">');
  1036. tmpl_array.push('</div>');
  1037. tmpl_array.push('<div class="progress">');
  1038. tmpl_array.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');
  1039. tmpl_array.push(' <span class="completion_span">0% Complete</span>');
  1040. tmpl_array.push(' </div>');
  1041. tmpl_array.push('</div>');
  1042. tmpl_array.push('');
  1043. return _.template(tmpl_array.join(''));
  1044. },
  1045. templateBrowserModal: function(){
  1046. var tmpl_array = [];
  1047. tmpl_array.push('<div id="file_browser_modal">');
  1048. tmpl_array.push('<div class="alert alert-info jstree-files-message">All files you select will be imported into the current folder.</div>');
  1049. tmpl_array.push('<div class="alert alert-info jstree-folders-message" style="display:none;">All files within the selected folders and their subfolders will be imported into the current folder.</div>');
  1050. tmpl_array.push('<div style="margin-bottom:1em;">');
  1051. tmpl_array.push('<label class="radio-inline">');
  1052. tmpl_array.push(' <input title="Switch to selecting files" type="radio" name="jstree-radio" value="jstree-disable-folders" checked="checked"> Files');
  1053. tmpl_array.push('</label>');
  1054. tmpl_array.push('<label class="radio-inline">');
  1055. tmpl_array.push(' <input title="Switch to selecting folders" type="radio" name="jstree-radio" value="jstree-disable-files"> Folders');
  1056. tmpl_array.push('</label>');
  1057. tmpl_array.push('</div>');
  1058. tmpl_array.push('<div style="margin-bottom:1em;">');
  1059. tmpl_array.push('<label class="checkbox-inline jstree-preserve-structure" style="display:none;">');
  1060. tmpl_array.push(' <input class="preserve-checkbox" type="checkbox" value="preserve_directory_structure">');
  1061. tmpl_array.push('Preserve directory structure');
  1062. tmpl_array.push(' </label>');
  1063. tmpl_array.push('<label class="checkbox-inline jstree-link-files" style="display:none;">');
  1064. tmpl_array.push(' <input class="link-checkbox" type="checkbox" value="link_files">');
  1065. tmpl_array.push('Link files instead of copying');
  1066. tmpl_array.push(' </label>');
  1067. tmpl_array.push('</div>');
  1068. tmpl_array.push('<div id="jstree_browser">');
  1069. tmpl_array.push('</div>');
  1070. tmpl_array.push('<hr />');
  1071. tmpl_array.push('<p>You can set extension type and genome for all imported datasets at once:</p>');
  1072. tmpl_array.push('<div>');
  1073. tmpl_array.push('Type: <span id="library_extension_select" class="library-extension-select" />');
  1074. tmpl_array.push(' Genome: <span id="library_genome_select" class="library-genome-select" />');
  1075. tmpl_array.push('</div>');
  1076. tmpl_array.push('</div>');
  1077. return _.template(tmpl_array.join(''));
  1078. },
  1079. templateImportPathModal: function(){
  1080. var tmpl_array = [];
  1081. tmpl_array.push('<div id="file_browser_modal">');
  1082. tmpl_array.push('<div class="alert alert-info jstree-folders-message">All files within the given folders and their subfolders will be imported into the current folder.</div>');
  1083. tmpl_array.push('<div style="margin-bottom: 0.5em;">');
  1084. tmpl_array.push('<label class="checkbox-inline jstree-preserve-structure">');
  1085. tmpl_array.push(' <input class="preserve-checkbox" type="checkbox" value="preserve_directory_structure">');
  1086. tmpl_array.push('Preserve directory structure');
  1087. tmpl_array.push(' </label>');
  1088. tmpl_array.push('<label class="checkbox-inline jstree-link-files">');
  1089. tmpl_array.push(' <input class="link-checkbox" type="checkbox" value="link_files">');
  1090. tmpl_array.push('Link files instead of copying');
  1091. tmpl_array.push(' </label>');
  1092. tmpl_array.push('</div>');
  1093. tmpl_array.push('<textarea id="import_paths" class="form-control" rows="5" placeholder="Absolute paths (or paths relative to Galaxy root) separated by newline"></textarea>');
  1094. tmpl_array.push('<hr />');
  1095. tmpl_array.push('<p>You can set extension type and genome for all imported datasets at once:</p>');
  1096. tmpl_array.push('<div>');
  1097. tmpl_array.push('Type: <span id="library_extension_select" class="library-extension-select" />');
  1098. tmpl_array.push(' Genome: <span id="library_genome_select" class="library-genome-…

Large files files are truncated, but you can click here to view the full file