From d197d2c17bd79901c35b3142ccac424727dd0d4f Mon Sep 17 00:00:00 2001 From: Daniel Blankenberg Date: Thu, 10 Apr 2014 13:38:44 -0400 Subject: [PATCH 01/16] Include tool version information in bug reports. --- lib/galaxy/tools/errors.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/galaxy/tools/errors.py b/lib/galaxy/tools/errors.py index 8410a7cfb4d..68e95be4187 100644 --- a/lib/galaxy/tools/errors.py +++ b/lib/galaxy/tools/errors.py @@ -28,7 +28,9 @@ ${message} ----------------------------------------------------------------------------- job id: ${job_id} tool id: ${job_tool_id} +tool version: ${tool_version} job pid or drm id: ${job_runner_external_id} +job tool version: ${job_tool_version} ----------------------------------------------------------------------------- job command line: ${job_command_line} @@ -86,7 +88,9 @@ class ErrorReporter( object ): history_item_name=hda.get_display_name(), history_view_link=history_view_link, job_id=job.id, + tool_version=job.tool_version, job_tool_id=job.tool_id, + job_tool_version=hda.tool_version, job_runner_external_id=job.job_runner_external_id, job_command_line=job.command_line, job_stderr=util.unicodify( job.stderr ), From e83208a0c15e7f857a3377dc54c608501d36d3cc Mon Sep 17 00:00:00 2001 From: Daniel Blankenberg Date: Thu, 10 Apr 2014 13:39:41 -0400 Subject: [PATCH 02/16] When posting to BioStar include a ToolShed url, as applicable. --- lib/galaxy/model/tool_shed_install/__init__.py | 8 ++++++++ lib/galaxy/util/biostar.py | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/model/tool_shed_install/__init__.py b/lib/galaxy/model/tool_shed_install/__init__.py index 980cfa53c86..76dc775cdde 100644 --- a/lib/galaxy/model/tool_shed_install/__init__.py +++ b/lib/galaxy/model/tool_shed_install/__init__.py @@ -4,6 +4,8 @@ from galaxy.model.item_attrs import Dictifiable from galaxy.util.bunch import Bunch from galaxy.util import asbool from tool_shed.util import common_util +from tool_shed.util.shed_util_common import get_url_from_tool_shed +from urlparse import urljoin log = logging.getLogger( __name__ ) @@ -73,6 +75,12 @@ class ToolShedRepository( object ): def can_reinstall_or_activate( self ): return self.deleted + def get_sharable_url( self, app ): + tool_shed_url = get_url_from_tool_shed( app, self.tool_shed ) + if tool_shed_url: + return urljoin( tool_shed_url, 'view/%s/%s' % ( self.owner, self.name ) ) + return tool_shed_url + def get_shed_config_filename( self ): shed_config_filename = None if self.metadata: diff --git a/lib/galaxy/util/biostar.py b/lib/galaxy/util/biostar.py index f7f4b3586e6..d5fea0e6501 100644 --- a/lib/galaxy/util/biostar.py +++ b/lib/galaxy/util/biostar.py @@ -86,7 +86,14 @@ def populate_tag_payload( payload=None, tool=None ): def populate_tool_payload( payload=None, tool=None ): payload = populate_tag_payload( payload=payload, tool=tool ) payload[ 'title' ] = 'Need help with "%s" tool' % ( tool.name ) - payload[ 'content' ] = '

Tool name: %s
Tool version: %s
Tool ID: %s

' % ( tool.name, tool.version, tool.id ) + tool_url = None + if tool.tool_shed_repository: + tool_url = tool.tool_shed_repository.get_sharable_url( tool.app ) + if tool_url: + tool_url = '
ToolShed URL: %s' % ( tool_url, tool_url ) + if not tool_url: + tool_url = '' + payload[ 'content' ] = '

Tool name: %s
Tool version: %s
Tool ID: %s%s


' % ( tool.name, tool.version, tool.id, tool_url ) return payload def determine_cookie_domain( galaxy_hostname, biostar_hostname ): From 2b52d39816ff110491f580bd1ae7d2d85cbafba1 Mon Sep 17 00:00:00 2001 From: Daniel Blankenberg Date: Thu, 10 Apr 2014 13:49:43 -0400 Subject: [PATCH 03/16] Change suc.get_url_from_tool_shed to common_util.get_tool_shed_url_from_tool_shed_registry. --- lib/galaxy/model/tool_shed_install/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/galaxy/model/tool_shed_install/__init__.py b/lib/galaxy/model/tool_shed_install/__init__.py index 24b07008fd3..d376f4d2e6f 100644 --- a/lib/galaxy/model/tool_shed_install/__init__.py +++ b/lib/galaxy/model/tool_shed_install/__init__.py @@ -4,7 +4,6 @@ from galaxy.model.item_attrs import Dictifiable from galaxy.util.bunch import Bunch from galaxy.util import asbool from tool_shed.util import common_util -from tool_shed.util.shed_util_common import get_url_from_tool_shed from urlparse import urljoin log = logging.getLogger( __name__ ) @@ -76,7 +75,7 @@ class ToolShedRepository( object ): return self.deleted def get_sharable_url( self, app ): - tool_shed_url = get_url_from_tool_shed( app, self.tool_shed ) + tool_shed_url = common_util.get_tool_shed_url_from_tool_shed_registry( app, self.tool_shed ) if tool_shed_url: return urljoin( tool_shed_url, 'view/%s/%s' % ( self.owner, self.name ) ) return tool_shed_url From 7da3f0a6aa309c939abd2521f65b41bc15d5bb35 Mon Sep 17 00:00:00 2001 From: Dave Bouvier Date: Thu, 10 Apr 2014 13:59:40 -0400 Subject: [PATCH 04/16] Corrected version for migrated tools. --- scripts/migrate_tools/0010_tools.xml | 52 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/scripts/migrate_tools/0010_tools.xml b/scripts/migrate_tools/0010_tools.xml index 51dacf67866..1ead6aceb24 100644 --- a/scripts/migrate_tools/0010_tools.xml +++ b/scripts/migrate_tools/0010_tools.xml @@ -3,17 +3,17 @@ - - + + - - + + - - + + - - + + @@ -24,8 +24,8 @@ - - + + @@ -36,23 +36,23 @@ - - + + - - + + - - + + - - + + @@ -63,11 +63,11 @@ - - + + - - + + @@ -93,8 +93,8 @@ - - + + @@ -135,7 +135,7 @@ - - + + \ No newline at end of file From 9b0bbb0dab8fb96f19cd46b104f6e16ced404899 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 10 Apr 2014 13:31:46 -0500 Subject: [PATCH 05/16] Remove unused variable? --- static/scripts/galaxy.workflow_editor.canvas.js | 1 - 1 file changed, 1 deletion(-) diff --git a/static/scripts/galaxy.workflow_editor.canvas.js b/static/scripts/galaxy.workflow_editor.canvas.js index 820d7f3ddef..0e3916fe8e2 100644 --- a/static/scripts/galaxy.workflow_editor.canvas.js +++ b/static/scripts/galaxy.workflow_editor.canvas.js @@ -422,7 +422,6 @@ $.extend( Node.prototype, { // Update input rows var old_body = el.find( "div.inputs" ); var new_body = $("
"); - var old = old_body.find( "div.input-data-row"); $.each( data.data_inputs, function( i, input ) { var t = node.new_input_terminal( input ); // If already connected save old connection From 69ddb385577b7d2a0f1417d07d2195e8785bc3ca Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 10 Apr 2014 13:31:47 -0500 Subject: [PATCH 06/16] Refactor interaction between workflows JS and editor JS for adding nodes. Add abstraction into editor for use by galaxy.workflow.js to hide some editor details from workflow code and reduce duplication between add_node_for_tool and add_node_for_module. --- static/scripts/galaxy.workflow_editor.canvas.js | 12 ++++++++++++ static/scripts/galaxy.workflows.js | 12 ++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/static/scripts/galaxy.workflow_editor.canvas.js b/static/scripts/galaxy.workflow_editor.canvas.js index 0e3916fe8e2..f7e1d3f2d79 100644 --- a/static/scripts/galaxy.workflow_editor.canvas.js +++ b/static/scripts/galaxy.workflow_editor.canvas.js @@ -892,6 +892,18 @@ function prebuild_node( type, title_text, tool_id ) { return node; } +function add_node( type, title_text, tool_id ) { + // Abstraction for use by galaxy.workflow.js to hide + // some editor details from workflow code and reduce duplication + // between add_node_for_tool and add_node_for_module. + var node = prebuild_node( type, title_text, tool_id ); + workflow.add_node( node ); + workflow.fit_canvas_to_nodes(); + canvas_manager.draw_overview(); + workflow.activate_node( node ); + return node; +} + var ext_to_type = null; var type_to_type = null; diff --git a/static/scripts/galaxy.workflows.js b/static/scripts/galaxy.workflows.js index 8a027621665..3dce5a6bfaa 100644 --- a/static/scripts/galaxy.workflows.js +++ b/static/scripts/galaxy.workflows.js @@ -320,11 +320,7 @@ function scroll_to_nodes() { // Add a new step to the workflow by tool id function add_node_for_tool( id, title ) { - var node = prebuild_node( 'tool', title, id ); - workflow.add_node( node ); - workflow.fit_canvas_to_nodes(); - canvas_manager.draw_overview(); - workflow.activate_node( node ); + node = add_node( 'tool', title, id ); $.ajax( { url: get_new_module_info_url, data: { type: "tool", tool_id: id, "_": "true" }, @@ -344,11 +340,7 @@ function add_node_for_tool( id, title ) { } function add_node_for_module( type, title ) { - node = prebuild_node( type, title ); - workflow.add_node( node ); - workflow.fit_canvas_to_nodes(); - canvas_manager.draw_overview(); - workflow.activate_node( node ); + node = add_node( type, title ); $.ajax( { url: get_new_module_info_url, data: { type: type, "_": "true" }, From 7b2c20cc46915dec4b97aa98413d47e2a5f74236 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 10 Apr 2014 13:31:48 -0500 Subject: [PATCH 07/16] Outline workflow editor tests. --- test/qunit/tests/workflow_editor_tests.html | 10 + test/qunit/tests/workflow_editor_tests.js | 379 ++++++++++++++++++++ 2 files changed, 389 insertions(+) create mode 100644 test/qunit/tests/workflow_editor_tests.html create mode 100644 test/qunit/tests/workflow_editor_tests.js diff --git a/test/qunit/tests/workflow_editor_tests.html b/test/qunit/tests/workflow_editor_tests.html new file mode 100644 index 00000000000..00e97f6ea8c --- /dev/null +++ b/test/qunit/tests/workflow_editor_tests.html @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/test/qunit/tests/workflow_editor_tests.js b/test/qunit/tests/workflow_editor_tests.js new file mode 100644 index 00000000000..e065c1125de --- /dev/null +++ b/test/qunit/tests/workflow_editor_tests.js @@ -0,0 +1,379 @@ +/* global define, QUnit, module, test, ok, equal, deepEqual, notEqual */ +/* global Workflow, CanvasManager, InputTerminal, Connector, add_node */ +define([ + "galaxy.workflow_editor.canvas", + "jquery", + "sinon-qunit" +], function( + workflowEditor, + $, + sinon +){ + "use strict"; + + // globals cosumed by workflow editor + window.show_form_for_tool = sinon.spy(); + 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; + } + }); + + var with_canvas_container = function( f ) { + var canvas_container = $("
"); + $("body").append( canvas_container ); + f( canvas_container ); + canvas_container.remove(); + }; + + var with_workflow_global = function( f ) { + var overview = $( "
" ); + var canvas_viewport = $( "
" ); + + $("body").append( overview, canvas_viewport ); + window.canvas_manager = new CanvasManager( canvas_viewport, overview ); + with_canvas_container( function( canvas_container ) { + window.workflow = new Workflow( canvas_container ); + f( window.workflow ); + window.workflow = null; + } ); + window.canvas_manager = null; + overview.remove(); + canvas_viewport.remove(); + }; + + module( "Input terminal model test", { + setup: function() { + this.node = { }; + this.element = $( "
" ); + this.input_terminal = new InputTerminal( this.element, [ "txt" ] ); + this.input_terminal.node = this.node; + }, + test_connector: function( attr ) { + var connector = attr || {}; + this.input_terminal.connectors.push( connector ); + return connector; + }, + with_test_connector: function( attr, f ) { + this.test_connector( attr ); + f(); + this.reset_connectors(); + }, + reset_connectors: function( ) { + this.input_terminal.connectors = []; + }, + test_accept: function( other ) { + other = other || { node: {}, datatypes: [ "txt" ] }; + return this.input_terminal.can_accept( other ); + } + } ); + + test( "test connect", function() { + this.node.changed = sinon.spy(); + + var connector = {}; + this.input_terminal.connect( connector ); + + // Assert node changed called + ok( this.node.changed.called ); + // Assert connectors updated + ok( this.input_terminal.connectors[ 0 ] === connector ); + } ); + + test( "test disconnect", function() { + this.node.changed = sinon.spy(); + + var connector = this.test_connector( {} ); + this.input_terminal.disconnect( connector ); + + // Assert node changed called + ok( this.node.changed.called ); + // Assert connectors updated + equal( this.input_terminal.connectors.length, 0 ); + } ); + + test( "test redraw", function() { + var connector = this.test_connector( { redraw: sinon.spy() } ); + this.input_terminal.redraw(); + // Assert connectors were redrawn + ok( connector.redraw.called ); + } ); + + test( "test destroy", function() { + var connector = this.test_connector( { destroy: sinon.spy() } ); + + this.input_terminal.destroy(); + // Assert connectors were redrawn + ok( connector.destroy.called ); + } ); + + test( "can accept correct datatype", function() { + issubtypeStub.returns(true); + ok( this.test_accept() ) ; + } ); + + test( "cannot accept incorrect datatypes", function() { + issubtypeStub.returns(false); + ok( ! this.test_accept() ); + } ); + + 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" ] }; + ok( this.test_accept( other ) ); + } ); + + 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() { + ok( ! self.test_accept() ); + } ); + } ); + + module( "Connector test", { + + } ); + + test( "connects only if both valid handles", function() { + var input = { connect: sinon.spy() }; + var output = { connect: sinon.spy() }; + new Connector( input, null ); + new Connector( null, output ); + // Not attempts to connect... + ok( ! input.connect.called ); + ok( ! output.connect.called ); + + new Connector( input, output ); + ok( input.connect.called ); + ok( output.connect.called ); + }); + + test( "default attributes", function() { + var input = { connect: sinon.spy() }; + var output = { connect: sinon.spy() }; + var connector = new Connector( input, output ); + + equal( connector.dragging, false ); + equal( connector.canvas, null ); + equal( connector.inner_color, "#FFFFFF" ); + equal( connector.outer_color, "#D8B365" ); + } ); + + test( "destroy", function() { + var input = { connect: sinon.spy(), disconnect: sinon.spy() }; + var output = { connect: sinon.spy(), disconnect: sinon.spy() }; + var connector = new Connector( input, output ); + + connector.destroy(); + ok( input.disconnect.called ); + ok( output.disconnect.called ); + } ); + + test( "initial redraw", function() { + with_canvas_container( function( canvas_container ) { + var input = { connect: sinon.spy(), element: $("
") }; + var output = { connect: sinon.spy(), element: $("
") }; + var connector = new Connector( input, output ); + + connector.redraw(); + // Ensure canvas gets set + ok( connector.canvas ); + // Ensure it gest added to canvas container + equal( canvas_container.children()[ 0 ], connector.canvas ); + } ); + } ); + + module( "Node unit test", { + setup: function() { + this.input_terminal = { destroy: sinon.spy(), redraw: sinon.spy() }; + this.output_terminal = { destroy: sinon.spy(), redraw: sinon.spy() }; + this.element = $("
"); + this.node = new Node( this.element ); + this.node.input_terminals.i1 = this.input_terminal; + this.node.output_terminals.o1 = this.output_terminal; + }, + $: function( selector ) { + return $( this.node.element.find( selector ) ); + }, + expect_workflow_node_changed: function( f ) { + var node = this.node; + with_workflow_global( function( workflow ) { + var node_changed_spy = sinon.spy( workflow, "node_changed" ); + f(); + ok( node_changed_spy.calledWith( node ) ); + } ); + }, + init_field_data_simple: function() { + var data = { + data_inputs: [ {name: "input1", extensions: [ "data" ] } ], + data_outputs: [ {name: "output1", extensions: [ "data" ] } ], + }; + this.node.init_field_data( data ); + }, + update_field_data_with_new_input: function() { + var new_data = { + data_inputs: [ + { name: "input1", extensions: [ "data" ] }, + { name: "extra_0|input1", extensions: [ "data" ] }, + ], + data_outputs: [ {name: "output1", extensions: [ "data" ] } ], + post_job_actions: "{}" + }; + this.node.update_field_data( new_data ); + } + } ); + + test( "make active", function() { + ok( ! this.element.hasClass( "toolForm-active" ) ); + this.node.make_active(); + ok( this.element.hasClass( "toolForm-active" ) ); + } ); + + test( "destroy", function() { + var test = this; + with_workflow_global( function( workflow ) { + var remove_node_spy = sinon.spy( workflow, "remove_node" ); + test.node.destroy(); + ok( test.input_terminal.destroy.called ); + ok( test.output_terminal.destroy.called ); + ok( remove_node_spy.calledWith( test.node ) ); + } ); + } ); + + test( "error", function() { + // Test body of toolFormBody div updated and workflow notified of change. + var test = this; + this.expect_workflow_node_changed( function() { + test.node.error( "TOOL ERROR" ); + equal( $( test.$(".toolFormBody").children()[ 0 ] ).html(), "TOOL ERROR" ); + } ); + } ); + + test( "init_field_data properties", function() { + var node = this.node; + this.expect_workflow_node_changed( function( ) { + var data = { + data_inputs: [], + data_outputs: [], + type: "tool", + name: "cat1", + form_html: "
", + tool_state: "ok", + tool_errors: false, + tooltip: "tool tooltip", + annotation: "tool annotation", + workflow_outputs: [ "out1" ], + }; + node.init_field_data( data ); + equal( node.type, "tool" ); + equal( node.name, "cat1" ); + equal( node.form_html, "" ); + equal( node.tool_state, "ok" ); + equal( node.tooltip, "tool tooltip" ); + equal( node.annotation, "tool annotation" ); + deepEqual( node.post_job_actions, {} ); + deepEqual( node.workflow_outputs, [ "out1" ] ); + } ); + } ); + + test( "init_field_data data", function() { + var test = this; + this.expect_workflow_node_changed( function( ) { + // pre-init not tool form body... + equal( test.$( ".output-terminal" ).length, 0 ); + equal( test.$( ".input-terminal" ).length, 0 ); + equal( test.$( ".rule" ).length, 0 ); + + test.init_field_data_simple(); + + // After init tool form should have three "rows"/divs - , inputs div, one output, and rule... + equal( test.$( ".output-terminal" ).length, 1 ); + equal( test.$( ".input-terminal" ).length, 1 ); + equal( test.$( ".rule" ).length, 1 ); + + equal( test.$( ".toolFormBody" ).children().length, 3 ); + } ); + } ); + + test( "update_field_data updated data inputs and outputs", function() { + var test = this; + this.expect_workflow_node_changed( function( ) { + // Call init with one input and output. + test.init_field_data_simple(); + + test.update_field_data_with_new_input(); + + // Now there are 2 inputs... + equal( test.$( ".input-terminal" ).length, 2 ); + equal( test.$( ".output-terminal" ).length, 1 ); + equal( test.$( ".rule" ).length, 1 ); + } ); + } ); + + test( "update_field_data preserves connectors", function() { + var test = this; + var node = this.node; + this.expect_workflow_node_changed( function( ) { + // Call init with one input and output. + test.init_field_data_simple(); + + var connector = new Connector(); + var old_input_terminal = node.input_terminals.input1; + old_input_terminal.connectors.push( connector ); + + test.update_field_data_with_new_input(); + + var new_input_terminal = node.input_terminals.input1; + equal( old_input_terminal, old_input_terminal ); + notEqual( old_input_terminal, new_input_terminal ); + equal( connector, new_input_terminal.connectors[ 0 ] ); + } ); + } ); + + test( "update_field_data destroys old terminals", function() { + var test = this; + var node = this.node; + this.expect_workflow_node_changed( function( ) { + var data = { + data_inputs: [ { name: "input1", extensions: [ "data" ] }, + { name: "willDisappear", extensions: [ "data" ] } ], + data_outputs: [ {name: "output1", extensions: [ "data" ] } ], + }; + node.init_field_data( data ); + + var old_input_terminal = node.input_terminals.willDisappear; + var destroy_spy = sinon.spy( old_input_terminal, "destroy" ); + // Update + test.update_field_data_with_new_input(); + + ok( destroy_spy.called ); + } ); + } ); + + module( "add_node" ); + + test( "node added to workflow", function() { + with_workflow_global( function( workflow ) { + var add_node_spy = sinon.spy( workflow, "add_node" ); + var node = add_node( "tool", "Cat Files", "cat1" ); + ok( add_node_spy.calledWith( node ) ); + } ); + } ); + +}); \ No newline at end of file From 86ee4fdabfaf431d0263ae3921424f8e80d63fde Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 10 Apr 2014 13:31:48 -0500 Subject: [PATCH 08/16] Simplify enable_output_terminal and enable_output_terminal in workflow editor. These functions were taking in a single element and then looping through it. I hope this is not some intententional jQuery pattern to change the value of 'this' I don't quite understand and is just a remnant of when some loop over inputs was on the inside of this function or some other such refactoring. --- .../scripts/galaxy.workflow_editor.canvas.js | 177 +++++++++--------- 1 file changed, 87 insertions(+), 90 deletions(-) diff --git a/static/scripts/galaxy.workflow_editor.canvas.js b/static/scripts/galaxy.workflow_editor.canvas.js index f7e1d3f2d79..c0c9f5b6afe 100644 --- a/static/scripts/galaxy.workflow_editor.canvas.js +++ b/static/scripts/galaxy.workflow_editor.canvas.js @@ -172,101 +172,98 @@ function Node( element ) { } $.extend( Node.prototype, { new_input_terminal : function( input ) { - var t = $("
"); + var t = $("
")[ 0 ]; this.enable_input_terminal( t, input.name, input.extensions, input.multiple ); return t; }, - enable_input_terminal : function( elements, name, types, multiple ) { + enable_input_terminal : function( element, name, types, multiple ) { var node = this; - $(elements).each( function() { - var terminal = this.terminal = new InputTerminal( this, types, multiple ); - terminal.node = node; - terminal.name = name; - $(this).bind( "dropinit", function( e, d ) { - // 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 ); - }).bind( "dropstart", function( e, d ) { - if (d.proxy.terminal) { - d.proxy.terminal.connectors[0].inner_color = "#BBFFBB"; - } - }).bind( "dropend", function ( e, d ) { - if (d.proxy.terminal) { - d.proxy.terminal.connectors[0].inner_color = "#FFFFFF"; - } - }).bind( "drop", function( e, d ) { - ( new Connector( d.drag.terminal, terminal ) ).redraw(); - }).bind( "hover", function() { - // If connected, create a popup to allow disconnection - if ( terminal.connectors.length > 0 ) { - // Create callout - var t = $("
") - .css( { display: 'none' } ) - .appendTo( "body" ) - .append( - $("
").append( - $("
").addClass("fa-icon-button fa fa-times").click( function() { - $.each( terminal.connectors, function( _, x ) { - if (x) { - x.destroy(); - } - }); - t.remove(); - }))) - .bind( "mouseleave", function() { - $(this).remove(); - }); - // Position it and show - t.css({ - top: $(this).offset().top - 2, - left: $(this).offset().left - t.width(), - 'padding-right': $(this).width() - }).show(); - } - }); - node.input_terminals[name] = terminal; + + var terminal = element.terminal = new InputTerminal( element, types, multiple ); + terminal.node = node; + terminal.name = name; + $(element).bind( "dropinit", function( e, d ) { + // 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 ); + }).bind( "dropstart", function( e, d ) { + if (d.proxy.terminal) { + d.proxy.terminal.connectors[0].inner_color = "#BBFFBB"; + } + }).bind( "dropend", function ( e, d ) { + if (d.proxy.terminal) { + d.proxy.terminal.connectors[0].inner_color = "#FFFFFF"; + } + }).bind( "drop", function( e, d ) { + ( new Connector( d.drag.terminal, terminal ) ).redraw(); + }).bind( "hover", function() { + // If connected, create a popup to allow disconnection + if ( terminal.connectors.length > 0 ) { + // Create callout + var t = $("
") + .css( { display: 'none' } ) + .appendTo( "body" ) + .append( + $("
").append( + $("
").addClass("fa-icon-button fa fa-times").click( function() { + $.each( terminal.connectors, function( _, x ) { + if (x) { + x.destroy(); + } + }); + t.remove(); + }))) + .bind( "mouseleave", function() { + $(this).remove(); + }); + // Position it and show + t.css({ + top: $(element).offset().top - 2, + left: $(element).offset().left - t.width(), + 'padding-right': $(element).width() + }).show(); + } }); + node.input_terminals[name] = terminal; }, - enable_output_terminal : function( elements, name, type ) { + enable_output_terminal : function( element, name, type ) { var node = this; - $(elements).each( function() { - var terminal_element = this; - var terminal = this.terminal = new OutputTerminal( this, type ); - terminal.node = node; - terminal.name = name; - $(this).bind( "dragstart", function( e, d ) { - $( d.available ).addClass( "input-terminal-active" ); - // Save PJAs in the case of change datatype actions. - workflow.check_changes_in_active_form(); - // Drag proxy div - var h = $( '
' ) - .appendTo( "#canvas-container" ).get(0); - // Terminal and connection to display noodle while dragging - h.terminal = new OutputTerminal( h ); - var c = new Connector(); - c.dragging = true; - c.connect( this.terminal, h.terminal ); - return h; - }).bind( "drag", function ( e, d ) { - var onmove = function() { - var po = $(d.proxy).offsetParent().offset(), - x = d.offsetX - po.left, - y = d.offsetY - po.top; - $(d.proxy).css( { left: x, top: y } ); - d.proxy.terminal.redraw(); - // FIXME: global - canvas_manager.update_viewport_overlay(); - }; - onmove(); - $("#canvas-container").get(0).scroll_panel.test( e, onmove ); - }).bind( "dragend", function ( e, d ) { - d.proxy.terminal.connectors[0].destroy(); - $(d.proxy).remove(); - $( d.available ).removeClass( "input-terminal-active" ); - $("#canvas-container").get(0).scroll_panel.stop(); - }); - node.output_terminals[name] = terminal; + var terminal_element = element; + var terminal = element.terminal = new OutputTerminal( element, type ); + terminal.node = node; + terminal.name = name; + $(element).bind( "dragstart", function( e, d ) { + $( d.available ).addClass( "input-terminal-active" ); + // Save PJAs in the case of change datatype actions. + workflow.check_changes_in_active_form(); + // Drag proxy div + var h = $( '
' ) + .appendTo( "#canvas-container" ).get(0); + // Terminal and connection to display noodle while dragging + h.terminal = new OutputTerminal( h ); + var c = new Connector(); + c.dragging = true; + c.connect( element.terminal, h.terminal ); + return h; + }).bind( "drag", function ( e, d ) { + var onmove = function() { + var po = $(d.proxy).offsetParent().offset(), + x = d.offsetX - po.left, + y = d.offsetY - po.top; + $(d.proxy).css( { left: x, top: y } ); + d.proxy.terminal.redraw(); + // FIXME: global + canvas_manager.update_viewport_overlay(); + }; + onmove(); + $("#canvas-container").get(0).scroll_panel.test( e, onmove ); + }).bind( "dragend", function ( e, d ) { + d.proxy.terminal.connectors[0].destroy(); + $(d.proxy).remove(); + $( d.available ).removeClass( "input-terminal-active" ); + $("#canvas-container").get(0).scroll_panel.stop(); }); + node.output_terminals[name] = terminal; }, redraw : function () { $.each( this.input_terminals, function( _, t ) { @@ -342,7 +339,7 @@ $.extend( Node.prototype, { } $.each( data.data_outputs, function( i, output ) { var t = $( "
" ); - node.enable_output_terminal( t, output.name, output.extensions ); + node.enable_output_terminal( t[ 0 ], output.name, output.extensions ); var label = output.name; if ( output.extensions.indexOf( 'input' ) < 0 ) { label = label + " (" + output.extensions.join(", ") + ")"; @@ -429,8 +426,8 @@ $.extend( Node.prototype, { $(this).find( ".input-terminal" ).each( function() { var c = this.terminal.connectors[0]; if ( c ) { - t[0].terminal.connectors[0] = c; - c.handle2 = t[0].terminal; + t.terminal.connectors[0] = c; + c.handle2 = t.terminal; } }); $(this).remove(); From 0dd3187401e28551bf73bb6081960783d5722b69 Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Thu, 10 Apr 2014 15:05:33 -0400 Subject: [PATCH 09/16] data libraries: API refactoring and improvements; backbone decoupling; role UI first implementation --- .../webapps/galaxy/api/folder_contents.py | 147 ++-- lib/galaxy/webapps/galaxy/api/folders.py | 11 +- lib/galaxy/webapps/galaxy/api/libraries.py | 14 +- .../webapps/galaxy/api/library_contents.py | 3 +- static/scripts/galaxy.library.js | 40 +- .../mvc/library/library-folderlist-view.js | 761 ++++-------------- .../mvc/library/library-librarylist-view.js | 45 +- .../mvc/library/library-libraryrow-view.js | 25 +- .../library/library-librarytoolbar-view.js | 26 +- static/scripts/mvc/library/library-model.js | 10 +- static/scripts/packed/galaxy.library.js | 2 +- .../mvc/library/library-folderlist-view.js | 2 +- .../mvc/library/library-librarylist-view.js | 2 +- .../mvc/library/library-libraryrow-view.js | 2 +- .../library/library-librarytoolbar-view.js | 2 +- .../packed/mvc/library/library-model.js | 2 +- static/style/blue/base.css | 1 + static/style/blue/library.css | 1 + static/style/src/less/library.less | 6 + 19 files changed, 329 insertions(+), 773 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/folder_contents.py b/lib/galaxy/webapps/galaxy/api/folder_contents.py index bad6f8ce18d..0725bd2c096 100644 --- a/lib/galaxy/webapps/galaxy/api/folder_contents.py +++ b/lib/galaxy/webapps/galaxy/api/folder_contents.py @@ -1,13 +1,16 @@ """ -API operations on the contents of a folder. +API operations on the contents of a library folder. """ -import logging, os, string, shutil, urllib, re, socket -from cgi import escape, FieldStorage -from galaxy import util, datatypes, jobs, web, util -from galaxy.web.base.controller import * -from galaxy.util.sanitize_html import sanitize_html -from galaxy.model.orm import * +from galaxy import util +from galaxy import web +from galaxy import exceptions +from galaxy.web import _future_expose_api as expose_api +from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous +from sqlalchemy.orm.exc import MultipleResultsFound +from sqlalchemy.orm.exc import NoResultFound +from galaxy.web.base.controller import BaseAPIController, UsesLibraryMixin, UsesLibraryMixinItems +import logging log = logging.getLogger( __name__ ) class FolderContentsController( BaseAPIController, UsesLibraryMixin, UsesLibraryMixinItems ): @@ -15,65 +18,60 @@ class FolderContentsController( BaseAPIController, UsesLibraryMixin, UsesLibrary Class controls retrieval, creation and updating of folder contents. """ - def load_folder_contents( self, trans, folder ): - """ - Loads all contents of the folder (folders and data sets) but only in the first level. - """ - current_user_roles = trans.get_current_user_roles() - is_admin = trans.user_is_admin() - content_items = [] - for subfolder in folder.active_folders: - if not is_admin: - can_access, folder_ids = trans.app.security_agent.check_folder_contents( trans.user, current_user_roles, subfolder ) - if (is_admin or can_access) and not subfolder.deleted: - subfolder.api_type = 'folder' - content_items.append( subfolder ) - for dataset in folder.datasets: - if not is_admin: - can_access = trans.app.security_agent.can_access_dataset( current_user_roles, dataset.library_dataset_dataset_association.dataset ) - if (is_admin or can_access) and not dataset.deleted: - dataset.api_type = 'file' - content_items.append( dataset ) - return content_items - - @web.expose_api + @expose_api_anonymous def index( self, trans, folder_id, **kwd ): """ GET /api/folders/{encoded_folder_id}/contents Displays a collection (list) of a folder's contents (files and folders). Encoded folder ID is prepended with 'F' if it is a folder as opposed to a data set which does not have it. - Full path is provided as a separate object in response providing data for breadcrumb path building. + Full path is provided in response as a separate object providing data for breadcrumb path building. """ - folder_container = [] - current_user_roles = trans.get_current_user_roles() - if ( folder_id.startswith( 'F' ) ): + if ( len( folder_id ) == 17 and folder_id.startswith( 'F' ) ): try: - decoded_folder_id = trans.security.decode_id( folder_id[1:] ) + decoded_folder_id = trans.security.decode_id( folder_id[ 1: ] ) except TypeError: - trans.response.status = 400 - return "Malformed folder id ( %s ) specified, unable to decode." % str( folder_id ) + raise exceptions.MalformedId( 'Malformed folder id ( %s ) specified, unable to decode.' % str( folder_id ) ) + else: + raise exceptions.MalformedId( 'Malformed folder id ( %s ) specified, unable to decode.' % str( folder_id ) ) try: - folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( decoded_folder_id ) - except: - folder = None - log.error( "FolderContentsController.index: Unable to retrieve folder with ID: %s" % folder_id ) + folder = trans.sa_session.query( trans.app.model.LibraryFolder ).filter( trans.app.model.LibraryFolder.table.c.id == decoded_folder_id ).one() + except MultipleResultsFound: + raise exceptions.InconsistentDatabase( 'Multiple folders with same id found.' ) + except NoResultFound: + raise exceptions.ObjectNotFound( 'Folder with the id provided ( %s ) was not found' % str( folder_id ) ) + except Exception: + raise exceptions.InternalServerError( 'Error loading from the database.' ) + + current_user_roles = trans.get_current_user_roles() + can_add_library_item = trans.user_is_admin() or trans.app.security_agent.can_add_library_item( current_user_roles, folder ) - # We didn't find the folder or user does not have an access to it. - if not folder: - trans.response.status = 400 - return "Invalid folder id ( %s ) specified." % str( folder_id ) - if not ( trans.user_is_admin() or trans.app.security_agent.can_access_library_item( current_user_roles, folder, trans.user ) ): - log.warning( "SECURITY: User (id: %s) without proper access rights is trying to load folder with ID of %s" % ( trans.user.id, folder.id ) ) - trans.response.status = 400 - return "Invalid folder id ( %s ) specified." % str( folder_id ) + if folder.parent_id == None: + try: + library = trans.sa_session.query( trans.app.model.Library ).filter( trans.app.model.Library.table.c.root_folder_id == decoded_folder_id ).one() + except Exception: + raise exceptions.InternalServerError( 'Error loading from the database.' ) + if trans.app.security_agent.library_is_public( library, contents=False ): + pass + else: + if trans.user: + log.warning( "SECURITY: User (id: %s) without proper access rights is trying to load folder with ID of %s" % ( trans.user.id, decoded_folder_id ) ) + else: + log.warning( "SECURITY: Anonymous user without proper access rights is trying to load folder with ID of %s" % ( decoded_folder_id ) ) + raise exceptions.ObjectNotFound( 'Folder with the id provided ( %s ) was not found' % str( folder_id ) ) + else: + if trans.user: + log.warning( "SECURITY: User (id: %s) without proper access rights is trying to load folder with ID of %s" % ( trans.user.id, decoded_folder_id ) ) + else: + log.warning( "SECURITY: Anonymous user without proper access rights is trying to load folder with ID of %s" % ( decoded_folder_id ) ) + raise exceptions.ObjectNotFound( 'Folder with the id provided ( %s ) was not found' % str( folder_id ) ) path_to_root = [] def build_path ( folder ): """ - Search the path upwards recursively and load the whole route of names and ids for breadcrumb purposes. + Search the path upwards recursively and load the whole route of names and ids for breadcrumb building purposes. """ path_to_root = [] # We are almost in root @@ -88,13 +86,13 @@ class FolderContentsController( BaseAPIController, UsesLibraryMixin, UsesLibrary # Return the reversed path so it starts with the library node. full_path = build_path( folder )[::-1] - folder_container.append( dict( full_path = full_path ) ) + folder_contents = [] time_updated = '' time_created = '' # Go through every item in the folder and include its meta-data. - for content_item in self.load_folder_contents( trans, folder ): + for content_item in self._load_folder_contents( trans, folder ): return_item = {} encoded_id = trans.security.encode_id( content_item.id ) time_updated = content_item.update_time.strftime( "%Y-%m-%d %I:%M %p" ) @@ -122,16 +120,36 @@ class FolderContentsController( BaseAPIController, UsesLibraryMixin, UsesLibrary time_created = time_created ) ) folder_contents.append( return_item ) - # Put the data in the container - folder_container.append( dict( folder_contents = folder_contents ) ) - return folder_container + + return { 'metadata' : { 'full_path' : full_path, 'can_add_library_item': can_add_library_item }, 'folder_contents' : folder_contents } + + def _load_folder_contents( self, trans, folder ): + """ + Loads all contents of the folder (folders and data sets) but only in the first level. + """ + current_user_roles = trans.get_current_user_roles() + is_admin = trans.user_is_admin() + content_items = [] + for subfolder in folder.active_folders: + if not is_admin: + can_access, folder_ids = trans.app.security_agent.check_folder_contents( trans.user, current_user_roles, subfolder ) + if (is_admin or can_access) and not subfolder.deleted: + subfolder.api_type = 'folder' + content_items.append( subfolder ) + for dataset in folder.datasets: + if not is_admin: + can_access = trans.app.security_agent.can_access_dataset( current_user_roles, dataset.library_dataset_dataset_association.dataset ) + if (is_admin or can_access) and not dataset.deleted: + dataset.api_type = 'file' + content_items.append( dataset ) + return content_items @web.expose_api def show( self, trans, id, library_id, **kwd ): """ GET /api/folders/{encoded_folder_id}/ """ - pass + raise exceptions.NotImplemented( 'Showing the library folder content is not implemented.' ) @web.expose_api def create( self, trans, library_id, payload, **kwd ): @@ -140,20 +158,21 @@ class FolderContentsController( BaseAPIController, UsesLibraryMixin, UsesLibrary Creates a new folder. This should be superseded by the LibraryController. """ - pass + raise exceptions.NotImplemented( 'Creating the library folder content is not implemented.' ) @web.expose_api def update( self, trans, id, library_id, payload, **kwd ): """ PUT /api/folders/{encoded_folder_id}/contents """ - pass + raise exceptions.NotImplemented( 'Updating the library folder content is not implemented.' ) # TODO: Move to library_common. - def __decode_library_content_id( self, trans, content_id ): - if ( len( content_id ) % 16 == 0 ): - return 'LibraryDataset', content_id - elif ( content_id.startswith( 'F' ) ): - return 'LibraryFolder', content_id[1:] - else: - raise HTTPBadRequest( 'Malformed library content id ( %s ) specified, unable to decode.' % str( content_id ) ) + # def __decode_library_content_id( self, trans, content_id ): + # if ( len( content_id ) % 16 == 0 ): + # return 'LibraryDataset', content_id + # elif ( content_id.startswith( 'F' ) ): + # return 'LibraryFolder', content_id[1:] + # else: + # raise HTTPBadRequest( 'Malformed library content id ( %s ) specified, unable to decode.' % str( content_id ) ) + diff --git a/lib/galaxy/webapps/galaxy/api/folders.py b/lib/galaxy/webapps/galaxy/api/folders.py index 6c086334326..e9bec4529d9 100644 --- a/lib/galaxy/webapps/galaxy/api/folders.py +++ b/lib/galaxy/webapps/galaxy/api/folders.py @@ -1,14 +1,17 @@ """ -API operations on folders +API operations on library folders """ -import logging, os, string, shutil, urllib, re, socket, traceback +import os, string, shutil, urllib, re, socket, traceback from galaxy import datatypes, jobs, web, security +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 +import logging log = logging.getLogger( __name__ ) class FoldersController( BaseAPIController, UsesLibraryMixin, UsesLibraryMixinItems ): @@ -18,9 +21,9 @@ class FoldersController( BaseAPIController, UsesLibraryMixin, UsesLibraryMixinIt """ GET /api/folders/ This would normally display a list of folders. However, that would - be across multiple libraries, so it's not implemented yet. + be across multiple libraries, so it's not implemented. """ - pass + raise exceptions.NotImplemented( 'Listing all accessible library folders is not implemented.' ) @web.expose_api def show( self, trans, id, **kwd ): diff --git a/lib/galaxy/webapps/galaxy/api/libraries.py b/lib/galaxy/webapps/galaxy/api/libraries.py index afd0da5397d..c29b5d11a82 100644 --- a/lib/galaxy/webapps/galaxy/api/libraries.py +++ b/lib/galaxy/webapps/galaxy/api/libraries.py @@ -7,7 +7,7 @@ from galaxy import exceptions from galaxy.web import _future_expose_api as expose_api from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous from galaxy.model.orm import and_, not_, or_ -from galaxy.web.base.controller import BaseAPIController, url_for +from galaxy.web.base.controller import BaseAPIController import logging log = logging.getLogger( __name__ ) @@ -61,7 +61,6 @@ class LibrariesController( BaseAPIController ): if trans.app.security_agent.library_is_public( library, contents=False ): item[ 'public' ] = True current_user_roles = trans.get_current_user_roles() - # can_user_add = trans.app.security_agent.can_add_library_item( current_user_roles, library.root_folder ) if not trans.user_is_admin(): item['can_user_add'] = trans.app.security_agent.can_add_library_item( current_user_roles, library ) item['can_user_modify'] = trans.app.security_agent.can_modify_library_item( current_user_roles, library ) @@ -98,7 +97,7 @@ class LibrariesController( BaseAPIController ): deleted = util.string_as_bool( deleted ) try: decoded_library_id = trans.security.decode_id( library_id ) - except Exception: + except TypeError: raise exceptions.MalformedId( 'Malformed library id ( %s ) specified, unable to decode.' % id ) try: library = trans.sa_session.query( trans.app.model.Library ).get( decoded_library_id ) @@ -144,7 +143,14 @@ class LibrariesController( BaseAPIController ): library.root_folder = root_folder trans.sa_session.add_all( ( library, root_folder ) ) trans.sa_session.flush() - return library.to_dict( view='element', value_mapper={ 'id' : trans.security.encode_id , 'root_folder_id' : trans.security.encode_id } ) + + item = library.to_dict( view='element', value_mapper={ 'id' : trans.security.encode_id , 'root_folder_id' : trans.security.encode_id } ) + item['can_user_add'] = True + item['can_user_modify'] = True + item['can_user_manage'] = True + if trans.app.security_agent.library_is_public( library, contents=False ): + item[ 'public' ] = True + return item @expose_api def update( self, trans, id, **kwd ): diff --git a/lib/galaxy/webapps/galaxy/api/library_contents.py b/lib/galaxy/webapps/galaxy/api/library_contents.py index 192d9970853..ed1c8780534 100644 --- a/lib/galaxy/webapps/galaxy/api/library_contents.py +++ b/lib/galaxy/webapps/galaxy/api/library_contents.py @@ -17,8 +17,7 @@ import logging log = logging.getLogger( __name__ ) -class LibraryContentsController( BaseAPIController, UsesLibraryMixin, UsesLibraryMixinItems, - UsesHistoryDatasetAssociationMixin ): +class LibraryContentsController( BaseAPIController, UsesLibraryMixin, UsesLibraryMixinItems, UsesHistoryDatasetAssociationMixin ): @expose_api def index( self, trans, library_id, **kwd ): diff --git a/static/scripts/galaxy.library.js b/static/scripts/galaxy.library.js index 1901497a8fb..9b9448b0486 100644 --- a/static/scripts/galaxy.library.js +++ b/static/scripts/galaxy.library.js @@ -2,28 +2,30 @@ // === MAIN GALAXY LIBRARY MODULE ==== // MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM -// global variables -var library_router = null; - // dependencies define([ - "galaxy.masthead", + "galaxy.masthead", "utils/utils", "libs/toastr", "mvc/base-mvc", "mvc/library/library-model", "mvc/library/library-folderlist-view", "mvc/library/library-librarylist-view", - "mvc/library/library-librarytoolbar-view"], -function(mod_masthead, - mod_utils, + "mvc/library/library-librarytoolbar-view", + "mvc/library/library-foldertoolbar-view" + ], +function(mod_masthead, + mod_utils, mod_toastr, mod_baseMVC, mod_library_model, mod_folderlist_view, mod_librarylist_view, - mod_librarytoolbar_view) { + mod_librarytoolbar_view, + mod_foldertoolbar_view + ) { +// ============================================================================ //ROUTER var LibraryRouter = Backbone.Router.extend({ routes: { @@ -44,12 +46,14 @@ var LibraryPrefs = mod_baseMVC.SessionStorageModel.extend({ } }); -// galaxy library wrapper View +// ============================================================================ +// Main controller of Galaxy Library var GalaxyLibrary = Backbone.View.extend({ - toolbarView: null, + libraryToolbarView: null, libraryListView: null, library_router: null, - folderContentView: null, + folderToolbarView: null, + folderListView: null, initialize : function(){ Galaxy.libraries = this; @@ -59,25 +63,26 @@ var GalaxyLibrary = Backbone.View.extend({ this.library_router.on('route:libraries', function() { // initialize and render the toolbar first - Galaxy.libraries.toolbarView = new mod_librarytoolbar_view.ToolbarView(); + Galaxy.libraries.libraryToolbarView = new mod_librarytoolbar_view.LibraryToolbarView(); // initialize and render libraries second Galaxy.libraries.libraryListView = new mod_librarylist_view.LibraryListView(); }); this.library_router.on('route:folder_content', function(id) { - // render folder contents - if (!Galaxy.libraries.folderContentView) {Galaxy.libraries.folderContentView = new mod_folderlist_view.FolderContentView();} - Galaxy.libraries.folderContentView.render({id: id}); + // TODO place caching here, sessionstorage/localstorage? + Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView({id: id}); + Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView({id: id}); }); this.library_router.on('route:download', function(folder_id, format) { - if ($('#center').find(':checked').length === 0) { + if ($('#center').find(':checked').length === 0) { + mod_toastr.info('You have to select some datasets to download') // this happens rarely when there is a server/data error and client gets an actual response instead of an attachment // we don't know what was selected so we can't download again, we redirect to the folder provided Galaxy.libraries.library_router.navigate('folders/' + folder_id, {trigger: true, replace: true}); } else { // send download stream - Galaxy.libraries.folderContentView.download(folder_id, format); + Galaxy.libraries.folderToolbarView.download(folder_id, format); Galaxy.libraries.library_router.navigate('folders/' + folder_id, {trigger: false, replace: true}); } }); @@ -86,7 +91,6 @@ var GalaxyLibrary = Backbone.View.extend({ } }); -// return return { GalaxyApp: GalaxyLibrary }; diff --git a/static/scripts/mvc/library/library-folderlist-view.js b/static/scripts/mvc/library/library-folderlist-view.js index 21e8f289c40..a0bd9a3f8a7 100644 --- a/static/scripts/mvc/library/library-folderlist-view.js +++ b/static/scripts/mvc/library/library-folderlist-view.js @@ -1,458 +1,126 @@ // dependencies define([ - "galaxy.masthead", + "galaxy.masthead", "utils/utils", "libs/toastr", - "mvc/library/library-model"], -function(mod_masthead, - mod_utils, + "mvc/library/library-model", + "mvc/library/library-folderrow-view"], +function(mod_masthead, + mod_utils, mod_toastr, - mod_library_model) { + mod_library_model, + mod_library_folderrow_view) { - //main view for folder browsing -var FolderContentView = Backbone.View.extend({ - // main element definition - el : '#center', - // progress percentage - progress: 0, - // progress rate per one item - progressStep: 1, - // last selected history in modal for UX - lastSelectedHistory: '', - // self modal - modal : null, - // loaded folders - folders : null, +var FolderListView = Backbone.View.extend({ + // main element definition + el : '#folder_items_element', + // progress percentage + progress: 0, + // progress rate per one item + progressStep: 1, + // self modal + modal : null, + folderContainer: null, + + // event binding + events: { + 'click #select-all-checkboxes' : 'selectAll', + 'click .dataset_row' : 'selectClickedRow' + }, // initialize - initialize : function(){ - this.folders = []; + initialize : function(options){ + var that = this; + this.options = _.defaults(this.options || {}, options); this.queue = jQuery.Deferred(); this.queue.resolve(); - }, - -// MMMMMMMMMMMMMMMMMM -// === TEMPLATES ==== -// MMMMMMMMMMMMMMMMMM - - // main template for folder browsing - templateFolder : function (){ - var tmpl_array = []; - - // CONTAINER - tmpl_array.push('
'); - tmpl_array.push('

Data Libraries Beta Test. This is work in progress. Please report problems & ideas via email and Trello.

'); - - // TOOLBAR - tmpl_array.push('
'); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - - tmpl_array.push('
'); - - // BREADCRUMBS - tmpl_array.push(''); - - - // FOLDER CONTENT - tmpl_array.push(''); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' <% _.each(items, function(content_item) { %>'); - tmpl_array.push(' <% if (content_item.get("type") === "folder") { %>'); // folder - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); // size - tmpl_array.push(' '); // time updated - tmpl_array.push(' '); - tmpl_array.push(' <% } else { %>'); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' '); // dataset - tmpl_array.push(' '); // data type - tmpl_array.push(' '); // size - tmpl_array.push(' '); // time updated - tmpl_array.push(' '); - tmpl_array.push(' <% } %> '); - tmpl_array.push(' <% }); %>'); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push('
namedata typesizedate (UTC)
" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..
'); - tmpl_array.push(' '); - tmpl_array.push(' '); - tmpl_array.push(' <%- content_item.get("name") %>'); - tmpl_array.push(' <% if (content_item.get("item_count") === 0) { %>'); // empty folder - tmpl_array.push(' (empty folder)'); - tmpl_array.push(' <% } %>'); - tmpl_array.push(' folder<%= _.escape(content_item.get("item_count")) %> item(s)<%= _.escape(content_item.get("time_updated")) %>
'); - tmpl_array.push(' '); - tmpl_array.push(' <%- content_item.get("name") %><%= _.escape(content_item.get("data_type")) %><%= _.escape(content_item.get("readable_size")) %><%= _.escape(content_item.get("time_updated")) %>
'); - - tmpl_array.push('
'); - return tmpl_array.join(''); - }, - templateDatasetModal : function(){ - var tmpl_array = []; - - tmpl_array.push(''); - - return tmpl_array.join(''); - }, - - templateHistorySelectInModal : function(){ - var tmpl_array = []; - - tmpl_array.push(''); - tmpl_array.push('Select history: '); - tmpl_array.push(''); - tmpl_array.push(''); - - return tmpl_array.join(''); - }, - - templateBulkImportInModal : function(){ - var tmpl_array = []; - - tmpl_array.push(''); - tmpl_array.push('Select history: '); - tmpl_array.push(''); - tmpl_array.push(''); - - return tmpl_array.join(''); - }, - - templateProgressBar : function (){ - var tmpl_array = []; - - tmpl_array.push('
'); - tmpl_array.push('Importing selected datasets to history <%= _.escape(history_name) %>'); - tmpl_array.push('
'); - tmpl_array.push('
'); - tmpl_array.push('
'); - tmpl_array.push(' 0% Complete'); - tmpl_array.push('
'); - tmpl_array.push('
'); - tmpl_array.push(''); - - return tmpl_array.join(''); - }, - - templateNewFolderInModal: function(){ - tmpl_array = []; - - tmpl_array.push('
'); - tmpl_array.push(''); - tmpl_array.push(''); - tmpl_array.push(''); - tmpl_array.push(''); - tmpl_array.push('
'); - - return tmpl_array.join(''); - }, - -// MMMMMMMMMMMMMMM -// === EVENTS ==== -// MMMMMMMMMMMMMMM - - // event binding - events: { - 'click #select-all-checkboxes' : 'selectAll', - 'click #toolbtn_bulk_import' : 'modalBulkImport', - 'click #toolbtn_dl' : 'bulkDownload', - 'click #toolbtn_create_folder' : 'createFolderFromModal', - 'click .library-dataset' : 'showDatasetDetails', - 'click .dataset_row' : 'selectClickedRow' - }, - -// MMMMMMMMMMMMMMMMMM -// === FUNCTIONS ==== -// MMMMMMMMMMMMMMMMMM - - //render the folder view - render: function (options) { - //hack to show scrollbars - $("#center").css('overflow','auto'); - - view = this; - var that = this; - - var folderContainer = new mod_library_model.FolderContainer({id: options.id}); - folderContainer.url = folderContainer.attributes.urlRoot + options.id + '/contents'; - - folderContainer.fetch({ - success: function (container) { - - // prepare nice size strings - for (var i = 0; i < folderContainer.attributes.folder.models.length; i++) { - var model = folderContainer.attributes.folder.models[i] - if (model.get('type') === 'file'){ - model.set('readable_size', that.size_to_string(model.get('file_size'))) - } - }; - - // find the upper id - var path = folderContainer.full_path; - var upper_folder_id; - if (path.length === 1){ // library is above us - upper_folder_id = 0; - } else { - upper_folder_id = path[path.length-2][0]; - } - - var template = _.template(that.templateFolder(), { path: folderContainer.full_path, items: folderContainer.attributes.folder.models, id: options.id, upper_folder_id: upper_folder_id }); - // var template = _.template(that.templateFolder(), { path: folderContainer.full_path, items: folderContainer.attributes.folder.models, id: options.id }); - that.$el.html(template); + this.folderContainer = new mod_library_model.FolderContainer({id: this.options.id}); + this.folderContainer.url = this.folderContainer.attributes.urlRoot + this.options.id + '/contents'; + this.folderContainer.fetch({ + success: function (folderContainer) { + that.render(); }, - error: function(){ - mod_toastr.error('An error occured :('); - } - }) - }, + error: function(){ + mod_toastr.error('An error occured :('); + } + }); + }, + + render: function (options) { + this.options = _.defaults(this.options || {}, options); + var template = this.templateFolder(); + var contains_file = false; + + // TODO move to server + // prepare nice size strings + for (var i = 0; i < this.folderContainer.attributes.folder.models.length; i++) { + var model = this.folderContainer.attributes.folder.models[i]; + if (model.get('type') === 'file'){ + contains_file = true; + model.set('readable_size', this.size_to_string(model.get('file_size'))); + } + } + + // TODO move to server + // find the upper id in the full path + var path = this.folderContainer.attributes.metadata.full_path; + var upper_folder_id; + if (path.length === 1){ // the library is above us + upper_folder_id = 0; + } else { + upper_folder_id = path[path.length-2][0]; + } + + this.$el.html(template({ path: this.folderContainer.attributes.metadata.full_path, items: this.folderContainer.attributes.folder.models, id: this.options.id, upper_folder_id: upper_folder_id })); + + if (this.folderContainer.attributes.folder.models.length > 0){ + this.renderRows(); + } + if (this.folderContainer.attributes.metadata.can_add_library_item === true){ + Galaxy.libraries.folderToolbarView.configureElements({ can_add_library_item: this.folderContainer.attributes.metadata.can_add_library_item, contains_file: contains_file }); + } + + // initialize the library tooltips + $("#center [data-toggle]").tooltip(); + //hack to show scrollbars + $("#center").css('overflow','auto'); + }, + + renderRows: function(){ + for (var i = 0; i < this.folderContainer.attributes.folder.models.length; i++) { + var folder_item = this.folderContainer.attributes.folder.models[i]; + var rowView = new mod_library_folderrow_view.FolderRowView(folder_item); + this.$el.find('#folder_list_body').append(rowView.el); + } + }, // convert size to nice string - size_to_string : function (size) - { - // identify unit - var unit = ""; - if (size >= 100000000000) { size = size / 100000000000; unit = "TB"; } else - if (size >= 100000000) { size = size / 100000000; unit = "GB"; } else - if (size >= 100000) { size = size / 100000; unit = "MB"; } else - if (size >= 100) { size = size / 100; unit = "KB"; } else - { size = size * 10; unit = "b"; } - // return formatted string - return (Math.round(size) / 10) + unit; - }, - - //show modal with current dataset info - showDatasetDetails : function(event){ - // prevent default - event.preventDefault(); - - //TODO check whether we already have the data - - //load the ID of the row - var id = $(event.target).parent().parent().parent().attr('id'); - if (typeof id === 'undefined'){ - id = $(event.target).parent().attr('id'); - } - if (typeof id === 'undefined'){ - id = $(event.target).parent().parent().attr('id') - } - - //create new item - var item = new mod_library_model.Item(); - var histories = new mod_library_model.GalaxyHistories(); - item.id = id; - var self = this; - - //fetch the dataset info - item.fetch({ - success: function (item) { - // TODO can render here already - //fetch user histories for import purposes - histories.fetch({ - success: function (histories){ - self.renderModalAfterFetch(item, histories) - }, - error: function(){ - mod_toastr.error('An error occured during fetching histories:('); - self.renderModalAfterFetch(item) - } - }); - }, - error: function(){ - mod_toastr.error('An error occured during loading dataset details :('); - } - }); - }, - - // show the current dataset in a modal - renderModalAfterFetch : function(item, histories){ - var size = this.size_to_string(item.get('file_size')); - var template = _.template(this.templateDatasetModal(), { item : item, size : size }); - // make modal - var self = this; - this.modal = Galaxy.modal; - this.modal.show({ - closing_events : true, - title : 'Dataset Details', - body : template, - buttons : { - 'Import' : function() { self.importCurrentIntoHistory() }, - 'Download' : function() { self.downloadCurrent() }, - 'Close' : function() { self.modal.hide() } - } - }); - - $(".peek").html('Peek:' + item.get("peek")); - - // show the import-into-history footer only if the request for histories succeeded - if (typeof history.models !== undefined){ - var history_footer_tmpl = _.template(this.templateHistorySelectInModal(), {histories : histories.models}); - $(this.modal.elMain).find('.buttons').prepend(history_footer_tmpl); - // preset last selected history if we know it - if (self.lastSelectedHistory.length > 0) { - $(this.modal.elMain).find('#dataset_import_single').val(self.lastSelectedHistory); - } - } - }, - - // download dataset shown currently in modal - downloadCurrent : function(){ - //disable the buttons - this.modal.disableButton('Import'); - this.modal.disableButton('Download'); - - var library_dataset_id = []; - library_dataset_id.push($('#id_row').attr('data-id')); - var url = '/api/libraries/datasets/download/uncompressed'; - var data = {'ldda_ids' : library_dataset_id}; - - // we assume the view is existent - folderContentView.processDownload(url, data); - this.modal.enableButton('Import'); - this.modal.enableButton('Download'); - }, - - // import dataset shown currently in modal into selected history - importCurrentIntoHistory : function(){ - //disable the buttons - this.modal.disableButton('Import'); - this.modal.disableButton('Download'); - - var history_id = $(this.modal.elMain).find('select[name=dataset_import_single] option:selected').val(); - this.lastSelectedHistory = history_id; //save selected history for further use - - var library_dataset_id = $('#id_row').attr('data-id'); - var historyItem = new mod_library_model.HistoryItem(); - var self = this; - historyItem.url = historyItem.urlRoot + history_id + '/contents'; - - // save the dataset into selected history - historyItem.save({ content : library_dataset_id, source : 'library' }, { success : function(){ - mod_toastr.success('Dataset imported'); - //enable the buttons - self.modal.enableButton('Import'); - self.modal.enableButton('Download'); - }, error : function(){ - mod_toastr.error('An error occured! Dataset not imported. Please try again.') - //enable the buttons - self.modal.enableButton('Import'); - self.modal.enableButton('Download'); - } - }); - }, + size_to_string : function (size){ + // identify unit + var unit = ""; + if (size >= 100000000000) { size = size / 100000000000; unit = "TB"; } else + if (size >= 100000000) { size = size / 100000000; unit = "GB"; } else + if (size >= 100000) { size = size / 100000; unit = "MB"; } else + if (size >= 100) { size = size / 100; unit = "KB"; } else + { size = size * 10; unit = "b"; } + // return formatted string + return (Math.round(size) / 10) + unit; + }, // select all datasets selectAll : function (event) { var selected = event.target.checked; that = this; // Iterate each checkbox - $(':checkbox').each(function () { - this.checked = selected; + $(':checkbox').each(function() { + this.checked = selected; $row = $(this.parentElement.parentElement); // Change color of selected/unselected (selected) ? that.makeDarkRow($row) : that.makeWhiteRow($row); }); // Show the tools in menu - this.checkTools(); + // this.checkTools(); }, // Check checkbox on row itself or row checkbox click @@ -485,7 +153,7 @@ var FolderContentView = Backbone.View.extend({ this.makeWhiteRow($row); } } - this.checkTools(); + // this.checkTools(); }, makeDarkRow: function($row){ @@ -507,207 +175,56 @@ var FolderContentView = Backbone.View.extend({ $row.find('span').removeClass('fa-file'); }, - // show toolbar in case something is selected - checkTools : function(){ - var checkedValues = $('#folder_table').find(':checked'); - if(checkedValues.length > 0){ - $('#toolbtn_bulk_import').show(); - $('#toolbtn_dl').show(); - } else { - $('#toolbtn_bulk_import').hide(); - $('#toolbtn_dl').hide(); - } - }, +// MMMMMMMMMMMMMMMMMM +// === TEMPLATES ==== +// MMMMMMMMMMMMMMMMMM - // show bulk import modal - modalBulkImport : function(){ - var self = this; - // fetch histories - var histories = new mod_library_model.GalaxyHistories(); - histories.fetch({ - success: function (histories){ - // make modal - var history_modal_tmpl = _.template(self.templateBulkImportInModal(), {histories : histories.models}); - self.modal = Galaxy.modal; - self.modal.show({ - closing_events : true, - title : 'Import into History', - body : history_modal_tmpl, - buttons : { - 'Import' : function() {self.importAllIntoHistory()}, - 'Close' : function() {self.modal.hide();} - } - }); - }, - error: function(){ - mod_toastr.error('An error occured :('); - } - }); - }, + // main template for folder browsing + templateFolder : function (){ + var tmpl_array = []; - // import all selected datasets into history - importAllIntoHistory : function (){ - //disable the button to prevent multiple submission - this.modal.disableButton('Import'); + // BREADCRUMBS + tmpl_array.push(''); - var history_id = $("select[name=dataset_import_bulk] option:selected").val(); - var history_name = $("select[name=dataset_import_bulk] option:selected").text(); + // FOLDER CONTENT + tmpl_array.push(''); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); - var dataset_ids = []; - $('#folder_table').find(':checked').each(function(){ - if (this.parentElement.parentElement.id != '') { - dataset_ids.push(this.parentElement.parentElement.id); - } - }); - var progress_bar_tmpl = _.template(this.templateProgressBar(), { history_name : history_name }); - $(this.modal.elMain).find('.modal-body').html(progress_bar_tmpl); + tmpl_array.push(' '); + tmpl_array.push('
namedata typesizedate (UTC)
" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..
'); - // init the progress bar - var progressStep = 100 / dataset_ids.length; - this.initProgress(progressStep); - - // prepare the dataset objects to be imported - var datasets_to_import = []; - for (var i = dataset_ids.length - 1; i >= 0; i--) { - library_dataset_id = dataset_ids[i]; - var historyItem = new mod_library_model.HistoryItem(); - var self = this; - historyItem.url = historyItem.urlRoot + history_id + '/contents'; - historyItem.content = library_dataset_id; - historyItem.source = 'library'; - datasets_to_import.push(historyItem); - }; - - // call the recursive function to call ajax one after each other (request FIFO queue) - this.chainCall(datasets_to_import); - }, - - chainCall: function(history_item_set){ - var self = this; - var popped_item = history_item_set.pop(); - if (typeof popped_item === "undefined") { - mod_toastr.success('All datasets imported'); - this.modal.hide(); - return - } - var promise = $.when(popped_item.save({content: popped_item.content, source: popped_item.source})).done(function(a1){ - self.updateProgress(); - // responses.push(a1); - self.chainCall(history_item_set); - }); - }, - - initProgress: function(progressStep){ - this.progress = 0; - this.progressStep = progressStep; - }, - 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 selected datasets - download : function(folder_id, format){ - var dataset_ids = []; - $('#folder_table').find(':checked').each(function(){ - if (this.parentElement.parentElement.id != '') { - dataset_ids.push(this.parentElement.parentElement.id); - } - }); - - var url = '/api/libraries/datasets/download/' + format; - var data = {'ldda_ids' : dataset_ids}; - this.processDownload(url, data, 'get'); - }, - - // create hidden form and submit through POST to initialize download - processDownload: function(url, data, method){ - //url and data options required - if( url && data ){ - //data can be string of parameters or array/object - data = typeof data == 'string' ? data : $.param(data); - //split params into form inputs - var inputs = ''; - $.each(data.split('&'), function(){ - var pair = this.split('='); - inputs+=''; - }); - //send request - $('
'+inputs+'
') - .appendTo('body').submit().remove(); - - mod_toastr.info('Your download will begin soon'); - }; - }, - - // shows modal for creating folder - createFolderFromModal: function(){ - event.preventDefault(); - event.stopPropagation(); - - // create modal - var self = this; - this.modal = Galaxy.modal; - this.modal.show({ - closing_events : true, - title : 'Create New Folder', - body : this.templateNewFolderInModal(), - buttons : { - 'Create' : function() {self.create_new_folder_event()}, - 'Close' : function() {self.modal.hide(); self.modal = null;} - } - }); - }, - - // create the new folder from modal - create_new_folder_event: function(){ - var folderDetails = this.serialize_new_folder(); - if (this.validate_new_folder(folderDetails)){ - var folder = new mod_library_model.FolderAsModel(); - - url_items = Backbone.history.fragment.split('/'); - 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(); - mod_toastr.success('Folder created'); - self.render({id: current_folder_id}); - }, - error: function(){ - mod_toastr.error('An error occured :('); - } - }); - } else { - mod_toastr.error('Folder\'s name is missing'); - } - return false; - }, - - // serialize data from the form - serialize_new_folder : function(){ - return { - name: $("input[name='Name']").val(), - description: $("input[name='Description']").val() - }; - }, - - // validate new library info - validate_new_folder: function(folderDetails){ - return folderDetails.name !== ''; + return _.template(tmpl_array.join('')); } }); -// return return { - FolderContentView: FolderContentView + FolderListView: FolderListView }; }); diff --git a/static/scripts/mvc/library/library-librarylist-view.js b/static/scripts/mvc/library/library-librarylist-view.js index f183fbd00df..5bea6fe4228 100644 --- a/static/scripts/mvc/library/library-librarylist-view.js +++ b/static/scripts/mvc/library/library-librarylist-view.js @@ -1,14 +1,14 @@ // dependencies define([ "galaxy.masthead", - "mvc/base-mvc", + "mvc/base-mvc", "utils/utils", "libs/toastr", "mvc/library/library-model", - "mvc/library/library-libraryrow-view"], + "mvc/library/library-libraryrow-view"], function(mod_masthead, - mod_baseMVC, - mod_utils, + mod_baseMVC, + mod_utils, mod_toastr, mod_library_model, mod_library_libraryrow_view) { @@ -29,7 +29,8 @@ var LibraryListView = Backbone.View.extend({ rowViews: {}, // initialize - initialize : function(){ + initialize : function(options){ + this.options = _.defaults(this.options || {}, options); var viewContext = this; this.rowViews = {}; @@ -43,7 +44,7 @@ var LibraryListView = Backbone.View.extend({ error: function(model, response){ mod_toastr.error('An error occured. Please try again.'); } - }) + }); }, /** Renders the libraries table either from the object's own collection, @@ -52,9 +53,8 @@ var LibraryListView = Backbone.View.extend({ render: function (options) { var template = this.templateLibraryList(); var libraries_to_render = null; - var include_deleted = true; var include_deleted = Galaxy.libraries.preferences.get('with_deleted'); - var models = null + var models = null; if (typeof options !== 'undefined'){ include_deleted = typeof options.with_deleted !== 'undefined' ? options.with_deleted : false; models = typeof options.models !== 'undefined' ? options.models : null; @@ -64,7 +64,7 @@ var LibraryListView = Backbone.View.extend({ if (include_deleted){ // show all the libraries libraries_to_render = this.collection.models; } else{ // show only undeleted libraries - libraries_to_render = this.collection.where({deleted: false});; + libraries_to_render = this.collection.where({deleted: false}); } } else if (models !== null){ libraries_to_render = models; @@ -74,7 +74,9 @@ var LibraryListView = Backbone.View.extend({ this.$el.html(template({length: libraries_to_render.length, order: Galaxy.libraries.preferences.get('sort_order') })); - this.renderRows(libraries_to_render); + if (libraries_to_render.length > 0){ + this.renderRows(libraries_to_render); + } // initialize the library tooltips $("#center [data-toggle]").tooltip(); // modification of upper DOM element to show scrollbars due to the #center element inheritance @@ -92,9 +94,9 @@ var LibraryListView = Backbone.View.extend({ var rowView = new mod_library_libraryrow_view.LibraryRowView(library); this.$el.find('#library_list_body').append(rowView.el); // save new rowView to cache - this.rowViews[library.get('id')] = rowView; + this.rowViews[library.get('id')] = rowView; } - }; + } }, sort_clicked : function(){ @@ -115,17 +117,17 @@ var LibraryListView = Backbone.View.extend({ if (order === 'asc'){ // this.collection.sort_order = 'asc'; this.collection.comparator = function(libraryA, libraryB){ - if (libraryA.get('name').toLowerCase() > libraryB.get('name').toLowerCase()) return 1; // after - if (libraryB.get('name').toLowerCase() > libraryA.get('name').toLowerCase()) return -1; // before + if (libraryA.get('name').toLowerCase() > libraryB.get('name').toLowerCase()) {return 1;} // after + if (libraryB.get('name').toLowerCase() > libraryA.get('name').toLowerCase()) {return -1;} // before return 0; // equal - } + }; } else if (order === 'desc'){ // this.collection.sort_order = 'desc'; this.collection.comparator = function(libraryA, libraryB){ - if (libraryA.get('name').toLowerCase() > libraryB.get('name').toLowerCase()) return -1; // before - if (libraryB.get('name').toLowerCase() > libraryA.get('name').toLowerCase()) return 1; // after + if (libraryA.get('name').toLowerCase() > libraryB.get('name').toLowerCase()) {return -1;} // before + if (libraryB.get('name').toLowerCase() > libraryA.get('name').toLowerCase()) {return 1;} // after return 0; // equal - } + }; } this.collection.sort(); } @@ -140,7 +142,7 @@ var LibraryListView = Backbone.View.extend({ tmpl_array.push('
'); tmpl_array.push('<% if(length === 0) { %>'); - tmpl_array.push("
I see no libraries. Why don't you create one?
"); + tmpl_array.push('
There are no libraries visible to you. If you expected some to show up please consult the library security wikipage.
'); tmpl_array.push('<% } else{ %>'); tmpl_array.push(''); tmpl_array.push(' '); @@ -175,7 +177,7 @@ var LibraryListView = Backbone.View.extend({ redirectToHome: function(){ window.location = '../'; - }, + }, redirectToLogin: function(){ window.location = '/user/login'; }, @@ -193,7 +195,7 @@ var LibraryListView = Backbone.View.extend({ title : 'Create New Library', body : this.templateNewLibraryInModal(), buttons : { - 'Create' : function() {self.create_new_library_event()}, + 'Create' : function() {self.create_new_library_event();}, 'Close' : function() {self.modal.hide();} } }); @@ -245,7 +247,6 @@ var LibraryListView = Backbone.View.extend({ } }); -// return return { LibraryListView: LibraryListView }; diff --git a/static/scripts/mvc/library/library-libraryrow-view.js b/static/scripts/mvc/library/library-libraryrow-view.js index b7deca3a5aa..3184f6e4ca3 100644 --- a/static/scripts/mvc/library/library-libraryrow-view.js +++ b/static/scripts/mvc/library/library-libraryrow-view.js @@ -1,11 +1,11 @@ // dependencies define([ - "galaxy.masthead", + "galaxy.masthead", "utils/utils", "libs/toastr", - "mvc/library/library-model"], -function(mod_masthead, - mod_utils, + "mvc/library/library-model"], +function(mod_masthead, + mod_utils, mod_toastr, mod_library_model) { @@ -39,7 +39,7 @@ var LibraryRowView = Backbone.View.extend({ render: function(library){ if (typeof library === 'undefined'){ - var library = Galaxy.libraries.libraryListView.collection.get(this.$el.data('id')); + library = Galaxy.libraries.libraryListView.collection.get(this.$el.data('id')); } this.prepareButtons(library); var tmpl = this.templateRow(); @@ -51,7 +51,7 @@ var LibraryRowView = Backbone.View.extend({ repaint: function(library){ /* need to hide manually because of the element removal in setElement invoked in render() */ - $(".tooltip").hide(); + $(".tooltip").hide(); /* we need to store the old element to be able to replace it with new one */ var old_element = this.$el; @@ -83,13 +83,13 @@ var LibraryRowView = Backbone.View.extend({ vis_config.undelete_library_btn = false; if (library.get('can_user_add') === true){ vis_config.upload_library_btn = true; - } + } if (library.get('can_user_modify') === true){ vis_config.edit_library_btn = true; - } + } if (library.get('can_user_manage') === true){ vis_config.permission_library_btn = true; - } + } } } else if (this.edit_mode === true){ vis_config.upload_library_btn = false; @@ -136,7 +136,7 @@ var LibraryRowView = Backbone.View.extend({ is_changed = true; } else{ mod_toastr.warning('Library name has to be at least 3 characters long'); - return + return; } } @@ -183,7 +183,7 @@ var LibraryRowView = Backbone.View.extend({ Galaxy.libraries.libraryListView.collection.add(library); row_view.edit_mode = false; if (Galaxy.libraries.preferences.get('with_deleted') === false){ - $(".tooltip").hide(); + $('.tooltip').hide(); row_view.$el.remove(); } else if (Galaxy.libraries.preferences.get('with_deleted') === true){ row_view.repaint(library); @@ -247,12 +247,11 @@ var LibraryRowView = Backbone.View.extend({ tmpl_array.push(' '); tmpl_array.push(' '); - return _.template(tmpl_array.join('')); + return _.template(tmpl_array.join('')); } }); - // return return { LibraryRowView: LibraryRowView }; diff --git a/static/scripts/mvc/library/library-librarytoolbar-view.js b/static/scripts/mvc/library/library-librarytoolbar-view.js index f713575e8ca..bc35c73c054 100644 --- a/static/scripts/mvc/library/library-librarytoolbar-view.js +++ b/static/scripts/mvc/library/library-librarytoolbar-view.js @@ -1,18 +1,18 @@ // dependencies define([ - "galaxy.masthead", + "galaxy.masthead", "utils/utils", "libs/toastr", - "mvc/library/library-model"], -function(mod_masthead, - mod_utils, + "mvc/library/library-model"], +function(mod_masthead, + mod_utils, mod_toastr, mod_library_model) { -var ToolbarView = Backbone.View.extend({ +var LibraryToolbarView = Backbone.View.extend({ el: '#center', - events: { + events: { 'click #create_new_library_btn' : 'delegate_modal', 'click #include_deleted_chk' : 'check_include_deleted' }, @@ -23,14 +23,16 @@ var ToolbarView = Backbone.View.extend({ render: function(){ var toolbar_template = this.templateToolBar(); - this.$el.html(toolbar_template({admin_user: Galaxy.currUser.isAdmin(), anon_user: Galaxy.currUser.isAnonymous()})) + var is_admin = Galaxy.currUser.isAdmin(); + var is_anonym = Galaxy.currUser.isAnonymous(); + this.$el.html(toolbar_template({admin_user: is_admin, anon_user: is_anonym})); if (Galaxy.currUser.isAdmin() === true){ this.$el.find('#include_deleted_chk')[0].checked = Galaxy.libraries.preferences.get('with_deleted'); } }, delegate_modal: function(event){ - // probably should refactor to have this functionality in this view, not in the library view + // probably should refactor to have this functionality in this view, not in the library list view Galaxy.libraries.libraryListView.show_library_modal(event); }, @@ -48,7 +50,7 @@ var ToolbarView = Backbone.View.extend({ templateToolBar: function(){ tmpl_array = []; - tmpl_array.push('
'); + tmpl_array.push('
'); // TOOLBAR tmpl_array.push('
'); tmpl_array.push('

Data Libraries Beta Test. This is work in progress. Please report problems & ideas via email and Trello.

'); @@ -60,16 +62,16 @@ var ToolbarView = Backbone.View.extend({ tmpl_array.push(' <% } %>'); tmpl_array.push('
'); tmpl_array.push('
'); + // table with libraries will append here tmpl_array.push('
'); tmpl_array.push('
'); return _.template(tmpl_array.join('')); } -}) +}); -// return return { - ToolbarView: ToolbarView + LibraryToolbarView: LibraryToolbarView }; }); diff --git a/static/scripts/mvc/library/library-model.js b/static/scripts/mvc/library/library-model.js index d159bc4409e..6942ae53753 100644 --- a/static/scripts/mvc/library/library-model.js +++ b/static/scripts/mvc/library/library-model.js @@ -66,16 +66,14 @@ define([], function() { var FolderContainer = Backbone.Model.extend({ defaults : { folder : new Folder(), - full_path : "unknown", urlRoot : "/api/folders/", id : "unknown" }, parse : function(obj) { - this.full_path = obj[0].full_path; - // response is not a simple array, it contains metadata - // this will update the inner collection - this.get("folder").reset(obj[1].folder_contents); - return obj; + // response is not a simple array, it contains metadata + // this will update the inner collection + this.get("folder").reset(obj.folder_contents); + return obj; } }); diff --git a/static/scripts/packed/galaxy.library.js b/static/scripts/packed/galaxy.library.js index 1e2cf49375f..592aecc523d 100644 --- a/static/scripts/packed/galaxy.library.js +++ b/static/scripts/packed/galaxy.library.js @@ -1 +1 @@ -var library_router=null;define(["galaxy.masthead","utils/utils","libs/toastr","mvc/base-mvc","mvc/library/library-model","mvc/library/library-folderlist-view","mvc/library/library-librarylist-view","mvc/library/library-librarytoolbar-view"],function(e,c,g,j,h,a,f,d){var k=Backbone.Router.extend({routes:{"":"libraries","sort/:sort_by/:order":"sort_libraries","folders/:id":"folder_content","folders/:folder_id/download/:format":"download"}});var i=j.SessionStorageModel.extend({defaults:{with_deleted:false,sort_order:"asc",sort_by:"name"}});var b=Backbone.View.extend({toolbarView:null,libraryListView:null,library_router:null,folderContentView:null,initialize:function(){Galaxy.libraries=this;this.preferences=new i({id:"global-lib-prefs"});this.library_router=new k();this.library_router.on("route:libraries",function(){Galaxy.libraries.toolbarView=new d.ToolbarView();Galaxy.libraries.libraryListView=new f.LibraryListView()});this.library_router.on("route:folder_content",function(l){if(!Galaxy.libraries.folderContentView){Galaxy.libraries.folderContentView=new a.FolderContentView()}Galaxy.libraries.folderContentView.render({id:l})});this.library_router.on("route:download",function(l,m){if($("#center").find(":checked").length===0){Galaxy.libraries.library_router.navigate("folders/"+l,{trigger:true,replace:true})}else{Galaxy.libraries.folderContentView.download(l,m);Galaxy.libraries.library_router.navigate("folders/"+l,{trigger:false,replace:true})}});Backbone.history.start({pushState:false})}});return{GalaxyApp:b}}); \ No newline at end of file +define(["galaxy.masthead","utils/utils","libs/toastr","mvc/base-mvc","mvc/library/library-model","mvc/library/library-folderlist-view","mvc/library/library-librarylist-view","mvc/library/library-librarytoolbar-view","mvc/library/library-foldertoolbar-view"],function(e,c,g,k,h,a,f,d,i){var l=Backbone.Router.extend({routes:{"":"libraries","sort/:sort_by/:order":"sort_libraries","folders/:id":"folder_content","folders/:folder_id/download/:format":"download"}});var j=k.SessionStorageModel.extend({defaults:{with_deleted:false,sort_order:"asc",sort_by:"name"}});var b=Backbone.View.extend({libraryToolbarView:null,libraryListView:null,library_router:null,folderToolbarView:null,folderListView:null,initialize:function(){Galaxy.libraries=this;this.preferences=new j({id:"global-lib-prefs"});this.library_router=new l();this.library_router.on("route:libraries",function(){Galaxy.libraries.libraryToolbarView=new d.LibraryToolbarView();Galaxy.libraries.libraryListView=new f.LibraryListView()});this.library_router.on("route:folder_content",function(m){Galaxy.libraries.folderToolbarView=new i.FolderToolbarView({id:m});Galaxy.libraries.folderListView=new a.FolderListView({id:m})});this.library_router.on("route:download",function(m,n){if($("#center").find(":checked").length===0){g.info("You have to select some datasets to download");Galaxy.libraries.library_router.navigate("folders/"+m,{trigger:true,replace:true})}else{Galaxy.libraries.folderToolbarView.download(m,n);Galaxy.libraries.library_router.navigate("folders/"+m,{trigger:false,replace:true})}});Backbone.history.start({pushState:false})}});return{GalaxyApp:b}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/library/library-folderlist-view.js b/static/scripts/packed/mvc/library/library-folderlist-view.js index 0ab07cf8b01..d940ceb3eeb 100644 --- a/static/scripts/packed/mvc/library/library-folderlist-view.js +++ b/static/scripts/packed/mvc/library/library-folderlist-view.js @@ -1 +1 @@ -define(["galaxy.masthead","utils/utils","libs/toastr","mvc/library/library-model"],function(a,c,d,b){var e=Backbone.View.extend({el:"#center",progress:0,progressStep:1,lastSelectedHistory:"",modal:null,folders:null,initialize:function(){this.folders=[];this.queue=jQuery.Deferred();this.queue.resolve()},templateFolder:function(){var f=[];f.push('
');f.push('

Data Libraries Beta Test. This is work in progress. Please report problems & ideas via email and Trello.

');f.push('
');f.push(' ');f.push(' ');f.push(' ");f.push("
");f.push('");f.push('
');f.push(" ");f.push(' ');f.push(' ');f.push(" ");f.push(" ");f.push(" ");f.push(" ");f.push(" ");f.push(" ");f.push(' ');f.push(" ");f.push(" ");f.push(" ");f.push(" ");f.push(" ");f.push(" ");f.push(" <% _.each(items, function(content_item) { %>");f.push(' <% if (content_item.get("type") === "folder") { %>');f.push(' ');f.push(" ");f.push(" ");f.push(" ");f.push(" ");f.push(' ');f.push(' ');f.push(" ");f.push(" <% } else { %>");f.push(' ');f.push(" ");f.push(' ');f.push(' ');f.push(' ');f.push(' ');f.push(' ');f.push(" ");f.push(" <% } %> ");f.push(" <% }); %>");f.push(" ");f.push(" ");f.push("
namedata typesizedate (UTC)
" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..
");f.push(' ');f.push(" ");f.push(' <%- content_item.get("name") %>');f.push(' <% if (content_item.get("item_count") === 0) { %>');f.push(' (empty folder)');f.push(" <% } %>");f.push(" folder<%= _.escape(content_item.get("item_count")) %> item(s)<%= _.escape(content_item.get("time_updated")) %>
");f.push(' ');f.push(" <%- content_item.get("name") %><%= _.escape(content_item.get("data_type")) %><%= _.escape(content_item.get("readable_size")) %><%= _.escape(content_item.get("time_updated")) %>
");f.push("
");return f.join("")},templateDatasetModal:function(){var f=[];f.push('");return f.join("")},templateHistorySelectInModal:function(){var f=[];f.push('');f.push("Select history: ");f.push('");f.push("");return f.join("")},templateBulkImportInModal:function(){var f=[];f.push('');f.push("Select history: ");f.push('");f.push("");return f.join("")},templateProgressBar:function(){var f=[];f.push('
');f.push("Importing selected datasets to history <%= _.escape(history_name) %>");f.push("
");f.push('
');f.push('
');f.push(' 0% Complete');f.push("
");f.push("
");f.push("");return f.join("")},templateNewFolderInModal:function(){tmpl_array=[];tmpl_array.push('
');tmpl_array.push("
");tmpl_array.push('');tmpl_array.push('');tmpl_array.push("
");tmpl_array.push("
");return tmpl_array.join("")},events:{"click #select-all-checkboxes":"selectAll","click #toolbtn_bulk_import":"modalBulkImport","click #toolbtn_dl":"bulkDownload","click #toolbtn_create_folder":"createFolderFromModal","click .library-dataset":"showDatasetDetails","click .dataset_row":"selectClickedRow"},render:function(f){$("#center").css("overflow","auto");view=this;var h=this;var g=new b.FolderContainer({id:f.id});g.url=g.attributes.urlRoot+f.id+"/contents";g.fetch({success:function(j){for(var l=0;l=100000000000){f=f/100000000000;g="TB"}else{if(f>=100000000){f=f/100000000;g="GB"}else{if(f>=100000){f=f/100000;g="MB"}else{if(f>=100){f=f/100;g="KB"}else{f=f*10;g="b"}}}}return(Math.round(f)/10)+g},showDatasetDetails:function(i){i.preventDefault();var j=$(i.target).parent().parent().parent().attr("id");if(typeof j==="undefined"){j=$(i.target).parent().attr("id")}if(typeof j==="undefined"){j=$(i.target).parent().parent().attr("id")}var h=new b.Item();var g=new b.GalaxyHistories();h.id=j;var f=this;h.fetch({success:function(k){g.fetch({success:function(l){f.renderModalAfterFetch(k,l)},error:function(){d.error("An error occured during fetching histories:(");f.renderModalAfterFetch(k)}})},error:function(){d.error("An error occured during loading dataset details :(")}})},renderModalAfterFetch:function(k,h){var i=this.size_to_string(k.get("file_size"));var j=_.template(this.templateDatasetModal(),{item:k,size:i});var g=this;this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Dataset Details",body:j,buttons:{Import:function(){g.importCurrentIntoHistory()},Download:function(){g.downloadCurrent()},Close:function(){g.modal.hide()}}});$(".peek").html("Peek:"+k.get("peek"));if(typeof history.models!==undefined){var f=_.template(this.templateHistorySelectInModal(),{histories:h.models});$(this.modal.elMain).find(".buttons").prepend(f);if(g.lastSelectedHistory.length>0){$(this.modal.elMain).find("#dataset_import_single").val(g.lastSelectedHistory)}}},downloadCurrent:function(){this.modal.disableButton("Import");this.modal.disableButton("Download");var f=[];f.push($("#id_row").attr("data-id"));var g="/api/libraries/datasets/download/uncompressed";var h={ldda_ids:f};folderContentView.processDownload(g,h);this.modal.enableButton("Import");this.modal.enableButton("Download")},importCurrentIntoHistory:function(){this.modal.disableButton("Import");this.modal.disableButton("Download");var h=$(this.modal.elMain).find("select[name=dataset_import_single] option:selected").val();this.lastSelectedHistory=h;var f=$("#id_row").attr("data-id");var i=new b.HistoryItem();var g=this;i.url=i.urlRoot+h+"/contents";i.save({content:f,source:"library"},{success:function(){d.success("Dataset imported");g.modal.enableButton("Import");g.modal.enableButton("Download")},error:function(){d.error("An error occured! Dataset not imported. Please try again.");g.modal.enableButton("Import");g.modal.enableButton("Download")}})},selectAll:function(g){var f=g.target.checked;that=this;$(":checkbox").each(function(){this.checked=f;$row=$(this.parentElement.parentElement);(f)?that.makeDarkRow($row):that.makeWhiteRow($row)});this.checkTools()},selectClickedRow:function(g){var i="";var f;var h;if(g.target.localName==="input"){i=g.target;f=$(g.target.parentElement.parentElement);h="input"}else{if(g.target.localName==="td"){i=$("#"+g.target.parentElement.id).find(":checkbox")[0];f=$(g.target.parentElement);h="td"}}if(i.checked){if(h==="td"){i.checked="";this.makeWhiteRow(f)}else{if(h==="input"){this.makeDarkRow(f)}}}else{if(h==="td"){i.checked="selected";this.makeDarkRow(f)}else{if(h==="input"){this.makeWhiteRow(f)}}}this.checkTools()},makeDarkRow:function(f){f.removeClass("light");f.find("a").removeClass("light");f.addClass("dark");f.find("a").addClass("dark");f.find("span").removeClass("fa-file-o");f.find("span").addClass("fa-file")},makeWhiteRow:function(f){f.removeClass("dark");f.find("a").removeClass("dark");f.addClass("light");f.find("a").addClass("light");f.find("span").addClass("fa-file-o");f.find("span").removeClass("fa-file")},checkTools:function(){var f=$("#folder_table").find(":checked");if(f.length>0){$("#toolbtn_bulk_import").show();$("#toolbtn_dl").show()}else{$("#toolbtn_bulk_import").hide();$("#toolbtn_dl").hide()}},modalBulkImport:function(){var g=this;var f=new b.GalaxyHistories();f.fetch({success:function(h){var i=_.template(g.templateBulkImportInModal(),{histories:h.models});g.modal=Galaxy.modal;g.modal.show({closing_events:true,title:"Import into History",body:i,buttons:{Import:function(){g.importAllIntoHistory()},Close:function(){g.modal.hide()}}})},error:function(){d.error("An error occured :(")}})},importAllIntoHistory:function(){this.modal.disableButton("Import");var h=$("select[name=dataset_import_bulk] option:selected").val();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=_.template(this.templateProgressBar(),{history_name:m});$(this.modal.elMain).find(".modal-body").html(n);var j=100/o.length;this.initProgress(j);var f=[];for(var g=o.length-1;g>=0;g--){library_dataset_id=o[g];var k=new b.HistoryItem();var l=this;k.url=k.urlRoot+h+"/contents";k.content=library_dataset_id;k.source="library";f.push(k)}this.chainCall(f)},chainCall:function(g){var f=this;var h=g.pop();if(typeof h==="undefined"){d.success("All datasets imported");this.modal.hide();return}var i=$.when(h.save({content:h.content,source:h.source})).done(function(j){f.updateProgress();f.chainCall(g)})},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+=''});$('
'+f+"
").appendTo("body").submit().remove();d.info("Your download will begin soon")}},createFolderFromModal:function(){event.preventDefault();event.stopPropagation();var f=this;this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Create New Folder",body:this.templateNewFolderInModal(),buttons:{Create:function(){f.create_new_folder_event()},Close:function(){f.modal.hide();f.modal=null}}})},create_new_folder_event:function(){var f=this.serialize_new_folder();if(this.validate_new_folder(f)){var h=new b.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();d.success("Folder created");g.render({id:current_folder_id})},error:function(){d.error("An error occured :(")}})}else{d.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!==""}});return{FolderContentView:e}}); \ No newline at end of file +define(["galaxy.masthead","utils/utils","libs/toastr","mvc/library/library-model","mvc/library/library-folderrow-view"],function(c,e,f,d,a){var b=Backbone.View.extend({el:"#folder_items_element",progress:0,progressStep:1,modal:null,folderContainer:null,events:{"click #select-all-checkboxes":"selectAll","click .dataset_row":"selectClickedRow"},initialize:function(g){var h=this;this.options=_.defaults(this.options||{},g);this.queue=jQuery.Deferred();this.queue.resolve();this.folderContainer=new d.FolderContainer({id:this.options.id});this.folderContainer.url=this.folderContainer.attributes.urlRoot+this.options.id+"/contents";this.folderContainer.fetch({success:function(i){h.render()},error:function(){f.error("An error occured :(")}})},render:function(h){this.options=_.defaults(this.options||{},h);var k=this.templateFolder();var l=false;for(var j=0;j0){this.renderRows()}if(this.folderContainer.attributes.metadata.can_add_library_item===true){Galaxy.libraries.folderToolbarView.configureElements({can_add_library_item:this.folderContainer.attributes.metadata.can_add_library_item,contains_file:l})}$("#center [data-toggle]").tooltip();$("#center").css("overflow","auto")},renderRows:function(){for(var j=0;j=100000000000){g=g/100000000000;h="TB"}else{if(g>=100000000){g=g/100000000;h="GB"}else{if(g>=100000){g=g/100000;h="MB"}else{if(g>=100){g=g/100;h="KB"}else{g=g*10;h="b"}}}}return(Math.round(g)/10)+h},selectAll:function(h){var g=h.target.checked;that=this;$(":checkbox").each(function(){this.checked=g;$row=$(this.parentElement.parentElement);(g)?that.makeDarkRow($row):that.makeWhiteRow($row)})},selectClickedRow:function(h){var j="";var g;var i;if(h.target.localName==="input"){j=h.target;g=$(h.target.parentElement.parentElement);i="input"}else{if(h.target.localName==="td"){j=$("#"+h.target.parentElement.id).find(":checkbox")[0];g=$(h.target.parentElement);i="td"}}if(j.checked){if(i==="td"){j.checked="";this.makeWhiteRow(g)}else{if(i==="input"){this.makeDarkRow(g)}}}else{if(i==="td"){j.checked="selected";this.makeDarkRow(g)}else{if(i==="input"){this.makeWhiteRow(g)}}}},makeDarkRow:function(g){g.removeClass("light");g.find("a").removeClass("light");g.addClass("dark");g.find("a").addClass("dark");g.find("span").removeClass("fa-file-o");g.find("span").addClass("fa-file")},makeWhiteRow:function(g){g.removeClass("dark");g.find("a").removeClass("dark");g.addClass("light");g.find("a").addClass("light");g.find("span").addClass("fa-file-o");g.find("span").removeClass("fa-file")},templateFolder:function(){var g=[];g.push('");g.push('');g.push(" ");g.push(' ');g.push(' ');g.push(" ");g.push(" ");g.push(" ");g.push(" ");g.push(" ");g.push(' ');g.push(" ");g.push(' ');g.push(" ");g.push(" ");g.push(" ");g.push(" ");g.push(" ");g.push(" ");g.push(" ");g.push("
namedata typesizedate (UTC)
" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..
");return _.template(g.join(""))}});return{FolderListView:b}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/library/library-librarylist-view.js b/static/scripts/packed/mvc/library/library-librarylist-view.js index 3e75fd5abc6..52e4dae9cfb 100644 --- a/static/scripts/packed/mvc/library/library-librarylist-view.js +++ b/static/scripts/packed/mvc/library/library-librarylist-view.js @@ -1 +1 @@ -define(["galaxy.masthead","mvc/base-mvc","utils/utils","libs/toastr","mvc/library/library-model","mvc/library/library-libraryrow-view"],function(b,g,d,e,c,a){var f=Backbone.View.extend({el:"#libraries_element",events:{"click .sort-libraries-link":"sort_clicked"},modal:null,collection:null,rowViews:{},initialize:function(){var h=this;this.rowViews={};this.collection=new c.Libraries();this.collection.fetch({success:function(i){h.render()},error:function(j,i){e.error("An error occured. Please try again.")}})},render:function(i){var j=this.templateLibraryList();var k=null;var h=true;var h=Galaxy.libraries.preferences.get("with_deleted");var l=null;if(typeof i!=="undefined"){h=typeof i.with_deleted!=="undefined"?i.with_deleted:false;l=typeof i.models!=="undefined"?i.models:null}if(this.collection!==null&&l===null){if(h){k=this.collection.models}else{k=this.collection.where({deleted:false})}}else{if(l!==null){k=l}else{k=[]}}this.$el.html(j({length:k.length,order:Galaxy.libraries.preferences.get("sort_order")}));this.renderRows(k);$("#center [data-toggle]").tooltip();$("#center").css("overflow","auto")},renderRows:function(m){for(var l=0;lj.get("name").toLowerCase()){return 1}if(j.get("name").toLowerCase()>k.get("name").toLowerCase()){return -1}return 0}}else{if(h==="desc"){this.collection.comparator=function(k,j){if(k.get("name").toLowerCase()>j.get("name").toLowerCase()){return -1}if(j.get("name").toLowerCase()>k.get("name").toLowerCase()){return 1}return 0}}}this.collection.sort()}},templateLibraryList:function(){tmpl_array=[];tmpl_array.push('
');tmpl_array.push("<% if(length === 0) { %>");tmpl_array.push("
I see no libraries. Why don't you create one?
");tmpl_array.push("<% } else{ %>");tmpl_array.push('');tmpl_array.push(" ");tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(" ");tmpl_array.push(' ');tmpl_array.push(" ");tmpl_array.push("
name descriptionsynopsis
");tmpl_array.push("<% }%>");tmpl_array.push("
");return _.template(tmpl_array.join(""))},templateNewLibraryInModal:function(){tmpl_array=[];tmpl_array.push('
');tmpl_array.push("
");tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push("
");tmpl_array.push("
");return tmpl_array.join("")},redirectToHome:function(){window.location="../"},redirectToLogin:function(){window.location="/user/login"},show_library_modal:function(i){i.preventDefault();i.stopPropagation();var h=this;this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Create New Library",body:this.templateNewLibraryInModal(),buttons:{Create:function(){h.create_new_library_event()},Close:function(){h.modal.hide()}}})},create_new_library_event:function(){var j=this.serialize_new_library();if(this.validate_new_library(j)){var i=new c.Library();var h=this;i.save(j,{success:function(k){h.collection.add(k);h.modal.hide();h.clear_library_modal();h.render();e.success("Library created")},error:function(){e.error("An error occured :(")}})}else{e.error("Library's name is missing")}return false},clear_library_modal:function(){$("input[name='Name']").val("");$("input[name='Description']").val("");$("input[name='Synopsis']").val("")},serialize_new_library:function(){return{name:$("input[name='Name']").val(),description:$("input[name='Description']").val(),synopsis:$("input[name='Synopsis']").val()}},validate_new_library:function(h){return h.name!==""}});return{LibraryListView:f}}); \ No newline at end of file +define(["galaxy.masthead","mvc/base-mvc","utils/utils","libs/toastr","mvc/library/library-model","mvc/library/library-libraryrow-view"],function(b,g,d,e,c,a){var f=Backbone.View.extend({el:"#libraries_element",events:{"click .sort-libraries-link":"sort_clicked"},modal:null,collection:null,rowViews:{},initialize:function(i){this.options=_.defaults(this.options||{},i);var h=this;this.rowViews={};this.collection=new c.Libraries();this.collection.fetch({success:function(j){h.render()},error:function(k,j){e.error("An error occured. Please try again.")}})},render:function(i){var j=this.templateLibraryList();var k=null;var h=Galaxy.libraries.preferences.get("with_deleted");var l=null;if(typeof i!=="undefined"){h=typeof i.with_deleted!=="undefined"?i.with_deleted:false;l=typeof i.models!=="undefined"?i.models:null}if(this.collection!==null&&l===null){if(h){k=this.collection.models}else{k=this.collection.where({deleted:false})}}else{if(l!==null){k=l}else{k=[]}}this.$el.html(j({length:k.length,order:Galaxy.libraries.preferences.get("sort_order")}));if(k.length>0){this.renderRows(k)}$("#center [data-toggle]").tooltip();$("#center").css("overflow","auto")},renderRows:function(m){for(var l=0;lj.get("name").toLowerCase()){return 1}if(j.get("name").toLowerCase()>k.get("name").toLowerCase()){return -1}return 0}}else{if(h==="desc"){this.collection.comparator=function(k,j){if(k.get("name").toLowerCase()>j.get("name").toLowerCase()){return -1}if(j.get("name").toLowerCase()>k.get("name").toLowerCase()){return 1}return 0}}}this.collection.sort()}},templateLibraryList:function(){tmpl_array=[];tmpl_array.push('
');tmpl_array.push("<% if(length === 0) { %>");tmpl_array.push('
There are no libraries visible to you. If you expected some to show up please consult the library security wikipage.
');tmpl_array.push("<% } else{ %>");tmpl_array.push('');tmpl_array.push(" ");tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(" ");tmpl_array.push(' ');tmpl_array.push(" ");tmpl_array.push("
name descriptionsynopsis
");tmpl_array.push("<% }%>");tmpl_array.push("
");return _.template(tmpl_array.join(""))},templateNewLibraryInModal:function(){tmpl_array=[];tmpl_array.push('
');tmpl_array.push("
");tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push("
");tmpl_array.push("
");return tmpl_array.join("")},redirectToHome:function(){window.location="../"},redirectToLogin:function(){window.location="/user/login"},show_library_modal:function(i){i.preventDefault();i.stopPropagation();var h=this;this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Create New Library",body:this.templateNewLibraryInModal(),buttons:{Create:function(){h.create_new_library_event()},Close:function(){h.modal.hide()}}})},create_new_library_event:function(){var j=this.serialize_new_library();if(this.validate_new_library(j)){var i=new c.Library();var h=this;i.save(j,{success:function(k){h.collection.add(k);h.modal.hide();h.clear_library_modal();h.render();e.success("Library created")},error:function(){e.error("An error occured :(")}})}else{e.error("Library's name is missing")}return false},clear_library_modal:function(){$("input[name='Name']").val("");$("input[name='Description']").val("");$("input[name='Synopsis']").val("")},serialize_new_library:function(){return{name:$("input[name='Name']").val(),description:$("input[name='Description']").val(),synopsis:$("input[name='Synopsis']").val()}},validate_new_library:function(h){return h.name!==""}});return{LibraryListView:f}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/library/library-libraryrow-view.js b/static/scripts/packed/mvc/library/library-libraryrow-view.js index 00853bdb50c..b6572a33e35 100644 --- a/static/scripts/packed/mvc/library/library-libraryrow-view.js +++ b/static/scripts/packed/mvc/library/library-libraryrow-view.js @@ -1 +1 @@ -define(["galaxy.masthead","utils/utils","libs/toastr","mvc/library/library-model"],function(b,d,e,c){var a=Backbone.View.extend({events:{"click .edit_library_btn":"edit_button_clicked","click .cancel_library_btn":"cancel_library_modification","click .save_library_btn":"save_library_modification","click .delete_library_btn":"delete_library","click .undelete_library_btn":"undelete_library","click .upload_library_btn":"upload_to_library","click .permission_library_btn":"permissions_on_library"},edit_mode:false,element_visibility_config:{upload_library_btn:false,edit_library_btn:false,permission_library_btn:false,save_library_btn:false,cancel_library_btn:false,delete_library_btn:false,undelete_library_btn:false},initialize:function(f){this.render(f)},render:function(g){if(typeof g==="undefined"){var g=Galaxy.libraries.libraryListView.collection.get(this.$el.data("id"))}this.prepareButtons(g);var f=this.templateRow();this.setElement(f({library:g,button_config:this.element_visibility_config,edit_mode:this.edit_mode}));this.$el.show();return this},repaint:function(f){$(".tooltip").hide();var g=this.$el;this.render(f);g.replaceWith(this.$el);this.$el.find("[data-toggle]").tooltip()},prepareButtons:function(f){vis_config=this.element_visibility_config;if(this.edit_mode===false){vis_config.save_library_btn=false;vis_config.cancel_library_btn=false;vis_config.delete_library_btn=false;if(f.get("deleted")===true){vis_config.undelete_library_btn=true;vis_config.upload_library_btn=false;vis_config.edit_library_btn=false;vis_config.permission_library_btn=false}else{if(f.get("deleted")===false){vis_config.save_library_btn=false;vis_config.cancel_library_btn=false;vis_config.undelete_library_btn=false;if(f.get("can_user_add")===true){vis_config.upload_library_btn=true}if(f.get("can_user_modify")===true){vis_config.edit_library_btn=true}if(f.get("can_user_manage")===true){vis_config.permission_library_btn=true}}}}else{if(this.edit_mode===true){vis_config.upload_library_btn=false;vis_config.edit_library_btn=false;vis_config.permission_library_btn=false;vis_config.save_library_btn=true;vis_config.cancel_library_btn=true;vis_config.delete_library_btn=true}}this.element_visibility_config=vis_config},upload_to_library:function(){e.info("Coming soon. Stay tuned.")},permissions_on_library:function(){e.info("Coming soon. Stay tuned.")},edit_button_clicked:function(){this.edit_mode=true;this.repaint()},cancel_library_modification:function(){e.info("Modifications canceled");this.edit_mode=false;this.repaint()},save_library_modification:function(){var g=Galaxy.libraries.libraryListView.collection.get(this.$el.data("id"));var h=false;var j=this.$el.find(".input_library_name").val();if(typeof j!=="undefined"&&j!==g.get("name")){if(j.length>2){g.set("name",j);h=true}else{e.warning("Library name has to be at least 3 characters long");return}}var i=this.$el.find(".input_library_description").val();if(typeof i!=="undefined"&&i!==g.get("description")){g.set("description",i);h=true}var k=this.$el.find(".input_library_synopsis").val();if(typeof k!=="undefined"&&k!==g.get("synopsis")){g.set("synopsis",k);h=true}if(h){var f=this;g.save(null,{patch:true,success:function(l){f.edit_mode=false;f.repaint(l);e.success("Changes to library saved")},error:function(m,l){e.error("An error occured during updating the library :(")}})}else{this.edit_mode=false;this.repaint(g);e.info("Nothing has changed")}},delete_library:function(){var g=Galaxy.libraries.libraryListView.collection.get(this.$el.data("id"));var f=this;g.destroy({success:function(h){h.set("deleted",true);Galaxy.libraries.libraryListView.collection.add(h);f.edit_mode=false;if(Galaxy.libraries.preferences.get("with_deleted")===false){$(".tooltip").hide();f.$el.remove()}else{if(Galaxy.libraries.preferences.get("with_deleted")===true){f.repaint(h)}}e.success("Library has been marked deleted")},error:function(){e.error("An error occured during deleting the library :(")}})},undelete_library:function(){var g=Galaxy.libraries.libraryListView.collection.get(this.$el.data("id"));var f=this;g.url=g.urlRoot+g.id+"?undelete=true";g.destroy({success:function(h){h.set("deleted",false);Galaxy.libraries.libraryListView.collection.add(h);f.edit_mode=false;f.repaint(h);e.success("Library has been undeleted")},error:function(){e.error("An error occured while undeleting the library :(")}})},templateRow:function(){tmpl_array=[];tmpl_array.push(' " style="display:none;" data-id="<%- library.get("id") %>">');tmpl_array.push(" <% if(!edit_mode) { %>");tmpl_array.push(' "><%- library.get("name") %>');tmpl_array.push(' <%= _.escape(library.get("description")) %>');tmpl_array.push(' <%= _.escape(library.get("synopsis")) %>');tmpl_array.push(" <% } else if(edit_mode){ %>");tmpl_array.push(' ">');tmpl_array.push(' ">');tmpl_array.push(' ">');tmpl_array.push(" <% } %>");tmpl_array.push(' ');tmpl_array.push(' <% if(library.get("deleted") === true) { %>');tmpl_array.push(' ');tmpl_array.push(' <% } else if(library.get("public") === true) { %>');tmpl_array.push(' ');tmpl_array.push(" <% }%>");tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(" ");tmpl_array.push(" ");return _.template(tmpl_array.join(""))}});return{LibraryRowView: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({events:{"click .edit_library_btn":"edit_button_clicked","click .cancel_library_btn":"cancel_library_modification","click .save_library_btn":"save_library_modification","click .delete_library_btn":"delete_library","click .undelete_library_btn":"undelete_library","click .upload_library_btn":"upload_to_library","click .permission_library_btn":"permissions_on_library"},edit_mode:false,element_visibility_config:{upload_library_btn:false,edit_library_btn:false,permission_library_btn:false,save_library_btn:false,cancel_library_btn:false,delete_library_btn:false,undelete_library_btn:false},initialize:function(f){this.render(f)},render:function(g){if(typeof g==="undefined"){g=Galaxy.libraries.libraryListView.collection.get(this.$el.data("id"))}this.prepareButtons(g);var f=this.templateRow();this.setElement(f({library:g,button_config:this.element_visibility_config,edit_mode:this.edit_mode}));this.$el.show();return this},repaint:function(f){$(".tooltip").hide();var g=this.$el;this.render(f);g.replaceWith(this.$el);this.$el.find("[data-toggle]").tooltip()},prepareButtons:function(f){vis_config=this.element_visibility_config;if(this.edit_mode===false){vis_config.save_library_btn=false;vis_config.cancel_library_btn=false;vis_config.delete_library_btn=false;if(f.get("deleted")===true){vis_config.undelete_library_btn=true;vis_config.upload_library_btn=false;vis_config.edit_library_btn=false;vis_config.permission_library_btn=false}else{if(f.get("deleted")===false){vis_config.save_library_btn=false;vis_config.cancel_library_btn=false;vis_config.undelete_library_btn=false;if(f.get("can_user_add")===true){vis_config.upload_library_btn=true}if(f.get("can_user_modify")===true){vis_config.edit_library_btn=true}if(f.get("can_user_manage")===true){vis_config.permission_library_btn=true}}}}else{if(this.edit_mode===true){vis_config.upload_library_btn=false;vis_config.edit_library_btn=false;vis_config.permission_library_btn=false;vis_config.save_library_btn=true;vis_config.cancel_library_btn=true;vis_config.delete_library_btn=true}}this.element_visibility_config=vis_config},upload_to_library:function(){e.info("Coming soon. Stay tuned.")},permissions_on_library:function(){e.info("Coming soon. Stay tuned.")},edit_button_clicked:function(){this.edit_mode=true;this.repaint()},cancel_library_modification:function(){e.info("Modifications canceled");this.edit_mode=false;this.repaint()},save_library_modification:function(){var g=Galaxy.libraries.libraryListView.collection.get(this.$el.data("id"));var h=false;var j=this.$el.find(".input_library_name").val();if(typeof j!=="undefined"&&j!==g.get("name")){if(j.length>2){g.set("name",j);h=true}else{e.warning("Library name has to be at least 3 characters long");return}}var i=this.$el.find(".input_library_description").val();if(typeof i!=="undefined"&&i!==g.get("description")){g.set("description",i);h=true}var k=this.$el.find(".input_library_synopsis").val();if(typeof k!=="undefined"&&k!==g.get("synopsis")){g.set("synopsis",k);h=true}if(h){var f=this;g.save(null,{patch:true,success:function(l){f.edit_mode=false;f.repaint(l);e.success("Changes to library saved")},error:function(m,l){e.error("An error occured during updating the library :(")}})}else{this.edit_mode=false;this.repaint(g);e.info("Nothing has changed")}},delete_library:function(){var g=Galaxy.libraries.libraryListView.collection.get(this.$el.data("id"));var f=this;g.destroy({success:function(h){h.set("deleted",true);Galaxy.libraries.libraryListView.collection.add(h);f.edit_mode=false;if(Galaxy.libraries.preferences.get("with_deleted")===false){$(".tooltip").hide();f.$el.remove()}else{if(Galaxy.libraries.preferences.get("with_deleted")===true){f.repaint(h)}}e.success("Library has been marked deleted")},error:function(){e.error("An error occured during deleting the library :(")}})},undelete_library:function(){var g=Galaxy.libraries.libraryListView.collection.get(this.$el.data("id"));var f=this;g.url=g.urlRoot+g.id+"?undelete=true";g.destroy({success:function(h){h.set("deleted",false);Galaxy.libraries.libraryListView.collection.add(h);f.edit_mode=false;f.repaint(h);e.success("Library has been undeleted")},error:function(){e.error("An error occured while undeleting the library :(")}})},templateRow:function(){tmpl_array=[];tmpl_array.push(' " style="display:none;" data-id="<%- library.get("id") %>">');tmpl_array.push(" <% if(!edit_mode) { %>");tmpl_array.push(' "><%- library.get("name") %>');tmpl_array.push(' <%= _.escape(library.get("description")) %>');tmpl_array.push(' <%= _.escape(library.get("synopsis")) %>');tmpl_array.push(" <% } else if(edit_mode){ %>");tmpl_array.push(' ">');tmpl_array.push(' ">');tmpl_array.push(' ">');tmpl_array.push(" <% } %>");tmpl_array.push(' ');tmpl_array.push(' <% if(library.get("deleted") === true) { %>');tmpl_array.push(' ');tmpl_array.push(' <% } else if(library.get("public") === true) { %>');tmpl_array.push(' ');tmpl_array.push(" <% }%>");tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(" ");tmpl_array.push(" ");return _.template(tmpl_array.join(""))}});return{LibraryRowView:a}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/library/library-librarytoolbar-view.js b/static/scripts/packed/mvc/library/library-librarytoolbar-view.js index 64acfd29113..6369a270cc9 100644 --- a/static/scripts/packed/mvc/library/library-librarytoolbar-view.js +++ b/static/scripts/packed/mvc/library/library-librarytoolbar-view.js @@ -1 +1 @@ -define(["galaxy.masthead","utils/utils","libs/toastr","mvc/library/library-model"],function(a,d,e,c){var b=Backbone.View.extend({el:"#center",events:{"click #create_new_library_btn":"delegate_modal","click #include_deleted_chk":"check_include_deleted"},initialize:function(){this.render()},render:function(){var f=this.templateToolBar();this.$el.html(f({admin_user:Galaxy.currUser.isAdmin(),anon_user:Galaxy.currUser.isAnonymous()}));if(Galaxy.currUser.isAdmin()===true){this.$el.find("#include_deleted_chk")[0].checked=Galaxy.libraries.preferences.get("with_deleted")}},delegate_modal:function(f){Galaxy.libraries.libraryListView.show_library_modal(f)},check_include_deleted:function(f){if(f.target.checked){Galaxy.libraries.preferences.set({with_deleted:true});Galaxy.libraries.libraryListView.render()}else{Galaxy.libraries.preferences.set({with_deleted:false});Galaxy.libraries.libraryListView.render()}},templateToolBar:function(){tmpl_array=[];tmpl_array.push('
');tmpl_array.push('
');tmpl_array.push('

Data Libraries Beta Test. This is work in progress. Please report problems & ideas via email and Trello.

');tmpl_array.push(" <% if(admin_user === true) { %>");tmpl_array.push('
');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push("
");tmpl_array.push(" <% } %>");tmpl_array.push("
");tmpl_array.push('
');tmpl_array.push("
");tmpl_array.push("
");return _.template(tmpl_array.join(""))}});return{ToolbarView:b}}); \ No newline at end of file +define(["galaxy.masthead","utils/utils","libs/toastr","mvc/library/library-model"],function(a,c,d,b){var e=Backbone.View.extend({el:"#center",events:{"click #create_new_library_btn":"delegate_modal","click #include_deleted_chk":"check_include_deleted"},initialize:function(){this.render()},render:function(){var h=this.templateToolBar();var g=Galaxy.currUser.isAdmin();var f=Galaxy.currUser.isAnonymous();this.$el.html(h({admin_user:g,anon_user:f}));if(Galaxy.currUser.isAdmin()===true){this.$el.find("#include_deleted_chk")[0].checked=Galaxy.libraries.preferences.get("with_deleted")}},delegate_modal:function(f){Galaxy.libraries.libraryListView.show_library_modal(f)},check_include_deleted:function(f){if(f.target.checked){Galaxy.libraries.preferences.set({with_deleted:true});Galaxy.libraries.libraryListView.render()}else{Galaxy.libraries.preferences.set({with_deleted:false});Galaxy.libraries.libraryListView.render()}},templateToolBar:function(){tmpl_array=[];tmpl_array.push('
');tmpl_array.push('
');tmpl_array.push('

Data Libraries Beta Test. This is work in progress. Please report problems & ideas via email and Trello.

');tmpl_array.push(" <% if(admin_user === true) { %>");tmpl_array.push('
');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push("
");tmpl_array.push(" <% } %>");tmpl_array.push("
");tmpl_array.push('
');tmpl_array.push("
");tmpl_array.push("
");return _.template(tmpl_array.join(""))}});return{LibraryToolbarView:e}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/library/library-model.js b/static/scripts/packed/mvc/library/library-model.js index bd1d114f95e..a752fc3d196 100644 --- a/static/scripts/packed/mvc/library/library-model.js +++ b/static/scripts/packed/mvc/library/library-model.js @@ -1 +1 @@ -define([],function(){var e=Backbone.Model.extend({urlRoot:"/api/libraries/",isVisible:function(k){var j=true;if((!show_delete)&&(this.get("deleted"))){j=false}return j}});var a=Backbone.Model.extend({urlRoot:"/api/folders"});var h=Backbone.Collection.extend({url:"/api/libraries",model:e,sort_key:"name",sort_order:null,initialize:function(j){j=j||{}},getVisible:function(k,l){l=l||[];var j=new h(this.filter(function(m){return m.isVisible(k)}));return j}});var f=Backbone.Model.extend({urlRoot:"/api/libraries/datasets"});var c=Backbone.Collection.extend({model:f});var d=Backbone.Model.extend({defaults:{folder:new c(),full_path:"unknown",urlRoot:"/api/folders/",id:"unknown"},parse:function(j){this.full_path=j[0].full_path;this.get("folder").reset(j[1].folder_contents);return j}});var b=Backbone.Model.extend({urlRoot:"/api/histories/"});var g=Backbone.Model.extend({url:"/api/histories/"});var i=Backbone.Collection.extend({url:"/api/histories",model:g});return{Library:e,FolderAsModel:a,Libraries:h,Item:f,Folder:c,FolderContainer:d,HistoryItem:b,GalaxyHistory:g,GalaxyHistories:i}}); \ No newline at end of file +define([],function(){var e=Backbone.Model.extend({urlRoot:"/api/libraries/",isVisible:function(k){var j=true;if((!show_delete)&&(this.get("deleted"))){j=false}return j}});var a=Backbone.Model.extend({urlRoot:"/api/folders"});var h=Backbone.Collection.extend({url:"/api/libraries",model:e,sort_key:"name",sort_order:null,initialize:function(j){j=j||{}},getVisible:function(k,l){l=l||[];var j=new h(this.filter(function(m){return m.isVisible(k)}));return j}});var f=Backbone.Model.extend({urlRoot:"/api/libraries/datasets"});var c=Backbone.Collection.extend({model:f});var d=Backbone.Model.extend({defaults:{folder:new c(),urlRoot:"/api/folders/",id:"unknown"},parse:function(j){this.get("folder").reset(j.folder_contents);return j}});var b=Backbone.Model.extend({urlRoot:"/api/histories/"});var g=Backbone.Model.extend({url:"/api/histories/"});var i=Backbone.Collection.extend({url:"/api/histories",model:g});return{Library:e,FolderAsModel:a,Libraries:h,Item:f,Folder:c,FolderContainer:d,HistoryItem:b,GalaxyHistory:g,GalaxyHistories:i}}); \ No newline at end of file diff --git a/static/style/blue/base.css b/static/style/blue/base.css index deef41dd0e1..6b043bf9e0d 100644 --- a/static/style/blue/base.css +++ b/static/style/blue/base.css @@ -1299,6 +1299,7 @@ td.right-center{vertical-align:middle !important;text-align:right} .library_table td{border-top:1px solid #5f6990 !important} .library_table th{border-bottom:2px solid #5f6990 !important} .library_table a{color:#0A143D}.library_table a:hover{color:maroon} +.library_style_container{width:95%;margin:auto;margin-top:2em;overflow:auto !important} tr.light td{background-color:white;color:black} tr.light:hover td{background-color:#f5e8cc} tr.dark td{background-color:#d6b161;color:white} diff --git a/static/style/blue/library.css b/static/style/blue/library.css index 83979d703f5..bb0e982e116 100644 --- a/static/style/blue/library.css +++ b/static/style/blue/library.css @@ -10,6 +10,7 @@ td.right-center{vertical-align:middle !important;text-align:right} .library_table td{border-top:1px solid #5f6990 !important} .library_table th{border-bottom:2px solid #5f6990 !important} .library_table a{color:#0A143D}.library_table a:hover{color:maroon} +.library_style_container{width:95%;margin:auto;margin-top:2em;overflow:auto !important} tr.light td{background-color:white;color:black} tr.light:hover td{background-color:#f5e8cc} tr.dark td{background-color:#d6b161;color:white} diff --git a/static/style/src/less/library.less b/static/style/src/less/library.less index ccd059e920b..9d1a83c0625 100644 --- a/static/style/src/less/library.less +++ b/static/style/src/less/library.less @@ -49,6 +49,12 @@ td.right-center{ } } } +.library_style_container{ + width: 95%; + margin: auto; + margin-top:2em; + overflow: auto !important; +} tr.light td { From 4bea6249f32616bb3fe79d7c3b7f50e13e15bd77 Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Thu, 10 Apr 2014 15:07:01 -0400 Subject: [PATCH 10/16] forgotten files for previous commit data libraries: API refactoring and improvements; backbone decoupling; role UI first implementation --- .../mvc/library/library-folderrow-view.js | 310 +++++++++++++++++ .../mvc/library/library-foldertoolbar-view.js | 320 ++++++++++++++++++ .../mvc/library/library-folderrow-view.js | 1 + .../mvc/library/library-foldertoolbar-view.js | 1 + 4 files changed, 632 insertions(+) create mode 100644 static/scripts/mvc/library/library-folderrow-view.js create mode 100644 static/scripts/mvc/library/library-foldertoolbar-view.js create mode 100644 static/scripts/packed/mvc/library/library-folderrow-view.js create mode 100644 static/scripts/packed/mvc/library/library-foldertoolbar-view.js diff --git a/static/scripts/mvc/library/library-folderrow-view.js b/static/scripts/mvc/library/library-folderrow-view.js new file mode 100644 index 00000000000..70b4fb9b61f --- /dev/null +++ b/static/scripts/mvc/library/library-folderrow-view.js @@ -0,0 +1,310 @@ +// dependencies +define([ + "galaxy.masthead", + "utils/utils", + "libs/toastr", + "mvc/library/library-model"], +function(mod_masthead, + mod_utils, + mod_toastr, + mod_library_model) { + +// galaxy library row view +var FolderRowView = Backbone.View.extend({ + // last selected history in modal for UX + lastSelectedHistory: '', + + events: { + 'click .library-dataset' : 'showDatasetDetails' + }, + + options: { + type: null + }, + + initialize : function(folder_item){ + this.render(folder_item); + }, + + render: function(folder_item){ + // if (typeof folder_item === 'undefined'){ + // folder_item = Galaxy.libraries.libraryFolderView.collection.get(this.$el.data('id')); + // } + var template = null; + if (folder_item.get('type') === 'folder'){ + this.options.type = 'folder'; + template = this.templateRowFolder(); + } else { + this.options.type = 'file'; + template = this.templateRowFile(); + } + this.setElement(template({content_item:folder_item})); + this.$el.show(); + return this; + }, + + //show modal with current dataset info + showDatasetDetails : function(event){ + // prevent default + event.preventDefault(); + + var id = this.id; + + //create new item + var item = new mod_library_model.Item(); + var histories = new mod_library_model.GalaxyHistories(); + item.id = id; + var self = this; + + //fetch the dataset info + item.fetch({ + success: function (item) { + // TODO can start rendering here already + //fetch user histories for import purposes + histories.fetch({ + success: function (histories){ + self.renderModalAfterFetch(item, histories); + }, + error: function(){ + mod_toastr.error('An error occured during fetching histories:('); + self.renderModalAfterFetch(item); + } + }); + }, + error: function(){ + mod_toastr.error('An error occured during loading dataset details :('); + } + }); +}, + + // show the current dataset in a modal + renderModalAfterFetch : function(item, histories){ + var size = this.size_to_string(item.get('file_size')); + var template = _.template(this.templateDatasetModal(), { item : item, size : size }); + // make modal + var self = this; + this.modal = Galaxy.modal; + this.modal.show({ + closing_events : true, + title : 'Dataset Details', + body : template, + buttons : { + 'Import' : function() { self.importCurrentIntoHistory(); }, + 'Download' : function() { self.downloadCurrent(); }, + 'Close' : function() { self.modal.hide(); } + } + }); + + $(".peek").html(item.get("peek")); + + // show the import-into-history footer only if the request for histories succeeded + if (typeof history.models !== undefined){ + var history_footer_tmpl = _.template(this.templateHistorySelectInModal(), {histories : histories.models}); + $(this.modal.elMain).find('.buttons').prepend(history_footer_tmpl); + // preset last selected history if we know it + if (self.lastSelectedHistory.length > 0) { + $(this.modal.elMain).find('#dataset_import_single').val(self.lastSelectedHistory); + } + } + }, + + // TODO this is dup func, unify + // convert size to nice string + size_to_string : function (size){ + // identify unit + var unit = ""; + if (size >= 100000000000) { size = size / 100000000000; unit = "TB"; } else + if (size >= 100000000) { size = size / 100000000; unit = "GB"; } else + if (size >= 100000) { size = size / 100000; unit = "MB"; } else + if (size >= 100) { size = size / 100; unit = "KB"; } else + { size = size * 10; unit = "b"; } + // return formatted string + return (Math.round(size) / 10) + unit; + }, + + // download dataset shown currently in modal + downloadCurrent : function(){ + //disable the buttons + this.modal.disableButton('Import'); + this.modal.disableButton('Download'); + + var library_dataset_id = []; + library_dataset_id.push($('#id_row').attr('data-id')); + var url = '/api/libraries/datasets/download/uncompressed'; + var data = {'ldda_ids' : library_dataset_id}; + + this.processDownload(url, data); + this.modal.enableButton('Import'); + this.modal.enableButton('Download'); + }, + + // TODO this is dup func, unify + // create hidden form and submit through POST to initialize download + processDownload: function(url, data, method){ + //url and data options required + if( url && data ){ + //data can be string of parameters or array/object + data = typeof data == 'string' ? data : $.param(data); + //split params into form inputs + var inputs = ''; + $.each(data.split('&'), function(){ + var pair = this.split('='); + inputs+=''; + }); + //send request + $('
'+inputs+'
') + .appendTo('body').submit().remove(); + + mod_toastr.info('Your download will begin soon'); + } + }, + + // import dataset shown currently in modal into selected history + importCurrentIntoHistory : function(){ + //disable the buttons + this.modal.disableButton('Import'); + this.modal.disableButton('Download'); + + var history_id = $(this.modal.elMain).find('select[name=dataset_import_single] option:selected').val(); + this.lastSelectedHistory = history_id; //save selected history for further use + + var library_dataset_id = $('#id_row').attr('data-id'); + var historyItem = new mod_library_model.HistoryItem(); + var self = this; + historyItem.url = historyItem.urlRoot + history_id + '/contents'; + + // save the dataset into selected history + historyItem.save({ content : library_dataset_id, source : 'library' }, { success : function(){ + mod_toastr.success('Dataset imported'); + //enable the buttons + self.modal.enableButton('Import'); + self.modal.enableButton('Download'); + }, error : function(){ + mod_toastr.error('An error occured! Dataset not imported. Please try again.'); + //enable the buttons + self.modal.enableButton('Import'); + self.modal.enableButton('Download'); + } + }); + }, + + templateRowFolder: function() { + tmpl_array = []; + + tmpl_array.push(''); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' <%- content_item.get("name") %>'); + tmpl_array.push(' <% if (content_item.get("item_count") === 0) { %>'); // empty folder + tmpl_array.push(' (empty folder)'); + tmpl_array.push(' <% } %>'); + tmpl_array.push(' '); + tmpl_array.push(' folder'); + tmpl_array.push(' <%= _.escape(content_item.get("item_count")) %> item(s)'); // size + tmpl_array.push(' <%= _.escape(content_item.get("time_updated")) %>'); // time updated + tmpl_array.push(''); + + return _.template(tmpl_array.join('')); + }, + + templateRowFile: function(){ + tmpl_array = []; + + tmpl_array.push(''); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' <%- content_item.get("name") %>'); // dataset + tmpl_array.push(' <%= _.escape(content_item.get("data_type")) %>'); // data type + tmpl_array.push(' <%= _.escape(content_item.get("readable_size")) %>'); // size + tmpl_array.push(' <%= _.escape(content_item.get("time_updated")) %>'); // time updated + tmpl_array.push(''); + + return _.template(tmpl_array.join('')); + }, + +templateDatasetModal : function(){ + var tmpl_array = []; + + tmpl_array.push(''); + + return tmpl_array.join(''); +}, + +templateHistorySelectInModal : function(){ + var tmpl_array = []; + + tmpl_array.push(''); + tmpl_array.push('Select history: '); + tmpl_array.push(''); + tmpl_array.push(''); + + return tmpl_array.join(''); +} + +}); + +return { + FolderRowView: FolderRowView +}; + +}); diff --git a/static/scripts/mvc/library/library-foldertoolbar-view.js b/static/scripts/mvc/library/library-foldertoolbar-view.js new file mode 100644 index 00000000000..7b702a782dd --- /dev/null +++ b/static/scripts/mvc/library/library-foldertoolbar-view.js @@ -0,0 +1,320 @@ +// dependencies +define([ + "galaxy.masthead", + "utils/utils", + "libs/toastr", + "mvc/library/library-model"], +function(mod_masthead, + mod_utils, + mod_toastr, + mod_library_model) { + +var FolderToolbarView = Backbone.View.extend({ + el: '#center', + + events: { + 'click #toolbtn_create_folder' : 'createFolderFromModal', + 'click #toolbtn_bulk_import' : 'modalBulkImport' + }, + + defaults: { + 'can_add_library_item' : false, + 'contains_file' : false + }, + + modal : null, + + initialize: function(options){ + this.options = _.defaults(options || {}, this.defaults); + this.render(); + }, + + render: function(options){ + this.options = _.extend(this.options, options); + var toolbar_template = this.templateToolBar(); + var is_admin = Galaxy.currUser.isAdmin(); + this.$el.html(toolbar_template({id: this.options.id, admin_user: is_admin})); + }, + + configureElements: function(options){ + this.options = _.extend(this.options, options); + if (this.options.can_add_library_item === true){ + $('#toolbtn_create_folder').show(); + $('#toolbtn_upload_files').show(); + } + if (this.options.contains_file === true){ + $('#toolbtn_bulk_import').show(); + $('#toolbtn_dl').show(); + } + this.$el.find('[data-toggle]').tooltip(); + }, + + // shows modal for creating folder + createFolderFromModal: function(){ + event.preventDefault(); + event.stopPropagation(); + + // create modal + var self = this; + var template = this.templateNewFolderInModal(); + this.modal = Galaxy.modal; + this.modal.show({ + closing_events : true, + title : 'Create New Folder', + body : template(), + buttons : { + 'Create' : function() {self.create_new_folder_event();}, + 'Close' : function() {self.modal.hide(); self.modal = null;} + } + }); + }, + + // create the new folder from modal + create_new_folder_event: function(){ + var folderDetails = this.serialize_new_folder(); + if (this.validate_new_folder(folderDetails)){ + var folder = new mod_library_model.FolderAsModel(); + url_items = Backbone.history.fragment.split('/'); + 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(); + mod_toastr.success('Folder created'); + Galaxy.libraries.folderListView.render({id: current_folder_id}); + }, + error: function(){ + mod_toastr.error('An error occured :('); + } + }); + } else { + mod_toastr.error('Folder\'s name is missing'); + } + return false; + }, + + // serialize data from the modal + serialize_new_folder : function(){ + return { + name: $("input[name='Name']").val(), + description: $("input[name='Description']").val() + }; + }, + + // validate new folder info + validate_new_folder: function(folderDetails){ + return folderDetails.name !== ''; + }, + + + // show bulk import modal + modalBulkImport : function(){ + var checkedValues = $('#folder_table').find(':checked'); + if(checkedValues.length === 0){ + mod_toastr.info('You have to select some datasets first'); + } else { + var self = this; + // fetch histories + var template = this.templateBulkImportInModal(); + var histories = new mod_library_model.GalaxyHistories(); + histories.fetch({ + success: function (histories){ + // make modal + // var history_modal_tmpl = template({histories : histories.models}); + self.modal = Galaxy.modal; + self.modal.show({ + closing_events : true, + title : 'Import into History', + body : template({histories : histories.models}), + buttons : { + 'Import' : function() {self.importAllIntoHistory();}, + 'Close' : function() {self.modal.hide();} + } + }); + }, + error: function(){ + mod_toastr.error('An error occured :('); + } + }); + } + }, + + // import all selected datasets into history + importAllIntoHistory : function (){ + //disable the button to prevent multiple submission + this.modal.disableButton('Import'); + + var history_id = $("select[name=dataset_import_bulk] option:selected").val(); + var history_name = $("select[name=dataset_import_bulk] option:selected").text(); + + var dataset_ids = []; + $('#folder_table').find(':checked').each(function(){ + if (this.parentElement.parentElement.id !== '') { + dataset_ids.push(this.parentElement.parentElement.id); + } + }); + var progress_bar_tmpl = this.templateProgressBar(); + $(this.modal.elMain).find('.modal-body').html(progress_bar_tmpl({ history_name : history_name })); + + // init the progress bar + var progressStep = 100 / dataset_ids.length; + this.initProgress(progressStep); + + // prepare the dataset objects to be imported + var datasets_to_import = []; + for (var i = dataset_ids.length - 1; i >= 0; i--) { + library_dataset_id = dataset_ids[i]; + var historyItem = new mod_library_model.HistoryItem(); + var self = this; + historyItem.url = historyItem.urlRoot + history_id + '/contents'; + historyItem.content = library_dataset_id; + historyItem.source = 'library'; + datasets_to_import.push(historyItem); + } + // call the recursive function to call ajax one after each other (request FIFO queue) + this.chainCall(datasets_to_import); + }, + + chainCall: function(history_item_set){ + var self = this; + var popped_item = history_item_set.pop(); + if (typeof popped_item === "undefined") { + mod_toastr.success('All datasets imported'); + this.modal.hide(); + return; + } + var promise = $.when(popped_item.save({content: popped_item.content, source: popped_item.source})).done(function(a1){ + self.updateProgress(); + self.chainCall(history_item_set); + }); + }, + + initProgress: function(progressStep){ + this.progress = 0; + this.progressStep = progressStep; + }, + + 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 selected datasets + download : function(folder_id, format){ + var dataset_ids = []; + $('#folder_table').find(':checked').each(function(){ + if (this.parentElement.parentElement.id !== '') { + dataset_ids.push(this.parentElement.parentElement.id); + } + }); + + var url = '/api/libraries/datasets/download/' + format; + var data = {'ldda_ids' : dataset_ids}; + this.processDownload(url, data, 'get'); + }, + + // create hidden form and submit through POST to initialize download + processDownload: function(url, data, method){ + //url and data options required + if( url && data ){ + //data can be string of parameters or array/object + data = typeof data == 'string' ? data : $.param(data); + //split params into form inputs + var inputs = ''; + $.each(data.split('&'), function(){ + var pair = this.split('='); + inputs+=''; + }); + //send request + $('
'+inputs+'
') + .appendTo('body').submit().remove(); + + mod_toastr.info('Your download will begin soon'); + } + }, + + templateToolBar: function(){ + tmpl_array = []; + + // CONTAINER + tmpl_array.push('
'); + tmpl_array.push('

Data Libraries Beta Test. This is work in progress. Please report problems & ideas via email and Trello.

'); + // TOOLBAR + tmpl_array.push('
'); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push(' '); + tmpl_array.push('
'); + tmpl_array.push('
'); + // library items will append here + tmpl_array.push('
'); + tmpl_array.push('
'); + + return _.template(tmpl_array.join('')); + }, + + templateNewFolderInModal: function(){ + tmpl_array = []; + + tmpl_array.push('
'); + tmpl_array.push('
'); + tmpl_array.push(''); + tmpl_array.push(''); + tmpl_array.push('
'); + tmpl_array.push('
'); + + return _.template(tmpl_array.join('')); + }, + + + templateBulkImportInModal : function(){ + var tmpl_array = []; + + tmpl_array.push(''); + tmpl_array.push('Select history: '); + tmpl_array.push(''); + tmpl_array.push(''); + + return _.template(tmpl_array.join('')); + }, + + templateProgressBar : function (){ + var tmpl_array = []; + + tmpl_array.push('
'); + tmpl_array.push('Importing selected datasets to history <%= _.escape(history_name) %>'); + tmpl_array.push('
'); + tmpl_array.push('
'); + tmpl_array.push('
'); + tmpl_array.push(' 0% Complete'); + tmpl_array.push('
'); + tmpl_array.push('
'); + tmpl_array.push(''); + + return _.template(tmpl_array.join('')); + } +}); + +return { + FolderToolbarView: FolderToolbarView +}; + +}); diff --git a/static/scripts/packed/mvc/library/library-folderrow-view.js b/static/scripts/packed/mvc/library/library-folderrow-view.js new file mode 100644 index 00000000000..47fd065beab --- /dev/null +++ b/static/scripts/packed/mvc/library/library-folderrow-view.js @@ -0,0 +1 @@ +define(["galaxy.masthead","utils/utils","libs/toastr","mvc/library/library-model"],function(b,d,e,c){var a=Backbone.View.extend({lastSelectedHistory:"",events:{"click .library-dataset":"showDatasetDetails"},options:{type:null},initialize:function(f){this.render(f)},render:function(f){var g=null;if(f.get("type")==="folder"){this.options.type="folder";g=this.templateRowFolder()}else{this.options.type="file";g=this.templateRowFile()}this.setElement(g({content_item:f}));this.$el.show();return this},showDatasetDetails:function(i){i.preventDefault();var j=this.id;var h=new c.Item();var g=new c.GalaxyHistories();h.id=j;var f=this;h.fetch({success:function(k){g.fetch({success:function(l){f.renderModalAfterFetch(k,l)},error:function(){e.error("An error occured during fetching histories:(");f.renderModalAfterFetch(k)}})},error:function(){e.error("An error occured during loading dataset details :(")}})},renderModalAfterFetch:function(k,h){var i=this.size_to_string(k.get("file_size"));var j=_.template(this.templateDatasetModal(),{item:k,size:i});var g=this;this.modal=Galaxy.modal;this.modal.show({closing_events:true,title:"Dataset Details",body:j,buttons:{Import:function(){g.importCurrentIntoHistory()},Download:function(){g.downloadCurrent()},Close:function(){g.modal.hide()}}});$(".peek").html(k.get("peek"));if(typeof history.models!==undefined){var f=_.template(this.templateHistorySelectInModal(),{histories:h.models});$(this.modal.elMain).find(".buttons").prepend(f);if(g.lastSelectedHistory.length>0){$(this.modal.elMain).find("#dataset_import_single").val(g.lastSelectedHistory)}}},size_to_string:function(f){var g="";if(f>=100000000000){f=f/100000000000;g="TB"}else{if(f>=100000000){f=f/100000000;g="GB"}else{if(f>=100000){f=f/100000;g="MB"}else{if(f>=100){f=f/100;g="KB"}else{f=f*10;g="b"}}}}return(Math.round(f)/10)+g},downloadCurrent:function(){this.modal.disableButton("Import");this.modal.disableButton("Download");var f=[];f.push($("#id_row").attr("data-id"));var g="/api/libraries/datasets/download/uncompressed";var h={ldda_ids:f};this.processDownload(g,h);this.modal.enableButton("Import");this.modal.enableButton("Download")},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+=''});$('
'+f+"
").appendTo("body").submit().remove();e.info("Your download will begin soon")}},importCurrentIntoHistory:function(){this.modal.disableButton("Import");this.modal.disableButton("Download");var h=$(this.modal.elMain).find("select[name=dataset_import_single] option:selected").val();this.lastSelectedHistory=h;var f=$("#id_row").attr("data-id");var i=new c.HistoryItem();var g=this;i.url=i.urlRoot+h+"/contents";i.save({content:f,source:"library"},{success:function(){e.success("Dataset imported");g.modal.enableButton("Import");g.modal.enableButton("Download")},error:function(){e.error("An error occured! Dataset not imported. Please try again.");g.modal.enableButton("Import");g.modal.enableButton("Download")}})},templateRowFolder:function(){tmpl_array=[];tmpl_array.push('');tmpl_array.push(" ");tmpl_array.push(' ');tmpl_array.push(" ");tmpl_array.push(" ");tmpl_array.push(" ");tmpl_array.push(' <%- content_item.get("name") %>');tmpl_array.push(' <% if (content_item.get("item_count") === 0) { %>');tmpl_array.push(" (empty folder)");tmpl_array.push(" <% } %>");tmpl_array.push(" ");tmpl_array.push(" folder");tmpl_array.push(' <%= _.escape(content_item.get("item_count")) %> item(s)');tmpl_array.push(' <%= _.escape(content_item.get("time_updated")) %>');tmpl_array.push("");return _.template(tmpl_array.join(""))},templateRowFile:function(){tmpl_array=[];tmpl_array.push('');tmpl_array.push(" ");tmpl_array.push(' ');tmpl_array.push(" ");tmpl_array.push(' ');tmpl_array.push(' <%- content_item.get("name") %>');tmpl_array.push(' <%= _.escape(content_item.get("data_type")) %>');tmpl_array.push(' <%= _.escape(content_item.get("readable_size")) %>');tmpl_array.push(' <%= _.escape(content_item.get("time_updated")) %>');tmpl_array.push("");return _.template(tmpl_array.join(""))},templateDatasetModal:function(){var f=[];f.push('");return f.join("")},templateHistorySelectInModal:function(){var f=[];f.push('');f.push("Select history: ");f.push('");f.push("");return f.join("")}});return{FolderRowView:a}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/library/library-foldertoolbar-view.js b/static/scripts/packed/mvc/library/library-foldertoolbar-view.js new file mode 100644 index 00000000000..b673edc51fe --- /dev/null +++ b/static/scripts/packed/mvc/library/library-foldertoolbar-view.js @@ -0,0 +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"},defaults:{can_add_library_item:false,contains_file:false},modal: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=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_upload_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(){f.modal.hide();f.modal=null}}})},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");Galaxy.libraries.folderListView.render({id:current_folder_id})},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{var h=this;var i=this.templateBulkImportInModal();var g=new c.GalaxyHistories();g.fetch({success:function(j){h.modal=Galaxy.modal;h.modal.show({closing_events:true,title:"Import into History",body:i({histories:j.models}),buttons:{Import:function(){h.importAllIntoHistory()},Close:function(){h.modal.hide()}}})},error:function(){e.error("An error occured :(")}})}},importAllIntoHistory:function(){this.modal.disableButton("Import");var h=$("select[name=dataset_import_bulk] option:selected").val();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.templateProgressBar();$(this.modal.elMain).find(".modal-body").html(n({history_name:m}));var j=100/o.length;this.initProgress(j);var f=[];for(var g=o.length-1;g>=0;g--){library_dataset_id=o[g];var k=new c.HistoryItem();var l=this;k.url=k.urlRoot+h+"/contents";k.content=library_dataset_id;k.source="library";f.push(k)}this.chainCall(f)},chainCall:function(g){var f=this;var h=g.pop();if(typeof h==="undefined"){e.success("All datasets imported");this.modal.hide();return}var i=$.when(h.save({content:h.content,source:h.source})).done(function(j){f.updateProgress();f.chainCall(g)})},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+=''});$('
'+f+"
").appendTo("body").submit().remove();e.info("Your download will begin soon")}},templateToolBar:function(){tmpl_array=[];tmpl_array.push('
');tmpl_array.push('

Data Libraries Beta Test. This is work in progress. Please report problems & ideas via email and Trello.

');tmpl_array.push('
');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ');tmpl_array.push(' ");tmpl_array.push("
");tmpl_array.push('
');tmpl_array.push("
");tmpl_array.push("
");return _.template(tmpl_array.join(""))},templateNewFolderInModal:function(){tmpl_array=[];tmpl_array.push('
');tmpl_array.push("
");tmpl_array.push('');tmpl_array.push('');tmpl_array.push("
");tmpl_array.push("
");return _.template(tmpl_array.join(""))},templateBulkImportInModal:function(){var f=[];f.push('');f.push("Select history: ");f.push('");f.push("");return _.template(f.join(""))},templateProgressBar:function(){var f=[];f.push('
');f.push("Importing selected datasets to history <%= _.escape(history_name) %>");f.push("
");f.push('
');f.push('
');f.push(' 0% Complete');f.push("
");f.push("
");f.push("");return _.template(f.join(""))}});return{FolderToolbarView:a}}); \ No newline at end of file From c3a29f9fb6d65509e35ece9043f7ae5776add5bd Mon Sep 17 00:00:00 2001 From: Daniel Blankenberg Date: Thu, 10 Apr 2014 15:55:26 -0400 Subject: [PATCH 11/16] Add a link to a tool's toolshed repository if it was installed from a ToolShed. --- templates/webapps/galaxy/tool_form.mako | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/templates/webapps/galaxy/tool_form.mako b/templates/webapps/galaxy/tool_form.mako index 3cc057e261e..54e22ed8372 100644 --- a/templates/webapps/galaxy/tool_form.mako +++ b/templates/webapps/galaxy/tool_form.mako @@ -378,3 +378,10 @@
%endif +%if tool.tool_shed_repository: + <% tool_url = tool.tool_shed_repository.get_sharable_url( tool.app ) %> + %if tool_url: +
+ ${ render_msg( 'This tool was installed from a ToolShed, you may be able to find additional information by following this link: %s' % ( tool_url, tool_url ), 'info' ) } + %endif +%endif From 8f179efe715b6b1132fe3166551336b2df51891f Mon Sep 17 00:00:00 2001 From: Carl Eberhard Date: Thu, 10 Apr 2014 16:28:16 -0400 Subject: [PATCH 12/16] Metrics: initial commit of client side logger --- .../packed/galaxy.workflow_editor.canvas.js | 2 +- static/scripts/packed/galaxy.workflows.js | 2 +- static/scripts/packed/utils/metrics-logger.js | 1 + static/scripts/utils/metrics-logger.js | 386 ++++++++++++++++++ 4 files changed, 389 insertions(+), 2 deletions(-) create mode 100644 static/scripts/packed/utils/metrics-logger.js create mode 100644 static/scripts/utils/metrics-logger.js diff --git a/static/scripts/packed/galaxy.workflow_editor.canvas.js b/static/scripts/packed/galaxy.workflow_editor.canvas.js index a15d9116073..2536ea4b2a6 100644 --- a/static/scripts/packed/galaxy.workflow_editor.canvas.js +++ b/static/scripts/packed/galaxy.workflow_editor.canvas.js @@ -1 +1 @@ -function Terminal(a){this.element=a;this.connectors=[]}$.extend(Terminal.prototype,{connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}});function OutputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}OutputTerminal.prototype=new Terminal();function InputTerminal(b,c,a){Terminal.call(this,b);this.datatypes=c;this.multiple=a}InputTerminal.prototype=new Terminal();$.extend(InputTerminal.prototype,{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()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{new_input_terminal:function(a){var b=$("
");this.enable_input_terminal(b,a.name,a.extensions,a.multiple);return b},enable_input_terminal:function(f,b,c,a){var d=this;$(f).each(function(){var g=this.terminal=new InputTerminal(this,c,a);g.node=d;g.name=b;$(this).bind("dropinit",function(h,i){return $(i.drag).hasClass("output-terminal")&&g.can_accept(i.drag.terminal)}).bind("dropstart",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#BBFFBB"}}).bind("dropend",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#FFFFFF"}}).bind("drop",function(h,i){(new Connector(i.drag.terminal,g)).redraw()}).bind("hover",function(){if(g.connectors.length>0){var h=$("
").css({display:"none"}).appendTo("body").append($("
").append($("
").addClass("fa-icon-button fa fa-times").click(function(){$.each(g.connectors,function(j,i){if(i){i.destroy()}});h.remove()}))).bind("mouseleave",function(){$(this).remove()});h.css({top:$(this).offset().top-2,left:$(this).offset().left-h.width(),"padding-right":$(this).width()}).show()}});d.input_terminals[b]=g})},enable_output_terminal:function(d,a,b){var c=this;$(d).each(function(){var g=this;var f=this.terminal=new OutputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dragstart",function(j,k){$(k.available).addClass("input-terminal-active");workflow.check_changes_in_active_form();var i=$('
').appendTo("#canvas-container").get(0);i.terminal=new OutputTerminal(i);var l=new Connector();l.dragging=true;l.connect(this.terminal,i.terminal);return i}).bind("drag",function(i,j){var h=function(){var l=$(j.proxy).offsetParent().offset(),k=j.offsetX-l.left,m=j.offsetY-l.top;$(j.proxy).css({left:k,top:m});j.proxy.terminal.redraw();canvas_manager.update_viewport_overlay()};h();$("#canvas-container").get(0).scroll_panel.test(i,h)}).bind("dragend",function(h,i){i.proxy.terminal.connectors[0].destroy();$(i.proxy).remove();$(i.available).removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()});c.output_terminals[a]=f})},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(h){var g=this.element;if(h.type){this.type=h.type}this.name=h.name;this.form_html=h.form_html;this.tool_state=h.tool_state;this.tool_errors=h.tool_errors;this.tooltip=h.tooltip?h.tooltip:"";this.annotation=h.annotation;this.post_job_actions=h.post_job_actions?h.post_job_actions:{};this.workflow_outputs=h.workflow_outputs?h.workflow_outputs:[];if(this.tool_errors){g.addClass("tool-node-error")}else{g.removeClass("tool-node-error")}var d=this;var c=Math.max(150,g.width());var a=g.find(".toolFormBody");a.find("div").remove();var i=$("
").appendTo(a);$.each(h.data_inputs,function(k,f){var j=d.new_input_terminal(f);var b=$("
"+f.label+"
");b.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(b);c=Math.max(c,b.outerWidth());b.css({position:"",left:"",top:"",display:""});b.remove();i.append(b.prepend(j))});if((h.data_inputs.length>0)&&(h.data_outputs.length>0)){a.append($("
"))}$.each(h.data_outputs,function(k,b){var j=$("
");d.enable_output_terminal(j,b.name,b.extensions);var f=b.name;if(b.extensions.indexOf("input")<0){f=f+" ("+b.extensions.join(", ")+")"}var m=$("
"+f+"
");if(d.type=="tool"){var l=$("
").css({display:"none"}).append($("
").append($("").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png").click(function(){if($.inArray(b.name,d.workflow_outputs)!=-1){d.workflow_outputs.splice($.inArray(b.name,d.workflow_outputs),1);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{d.workflow_outputs.push(b.name);l.find("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."});l.css({top:"50%",margin:"-8px 0px 0px 0px",right:8});l.show();m.append(l);if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}m.hover(function(){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-yellow.png")},function(){if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}})}m.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(m);c=Math.max(c,m.outerWidth()+17);m.css({position:"",left:"",top:"",display:""});m.detach();a.append(m.append(j))});g.css("width",Math.min(250,Math.max(g.width(),c)));workflow.node_changed(this)},update_field_data:function(f){var c=$(this.element),d=this;this.tool_state=f.tool_state;this.form_html=f.form_html;this.tool_errors=f.tool_errors;this.annotation=f.annotation;var g=$.parseJSON(f.post_job_actions);this.post_job_actions=g?g:{};if(this.tool_errors){c.addClass("tool-node-error")}else{c.removeClass("tool-node-error")}var h=c.find("div.inputs");var b=$("
");var a=h.find("div.input-data-row");$.each(f.data_inputs,function(l,j){var k=d.new_input_terminal(j);h.find("div[name='"+j.name+"']").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){k[0].terminal.connectors[0]=i;i.handle2=k[0].terminal}});$(this).remove()});b.append($("
"+j.label+"
").prepend(k))});h.replaceWith(b);h.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.changed();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="
"+d+"
";this.form_html=c;a.html(c);workflow.node_changed(this)},changed: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("
No node selected
")},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(a3*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=$("
");var g=new Node(i);g.type=l;if(l=="tool"){g.tool_id=r}var n=$("
"+j+"
");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("
");var h="
loading tool info...
";m.append(h);g.form_html=h;i.append(m);var k=$("
");k.append($("
").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}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}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-qA){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-qu){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(d0){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 +function Terminal(a){this.element=a;this.connectors=[]}$.extend(Terminal.prototype,{connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}});function OutputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}OutputTerminal.prototype=new Terminal();function InputTerminal(b,c,a){Terminal.call(this,b);this.datatypes=c;this.multiple=a}InputTerminal.prototype=new Terminal();$.extend(InputTerminal.prototype,{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()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{new_input_terminal:function(a){var b=$("
")[0];this.enable_input_terminal(b,a.name,a.extensions,a.multiple);return b},enable_input_terminal:function(f,b,d,a){var g=this;var c=f.terminal=new InputTerminal(f,d,a);c.node=g;c.name=b;$(f).bind("dropinit",function(h,i){return $(i.drag).hasClass("output-terminal")&&c.can_accept(i.drag.terminal)}).bind("dropstart",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#BBFFBB"}}).bind("dropend",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#FFFFFF"}}).bind("drop",function(h,i){(new Connector(i.drag.terminal,c)).redraw()}).bind("hover",function(){if(c.connectors.length>0){var h=$("
").css({display:"none"}).appendTo("body").append($("
").append($("
").addClass("fa-icon-button fa fa-times").click(function(){$.each(c.connectors,function(j,i){if(i){i.destroy()}});h.remove()}))).bind("mouseleave",function(){$(this).remove()});h.css({top:$(f).offset().top-2,left:$(f).offset().left-h.width(),"padding-right":$(f).width()}).show()}});g.input_terminals[b]=c},enable_output_terminal:function(d,a,f){var g=this;var c=d;var b=d.terminal=new OutputTerminal(d,f);b.node=g;b.name=a;$(d).bind("dragstart",function(j,k){$(k.available).addClass("input-terminal-active");workflow.check_changes_in_active_form();var i=$('
').appendTo("#canvas-container").get(0);i.terminal=new OutputTerminal(i);var l=new Connector();l.dragging=true;l.connect(d.terminal,i.terminal);return i}).bind("drag",function(i,j){var h=function(){var l=$(j.proxy).offsetParent().offset(),k=j.offsetX-l.left,m=j.offsetY-l.top;$(j.proxy).css({left:k,top:m});j.proxy.terminal.redraw();canvas_manager.update_viewport_overlay()};h();$("#canvas-container").get(0).scroll_panel.test(i,h)}).bind("dragend",function(h,i){i.proxy.terminal.connectors[0].destroy();$(i.proxy).remove();$(i.available).removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()});g.output_terminals[a]=b},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(h){var g=this.element;if(h.type){this.type=h.type}this.name=h.name;this.form_html=h.form_html;this.tool_state=h.tool_state;this.tool_errors=h.tool_errors;this.tooltip=h.tooltip?h.tooltip:"";this.annotation=h.annotation;this.post_job_actions=h.post_job_actions?h.post_job_actions:{};this.workflow_outputs=h.workflow_outputs?h.workflow_outputs:[];if(this.tool_errors){g.addClass("tool-node-error")}else{g.removeClass("tool-node-error")}var d=this;var c=Math.max(150,g.width());var a=g.find(".toolFormBody");a.find("div").remove();var i=$("
").appendTo(a);$.each(h.data_inputs,function(k,f){var j=d.new_input_terminal(f);var b=$("
"+f.label+"
");b.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(b);c=Math.max(c,b.outerWidth());b.css({position:"",left:"",top:"",display:""});b.remove();i.append(b.prepend(j))});if((h.data_inputs.length>0)&&(h.data_outputs.length>0)){a.append($("
"))}$.each(h.data_outputs,function(k,b){var j=$("
");d.enable_output_terminal(j[0],b.name,b.extensions);var f=b.name;if(b.extensions.indexOf("input")<0){f=f+" ("+b.extensions.join(", ")+")"}var m=$("
"+f+"
");if(d.type=="tool"){var l=$("
").css({display:"none"}).append($("
").append($("").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png").click(function(){if($.inArray(b.name,d.workflow_outputs)!=-1){d.workflow_outputs.splice($.inArray(b.name,d.workflow_outputs),1);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{d.workflow_outputs.push(b.name);l.find("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."});l.css({top:"50%",margin:"-8px 0px 0px 0px",right:8});l.show();m.append(l);if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}m.hover(function(){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-yellow.png")},function(){if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}})}m.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(m);c=Math.max(c,m.outerWidth()+17);m.css({position:"",left:"",top:"",display:""});m.detach();a.append(m.append(j))});g.css("width",Math.min(250,Math.max(g.width(),c)));workflow.node_changed(this)},update_field_data:function(d){var b=$(this.element),c=this;this.tool_state=d.tool_state;this.form_html=d.form_html;this.tool_errors=d.tool_errors;this.annotation=d.annotation;var f=$.parseJSON(d.post_job_actions);this.post_job_actions=f?f:{};if(this.tool_errors){b.addClass("tool-node-error")}else{b.removeClass("tool-node-error")}var g=b.find("div.inputs");var a=$("
");$.each(d.data_inputs,function(k,h){var j=c.new_input_terminal(h);g.find("div[name='"+h.name+"']").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){j.terminal.connectors[0]=i;i.handle2=j.terminal}});$(this).remove()});a.append($("
"+h.label+"
").prepend(j))});g.replaceWith(a);g.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.changed();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="
"+d+"
";this.form_html=c;a.html(c);workflow.node_changed(this)},changed: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("
No node selected
")},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(a3*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=$("
");var g=new Node(i);g.type=l;if(l=="tool"){g.tool_id=r}var n=$("
"+j+"
");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("
");var h="
loading tool info...
";m.append(h);g.form_html=h;i.append(m);var k=$("
");k.append($("
").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}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-qA){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-qu){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(d0){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 diff --git a/static/scripts/packed/galaxy.workflows.js b/static/scripts/packed/galaxy.workflows.js index 32ca6a53869..3c353ebb802 100644 --- a/static/scripts/packed/galaxy.workflows.js +++ b/static/scripts/packed/galaxy.workflows.js @@ -1 +1 @@ -$(function(){if(window.lt_ie_7){show_modal("Browser not supported","Sorry, the workflow editor is not supported for IE6 and below.");return}$("#tool-search-query").click(function(){$(this).focus();$(this).select()}).keyup(function(){$(this).css("font-style","normal");if(this.value.length<3){reset_tool_search(false)}else{if(this.value!=this.lastValue){$(this).addClass("search_active");var g=this.value+"*";if(this.timer){clearTimeout(this.timer)}$("#search-spinner").show();this.timer=setTimeout(function(){$.get(tool_search_url,{query:g},function(i){$("#search-no-results").hide();$(".toolSectionWrapper").hide();$(".toolSectionWrapper").find(".toolTitle").hide();if(i.length!=0){var h=$.map(i,function(k,j){return"link-"+k});$(h).each(function(j,k){$("[id='"+k+"']").parent().addClass("search_match");$("[id='"+k+"']").parent().show().parent().parent().show().parent().show()});$(".toolPanelLabel").each(function(){var l=$(this);var k=l.next();var j=true;while(k.length!==0&&k.hasClass("toolTitle")){if(k.is(":visible")){j=false;break}else{k=k.next()}}if(j){l.hide()}})}else{$("#search-no-results").show()}$("#search-spinner").hide()},"json")},200)}}this.lastValue=this.value});canvas_manager=new CanvasManager($("#canvas-viewport"),$("#overview"));reset();$.ajax({url:get_datatypes_url,dataType:"json",cache:false,success:function(g){populate_datatype_info(g);$.ajax({url:load_workflow_url,data:{id:workflow_id,_:"true"},dataType:"json",cache:false,success:function(h){reset();workflow.from_simple(h);workflow.has_changes=false;workflow.fit_canvas_to_nodes();scroll_to_nodes();canvas_manager.draw_overview();upgrade_message="";$.each(h.upgrade_messages,function(j,i){upgrade_message+=("
  • Step "+(parseInt(j,10)+1)+": "+workflow.nodes[j].name+"
      ");$.each(i,function(k,l){upgrade_message+="
    • "+l+"
    • "});upgrade_message+="
  • "});if(upgrade_message){show_modal("Workflow loaded with changes","Problems were encountered loading this workflow (possibly a result of tool upgrades). Please review the following parameters and then save.
      "+upgrade_message+"
    ",{Continue:hide_modal})}else{hide_modal()}show_workflow_parameters()},beforeSubmit:function(h){show_message("Loading workflow","progress")}})}});$(document).ajaxStart(function(){active_ajax_call=true;$(document).bind("ajaxStop.global",function(){active_ajax_call=false})});$(document).ajaxError(function(i,g){var h=g.responseText||g.statusText||"Could not connect to server";show_modal("Server error",h,{"Ignore error":hide_modal});return false});make_popupmenu($("#workflow-options-button"),{Save:save_current_workflow,Run:function(){window.location=run_workflow_url},"Edit Attributes":c,"Auto Re-layout":f,Close:close_editor});function b(){workflow.clear_active_node();$(".right-content").hide();var j="";for(var h in workflow.nodes){var i=workflow.nodes[h];if(i.type=="tool"){j+="
    Step "+i.id+" - "+i.name+"
    ";for(var k in i.output_terminals){var g=i.output_terminals[k];if($.inArray(g.name,i.workflow_outputs)!=-1){j+="

    "+g.name+"

    "}else{j+="

    "+g.name+"

    "}}j+="
    "}}$("#output-fill-area").html(j);$("#output-fill-area input").bind("click",function(){var n=this.name.split("|")[0];var l=this.name.split("|")[1];if(this.checked){if($.inArray(l,workflow.nodes[n].workflow_outputs)==-1){workflow.nodes[n].workflow_outputs.push(l)}}else{while($.inArray(l,workflow.nodes[n].workflow_outputs)!=-1){var m=$.inArray(l,workflow.nodes[n].workflow_outputs);workflow.nodes[n].workflow_outputs=workflow.nodes[n].workflow_outputs.slice(0,m).concat(workflow.nodes[n].workflow_outputs.slice(m+1))}}workflow.has_changes=true});$("#workflow-output-area").show()}function f(){workflow.layout();workflow.fit_canvas_to_nodes();scroll_to_nodes();canvas_manager.draw_overview()}function c(){workflow.clear_active_node();$(".right-content").hide();$("#edit-attributes").show()}overview_size=$.jStorage.get("overview-size");if(overview_size!==undefined){$("#overview-border").css({width:overview_size,height:overview_size})}if($.jStorage.get("overview-off")){d()}else{e()}$("#overview-border").bind("dragend",function(h,j){var k=$(this).offsetParent();var i=k.offset();var g=Math.max(k.width()-(j.offsetX-i.left),k.height()-(j.offsetY-i.top));$.jStorage.set("overview-size",g+"px")});function e(){$.jStorage.set("overview-off",false);$("#overview-border").css("right","0px");$("#close-viewport").css("background-position","0px 0px")}function d(){$.jStorage.set("overview-off",true);$("#overview-border").css("right","20000px");$("#close-viewport").css("background-position","12px 0px")}$("#close-viewport").click(function(){if($("#overview-border").css("right")==="0px"){d()}else{e()}});window.onbeforeunload=function(){if(workflow&&workflow.has_changes){return"There are unsaved changes to your workflow which will be lost."}};$("div.toolSectionBody").hide();$("div.toolSectionTitle > span").wrap("");var a=null;$("div.toolSectionTitle").each(function(){var g=$(this).next("div.toolSectionBody");$(this).click(function(){if(g.is(":hidden")){if(a){a.slideUp("fast")}a=g;g.slideDown("fast")}else{g.slideUp("fast");a=null}})});async_save_text("workflow-name","workflow-name",rename_async_url,"new_name");$("#workflow-tag").click(function(){$(".tag-area").click();return false});async_save_text("workflow-annotation","workflow-annotation",annotate_async_url,"new_annotation",25,true,4)});function reset(){if(workflow){workflow.remove_all()}workflow=new Workflow($("#canvas-container"))}function scroll_to_nodes(){var a=$("#canvas-viewport");var d=$("#canvas-container");var c,b;if(d.width().toolForm:last>.toolFormTitle>.buttons").click(function(){action_to_rem=$(this).closest(".toolForm",".action_tag").children(".action_tag:first").text();$(this).closest(".toolForm").remove();delete workflow.active_node.post_job_actions[action_to_rem];workflow.active_form_has_changes=true})}function display_pja_list(){return pja_list}function display_file_list(b){addlist="";return addlist}function new_pja(d,b,a){if(a.post_job_actions===undefined){a.post_job_actions={}}if(a.post_job_actions[d+b]===undefined){var c={};c.action_type=d;c.output_name=b;a.post_job_actions[d+b]=null;a.post_job_actions[d+b]=c;display_pja(c,a);workflow.active_form_has_changes=true;return true}else{return false}}function show_workflow_parameters(){var c=/\$\{.+?\}/g;var b=[];var f=$("#workflow-parameters-container");var e=$("#workflow-parameters-box");var a="";var d=[];$.each(workflow.nodes,function(g,h){var i=h.form_html.match(c);if(i){d=d.concat(i)}if(h.post_job_actions){$.each(h.post_job_actions,function(j,l){if(l.action_arguments){$.each(l.action_arguments,function(m,n){var o=n.match(c);if(o){d=d.concat(o)}})}});if(d){$.each(d,function(j,l){if($.inArray(l,b)===-1){b.push(l)}})}}});if(b&&b.length!==0){$.each(b,function(g,h){a+="
    "+h.substring(2,h.length-1)+"
    "});f.html(a);e.show()}else{f.html(a);e.hide()}}function show_form_for_tool(c,b){$(".right-content").hide();$("#right-content").show().html(c);if(b){$("#right-content").find(".toolForm:first").after("

    Edit Step Attributes
    Add an annotation or notes to this step; annotations are available when a workflow is viewed.
    ")}if(b&&b.type=="tool"){pjastr="

    Edit Step Actions
    "+display_pja_list()+"
    "+display_file_list(b)+"
    Create
    ";pjastr+="
    Add actions to this step; actions are applied when this workflow step completes.
    ";$("#right-content").find(".toolForm").after(pjastr);for(var a in b.post_job_actions){if(a!="undefined"){display_pja(b.post_job_actions[a],b)}}$("#add_pja").click(function(){new_pja($("#new_pja_list").val(),$("#node_data_list").val(),b)})}$("#right-content").find("form").ajaxForm({type:"POST",dataType:"json",success:function(d){workflow.active_form_has_changes=false;b.update_field_data(d);show_workflow_parameters()},beforeSubmit:function(d){d.push({name:"tool_state",value:b.tool_state});d.push({name:"_",value:"true"})}}).each(function(){var d=this;$(this).find("select[refresh_on_change='true']").change(function(){$(d).submit()});$(this).find(".popupmenu").each(function(){var g=$(this).parents("div.form-row").attr("id");var e=$('▼');var f={};$(this).find("button").each(function(){var h=$(this).attr("name");var i=$(this).attr("value");f[$(this).text()]=function(){$(d).append("").submit()}});e.insertAfter(this);$(this).remove();make_popupmenu(e,f)});$(this).find("input,textarea,select").each(function(){$(this).bind("focus click",function(){workflow.active_form_has_changes=true})})})}var close_editor=function(){workflow.check_changes_in_active_form();if(workflow&&workflow.has_changes){do_close=function(){window.onbeforeunload=undefined;window.document.location=workflow_index_url};show_modal("Close workflow editor","There are unsaved changes to your workflow which will be lost.",{Cancel:hide_modal,"Save Changes":function(){save_current_workflow(null,do_close)}},{"Don't Save":do_close})}else{window.document.location=workflow_index_url}};var save_current_workflow=function(b,c){show_message("Saving workflow","progress");workflow.check_changes_in_active_form();if(!workflow.has_changes){hide_modal();if(c){c()}return}workflow.rectify_workflow_outputs();var a=function(d){$.ajax({url:save_workflow_url,type:"POST",data:{id:workflow_id,workflow_data:function(){return JSON.stringify(workflow.to_simple())},_:"true"},dataType:"json",success:function(g){var e=$("
    ").text(g.message);if(g.errors){e.addClass("warningmark");var f=$("