galaxy-commits
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
September 2014
- 2 participants
- 236 discussions
commit/galaxy-central: dannon: Merged in lance_parsons/galaxy-central-pull-requests/igv-local-dbkey (pull request #488)
by commits-noreply@bitbucket.org 12 Sep '14
by commits-noreply@bitbucket.org 12 Sep '14
12 Sep '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/f8465681a19d/
Changeset: f8465681a19d
User: dannon
Date: 2014-09-12 19:10:52
Summary: Merged in lance_parsons/galaxy-central-pull-requests/igv-local-dbkey (pull request #488)
Allow local IGV users to visualize custom genomes
Affected #: 2 files
diff -r 2346e098b27e0141fdd3e9821895413e27bc2c2f -r f8465681a19d189317fabebbc3c400c2418e8776 display_applications/igv/bam.xml
--- a/display_applications/igv/bam.xml
+++ b/display_applications/igv/bam.xml
@@ -12,15 +12,19 @@
<dynamic_param name="site_organisms" value="4" split="True" separator="," /><!-- Filter out some of the links based upon matching site_dbkeys to dataset dbkey -->
- <filter>${dataset.dbkey in $site_dbkeys}</filter>
-
+ <filter>${$site_id.startswith( 'local_' ) or $dataset.dbkey in $site_dbkeys}</filter>
+
<!-- We define url and params as normal, but values defined in dynamic_param are available by specified name --><url>${redirect_url}</url><param type="data" name="bam_file" url="galaxy_${DATASET_HASH}.bam" /><param type="data" name="bai_file" url="galaxy_${DATASET_HASH}.bam.bai" metadata="bam_index" /><param type="template" name="site_organism" strip="True" >
- $site_organisms[ $site_dbkeys.index( $bam_file.dbkey ) ]
+ #if ($dataset.dbkey in $site_dbkeys)
+ $site_organisms[ $site_dbkeys.index( $bam_file.dbkey ) ]
+ #else:
+ $bam_file.dbkey
+ #end if
</param><param type="template" name="jnlp" url="galaxy_${DATASET_HASH}.jnlp" viewable="True" mimetype="application/x-java-jnlp-file"><?xml version="1.0" encoding="utf-8"?>
diff -r 2346e098b27e0141fdd3e9821895413e27bc2c2f -r f8465681a19d189317fabebbc3c400c2418e8776 display_applications/igv/vcf.xml
--- a/display_applications/igv/vcf.xml
+++ b/display_applications/igv/vcf.xml
@@ -12,15 +12,19 @@
<dynamic_param name="site_organisms" value="4" split="True" separator="," /><!-- Filter out some of the links based upon matching site_dbkeys to dataset dbkey -->
- <filter>${dataset.dbkey in $site_dbkeys}</filter>
-
+ <filter>${$site_id.startswith( 'local_' ) or $dataset.dbkey in $site_dbkeys}</filter>
+
<!-- We define url and params as normal, but values defined in dynamic_param are available by specified name --><url>${redirect_url}</url><param type="data" name="bgzip_file" url="galaxy_${DATASET_HASH}.vcf.gz" format="vcf_bgzip" /><param type="data" name="tabix_file" dataset="bgzip_file" url="galaxy_${DATASET_HASH}.vcf.gz.tbi" format="tabix" /><param type="template" name="site_organism" strip="True" >
- $site_organisms[ $site_dbkeys.index( $bgzip_file.dbkey ) ]
+ #if ($dataset.dbkey in $site_dbkeys)
+ $site_organisms[ $site_dbkeys.index( $bgzip_file.dbkey ) ]
+ #else:
+ $bgzip_file.dbkey
+ #end if
</param><param type="template" name="jnlp" url="galaxy_${DATASET_HASH}.jnlp" viewable="True" mimetype="application/x-java-jnlp-file"><?xml version="1.0" encoding="utf-8"?>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4456e0cf7721/
Changeset: 4456e0cf7721
Branch: igv-local-dbkey
User: lance_parsons
Date: 2014-09-04 21:22:10
Summary: Allow local IGV users to visualize custom genomes
Affected #: 2 files
diff -r 9b6cccb3af2d6b13a1a1da7def87dcc19172be88 -r 4456e0cf7721386a728e9cb05ef7463bbd477d5b display_applications/igv/bam.xml
--- a/display_applications/igv/bam.xml
+++ b/display_applications/igv/bam.xml
@@ -12,15 +12,19 @@
<dynamic_param name="site_organisms" value="4" split="True" separator="," /><!-- Filter out some of the links based upon matching site_dbkeys to dataset dbkey -->
- <filter>${dataset.dbkey in $site_dbkeys}</filter>
-
+ <filter>${$site_id.startswith( 'local_' ) or $dataset.dbkey in $site_dbkeys}</filter>
+
<!-- We define url and params as normal, but values defined in dynamic_param are available by specified name --><url>${redirect_url}</url><param type="data" name="bam_file" url="galaxy_${DATASET_HASH}.bam" /><param type="data" name="bai_file" url="galaxy_${DATASET_HASH}.bam.bai" metadata="bam_index" /><param type="template" name="site_organism" strip="True" >
- $site_organisms[ $site_dbkeys.index( $bam_file.dbkey ) ]
+ #if ($dataset.dbkey in $site_dbkeys)
+ $site_organisms[ $site_dbkeys.index( $bam_file.dbkey ) ]
+ #else:
+ $bam_file.dbkey
+ #end if
</param><param type="template" name="jnlp" url="galaxy_${DATASET_HASH}.jnlp" viewable="True" mimetype="application/x-java-jnlp-file"><?xml version="1.0" encoding="utf-8"?>
diff -r 9b6cccb3af2d6b13a1a1da7def87dcc19172be88 -r 4456e0cf7721386a728e9cb05ef7463bbd477d5b display_applications/igv/vcf.xml
--- a/display_applications/igv/vcf.xml
+++ b/display_applications/igv/vcf.xml
@@ -12,15 +12,19 @@
<dynamic_param name="site_organisms" value="4" split="True" separator="," /><!-- Filter out some of the links based upon matching site_dbkeys to dataset dbkey -->
- <filter>${dataset.dbkey in $site_dbkeys}</filter>
-
+ <filter>${$site_id.startswith( 'local_' ) or $dataset.dbkey in $site_dbkeys}</filter>
+
<!-- We define url and params as normal, but values defined in dynamic_param are available by specified name --><url>${redirect_url}</url><param type="data" name="bgzip_file" url="galaxy_${DATASET_HASH}.vcf.gz" format="vcf_bgzip" /><param type="data" name="tabix_file" dataset="bgzip_file" url="galaxy_${DATASET_HASH}.vcf.gz.tbi" format="tabix" /><param type="template" name="site_organism" strip="True" >
- $site_organisms[ $site_dbkeys.index( $bgzip_file.dbkey ) ]
+ #if ($dataset.dbkey in $site_dbkeys)
+ $site_organisms[ $site_dbkeys.index( $bgzip_file.dbkey ) ]
+ #else:
+ $bgzip_file.dbkey
+ #end if
</param><param type="template" name="jnlp" url="galaxy_${DATASET_HASH}.jnlp" viewable="True" mimetype="application/x-java-jnlp-file"><?xml version="1.0" encoding="utf-8"?>
https://bitbucket.org/galaxy/galaxy-central/commits/f8465681a19d/
Changeset: f8465681a19d
User: dannon
Date: 2014-09-12 19:10:52
Summary: Merged in lance_parsons/galaxy-central-pull-requests/igv-local-dbkey (pull request #488)
Allow local IGV users to visualize custom genomes
Affected #: 2 files
diff -r 2346e098b27e0141fdd3e9821895413e27bc2c2f -r f8465681a19d189317fabebbc3c400c2418e8776 display_applications/igv/bam.xml
--- a/display_applications/igv/bam.xml
+++ b/display_applications/igv/bam.xml
@@ -12,15 +12,19 @@
<dynamic_param name="site_organisms" value="4" split="True" separator="," /><!-- Filter out some of the links based upon matching site_dbkeys to dataset dbkey -->
- <filter>${dataset.dbkey in $site_dbkeys}</filter>
-
+ <filter>${$site_id.startswith( 'local_' ) or $dataset.dbkey in $site_dbkeys}</filter>
+
<!-- We define url and params as normal, but values defined in dynamic_param are available by specified name --><url>${redirect_url}</url><param type="data" name="bam_file" url="galaxy_${DATASET_HASH}.bam" /><param type="data" name="bai_file" url="galaxy_${DATASET_HASH}.bam.bai" metadata="bam_index" /><param type="template" name="site_organism" strip="True" >
- $site_organisms[ $site_dbkeys.index( $bam_file.dbkey ) ]
+ #if ($dataset.dbkey in $site_dbkeys)
+ $site_organisms[ $site_dbkeys.index( $bam_file.dbkey ) ]
+ #else:
+ $bam_file.dbkey
+ #end if
</param><param type="template" name="jnlp" url="galaxy_${DATASET_HASH}.jnlp" viewable="True" mimetype="application/x-java-jnlp-file"><?xml version="1.0" encoding="utf-8"?>
diff -r 2346e098b27e0141fdd3e9821895413e27bc2c2f -r f8465681a19d189317fabebbc3c400c2418e8776 display_applications/igv/vcf.xml
--- a/display_applications/igv/vcf.xml
+++ b/display_applications/igv/vcf.xml
@@ -12,15 +12,19 @@
<dynamic_param name="site_organisms" value="4" split="True" separator="," /><!-- Filter out some of the links based upon matching site_dbkeys to dataset dbkey -->
- <filter>${dataset.dbkey in $site_dbkeys}</filter>
-
+ <filter>${$site_id.startswith( 'local_' ) or $dataset.dbkey in $site_dbkeys}</filter>
+
<!-- We define url and params as normal, but values defined in dynamic_param are available by specified name --><url>${redirect_url}</url><param type="data" name="bgzip_file" url="galaxy_${DATASET_HASH}.vcf.gz" format="vcf_bgzip" /><param type="data" name="tabix_file" dataset="bgzip_file" url="galaxy_${DATASET_HASH}.vcf.gz.tbi" format="tabix" /><param type="template" name="site_organism" strip="True" >
- $site_organisms[ $site_dbkeys.index( $bgzip_file.dbkey ) ]
+ #if ($dataset.dbkey in $site_dbkeys)
+ $site_organisms[ $site_dbkeys.index( $bgzip_file.dbkey ) ]
+ #else:
+ $bgzip_file.dbkey
+ #end if
</param><param type="template" name="jnlp" url="galaxy_${DATASET_HASH}.jnlp" viewable="True" mimetype="application/x-java-jnlp-file"><?xml version="1.0" encoding="utf-8"?>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/aa8d4381785e/
Changeset: aa8d4381785e
User: jmchilton
Date: 2014-09-12 15:32:22
Summary: More workflow module documentation improvements.
I nearly understand workflow modules...
Affected #: 2 files
diff -r b8520d9c8269c4c7deca6418d54f2e722886073e -r aa8d4381785ee94746dbdcfd35c9b0798a10be30 lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -79,10 +79,16 @@
def get_state( self ):
""" Return a serializable representation of the persistable state of
the step - for tools it DefaultToolState.encode returns a string and
- for inputs a json description is dumped out.
+ for simpler module types a json description is dumped out.
"""
return None
+ def update_state( self, incoming ):
+ """ Update the current state of the module against the user supplied
+ parameters in the dict-like object `incoming`.
+ """
+ pass
+
def get_errors( self ):
""" It seems like this is effectively just used as boolean - some places
in the tool shed self.errors is set to boolean, other places 'unavailable',
@@ -97,9 +103,6 @@
def get_data_outputs( self ):
return []
- def update_state( self ):
- pass
-
def get_config_form( self ):
""" Render form that is embedded in workflow editor for modifying the
step state of a node.
@@ -120,33 +123,38 @@
## ---- Run time ---------------------------------------------------------
def get_runtime_inputs( self ):
- """ Used internally to modules and when displaying inputs in display
- and run workflow templates. The ToolModule doesn't implement this and
- these templates contain specialized logic for dealing with the tool and
- state directly in these cases.
+ """ Used internally by modules and when displaying inputs in workflow
+ editor and run workflow templates.
+
+ Note: The ToolModule doesn't implement this and these templates contain
+ specialized logic for dealing with the tool and state directly in the
+ case of ToolModules.
"""
raise TypeError( "Abstract method" )
def encode_runtime_state( self, trans, state ):
- """ Encode the runtime state (loaded from the stored step and
- populated via the WorkflowModuleInjector below) for use in a hidden
- parameter on the webpage.
+ """ Encode the default runtime state at return as a simple `str` for
+ use in a hidden parameter on the workflow run submission form.
- This will combined with runtime parameters supplied by user running
- the workflow to create the final state to pass along to execute during
- workflow invocation.
+ This default runtime state will be combined with user supplied
+ parameters in `compute_runtime_state` below at workflow invocation time to
+ actually describe how each step will be executed.
"""
raise TypeError( "Abstract method" )
- def compute_state( self, trans, step_updates=None ):
- """ Recover the transient "state" attribute to populate corresponding
- step with (currently this is always a DefaultToolState instance,
- though I am not sure this is strictly nessecary).
+ def compute_runtime_state( self, trans, step_updates=None ):
+ """ Determine the runtime state (potentially different from self.state
+ which describes configuration state). This (again unlike self.state) is
+ currently always a `DefaultToolState` object.
If `step_updates` is `None`, this is likely for rendering the run form
for instance and no runtime properties are available and state must be
- solely determined by step. If `step_updates` are available they describe
- the runtime properties supplied by the workflow runner.
+ solely determined by the default runtime state described by the step.
+
+ If `step_updates` are available they describe the runtime properties
+ supplied by the workflow runner (potentially including a `tool_state`
+ parameter which is the serialized default encoding state created with
+ encode_runtime_state above).
"""
raise TypeError( "Abstract method" )
@@ -232,7 +240,7 @@
errors[ name ] = error
return errors
- def compute_state( self, trans, step_updates=None ):
+ def compute_runtime_state( self, trans, step_updates=None ):
if step_updates:
# Fix this for multiple inputs
state = self.decode_runtime_state( trans, step_updates.pop( "tool_state" ) )
@@ -559,7 +567,7 @@
def check_and_update_state( self ):
return self.tool.check_and_update_param_values( self.state.inputs, self.trans, allow_workflow_parameters=True )
- def compute_state( self, trans, step_updates=None ):
+ def compute_runtime_state( self, trans, step_updates=None ):
# Warning: This method destructively modifies existing step state.
step_errors = None
state = self.state
@@ -788,7 +796,7 @@
# are not persisted so we need to do it every time)
module.add_dummy_datasets( connections=step.input_connections )
- state, step_errors = module.compute_state( trans, step_args )
+ state, step_errors = module.compute_runtime_state( trans, step_args )
step.state = state
return step_errors
diff -r b8520d9c8269c4c7deca6418d54f2e722886073e -r aa8d4381785ee94746dbdcfd35c9b0798a10be30 test/unit/workflows/test_modules.py
--- a/test/unit/workflows/test_modules.py
+++ b/test/unit/workflows/test_modules.py
@@ -7,7 +7,6 @@
from galaxy import model
from galaxy.workflow import modules
-from galaxy.tools import parameters
from .workflow_support import MockTrans
@@ -49,17 +48,17 @@
__assert_has_runtime_input( module, label="Cool Input" )
-def test_data_input_compute_state_default():
+def test_data_input_compute_runtime_state_default():
module = __from_step(
type="data_input",
)
- state, errors = module.compute_state( module.trans )
+ state, errors = module.compute_runtime_state( module.trans )
assert not errors
assert 'input' in state.inputs
assert state.inputs[ 'input' ] is None
-def test_data_input_compute_state_args():
+def test_data_input_compute_runtime_state_args():
module = __from_step(
type="data_input",
)
@@ -68,7 +67,7 @@
hda = model.HistoryDatasetAssociation()
with mock.patch('galaxy.workflow.modules.check_param') as check_method:
check_method.return_value = ( hda, None )
- state, errors = module.compute_state( module.trans, { 'input': 4, 'tool_state': tool_state } )
+ state, errors = module.compute_runtime_state( module.trans, { 'input': 4, 'tool_state': tool_state } )
assert not errors
assert 'input' in state.inputs
https://bitbucket.org/galaxy/galaxy-central/commits/945ebcd32f33/
Changeset: 945ebcd32f33
User: jmchilton
Date: 2014-09-12 15:32:22
Summary: Rework workflow modules to reduce duplication and add more consistency..
Adding a recover_state method that to both implementations (though meant to be part of the module interface) that recovers the configuration state (module.state) from a dictionary. This turns out to reduce a lot of duplication between data and data collection input modules.
Affected #: 1 file
diff -r aa8d4381785ee94746dbdcfd35c9b0798a10be30 -r 945ebcd32f336a5b3b97c4c66aa1274a49d8e07b lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -171,24 +171,41 @@
@classmethod
def new( Class, trans, tool_id=None ):
module = Class( trans )
- module.state = dict( name=Class.default_name )
+ module.state = Class.default_state()
return module
@classmethod
def from_dict( Class, trans, d, secure=True ):
module = Class( trans )
state = loads( d["tool_state"] )
- module.state = dict( name=state.get( "name", Class.default_name ) )
+ module.recover_state( state )
return module
@classmethod
def from_workflow_step( Class, trans, step ):
module = Class( trans )
- module.state = dict( name="Input Dataset" )
- if step.tool_inputs and "name" in step.tool_inputs:
- module.state['name'] = step.tool_inputs[ 'name' ]
+ module.recover_state( step.tool_inputs )
return module
+ @classmethod
+ def default_state( Class ):
+ """ This method should return a dictionary describing each
+ configuration property and its default value.
+ """
+ raise TypeError( "Abstract method" )
+
+ def recover_state( self, state, **kwds ):
+ """ Recover state `dict` from simple dictionary describing configuration
+ state (potentially from persisted step state).
+
+ Sub-classes should supply `default_state` method and `state_fields`
+ attribute which are used to build up the state `dict`.
+ """
+ self.state = self.default_state()
+ for key in self.state_fields:
+ if state and key in state:
+ self.state[ key ] = state[ key ]
+
def save_to_step( self, step ):
step.type = self.type
step.tool_id = None
@@ -277,6 +294,11 @@
type = "data_input"
name = "Input dataset"
default_name = "Input Dataset"
+ state_fields = [ "name" ]
+
+ @classmethod
+ def default_state( Class ):
+ return dict( name=Class.default_name )
class InputDataCollectionModule( InputModule ):
@@ -285,34 +307,11 @@
type = "data_collection_input"
name = "Input dataset collection"
collection_type = default_collection_type
+ state_fields = [ "name", "collection_type" ]
@classmethod
- def new( Class, trans, tool_id=None ):
- module = Class( trans )
- module.state = dict( name=Class.default_name, collection_type=Class.default_collection_type )
- return module
-
- @classmethod
- def from_dict( Class, trans, d, secure=True ):
- module = Class( trans )
- state = loads( d["tool_state"] )
- module.state = dict(
- name=state.get( "name", Class.default_name ),
- collection_type=state.get( "collection_type", Class.default_collection_type )
- )
- return module
-
- @classmethod
- def from_workflow_step( Class, trans, step ):
- module = Class( trans )
- module.state = dict(
- name=Class.default_name,
- collection_type=Class.default_collection_type
- )
- for key in [ "name", "collection_type" ]:
- if step.tool_inputs and key in step.tool_inputs:
- module.state[ key ] = step.tool_inputs[ key ]
- return module
+ def default_state( Class ):
+ return dict( name=Class.default_name, collection_type=Class.default_collection_type )
def get_runtime_inputs( self, filter_set=['data'] ):
label = self.state.get( "name", self.default_name )
@@ -408,10 +407,9 @@
# tool being previously unavailable.
return module_factory.from_dict(trans, loads(step.config), secure=False)
module = Class( trans, tool_id )
- module.state = galaxy.tools.DefaultToolState()
if step.tool_version and (step.tool_version != module.tool.version):
module.version_changes.append("%s: using version '%s' instead of version '%s' indicated in this workflow." % (tool_id, module.tool.version, step.tool_version))
- module.state.inputs = module.tool.params_from_strings( step.tool_inputs, trans.app, ignore_errors=True )
+ module.recover_state( step.tool_inputs )
module.errors = step.tool_errors
module.workflow_outputs = step.workflow_outputs
pjadict = {}
@@ -421,6 +419,17 @@
return module
return None
+ def recover_state( self, state, **kwds ):
+ """ Recover module configuration state property (a `DefaultToolState`
+ object) using the tool's `params_from_strings` method.
+ """
+ app = self.trans.app
+ self.state = galaxy.tools.DefaultToolState()
+ params_from_kwds = dict(
+ ignore_errors=kwds.get( "ignore_errors", True )
+ )
+ self.state.inputs = self.tool.params_from_strings( state, app, **params_from_kwds )
+
@classmethod
def __get_tool_version( cls, trans, tool_id ):
# Return a ToolVersion if one exists for tool_id.
https://bitbucket.org/galaxy/galaxy-central/commits/2346e098b27e/
Changeset: 2346e098b27e
User: jmchilton
Date: 2014-09-12 15:32:22
Summary: Better OOP design for separation between input and input collection modules.
(Lot easier now that I understand what all of the module methods are doing and have an example of a 4th module downstream.) Now with even more unit tests.
Affected #: 2 files
diff -r 945ebcd32f336a5b3b97c4c66aa1274a49d8e07b -r 2346e098b27e0141fdd3e9821895413e27bc2c2f lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -214,12 +214,8 @@
def get_data_inputs( self ):
return []
- def get_data_outputs( self ):
- return [ dict( name='output', extensions=['input'] ) ]
-
def get_config_form( self ):
- form = formbuilder.FormBuilder( title=self.name ) \
- .add_text( "name", "Name", value=self.state['name'] )
+ form = self._abstract_config_form( )
return self.trans.fill_template( "workflow/editor_generic_form.mako",
module=self, form=form )
@@ -227,11 +223,7 @@
return dumps( self.state )
def update_state( self, incoming ):
- self.state['name'] = incoming.get( 'name', 'Input Dataset' )
-
- def get_runtime_inputs( self, filter_set=['data'] ):
- label = self.state.get( "name", "Input Dataset" )
- return dict( input=DataToolParameter( None, Element( "param", name="input", label=label, multiple=True, type="data", format=', '.join(filter_set) ), self.trans ) )
+ self.recover_state( incoming )
def get_runtime_state( self ):
state = galaxy.tools.DefaultToolState()
@@ -300,6 +292,18 @@
def default_state( Class ):
return dict( name=Class.default_name )
+ def _abstract_config_form( self ):
+ form = formbuilder.FormBuilder( title=self.name ) \
+ .add_text( "name", "Name", value=self.state['name'] )
+ return form
+
+ def get_data_outputs( self ):
+ return [ dict( name='output', extensions=['input'] ) ]
+
+ def get_runtime_inputs( self, filter_set=['data'] ):
+ label = self.state.get( "name", "Input Dataset" )
+ return dict( input=DataToolParameter( None, Element( "param", name="input", label=label, multiple=True, type="data", format=', '.join(filter_set) ), self.trans ) )
+
class InputDataCollectionModule( InputModule ):
default_name = "Input Dataset Collection"
@@ -319,7 +323,7 @@
input_element = Element( "param", name="input", label=label, type="data_collection", collection_type=collection_type )
return dict( input=DataCollectionToolParameter( None, input_element, self.trans ) )
- def get_config_form( self ):
+ def _abstract_config_form( self ):
type_hints = odict.odict()
type_hints[ "list" ] = "List of Datasets"
type_hints[ "paired" ] = "Dataset Pair"
@@ -338,12 +342,7 @@
"name", "Name", value=self.state['name']
)
form.inputs.append( type_input )
- return self.trans.fill_template( "workflow/editor_generic_form.mako",
- module=self, form=form )
-
- def update_state( self, incoming ):
- self.state[ 'name' ] = incoming.get( 'name', self.default_name )
- self.state[ 'collection_type' ] = incoming.get( 'collection_type', self.collection_type )
+ return form
def get_data_outputs( self ):
return [ dict( name='output', extensions=['input_collection'], collection_type=self.state[ 'collection_type' ] ) ]
diff -r 945ebcd32f336a5b3b97c4c66aa1274a49d8e07b -r 2346e098b27e0141fdd3e9821895413e27bc2c2f test/unit/workflows/test_modules.py
--- a/test/unit/workflows/test_modules.py
+++ b/test/unit/workflows/test_modules.py
@@ -74,6 +74,49 @@
assert state.inputs[ 'input' ] is hda
+def test_data_input_connections():
+ module = __from_step(
+ type="data_input",
+ )
+ assert len( module.get_data_inputs() ) == 0
+
+ outputs = module.get_data_outputs()
+ assert len( outputs ) == 1
+ output = outputs[ 0 ]
+ assert output[ 'name' ] == 'output'
+ assert output[ 'extensions' ] == [ 'input' ]
+
+
+def test_data_input_update():
+ module = __from_step(
+ type="data_input",
+ tool_inputs={
+ "name": "Cool Input",
+ },
+ )
+ module.update_state( dict( name="Awesome New Name" ) )
+ assert module.state[ 'name' ] == "Awesome New Name"
+
+
+def test_data_input_get_form():
+ module = __from_step(
+ type="data_input",
+ tool_inputs={
+ "name": "Cool Input",
+ },
+ )
+
+ def test_form(template, **kwds ):
+ assert template == "workflow/editor_generic_form.mako"
+ assert "form" in kwds
+ assert len( kwds[ "form" ].inputs ) == 1
+ return "TEMPLATE"
+
+ fill_mock = mock.Mock( side_effect=test_form )
+ module.trans.fill_template = fill_mock
+ assert module.get_config_form() == "TEMPLATE"
+
+
def test_data_collection_input_default_state():
trans = MockTrans()
module = modules.module_factory.new( trans, "data_collection_input" )
@@ -99,6 +142,55 @@
__assert_has_runtime_input( module, label="Cool Input Collection", collection_type="list:paired" )
+def test_data_collection_input_connections():
+ module = __from_step(
+ type="data_collection_input",
+ tool_inputs={
+ 'collection_type': 'list:paired'
+ }
+ )
+ assert len( module.get_data_inputs() ) == 0
+
+ outputs = module.get_data_outputs()
+ assert len( outputs ) == 1
+ output = outputs[ 0 ]
+ assert output[ 'name' ] == 'output'
+ assert output[ 'extensions' ] == [ 'input_collection' ]
+ assert output[ 'collection_type' ] == 'list:paired'
+
+
+def test_data_collection_input_update():
+ module = __from_step(
+ type="data_collection_input",
+ tool_inputs={
+ 'name': 'Cool Collection',
+ 'collection_type': 'list:paired',
+ }
+ )
+ module.update_state( dict( name="New Collection", collection_type="list" ) )
+ assert module.state[ 'name' ] == "New Collection"
+
+
+def test_data_collection_input_config_form():
+ module = __from_step(
+ type="data_collection_input",
+ tool_inputs={
+ 'name': 'Cool Collection',
+ 'collection_type': 'list:paired',
+ }
+ )
+
+ def test_form(template, **kwds ):
+ assert template == "workflow/editor_generic_form.mako"
+ assert "form" in kwds
+ assert len( kwds[ "form" ].inputs ) == 2
+ return "TEMPLATE"
+
+ fill_mock = mock.Mock( side_effect=test_form )
+ module.trans.fill_template = fill_mock
+ assert module.get_config_form() == "TEMPLATE"
+
+
def test_cannot_create_tool_modules_for_missing_tools():
trans = MockTrans()
exception = False
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
[galaxyproject/usegalaxy-playbook] 14926e: Update pulsar vars for new job_managers.ini templa...
by GitHub 11 Sep '14
by GitHub 11 Sep '14
11 Sep '14
Branch: refs/heads/master
Home: https://github.com/galaxyproject/usegalaxy-playbook
Commit: 14926e345bc4f9e1426398508abf1f1886b175c5
https://github.com/galaxyproject/usegalaxy-playbook/commit/14926e345bc4f9e1…
Author: Nate Coraor <nate(a)bx.psu.edu>
Date: 2014-09-11 (Thu, 11 Sep 2014)
Changed paths:
M stage/host_vars/login5.stampede.tacc.utexas.edu.yml
Log Message:
-----------
Update pulsar vars for new job_managers.ini template style.
1
0
[galaxyproject/usegalaxy-playbook] 87f275: Update galaxyprojectdotorg.pulsar to v0.3
by GitHub 11 Sep '14
by GitHub 11 Sep '14
11 Sep '14
Branch: refs/heads/master
Home: https://github.com/galaxyproject/usegalaxy-playbook
Commit: 87f2751c7c727d57146f436dcf0f10d3f089dbad
https://github.com/galaxyproject/usegalaxy-playbook/commit/87f2751c7c727d57…
Author: Nate Coraor <nate(a)bx.psu.edu>
Date: 2014-09-11 (Thu, 11 Sep 2014)
Changed paths:
M roles/galaxyprojectdotorg.pulsar/README.md
M roles/galaxyprojectdotorg.pulsar/defaults/main.yml
M roles/galaxyprojectdotorg.pulsar/meta/.galaxy_install_info
M roles/galaxyprojectdotorg.pulsar/tasks/main.yml
M roles/galaxyprojectdotorg.pulsar/templates/job_managers.ini.j2
Log Message:
-----------
Update galaxyprojectdotorg.pulsar to v0.3
1
0
7 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9278a44330b7/
Changeset: 9278a44330b7
User: jmchilton
Date: 2014-09-11 22:01:08
Summary: Initial work on a tags manager.
Rest of UsesTagsMixin needs to be copied over similarly and deprecated, following that I guess all references need to be updated and then the mixin eliminated all together I guess (exhausting :)).
Affected #: 3 files
diff -r da6e8248d7b402783e829f27ee1ab9e6ba4367d7 -r 9278a44330b7343a7f414057669fc1e047cfc1b6 lib/galaxy/dataset_collections/__init__.py
--- a/lib/galaxy/dataset_collections/__init__.py
+++ b/lib/galaxy/dataset_collections/__init__.py
@@ -10,9 +10,9 @@
from galaxy.web.base.controller import (
UsesHistoryDatasetAssociationMixin,
UsesLibraryMixinItems,
- UsesTagsMixin,
)
from galaxy.managers import hdas # TODO: Refactor all mixin use into managers.
+from galaxy.managers import tags
from galaxy.managers.collections_util import validate_input_element_identifiers
from galaxy.util import validation
from galaxy.util import odict
@@ -27,8 +27,7 @@
class DatasetCollectionsService(
UsesHistoryDatasetAssociationMixin,
- UsesLibraryMixinItems,
- UsesTagsMixin,
+ UsesLibraryMixinItems
):
"""
Abstraction for interfacing with dataset collections instance - ideally abstarcts
@@ -41,6 +40,7 @@
self.model = app.model
self.security = app.security
self.hda_manager = hdas.HDAManager()
+ self.tag_manager = tags.TagsManager( app )
def create(
self,
@@ -166,7 +166,7 @@
dataset_collection_instance.add_item_annotation( trans.sa_session, trans.get_user(), dataset_collection_instance, new_data[ 'annotation' ] )
changed[ 'annotation' ] = new_data[ 'annotation' ]
if 'tags' in new_data.keys() and trans.get_user():
- self.set_tags_from_list( trans, dataset_collection_instance, new_data[ 'tags' ], user=trans.user )
+ self.tag_manager.set_tags_from_list( trans, dataset_collection_instance, new_data[ 'tags' ], user=trans.user )
if changed.keys():
trans.sa_session.flush()
diff -r da6e8248d7b402783e829f27ee1ab9e6ba4367d7 -r 9278a44330b7343a7f414057669fc1e047cfc1b6 lib/galaxy/managers/tags.py
--- /dev/null
+++ b/lib/galaxy/managers/tags.py
@@ -0,0 +1,20 @@
+
+
+class TagsManager( object ):
+ """ Manages CRUD operations related to tagging objects.
+ """
+
+ def __init__( self, app ):
+ self.app = app
+ self.tag_handler = app.tag_handler
+
+ def set_tags_from_list( self, trans, item, new_tags_list, user=None ):
+ #precondition: item is already security checked against user
+ #precondition: incoming tags is a list of sanitized/formatted strings
+ user = user or trans.user
+
+ self.tag_handler.delete_item_tags( trans, user, item )
+ new_tags_str = ','.join( new_tags_list )
+ self.tag_handler.apply_item_tags( trans, user, item, unicode( new_tags_str.encode( 'utf-8' ), 'utf-8' ) )
+ trans.sa_session.flush()
+ return item.tags
diff -r da6e8248d7b402783e829f27ee1ab9e6ba4367d7 -r 9278a44330b7343a7f414057669fc1e047cfc1b6 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -38,6 +38,7 @@
from galaxy.model import ExtendedMetadata, ExtendedMetadataIndex, LibraryDatasetDatasetAssociation, HistoryDatasetAssociation
from galaxy.managers import api_keys
+from galaxy.managers import tags
from galaxy.datatypes.metadata import FileParameter
from galaxy.tools.parameters import RuntimeValue, visit_input_values
from galaxy.tools.parameters.basic import DataToolParameter
@@ -2808,16 +2809,9 @@
return self.get_tag_handler( trans )._get_item_tag_assoc( user, tagged_item, tag_name )
def set_tags_from_list( self, trans, item, new_tags_list, user=None ):
- #precondition: item is already security checked against user
- #precondition: incoming tags is a list of sanitized/formatted strings
- user = user or trans.user
-
- # based on controllers/tag retag_async: delete all old, reset to entire new
- trans.app.tag_handler.delete_item_tags( trans, user, item )
- new_tags_str = ','.join( new_tags_list )
- trans.app.tag_handler.apply_item_tags( trans, user, item, unicode( new_tags_str.encode( 'utf-8' ), 'utf-8' ) )
- trans.sa_session.flush()
- return item.tags
+ # Method deprecated - try to use TagsHandler instead.
+ tags_manager = tags.TagsManager( trans.app )
+ return tags_manager.set_tags_from_list( trans, item, new_tags_list, user=user )
def get_user_tags_used( self, trans, user=None ):
"""
https://bitbucket.org/galaxy/galaxy-central/commits/6f5195e15d09/
Changeset: 6f5195e15d09
User: jmchilton
Date: 2014-09-11 22:01:08
Summary: Refactor generic controller mixin code for security out for reuse in managers.
Affected #: 2 files
diff -r 9278a44330b7343a7f414057669fc1e047cfc1b6 -r 6f5195e15d0919790db68865dba5e365d67d14c1 lib/galaxy/managers/base.py
--- a/lib/galaxy/managers/base.py
+++ b/lib/galaxy/managers/base.py
@@ -1,7 +1,41 @@
+from galaxy import exceptions
class ModelManager( object ):
pass
+
class ModelSerializer( object ):
pass
+
+
+def security_check( trans, item, check_ownership=False, check_accessible=False ):
+ """ Security checks for an item: checks if (a) user owns item or (b) item
+ is accessible to user. This is a generic method for dealing with objects
+ uniformly from the older controller mixin code - however whenever possible
+ the managers for a particular model should be used to perform security
+ checks.
+ """
+
+ # all items are accessible to an admin
+ if trans.user_is_admin():
+ return item
+
+ # Verify ownership: there is a current user and that user is the same as the item's
+ if check_ownership:
+ if not trans.user:
+ raise exceptions.ItemOwnershipException( "Must be logged in to manage Galaxy items", type='error' )
+ if item.user != trans.user:
+ raise exceptions.ItemOwnershipException( "%s is not owned by the current user" % item.__class__.__name__, type='error' )
+
+ # Verify accessible:
+ # if it's part of a lib - can they access via security
+ # if it's something else (sharable) have they been added to the item's users_shared_with_dot_users
+ if check_accessible:
+ if type( item ) in ( trans.app.model.LibraryFolder, trans.app.model.LibraryDatasetDatasetAssociation, trans.app.model.LibraryDataset ):
+ if not trans.app.security_agent.can_access_library_item( trans.get_current_user_roles(), item, trans.user ):
+ raise exceptions.ItemAccessibilityException( "%s is not accessible to the current user" % item.__class__.__name__, type='error' )
+ else:
+ if ( item.user != trans.user ) and ( not item.importable ) and ( trans.user not in item.users_shared_with_dot_users ):
+ raise exceptions.ItemAccessibilityException( "%s is not accessible to the current user" % item.__class__.__name__, type='error' )
+ return item
diff -r 9278a44330b7343a7f414057669fc1e047cfc1b6 -r 6f5195e15d0919790db68865dba5e365d67d14c1 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -39,6 +39,7 @@
from galaxy.managers import api_keys
from galaxy.managers import tags
+from galaxy.managers import base as managers_base
from galaxy.datatypes.metadata import FileParameter
from galaxy.tools.parameters import RuntimeValue, visit_input_values
from galaxy.tools.parameters.basic import DataToolParameter
@@ -301,28 +302,7 @@
def security_check( self, trans, item, check_ownership=False, check_accessible=False ):
""" Security checks for an item: checks if (a) user owns item or (b) item is accessible to user. """
- # all items are accessible to an admin
- if trans.user_is_admin():
- return item
-
- # Verify ownership: there is a current user and that user is the same as the item's
- if check_ownership:
- if not trans.user:
- raise ItemOwnershipException( "Must be logged in to manage Galaxy items", type='error' )
- if item.user != trans.user:
- raise ItemOwnershipException( "%s is not owned by the current user" % item.__class__.__name__, type='error' )
-
- # Verify accessible:
- # if it's part of a lib - can they access via security
- # if it's something else (sharable) have they been added to the item's users_shared_with_dot_users
- if check_accessible:
- if type( item ) in ( trans.app.model.LibraryFolder, trans.app.model.LibraryDatasetDatasetAssociation, trans.app.model.LibraryDataset ):
- if not trans.app.security_agent.can_access_library_item( trans.get_current_user_roles(), item, trans.user ):
- raise ItemAccessibilityException( "%s is not accessible to the current user" % item.__class__.__name__, type='error' )
- else:
- if ( item.user != trans.user ) and ( not item.importable ) and ( trans.user not in item.users_shared_with_dot_users ):
- raise ItemAccessibilityException( "%s is not accessible to the current user" % item.__class__.__name__, type='error' )
- return item
+ return managers_base.security_check( trans, item, check_ownership=check_ownership, check_accessible=check_accessible )
class UsesHistoryMixin( SharableItemSecurityMixin ):
https://bitbucket.org/galaxy/galaxy-central/commits/83016af21151/
Changeset: 83016af21151
User: jmchilton
Date: 2014-09-11 22:01:08
Summary: Refactor generic controller mixin code for loading objects into managers.
Affected #: 2 files
diff -r 6f5195e15d0919790db68865dba5e365d67d14c1 -r 83016af2115156f4ebb640ea231824f23aeecad3 lib/galaxy/managers/base.py
--- a/lib/galaxy/managers/base.py
+++ b/lib/galaxy/managers/base.py
@@ -1,5 +1,12 @@
from galaxy import exceptions
+from galaxy import model
+from galaxy.model import tool_shed_install
+
+
+import logging
+log = logging.getLogger( __name__ )
+
class ModelManager( object ):
pass
@@ -39,3 +46,75 @@
if ( item.user != trans.user ) and ( not item.importable ) and ( trans.user not in item.users_shared_with_dot_users ):
raise exceptions.ItemAccessibilityException( "%s is not accessible to the current user" % item.__class__.__name__, type='error' )
return item
+
+
+def get_class( class_name ):
+ """ Returns the class object that a string denotes. Without this method, we'd have to do eval(<class_name>). """
+ if class_name == 'History':
+ item_class = model.History
+ elif class_name == 'HistoryDatasetAssociation':
+ item_class = model.HistoryDatasetAssociation
+ elif class_name == 'Page':
+ item_class = model.Page
+ elif class_name == 'StoredWorkflow':
+ item_class = model.StoredWorkflow
+ elif class_name == 'Visualization':
+ item_class = model.Visualization
+ elif class_name == 'Tool':
+ item_class = model.Tool
+ elif class_name == 'Job':
+ item_class = model.Job
+ elif class_name == 'User':
+ item_class = model.User
+ elif class_name == 'Group':
+ item_class = model.Group
+ elif class_name == 'Role':
+ item_class = model.Role
+ elif class_name == 'Quota':
+ item_class = model.Quota
+ elif class_name == 'Library':
+ item_class = model.Library
+ elif class_name == 'LibraryFolder':
+ item_class = model.LibraryFolder
+ elif class_name == 'LibraryDatasetDatasetAssociation':
+ item_class = model.LibraryDatasetDatasetAssociation
+ elif class_name == 'LibraryDataset':
+ item_class = model.LibraryDataset
+ elif class_name == 'ToolShedRepository':
+ item_class = tool_shed_install.ToolShedRepository
+ else:
+ item_class = None
+ return item_class
+
+
+def get_object( trans, id, class_name, check_ownership=False, check_accessible=False, deleted=None ):
+ """
+ Convenience method to get a model object with the specified checks. This is
+ a generic method for dealing with objects uniformly from the older
+ controller mixin code - however whenever possible the managers for a
+ particular model should be used to load objects.
+ """
+ try:
+ decoded_id = trans.security.decode_id( id )
+ except:
+ raise exceptions.MessageException( "Malformed %s id ( %s ) specified, unable to decode"
+ % ( class_name, str( id ) ), type='error' )
+ try:
+ item_class = get_class( class_name )
+ assert item_class is not None
+ item = trans.sa_session.query( item_class ).get( decoded_id )
+ assert item is not None
+ except Exception:
+ log.exception( "Invalid %s id ( %s ) specified." % ( class_name, id ) )
+ raise exceptions.MessageException( "Invalid %s id ( %s ) specified" % ( class_name, id ), type="error" )
+
+ if check_ownership or check_accessible:
+ security_check( trans, item, check_ownership, check_accessible )
+ if deleted is True and not item.deleted:
+ raise exceptions.ItemDeletionException( '%s "%s" is not deleted'
+ % ( class_name, getattr( item, 'name', id ) ), type="warning" )
+ elif deleted is False and item.deleted:
+ raise exceptions.ItemDeletionException( '%s "%s" is deleted'
+ % ( class_name, getattr( item, 'name', id ) ), type="warning" )
+ return item
+
diff -r 6f5195e15d0919790db68865dba5e365d67d14c1 -r 83016af2115156f4ebb640ea231824f23aeecad3 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -78,70 +78,14 @@
def get_class( self, class_name ):
""" Returns the class object that a string denotes. Without this method, we'd have to do eval(<class_name>). """
- if class_name == 'History':
- item_class = self.app.model.History
- elif class_name == 'HistoryDatasetAssociation':
- item_class = self.app.model.HistoryDatasetAssociation
- elif class_name == 'Page':
- item_class = self.app.model.Page
- elif class_name == 'StoredWorkflow':
- item_class = self.app.model.StoredWorkflow
- elif class_name == 'Visualization':
- item_class = self.app.model.Visualization
- elif class_name == 'Tool':
- item_class = self.app.model.Tool
- elif class_name == 'Job':
- item_class = self.app.model.Job
- elif class_name == 'User':
- item_class = self.app.model.User
- elif class_name == 'Group':
- item_class = self.app.model.Group
- elif class_name == 'Role':
- item_class = self.app.model.Role
- elif class_name == 'Quota':
- item_class = self.app.model.Quota
- elif class_name == 'Library':
- item_class = self.app.model.Library
- elif class_name == 'LibraryFolder':
- item_class = self.app.model.LibraryFolder
- elif class_name == 'LibraryDatasetDatasetAssociation':
- item_class = self.app.model.LibraryDatasetDatasetAssociation
- elif class_name == 'LibraryDataset':
- item_class = self.app.model.LibraryDataset
- elif class_name == 'ToolShedRepository':
- item_class = self.app.install_model.ToolShedRepository
- else:
- item_class = None
- return item_class
+ return managers_base.get_class( class_name )
def get_object( self, trans, id, class_name, check_ownership=False, check_accessible=False, deleted=None ):
"""
Convenience method to get a model object with the specified checks.
"""
- try:
- decoded_id = trans.security.decode_id( id )
- except:
- raise MessageException( "Malformed %s id ( %s ) specified, unable to decode"
- % ( class_name, str( id ) ), type='error' )
- try:
- item_class = self.get_class( class_name )
- assert item_class is not None
- item = trans.sa_session.query( item_class ).get( decoded_id )
- assert item is not None
- except Exception:
- log.exception( "Invalid %s id ( %s ) specified." % ( class_name, id ) )
- raise MessageException( "Invalid %s id ( %s ) specified" % ( class_name, id ), type="error" )
-
- if check_ownership or check_accessible:
- self.security_check( trans, item, check_ownership, check_accessible )
- if deleted == True and not item.deleted:
- raise ItemDeletionException( '%s "%s" is not deleted'
- % ( class_name, getattr( item, 'name', id ) ), type="warning" )
- elif deleted == False and item.deleted:
- raise ItemDeletionException( '%s "%s" is deleted'
- % ( class_name, getattr( item, 'name', id ) ), type="warning" )
- return item
-
+ return managers_base.get_object( trans, id, class_name, check_ownership=check_ownership, check_accessible=check_accessible, deleted=deleted )
+
# this should be here - but catching errors from sharable item controllers that *should* have SharableItemMixin
# but *don't* then becomes difficult
#def security_check( self, trans, item, check_ownership=False, check_accessible=False ):
https://bitbucket.org/galaxy/galaxy-central/commits/355aee34a371/
Changeset: 355aee34a371
User: jmchilton
Date: 2014-09-11 22:01:08
Summary: Introduce LDDA manager stub.
Use it to eliminate awful controller dependencies (and associated circular dependency errors when controllers are not loaded before everything else) in galaxy.dataset_collections.
Affected #: 3 files
diff -r 83016af2115156f4ebb640ea231824f23aeecad3 -r 355aee34a371c99f9251b965ea625066a80419ea lib/galaxy/dataset_collections/__init__.py
--- a/lib/galaxy/dataset_collections/__init__.py
+++ b/lib/galaxy/dataset_collections/__init__.py
@@ -7,11 +7,9 @@
from galaxy.exceptions import MessageException
from galaxy.exceptions import ItemAccessibilityException
from galaxy.exceptions import RequestParameterInvalidException
-from galaxy.web.base.controller import (
- UsesHistoryDatasetAssociationMixin,
- UsesLibraryMixinItems,
-)
from galaxy.managers import hdas # TODO: Refactor all mixin use into managers.
+from galaxy.managers import histories
+from galaxy.managers import lddas
from galaxy.managers import tags
from galaxy.managers.collections_util import validate_input_element_identifiers
from galaxy.util import validation
@@ -25,10 +23,7 @@
ERROR_NO_COLLECTION_TYPE = "Create called without specifing a collection type."
-class DatasetCollectionsService(
- UsesHistoryDatasetAssociationMixin,
- UsesLibraryMixinItems
-):
+class DatasetCollectionsService( object ):
"""
Abstraction for interfacing with dataset collections instance - ideally abstarcts
out model and plugin details.
@@ -40,7 +35,9 @@
self.model = app.model
self.security = app.security
self.hda_manager = hdas.HDAManager()
+ self.history_manager = histories.HistoryManager()
self.tag_manager = tags.TagsManager( app )
+ self.ldda_manager = lddas.LDDAManager( )
def create(
self,
@@ -249,7 +246,7 @@
decoded_id = int( trans.app.security.decode_id( encoded_id ) )
element = self.hda_manager.get( trans, decoded_id, check_ownership=False )
elif src_type == 'ldda':
- element = self.get_library_dataset_dataset_association( trans, encoded_id )
+ element = self.ldda_manager.get( trans, encoded_id )
elif src_type == 'hdca':
# TODO: Option to copy? Force copy? Copy or allow if not owned?
element = self.__get_history_collection_instance( trans, encoded_id ).collection
@@ -281,7 +278,7 @@
def __get_history_collection_instance( self, trans, id, check_ownership=False, check_accessible=True ):
instance_id = int( trans.app.security.decode_id( id ) )
collection_instance = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( instance_id )
- self.security_check( trans, collection_instance.history, check_ownership=check_ownership, check_accessible=check_accessible )
+ self.history_manager.secure( trans, collection_instance.history, check_ownership=check_ownership, check_accessible=check_accessible )
return collection_instance
def __get_library_collection_instance( self, trans, id, check_ownership=False, check_accessible=True ):
diff -r 83016af2115156f4ebb640ea231824f23aeecad3 -r 355aee34a371c99f9251b965ea625066a80419ea lib/galaxy/managers/lddas.py
--- /dev/null
+++ b/lib/galaxy/managers/lddas.py
@@ -0,0 +1,16 @@
+from galaxy.managers import base as manager_base
+
+
+class LDDAManager( manager_base.ModelManager ):
+ """ A fairly sparse manager for LDDAs.
+ """
+
+ def __init__( self ):
+ """
+ Set up and initialize other managers needed by lddas.
+ """
+ pass
+
+ def get( self, trans, id, check_accessible=True ):
+ return manager_base.get_object( trans, id, 'LibraryDatasetDatasetAssociation',
+ check_ownership=False, check_accessible=check_accessible )
diff -r 83016af2115156f4ebb640ea231824f23aeecad3 -r 355aee34a371c99f9251b965ea625066a80419ea lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -875,6 +875,9 @@
check_ownership=False, check_accessible=check_accessible )
def get_library_dataset_dataset_association( self, trans, id, check_ownership=False, check_accessible=True ):
+ # Deprecated in lieu to galaxy.managers.lddas.LDDAManager.get() but not
+ # reusing that exactly because of subtle differences in exception handling
+ # logic (API controller override get_object to be slightly different).
return self.get_object( trans, id, 'LibraryDatasetDatasetAssociation',
check_ownership=False, check_accessible=check_accessible )
https://bitbucket.org/galaxy/galaxy-central/commits/dd31ab49162d/
Changeset: dd31ab49162d
User: jmchilton
Date: 2014-09-11 22:01:08
Summary: Make dataset collections service a manager.
It would hve been arcitected this way from the beginning but my initial work on it predated Carl's managers work and it had those pesky controller dependencies.
Affected #: 3 files
diff -r 355aee34a371c99f9251b965ea625066a80419ea -r dd31ab49162d3faa30818947a80a6165c2f0b4c7 lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -5,7 +5,7 @@
from galaxy import config, jobs
import galaxy.model
import galaxy.security
-from galaxy import dataset_collections
+from galaxy.managers.collections import DatasetCollectionManager
import galaxy.quota
from galaxy.tags.tag_handler import GalaxyTagHandler
from galaxy.visualization.genomes import Genomes
@@ -57,7 +57,7 @@
# Tag handler
self.tag_handler = GalaxyTagHandler()
# Dataset Collection Plugins
- self.dataset_collections_service = dataset_collections.DatasetCollectionsService(self)
+ self.dataset_collections_service = DatasetCollectionManager(self)
# Tool Data Tables
self._configure_tool_data_tables( from_shed_config=False )
diff -r 355aee34a371c99f9251b965ea625066a80419ea -r dd31ab49162d3faa30818947a80a6165c2f0b4c7 lib/galaxy/dataset_collections/__init__.py
--- a/lib/galaxy/dataset_collections/__init__.py
+++ b/lib/galaxy/dataset_collections/__init__.py
@@ -1,292 +0,0 @@
-from .registry import DatasetCollectionTypesRegistry
-from .matching import MatchingCollections
-from .type_description import CollectionTypeDescriptionFactory
-
-
-from galaxy import model
-from galaxy.exceptions import MessageException
-from galaxy.exceptions import ItemAccessibilityException
-from galaxy.exceptions import RequestParameterInvalidException
-from galaxy.managers import hdas # TODO: Refactor all mixin use into managers.
-from galaxy.managers import histories
-from galaxy.managers import lddas
-from galaxy.managers import tags
-from galaxy.managers.collections_util import validate_input_element_identifiers
-from galaxy.util import validation
-from galaxy.util import odict
-
-import logging
-log = logging.getLogger( __name__ )
-
-
-ERROR_INVALID_ELEMENTS_SPECIFICATION = "Create called with invalid parameters, must specify element identifiers."
-ERROR_NO_COLLECTION_TYPE = "Create called without specifing a collection type."
-
-
-class DatasetCollectionsService( object ):
- """
- Abstraction for interfacing with dataset collections instance - ideally abstarcts
- out model and plugin details.
- """
-
- def __init__( self, app ):
- self.type_registry = DatasetCollectionTypesRegistry( app )
- self.collection_type_descriptions = CollectionTypeDescriptionFactory( self.type_registry )
- self.model = app.model
- self.security = app.security
- self.hda_manager = hdas.HDAManager()
- self.history_manager = histories.HistoryManager()
- self.tag_manager = tags.TagsManager( app )
- self.ldda_manager = lddas.LDDAManager( )
-
- def create(
- self,
- trans,
- parent, # PRECONDITION: security checks on ability to add to parent occurred during load.
- name,
- collection_type,
- element_identifiers=None,
- elements=None,
- implicit_collection_info=None,
- ):
- """
- """
- # Trust embedded, newly created objects created by tool subsystem.
- trusted_identifiers = implicit_collection_info is not None
-
- if element_identifiers and not trusted_identifiers:
- validate_input_element_identifiers( element_identifiers )
-
- dataset_collection = self.__create_dataset_collection(
- trans=trans,
- collection_type=collection_type,
- element_identifiers=element_identifiers,
- elements=elements,
- )
- if isinstance( parent, model.History ):
- dataset_collection_instance = self.model.HistoryDatasetCollectionAssociation(
- collection=dataset_collection,
- name=name,
- )
- if implicit_collection_info:
- for input_name, input_collection in implicit_collection_info[ "implicit_inputs" ]:
- dataset_collection_instance.add_implicit_input_collection( input_name, input_collection )
- for output_dataset in implicit_collection_info.get( "outputs" ):
- output_dataset.hidden_beneath_collection_instance = dataset_collection_instance
- trans.sa_session.add( output_dataset )
-
- dataset_collection_instance.implicit_output_name = implicit_collection_info[ "implicit_output_name" ]
- log.debug("Created collection with %d elements" % ( len( dataset_collection_instance.collection.elements ) ) )
- # Handle setting hid
- parent.add_dataset_collection( dataset_collection_instance )
- elif isinstance( parent, model.LibraryFolder ):
- dataset_collection_instance = self.model.LibraryDatasetCollectionAssociation(
- collection=dataset_collection,
- folder=parent,
- name=name,
- )
- else:
- message = "Internal logic error - create called with unknown parent type %s" % type( parent )
- log.exception( message )
- raise MessageException( message )
-
- return self.__persist( dataset_collection_instance )
-
- def __create_dataset_collection(
- self,
- trans,
- collection_type,
- element_identifiers=None,
- elements=None,
- ):
- if element_identifiers is None and elements is None:
- raise RequestParameterInvalidException( ERROR_INVALID_ELEMENTS_SPECIFICATION )
- if not collection_type:
- raise RequestParameterInvalidException( ERROR_NO_COLLECTION_TYPE )
- collection_type_description = self.collection_type_descriptions.for_collection_type( collection_type )
- # If we have elements, this is an internal request, don't need to load
- # objects from identifiers.
- if elements is None:
- if collection_type_description.has_subcollections( ):
- # Nested collection - recursively create collections and update identifiers.
- self.__recursively_create_collections( trans, element_identifiers )
- elements = self.__load_elements( trans, element_identifiers )
- # else if elements is set, it better be an ordered dict!
-
- type_plugin = collection_type_description.rank_type_plugin()
- dataset_collection = type_plugin.build_collection( elements )
- dataset_collection.collection_type = collection_type
- return dataset_collection
-
- def delete( self, trans, instance_type, id ):
- dataset_collection_instance = self.get_dataset_collection_instance( trans, instance_type, id, check_ownership=True )
- dataset_collection_instance.deleted = True
- trans.sa_session.add( dataset_collection_instance )
- trans.sa_session.flush( )
-
- def update( self, trans, instance_type, id, payload ):
- dataset_collection_instance = self.get_dataset_collection_instance( trans, instance_type, id, check_ownership=True )
- if trans.user is None:
- anon_allowed_payload = {}
- if 'deleted' in payload:
- anon_allowed_payload[ 'deleted' ] = payload[ 'deleted' ]
- if 'visible' in payload:
- anon_allowed_payload[ 'visible' ] = payload[ 'visible' ]
- payload = self._validate_and_parse_update_payload( anon_allowed_payload )
- else:
- payload = self._validate_and_parse_update_payload( payload )
- changed = self._set_from_dict( trans, dataset_collection_instance, payload )
- return changed
-
- def copy(
- self,
- trans,
- parent, # PRECONDITION: security checks on ability to add to parent occurred during load.
- source,
- encoded_source_id,
- ):
- assert source == "hdca" # for now
- source_hdca = self.__get_history_collection_instance( trans, encoded_source_id )
- new_hdca = source_hdca.copy()
- parent.add_dataset_collection( new_hdca )
- trans.sa_session.add( new_hdca )
- trans.sa_session.flush()
- return source_hdca
-
- def _set_from_dict( self, trans, dataset_collection_instance, new_data ):
- # Blatantly stolen from UsesHistoryDatasetAssociationMixin.set_hda_from_dict.
-
- # send what we can down into the model
- changed = dataset_collection_instance.set_from_dict( new_data )
- # the rest (often involving the trans) - do here
- if 'annotation' in new_data.keys() and trans.get_user():
- dataset_collection_instance.add_item_annotation( trans.sa_session, trans.get_user(), dataset_collection_instance, new_data[ 'annotation' ] )
- changed[ 'annotation' ] = new_data[ 'annotation' ]
- if 'tags' in new_data.keys() and trans.get_user():
- self.tag_manager.set_tags_from_list( trans, dataset_collection_instance, new_data[ 'tags' ], user=trans.user )
-
- if changed.keys():
- trans.sa_session.flush()
-
- return changed
-
- def _validate_and_parse_update_payload( self, payload ):
- validated_payload = {}
- for key, val in payload.items():
- if val is None:
- continue
- if key in ( 'name' ):
- val = validation.validate_and_sanitize_basestring( key, val )
- validated_payload[ key ] = val
- if key in ( 'deleted', 'visible' ):
- validated_payload[ key ] = validation.validate_boolean( key, val )
- elif key == 'tags':
- validated_payload[ key ] = validation.validate_and_sanitize_basestring_list( key, val )
- return validated_payload
-
- def history_dataset_collections(self, history, query):
- collections = history.active_dataset_collections
- collections = filter( query.direct_match, collections )
- return collections
-
- def __persist( self, dataset_collection_instance ):
- context = self.model.context
- context.add( dataset_collection_instance )
- context.flush()
- return dataset_collection_instance
-
- def __recursively_create_collections( self, trans, element_identifiers ):
- for index, element_identifier in enumerate( element_identifiers ):
- try:
- if not element_identifier[ "src" ] == "new_collection":
- # not a new collection, keep moving...
- continue
- except KeyError:
- # Not a dictionary, just an id of an HDA - move along.
- continue
-
- # element identifier is a dict with src new_collection...
- collection_type = element_identifier.get( "collection_type", None )
- collection = self.__create_dataset_collection(
- trans=trans,
- collection_type=collection_type,
- element_identifiers=element_identifier[ "element_identifiers" ],
- )
- element_identifier[ "__object__" ] = collection
-
- return element_identifiers
-
- def __load_elements( self, trans, element_identifiers ):
- elements = odict.odict()
- for element_identifier in element_identifiers:
- elements[ element_identifier[ "name" ] ] = self.__load_element( trans, element_identifier )
- return elements
-
- def __load_element( self, trans, element_identifier ):
- #if not isinstance( element_identifier, dict ):
- # # Is allowing this to just be the id of an hda too clever? Somewhat
- # # consistent with other API methods though.
- # element_identifier = dict( src='hda', id=str( element_identifier ) )
-
- # Previously created collection already found in request, just pass
- # through as is.
- if "__object__" in element_identifier:
- return element_identifier[ "__object__" ]
-
- # dateset_identifier is dict {src=hda|ldda|hdca|new_collection, id=<encoded_id>}
- try:
- src_type = element_identifier.get( 'src', 'hda' )
- except AttributeError:
- raise MessageException( "Dataset collection element definition (%s) not dictionary-like." % element_identifier )
- encoded_id = element_identifier.get( 'id', None )
- if not src_type or not encoded_id:
- raise RequestParameterInvalidException( "Problem decoding element identifier %s" % element_identifier )
-
- if src_type == 'hda':
- decoded_id = int( trans.app.security.decode_id( encoded_id ) )
- element = self.hda_manager.get( trans, decoded_id, check_ownership=False )
- elif src_type == 'ldda':
- element = self.ldda_manager.get( trans, encoded_id )
- elif src_type == 'hdca':
- # TODO: Option to copy? Force copy? Copy or allow if not owned?
- element = self.__get_history_collection_instance( trans, encoded_id ).collection
- # TODO: ldca.
- else:
- raise RequestParameterInvalidException( "Unknown src_type parameter supplied '%s'." % src_type )
- return element
-
- def match_collections( self, collections_to_match ):
- """
- May seem odd to place it here, but planning to grow sophistication and
- get plugin types involved so it will likely make sense in the future.
- """
- return MatchingCollections.for_collections( collections_to_match, self.collection_type_descriptions )
-
- def get_dataset_collection_instance( self, trans, instance_type, id, **kwds ):
- """
- """
- if instance_type == "history":
- return self.__get_history_collection_instance( trans, id, **kwds )
- elif instance_type == "library":
- return self.__get_library_collection_instance( trans, id, **kwds )
-
- def get_dataset_collection( self, trans, encoded_id ):
- collection_id = int( trans.app.security.decode_id( encoded_id ) )
- collection = trans.sa_session.query( trans.app.model.DatasetCollection ).get( collection_id )
- return collection
-
- def __get_history_collection_instance( self, trans, id, check_ownership=False, check_accessible=True ):
- instance_id = int( trans.app.security.decode_id( id ) )
- collection_instance = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( instance_id )
- self.history_manager.secure( trans, collection_instance.history, check_ownership=check_ownership, check_accessible=check_accessible )
- return collection_instance
-
- def __get_library_collection_instance( self, trans, id, check_ownership=False, check_accessible=True ):
- if check_ownership:
- raise NotImplemented( "Functionality (getting library dataset collection with ownership check) unimplemented." )
- instance_id = int( trans.security.decode_id( id ) )
- collection_instance = trans.sa_session.query( trans.app.model.LibraryDatasetCollectionAssociation ).get( instance_id )
- if check_accessible:
- if not trans.app.security_agent.can_access_library_item( trans.get_current_user_roles(), collection_instance, trans.user ):
- raise ItemAccessibilityException( "LibraryDatasetCollectionAssociation is not accessible to the current user", type='error' )
- return collection_instance
diff -r 355aee34a371c99f9251b965ea625066a80419ea -r dd31ab49162d3faa30818947a80a6165c2f0b4c7 lib/galaxy/managers/collections.py
--- a/lib/galaxy/managers/collections.py
+++ b/lib/galaxy/managers/collections.py
@@ -1,1 +1,291 @@
-""" Future home of dataset collections managers. """
+from galaxy.dataset_collections.registry import DatasetCollectionTypesRegistry
+from galaxy.dataset_collections.matching import MatchingCollections
+from galaxy.dataset_collections.type_description import CollectionTypeDescriptionFactory
+
+from galaxy import model
+from galaxy.exceptions import MessageException
+from galaxy.exceptions import ItemAccessibilityException
+from galaxy.exceptions import RequestParameterInvalidException
+from galaxy.managers import hdas # TODO: Refactor all mixin use into managers.
+from galaxy.managers import histories
+from galaxy.managers import lddas
+from galaxy.managers import tags
+from galaxy.managers.collections_util import validate_input_element_identifiers
+from galaxy.util import validation
+from galaxy.util import odict
+
+import logging
+log = logging.getLogger( __name__ )
+
+
+ERROR_INVALID_ELEMENTS_SPECIFICATION = "Create called with invalid parameters, must specify element identifiers."
+ERROR_NO_COLLECTION_TYPE = "Create called without specifing a collection type."
+
+
+class DatasetCollectionManager( object ):
+ """
+ Abstraction for interfacing with dataset collections instance - ideally abstarcts
+ out model and plugin details.
+ """
+
+ def __init__( self, app ):
+ self.type_registry = DatasetCollectionTypesRegistry( app )
+ self.collection_type_descriptions = CollectionTypeDescriptionFactory( self.type_registry )
+ self.model = app.model
+ self.security = app.security
+ self.hda_manager = hdas.HDAManager()
+ self.history_manager = histories.HistoryManager()
+ self.tag_manager = tags.TagsManager( app )
+ self.ldda_manager = lddas.LDDAManager( )
+
+ def create(
+ self,
+ trans,
+ parent, # PRECONDITION: security checks on ability to add to parent occurred during load.
+ name,
+ collection_type,
+ element_identifiers=None,
+ elements=None,
+ implicit_collection_info=None,
+ ):
+ """
+ """
+ # Trust embedded, newly created objects created by tool subsystem.
+ trusted_identifiers = implicit_collection_info is not None
+
+ if element_identifiers and not trusted_identifiers:
+ validate_input_element_identifiers( element_identifiers )
+
+ dataset_collection = self.__create_dataset_collection(
+ trans=trans,
+ collection_type=collection_type,
+ element_identifiers=element_identifiers,
+ elements=elements,
+ )
+ if isinstance( parent, model.History ):
+ dataset_collection_instance = self.model.HistoryDatasetCollectionAssociation(
+ collection=dataset_collection,
+ name=name,
+ )
+ if implicit_collection_info:
+ for input_name, input_collection in implicit_collection_info[ "implicit_inputs" ]:
+ dataset_collection_instance.add_implicit_input_collection( input_name, input_collection )
+ for output_dataset in implicit_collection_info.get( "outputs" ):
+ output_dataset.hidden_beneath_collection_instance = dataset_collection_instance
+ trans.sa_session.add( output_dataset )
+
+ dataset_collection_instance.implicit_output_name = implicit_collection_info[ "implicit_output_name" ]
+ log.debug("Created collection with %d elements" % ( len( dataset_collection_instance.collection.elements ) ) )
+ # Handle setting hid
+ parent.add_dataset_collection( dataset_collection_instance )
+ elif isinstance( parent, model.LibraryFolder ):
+ dataset_collection_instance = self.model.LibraryDatasetCollectionAssociation(
+ collection=dataset_collection,
+ folder=parent,
+ name=name,
+ )
+ else:
+ message = "Internal logic error - create called with unknown parent type %s" % type( parent )
+ log.exception( message )
+ raise MessageException( message )
+
+ return self.__persist( dataset_collection_instance )
+
+ def __create_dataset_collection(
+ self,
+ trans,
+ collection_type,
+ element_identifiers=None,
+ elements=None,
+ ):
+ if element_identifiers is None and elements is None:
+ raise RequestParameterInvalidException( ERROR_INVALID_ELEMENTS_SPECIFICATION )
+ if not collection_type:
+ raise RequestParameterInvalidException( ERROR_NO_COLLECTION_TYPE )
+ collection_type_description = self.collection_type_descriptions.for_collection_type( collection_type )
+ # If we have elements, this is an internal request, don't need to load
+ # objects from identifiers.
+ if elements is None:
+ if collection_type_description.has_subcollections( ):
+ # Nested collection - recursively create collections and update identifiers.
+ self.__recursively_create_collections( trans, element_identifiers )
+ elements = self.__load_elements( trans, element_identifiers )
+ # else if elements is set, it better be an ordered dict!
+
+ type_plugin = collection_type_description.rank_type_plugin()
+ dataset_collection = type_plugin.build_collection( elements )
+ dataset_collection.collection_type = collection_type
+ return dataset_collection
+
+ def delete( self, trans, instance_type, id ):
+ dataset_collection_instance = self.get_dataset_collection_instance( trans, instance_type, id, check_ownership=True )
+ dataset_collection_instance.deleted = True
+ trans.sa_session.add( dataset_collection_instance )
+ trans.sa_session.flush( )
+
+ def update( self, trans, instance_type, id, payload ):
+ dataset_collection_instance = self.get_dataset_collection_instance( trans, instance_type, id, check_ownership=True )
+ if trans.user is None:
+ anon_allowed_payload = {}
+ if 'deleted' in payload:
+ anon_allowed_payload[ 'deleted' ] = payload[ 'deleted' ]
+ if 'visible' in payload:
+ anon_allowed_payload[ 'visible' ] = payload[ 'visible' ]
+ payload = self._validate_and_parse_update_payload( anon_allowed_payload )
+ else:
+ payload = self._validate_and_parse_update_payload( payload )
+ changed = self._set_from_dict( trans, dataset_collection_instance, payload )
+ return changed
+
+ def copy(
+ self,
+ trans,
+ parent, # PRECONDITION: security checks on ability to add to parent occurred during load.
+ source,
+ encoded_source_id,
+ ):
+ assert source == "hdca" # for now
+ source_hdca = self.__get_history_collection_instance( trans, encoded_source_id )
+ new_hdca = source_hdca.copy()
+ parent.add_dataset_collection( new_hdca )
+ trans.sa_session.add( new_hdca )
+ trans.sa_session.flush()
+ return source_hdca
+
+ def _set_from_dict( self, trans, dataset_collection_instance, new_data ):
+ # Blatantly stolen from UsesHistoryDatasetAssociationMixin.set_hda_from_dict.
+
+ # send what we can down into the model
+ changed = dataset_collection_instance.set_from_dict( new_data )
+ # the rest (often involving the trans) - do here
+ if 'annotation' in new_data.keys() and trans.get_user():
+ dataset_collection_instance.add_item_annotation( trans.sa_session, trans.get_user(), dataset_collection_instance, new_data[ 'annotation' ] )
+ changed[ 'annotation' ] = new_data[ 'annotation' ]
+ if 'tags' in new_data.keys() and trans.get_user():
+ self.tag_manager.set_tags_from_list( trans, dataset_collection_instance, new_data[ 'tags' ], user=trans.user )
+
+ if changed.keys():
+ trans.sa_session.flush()
+
+ return changed
+
+ def _validate_and_parse_update_payload( self, payload ):
+ validated_payload = {}
+ for key, val in payload.items():
+ if val is None:
+ continue
+ if key in ( 'name' ):
+ val = validation.validate_and_sanitize_basestring( key, val )
+ validated_payload[ key ] = val
+ if key in ( 'deleted', 'visible' ):
+ validated_payload[ key ] = validation.validate_boolean( key, val )
+ elif key == 'tags':
+ validated_payload[ key ] = validation.validate_and_sanitize_basestring_list( key, val )
+ return validated_payload
+
+ def history_dataset_collections(self, history, query):
+ collections = history.active_dataset_collections
+ collections = filter( query.direct_match, collections )
+ return collections
+
+ def __persist( self, dataset_collection_instance ):
+ context = self.model.context
+ context.add( dataset_collection_instance )
+ context.flush()
+ return dataset_collection_instance
+
+ def __recursively_create_collections( self, trans, element_identifiers ):
+ for index, element_identifier in enumerate( element_identifiers ):
+ try:
+ if not element_identifier[ "src" ] == "new_collection":
+ # not a new collection, keep moving...
+ continue
+ except KeyError:
+ # Not a dictionary, just an id of an HDA - move along.
+ continue
+
+ # element identifier is a dict with src new_collection...
+ collection_type = element_identifier.get( "collection_type", None )
+ collection = self.__create_dataset_collection(
+ trans=trans,
+ collection_type=collection_type,
+ element_identifiers=element_identifier[ "element_identifiers" ],
+ )
+ element_identifier[ "__object__" ] = collection
+
+ return element_identifiers
+
+ def __load_elements( self, trans, element_identifiers ):
+ elements = odict.odict()
+ for element_identifier in element_identifiers:
+ elements[ element_identifier[ "name" ] ] = self.__load_element( trans, element_identifier )
+ return elements
+
+ def __load_element( self, trans, element_identifier ):
+ #if not isinstance( element_identifier, dict ):
+ # # Is allowing this to just be the id of an hda too clever? Somewhat
+ # # consistent with other API methods though.
+ # element_identifier = dict( src='hda', id=str( element_identifier ) )
+
+ # Previously created collection already found in request, just pass
+ # through as is.
+ if "__object__" in element_identifier:
+ return element_identifier[ "__object__" ]
+
+ # dateset_identifier is dict {src=hda|ldda|hdca|new_collection, id=<encoded_id>}
+ try:
+ src_type = element_identifier.get( 'src', 'hda' )
+ except AttributeError:
+ raise MessageException( "Dataset collection element definition (%s) not dictionary-like." % element_identifier )
+ encoded_id = element_identifier.get( 'id', None )
+ if not src_type or not encoded_id:
+ raise RequestParameterInvalidException( "Problem decoding element identifier %s" % element_identifier )
+
+ if src_type == 'hda':
+ decoded_id = int( trans.app.security.decode_id( encoded_id ) )
+ element = self.hda_manager.get( trans, decoded_id, check_ownership=False )
+ elif src_type == 'ldda':
+ element = self.ldda_manager.get( trans, encoded_id )
+ elif src_type == 'hdca':
+ # TODO: Option to copy? Force copy? Copy or allow if not owned?
+ element = self.__get_history_collection_instance( trans, encoded_id ).collection
+ # TODO: ldca.
+ else:
+ raise RequestParameterInvalidException( "Unknown src_type parameter supplied '%s'." % src_type )
+ return element
+
+ def match_collections( self, collections_to_match ):
+ """
+ May seem odd to place it here, but planning to grow sophistication and
+ get plugin types involved so it will likely make sense in the future.
+ """
+ return MatchingCollections.for_collections( collections_to_match, self.collection_type_descriptions )
+
+ def get_dataset_collection_instance( self, trans, instance_type, id, **kwds ):
+ """
+ """
+ if instance_type == "history":
+ return self.__get_history_collection_instance( trans, id, **kwds )
+ elif instance_type == "library":
+ return self.__get_library_collection_instance( trans, id, **kwds )
+
+ def get_dataset_collection( self, trans, encoded_id ):
+ collection_id = int( trans.app.security.decode_id( encoded_id ) )
+ collection = trans.sa_session.query( trans.app.model.DatasetCollection ).get( collection_id )
+ return collection
+
+ def __get_history_collection_instance( self, trans, id, check_ownership=False, check_accessible=True ):
+ instance_id = int( trans.app.security.decode_id( id ) )
+ collection_instance = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( instance_id )
+ self.history_manager.secure( trans, collection_instance.history, check_ownership=check_ownership, check_accessible=check_accessible )
+ return collection_instance
+
+ def __get_library_collection_instance( self, trans, id, check_ownership=False, check_accessible=True ):
+ if check_ownership:
+ raise NotImplemented( "Functionality (getting library dataset collection with ownership check) unimplemented." )
+ instance_id = int( trans.security.decode_id( id ) )
+ collection_instance = trans.sa_session.query( trans.app.model.LibraryDatasetCollectionAssociation ).get( instance_id )
+ if check_accessible:
+ if not trans.app.security_agent.can_access_library_item( trans.get_current_user_roles(), collection_instance, trans.user ):
+ raise ItemAccessibilityException( "LibraryDatasetCollectionAssociation is not accessible to the current user", type='error' )
+ return collection_instance
https://bitbucket.org/galaxy/galaxy-central/commits/d2ec0f230bda/
Changeset: d2ec0f230bda
User: jmchilton
Date: 2014-09-11 22:01:08
Summary: Work on workflow module testing.
Affected #: 3 files
diff -r dd31ab49162d3faa30818947a80a6165c2f0b4c7 -r d2ec0f230bdaed4ce52607b6ac1b6d5348dc1834 lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -120,6 +120,11 @@
## ---- Run time ---------------------------------------------------------
def get_runtime_inputs( self ):
+ """ Used internally to modules and when displaying inputs in display
+ and run workflow templates. The ToolModule doesn't implement this and
+ these templates contain specialized logic for dealing with the tool and
+ state directly in these cases.
+ """
raise TypeError( "Abstract method" )
def encode_runtime_state( self, trans, state ):
diff -r dd31ab49162d3faa30818947a80a6165c2f0b4c7 -r d2ec0f230bdaed4ce52607b6ac1b6d5348dc1834 test/unit/workflows/test_modules.py
--- a/test/unit/workflows/test_modules.py
+++ b/test/unit/workflows/test_modules.py
@@ -1,16 +1,19 @@
from galaxy import eggs
eggs.require( "mock" )
-
+import json
import mock
+from galaxy import model
+
from galaxy.workflow import modules
+from galaxy.tools import parameters
from .workflow_support import MockTrans
def test_input_has_no_errors():
trans = MockTrans()
- input_step_module = modules.module_factory.new( trans, 'data_input' )
+ input_step_module = modules.module_factory.new( trans, "data_input" )
assert not input_step_module.get_errors()
@@ -18,15 +21,129 @@
trans = MockTrans()
mock_tool = mock.Mock()
trans.app.toolbox.tools[ "cat1" ] = mock_tool
- tool_module = modules.module_factory.new( trans, 'tool', tool_id="cat1" )
+ tool_module = modules.module_factory.new( trans, "tool", tool_id="cat1" )
assert not tool_module.get_errors()
+def test_data_input_default_state():
+ trans = MockTrans()
+ module = modules.module_factory.new( trans, "data_input" )
+ __assert_has_runtime_input( module, label="Input Dataset" )
+
+
+def test_data_input_modified_state():
+ module = __from_state( {
+ "type": "data_input",
+ "tool_state": json.dumps({ "name": "Cool Input" }),
+ } )
+ __assert_has_runtime_input( module, label="Cool Input" )
+
+
+def test_data_input_step_modified_state():
+ module = __from_step(
+ type="data_input",
+ tool_inputs={
+ "name": "Cool Input",
+ },
+ )
+ __assert_has_runtime_input( module, label="Cool Input" )
+
+
+def test_data_input_compute_state_default():
+ module = __from_step(
+ type="data_input",
+ )
+ state, errors = module.compute_state( module.trans )
+ assert not errors
+ assert 'input' in state.inputs
+ assert state.inputs[ 'input' ] is None
+
+
+def test_data_input_compute_state_args():
+ module = __from_step(
+ type="data_input",
+ )
+ tool_state = module.encode_runtime_state( module.trans, module.test_step.state )
+
+ hda = model.HistoryDatasetAssociation()
+ with mock.patch('galaxy.workflow.modules.check_param') as check_method:
+ check_method.return_value = ( hda, None )
+ state, errors = module.compute_state( module.trans, { 'input': 4, 'tool_state': tool_state } )
+
+ assert not errors
+ assert 'input' in state.inputs
+ assert state.inputs[ 'input' ] is hda
+
+
+def test_data_collection_input_default_state():
+ trans = MockTrans()
+ module = modules.module_factory.new( trans, "data_collection_input" )
+ __assert_has_runtime_input( module, label="Input Dataset Collection", collection_type="list" )
+
+
+def test_data_input_collection_modified_state():
+ module = __from_state( {
+ "type": "data_collection_input",
+ "tool_state": json.dumps({ "name": "Cool Input Collection", "collection_type": "list:paired" }),
+ } )
+ __assert_has_runtime_input( module, label="Cool Input Collection", collection_type="list:paired" )
+
+
+def test_data_input_collection_step_modified_state():
+ module = __from_step(
+ type="data_collection_input",
+ tool_inputs={
+ "name": "Cool Input Collection",
+ "collection_type": "list:paired",
+ },
+ )
+ __assert_has_runtime_input( module, label="Cool Input Collection", collection_type="list:paired" )
+
+
def test_cannot_create_tool_modules_for_missing_tools():
trans = MockTrans()
exception = False
try:
- modules.module_factory.new( trans, 'tool', tool_id="cat1" )
+ modules.module_factory.new( trans, "tool", tool_id="cat1" )
except Exception:
exception = True
assert exception
+
+
+def __assert_has_runtime_input( module, label=None, collection_type=None ):
+ inputs = module.get_runtime_inputs()
+ assert len( inputs ) == 1
+ assert "input" in inputs
+
+ input_param = inputs[ "input" ]
+ if label is not None:
+ assert input_param.get_label() == label, input_param.get_label()
+ if collection_type is not None:
+ assert input_param.collection_type == collection_type
+ return input_param
+
+
+def __from_state( state ):
+ trans = MockTrans()
+ module = modules.module_factory.from_dict( trans, state )
+ return module
+
+
+def __from_step( **kwds ):
+ trans = MockTrans()
+ step = __step(
+ **kwds
+ )
+ injector = modules.WorkflowModuleInjector( trans )
+ injector.inject( step )
+ module = step.module
+ module.test_step = step
+ return module
+
+
+def __step( **kwds ):
+ step = model.WorkflowStep()
+ for key, value in kwds.iteritems():
+ setattr( step, key, value )
+
+ return step
diff -r dd31ab49162d3faa30818947a80a6165c2f0b4c7 -r d2ec0f230bdaed4ce52607b6ac1b6d5348dc1834 test/unit/workflows/workflow_support.py
--- a/test/unit/workflows/workflow_support.py
+++ b/test/unit/workflows/workflow_support.py
@@ -11,13 +11,25 @@
class TestApp( object ):
def __init__( self ):
- self.config = bunch.Bunch( )
+ self.config = bunch.Bunch(
+ tool_secret="awesome_secret",
+ )
self.model = mapping.init(
"/tmp",
"sqlite:///:memory:",
create_tables=True
)
self.toolbox = TestToolbox()
+ self.datatypes_registry = TestDatatypesRegistry()
+
+
+class TestDatatypesRegistry( object ):
+
+ def __init__( self ):
+ pass
+
+ def get_datatype_by_extension( self, ext ):
+ return ext
class TestToolbox( object ):
https://bitbucket.org/galaxy/galaxy-central/commits/b8520d9c8269/
Changeset: b8520d9c8269
User: jmchilton
Date: 2014-09-11 22:01:08
Summary: Allow uuid values in to_dict.
Affected #: 1 file
diff -r d2ec0f230bdaed4ce52607b6ac1b6d5348dc1834 -r b8520d9c8269c4c7deca6418d54f2e722886073e lib/galaxy/model/item_attrs.py
--- a/lib/galaxy/model/item_attrs.py
+++ b/lib/galaxy/model/item_attrs.py
@@ -4,6 +4,7 @@
import galaxy
import logging
import datetime
+import uuid
log = logging.getLogger( __name__ )
@@ -186,6 +187,8 @@
return value_mapper.get( key )( item )
if type(item) == datetime.datetime:
return item.isoformat()
+ elif type(item) == uuid.UUID:
+ return str(item)
# Leaving this for future reference, though we may want a more
# generic way to handle special type mappings going forward.
# If the item is of a class that needs to be 'stringified' before being put into a JSON data structure
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
Branch: refs/tags/0.3
Home: https://github.com/galaxyproject/ansible-pulsar
1
0
[galaxyproject/ansible-pulsar] 43d526: Handle install environments for dependencies that ...
by GitHub 11 Sep '14
by GitHub 11 Sep '14
11 Sep '14
Branch: refs/heads/master
Home: https://github.com/galaxyproject/ansible-pulsar
Commit: 43d52683a342f6788a0751c4737ac376aafcb271
https://github.com/galaxyproject/ansible-pulsar/commit/43d52683a342f6788a07…
Author: Nate Coraor <nate(a)bx.psu.edu>
Date: 2014-09-11 (Thu, 11 Sep 2014)
Changed paths:
M tasks/main.yml
Log Message:
-----------
Handle install environments for dependencies that are pinned to a
specific version.
1
0
commit/galaxy-central: carlfeberhard: Fix to 618b02d13329: remove console, add documentation
by commits-noreply@bitbucket.org 11 Sep '14
by commits-noreply@bitbucket.org 11 Sep '14
11 Sep '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/da6e8248d7b4/
Changeset: da6e8248d7b4
User: carlfeberhard
Date: 2014-09-11 20:11:37
Summary: Fix to 618b02d13329: remove console, add documentation
Affected #: 7 files
diff -r 618b02d13329adf2d01b72e9743a8fa00192c6fd -r da6e8248d7b402783e829f27ee1ab9e6ba4367d7 static/scripts/mvc/collection/collection-li.js
--- a/static/scripts/mvc/collection/collection-li.js
+++ b/static/scripts/mvc/collection/collection-li.js
@@ -47,6 +47,7 @@
},
// ......................................................................... foldout
+ /** override to add linktarget to sub-panel */
_getFoldoutPanelOptions : function(){
var options = FoldoutListItemView.prototype._getFoldoutPanelOptions.call( this );
return _.extend( options, {
@@ -54,7 +55,7 @@
});
},
- /** override in the case of sub-panels */
+ /** override to not catch sub-panel selectors */
$selector : function(){
return this.$( '> .selector' );
},
diff -r 618b02d13329adf2d01b72e9743a8fa00192c6fd -r da6e8248d7b402783e829f27ee1ab9e6ba4367d7 static/scripts/mvc/collection/collection-panel.js
--- a/static/scripts/mvc/collection/collection-panel.js
+++ b/static/scripts/mvc/collection/collection-panel.js
@@ -93,7 +93,7 @@
return this;
},
- /** */
+ /** Handle drill down by hiding this panels list and controls and showing the sub-panel */
_expandDrilldownPanel : function( drilldown ){
this.panelStack.push( drilldown );
// hide this panel's controls and list, set the name for back navigation, and attach to the $el
@@ -102,7 +102,7 @@
this.$el.append( drilldown.render().$el );
},
- /** */
+ /** Handle drilldown close by freeing the panel and re-rendering this panel */
_collapseDrilldownPanel : function( drilldown ){
this.panelStack.pop();
this.render();
diff -r 618b02d13329adf2d01b72e9743a8fa00192c6fd -r da6e8248d7b402783e829f27ee1ab9e6ba4367d7 static/scripts/mvc/history/history-panel-edit-current.js
--- a/static/scripts/mvc/history/history-panel-edit-current.js
+++ b/static/scripts/mvc/history/history-panel-edit-current.js
@@ -301,6 +301,7 @@
return this;
},
+ /** Handle drill down by hiding this panels list and controls and showing the sub-panel */
_expandDrilldownPanel : function( drilldown ){
this.panelStack.push( drilldown );
// hide this panel's controls and list, set the name for back navigation, and attach to the $el
@@ -309,6 +310,7 @@
this.$el.append( drilldown.render().$el );
},
+ /** Handle drilldown close by freeing the panel and re-rendering this panel */
_collapseDrilldownPanel : function( drilldown ){
this.panelStack.pop();
//TODO: MEM: free the panel
diff -r 618b02d13329adf2d01b72e9743a8fa00192c6fd -r da6e8248d7b402783e829f27ee1ab9e6ba4367d7 static/scripts/mvc/list/list-item.js
--- a/static/scripts/mvc/list/list-item.js
+++ b/static/scripts/mvc/list/list-item.js
@@ -355,9 +355,18 @@
*/
var FoldoutListItemView = ListItemView.extend({
+ /** If 'foldout': show the sub-panel inside the expanded item
+ * If 'drilldown': only fire events and handle by pub-sub
+ * (allow the panel containing this item to attach it, hide itself, etc.)
+ */
foldoutStyle : 'foldout',
+ /** Panel view class to instantiate for the sub-panel */
foldoutPanelClass : null,
+ /** override to:
+ * add attributes foldoutStyle and foldoutPanelClass for config poly
+ * disrespect attributes.expanded if drilldown
+ */
initialize : function( attributes ){
ListItemView.prototype.initialize.call( this, attributes );
//TODO: hackish
@@ -367,10 +376,10 @@
},
//TODO:?? override to exclude foldout scope?
- $ : function( selector ){
- var $found = ListItemView.prototype.$.call( this, selector );
- return $found;
- },
+ //$ : function( selector ){
+ // var $found = ListItemView.prototype.$.call( this, selector );
+ // return $found;
+ //},
/** in this override, attach the foldout panel when rendering details */
_renderDetails : function(){
@@ -391,11 +400,13 @@
return foldout;
},
+ /** Stub to return proper foldout panel class */
_getFoldoutPanelClass : function(){
// override
return this.foldoutPanelClass;
},
+ /** Stub to return proper foldout panel options */
_getFoldoutPanelOptions : function(){
return {
// propagate foldout style down
@@ -403,7 +414,7 @@
};
},
- /** */
+ /** Render the foldout panel inside the view, hiding controls */
_attachFoldout : function( foldout, $whereTo ){
$whereTo = $whereTo || this.$( '> .details' );
this.foldout = foldout.render( 0 );
@@ -412,10 +423,7 @@
return $whereTo.append( foldout.$el );
},
- /** Render and show the full, detailed body of this view including extra data and controls.
- * note: if the model does not have detailed data, fetch that data before showing the body
- * @fires expanded when a body has been expanded
- */
+ /** In this override, branch on foldoutStyle to show expanded */
expand : function(){
var view = this;
return view._fetchModelDetails()
@@ -428,6 +436,7 @@
});
},
+ /** For foldout, call render details then slide down */
_expandByFoldout : function(){
var view = this;
var $newDetails = view._renderDetails();
@@ -439,6 +448,10 @@
});
},
+ /** For drilldown, set up close handler and fire expanded:drilldown
+ * containing views can listen to this and handle other things
+ * (like hiding themselves) by listening for expanded/collapsed:drilldown
+ */
_expandByDrilldown : function(){
var view = this;
// attachment and rendering done by listener
@@ -455,6 +468,7 @@
/** underscore templates */
FoldoutListItemView.prototype.templates = (function(){
+//TODO:?? unnecessary?
// use element identifier
var detailsTemplate = BASE_MVC.wrapTemplate([
'<div class="details">',
diff -r 618b02d13329adf2d01b72e9743a8fa00192c6fd -r da6e8248d7b402783e829f27ee1ab9e6ba4367d7 static/scripts/mvc/list/list-panel.js
--- a/static/scripts/mvc/list/list-panel.js
+++ b/static/scripts/mvc/list/list-panel.js
@@ -334,15 +334,15 @@
return panel.views;
},
- /**
- */
+ /** Filter the collection to only those models that should be currently viewed */
_filterCollection : function(){
// override this
var panel = this;
return panel.collection.filter( _.bind( panel._filterItem, panel ) );
},
- /**
+ /** Should the model be viewable in the current state?
+ * Checks against this.filters and this.searchFor
*/
_filterItem : function( model ){
// override this
@@ -351,8 +351,7 @@
&& ( !panel.searchFor || model.matchesAll( panel.searchFor ) );
},
- /**
- */
+ /** Create a view for a model and set up it's listeners */
_createItemView : function( model ){
var ViewClass = this._getItemViewClass( model ),
options = _.extend( this._getItemViewOptions( model ), {
@@ -363,15 +362,13 @@
return view;
},
- /**
- */
+ /** Get the bbone view class based on the model */
_getItemViewClass : function( model ){
// override this
return this.viewClass;
},
- /**
- */
+ /** Get the options passed to the new view based on the model */
_getItemViewOptions : function( model ){
// override this
return {
@@ -384,8 +381,7 @@
};
},
- /**
- */
+ /** Set up listeners for new models */
_setUpItemViewListeners : function( view ){
var panel = this;
// send all events to the panel, re-namspaceing them with the view prefix
@@ -404,8 +400,7 @@
return panel;
},
- /**
- */
+ /** Attach views in this.views to the model based on $whereTo */
_attachItems : function( $whereTo ){
this.$list( $whereTo ).append( this.views.map( function( view ){
return view.$el;
@@ -435,8 +430,7 @@
},
// ------------------------------------------------------------------------ collection/views syncing
- /**
- */
+ /** Add a view (if the model should be viewable) to the panel */
addItemView : function( model, collection, options ){
this.log( this + '.addItemView:', model );
var panel = this;
@@ -446,6 +440,7 @@
var view = panel._createItemView( model );
panel.views.push( view );
+ // hide the empty message if only view
$( view ).queue( 'fx', [
function( next ){ panel.$emptyMessage().fadeOut( panel.fxSpeed, next ); },
function( next ){
@@ -458,13 +453,14 @@
return view;
},
- /** */
+ /** Remove a view from the panel (if found) */
removeItemView : function( model, collection, options ){
this.log( this + '.removeItemView:', model );
var panel = this,
view = panel.viewFromModel( model );
if( !view ){ return undefined; }
+ // potentially show the empty message if no views left
// use anonymous queue here - since remove can happen multiple times
$({}).queue( 'fx', [
function( next ){ view.$el.fadeOut( panel.fxSpeed, next ); },
@@ -481,18 +477,6 @@
return view;
},
- /** get views based on model
- */
- viewFromModel : function( model ){
- for( var i=0; i<this.views.length; i++ ){
- var view = this.views[i];
- if( view.model === model ){
- return view;
- }
- }
- return undefined;
- },
-
/** get views based on model.id */
viewFromModelId : function( id ){
for( var i=0; i<this.views.length; i++ ){
@@ -503,8 +487,12 @@
return undefined;
},
- /** get views based on model properties
- */
+ /** get views based on model */
+ viewFromModel : function( model ){
+ return this.viewFromModelId( model.id );
+ },
+
+ /** get views based on model properties */
viewsWhereModel : function( properties ){
return this.views.filter( function( view ){
//return view.model.matches( properties );
@@ -523,8 +511,7 @@
});
},
- /**
- */
+ /** A range of views between (and including) viewA and viewB */
viewRange : function( viewA, viewB ){
if( viewA === viewB ){ return ( viewA )?( [ viewA ] ):( [] ); }
@@ -562,7 +549,9 @@
return $where;
},
+ /** What to do on the first search entered */
_firstSearch : function( searchFor ){
+ // override to load model details if necc.
this.log( 'onFirstSearch', searchFor );
return this.searchItems( searchFor );
},
@@ -591,7 +580,6 @@
this.selecting = true;
this.$( '.list-actions' ).slideDown( speed );
_.each( this.views, function( view ){
-console.debug( view.$el );
view.showSelector( speed );
});
//this.selected = [];
@@ -749,13 +737,16 @@
'<div class="name"><%= view.title %></div>',
'</div>',
'<div class="subtitle"><%= view.subtitle %></div>',
+ // buttons, controls go here
'<div class="actions"></div>',
+ // deleted msg, etc.
'<div class="messages"></div>',
'<div class="search">',
'<div class="search-input"></div>',
'</div>',
+ // show when selectors are shown
'<div class="list-actions">',
'<div class="btn-group">',
'<button class="select-all btn btn-default"',
@@ -779,7 +770,9 @@
//=============================================================================
/** View for a model that has a sub-collection (e.g. History, DatasetCollection)
- *
+ * Allows:
+ * the model to be reset
+ * auto assign panel.collection to panel.model[ panel.modelCollectionKey ]
*
*/
var ModelListPanel = ListPanel.extend({
@@ -791,8 +784,6 @@
ListPanel.prototype.initialize.call( this, attributes );
this.selecting = ( attributes.selecting !== undefined )? attributes.selecting : false;
- // ---- instance vars
- // don't render when setting the first time
this.setModel( this.model, attributes );
},
@@ -862,8 +853,6 @@
var json = this.model? this.model.toJSON() : {},
$controls = $( this.templates.controls( json, this ) );
$newRender.find( '.controls' ).replaceWith( $controls );
- this.debug( '\t .controls:', this.$( '.controls' ) );
- this.debug( '\t $controls:', $controls );
return $controls;
},
@@ -882,6 +871,7 @@
var controlsTemplate = BASE_MVC.wrapTemplate([
'<div class="controls">',
'<div class="title">',
+//TODO: this is really the only difference - consider factoring titlebar out
'<div class="name"><%= model.name %></div>',
'</div>',
'<div class="subtitle"><%= view.subtitle %></div>',
diff -r 618b02d13329adf2d01b72e9743a8fa00192c6fd -r da6e8248d7b402783e829f27ee1ab9e6ba4367d7 static/scripts/packed/mvc/list/list-item.js
--- a/static/scripts/packed/mvc/list/list-item.js
+++ b/static/scripts/packed/mvc/list/list-item.js
@@ -1,1 +1,1 @@
-define(["mvc/base-mvc","utils/localization"],function(b,d){var e=Backbone.View.extend(b.LoggableMixin).extend({initialize:function(f){this.expanded=f.expanded||false;this.fxSpeed=f.fxSpeed||this.fxSpeed},fxSpeed:"fast",render:function(g){var f=this._buildNewRender();this._setUpBehaviors(f);this._queueNewRender(f,g);return this},_buildNewRender:function(){var f=$(this.templates.el(this.model.toJSON(),this));if(this.expanded){this.$details(f).replaceWith(this._renderDetails().show())}return f},_queueNewRender:function(g,h){h=(h===undefined)?(this.fxSpeed):(h);var f=this;$(f).queue("fx",[function(i){this.$el.fadeOut(h,i)},function(i){f._swapNewRender(g);i()},function(i){this.$el.fadeIn(h,i)},function(i){this.trigger("rendered",f);i()}])},_swapNewRender:function(f){return this.$el.empty().attr("class",this.className).append(f.children())},_setUpBehaviors:function(f){f=f||this.$el;f.find("[title]").tooltip({placement:"bottom"})},$details:function(f){f=f||this.$el;return f.find("> .details")},_renderDetails:function(){var f=$(this.templates.details(this.model.toJSON(),this));this._setUpBehaviors(f);return f},toggleExpanded:function(f){f=(f===undefined)?(!this.expanded):(f);if(f){this.expand()}else{this.collapse()}return this},expand:function(){var f=this;return f._fetchModelDetails().always(function(){var g=f._renderDetails();f.$details().replaceWith(g);f.expanded=true;f.$details().slideDown(f.fxSpeed,function(){f.trigger("expanded",f)})})},_fetchModelDetails:function(){if(!this.model.hasDetails()){return this.model.fetch()}return jQuery.when()},collapse:function(){this.debug(this+"(ExpandableView).collapse");var f=this;f.expanded=false;this.$details().slideUp(f.fxSpeed,function(){f.trigger("collapsed",f)})}});var a=e.extend(b.mixin(b.SelectableViewMixin,b.DraggableViewMixin,{tagName:"div",className:"list-item",initialize:function(f){e.prototype.initialize.call(this,f);b.SelectableViewMixin.initialize.call(this,f);b.DraggableViewMixin.initialize.call(this,f);this._setUpListeners()},_setUpListeners:function(){this.on("selectable",function(f){if(f){this.$(".primary-actions").hide()}else{this.$(".primary-actions").show()}},this);return this},_buildNewRender:function(){var f=e.prototype._buildNewRender.call(this);f.children(".warnings").replaceWith(this._renderWarnings());f.children(".title-bar").replaceWith(this._renderTitleBar());f.children(".primary-actions").append(this._renderPrimaryActions());f.find(".title-bar .subtitle").replaceWith(this._renderSubtitle());return f},_swapNewRender:function(f){e.prototype._swapNewRender.call(this,f);if(this.selectable){this.showSelector(0)}if(this.draggable){this.draggableOn()}return this.$el},_renderWarnings:function(){var f=this,h=$('<div class="warnings"></div>'),g=f.model.toJSON();_.each(f.templates.warnings,function(i){h.append($(i(g,f)))});return h},_renderTitleBar:function(){return $(this.templates.titleBar(this.model.toJSON(),this))},_renderPrimaryActions:function(){return[]},_renderSubtitle:function(){return $(this.templates.subtitle(this.model.toJSON(),this))},events:{"click .title-bar":"_clickTitleBar","keydown .title-bar":"_keyDownTitleBar","click .selector":"toggleSelect"},_clickTitleBar:function(f){f.stopPropagation();this.toggleExpanded()},_keyDownTitleBar:function(h){var f=32,g=13;if(h&&(h.type==="keydown")&&(h.keyCode===f||h.keyCode===g)){this.toggleExpanded();h.stopPropagation();return false}return true},toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"ListItemView("+f+")"}}));a.prototype.templates=(function(){var h=b.wrapTemplate(['<div class="list-element">','<div class="warnings"></div>','<div class="selector">','<span class="fa fa-2x fa-square-o"></span>',"</div>",'<div class="primary-actions"></div>','<div class="title-bar"></div>','<div class="details"></div>',"</div>"]);var f={};var i=b.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="name"><%- element.name %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"element");var j=b.wrapTemplate(['<div class="subtitle"></div>']);var g=b.wrapTemplate(['<div class="details"></div>']);return{el:h,warnings:f,titleBar:i,subtitle:j,details:g}}());var c=a.extend({foldoutStyle:"foldout",foldoutPanelClass:null,initialize:function(f){a.prototype.initialize.call(this,f);if(this.foldoutStyle==="drilldown"){this.expanded=false}this.foldoutStyle=f.foldoutStyle||this.foldoutStyle;this.foldoutPanelClass=f.foldoutPanelClass||this.foldoutPanelClass},$:function(f){var g=a.prototype.$.call(this,f);return g},_renderDetails:function(){if(this.foldoutStyle==="drilldown"){return $()}var f=a.prototype._renderDetails.call(this);return this._attachFoldout(this._createFoldoutPanel(),f)},_createFoldoutPanel:function(){var h=this.model;var i=this._getFoldoutPanelClass(h),g=this._getFoldoutPanelOptions(h),f=new i(_.extend(g,{model:h}));return f},_getFoldoutPanelClass:function(){return this.foldoutPanelClass},_getFoldoutPanelOptions:function(){return{foldoutStyle:this.foldoutStyle}},_attachFoldout:function(f,g){g=g||this.$("> .details");this.foldout=f.render(0);f.$("> .controls").hide();return g.append(f.$el)},expand:function(){var f=this;return f._fetchModelDetails().always(function(){if(f.foldoutStyle==="foldout"){f._expandByFoldout()}else{if(f.foldoutStyle==="drilldown"){f._expandByDrilldown()}}})},_expandByFoldout:function(){var f=this;var g=f._renderDetails();f.$details().replaceWith(g);f.expanded=true;f.$details().slideDown(f.fxSpeed,function(){f.trigger("expanded",f)})},_expandByDrilldown:function(){var f=this;f.foldout=this._createFoldoutPanel();f.foldout.on("close",function(){f.trigger("collapsed:drilldown",f,f.foldout)});f.trigger("expanded:drilldown",f,f.foldout)}});c.prototype.templates=(function(){var f=b.wrapTemplate(['<div class="details">',"</div>"],"collection");return _.extend({},a.prototype.templates,{details:f})}());return{ExpandableView:e,ListItemView:a,FoldoutListItemView:c}});
\ No newline at end of file
+define(["mvc/base-mvc","utils/localization"],function(b,d){var e=Backbone.View.extend(b.LoggableMixin).extend({initialize:function(f){this.expanded=f.expanded||false;this.fxSpeed=f.fxSpeed||this.fxSpeed},fxSpeed:"fast",render:function(g){var f=this._buildNewRender();this._setUpBehaviors(f);this._queueNewRender(f,g);return this},_buildNewRender:function(){var f=$(this.templates.el(this.model.toJSON(),this));if(this.expanded){this.$details(f).replaceWith(this._renderDetails().show())}return f},_queueNewRender:function(g,h){h=(h===undefined)?(this.fxSpeed):(h);var f=this;$(f).queue("fx",[function(i){this.$el.fadeOut(h,i)},function(i){f._swapNewRender(g);i()},function(i){this.$el.fadeIn(h,i)},function(i){this.trigger("rendered",f);i()}])},_swapNewRender:function(f){return this.$el.empty().attr("class",this.className).append(f.children())},_setUpBehaviors:function(f){f=f||this.$el;f.find("[title]").tooltip({placement:"bottom"})},$details:function(f){f=f||this.$el;return f.find("> .details")},_renderDetails:function(){var f=$(this.templates.details(this.model.toJSON(),this));this._setUpBehaviors(f);return f},toggleExpanded:function(f){f=(f===undefined)?(!this.expanded):(f);if(f){this.expand()}else{this.collapse()}return this},expand:function(){var f=this;return f._fetchModelDetails().always(function(){var g=f._renderDetails();f.$details().replaceWith(g);f.expanded=true;f.$details().slideDown(f.fxSpeed,function(){f.trigger("expanded",f)})})},_fetchModelDetails:function(){if(!this.model.hasDetails()){return this.model.fetch()}return jQuery.when()},collapse:function(){this.debug(this+"(ExpandableView).collapse");var f=this;f.expanded=false;this.$details().slideUp(f.fxSpeed,function(){f.trigger("collapsed",f)})}});var a=e.extend(b.mixin(b.SelectableViewMixin,b.DraggableViewMixin,{tagName:"div",className:"list-item",initialize:function(f){e.prototype.initialize.call(this,f);b.SelectableViewMixin.initialize.call(this,f);b.DraggableViewMixin.initialize.call(this,f);this._setUpListeners()},_setUpListeners:function(){this.on("selectable",function(f){if(f){this.$(".primary-actions").hide()}else{this.$(".primary-actions").show()}},this);return this},_buildNewRender:function(){var f=e.prototype._buildNewRender.call(this);f.children(".warnings").replaceWith(this._renderWarnings());f.children(".title-bar").replaceWith(this._renderTitleBar());f.children(".primary-actions").append(this._renderPrimaryActions());f.find(".title-bar .subtitle").replaceWith(this._renderSubtitle());return f},_swapNewRender:function(f){e.prototype._swapNewRender.call(this,f);if(this.selectable){this.showSelector(0)}if(this.draggable){this.draggableOn()}return this.$el},_renderWarnings:function(){var f=this,h=$('<div class="warnings"></div>'),g=f.model.toJSON();_.each(f.templates.warnings,function(i){h.append($(i(g,f)))});return h},_renderTitleBar:function(){return $(this.templates.titleBar(this.model.toJSON(),this))},_renderPrimaryActions:function(){return[]},_renderSubtitle:function(){return $(this.templates.subtitle(this.model.toJSON(),this))},events:{"click .title-bar":"_clickTitleBar","keydown .title-bar":"_keyDownTitleBar","click .selector":"toggleSelect"},_clickTitleBar:function(f){f.stopPropagation();this.toggleExpanded()},_keyDownTitleBar:function(h){var f=32,g=13;if(h&&(h.type==="keydown")&&(h.keyCode===f||h.keyCode===g)){this.toggleExpanded();h.stopPropagation();return false}return true},toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"ListItemView("+f+")"}}));a.prototype.templates=(function(){var h=b.wrapTemplate(['<div class="list-element">','<div class="warnings"></div>','<div class="selector">','<span class="fa fa-2x fa-square-o"></span>',"</div>",'<div class="primary-actions"></div>','<div class="title-bar"></div>','<div class="details"></div>',"</div>"]);var f={};var i=b.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="name"><%- element.name %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"element");var j=b.wrapTemplate(['<div class="subtitle"></div>']);var g=b.wrapTemplate(['<div class="details"></div>']);return{el:h,warnings:f,titleBar:i,subtitle:j,details:g}}());var c=a.extend({foldoutStyle:"foldout",foldoutPanelClass:null,initialize:function(f){a.prototype.initialize.call(this,f);if(this.foldoutStyle==="drilldown"){this.expanded=false}this.foldoutStyle=f.foldoutStyle||this.foldoutStyle;this.foldoutPanelClass=f.foldoutPanelClass||this.foldoutPanelClass},_renderDetails:function(){if(this.foldoutStyle==="drilldown"){return $()}var f=a.prototype._renderDetails.call(this);return this._attachFoldout(this._createFoldoutPanel(),f)},_createFoldoutPanel:function(){var h=this.model;var i=this._getFoldoutPanelClass(h),g=this._getFoldoutPanelOptions(h),f=new i(_.extend(g,{model:h}));return f},_getFoldoutPanelClass:function(){return this.foldoutPanelClass},_getFoldoutPanelOptions:function(){return{foldoutStyle:this.foldoutStyle}},_attachFoldout:function(f,g){g=g||this.$("> .details");this.foldout=f.render(0);f.$("> .controls").hide();return g.append(f.$el)},expand:function(){var f=this;return f._fetchModelDetails().always(function(){if(f.foldoutStyle==="foldout"){f._expandByFoldout()}else{if(f.foldoutStyle==="drilldown"){f._expandByDrilldown()}}})},_expandByFoldout:function(){var f=this;var g=f._renderDetails();f.$details().replaceWith(g);f.expanded=true;f.$details().slideDown(f.fxSpeed,function(){f.trigger("expanded",f)})},_expandByDrilldown:function(){var f=this;f.foldout=this._createFoldoutPanel();f.foldout.on("close",function(){f.trigger("collapsed:drilldown",f,f.foldout)});f.trigger("expanded:drilldown",f,f.foldout)}});c.prototype.templates=(function(){var f=b.wrapTemplate(['<div class="details">',"</div>"],"collection");return _.extend({},a.prototype.templates,{details:f})}());return{ExpandableView:e,ListItemView:a,FoldoutListItemView:c}});
\ No newline at end of file
diff -r 618b02d13329adf2d01b72e9743a8fa00192c6fd -r da6e8248d7b402783e829f27ee1ab9e6ba4367d7 static/scripts/packed/mvc/list/list-panel.js
--- a/static/scripts/packed/mvc/list/list-panel.js
+++ b/static/scripts/packed/mvc/list/list-panel.js
@@ -1,1 +1,1 @@
-define(["mvc/list/list-item","mvc/base-mvc","utils/localization"],function(d,b,c){var e=Backbone.View.extend(b.LoggableMixin).extend({viewClass:d.ListItemView,collectionClass:Backbone.Collection,tagName:"div",className:"list-panel",fxSpeed:"fast",emptyMsg:c("This list is empty"),noneFoundMsg:c("No matching items found"),searchPlaceholder:c("search"),multiselectActions:[],initialize:function(f,g){f=f||{};if(f.logger){this.logger=f.logger}this.log(this+".initialize:",f);this.fxSpeed=_.has(f,"fxSpeed")?(f.fxSpeed):(this.fxSpeed);this.filters=[];this.searchFor=f.searchFor||"";this.indicator=new LoadingIndicator(this.$el);this.selecting=(f.selecting!==undefined)?f.selecting:true;this.selected=f.selected||[];this.lastSelected=null;this.viewClass=f.viewClass||this.viewClass;this.views=[];this.collection=f.collection||(new this.collectionClass([]));this.filters=f.filters||[];this.$scrollContainer=f.$scrollContainer||this.$scrollContainer;this.title=f.title||"";this.subtitle=f.subtitle||"";this.multiselectActions=f.multiselectActions||this.multiselectActions;this.actionsPopup=null;this._setUpListeners()},freeViews:function(){_.each(this.views,function(f){f.off()});this.views=[];return this},_setUpListeners:function(){this.off();this.on("error",function(g,j,f,i,h){console.error(g,j,f,i,h)},this);this.on("loading",function(){this._showLoadingIndicator("loading...",40)},this);this.on("loading-done",function(){this._hideLoadingIndicator(40)},this);this.once("rendered",function(){this.trigger("rendered:initial",this)},this);if(this.logger){this.on("all",function(f){this.log(this+"",arguments)},this)}this._setUpCollectionListeners();this._setUpViewListeners();return this},_setUpCollectionListeners:function(){this.log(this+"._setUpCollectionListeners",this.collection);this.collection.off();this.collection.on("error",function(g,j,f,i,h){this.trigger("error",g,j,f,i,h)},this);this.collection.on("reset",function(){this.renderItems()},this);this.collection.on("add",this.addItemView,this);this.collection.on("remove",this.removeItemView,this);if(this.logger){this.collection.on("all",function(f){this.info(this+"(collection)",arguments)},this)}return this},_setUpViewListeners:function(){this.log(this+"._setUpViewListeners");this.on("view:selected",function(f,g){if(g&&g.shiftKey&&this.lastSelected){var h=this.viewFromModelId(this.lastSelected);if(h){this.selectRange(f,h)}}this.selected.push(f.model.id);this.lastSelected=f.model.id},this);this.on("view:de-selected",function(f,g){this.selected=_.without(this.selected,f.model.id)},this)},render:function(g){this.log(this+".render",g);var f=this._buildNewRender();this._setUpBehaviors(f);this._queueNewRender(f,g);return this},_buildNewRender:function(){this.debug(this+"(ListPanel)._buildNewRender");var f=$(this.templates.el({},this));this._renderControls(f);this._renderTitle(f);this._renderSubtitle(f);this._renderSearch(f);this.renderItems(f);return f},_renderControls:function(g){this.debug(this+"(ListPanel)._renderControls");var f=$(this.templates.controls({},this));g.find(".controls").replaceWith(f);return f},_renderTitle:function(f){},_renderSubtitle:function(f){},_queueNewRender:function(g,h){h=(h===undefined)?(this.fxSpeed):(h);var f=this;f.log("_queueNewRender:",g,h);$(f).queue("fx",[function(i){this.$el.fadeOut(h,i)},function(i){f._swapNewRender(g);i()},function(i){this.$el.fadeIn(h,i)},function(i){f.trigger("rendered",f);i()}])},_swapNewRender:function(f){this.$el.empty().attr("class",this.className).append(f.children());if(this.selecting){this.showSelectors(0)}return this},_setUpBehaviors:function(f){f=f||this.$el;f.find(".controls [title]").tooltip({placement:"bottom"});return this},$scrollContainer:function(){return this.$el.parent().parent()},$list:function(f){return(f||this.$el).find("> .list-items")},$messages:function(f){return(f||this.$el).find("> .controls .messages")},$emptyMessage:function(f){return(f||this.$el).find("> .empty-message")},renderItems:function(h){h=h||this.$el;var f=this;f.log(this+".renderItems",h);var g=f.$list(h);f.views=f._filterCollection().map(function(i){return f._createItemView(i).render(0)});g.empty();if(f.views.length){f._attachItems(h);f.$emptyMessage(h).hide()}else{f._renderEmptyMessage(h).show()}return f.views},_filterCollection:function(){var f=this;return f.collection.filter(_.bind(f._filterItem,f))},_filterItem:function(g){var f=this;return(_.every(f.filters.map(function(h){return h.call(g)})))&&(!f.searchFor||g.matchesAll(f.searchFor))},_createItemView:function(h){var i=this._getItemViewClass(h),g=_.extend(this._getItemViewOptions(h),{model:h}),f=new i(g);this._setUpItemViewListeners(f);return f},_getItemViewClass:function(f){return this.viewClass},_getItemViewOptions:function(f){return{fxSpeed:this.fxSpeed,expanded:false,selectable:this.selecting,selected:_.contains(this.selected,f.id),draggable:this.dragging}},_setUpItemViewListeners:function(g){var f=this;g.on("all",function(){var h=Array.prototype.slice.call(arguments,0);h[0]="view:"+h[0];f.trigger.apply(f,h)});return f},_attachItems:function(f){this.$list(f).append(this.views.map(function(g){return g.$el}));return this},_renderEmptyMessage:function(f){this.debug("_renderEmptyMessage",f,this.searchFor);var g=this.searchFor?this.noneFoundMsg:this.emptyMsg;return this.$emptyMessage(f).text(g)},expandAll:function(){_.each(this.views,function(f){f.expand()})},collapseAll:function(){_.each(this.views,function(f){f.collapse()})},addItemView:function(i,j,h){this.log(this+".addItemView:",i);var g=this;if(!g._filterItem(i)){return undefined}var f=g._createItemView(i);g.views.push(f);$(f).queue("fx",[function(k){g.$emptyMessage().fadeOut(g.fxSpeed,k)},function(k){g.$list().append(f.render().$el);k()}]);return f},removeItemView:function(i,j,h){this.log(this+".removeItemView:",i);var g=this,f=g.viewFromModel(i);if(!f){return undefined}$({}).queue("fx",[function(k){f.$el.fadeOut(g.fxSpeed,k)},function(k){g.views=_.without(g.views,f);f.remove();if(!g.views.length){g._renderEmptyMessage().fadeIn(g.fxSpeed,k)}else{k()}}]);return f},viewFromModel:function(g){for(var h=0;h<this.views.length;h++){var f=this.views[h];if(f.model===g){return f}}return undefined},viewFromModelId:function(g){for(var f=0;f<this.views.length;f++){if(this.views[f].model.id===g){return this.views[f]}}return undefined},viewsWhereModel:function(f){return this.views.filter(function(g){var i=g.model.toJSON();for(var h in f){if(f.hasOwnProperty(h)){if(i[h]!==g.model.get(h)){return false}}}return true})},viewRange:function(i,h){if(i===h){return(i)?([i]):([])}var g=this.views.indexOf(i),f=this.views.indexOf(h);if(g===-1||f===-1){if(g===f){return[]}return(g===-1)?([h]):([i])}return(g<f)?this.views.slice(g,f+1):this.views.slice(f,g+1)},_renderSearch:function(f){f.find(".controls .search-input").searchInput({placeholder:this.searchPlaceholder,initialVal:this.searchFor,onfirstsearch:_.bind(this._firstSearch,this),onsearch:_.bind(this.searchItems,this),onclear:_.bind(this.clearSearch,this)});return f},_firstSearch:function(f){this.log("onFirstSearch",f);return this.searchItems(f)},searchItems:function(f){this.searchFor=f;this.trigger("search:searching",f,this);this.renderItems();return this},clearSearch:function(f){this.searchFor="";this.trigger("search:clear",this);this.renderItems();return this},showSelectors:function(f){f=(f!==undefined)?(f):(this.fxSpeed);this.selecting=true;this.$(".list-actions").slideDown(f);_.each(this.views,function(g){console.debug(g.$el);g.showSelector(f)})},hideSelectors:function(f){f=(f!==undefined)?(f):(this.fxSpeed);this.selecting=false;this.$(".list-actions").slideUp(f);_.each(this.views,function(g){g.hideSelector(f)});this.selected=[];this.lastSelected=null},toggleSelectors:function(){if(!this.selecting){this.showSelectors()}else{this.hideSelectors()}},selectAll:function(f){_.each(this.views,function(g){g.select(f)})},deselectAll:function(f){this.lastSelected=null;_.each(this.views,function(g){g.deselect(f)})},selectRange:function(h,g){var f=this.viewRange(h,g);_.each(f,function(i){i.select()});return f},getSelectedViews:function(){return _.filter(this.views,function(f){return f.selected})},getSelectedModels:function(){return new this.collection.constructor(_.map(this.getSelectedViews(),function(f){return f.model}))},_showLoadingIndicator:function(g,f,h){this.debug("_showLoadingIndicator",this.indicator,g,f,h);f=(f!==undefined)?(f):(this.fxSpeed);if(!this.indicator){this.indicator=new LoadingIndicator(this.$el,this.$el.parent());this.debug("\t created",this.indicator)}if(!this.$el.is(":visible")){this.indicator.show(0,h)}else{this.$el.fadeOut(f);this.indicator.show(g,f,h)}},_hideLoadingIndicator:function(f,g){this.debug("_hideLoadingIndicator",this.indicator,f,g);f=(f!==undefined)?(f):(this.fxSpeed);if(this.indicator){this.indicator.hide(f,g)}},scrollPosition:function(){return this.$scrollContainer().scrollTop()},scrollTo:function(f){this.$scrollContainer().scrollTop(f);return this},scrollToTop:function(){this.$scrollContainer().scrollTop(0);return this},scrollToItem:function(f){if(!f){return this}var g=f.$el.offset().top;this.$scrollContainer().scrollTop(g);return this},scrollToId:function(f){return this.scrollToItem(this.viewFromModelId(f))},events:{"click .select-all":"selectAll","click .deselect-all":"deselectAll"},toString:function(){return"ListPanel("+this.collection+")"}});e.prototype.templates=(function(){var g=b.wrapTemplate(["<div>",'<div class="controls"></div>','<div class="list-items"></div>','<div class="empty-message infomessagesmall"></div>',"</div>"]);var f=b.wrapTemplate(['<div class="controls">','<div class="title">','<div class="name"><%= view.title %></div>',"</div>",'<div class="subtitle"><%= view.subtitle %></div>','<div class="actions"></div>','<div class="messages"></div>','<div class="search">','<div class="search-input"></div>',"</div>",'<div class="list-actions">','<div class="btn-group">','<button class="select-all btn btn-default"','data-mode="select">',c("All"),"</button>",'<button class="deselect-all btn btn-default"','data-mode="select">',c("None"),"</button>","</div>","</div>","</div>"]);return{el:g,controls:f}}());var a=e.extend({modelCollectionKey:"contents",initialize:function(f){e.prototype.initialize.call(this,f);this.selecting=(f.selecting!==undefined)?f.selecting:false;this.setModel(this.model,f)},setModel:function(g,f){f=f||{};this.debug(this+".setModel:",g,f);this.freeModel();this.freeViews();if(g){this.model=g;if(this.logger){this.model.logger=this.logger}this._setUpModelListeners();this.collection.off();this.collection=(this.model[this.modelCollectionKey])?this.model[this.modelCollectionKey]:(f.collection||(new this.collectionClass([])));this._setUpCollectionListeners();this.trigger("new-model",this)}return this},freeModel:function(){if(this.model){this.stopListening(this.model)}return this},_setUpModelListeners:function(){this.log(this+"._setUpModelListeners",this.model);this.model.on("error",function(){this.trigger.apply(panel,arguments)},this);return this},_renderControls:function(g){this.debug(this+"(ListPanel)._renderControls");var h=this.model?this.model.toJSON():{},f=$(this.templates.controls(h,this));g.find(".controls").replaceWith(f);this.debug("\t .controls:",this.$(".controls"));this.debug("\t $controls:",f);return f},toString:function(){return"ModelListPanel("+this.model+")"}});a.prototype.templates=(function(){var f=b.wrapTemplate(['<div class="controls">','<div class="title">','<div class="name"><%= model.name %></div>',"</div>",'<div class="subtitle"><%= view.subtitle %></div>','<div class="actions"></div>','<div class="messages"></div>','<div class="search">','<div class="search-input"></div>',"</div>",'<div class="list-actions">','<div class="btn-group">','<button class="select-all btn btn-default"','data-mode="select">',c("All"),"</button>",'<button class="deselect-all btn btn-default"','data-mode="select">',c("None"),"</button>","</div>","</div>","</div>"]);return _.extend(_.clone(e.prototype.templates),{controls:f})}());return{ListPanel:e,ModelListPanel:a}});
\ No newline at end of file
+define(["mvc/list/list-item","mvc/base-mvc","utils/localization"],function(d,b,c){var e=Backbone.View.extend(b.LoggableMixin).extend({viewClass:d.ListItemView,collectionClass:Backbone.Collection,tagName:"div",className:"list-panel",fxSpeed:"fast",emptyMsg:c("This list is empty"),noneFoundMsg:c("No matching items found"),searchPlaceholder:c("search"),multiselectActions:[],initialize:function(f,g){f=f||{};if(f.logger){this.logger=f.logger}this.log(this+".initialize:",f);this.fxSpeed=_.has(f,"fxSpeed")?(f.fxSpeed):(this.fxSpeed);this.filters=[];this.searchFor=f.searchFor||"";this.indicator=new LoadingIndicator(this.$el);this.selecting=(f.selecting!==undefined)?f.selecting:true;this.selected=f.selected||[];this.lastSelected=null;this.viewClass=f.viewClass||this.viewClass;this.views=[];this.collection=f.collection||(new this.collectionClass([]));this.filters=f.filters||[];this.$scrollContainer=f.$scrollContainer||this.$scrollContainer;this.title=f.title||"";this.subtitle=f.subtitle||"";this.multiselectActions=f.multiselectActions||this.multiselectActions;this.actionsPopup=null;this._setUpListeners()},freeViews:function(){_.each(this.views,function(f){f.off()});this.views=[];return this},_setUpListeners:function(){this.off();this.on("error",function(g,j,f,i,h){console.error(g,j,f,i,h)},this);this.on("loading",function(){this._showLoadingIndicator("loading...",40)},this);this.on("loading-done",function(){this._hideLoadingIndicator(40)},this);this.once("rendered",function(){this.trigger("rendered:initial",this)},this);if(this.logger){this.on("all",function(f){this.log(this+"",arguments)},this)}this._setUpCollectionListeners();this._setUpViewListeners();return this},_setUpCollectionListeners:function(){this.log(this+"._setUpCollectionListeners",this.collection);this.collection.off();this.collection.on("error",function(g,j,f,i,h){this.trigger("error",g,j,f,i,h)},this);this.collection.on("reset",function(){this.renderItems()},this);this.collection.on("add",this.addItemView,this);this.collection.on("remove",this.removeItemView,this);if(this.logger){this.collection.on("all",function(f){this.info(this+"(collection)",arguments)},this)}return this},_setUpViewListeners:function(){this.log(this+"._setUpViewListeners");this.on("view:selected",function(f,g){if(g&&g.shiftKey&&this.lastSelected){var h=this.viewFromModelId(this.lastSelected);if(h){this.selectRange(f,h)}}this.selected.push(f.model.id);this.lastSelected=f.model.id},this);this.on("view:de-selected",function(f,g){this.selected=_.without(this.selected,f.model.id)},this)},render:function(g){this.log(this+".render",g);var f=this._buildNewRender();this._setUpBehaviors(f);this._queueNewRender(f,g);return this},_buildNewRender:function(){this.debug(this+"(ListPanel)._buildNewRender");var f=$(this.templates.el({},this));this._renderControls(f);this._renderTitle(f);this._renderSubtitle(f);this._renderSearch(f);this.renderItems(f);return f},_renderControls:function(g){this.debug(this+"(ListPanel)._renderControls");var f=$(this.templates.controls({},this));g.find(".controls").replaceWith(f);return f},_renderTitle:function(f){},_renderSubtitle:function(f){},_queueNewRender:function(g,h){h=(h===undefined)?(this.fxSpeed):(h);var f=this;f.log("_queueNewRender:",g,h);$(f).queue("fx",[function(i){this.$el.fadeOut(h,i)},function(i){f._swapNewRender(g);i()},function(i){this.$el.fadeIn(h,i)},function(i){f.trigger("rendered",f);i()}])},_swapNewRender:function(f){this.$el.empty().attr("class",this.className).append(f.children());if(this.selecting){this.showSelectors(0)}return this},_setUpBehaviors:function(f){f=f||this.$el;f.find(".controls [title]").tooltip({placement:"bottom"});return this},$scrollContainer:function(){return this.$el.parent().parent()},$list:function(f){return(f||this.$el).find("> .list-items")},$messages:function(f){return(f||this.$el).find("> .controls .messages")},$emptyMessage:function(f){return(f||this.$el).find("> .empty-message")},renderItems:function(h){h=h||this.$el;var f=this;f.log(this+".renderItems",h);var g=f.$list(h);f.views=f._filterCollection().map(function(i){return f._createItemView(i).render(0)});g.empty();if(f.views.length){f._attachItems(h);f.$emptyMessage(h).hide()}else{f._renderEmptyMessage(h).show()}return f.views},_filterCollection:function(){var f=this;return f.collection.filter(_.bind(f._filterItem,f))},_filterItem:function(g){var f=this;return(_.every(f.filters.map(function(h){return h.call(g)})))&&(!f.searchFor||g.matchesAll(f.searchFor))},_createItemView:function(h){var i=this._getItemViewClass(h),g=_.extend(this._getItemViewOptions(h),{model:h}),f=new i(g);this._setUpItemViewListeners(f);return f},_getItemViewClass:function(f){return this.viewClass},_getItemViewOptions:function(f){return{fxSpeed:this.fxSpeed,expanded:false,selectable:this.selecting,selected:_.contains(this.selected,f.id),draggable:this.dragging}},_setUpItemViewListeners:function(g){var f=this;g.on("all",function(){var h=Array.prototype.slice.call(arguments,0);h[0]="view:"+h[0];f.trigger.apply(f,h)});return f},_attachItems:function(f){this.$list(f).append(this.views.map(function(g){return g.$el}));return this},_renderEmptyMessage:function(f){this.debug("_renderEmptyMessage",f,this.searchFor);var g=this.searchFor?this.noneFoundMsg:this.emptyMsg;return this.$emptyMessage(f).text(g)},expandAll:function(){_.each(this.views,function(f){f.expand()})},collapseAll:function(){_.each(this.views,function(f){f.collapse()})},addItemView:function(i,j,h){this.log(this+".addItemView:",i);var g=this;if(!g._filterItem(i)){return undefined}var f=g._createItemView(i);g.views.push(f);$(f).queue("fx",[function(k){g.$emptyMessage().fadeOut(g.fxSpeed,k)},function(k){g.$list().append(f.render().$el);k()}]);return f},removeItemView:function(i,j,h){this.log(this+".removeItemView:",i);var g=this,f=g.viewFromModel(i);if(!f){return undefined}$({}).queue("fx",[function(k){f.$el.fadeOut(g.fxSpeed,k)},function(k){g.views=_.without(g.views,f);f.remove();if(!g.views.length){g._renderEmptyMessage().fadeIn(g.fxSpeed,k)}else{k()}}]);return f},viewFromModelId:function(g){for(var f=0;f<this.views.length;f++){if(this.views[f].model.id===g){return this.views[f]}}return undefined},viewFromModel:function(f){return this.viewFromModelId(f.id)},viewsWhereModel:function(f){return this.views.filter(function(g){var i=g.model.toJSON();for(var h in f){if(f.hasOwnProperty(h)){if(i[h]!==g.model.get(h)){return false}}}return true})},viewRange:function(i,h){if(i===h){return(i)?([i]):([])}var g=this.views.indexOf(i),f=this.views.indexOf(h);if(g===-1||f===-1){if(g===f){return[]}return(g===-1)?([h]):([i])}return(g<f)?this.views.slice(g,f+1):this.views.slice(f,g+1)},_renderSearch:function(f){f.find(".controls .search-input").searchInput({placeholder:this.searchPlaceholder,initialVal:this.searchFor,onfirstsearch:_.bind(this._firstSearch,this),onsearch:_.bind(this.searchItems,this),onclear:_.bind(this.clearSearch,this)});return f},_firstSearch:function(f){this.log("onFirstSearch",f);return this.searchItems(f)},searchItems:function(f){this.searchFor=f;this.trigger("search:searching",f,this);this.renderItems();return this},clearSearch:function(f){this.searchFor="";this.trigger("search:clear",this);this.renderItems();return this},showSelectors:function(f){f=(f!==undefined)?(f):(this.fxSpeed);this.selecting=true;this.$(".list-actions").slideDown(f);_.each(this.views,function(g){g.showSelector(f)})},hideSelectors:function(f){f=(f!==undefined)?(f):(this.fxSpeed);this.selecting=false;this.$(".list-actions").slideUp(f);_.each(this.views,function(g){g.hideSelector(f)});this.selected=[];this.lastSelected=null},toggleSelectors:function(){if(!this.selecting){this.showSelectors()}else{this.hideSelectors()}},selectAll:function(f){_.each(this.views,function(g){g.select(f)})},deselectAll:function(f){this.lastSelected=null;_.each(this.views,function(g){g.deselect(f)})},selectRange:function(h,g){var f=this.viewRange(h,g);_.each(f,function(i){i.select()});return f},getSelectedViews:function(){return _.filter(this.views,function(f){return f.selected})},getSelectedModels:function(){return new this.collection.constructor(_.map(this.getSelectedViews(),function(f){return f.model}))},_showLoadingIndicator:function(g,f,h){this.debug("_showLoadingIndicator",this.indicator,g,f,h);f=(f!==undefined)?(f):(this.fxSpeed);if(!this.indicator){this.indicator=new LoadingIndicator(this.$el,this.$el.parent());this.debug("\t created",this.indicator)}if(!this.$el.is(":visible")){this.indicator.show(0,h)}else{this.$el.fadeOut(f);this.indicator.show(g,f,h)}},_hideLoadingIndicator:function(f,g){this.debug("_hideLoadingIndicator",this.indicator,f,g);f=(f!==undefined)?(f):(this.fxSpeed);if(this.indicator){this.indicator.hide(f,g)}},scrollPosition:function(){return this.$scrollContainer().scrollTop()},scrollTo:function(f){this.$scrollContainer().scrollTop(f);return this},scrollToTop:function(){this.$scrollContainer().scrollTop(0);return this},scrollToItem:function(f){if(!f){return this}var g=f.$el.offset().top;this.$scrollContainer().scrollTop(g);return this},scrollToId:function(f){return this.scrollToItem(this.viewFromModelId(f))},events:{"click .select-all":"selectAll","click .deselect-all":"deselectAll"},toString:function(){return"ListPanel("+this.collection+")"}});e.prototype.templates=(function(){var g=b.wrapTemplate(["<div>",'<div class="controls"></div>','<div class="list-items"></div>','<div class="empty-message infomessagesmall"></div>',"</div>"]);var f=b.wrapTemplate(['<div class="controls">','<div class="title">','<div class="name"><%= view.title %></div>',"</div>",'<div class="subtitle"><%= view.subtitle %></div>','<div class="actions"></div>','<div class="messages"></div>','<div class="search">','<div class="search-input"></div>',"</div>",'<div class="list-actions">','<div class="btn-group">','<button class="select-all btn btn-default"','data-mode="select">',c("All"),"</button>",'<button class="deselect-all btn btn-default"','data-mode="select">',c("None"),"</button>","</div>","</div>","</div>"]);return{el:g,controls:f}}());var a=e.extend({modelCollectionKey:"contents",initialize:function(f){e.prototype.initialize.call(this,f);this.selecting=(f.selecting!==undefined)?f.selecting:false;this.setModel(this.model,f)},setModel:function(g,f){f=f||{};this.debug(this+".setModel:",g,f);this.freeModel();this.freeViews();if(g){this.model=g;if(this.logger){this.model.logger=this.logger}this._setUpModelListeners();this.collection.off();this.collection=(this.model[this.modelCollectionKey])?this.model[this.modelCollectionKey]:(f.collection||(new this.collectionClass([])));this._setUpCollectionListeners();this.trigger("new-model",this)}return this},freeModel:function(){if(this.model){this.stopListening(this.model)}return this},_setUpModelListeners:function(){this.log(this+"._setUpModelListeners",this.model);this.model.on("error",function(){this.trigger.apply(panel,arguments)},this);return this},_renderControls:function(g){this.debug(this+"(ListPanel)._renderControls");var h=this.model?this.model.toJSON():{},f=$(this.templates.controls(h,this));g.find(".controls").replaceWith(f);return f},toString:function(){return"ModelListPanel("+this.model+")"}});a.prototype.templates=(function(){var f=b.wrapTemplate(['<div class="controls">','<div class="title">','<div class="name"><%= model.name %></div>',"</div>",'<div class="subtitle"><%= view.subtitle %></div>','<div class="actions"></div>','<div class="messages"></div>','<div class="search">','<div class="search-input"></div>',"</div>",'<div class="list-actions">','<div class="btn-group">','<button class="select-all btn btn-default"','data-mode="select">',c("All"),"</button>",'<button class="deselect-all btn btn-default"','data-mode="select">',c("None"),"</button>","</div>","</div>","</div>"]);return _.extend(_.clone(e.prototype.templates),{controls:f})}());return{ListPanel:e,ModelListPanel:a}});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: History panels: allow foldout display of collections in display_by_slug, pages, and /view
by commits-noreply@bitbucket.org 11 Sep '14
by commits-noreply@bitbucket.org 11 Sep '14
11 Sep '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/618b02d13329/
Changeset: 618b02d13329
User: carlfeberhard
Date: 2014-09-11 18:23:00
Summary: History panels: allow foldout display of collections in display_by_slug, pages, and /view
Affected #: 24 files
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/mvc/collection/collection-li.js
--- a/static/scripts/mvc/collection/collection-li.js
+++ b/static/scripts/mvc/collection/collection-li.js
@@ -6,42 +6,26 @@
], function( LIST_ITEM, DATASET_LI, BASE_MVC, _l ){
/* global Backbone, LoggableMixin */
//==============================================================================
-var ListItemView = LIST_ITEM.ListItemView;
+var FoldoutListItemView = LIST_ITEM.FoldoutListItemView,
+ ListItemView = LIST_ITEM.ListItemView;
/** @class Read only view for DatasetCollection.
*/
-var DCListItemView = ListItemView.extend(
+var DCListItemView = FoldoutListItemView.extend(
/** @lends DCListItemView.prototype */{
//TODO: may not be needed
/** logger used to record this.log messages, commonly set to console */
//logger : console,
- className : ListItemView.prototype.className + " dataset-collection",
+ className : FoldoutListItemView.prototype.className + " dataset-collection",
id : function(){
return [ 'dataset_collection', this.model.get( 'id' ) ].join( '-' );
},
- /** jq speed for effects used */
- fxSpeed : 'fast',
-
-//TODO: ununsed
- /** set up */
- initialize : function( attributes ){
- if( attributes.logger ){ this.logger = this.model.logger = attributes.logger; }
- this.log( this + '(DCListItemView).initialize:', attributes );
- ListItemView.prototype.initialize.call( this, attributes );
- },
-
- /** In this override, don't show or render any details (no need to do anything here)
- * - currently the parent control will load a panel for this collection over itself
- * @fires expanded when a body has been expanded
- */
- expand : function(){
- var view = this;
- return view._fetchModelDetails()
- .always(function(){
- view.trigger( 'expanded', view );
- });
+ /** override to add linkTarget */
+ initialize : function( attributes ){
+ FoldoutListItemView.prototype.initialize.call( this, attributes );
+ this.linkTarget = attributes.linkTarget || '_blank';
},
// ......................................................................... rendering
@@ -62,6 +46,19 @@
return $subtitle;
},
+ // ......................................................................... foldout
+ _getFoldoutPanelOptions : function(){
+ var options = FoldoutListItemView.prototype._getFoldoutPanelOptions.call( this );
+ return _.extend( options, {
+ linkTarget : this.linkTarget
+ });
+ },
+
+ /** override in the case of sub-panels */
+ $selector : function(){
+ return this.$( '> .selector' );
+ },
+
// ......................................................................... misc
/** String representation */
toString : function(){
@@ -84,7 +81,7 @@
'</div>'
], 'collection' );
- return _.extend( {}, ListItemView.prototype.templates, {
+ return _.extend( {}, FoldoutListItemView.prototype.templates, {
titleBar : titleBarTemplate
});
}());
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/mvc/collection/collection-panel.js
--- a/static/scripts/mvc/collection/collection-panel.js
+++ b/static/scripts/mvc/collection/collection-panel.js
@@ -9,7 +9,6 @@
TODO:
============================================================================= */
-// =============================================================================
/** @class non-editable, read-only View/Controller for a dataset collection.
*/
var _super = LIST_PANEL.ModelListPanel;
@@ -23,11 +22,11 @@
className : _super.prototype.className + ' dataset-collection-panel',
/** sub view class used for datasets */
- DatasetDCEViewClass : DC_LI.DatasetDCEListItemView,
+ DatasetDCEViewClass : DC_LI.DatasetDCEListItemView,
/** sub view class used for nested collections */
- NestedDCDCEViewClass : DC_LI.NestedDCDCEListItemView,
+ NestedDCDCEViewClass: DC_LI.NestedDCDCEListItemView,
/** key of attribute in model to assign to this.collection */
- modelCollectionKey : 'elements',
+ modelCollectionKey : 'elements',
// ......................................................................... SET UP
/** Set up the view, set up storage, bind listeners to HistoryContents events
@@ -38,16 +37,19 @@
this.linkTarget = attributes.linkTarget || '_blank';
this.hasUser = attributes.hasUser;
+
+ /** */
this.panelStack = [];
+ /** */
this.parentName = attributes.parentName;
-
- //window.collectionPanel = this;
+ /** */
+ this.foldoutStyle = attributes.foldoutStyle || 'foldout';
},
// ------------------------------------------------------------------------ sub-views
/** In this override, use model.getVisibleContents */
_filterCollection : function(){
-//TODO: should *not* be model.getVisibleContents
+//TODO: should *not* be model.getVisibleContents - visibility is not model related
return this.model.getVisibleContents();
},
@@ -69,59 +71,41 @@
var options = _super.prototype._getItemViewOptions.call( this, model );
return _.extend( options, {
linkTarget : this.linkTarget,
- hasUser : this.hasUser
+ hasUser : this.hasUser,
+//TODO: could move to only nested: list:paired
+ foldoutStyle : this.foldoutStyle
});
},
- /** when a sub-view is clicked in the collection panel that is itself a collection,
- * hide this panel's elements and show the sub-collection in its own panel.
- */
+ // ------------------------------------------------------------------------ collection sub-views
+ /** In this override, add/remove expanded/collapsed model ids to/from web storage */
_setUpItemViewListeners : function( view ){
var panel = this;
_super.prototype._setUpItemViewListeners.call( panel, view );
- //TODO:?? doesn't seem to belong here
- if( view.model.get( 'element_type' ) === 'dataset_collection' ){
- view.on( 'expanded', function( collectionView ){
- panel.info( 'expanded', collectionView );
- panel._addCollectionPanel( collectionView );
- });
- }
- return panel;
+
+ // use pub-sub to: handle drilldown expansion and collapse
+ view.on( 'expanded:drilldown', function( v, drilldown ){
+ this._expandDrilldownPanel( drilldown );
+ }, this );
+ view.on( 'collapsed:drilldown', function( v, drilldown ){
+ this._collapseDrilldownPanel( drilldown );
+ }, this );
+ return this;
},
- /** When a sub-collection is clicked, hide the current panel and render the sub-collection in its own panel */
- _addCollectionPanel : function( collectionView ){
-//TODO: a bit hackish
- var currPanel = this,
- collectionModel = collectionView.model;
+ /** */
+ _expandDrilldownPanel : function( drilldown ){
+ this.panelStack.push( drilldown );
+ // hide this panel's controls and list, set the name for back navigation, and attach to the $el
+ this.$( '> .controls' ).add( this.$list() ).hide();
+ drilldown.parentName = this.model.get( 'name' );
+ this.$el.append( drilldown.render().$el );
+ },
- //this.debug( 'collection panel (stack), collectionView:', collectionView );
- //this.debug( 'collection panel (stack), collectionModel:', collectionModel );
- var panel = new PairCollectionPanel({
- model : collectionModel,
- parentName : this.model.get( 'name' ),
- linkTarget : this.linkTarget
- });
- currPanel.panelStack.push( panel );
-
- currPanel.$( '.controls' ).add( '.list-items' ).hide();
- currPanel.$el.append( panel.$el );
- panel.on( 'close', function(){
- currPanel.render();
- collectionView.collapse();
- currPanel.panelStack.pop();
- });
-
- //TODO: to hdca-model, hasDetails
- if( !panel.model.hasDetails() ){
- var xhr = panel.model.fetch();
- xhr.done( function(){
- //TODO: (re-)render collection contents
- panel.render();
- });
- } else {
- panel.render();
- }
+ /** */
+ _collapseDrilldownPanel : function( drilldown ){
+ this.panelStack.pop();
+ this.render();
},
// ------------------------------------------------------------------------ panel events
@@ -216,7 +200,9 @@
//TODO: not strictly needed - due to switch in CollectionPanel._getContentClass
/** sub view class used for nested collections */
- NestedDCDCEViewClass : DC_LI.NestedDCDCEListItemView,
+ NestedDCDCEViewClass : DC_LI.NestedDCDCEListItemView.extend({
+ foldoutPanelClass : PairCollectionPanel
+ }),
// ........................................................................ misc
/** string rep */
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/mvc/dataset/dataset-li.js
--- a/static/scripts/mvc/dataset/dataset-li.js
+++ b/static/scripts/mvc/dataset/dataset-li.js
@@ -42,15 +42,7 @@
/** event listeners */
_setUpListeners : function(){
-//TODO:?? may want to move this to ListItemView (although this is only needed in the *narrow* panel views (current))
- // hide the primary actions in the title bar when selectable and narrow
- this.on( 'selectable', function( isSelectable ){
- if( isSelectable ){
- this.$( '.primary-actions' ).hide();
- } else {
- this.$( '.primary-actions' ).show();
- }
- }, this );
+ _super.prototype._setUpListeners.call( this );
// re-rendering on any model changes
this.model.on( 'change', function( model, options ){
@@ -64,10 +56,6 @@
this.render();
}
}, this );
-
- this.on( 'all', function( event ){
- this.log( event );
- }, this );
},
// ......................................................................... expandable
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/mvc/history/hdca-li.js
--- a/static/scripts/mvc/history/hdca-li.js
+++ b/static/scripts/mvc/history/hdca-li.js
@@ -1,9 +1,10 @@
define([
"mvc/dataset/states",
"mvc/collection/collection-li",
+ "mvc/collection/collection-panel",
"mvc/base-mvc",
"utils/localization"
-], function( STATES, DC_LI, BASE_MVC, _l ){
+], function( STATES, DC_LI, DC_PANEL, BASE_MVC, _l ){
/* global Backbone */
//==============================================================================
var _super = DC_LI.DCListItemView;
@@ -17,6 +18,18 @@
className : _super.prototype.className + " history-content",
+ _getFoldoutPanelClass : function(){
+ switch( this.model.get( 'collection_type' ) ){
+ case 'list':
+ return DC_PANEL.ListCollectionPanel;
+ case 'paired':
+ return DC_PANEL.PairCollectionPanel;
+ case 'list:paired':
+ return DC_PANEL.ListOfPairsCollectionPanel;
+ }
+ throw new TypeError( 'Uknown collection_type: ' + this.model.get( 'collection_type' ) );
+ },
+
/** In this override, add the state as a class for use with state-based CSS */
_swapNewRender : function( $newRender ){
_super.prototype._swapNewRender.call( this, $newRender );
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/mvc/history/history-panel-edit-current.js
--- a/static/scripts/mvc/history/history-panel-edit-current.js
+++ b/static/scripts/mvc/history/history-panel-edit-current.js
@@ -35,19 +35,26 @@
/** @class View/Controller for the user's current history model as used in the history
* panel (current right hand panel) of the analysis page.
*
- * The only history panel that will poll for updates.
+ * The only history panel that:
+ * will poll for updates.
+ * displays datasets in reverse hid order.
*/
var CurrentHistoryPanel = _super.extend(
/** @lends CurrentHistoryPanel.prototype */{
- className : _super.prototype.className + ' current-history-panel',
-
/** logger used to record this.log messages, commonly set to console */
//logger : console,
+ className : _super.prototype.className + ' current-history-panel',
+
emptyMsg : _l( "This history is empty. Click 'Get Data' on the left tool menu to start" ),
noneFoundMsg : _l( "No matching datasets found" ),
+ /** */
+ HDCAViewClass : _super.prototype.HDCAViewClass.extend({
+ foldoutStyle : 'drilldown'
+ }),
+
// ......................................................................... SET UP
/** Set up the view, set up storage, bind listeners to HistoryContents events */
initialize : function( attributes ){
@@ -220,6 +227,7 @@
panel.preferences.set( 'tagsEditorShown', tagsEditor.hidden );
});
},
+
/** In this override, get and set current panel preferences when editor is used */
_renderAnnotation : function( $where ){
var panel = this;
@@ -236,6 +244,7 @@
},
// ------------------------------------------------------------------------ sub-views
+ // reverse HID order
/** Override to reverse order of views - newest contents on top */
_attachItems : function( $whereTo ){
this.$list( $whereTo ).append( this.views.reverse().map( function( view ){
@@ -244,85 +253,20 @@
return this;
},
- /** In this override, handle collection expansion. */
- _setUpItemViewListeners : function( view ){
- var panel = this;
- _super.prototype._setUpItemViewListeners.call( panel, view );
-
- if( view instanceof panel.HDCAViewClass ){
- view.off( 'expanded' );
- view.on( 'expanded', function( collectionView ){
- panel.info( 'expanded', collectionView );
- panel._addCollectionPanel( collectionView );
- });
- view.off( 'collapsed' );
- }
- },
-
- /** In this override, handle collection expansion. */
- _addCollectionPanel : function( collectionView ){
- var panel = this,
- collectionModel = collectionView.model;
-
- this.debug( 'history panel (stack), collectionModel:', collectionModel );
- var overlaid = new ( this._getCollectionPanelClass( collectionModel ) )({
- model : collectionModel,
- HDAViewClass : this.HDAViewClass,
- parentName : this.model.get( 'name' ),
- linkTarget : this.linkTarget
- });
- panel.panelStack.push( overlaid );
-
- panel.$( '.controls' ).add( panel.$list() ).hide();
- panel.$el.append( overlaid.$el );
- overlaid.on( 'close', function(){
- panel.render();
- collectionView.collapse();
- panel.panelStack.pop();
- });
-
- //TODO: to hdca-model, hasDetails
- if( !overlaid.model.hasDetails() ){
- var xhr = overlaid.model.fetch();
- xhr.done( function(){
- //this.debug( 'collection data fetched' );
- //this.debug( JSON.stringify( overlaid.model.toJSON(), null, ' ' ) );
- //TODO: (re-)render collection contents
- overlaid.render();
- });
- } else {
- overlaid.render();
- }
- },
-
- _getCollectionPanelClass : function( model ){
- switch( model.get( 'collection_type' ) ){
- case 'list':
- return DC_PANEL.ListCollectionPanel;
- case 'paired':
- return DC_PANEL.PairCollectionPanel;
- case 'list:paired':
- return DC_PANEL.ListOfPairsCollectionPanel;
- }
- throw new TypeError( 'Uknown collection_type: ' + model.get( 'collection_type' ) );
- },
-
- /** In this override, check for any overlaid panels first */
+ /** Override to add datasets at the top */
addItemView : function( model, collection, options ){
this.log( this + '.addItemView:', model );
- if( !this._filterItem( model ) ){ return undefined; }
+ var panel = this;
+ if( !panel._filterItem( model ) ){ return undefined; }
+//TODO: alternately, call collapse drilldown
+ // if this panel is currently hidden, return undefined
+ if( panel.panelStack.length ){ return this._collapseDrilldownPanel(); }
- var panel = this;
- // don't show/add if there are panels overlaid on this one
- if( this.panelStack.length ){
- return panel;
- }
+ var view = panel._createItemView( model );
+ // use unshift and prepend to preserve reversed order
+ panel.views.unshift( view );
- // current history item order is reversed - use unshift and prepend
- var view = panel._createItemView( model );
- this.views.unshift( view );
panel.scrollToTop();
-
$({}).queue([
function fadeOutEmptyMsg( next ){
var $emptyMsg = panel.$emptyMessage();
@@ -333,8 +277,7 @@
}
},
function createAndPrepend( next ){
- //view.render().$el.hide();
- panel.scrollToTop();
+ // render as hidden then slide down
panel.$list().prepend( view.render( 0 ).$el.hide() );
view.$el.slideDown( panel.fxSpeed );
}
@@ -342,6 +285,36 @@
return view;
},
+ // ------------------------------------------------------------------------ collection sub-views
+ /** In this override, add/remove expanded/collapsed model ids to/from web storage */
+ _setUpItemViewListeners : function( view ){
+ var panel = this;
+ _super.prototype._setUpItemViewListeners.call( panel, view );
+
+ // use pub-sub to: handle drilldown expansion and collapse
+ view.on( 'expanded:drilldown', function( v, drilldown ){
+ this._expandDrilldownPanel( drilldown );
+ }, this );
+ view.on( 'collapsed:drilldown', function( v, drilldown ){
+ this._collapseDrilldownPanel( drilldown );
+ }, this );
+ return this;
+ },
+
+ _expandDrilldownPanel : function( drilldown ){
+ this.panelStack.push( drilldown );
+ // hide this panel's controls and list, set the name for back navigation, and attach to the $el
+ this.$( '> .controls' ).add( this.$list() ).hide();
+ drilldown.parentName = this.model.get( 'name' );
+ this.$el.append( drilldown.render().$el );
+ },
+
+ _collapseDrilldownPanel : function( drilldown ){
+ this.panelStack.pop();
+//TODO: MEM: free the panel
+ this.render();
+ },
+
// ........................................................................ external objects/MVC
//TODO: remove quota meter from panel and remove this
/** add listeners to an external quota meter (mvc/user/user-quotameter.js) */
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/mvc/history/history-panel.js
--- a/static/scripts/mvc/history/history-panel.js
+++ b/static/scripts/mvc/history/history-panel.js
@@ -4,10 +4,21 @@
"mvc/history/history-contents",
"mvc/history/hda-li",
"mvc/history/hdca-li",
+ "mvc/collection/collection-panel",
"mvc/user/user-model",
"mvc/base-mvc",
"utils/localization"
-], function( LIST_PANEL, HISTORY_MODEL, HISTORY_CONTENTS, HDA_LI, HDCA_LI, USER, BASE_MVC, _l ){
+], function(
+ LIST_PANEL,
+ HISTORY_MODEL,
+ HISTORY_CONTENTS,
+ HDA_LI,
+ HDCA_LI,
+ COLLECTION_PANEL,
+ USER,
+ BASE_MVC,
+ _l
+){
// ============================================================================
/** session storage for individual history preferences */
var HistoryPrefs = BASE_MVC.SessionStorageModel.extend(
@@ -22,13 +33,13 @@
//TODO: add scroll position?
},
/** add an hda id to the hash of expanded hdas */
- addExpandedHda : function( model ){
+ addExpanded : function( model ){
var key = 'expandedIds';
//TODO:?? is this right anymore?
this.save( key, _.extend( this.get( key ), _.object([ model.id ], [ model.get( 'id' ) ]) ) );
},
/** remove an hda id from the hash of expanded hdas */
- removeExpandedHda : function( model ){
+ removeExpanded : function( model ){
var key = 'expandedIds';
this.save( key, _.omit( this.get( key ), model.id ) );
},
@@ -199,6 +210,15 @@
return xhr;
},
+ /** convenience alias to the model. Updates the item list only (not the history) */
+ refreshContents : function( detailIds, options ){
+ if( this.model ){
+ return this.model.refresh( detailIds, options );
+ }
+ // may have callbacks - so return an empty promise
+ return $.when();
+ },
+
//TODO:?? seems unneccesary
//TODO: Maybe better in History?
/** create a new history model from JSON and call setModel on it */
@@ -319,24 +339,14 @@
//TODO:?? could use 'view:expanded' here?
// maintain a list of items whose bodies are expanded
view.on( 'expanded', function( v ){
- panel.storage.addExpandedHda( v.model );
+ panel.storage.addExpanded( v.model );
});
view.on( 'collapsed', function( v ){
- panel.storage.removeExpandedHda( v.model );
+ panel.storage.removeExpanded( v.model );
});
return this;
},
- // ------------------------------------------------------------------------ collection/views syncing
- /** convenience alias to the model. Updates the item list only (not the history) */
- refreshContents : function( detailIds, options ){
- if( this.model ){
- return this.model.refresh( detailIds, options );
- }
- // may have callbacks - so return an empty promise
- return $.when();
- },
-
// ------------------------------------------------------------------------ selection
/** Override to correctly set the historyId of the new collection */
getSelectedModels : function(){
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/mvc/list/list-item.js
--- a/static/scripts/mvc/list/list-item.js
+++ b/static/scripts/mvc/list/list-item.js
@@ -87,7 +87,7 @@
/** shortcut to details DOM (as jQ) */
$details : function( $where ){
$where = $where || this.$el;
- return $where.find( '.details' );
+ return $where.find( '> .details' );
},
/** build the DOM for the details and set up behaviors on it */
@@ -123,7 +123,7 @@
view.$details().replaceWith( $newDetails );
// needs to be set after the above or the slide will not show
view.expanded = true;
- $newDetails.slideDown( view.fxSpeed, function(){
+ view.$details().slideDown( view.fxSpeed, function(){
view.trigger( 'expanded', view );
});
});
@@ -143,6 +143,7 @@
* @fires collapsed when a body has been collapsed
*/
collapse : function(){
+ this.debug( this + '(ExpandableView).collapse' );
var view = this;
view.expanded = false;
this.$details().slideUp( view.fxSpeed, function(){
@@ -177,16 +178,33 @@
ExpandableView.prototype.initialize.call( this, attributes );
BASE_MVC.SelectableViewMixin.initialize.call( this, attributes );
BASE_MVC.DraggableViewMixin.initialize.call( this, attributes );
+ this._setUpListeners();
+ },
+
+ /** event listeners */
+ _setUpListeners : function(){
+ // hide the primary actions in the title bar when selectable and narrow
+ this.on( 'selectable', function( isSelectable ){
+ if( isSelectable ){
+ this.$( '.primary-actions' ).hide();
+ } else {
+ this.$( '.primary-actions' ).show();
+ }
+ }, this );
+ //this.on( 'all', function( event ){
+ // this.log( event );
+ //}, this );
+ return this;
},
// ........................................................................ rendering
/** In this override, call methods to build warnings, titlebar and primary actions */
_buildNewRender : function(){
var $newRender = ExpandableView.prototype._buildNewRender.call( this );
- $newRender.find( '.warnings' ).replaceWith( this._renderWarnings() );
- $newRender.find( '.title-bar' ).replaceWith( this._renderTitleBar() );
- $newRender.find( '.primary-actions' ).append( this._renderPrimaryActions() );
- $newRender.find( '.subtitle' ).replaceWith( this._renderSubtitle() );
+ $newRender.children( '.warnings' ).replaceWith( this._renderWarnings() );
+ $newRender.children( '.title-bar' ).replaceWith( this._renderTitleBar() );
+ $newRender.children( '.primary-actions' ).append( this._renderPrimaryActions() );
+ $newRender.find( '.title-bar .subtitle' ).replaceWith( this._renderSubtitle() );
return $newRender;
},
@@ -325,8 +343,135 @@
//==============================================================================
+/** A view that is displayed in some larger list/grid/collection.
+ * *AND* can display some sub-list of it's own when expanded (e.g. dataset collections).
+ * This list will 'foldout' when the item is expanded depending on this.foldoutStyle:
+ * If 'foldout': will expand vertically to show the nested list
+ * If 'drilldown': will overlay the parent list
+ *
+ * Inherits from ListItemView.
+ *
+ * _renderDetails does the work of creating this.details: a sub-view that shows the nested list
+ */
+var FoldoutListItemView = ListItemView.extend({
+
+ foldoutStyle : 'foldout',
+ foldoutPanelClass : null,
+
+ initialize : function( attributes ){
+ ListItemView.prototype.initialize.call( this, attributes );
+//TODO: hackish
+ if( this.foldoutStyle === 'drilldown' ){ this.expanded = false; }
+ this.foldoutStyle = attributes.foldoutStyle || this.foldoutStyle;
+ this.foldoutPanelClass = attributes.foldoutPanelClass || this.foldoutPanelClass;
+ },
+
+//TODO:?? override to exclude foldout scope?
+ $ : function( selector ){
+ var $found = ListItemView.prototype.$.call( this, selector );
+ return $found;
+ },
+
+ /** in this override, attach the foldout panel when rendering details */
+ _renderDetails : function(){
+//TODO: hackish
+ if( this.foldoutStyle === 'drilldown' ){ return $(); }
+ var $newDetails = ListItemView.prototype._renderDetails.call( this );
+ return this._attachFoldout( this._createFoldoutPanel(), $newDetails );
+ },
+
+ /** In this override, handle collection expansion. */
+ _createFoldoutPanel : function(){
+ var model = this.model;
+ var FoldoutClass = this._getFoldoutPanelClass( model ),
+ options = this._getFoldoutPanelOptions( model ),
+ foldout = new FoldoutClass( _.extend( options, {
+ model : model
+ }));
+ return foldout;
+ },
+
+ _getFoldoutPanelClass : function(){
+ // override
+ return this.foldoutPanelClass;
+ },
+
+ _getFoldoutPanelOptions : function(){
+ return {
+ // propagate foldout style down
+ foldoutStyle : this.foldoutStyle
+ };
+ },
+
+ /** */
+ _attachFoldout : function( foldout, $whereTo ){
+ $whereTo = $whereTo || this.$( '> .details' );
+ this.foldout = foldout.render( 0 );
+//TODO: hack
+ foldout.$( '> .controls' ).hide();
+ return $whereTo.append( foldout.$el );
+ },
+
+ /** Render and show the full, detailed body of this view including extra data and controls.
+ * note: if the model does not have detailed data, fetch that data before showing the body
+ * @fires expanded when a body has been expanded
+ */
+ expand : function(){
+ var view = this;
+ return view._fetchModelDetails()
+ .always(function(){
+ if( view.foldoutStyle === 'foldout' ){
+ view._expandByFoldout();
+ } else if( view.foldoutStyle === 'drilldown' ){
+ view._expandByDrilldown();
+ }
+ });
+ },
+
+ _expandByFoldout : function(){
+ var view = this;
+ var $newDetails = view._renderDetails();
+ view.$details().replaceWith( $newDetails );
+ // needs to be set after the above or the slide will not show
+ view.expanded = true;
+ view.$details().slideDown( view.fxSpeed, function(){
+ view.trigger( 'expanded', view );
+ });
+ },
+
+ _expandByDrilldown : function(){
+ var view = this;
+ // attachment and rendering done by listener
+ view.foldout = this._createFoldoutPanel();
+ view.foldout.on( 'close', function(){
+ view.trigger( 'collapsed:drilldown', view, view.foldout );
+ });
+ view.trigger( 'expanded:drilldown', view, view.foldout );
+ }
+
+});
+
+// ............................................................................ TEMPLATES
+/** underscore templates */
+FoldoutListItemView.prototype.templates = (function(){
+
+ // use element identifier
+ var detailsTemplate = BASE_MVC.wrapTemplate([
+ '<div class="details">',
+ // override with more info (that goes above the panel)
+ '</div>'
+ ], 'collection' );
+
+ return _.extend( {}, ListItemView.prototype.templates, {
+ details : detailsTemplate
+ });
+}());
+
+
+//==============================================================================
return {
ExpandableView : ExpandableView,
- ListItemView : ListItemView
+ ListItemView : ListItemView,
+ FoldoutListItemView : FoldoutListItemView
};
});
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/mvc/list/list-panel.js
--- a/static/scripts/mvc/list/list-panel.js
+++ b/static/scripts/mvc/list/list-panel.js
@@ -184,9 +184,7 @@
// shift to select a range
this.on( 'view:selected', function( view, ev ){
if( ev && ev.shiftKey && this.lastSelected ){
- var lastSelectedView = _.find( this.views, function( view ){
- return view.model.id === this.lastSelected;
- });
+ var lastSelectedView = this.viewFromModelId( this.lastSelected );
if( lastSelectedView ){
this.selectRange( view, lastSelectedView );
}
@@ -294,15 +292,15 @@
},
/** */
$list : function( $where ){
- return ( $where || this.$el ).find( '.list-items' );
+ return ( $where || this.$el ).find( '> .list-items' );
},
/** container where list messages are attached */
$messages : function( $where ){
- return ( $where || this.$el ).find( '.messages' );
+ return ( $where || this.$el ).find( '> .controls .messages' );
},
/** the message displayed when no views can be shown (no views, none matching search) */
$emptyMessage : function( $where ){
- return ( $where || this.$el ).find( '.empty-message' );
+ return ( $where || this.$el ).find( '> .empty-message' );
},
// ------------------------------------------------------------------------ hda sub-views
@@ -593,6 +591,7 @@
this.selecting = true;
this.$( '.list-actions' ).slideDown( speed );
_.each( this.views, function( view ){
+console.debug( view.$el );
view.showSelector( speed );
});
//this.selected = [];
@@ -915,7 +914,7 @@
//=============================================================================
return {
- ListPanel : ListPanel,
- ModelListPanel : ModelListPanel
+ ListPanel : ListPanel,
+ ModelListPanel : ModelListPanel
};
});
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/packed/mvc/collection/collection-li.js
--- a/static/scripts/packed/mvc/collection/collection-li.js
+++ b/static/scripts/packed/mvc/collection/collection-li.js
@@ -1,1 +1,1 @@
-define(["mvc/list/list-item","mvc/dataset/dataset-li","mvc/base-mvc","utils/localization"],function(a,h,i,d){var e=a.ListItemView;var c=e.extend({className:e.prototype.className+" dataset-collection",id:function(){return["dataset_collection",this.model.get("id")].join("-")},fxSpeed:"fast",initialize:function(j){if(j.logger){this.logger=this.model.logger=j.logger}this.log(this+"(DCListItemView).initialize:",j);e.prototype.initialize.call(this,j)},expand:function(){var j=this;return j._fetchModelDetails().always(function(){j.trigger("expanded",j)})},_renderSubtitle:function(){var j=$('<div class="subtitle"></div>');switch(this.model.get("collection_type")){case"list":return j.text(d("a list of datasets"));case"paired":return j.text(d("a pair of datasets"));case"list:paired":return j.text(d("a list of paired datasets"))}return j},toString:function(){var j=(this.model)?(this.model+""):("(no model)");return"DCListItemView("+j+")"}});c.prototype.templates=(function(){var j=i.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<div class="title">','<span class="name"><%- collection.element_identifier || collection.name %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"collection");return _.extend({},e.prototype.templates,{titleBar:j})}());var f=e.extend({className:e.prototype.className+" dataset-collection-element",fxSpeed:"fast",initialize:function(j){if(j.logger){this.logger=this.model.logger=j.logger}this.log("DCEListItemView.initialize:",j);e.prototype.initialize.call(this,j)},toString:function(){var j=(this.model)?(this.model+""):("(no model)");return"DCEListItemView("+j+")"}});f.prototype.templates=(function(){var j=i.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<div class="title">','<span class="name"><%- element.element_identifier %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"element");return _.extend({},e.prototype.templates,{titleBar:j})}());var b=h.DatasetListItemView.extend({className:h.DatasetListItemView.prototype.className+" dataset-collection-element",initialize:function(j){if(j.logger){this.logger=this.model.logger=j.logger}this.log("DatasetDCEListItemView.initialize:",j);h.DatasetListItemView.prototype.initialize.call(this,j)},toString:function(){var j=(this.model)?(this.model+""):("(no model)");return"DatasetDCEListItemView("+j+")"}});b.prototype.templates=(function(){var j=i.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="name"><%- element.element_identifier %></span>',"</div>","</div>"],"element");return _.extend({},h.DatasetListItemView.prototype.templates,{titleBar:j})}());var g=c.extend({className:c.prototype.className+" dataset-collection-element",_swapNewRender:function(j){c.prototype._swapNewRender.call(this,j);var k=this.model.get("state")||"ok";this.$el.addClass("state-"+k);return this.$el},toString:function(){var j=(this.model)?(this.model+""):("(no model)");return"NestedDCDCEListItemView("+j+")"}});return{DCListItemView:c,DCEListItemView:f,DatasetDCEListItemView:b,NestedDCDCEListItemView:g}});
\ No newline at end of file
+define(["mvc/list/list-item","mvc/dataset/dataset-li","mvc/base-mvc","utils/localization"],function(a,h,i,d){var j=a.FoldoutListItemView,e=a.ListItemView;var c=j.extend({className:j.prototype.className+" dataset-collection",id:function(){return["dataset_collection",this.model.get("id")].join("-")},initialize:function(k){j.prototype.initialize.call(this,k);this.linkTarget=k.linkTarget||"_blank"},_renderSubtitle:function(){var k=$('<div class="subtitle"></div>');switch(this.model.get("collection_type")){case"list":return k.text(d("a list of datasets"));case"paired":return k.text(d("a pair of datasets"));case"list:paired":return k.text(d("a list of paired datasets"))}return k},_getFoldoutPanelOptions:function(){var k=j.prototype._getFoldoutPanelOptions.call(this);return _.extend(k,{linkTarget:this.linkTarget})},$selector:function(){return this.$("> .selector")},toString:function(){var k=(this.model)?(this.model+""):("(no model)");return"DCListItemView("+k+")"}});c.prototype.templates=(function(){var k=i.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<div class="title">','<span class="name"><%- collection.element_identifier || collection.name %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"collection");return _.extend({},j.prototype.templates,{titleBar:k})}());var f=e.extend({className:e.prototype.className+" dataset-collection-element",fxSpeed:"fast",initialize:function(k){if(k.logger){this.logger=this.model.logger=k.logger}this.log("DCEListItemView.initialize:",k);e.prototype.initialize.call(this,k)},toString:function(){var k=(this.model)?(this.model+""):("(no model)");return"DCEListItemView("+k+")"}});f.prototype.templates=(function(){var k=i.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<div class="title">','<span class="name"><%- element.element_identifier %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"element");return _.extend({},e.prototype.templates,{titleBar:k})}());var b=h.DatasetListItemView.extend({className:h.DatasetListItemView.prototype.className+" dataset-collection-element",initialize:function(k){if(k.logger){this.logger=this.model.logger=k.logger}this.log("DatasetDCEListItemView.initialize:",k);h.DatasetListItemView.prototype.initialize.call(this,k)},toString:function(){var k=(this.model)?(this.model+""):("(no model)");return"DatasetDCEListItemView("+k+")"}});b.prototype.templates=(function(){var k=i.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="name"><%- element.element_identifier %></span>',"</div>","</div>"],"element");return _.extend({},h.DatasetListItemView.prototype.templates,{titleBar:k})}());var g=c.extend({className:c.prototype.className+" dataset-collection-element",_swapNewRender:function(k){c.prototype._swapNewRender.call(this,k);var l=this.model.get("state")||"ok";this.$el.addClass("state-"+l);return this.$el},toString:function(){var k=(this.model)?(this.model+""):("(no model)");return"NestedDCDCEListItemView("+k+")"}});return{DCListItemView:c,DCEListItemView:f,DatasetDCEListItemView:b,NestedDCDCEListItemView:g}});
\ No newline at end of file
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/packed/mvc/collection/collection-panel.js
--- a/static/scripts/packed/mvc/collection/collection-panel.js
+++ b/static/scripts/packed/mvc/collection/collection-panel.js
@@ -1,1 +1,1 @@
-define(["mvc/list/list-panel","mvc/collection/collection-model","mvc/collection/collection-li","mvc/base-mvc","utils/localization"],function(a,d,f,j,b){var h=a.ModelListPanel;var g=h.extend({className:h.prototype.className+" dataset-collection-panel",DatasetDCEViewClass:f.DatasetDCEListItemView,NestedDCDCEViewClass:f.NestedDCDCEListItemView,modelCollectionKey:"elements",initialize:function(k){h.prototype.initialize.call(this,k);this.linkTarget=k.linkTarget||"_blank";this.hasUser=k.hasUser;this.panelStack=[];this.parentName=k.parentName},_filterCollection:function(){return this.model.getVisibleContents()},_getItemViewClass:function(k){switch(k.get("element_type")){case"hda":return this.DatasetDCEViewClass;case"dataset_collection":return this.NestedDCDCEViewClass}throw new TypeError("Unknown element type:",k.get("element_type"))},_getItemViewOptions:function(l){var k=h.prototype._getItemViewOptions.call(this,l);return _.extend(k,{linkTarget:this.linkTarget,hasUser:this.hasUser})},_setUpItemViewListeners:function(l){var k=this;h.prototype._setUpItemViewListeners.call(k,l);if(l.model.get("element_type")==="dataset_collection"){l.on("expanded",function(m){k.info("expanded",m);k._addCollectionPanel(m)})}return k},_addCollectionPanel:function(m){var n=this,k=m.model;var l=new i({model:k,parentName:this.model.get("name"),linkTarget:this.linkTarget});n.panelStack.push(l);n.$(".controls").add(".list-items").hide();n.$el.append(l.$el);l.on("close",function(){n.render();m.collapse();n.panelStack.pop()});if(!l.model.hasDetails()){var o=l.model.fetch();o.done(function(){l.render()})}else{l.render()}},events:{"click .navigation .back":"close"},close:function(k){this.$el.remove();this.trigger("close")},toString:function(){return"CollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});g.prototype.templates=(function(){var k=j.wrapTemplate(['<div class="controls">','<div class="navigation">','<a class="back" href="javascript:void(0)">','<span class="fa fa-icon fa-angle-left"></span>',b("Back to "),"<%- view.parentName %>","</a>","</div>",'<div class="title">','<div class="name"><%- collection.name || collection.element_identifier %></div>','<div class="subtitle">','<% if( collection.collection_type === "list" ){ %>',b("a list of datasets"),'<% } else if( collection.collection_type === "paired" ){ %>',b("a pair of datasets"),'<% } else if( collection.collection_type === "list:paired" ){ %>',b("a list of paired datasets"),"<% } %>","</div>","</div>","</div>"],"collection");return _.extend(_.clone(h.prototype.templates),{controls:k})}());var e=g.extend({DatasetDCEViewClass:f.DatasetDCEListItemView,toString:function(){return"ListCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var i=e.extend({toString:function(){return"PairCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var c=g.extend({NestedDCDCEViewClass:f.NestedDCDCEListItemView,toString:function(){return"ListOfPairsCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{CollectionPanel:g,ListCollectionPanel:e,PairCollectionPanel:i,ListOfPairsCollectionPanel:c}});
\ No newline at end of file
+define(["mvc/list/list-panel","mvc/collection/collection-model","mvc/collection/collection-li","mvc/base-mvc","utils/localization"],function(a,d,f,j,b){var h=a.ModelListPanel;var g=h.extend({className:h.prototype.className+" dataset-collection-panel",DatasetDCEViewClass:f.DatasetDCEListItemView,NestedDCDCEViewClass:f.NestedDCDCEListItemView,modelCollectionKey:"elements",initialize:function(k){h.prototype.initialize.call(this,k);this.linkTarget=k.linkTarget||"_blank";this.hasUser=k.hasUser;this.panelStack=[];this.parentName=k.parentName;this.foldoutStyle=k.foldoutStyle||"foldout"},_filterCollection:function(){return this.model.getVisibleContents()},_getItemViewClass:function(k){switch(k.get("element_type")){case"hda":return this.DatasetDCEViewClass;case"dataset_collection":return this.NestedDCDCEViewClass}throw new TypeError("Unknown element type:",k.get("element_type"))},_getItemViewOptions:function(l){var k=h.prototype._getItemViewOptions.call(this,l);return _.extend(k,{linkTarget:this.linkTarget,hasUser:this.hasUser,foldoutStyle:this.foldoutStyle})},_setUpItemViewListeners:function(l){var k=this;h.prototype._setUpItemViewListeners.call(k,l);l.on("expanded:drilldown",function(n,m){this._expandDrilldownPanel(m)},this);l.on("collapsed:drilldown",function(n,m){this._collapseDrilldownPanel(m)},this);return this},_expandDrilldownPanel:function(k){this.panelStack.push(k);this.$("> .controls").add(this.$list()).hide();k.parentName=this.model.get("name");this.$el.append(k.render().$el)},_collapseDrilldownPanel:function(k){this.panelStack.pop();this.render()},events:{"click .navigation .back":"close"},close:function(k){this.$el.remove();this.trigger("close")},toString:function(){return"CollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});g.prototype.templates=(function(){var k=j.wrapTemplate(['<div class="controls">','<div class="navigation">','<a class="back" href="javascript:void(0)">','<span class="fa fa-icon fa-angle-left"></span>',b("Back to "),"<%- view.parentName %>","</a>","</div>",'<div class="title">','<div class="name"><%- collection.name || collection.element_identifier %></div>','<div class="subtitle">','<% if( collection.collection_type === "list" ){ %>',b("a list of datasets"),'<% } else if( collection.collection_type === "paired" ){ %>',b("a pair of datasets"),'<% } else if( collection.collection_type === "list:paired" ){ %>',b("a list of paired datasets"),"<% } %>","</div>","</div>","</div>"],"collection");return _.extend(_.clone(h.prototype.templates),{controls:k})}());var e=g.extend({DatasetDCEViewClass:f.DatasetDCEListItemView,toString:function(){return"ListCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var i=e.extend({toString:function(){return"PairCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var c=g.extend({NestedDCDCEViewClass:f.NestedDCDCEListItemView.extend({foldoutPanelClass:i}),toString:function(){return"ListOfPairsCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{CollectionPanel:g,ListCollectionPanel:e,PairCollectionPanel:i,ListOfPairsCollectionPanel:c}});
\ No newline at end of file
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/packed/mvc/dataset/dataset-li.js
--- a/static/scripts/packed/mvc/dataset/dataset-li.js
+++ b/static/scripts/packed/mvc/dataset/dataset-li.js
@@ -1,1 +1,1 @@
-define(["mvc/list/list-item","mvc/dataset/states","mvc/base-mvc","utils/localization"],function(d,a,b,c){var f=d.ListItemView;var e=f.extend({className:f.prototype.className+" dataset",id:function(){return["dataset",this.model.get("id")].join("-")},initialize:function(g){if(g.logger){this.logger=this.model.logger=g.logger}this.log(this+".initialize:",g);f.prototype.initialize.call(this,g);this.linkTarget=g.linkTarget||"_blank";this._setUpListeners()},_setUpListeners:function(){this.on("selectable",function(g){if(g){this.$(".primary-actions").hide()}else{this.$(".primary-actions").show()}},this);this.model.on("change",function(h,g){if(this.model.changedAttributes().state&&this.model.inReadyState()&&this.expanded&&!this.model.hasDetails()){this.model.fetch()}else{this.render()}},this);this.on("all",function(g){this.log(g)},this)},_fetchModelDetails:function(){var g=this;if(g.model.inReadyState()&&!g.model.hasDetails()){return g.model.fetch({silent:true})}return jQuery.when()},remove:function(h,i){var g=this;h=h||this.fxSpeed;this.$el.fadeOut(h,function(){Backbone.View.prototype.remove.call(g);if(i){i.call(g)}})},render:function(g){return f.prototype.render.call(this,g)},_swapNewRender:function(g){f.prototype._swapNewRender.call(this,g);if(this.model.has("state")){this.$el.addClass("state-"+this.model.get("state"))}return this.$el},_renderPrimaryActions:function(){return[this._renderDisplayButton()]},_renderDisplayButton:function(){var i=this.model.get("state");if((i===a.NOT_VIEWABLE)||(i===a.DISCARDED)||(!this.model.get("accessible"))){return null}var h={target:this.linkTarget,classes:"display-btn"};if(this.model.get("purged")){h.disabled=true;h.title=c("Cannot display datasets removed from disk")}else{if(i===a.UPLOAD){h.disabled=true;h.title=c("This dataset must finish uploading before it can be viewed")}else{if(i===a.NEW){h.disabled=true;h.title=c("This dataset is not yet viewable")}else{h.title=c("View data");h.href=this.model.urls.display;var g=this;h.onclick=function(j){if(Galaxy.frame&&Galaxy.frame.active){Galaxy.frame.add({title:"Data Viewer: "+g.model.get("name"),type:"other",content:function(k){require(["mvc/data"],function(l){var m=new l.TabularDataset({id:g.model.get("id")});$.when(m.fetch()).then(function(){l.createTabularDatasetChunkedView({model:m,parent_elt:k,embedded:true,height:"100%"})})})}});j.preventDefault()}}}}}h.faIcon="fa-eye";return faIconButton(h)},_renderDetails:function(){if(this.model.get("state")===a.NOT_VIEWABLE){return $(this.templates.noAccess(this.model.toJSON(),this))}var g=f.prototype._renderDetails.call(this);g.find(".actions .left").empty().append(this._renderSecondaryActions());g.find(".summary").html(this._renderSummary()).prepend(this._renderDetailMessages());g.find(".display-applications").html(this._renderDisplayApplications());this._setUpBehaviors(g);return g},_renderSummary:function(){var g=this.model.toJSON(),h=this.templates.summaries[g.state];h=h||this.templates.summaries.unknown;return h(g,this)},_renderDetailMessages:function(){var g=this,i=$('<div class="detail-messages"></div>'),h=g.model.toJSON();_.each(g.templates.detailMessages,function(j){i.append($(j(h,g)))});return i},_renderDisplayApplications:function(){if(this.model.isDeletedOrPurged()){return""}return[this.templates.displayApplications(this.model.get("display_apps"),this),this.templates.displayApplications(this.model.get("display_types"),this)].join("")},_renderSecondaryActions:function(){this.debug("_renderSecondaryActions");switch(this.model.get("state")){case a.NOT_VIEWABLE:return[];case a.OK:case a.FAILED_METADATA:case a.ERROR:return[this._renderDownloadButton(),this._renderShowParamsButton()]}return[this._renderShowParamsButton()]},_renderShowParamsButton:function(){return faIconButton({title:c("View details"),classes:"params-btn",href:this.model.urls.show_params,target:this.linkTarget,faIcon:"fa-info-circle"})},_renderDownloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}if(!_.isEmpty(this.model.get("meta_files"))){return this._renderMetaFileDownloadButton()}return $(['<a class="download-btn icon-btn" href="',this.model.urls.download,'" title="'+c("Download")+'">','<span class="fa fa-floppy-o"></span>',"</a>"].join(""))},_renderMetaFileDownloadButton:function(){var g=this.model.urls;return $(['<div class="metafile-dropdown dropdown">','<a class="download-btn icon-btn" href="javascript:void(0)" data-toggle="dropdown"',' title="'+c("Download")+'">','<span class="fa fa-floppy-o"></span>',"</a>",'<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">','<li><a href="'+g.download+'">',c("Download dataset"),"</a></li>",_.map(this.model.get("meta_files"),function(h){return['<li><a href="',g.meta_download+h.file_type,'">',c("Download")," ",h.file_type,"</a></li>"].join("")}).join("\n"),"</ul>","</div>"].join("\n"))},toString:function(){var g=(this.model)?(this.model+""):("(no model)");return"DatasetListItemView("+g+")"}});e.prototype.templates=(function(){var i=_.extend({},f.prototype.templates.warnings,{failed_metadata:b.wrapTemplate(['<% if( model.state === "failed_metadata" ){ %>','<div class="warningmessagesmall">',c("An error occurred setting the metadata for this dataset"),"</div>","<% } %>"]),error:b.wrapTemplate(["<% if( model.error ){ %>",'<div class="errormessagesmall">',c("There was an error getting the data for this dataset"),": <%- model.error %>","</div>","<% } %>"]),purged:b.wrapTemplate(["<% if( model.purged ){ %>",'<div class="purged-msg warningmessagesmall">',c("This dataset has been deleted and removed from disk"),"</div>","<% } %>"]),deleted:b.wrapTemplate(["<% if( model.deleted && !model.purged ){ %>",'<div class="deleted-msg warningmessagesmall">',c("This dataset has been deleted"),"</div>","<% } %>"])});var j=b.wrapTemplate(['<div class="details">','<div class="summary"></div>','<div class="actions clear">','<div class="left"></div>','<div class="right"></div>',"</div>","<% if( !dataset.deleted && !dataset.purged ){ %>",'<div class="tags-display"></div>','<div class="annotation-display"></div>','<div class="display-applications"></div>',"<% if( dataset.peek ){ %>",'<pre class="dataset-peek"><%= dataset.peek %></pre>',"<% } %>","<% } %>","</div>"],"dataset");var h=b.wrapTemplate(['<div class="details">','<div class="summary">',c("You do not have permission to view this dataset"),"</div>","</div>"],"dataset");var k={};k[a.OK]=k[a.FAILED_METADATA]=b.wrapTemplate(["<% if( dataset.misc_blurb ){ %>",'<div class="blurb">','<span class="value"><%- dataset.misc_blurb %></span>',"</div>","<% } %>","<% if( dataset.file_ext ){ %>",'<div class="datatype">','<label class="prompt">',c("format"),"</label>",'<span class="value"><%- dataset.file_ext %></span>',"</div>","<% } %>","<% if( dataset.metadata_dbkey ){ %>",'<div class="dbkey">','<label class="prompt">',c("database"),"</label>",'<span class="value">',"<%- dataset.metadata_dbkey %>","</span>","</div>","<% } %>","<% if( dataset.misc_info ){ %>",'<div class="info">','<span class="value"><%- dataset.misc_info %></span>',"</div>","<% } %>"],"dataset");k[a.NEW]=b.wrapTemplate(["<div>",c("This is a new dataset and not all of its data are available yet"),"</div>"],"dataset");k[a.NOT_VIEWABLE]=b.wrapTemplate(["<div>",c("You do not have permission to view this dataset"),"</div>"],"dataset");k[a.DISCARDED]=b.wrapTemplate(["<div>",c("The job creating this dataset was cancelled before completion"),"</div>"],"dataset");k[a.QUEUED]=b.wrapTemplate(["<div>",c("This job is waiting to run"),"</div>"],"dataset");k[a.RUNNING]=b.wrapTemplate(["<div>",c("This job is currently running"),"</div>"],"dataset");k[a.UPLOAD]=b.wrapTemplate(["<div>",c("This dataset is currently uploading"),"</div>"],"dataset");k[a.SETTING_METADATA]=b.wrapTemplate(["<div>",c("Metadata is being auto-detected"),"</div>"],"dataset");k[a.PAUSED]=b.wrapTemplate(["<div>",c('This job is paused. Use the "Resume Paused Jobs" in the history menu to resume'),"</div>"],"dataset");k[a.ERROR]=b.wrapTemplate(["<% if( !dataset.purged ){ %>","<div><%- dataset.misc_blurb %></div>","<% } %>",'<span class="help-text">',c("An error occurred with this dataset"),":</span>",'<div class="job-error-text"><%- dataset.misc_info %></div>'],"dataset");k[a.EMPTY]=b.wrapTemplate(["<div>",c("No data"),": <i><%- dataset.misc_blurb %></i></div>"],"dataset");k.unknown=b.wrapTemplate(['<div>Error: unknown dataset state: "<%- dataset.state %>"</div>'],"dataset");var l={resubmitted:b.wrapTemplate(["<% if( model.resubmitted ){ %>",'<div class="resubmitted-msg infomessagesmall">',c("The job creating this dataset has been resubmitted"),"</div>","<% } %>"])};var g=b.wrapTemplate(["<% _.each( apps, function( app ){ %>",'<div class="display-application">','<span class="display-application-location"><%- app.label %></span> ','<span class="display-application-links">',"<% _.each( app.links, function( link ){ %>",'<a target="<%= link.target %>" href="<%= link.href %>">',"<% print( _l( link.text ) ); %>","</a> ","<% }); %>","</span>","</div>","<% }); %>"],"apps");return _.extend({},f.prototype.templates,{warnings:i,details:j,noAccess:h,summaries:k,detailMessages:l,displayApplications:g})}());return{DatasetListItemView:e}});
\ No newline at end of file
+define(["mvc/list/list-item","mvc/dataset/states","mvc/base-mvc","utils/localization"],function(d,a,b,c){var f=d.ListItemView;var e=f.extend({className:f.prototype.className+" dataset",id:function(){return["dataset",this.model.get("id")].join("-")},initialize:function(g){if(g.logger){this.logger=this.model.logger=g.logger}this.log(this+".initialize:",g);f.prototype.initialize.call(this,g);this.linkTarget=g.linkTarget||"_blank";this._setUpListeners()},_setUpListeners:function(){f.prototype._setUpListeners.call(this);this.model.on("change",function(h,g){if(this.model.changedAttributes().state&&this.model.inReadyState()&&this.expanded&&!this.model.hasDetails()){this.model.fetch()}else{this.render()}},this)},_fetchModelDetails:function(){var g=this;if(g.model.inReadyState()&&!g.model.hasDetails()){return g.model.fetch({silent:true})}return jQuery.when()},remove:function(h,i){var g=this;h=h||this.fxSpeed;this.$el.fadeOut(h,function(){Backbone.View.prototype.remove.call(g);if(i){i.call(g)}})},render:function(g){return f.prototype.render.call(this,g)},_swapNewRender:function(g){f.prototype._swapNewRender.call(this,g);if(this.model.has("state")){this.$el.addClass("state-"+this.model.get("state"))}return this.$el},_renderPrimaryActions:function(){return[this._renderDisplayButton()]},_renderDisplayButton:function(){var i=this.model.get("state");if((i===a.NOT_VIEWABLE)||(i===a.DISCARDED)||(!this.model.get("accessible"))){return null}var h={target:this.linkTarget,classes:"display-btn"};if(this.model.get("purged")){h.disabled=true;h.title=c("Cannot display datasets removed from disk")}else{if(i===a.UPLOAD){h.disabled=true;h.title=c("This dataset must finish uploading before it can be viewed")}else{if(i===a.NEW){h.disabled=true;h.title=c("This dataset is not yet viewable")}else{h.title=c("View data");h.href=this.model.urls.display;var g=this;h.onclick=function(j){if(Galaxy.frame&&Galaxy.frame.active){Galaxy.frame.add({title:"Data Viewer: "+g.model.get("name"),type:"other",content:function(k){require(["mvc/data"],function(l){var m=new l.TabularDataset({id:g.model.get("id")});$.when(m.fetch()).then(function(){l.createTabularDatasetChunkedView({model:m,parent_elt:k,embedded:true,height:"100%"})})})}});j.preventDefault()}}}}}h.faIcon="fa-eye";return faIconButton(h)},_renderDetails:function(){if(this.model.get("state")===a.NOT_VIEWABLE){return $(this.templates.noAccess(this.model.toJSON(),this))}var g=f.prototype._renderDetails.call(this);g.find(".actions .left").empty().append(this._renderSecondaryActions());g.find(".summary").html(this._renderSummary()).prepend(this._renderDetailMessages());g.find(".display-applications").html(this._renderDisplayApplications());this._setUpBehaviors(g);return g},_renderSummary:function(){var g=this.model.toJSON(),h=this.templates.summaries[g.state];h=h||this.templates.summaries.unknown;return h(g,this)},_renderDetailMessages:function(){var g=this,i=$('<div class="detail-messages"></div>'),h=g.model.toJSON();_.each(g.templates.detailMessages,function(j){i.append($(j(h,g)))});return i},_renderDisplayApplications:function(){if(this.model.isDeletedOrPurged()){return""}return[this.templates.displayApplications(this.model.get("display_apps"),this),this.templates.displayApplications(this.model.get("display_types"),this)].join("")},_renderSecondaryActions:function(){this.debug("_renderSecondaryActions");switch(this.model.get("state")){case a.NOT_VIEWABLE:return[];case a.OK:case a.FAILED_METADATA:case a.ERROR:return[this._renderDownloadButton(),this._renderShowParamsButton()]}return[this._renderShowParamsButton()]},_renderShowParamsButton:function(){return faIconButton({title:c("View details"),classes:"params-btn",href:this.model.urls.show_params,target:this.linkTarget,faIcon:"fa-info-circle"})},_renderDownloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}if(!_.isEmpty(this.model.get("meta_files"))){return this._renderMetaFileDownloadButton()}return $(['<a class="download-btn icon-btn" href="',this.model.urls.download,'" title="'+c("Download")+'">','<span class="fa fa-floppy-o"></span>',"</a>"].join(""))},_renderMetaFileDownloadButton:function(){var g=this.model.urls;return $(['<div class="metafile-dropdown dropdown">','<a class="download-btn icon-btn" href="javascript:void(0)" data-toggle="dropdown"',' title="'+c("Download")+'">','<span class="fa fa-floppy-o"></span>',"</a>",'<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">','<li><a href="'+g.download+'">',c("Download dataset"),"</a></li>",_.map(this.model.get("meta_files"),function(h){return['<li><a href="',g.meta_download+h.file_type,'">',c("Download")," ",h.file_type,"</a></li>"].join("")}).join("\n"),"</ul>","</div>"].join("\n"))},toString:function(){var g=(this.model)?(this.model+""):("(no model)");return"DatasetListItemView("+g+")"}});e.prototype.templates=(function(){var i=_.extend({},f.prototype.templates.warnings,{failed_metadata:b.wrapTemplate(['<% if( model.state === "failed_metadata" ){ %>','<div class="warningmessagesmall">',c("An error occurred setting the metadata for this dataset"),"</div>","<% } %>"]),error:b.wrapTemplate(["<% if( model.error ){ %>",'<div class="errormessagesmall">',c("There was an error getting the data for this dataset"),": <%- model.error %>","</div>","<% } %>"]),purged:b.wrapTemplate(["<% if( model.purged ){ %>",'<div class="purged-msg warningmessagesmall">',c("This dataset has been deleted and removed from disk"),"</div>","<% } %>"]),deleted:b.wrapTemplate(["<% if( model.deleted && !model.purged ){ %>",'<div class="deleted-msg warningmessagesmall">',c("This dataset has been deleted"),"</div>","<% } %>"])});var j=b.wrapTemplate(['<div class="details">','<div class="summary"></div>','<div class="actions clear">','<div class="left"></div>','<div class="right"></div>',"</div>","<% if( !dataset.deleted && !dataset.purged ){ %>",'<div class="tags-display"></div>','<div class="annotation-display"></div>','<div class="display-applications"></div>',"<% if( dataset.peek ){ %>",'<pre class="dataset-peek"><%= dataset.peek %></pre>',"<% } %>","<% } %>","</div>"],"dataset");var h=b.wrapTemplate(['<div class="details">','<div class="summary">',c("You do not have permission to view this dataset"),"</div>","</div>"],"dataset");var k={};k[a.OK]=k[a.FAILED_METADATA]=b.wrapTemplate(["<% if( dataset.misc_blurb ){ %>",'<div class="blurb">','<span class="value"><%- dataset.misc_blurb %></span>',"</div>","<% } %>","<% if( dataset.file_ext ){ %>",'<div class="datatype">','<label class="prompt">',c("format"),"</label>",'<span class="value"><%- dataset.file_ext %></span>',"</div>","<% } %>","<% if( dataset.metadata_dbkey ){ %>",'<div class="dbkey">','<label class="prompt">',c("database"),"</label>",'<span class="value">',"<%- dataset.metadata_dbkey %>","</span>","</div>","<% } %>","<% if( dataset.misc_info ){ %>",'<div class="info">','<span class="value"><%- dataset.misc_info %></span>',"</div>","<% } %>"],"dataset");k[a.NEW]=b.wrapTemplate(["<div>",c("This is a new dataset and not all of its data are available yet"),"</div>"],"dataset");k[a.NOT_VIEWABLE]=b.wrapTemplate(["<div>",c("You do not have permission to view this dataset"),"</div>"],"dataset");k[a.DISCARDED]=b.wrapTemplate(["<div>",c("The job creating this dataset was cancelled before completion"),"</div>"],"dataset");k[a.QUEUED]=b.wrapTemplate(["<div>",c("This job is waiting to run"),"</div>"],"dataset");k[a.RUNNING]=b.wrapTemplate(["<div>",c("This job is currently running"),"</div>"],"dataset");k[a.UPLOAD]=b.wrapTemplate(["<div>",c("This dataset is currently uploading"),"</div>"],"dataset");k[a.SETTING_METADATA]=b.wrapTemplate(["<div>",c("Metadata is being auto-detected"),"</div>"],"dataset");k[a.PAUSED]=b.wrapTemplate(["<div>",c('This job is paused. Use the "Resume Paused Jobs" in the history menu to resume'),"</div>"],"dataset");k[a.ERROR]=b.wrapTemplate(["<% if( !dataset.purged ){ %>","<div><%- dataset.misc_blurb %></div>","<% } %>",'<span class="help-text">',c("An error occurred with this dataset"),":</span>",'<div class="job-error-text"><%- dataset.misc_info %></div>'],"dataset");k[a.EMPTY]=b.wrapTemplate(["<div>",c("No data"),": <i><%- dataset.misc_blurb %></i></div>"],"dataset");k.unknown=b.wrapTemplate(['<div>Error: unknown dataset state: "<%- dataset.state %>"</div>'],"dataset");var l={resubmitted:b.wrapTemplate(["<% if( model.resubmitted ){ %>",'<div class="resubmitted-msg infomessagesmall">',c("The job creating this dataset has been resubmitted"),"</div>","<% } %>"])};var g=b.wrapTemplate(["<% _.each( apps, function( app ){ %>",'<div class="display-application">','<span class="display-application-location"><%- app.label %></span> ','<span class="display-application-links">',"<% _.each( app.links, function( link ){ %>",'<a target="<%= link.target %>" href="<%= link.href %>">',"<% print( _l( link.text ) ); %>","</a> ","<% }); %>","</span>","</div>","<% }); %>"],"apps");return _.extend({},f.prototype.templates,{warnings:i,details:j,noAccess:h,summaries:k,detailMessages:l,displayApplications:g})}());return{DatasetListItemView:e}});
\ No newline at end of file
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/packed/mvc/history/hdca-li.js
--- a/static/scripts/packed/mvc/history/hdca-li.js
+++ b/static/scripts/packed/mvc/history/hdca-li.js
@@ -1,1 +1,1 @@
-define(["mvc/dataset/states","mvc/collection/collection-li","mvc/base-mvc","utils/localization"],function(a,e,c,d){var f=e.DCListItemView;var b=f.extend({className:f.prototype.className+" history-content",_swapNewRender:function(g){f.prototype._swapNewRender.call(this,g);var h=this.model.get("state")||a.OK;this.$el.addClass("state-"+h);return this.$el},toString:function(){var g=(this.model)?(this.model+""):("(no model)");return"HDCAListItemView("+g+")"}});b.prototype.templates=(function(){var g=c.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="hid"><%- collection.hid %></span> ','<span class="name"><%- collection.name %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"collection");return _.extend({},f.prototype.templates,{titleBar:g})}());return{HDCAListItemView:b}});
\ No newline at end of file
+define(["mvc/dataset/states","mvc/collection/collection-li","mvc/collection/collection-panel","mvc/base-mvc","utils/localization"],function(a,e,g,c,d){var f=e.DCListItemView;var b=f.extend({className:f.prototype.className+" history-content",_getFoldoutPanelClass:function(){switch(this.model.get("collection_type")){case"list":return g.ListCollectionPanel;case"paired":return g.PairCollectionPanel;case"list:paired":return g.ListOfPairsCollectionPanel}throw new TypeError("Uknown collection_type: "+this.model.get("collection_type"))},_swapNewRender:function(h){f.prototype._swapNewRender.call(this,h);var i=this.model.get("state")||a.OK;this.$el.addClass("state-"+i);return this.$el},toString:function(){var h=(this.model)?(this.model+""):("(no model)");return"HDCAListItemView("+h+")"}});b.prototype.templates=(function(){var h=c.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="hid"><%- collection.hid %></span> ','<span class="name"><%- collection.name %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"collection");return _.extend({},f.prototype.templates,{titleBar:h})}());return{HDCAListItemView:b}});
\ No newline at end of file
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/packed/mvc/history/history-panel-edit-current.js
--- a/static/scripts/packed/mvc/history/history-panel-edit-current.js
+++ b/static/scripts/packed/mvc/history/history-panel-edit-current.js
@@ -1,1 +1,1 @@
-define(["mvc/history/history-model","mvc/history/history-panel-edit","mvc/collection/collection-panel","mvc/base-mvc","utils/localization"],function(d,c,a,h,b){var e=h.SessionStorageModel.extend({defaults:{tagsEditorShown:false,annotationEditorShown:false},toString:function(){return"HistoryPanelPrefs("+JSON.stringify(this.toJSON())+")"}});e.storageKey=function f(){return("history-panel")};var g=c.HistoryPanelEdit;var i=g.extend({className:g.prototype.className+" current-history-panel",emptyMsg:b("This history is empty. Click 'Get Data' on the left tool menu to start"),noneFoundMsg:b("No matching datasets found"),initialize:function(j){j=j||{};this.preferences=new e(_.extend({id:e.storageKey()},_.pick(j,_.keys(e.prototype.defaults))));g.prototype.initialize.call(this,j);this.panelStack=[]},loadCurrentHistory:function(k){this.debug(this+".loadCurrentHistory");var j=this;return this.loadHistoryWithDetails("current",k).then(function(m,l){j.trigger("current-history",j)})},switchToHistory:function(m,l){var j=this,k=function(){return jQuery.getJSON(galaxy_config.root+"history/set_as_current?id="+m)};return this.loadHistoryWithDetails(m,l,k).then(function(o,n){j.trigger("switched-history",j)})},createNewHistory:function(l){if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){this.displayMessage("error",b("You must be logged in to create histories"));return $.when()}var j=this,k=function(){return jQuery.getJSON(galaxy_config.root+"history/create_new_current")};return this.loadHistory(undefined,l,k).then(function(n,m){j.trigger("new-history",j)})},setModel:function(k,j,l){g.prototype.setModel.call(this,k,j,l);if(this.model){this.log("checking for updates");this.model.checkForUpdates()}return this},_setUpCollectionListeners:function(){g.prototype._setUpCollectionListeners.call(this);this.collection.on("state:ready",function(k,l,j){if((!k.get("visible"))&&(!this.storage.get("show_hidden"))){this.removeItemView(this.viewFromModel(k))}},this)},_setUpModelListeners:function(){g.prototype._setUpModelListeners.call(this);if(Galaxy&&Galaxy.quotaMeter){this.listenTo(this.model,"change:nice_size",function(){Galaxy.quotaMeter.update()})}},_buildNewRender:function(){if(!this.model){return $()}var j=g.prototype._buildNewRender.call(this);j.find(".search").prependTo(j.find(".controls"));this._renderQuotaMessage(j);return j},_renderQuotaMessage:function(j){j=j||this.$el;return $(this.templates.quotaMsg({},this)).prependTo(j.find(".messages"))},_renderEmptyMessage:function(l){var k=this,j=k.$emptyMessage(l),m=$(".toolMenuContainer");if((_.isEmpty(k.views)&&!k.searchFor)&&(Galaxy&&Galaxy.upload&&m.size())){j.empty();j.html([b("This history is empty"),". ",b("You can "),'<a class="uploader-link" href="javascript:void(0)">',b("load your own data"),"</a>",b(" or "),'<a class="get-data-link" href="javascript:void(0)">',b("get data from an external source"),"</a>"].join(""));j.find(".uploader-link").click(function(n){Galaxy.upload._eventShow(n)});j.find(".get-data-link").click(function(n){m.parent().scrollTop(0);m.find('span:contains("Get Data")').click()});return j.show()}return g.prototype._renderEmptyMessage.call(this,l)},_renderTags:function(j){var k=this;g.prototype._renderTags.call(this,j);if(this.preferences.get("tagsEditorShown")){this.tagsEditor.toggle(true)}this.tagsEditor.on("hiddenUntilActivated:shown hiddenUntilActivated:hidden",function(l){k.preferences.set("tagsEditorShown",l.hidden)})},_renderAnnotation:function(j){var k=this;g.prototype._renderAnnotation.call(this,j);if(this.preferences.get("annotationEditorShown")){this.annotationEditor.toggle(true)}this.annotationEditor.on("hiddenUntilActivated:shown hiddenUntilActivated:hidden",function(l){k.preferences.set("annotationEditorShown",l.hidden)})},_attachItems:function(j){this.$list(j).append(this.views.reverse().map(function(k){return k.$el}));return this},_setUpItemViewListeners:function(k){var j=this;g.prototype._setUpItemViewListeners.call(j,k);if(k instanceof j.HDCAViewClass){k.off("expanded");k.on("expanded",function(l){j.info("expanded",l);j._addCollectionPanel(l)});k.off("collapsed")}},_addCollectionPanel:function(l){var k=this,j=l.model;this.debug("history panel (stack), collectionModel:",j);var n=new (this._getCollectionPanelClass(j))({model:j,HDAViewClass:this.HDAViewClass,parentName:this.model.get("name"),linkTarget:this.linkTarget});k.panelStack.push(n);k.$(".controls").add(k.$list()).hide();k.$el.append(n.$el);n.on("close",function(){k.render();l.collapse();k.panelStack.pop()});if(!n.model.hasDetails()){var m=n.model.fetch();m.done(function(){n.render()})}else{n.render()}},_getCollectionPanelClass:function(j){switch(j.get("collection_type")){case"list":return a.ListCollectionPanel;case"paired":return a.PairCollectionPanel;case"list:paired":return a.ListOfPairsCollectionPanel}throw new TypeError("Uknown collection_type: "+j.get("collection_type"))},addItemView:function(o,p,n){this.log(this+".addItemView:",o);if(!this._filterItem(o)){return undefined}var l=this;if(this.panelStack.length){return l}var k=l._createItemView(o);this.views.unshift(k);l.scrollToTop();$({}).queue([function m(r){var q=l.$emptyMessage();if(q.is(":visible")){q.fadeOut(l.fxSpeed,r)}else{r()}},function j(q){l.scrollToTop();l.$list().prepend(k.render(0).$el.hide());k.$el.slideDown(l.fxSpeed)}]);return k},connectToQuotaMeter:function(j){if(!j){return this}this.listenTo(j,"quota:over",this.showQuotaMessage);this.listenTo(j,"quota:under",this.hideQuotaMessage);this.on("rendered rendered:initial",function(){if(j&&j.isOverQuota()){this.showQuotaMessage()}});return this},showQuotaMessage:function(){var j=this.$el.find(".quota-message");if(j.is(":hidden")){j.slideDown(this.fxSpeed)}},hideQuotaMessage:function(){var j=this.$el.find(".quota-message");if(!j.is(":hidden")){j.slideUp(this.fxSpeed)}},connectToOptionsMenu:function(j){if(!j){return this}this.on("new-storage",function(l,k){if(j&&l){j.findItemByHtml(b("Include Deleted Datasets")).checked=l.get("show_deleted");j.findItemByHtml(b("Include Hidden Datasets")).checked=l.get("show_hidden")}});return this},toString:function(){return"CurrentHistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});i.prototype.templates=(function(){var j=h.wrapTemplate(['<div class="quota-message errormessage">',b("You are over your disk quota"),". ",b("Tool execution is on hold until your disk usage drops below your allocated quota"),".","</div>"],"history");return _.extend(_.clone(g.prototype.templates),{quotaMsg:j})}());return{CurrentHistoryPanel:i}});
\ No newline at end of file
+define(["mvc/history/history-model","mvc/history/history-panel-edit","mvc/collection/collection-panel","mvc/base-mvc","utils/localization"],function(d,c,a,h,b){var e=h.SessionStorageModel.extend({defaults:{tagsEditorShown:false,annotationEditorShown:false},toString:function(){return"HistoryPanelPrefs("+JSON.stringify(this.toJSON())+")"}});e.storageKey=function f(){return("history-panel")};var g=c.HistoryPanelEdit;var i=g.extend({className:g.prototype.className+" current-history-panel",emptyMsg:b("This history is empty. Click 'Get Data' on the left tool menu to start"),noneFoundMsg:b("No matching datasets found"),HDCAViewClass:g.prototype.HDCAViewClass.extend({foldoutStyle:"drilldown"}),initialize:function(j){j=j||{};this.preferences=new e(_.extend({id:e.storageKey()},_.pick(j,_.keys(e.prototype.defaults))));g.prototype.initialize.call(this,j);this.panelStack=[]},loadCurrentHistory:function(k){this.debug(this+".loadCurrentHistory");var j=this;return this.loadHistoryWithDetails("current",k).then(function(m,l){j.trigger("current-history",j)})},switchToHistory:function(m,l){var j=this,k=function(){return jQuery.getJSON(galaxy_config.root+"history/set_as_current?id="+m)};return this.loadHistoryWithDetails(m,l,k).then(function(o,n){j.trigger("switched-history",j)})},createNewHistory:function(l){if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){this.displayMessage("error",b("You must be logged in to create histories"));return $.when()}var j=this,k=function(){return jQuery.getJSON(galaxy_config.root+"history/create_new_current")};return this.loadHistory(undefined,l,k).then(function(n,m){j.trigger("new-history",j)})},setModel:function(k,j,l){g.prototype.setModel.call(this,k,j,l);if(this.model){this.log("checking for updates");this.model.checkForUpdates()}return this},_setUpCollectionListeners:function(){g.prototype._setUpCollectionListeners.call(this);this.collection.on("state:ready",function(k,l,j){if((!k.get("visible"))&&(!this.storage.get("show_hidden"))){this.removeItemView(this.viewFromModel(k))}},this)},_setUpModelListeners:function(){g.prototype._setUpModelListeners.call(this);if(Galaxy&&Galaxy.quotaMeter){this.listenTo(this.model,"change:nice_size",function(){Galaxy.quotaMeter.update()})}},_buildNewRender:function(){if(!this.model){return $()}var j=g.prototype._buildNewRender.call(this);j.find(".search").prependTo(j.find(".controls"));this._renderQuotaMessage(j);return j},_renderQuotaMessage:function(j){j=j||this.$el;return $(this.templates.quotaMsg({},this)).prependTo(j.find(".messages"))},_renderEmptyMessage:function(l){var k=this,j=k.$emptyMessage(l),m=$(".toolMenuContainer");if((_.isEmpty(k.views)&&!k.searchFor)&&(Galaxy&&Galaxy.upload&&m.size())){j.empty();j.html([b("This history is empty"),". ",b("You can "),'<a class="uploader-link" href="javascript:void(0)">',b("load your own data"),"</a>",b(" or "),'<a class="get-data-link" href="javascript:void(0)">',b("get data from an external source"),"</a>"].join(""));j.find(".uploader-link").click(function(n){Galaxy.upload._eventShow(n)});j.find(".get-data-link").click(function(n){m.parent().scrollTop(0);m.find('span:contains("Get Data")').click()});return j.show()}return g.prototype._renderEmptyMessage.call(this,l)},_renderTags:function(j){var k=this;g.prototype._renderTags.call(this,j);if(this.preferences.get("tagsEditorShown")){this.tagsEditor.toggle(true)}this.tagsEditor.on("hiddenUntilActivated:shown hiddenUntilActivated:hidden",function(l){k.preferences.set("tagsEditorShown",l.hidden)})},_renderAnnotation:function(j){var k=this;g.prototype._renderAnnotation.call(this,j);if(this.preferences.get("annotationEditorShown")){this.annotationEditor.toggle(true)}this.annotationEditor.on("hiddenUntilActivated:shown hiddenUntilActivated:hidden",function(l){k.preferences.set("annotationEditorShown",l.hidden)})},_attachItems:function(j){this.$list(j).append(this.views.reverse().map(function(k){return k.$el}));return this},addItemView:function(o,p,n){this.log(this+".addItemView:",o);var l=this;if(!l._filterItem(o)){return undefined}if(l.panelStack.length){return this._collapseDrilldownPanel()}var k=l._createItemView(o);l.views.unshift(k);l.scrollToTop();$({}).queue([function m(r){var q=l.$emptyMessage();if(q.is(":visible")){q.fadeOut(l.fxSpeed,r)}else{r()}},function j(q){l.$list().prepend(k.render(0).$el.hide());k.$el.slideDown(l.fxSpeed)}]);return k},_setUpItemViewListeners:function(k){var j=this;g.prototype._setUpItemViewListeners.call(j,k);k.on("expanded:drilldown",function(m,l){this._expandDrilldownPanel(l)},this);k.on("collapsed:drilldown",function(m,l){this._collapseDrilldownPanel(l)},this);return this},_expandDrilldownPanel:function(j){this.panelStack.push(j);this.$("> .controls").add(this.$list()).hide();j.parentName=this.model.get("name");this.$el.append(j.render().$el)},_collapseDrilldownPanel:function(j){this.panelStack.pop();this.render()},connectToQuotaMeter:function(j){if(!j){return this}this.listenTo(j,"quota:over",this.showQuotaMessage);this.listenTo(j,"quota:under",this.hideQuotaMessage);this.on("rendered rendered:initial",function(){if(j&&j.isOverQuota()){this.showQuotaMessage()}});return this},showQuotaMessage:function(){var j=this.$el.find(".quota-message");if(j.is(":hidden")){j.slideDown(this.fxSpeed)}},hideQuotaMessage:function(){var j=this.$el.find(".quota-message");if(!j.is(":hidden")){j.slideUp(this.fxSpeed)}},connectToOptionsMenu:function(j){if(!j){return this}this.on("new-storage",function(l,k){if(j&&l){j.findItemByHtml(b("Include Deleted Datasets")).checked=l.get("show_deleted");j.findItemByHtml(b("Include Hidden Datasets")).checked=l.get("show_hidden")}});return this},toString:function(){return"CurrentHistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});i.prototype.templates=(function(){var j=h.wrapTemplate(['<div class="quota-message errormessage">',b("You are over your disk quota"),". ",b("Tool execution is on hold until your disk usage drops below your allocated quota"),".","</div>"],"history");return _.extend(_.clone(g.prototype.templates),{quotaMsg:j})}());return{CurrentHistoryPanel:i}});
\ No newline at end of file
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/packed/mvc/history/history-panel.js
--- a/static/scripts/packed/mvc/history/history-panel.js
+++ b/static/scripts/packed/mvc/history/history-panel.js
@@ -1,1 +1,1 @@
-define(["mvc/list/list-panel","mvc/history/history-model","mvc/history/history-contents","mvc/history/hda-li","mvc/history/hdca-li","mvc/user/user-model","mvc/base-mvc","utils/localization"],function(d,f,l,b,a,g,n,e){var j=n.SessionStorageModel.extend({defaults:{expandedIds:{},show_deleted:false,show_hidden:false},addExpandedHda:function(o){var p="expandedIds";this.save(p,_.extend(this.get(p),_.object([o.id],[o.get("id")])))},removeExpandedHda:function(o){var p="expandedIds";this.save(p,_.omit(this.get(p),o.id))},toString:function(){return"HistoryPrefs("+this.id+")"}});j.storageKeyPrefix="history:";j.historyStorageKey=function h(o){if(!o){throw new Error("HistoryPrefs.historyStorageKey needs valid id: "+o)}return(j.storageKeyPrefix+o)};j.get=function c(o){return new j({id:j.historyStorageKey(o)})};j.clearAll=function i(p){for(var o in sessionStorage){if(o.indexOf(j.storageKeyPrefix)===0){sessionStorage.removeItem(o)}}};var m=d.ModelListPanel;var k=m.extend({HDAViewClass:b.HDAListItemView,HDCAViewClass:a.HDCAListItemView,collectionClass:l.HistoryContents,modelCollectionKey:"contents",tagName:"div",className:m.prototype.className+" history-panel",emptyMsg:e("This history is empty"),noneFoundMsg:e("No matching datasets found"),searchPlaceholder:e("search datasets"),initialize:function(o){m.prototype.initialize.call(this,o);this.linkTarget=o.linkTarget||"_blank"},freeModel:function(){m.prototype.freeModel.call(this);if(this.model){this.model.clearUpdateTimeout()}return this},_setUpListeners:function(){m.prototype._setUpListeners.call(this);this.on("error",function(p,s,o,r,q){this.errorHandler(p,s,o,r,q)});this.on("loading-done",function(){if(!this.views.length){this.trigger("empty-history",this)}})},loadHistoryWithDetails:function(r,q,p,s){this.info("loadHistoryWithDetails:",r,q,p,s);var o=function(t){return _.values(j.get(t.id).get("expandedIds"))};return this.loadHistory(r,q,p,s,o)},loadHistory:function(s,r,q,t,o){this.info("loadHistory:",s,r,q,t,o);var p=this;r=r||{};p.trigger("loading",p);var u=f.History.getHistoryData(s,{historyFn:q,contentsFn:t,detailIdsFn:r.initiallyExpanded||o});return p._loadHistoryFromXHR(u,r).fail(function(x,v,w){p.trigger("error",p,x,r,e("An error was encountered while "+v),{historyId:s,history:w||{}})}).always(function(){p.trigger("loading-done",p)})},_loadHistoryFromXHR:function(q,p){var o=this;q.then(function(r,s){o.JSONToModel(r,s,p);o.render()});q.fail(function(s,r){o.render()});return q},JSONToModel:function(r,o,p){this.log("JSONToModel:",r,o,p);p=p||{};var q=new f.History(r,o,p);this.setModel(q);return q},setModel:function(p,o){o=o||{};m.prototype.setModel.call(this,p,o);if(this.model){this._setUpWebStorage(o.initiallyExpanded,o.show_deleted,o.show_hidden)}},_setUpWebStorage:function(p,o,q){this.storage=new j({id:j.historyStorageKey(this.model.get("id"))});if(_.isObject(p)){this.storage.set("expandedIds",p)}if(_.isBoolean(o)){this.storage.set("show_deleted",o)}if(_.isBoolean(q)){this.storage.set("show_hidden",q)}this.trigger("new-storage",this.storage,this);this.log(this+" (init'd) storage:",this.storage.get());return this},_buildNewRender:function(){var o=m.prototype._buildNewRender.call(this);if(this.multiselectActions.length){o.find(".controls .actions").prepend(this._renderSelectButton())}return o},_renderSelectButton:function(o){return faIconButton({title:e("Operations on multiple datasets"),classes:"show-selectors-btn",faIcon:"fa-check-square-o"})},_getItemViewClass:function(o){var p=o.get("history_content_type");switch(p){case"dataset":return this.HDAViewClass;case"dataset_collection":return this.HDCAViewClass}throw new TypeError("Unknown history_content_type: "+p)},_filterItem:function(p){var o=this;return(m.prototype._filterItem.call(o,p)&&(!p.hidden()||o.storage.get("show_hidden"))&&(!p.isDeletedOrPurged()||o.storage.get("show_deleted")))},_getItemViewOptions:function(p){var o=m.prototype._getItemViewOptions.call(this,p);return _.extend(o,{linkTarget:this.linkTarget,expanded:!!this.storage.get("expandedIds")[p.id],hasUser:this.model.ownedByCurrUser()})},_setUpItemViewListeners:function(p){var o=this;m.prototype._setUpItemViewListeners.call(o,p);p.on("expanded",function(q){o.storage.addExpandedHda(q.model)});p.on("collapsed",function(q){o.storage.removeExpandedHda(q.model)});return this},refreshContents:function(p,o){if(this.model){return this.model.refresh(p,o)}return $.when()},getSelectedModels:function(){var o=m.prototype.getSelectedModels.call(this);o.historyId=this.collection.historyId;return o},events:_.extend(_.clone(m.prototype.events),{"click .show-selectors-btn":"toggleSelectors"}),toggleShowDeleted:function(o){o=(o!==undefined)?(o):(!this.storage.get("show_deleted"));this.storage.set("show_deleted",o);this.renderItems();return this.storage.get("show_deleted")},toggleShowHidden:function(o){o=(o!==undefined)?(o):(!this.storage.get("show_hidden"));this.storage.set("show_hidden",o);this.renderItems();return this.storage.get("show_hidden")},_firstSearch:function(o){var p=this,q=".history-search-input";this.log("onFirstSearch",o);if(p.model.contents.haveDetails()){p.searchItems(o);return}p.$el.find(q).searchInput("toggle-loading");p.model.contents.fetchAllDetails({silent:true}).always(function(){p.$el.find(q).searchInput("toggle-loading")}).done(function(){p.searchItems(o)})},errorHandler:function(q,t,p,s,r){this.error(q,t,p,s,r);if(t&&t.status===0&&t.readyState===0){}else{if(t&&t.status===502){}else{var o=this._parseErrorMessage(q,t,p,s,r);if(!this.$messages().is(":visible")){this.once("rendered",function(){this.displayMessage("error",o.message,o.details)})}else{this.displayMessage("error",o.message,o.details)}}}},_parseErrorMessage:function(s,v,w,q,o,t){var r=Galaxy.currUser,u={message:this._bePolite(q),details:{message:q,raven:(window.Raven&&_.isFunction(Raven.lastEventId))?(Raven.lastEventId()):(undefined),agent:navigator.userAgent,url:(window.Galaxy)?(Galaxy.lastAjax.url):(undefined),data:(window.Galaxy)?(Galaxy.lastAjax.data):(undefined),options:(v)?(_.omit(w,"xhr")):(w),xhr:v,source:(_.isFunction(s.toJSON))?(s.toJSON()):(s+""),user:(r instanceof g.User)?(r.toJSON()):(r+"")}};_.extend(u.details,o||{});if(v&&_.isFunction(v.getAllResponseHeaders)){var p=v.getAllResponseHeaders();p=_.compact(p.split("\n"));p=_.map(p,function(x){return x.split(": ")});u.details.xhr.responseHeaders=_.object(p)}return u},_bePolite:function(o){o=o||e("An error occurred while getting updates from the server");return o+". "+e("Please contact a Galaxy administrator if the problem persists")+"."},displayMessage:function(t,u,s){var q=this;this.scrollToTop();var r=this.$messages(),o=$("<div/>").addClass(t+"message").html(u);if(!_.isEmpty(s)){var p=$('<a href="javascript:void(0)">Details</a>').click(function(){Galaxy.modal.show(q._messageToModalOptions(t,u,s));return false});o.append(" ",p)}return r.html(o)},_messageToModalOptions:function(r,u,q){var o=this,p={title:"Details"};if(_.isObject(q)){q=_.omit(q,_.functions(q));var t=JSON.stringify(q,null," "),s=$("<pre/>").text(t);p.body=$("<div/>").append(s)}else{p.body=$("<div/>").html(q)}p.buttons={Ok:function(){Galaxy.modal.hide();o.clearMessages()}};return p},clearMessages:function(o){$(o.currentTarget).fadeOut(this.fxSpeed,function(){$(this).remove()});return this},scrollToHid:function(o){return this.scrollToItem(_.first(this.viewsWhereModel({hid:o})))},toString:function(){return"HistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});k.prototype.templates=(function(){var o=n.wrapTemplate(['<div class="controls">','<div class="title">','<div class="name"><%= history.name %></div>',"</div>",'<div class="subtitle">',"</div>",'<div class="history-size"><%= history.nice_size %></div>','<div class="actions"></div>','<div class="messages">',"<% if( history.deleted ){ %>",'<div class="deleted-msg warningmessagesmall">',e("This history has been deleted"),"</div>","<% } %>","<% if( history.message ){ %>",'<div class="<%= history.message.level || "info" %>messagesmall">',"<%= history.message.text %>","</div>","<% } %>","</div>",'<div class="tags-display"></div>','<div class="annotation-display"></div>','<div class="search">','<div class="search-input"></div>',"</div>",'<div class="list-actions">','<div class="btn-group">','<button class="select-all btn btn-default"','data-mode="select">',e("All"),"</button>",'<button class="deselect-all btn btn-default"','data-mode="select">',e("None"),"</button>","</div>",'<button class="list-action-popup-btn btn btn-default">',e("For all selected"),"...</button>","</div>","</div>"],"history");return _.extend(_.clone(m.prototype.templates),{controls:o})}());return{HistoryPanel:k}});
\ No newline at end of file
+define(["mvc/list/list-panel","mvc/history/history-model","mvc/history/history-contents","mvc/history/hda-li","mvc/history/hdca-li","mvc/collection/collection-panel","mvc/user/user-model","mvc/base-mvc","utils/localization"],function(d,f,l,b,a,m,g,o,e){var j=o.SessionStorageModel.extend({defaults:{expandedIds:{},show_deleted:false,show_hidden:false},addExpanded:function(p){var q="expandedIds";this.save(q,_.extend(this.get(q),_.object([p.id],[p.get("id")])))},removeExpanded:function(p){var q="expandedIds";this.save(q,_.omit(this.get(q),p.id))},toString:function(){return"HistoryPrefs("+this.id+")"}});j.storageKeyPrefix="history:";j.historyStorageKey=function h(p){if(!p){throw new Error("HistoryPrefs.historyStorageKey needs valid id: "+p)}return(j.storageKeyPrefix+p)};j.get=function c(p){return new j({id:j.historyStorageKey(p)})};j.clearAll=function i(q){for(var p in sessionStorage){if(p.indexOf(j.storageKeyPrefix)===0){sessionStorage.removeItem(p)}}};var n=d.ModelListPanel;var k=n.extend({HDAViewClass:b.HDAListItemView,HDCAViewClass:a.HDCAListItemView,collectionClass:l.HistoryContents,modelCollectionKey:"contents",tagName:"div",className:n.prototype.className+" history-panel",emptyMsg:e("This history is empty"),noneFoundMsg:e("No matching datasets found"),searchPlaceholder:e("search datasets"),initialize:function(p){n.prototype.initialize.call(this,p);this.linkTarget=p.linkTarget||"_blank"},freeModel:function(){n.prototype.freeModel.call(this);if(this.model){this.model.clearUpdateTimeout()}return this},_setUpListeners:function(){n.prototype._setUpListeners.call(this);this.on("error",function(q,t,p,s,r){this.errorHandler(q,t,p,s,r)});this.on("loading-done",function(){if(!this.views.length){this.trigger("empty-history",this)}})},loadHistoryWithDetails:function(s,r,q,t){this.info("loadHistoryWithDetails:",s,r,q,t);var p=function(u){return _.values(j.get(u.id).get("expandedIds"))};return this.loadHistory(s,r,q,t,p)},loadHistory:function(t,s,r,u,p){this.info("loadHistory:",t,s,r,u,p);var q=this;s=s||{};q.trigger("loading",q);var v=f.History.getHistoryData(t,{historyFn:r,contentsFn:u,detailIdsFn:s.initiallyExpanded||p});return q._loadHistoryFromXHR(v,s).fail(function(y,w,x){q.trigger("error",q,y,s,e("An error was encountered while "+w),{historyId:t,history:x||{}})}).always(function(){q.trigger("loading-done",q)})},_loadHistoryFromXHR:function(r,q){var p=this;r.then(function(s,t){p.JSONToModel(s,t,q);p.render()});r.fail(function(t,s){p.render()});return r},refreshContents:function(q,p){if(this.model){return this.model.refresh(q,p)}return $.when()},JSONToModel:function(s,p,q){this.log("JSONToModel:",s,p,q);q=q||{};var r=new f.History(s,p,q);this.setModel(r);return r},setModel:function(q,p){p=p||{};n.prototype.setModel.call(this,q,p);if(this.model){this._setUpWebStorage(p.initiallyExpanded,p.show_deleted,p.show_hidden)}},_setUpWebStorage:function(q,p,r){this.storage=new j({id:j.historyStorageKey(this.model.get("id"))});if(_.isObject(q)){this.storage.set("expandedIds",q)}if(_.isBoolean(p)){this.storage.set("show_deleted",p)}if(_.isBoolean(r)){this.storage.set("show_hidden",r)}this.trigger("new-storage",this.storage,this);this.log(this+" (init'd) storage:",this.storage.get());return this},_buildNewRender:function(){var p=n.prototype._buildNewRender.call(this);if(this.multiselectActions.length){p.find(".controls .actions").prepend(this._renderSelectButton())}return p},_renderSelectButton:function(p){return faIconButton({title:e("Operations on multiple datasets"),classes:"show-selectors-btn",faIcon:"fa-check-square-o"})},_getItemViewClass:function(p){var q=p.get("history_content_type");switch(q){case"dataset":return this.HDAViewClass;case"dataset_collection":return this.HDCAViewClass}throw new TypeError("Unknown history_content_type: "+q)},_filterItem:function(q){var p=this;return(n.prototype._filterItem.call(p,q)&&(!q.hidden()||p.storage.get("show_hidden"))&&(!q.isDeletedOrPurged()||p.storage.get("show_deleted")))},_getItemViewOptions:function(q){var p=n.prototype._getItemViewOptions.call(this,q);return _.extend(p,{linkTarget:this.linkTarget,expanded:!!this.storage.get("expandedIds")[q.id],hasUser:this.model.ownedByCurrUser()})},_setUpItemViewListeners:function(q){var p=this;n.prototype._setUpItemViewListeners.call(p,q);q.on("expanded",function(r){p.storage.addExpanded(r.model)});q.on("collapsed",function(r){p.storage.removeExpanded(r.model)});return this},getSelectedModels:function(){var p=n.prototype.getSelectedModels.call(this);p.historyId=this.collection.historyId;return p},events:_.extend(_.clone(n.prototype.events),{"click .show-selectors-btn":"toggleSelectors"}),toggleShowDeleted:function(p){p=(p!==undefined)?(p):(!this.storage.get("show_deleted"));this.storage.set("show_deleted",p);this.renderItems();return this.storage.get("show_deleted")},toggleShowHidden:function(p){p=(p!==undefined)?(p):(!this.storage.get("show_hidden"));this.storage.set("show_hidden",p);this.renderItems();return this.storage.get("show_hidden")},_firstSearch:function(p){var q=this,r=".history-search-input";this.log("onFirstSearch",p);if(q.model.contents.haveDetails()){q.searchItems(p);return}q.$el.find(r).searchInput("toggle-loading");q.model.contents.fetchAllDetails({silent:true}).always(function(){q.$el.find(r).searchInput("toggle-loading")}).done(function(){q.searchItems(p)})},errorHandler:function(r,u,q,t,s){this.error(r,u,q,t,s);if(u&&u.status===0&&u.readyState===0){}else{if(u&&u.status===502){}else{var p=this._parseErrorMessage(r,u,q,t,s);if(!this.$messages().is(":visible")){this.once("rendered",function(){this.displayMessage("error",p.message,p.details)})}else{this.displayMessage("error",p.message,p.details)}}}},_parseErrorMessage:function(t,w,x,r,p,u){var s=Galaxy.currUser,v={message:this._bePolite(r),details:{message:r,raven:(window.Raven&&_.isFunction(Raven.lastEventId))?(Raven.lastEventId()):(undefined),agent:navigator.userAgent,url:(window.Galaxy)?(Galaxy.lastAjax.url):(undefined),data:(window.Galaxy)?(Galaxy.lastAjax.data):(undefined),options:(w)?(_.omit(x,"xhr")):(x),xhr:w,source:(_.isFunction(t.toJSON))?(t.toJSON()):(t+""),user:(s instanceof g.User)?(s.toJSON()):(s+"")}};_.extend(v.details,p||{});if(w&&_.isFunction(w.getAllResponseHeaders)){var q=w.getAllResponseHeaders();q=_.compact(q.split("\n"));q=_.map(q,function(y){return y.split(": ")});v.details.xhr.responseHeaders=_.object(q)}return v},_bePolite:function(p){p=p||e("An error occurred while getting updates from the server");return p+". "+e("Please contact a Galaxy administrator if the problem persists")+"."},displayMessage:function(u,v,t){var r=this;this.scrollToTop();var s=this.$messages(),p=$("<div/>").addClass(u+"message").html(v);if(!_.isEmpty(t)){var q=$('<a href="javascript:void(0)">Details</a>').click(function(){Galaxy.modal.show(r._messageToModalOptions(u,v,t));return false});p.append(" ",q)}return s.html(p)},_messageToModalOptions:function(s,v,r){var p=this,q={title:"Details"};if(_.isObject(r)){r=_.omit(r,_.functions(r));var u=JSON.stringify(r,null," "),t=$("<pre/>").text(u);q.body=$("<div/>").append(t)}else{q.body=$("<div/>").html(r)}q.buttons={Ok:function(){Galaxy.modal.hide();p.clearMessages()}};return q},clearMessages:function(p){$(p.currentTarget).fadeOut(this.fxSpeed,function(){$(this).remove()});return this},scrollToHid:function(p){return this.scrollToItem(_.first(this.viewsWhereModel({hid:p})))},toString:function(){return"HistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});k.prototype.templates=(function(){var p=o.wrapTemplate(['<div class="controls">','<div class="title">','<div class="name"><%= history.name %></div>',"</div>",'<div class="subtitle">',"</div>",'<div class="history-size"><%= history.nice_size %></div>','<div class="actions"></div>','<div class="messages">',"<% if( history.deleted ){ %>",'<div class="deleted-msg warningmessagesmall">',e("This history has been deleted"),"</div>","<% } %>","<% if( history.message ){ %>",'<div class="<%= history.message.level || "info" %>messagesmall">',"<%= history.message.text %>","</div>","<% } %>","</div>",'<div class="tags-display"></div>','<div class="annotation-display"></div>','<div class="search">','<div class="search-input"></div>',"</div>",'<div class="list-actions">','<div class="btn-group">','<button class="select-all btn btn-default"','data-mode="select">',e("All"),"</button>",'<button class="deselect-all btn btn-default"','data-mode="select">',e("None"),"</button>","</div>",'<button class="list-action-popup-btn btn btn-default">',e("For all selected"),"...</button>","</div>","</div>"],"history");return _.extend(_.clone(n.prototype.templates),{controls:p})}());return{HistoryPanel:k}});
\ No newline at end of file
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/packed/mvc/list/list-item.js
--- a/static/scripts/packed/mvc/list/list-item.js
+++ b/static/scripts/packed/mvc/list/list-item.js
@@ -1,1 +1,1 @@
-define(["mvc/base-mvc","utils/localization"],function(b,c){var d=Backbone.View.extend(b.LoggableMixin).extend({initialize:function(e){this.expanded=e.expanded||false;this.fxSpeed=e.fxSpeed||this.fxSpeed},fxSpeed:"fast",render:function(f){var e=this._buildNewRender();this._setUpBehaviors(e);this._queueNewRender(e,f);return this},_buildNewRender:function(){var e=$(this.templates.el(this.model.toJSON(),this));if(this.expanded){this.$details(e).replaceWith(this._renderDetails().show())}return e},_queueNewRender:function(f,g){g=(g===undefined)?(this.fxSpeed):(g);var e=this;$(e).queue("fx",[function(h){this.$el.fadeOut(g,h)},function(h){e._swapNewRender(f);h()},function(h){this.$el.fadeIn(g,h)},function(h){this.trigger("rendered",e);h()}])},_swapNewRender:function(e){return this.$el.empty().attr("class",this.className).append(e.children())},_setUpBehaviors:function(e){e=e||this.$el;e.find("[title]").tooltip({placement:"bottom"})},$details:function(e){e=e||this.$el;return e.find(".details")},_renderDetails:function(){var e=$(this.templates.details(this.model.toJSON(),this));this._setUpBehaviors(e);return e},toggleExpanded:function(e){e=(e===undefined)?(!this.expanded):(e);if(e){this.expand()}else{this.collapse()}return this},expand:function(){var e=this;return e._fetchModelDetails().always(function(){var f=e._renderDetails();e.$details().replaceWith(f);e.expanded=true;f.slideDown(e.fxSpeed,function(){e.trigger("expanded",e)})})},_fetchModelDetails:function(){if(!this.model.hasDetails()){return this.model.fetch()}return jQuery.when()},collapse:function(){var e=this;e.expanded=false;this.$details().slideUp(e.fxSpeed,function(){e.trigger("collapsed",e)})}});var a=d.extend(b.mixin(b.SelectableViewMixin,b.DraggableViewMixin,{tagName:"div",className:"list-item",initialize:function(e){d.prototype.initialize.call(this,e);b.SelectableViewMixin.initialize.call(this,e);b.DraggableViewMixin.initialize.call(this,e)},_buildNewRender:function(){var e=d.prototype._buildNewRender.call(this);e.find(".warnings").replaceWith(this._renderWarnings());e.find(".title-bar").replaceWith(this._renderTitleBar());e.find(".primary-actions").append(this._renderPrimaryActions());e.find(".subtitle").replaceWith(this._renderSubtitle());return e},_swapNewRender:function(e){d.prototype._swapNewRender.call(this,e);if(this.selectable){this.showSelector(0)}if(this.draggable){this.draggableOn()}return this.$el},_renderWarnings:function(){var e=this,g=$('<div class="warnings"></div>'),f=e.model.toJSON();_.each(e.templates.warnings,function(h){g.append($(h(f,e)))});return g},_renderTitleBar:function(){return $(this.templates.titleBar(this.model.toJSON(),this))},_renderPrimaryActions:function(){return[]},_renderSubtitle:function(){return $(this.templates.subtitle(this.model.toJSON(),this))},events:{"click .title-bar":"_clickTitleBar","keydown .title-bar":"_keyDownTitleBar","click .selector":"toggleSelect"},_clickTitleBar:function(e){e.stopPropagation();this.toggleExpanded()},_keyDownTitleBar:function(g){var e=32,f=13;if(g&&(g.type==="keydown")&&(g.keyCode===e||g.keyCode===f)){this.toggleExpanded();g.stopPropagation();return false}return true},toString:function(){var e=(this.model)?(this.model+""):("(no model)");return"ListItemView("+e+")"}}));a.prototype.templates=(function(){var g=b.wrapTemplate(['<div class="list-element">','<div class="warnings"></div>','<div class="selector">','<span class="fa fa-2x fa-square-o"></span>',"</div>",'<div class="primary-actions"></div>','<div class="title-bar"></div>','<div class="details"></div>',"</div>"]);var e={};var h=b.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="name"><%- element.name %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"element");var i=b.wrapTemplate(['<div class="subtitle"></div>']);var f=b.wrapTemplate(['<div class="details"></div>']);return{el:g,warnings:e,titleBar:h,subtitle:i,details:f}}());return{ExpandableView:d,ListItemView:a}});
\ No newline at end of file
+define(["mvc/base-mvc","utils/localization"],function(b,d){var e=Backbone.View.extend(b.LoggableMixin).extend({initialize:function(f){this.expanded=f.expanded||false;this.fxSpeed=f.fxSpeed||this.fxSpeed},fxSpeed:"fast",render:function(g){var f=this._buildNewRender();this._setUpBehaviors(f);this._queueNewRender(f,g);return this},_buildNewRender:function(){var f=$(this.templates.el(this.model.toJSON(),this));if(this.expanded){this.$details(f).replaceWith(this._renderDetails().show())}return f},_queueNewRender:function(g,h){h=(h===undefined)?(this.fxSpeed):(h);var f=this;$(f).queue("fx",[function(i){this.$el.fadeOut(h,i)},function(i){f._swapNewRender(g);i()},function(i){this.$el.fadeIn(h,i)},function(i){this.trigger("rendered",f);i()}])},_swapNewRender:function(f){return this.$el.empty().attr("class",this.className).append(f.children())},_setUpBehaviors:function(f){f=f||this.$el;f.find("[title]").tooltip({placement:"bottom"})},$details:function(f){f=f||this.$el;return f.find("> .details")},_renderDetails:function(){var f=$(this.templates.details(this.model.toJSON(),this));this._setUpBehaviors(f);return f},toggleExpanded:function(f){f=(f===undefined)?(!this.expanded):(f);if(f){this.expand()}else{this.collapse()}return this},expand:function(){var f=this;return f._fetchModelDetails().always(function(){var g=f._renderDetails();f.$details().replaceWith(g);f.expanded=true;f.$details().slideDown(f.fxSpeed,function(){f.trigger("expanded",f)})})},_fetchModelDetails:function(){if(!this.model.hasDetails()){return this.model.fetch()}return jQuery.when()},collapse:function(){this.debug(this+"(ExpandableView).collapse");var f=this;f.expanded=false;this.$details().slideUp(f.fxSpeed,function(){f.trigger("collapsed",f)})}});var a=e.extend(b.mixin(b.SelectableViewMixin,b.DraggableViewMixin,{tagName:"div",className:"list-item",initialize:function(f){e.prototype.initialize.call(this,f);b.SelectableViewMixin.initialize.call(this,f);b.DraggableViewMixin.initialize.call(this,f);this._setUpListeners()},_setUpListeners:function(){this.on("selectable",function(f){if(f){this.$(".primary-actions").hide()}else{this.$(".primary-actions").show()}},this);return this},_buildNewRender:function(){var f=e.prototype._buildNewRender.call(this);f.children(".warnings").replaceWith(this._renderWarnings());f.children(".title-bar").replaceWith(this._renderTitleBar());f.children(".primary-actions").append(this._renderPrimaryActions());f.find(".title-bar .subtitle").replaceWith(this._renderSubtitle());return f},_swapNewRender:function(f){e.prototype._swapNewRender.call(this,f);if(this.selectable){this.showSelector(0)}if(this.draggable){this.draggableOn()}return this.$el},_renderWarnings:function(){var f=this,h=$('<div class="warnings"></div>'),g=f.model.toJSON();_.each(f.templates.warnings,function(i){h.append($(i(g,f)))});return h},_renderTitleBar:function(){return $(this.templates.titleBar(this.model.toJSON(),this))},_renderPrimaryActions:function(){return[]},_renderSubtitle:function(){return $(this.templates.subtitle(this.model.toJSON(),this))},events:{"click .title-bar":"_clickTitleBar","keydown .title-bar":"_keyDownTitleBar","click .selector":"toggleSelect"},_clickTitleBar:function(f){f.stopPropagation();this.toggleExpanded()},_keyDownTitleBar:function(h){var f=32,g=13;if(h&&(h.type==="keydown")&&(h.keyCode===f||h.keyCode===g)){this.toggleExpanded();h.stopPropagation();return false}return true},toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"ListItemView("+f+")"}}));a.prototype.templates=(function(){var h=b.wrapTemplate(['<div class="list-element">','<div class="warnings"></div>','<div class="selector">','<span class="fa fa-2x fa-square-o"></span>',"</div>",'<div class="primary-actions"></div>','<div class="title-bar"></div>','<div class="details"></div>',"</div>"]);var f={};var i=b.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="name"><%- element.name %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"element");var j=b.wrapTemplate(['<div class="subtitle"></div>']);var g=b.wrapTemplate(['<div class="details"></div>']);return{el:h,warnings:f,titleBar:i,subtitle:j,details:g}}());var c=a.extend({foldoutStyle:"foldout",foldoutPanelClass:null,initialize:function(f){a.prototype.initialize.call(this,f);if(this.foldoutStyle==="drilldown"){this.expanded=false}this.foldoutStyle=f.foldoutStyle||this.foldoutStyle;this.foldoutPanelClass=f.foldoutPanelClass||this.foldoutPanelClass},$:function(f){var g=a.prototype.$.call(this,f);return g},_renderDetails:function(){if(this.foldoutStyle==="drilldown"){return $()}var f=a.prototype._renderDetails.call(this);return this._attachFoldout(this._createFoldoutPanel(),f)},_createFoldoutPanel:function(){var h=this.model;var i=this._getFoldoutPanelClass(h),g=this._getFoldoutPanelOptions(h),f=new i(_.extend(g,{model:h}));return f},_getFoldoutPanelClass:function(){return this.foldoutPanelClass},_getFoldoutPanelOptions:function(){return{foldoutStyle:this.foldoutStyle}},_attachFoldout:function(f,g){g=g||this.$("> .details");this.foldout=f.render(0);f.$("> .controls").hide();return g.append(f.$el)},expand:function(){var f=this;return f._fetchModelDetails().always(function(){if(f.foldoutStyle==="foldout"){f._expandByFoldout()}else{if(f.foldoutStyle==="drilldown"){f._expandByDrilldown()}}})},_expandByFoldout:function(){var f=this;var g=f._renderDetails();f.$details().replaceWith(g);f.expanded=true;f.$details().slideDown(f.fxSpeed,function(){f.trigger("expanded",f)})},_expandByDrilldown:function(){var f=this;f.foldout=this._createFoldoutPanel();f.foldout.on("close",function(){f.trigger("collapsed:drilldown",f,f.foldout)});f.trigger("expanded:drilldown",f,f.foldout)}});c.prototype.templates=(function(){var f=b.wrapTemplate(['<div class="details">',"</div>"],"collection");return _.extend({},a.prototype.templates,{details:f})}());return{ExpandableView:e,ListItemView:a,FoldoutListItemView:c}});
\ No newline at end of file
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/packed/mvc/list/list-panel.js
--- a/static/scripts/packed/mvc/list/list-panel.js
+++ b/static/scripts/packed/mvc/list/list-panel.js
@@ -1,1 +1,1 @@
-define(["mvc/list/list-item","mvc/base-mvc","utils/localization"],function(d,b,c){var e=Backbone.View.extend(b.LoggableMixin).extend({viewClass:d.ListItemView,collectionClass:Backbone.Collection,tagName:"div",className:"list-panel",fxSpeed:"fast",emptyMsg:c("This list is empty"),noneFoundMsg:c("No matching items found"),searchPlaceholder:c("search"),multiselectActions:[],initialize:function(f,g){f=f||{};if(f.logger){this.logger=f.logger}this.log(this+".initialize:",f);this.fxSpeed=_.has(f,"fxSpeed")?(f.fxSpeed):(this.fxSpeed);this.filters=[];this.searchFor=f.searchFor||"";this.indicator=new LoadingIndicator(this.$el);this.selecting=(f.selecting!==undefined)?f.selecting:true;this.selected=f.selected||[];this.lastSelected=null;this.viewClass=f.viewClass||this.viewClass;this.views=[];this.collection=f.collection||(new this.collectionClass([]));this.filters=f.filters||[];this.$scrollContainer=f.$scrollContainer||this.$scrollContainer;this.title=f.title||"";this.subtitle=f.subtitle||"";this.multiselectActions=f.multiselectActions||this.multiselectActions;this.actionsPopup=null;this._setUpListeners()},freeViews:function(){_.each(this.views,function(f){f.off()});this.views=[];return this},_setUpListeners:function(){this.off();this.on("error",function(g,j,f,i,h){console.error(g,j,f,i,h)},this);this.on("loading",function(){this._showLoadingIndicator("loading...",40)},this);this.on("loading-done",function(){this._hideLoadingIndicator(40)},this);this.once("rendered",function(){this.trigger("rendered:initial",this)},this);if(this.logger){this.on("all",function(f){this.log(this+"",arguments)},this)}this._setUpCollectionListeners();this._setUpViewListeners();return this},_setUpCollectionListeners:function(){this.log(this+"._setUpCollectionListeners",this.collection);this.collection.off();this.collection.on("error",function(g,j,f,i,h){this.trigger("error",g,j,f,i,h)},this);this.collection.on("reset",function(){this.renderItems()},this);this.collection.on("add",this.addItemView,this);this.collection.on("remove",this.removeItemView,this);if(this.logger){this.collection.on("all",function(f){this.info(this+"(collection)",arguments)},this)}return this},_setUpViewListeners:function(){this.log(this+"._setUpViewListeners");this.on("view:selected",function(f,g){if(g&&g.shiftKey&&this.lastSelected){var h=_.find(this.views,function(i){return i.model.id===this.lastSelected});if(h){this.selectRange(f,h)}}this.selected.push(f.model.id);this.lastSelected=f.model.id},this);this.on("view:de-selected",function(f,g){this.selected=_.without(this.selected,f.model.id)},this)},render:function(g){this.log(this+".render",g);var f=this._buildNewRender();this._setUpBehaviors(f);this._queueNewRender(f,g);return this},_buildNewRender:function(){this.debug(this+"(ListPanel)._buildNewRender");var f=$(this.templates.el({},this));this._renderControls(f);this._renderTitle(f);this._renderSubtitle(f);this._renderSearch(f);this.renderItems(f);return f},_renderControls:function(g){this.debug(this+"(ListPanel)._renderControls");var f=$(this.templates.controls({},this));g.find(".controls").replaceWith(f);return f},_renderTitle:function(f){},_renderSubtitle:function(f){},_queueNewRender:function(g,h){h=(h===undefined)?(this.fxSpeed):(h);var f=this;f.log("_queueNewRender:",g,h);$(f).queue("fx",[function(i){this.$el.fadeOut(h,i)},function(i){f._swapNewRender(g);i()},function(i){this.$el.fadeIn(h,i)},function(i){f.trigger("rendered",f);i()}])},_swapNewRender:function(f){this.$el.empty().attr("class",this.className).append(f.children());if(this.selecting){this.showSelectors(0)}return this},_setUpBehaviors:function(f){f=f||this.$el;f.find(".controls [title]").tooltip({placement:"bottom"});return this},$scrollContainer:function(){return this.$el.parent().parent()},$list:function(f){return(f||this.$el).find(".list-items")},$messages:function(f){return(f||this.$el).find(".messages")},$emptyMessage:function(f){return(f||this.$el).find(".empty-message")},renderItems:function(h){h=h||this.$el;var f=this;f.log(this+".renderItems",h);var g=f.$list(h);f.views=f._filterCollection().map(function(i){return f._createItemView(i).render(0)});g.empty();if(f.views.length){f._attachItems(h);f.$emptyMessage(h).hide()}else{f._renderEmptyMessage(h).show()}return f.views},_filterCollection:function(){var f=this;return f.collection.filter(_.bind(f._filterItem,f))},_filterItem:function(g){var f=this;return(_.every(f.filters.map(function(h){return h.call(g)})))&&(!f.searchFor||g.matchesAll(f.searchFor))},_createItemView:function(h){var i=this._getItemViewClass(h),g=_.extend(this._getItemViewOptions(h),{model:h}),f=new i(g);this._setUpItemViewListeners(f);return f},_getItemViewClass:function(f){return this.viewClass},_getItemViewOptions:function(f){return{fxSpeed:this.fxSpeed,expanded:false,selectable:this.selecting,selected:_.contains(this.selected,f.id),draggable:this.dragging}},_setUpItemViewListeners:function(g){var f=this;g.on("all",function(){var h=Array.prototype.slice.call(arguments,0);h[0]="view:"+h[0];f.trigger.apply(f,h)});return f},_attachItems:function(f){this.$list(f).append(this.views.map(function(g){return g.$el}));return this},_renderEmptyMessage:function(f){this.debug("_renderEmptyMessage",f,this.searchFor);var g=this.searchFor?this.noneFoundMsg:this.emptyMsg;return this.$emptyMessage(f).text(g)},expandAll:function(){_.each(this.views,function(f){f.expand()})},collapseAll:function(){_.each(this.views,function(f){f.collapse()})},addItemView:function(i,j,h){this.log(this+".addItemView:",i);var g=this;if(!g._filterItem(i)){return undefined}var f=g._createItemView(i);g.views.push(f);$(f).queue("fx",[function(k){g.$emptyMessage().fadeOut(g.fxSpeed,k)},function(k){g.$list().append(f.render().$el);k()}]);return f},removeItemView:function(i,j,h){this.log(this+".removeItemView:",i);var g=this,f=g.viewFromModel(i);if(!f){return undefined}$({}).queue("fx",[function(k){f.$el.fadeOut(g.fxSpeed,k)},function(k){g.views=_.without(g.views,f);f.remove();if(!g.views.length){g._renderEmptyMessage().fadeIn(g.fxSpeed,k)}else{k()}}]);return f},viewFromModel:function(g){for(var h=0;h<this.views.length;h++){var f=this.views[h];if(f.model===g){return f}}return undefined},viewFromModelId:function(g){for(var f=0;f<this.views.length;f++){if(this.views[f].model.id===g){return this.views[f]}}return undefined},viewsWhereModel:function(f){return this.views.filter(function(g){var i=g.model.toJSON();for(var h in f){if(f.hasOwnProperty(h)){if(i[h]!==g.model.get(h)){return false}}}return true})},viewRange:function(i,h){if(i===h){return(i)?([i]):([])}var g=this.views.indexOf(i),f=this.views.indexOf(h);if(g===-1||f===-1){if(g===f){return[]}return(g===-1)?([h]):([i])}return(g<f)?this.views.slice(g,f+1):this.views.slice(f,g+1)},_renderSearch:function(f){f.find(".controls .search-input").searchInput({placeholder:this.searchPlaceholder,initialVal:this.searchFor,onfirstsearch:_.bind(this._firstSearch,this),onsearch:_.bind(this.searchItems,this),onclear:_.bind(this.clearSearch,this)});return f},_firstSearch:function(f){this.log("onFirstSearch",f);return this.searchItems(f)},searchItems:function(f){this.searchFor=f;this.trigger("search:searching",f,this);this.renderItems();return this},clearSearch:function(f){this.searchFor="";this.trigger("search:clear",this);this.renderItems();return this},showSelectors:function(f){f=(f!==undefined)?(f):(this.fxSpeed);this.selecting=true;this.$(".list-actions").slideDown(f);_.each(this.views,function(g){g.showSelector(f)})},hideSelectors:function(f){f=(f!==undefined)?(f):(this.fxSpeed);this.selecting=false;this.$(".list-actions").slideUp(f);_.each(this.views,function(g){g.hideSelector(f)});this.selected=[];this.lastSelected=null},toggleSelectors:function(){if(!this.selecting){this.showSelectors()}else{this.hideSelectors()}},selectAll:function(f){_.each(this.views,function(g){g.select(f)})},deselectAll:function(f){this.lastSelected=null;_.each(this.views,function(g){g.deselect(f)})},selectRange:function(h,g){var f=this.viewRange(h,g);_.each(f,function(i){i.select()});return f},getSelectedViews:function(){return _.filter(this.views,function(f){return f.selected})},getSelectedModels:function(){return new this.collection.constructor(_.map(this.getSelectedViews(),function(f){return f.model}))},_showLoadingIndicator:function(g,f,h){this.debug("_showLoadingIndicator",this.indicator,g,f,h);f=(f!==undefined)?(f):(this.fxSpeed);if(!this.indicator){this.indicator=new LoadingIndicator(this.$el,this.$el.parent());this.debug("\t created",this.indicator)}if(!this.$el.is(":visible")){this.indicator.show(0,h)}else{this.$el.fadeOut(f);this.indicator.show(g,f,h)}},_hideLoadingIndicator:function(f,g){this.debug("_hideLoadingIndicator",this.indicator,f,g);f=(f!==undefined)?(f):(this.fxSpeed);if(this.indicator){this.indicator.hide(f,g)}},scrollPosition:function(){return this.$scrollContainer().scrollTop()},scrollTo:function(f){this.$scrollContainer().scrollTop(f);return this},scrollToTop:function(){this.$scrollContainer().scrollTop(0);return this},scrollToItem:function(f){if(!f){return this}var g=f.$el.offset().top;this.$scrollContainer().scrollTop(g);return this},scrollToId:function(f){return this.scrollToItem(this.viewFromModelId(f))},events:{"click .select-all":"selectAll","click .deselect-all":"deselectAll"},toString:function(){return"ListPanel("+this.collection+")"}});e.prototype.templates=(function(){var g=b.wrapTemplate(["<div>",'<div class="controls"></div>','<div class="list-items"></div>','<div class="empty-message infomessagesmall"></div>',"</div>"]);var f=b.wrapTemplate(['<div class="controls">','<div class="title">','<div class="name"><%= view.title %></div>',"</div>",'<div class="subtitle"><%= view.subtitle %></div>','<div class="actions"></div>','<div class="messages"></div>','<div class="search">','<div class="search-input"></div>',"</div>",'<div class="list-actions">','<div class="btn-group">','<button class="select-all btn btn-default"','data-mode="select">',c("All"),"</button>",'<button class="deselect-all btn btn-default"','data-mode="select">',c("None"),"</button>","</div>","</div>","</div>"]);return{el:g,controls:f}}());var a=e.extend({modelCollectionKey:"contents",initialize:function(f){e.prototype.initialize.call(this,f);this.selecting=(f.selecting!==undefined)?f.selecting:false;this.setModel(this.model,f)},setModel:function(g,f){f=f||{};this.debug(this+".setModel:",g,f);this.freeModel();this.freeViews();if(g){this.model=g;if(this.logger){this.model.logger=this.logger}this._setUpModelListeners();this.collection.off();this.collection=(this.model[this.modelCollectionKey])?this.model[this.modelCollectionKey]:(f.collection||(new this.collectionClass([])));this._setUpCollectionListeners();this.trigger("new-model",this)}return this},freeModel:function(){if(this.model){this.stopListening(this.model)}return this},_setUpModelListeners:function(){this.log(this+"._setUpModelListeners",this.model);this.model.on("error",function(){this.trigger.apply(panel,arguments)},this);return this},_renderControls:function(g){this.debug(this+"(ListPanel)._renderControls");var h=this.model?this.model.toJSON():{},f=$(this.templates.controls(h,this));g.find(".controls").replaceWith(f);this.debug("\t .controls:",this.$(".controls"));this.debug("\t $controls:",f);return f},toString:function(){return"ModelListPanel("+this.model+")"}});a.prototype.templates=(function(){var f=b.wrapTemplate(['<div class="controls">','<div class="title">','<div class="name"><%= model.name %></div>',"</div>",'<div class="subtitle"><%= view.subtitle %></div>','<div class="actions"></div>','<div class="messages"></div>','<div class="search">','<div class="search-input"></div>',"</div>",'<div class="list-actions">','<div class="btn-group">','<button class="select-all btn btn-default"','data-mode="select">',c("All"),"</button>",'<button class="deselect-all btn btn-default"','data-mode="select">',c("None"),"</button>","</div>","</div>","</div>"]);return _.extend(_.clone(e.prototype.templates),{controls:f})}());return{ListPanel:e,ModelListPanel:a}});
\ No newline at end of file
+define(["mvc/list/list-item","mvc/base-mvc","utils/localization"],function(d,b,c){var e=Backbone.View.extend(b.LoggableMixin).extend({viewClass:d.ListItemView,collectionClass:Backbone.Collection,tagName:"div",className:"list-panel",fxSpeed:"fast",emptyMsg:c("This list is empty"),noneFoundMsg:c("No matching items found"),searchPlaceholder:c("search"),multiselectActions:[],initialize:function(f,g){f=f||{};if(f.logger){this.logger=f.logger}this.log(this+".initialize:",f);this.fxSpeed=_.has(f,"fxSpeed")?(f.fxSpeed):(this.fxSpeed);this.filters=[];this.searchFor=f.searchFor||"";this.indicator=new LoadingIndicator(this.$el);this.selecting=(f.selecting!==undefined)?f.selecting:true;this.selected=f.selected||[];this.lastSelected=null;this.viewClass=f.viewClass||this.viewClass;this.views=[];this.collection=f.collection||(new this.collectionClass([]));this.filters=f.filters||[];this.$scrollContainer=f.$scrollContainer||this.$scrollContainer;this.title=f.title||"";this.subtitle=f.subtitle||"";this.multiselectActions=f.multiselectActions||this.multiselectActions;this.actionsPopup=null;this._setUpListeners()},freeViews:function(){_.each(this.views,function(f){f.off()});this.views=[];return this},_setUpListeners:function(){this.off();this.on("error",function(g,j,f,i,h){console.error(g,j,f,i,h)},this);this.on("loading",function(){this._showLoadingIndicator("loading...",40)},this);this.on("loading-done",function(){this._hideLoadingIndicator(40)},this);this.once("rendered",function(){this.trigger("rendered:initial",this)},this);if(this.logger){this.on("all",function(f){this.log(this+"",arguments)},this)}this._setUpCollectionListeners();this._setUpViewListeners();return this},_setUpCollectionListeners:function(){this.log(this+"._setUpCollectionListeners",this.collection);this.collection.off();this.collection.on("error",function(g,j,f,i,h){this.trigger("error",g,j,f,i,h)},this);this.collection.on("reset",function(){this.renderItems()},this);this.collection.on("add",this.addItemView,this);this.collection.on("remove",this.removeItemView,this);if(this.logger){this.collection.on("all",function(f){this.info(this+"(collection)",arguments)},this)}return this},_setUpViewListeners:function(){this.log(this+"._setUpViewListeners");this.on("view:selected",function(f,g){if(g&&g.shiftKey&&this.lastSelected){var h=this.viewFromModelId(this.lastSelected);if(h){this.selectRange(f,h)}}this.selected.push(f.model.id);this.lastSelected=f.model.id},this);this.on("view:de-selected",function(f,g){this.selected=_.without(this.selected,f.model.id)},this)},render:function(g){this.log(this+".render",g);var f=this._buildNewRender();this._setUpBehaviors(f);this._queueNewRender(f,g);return this},_buildNewRender:function(){this.debug(this+"(ListPanel)._buildNewRender");var f=$(this.templates.el({},this));this._renderControls(f);this._renderTitle(f);this._renderSubtitle(f);this._renderSearch(f);this.renderItems(f);return f},_renderControls:function(g){this.debug(this+"(ListPanel)._renderControls");var f=$(this.templates.controls({},this));g.find(".controls").replaceWith(f);return f},_renderTitle:function(f){},_renderSubtitle:function(f){},_queueNewRender:function(g,h){h=(h===undefined)?(this.fxSpeed):(h);var f=this;f.log("_queueNewRender:",g,h);$(f).queue("fx",[function(i){this.$el.fadeOut(h,i)},function(i){f._swapNewRender(g);i()},function(i){this.$el.fadeIn(h,i)},function(i){f.trigger("rendered",f);i()}])},_swapNewRender:function(f){this.$el.empty().attr("class",this.className).append(f.children());if(this.selecting){this.showSelectors(0)}return this},_setUpBehaviors:function(f){f=f||this.$el;f.find(".controls [title]").tooltip({placement:"bottom"});return this},$scrollContainer:function(){return this.$el.parent().parent()},$list:function(f){return(f||this.$el).find("> .list-items")},$messages:function(f){return(f||this.$el).find("> .controls .messages")},$emptyMessage:function(f){return(f||this.$el).find("> .empty-message")},renderItems:function(h){h=h||this.$el;var f=this;f.log(this+".renderItems",h);var g=f.$list(h);f.views=f._filterCollection().map(function(i){return f._createItemView(i).render(0)});g.empty();if(f.views.length){f._attachItems(h);f.$emptyMessage(h).hide()}else{f._renderEmptyMessage(h).show()}return f.views},_filterCollection:function(){var f=this;return f.collection.filter(_.bind(f._filterItem,f))},_filterItem:function(g){var f=this;return(_.every(f.filters.map(function(h){return h.call(g)})))&&(!f.searchFor||g.matchesAll(f.searchFor))},_createItemView:function(h){var i=this._getItemViewClass(h),g=_.extend(this._getItemViewOptions(h),{model:h}),f=new i(g);this._setUpItemViewListeners(f);return f},_getItemViewClass:function(f){return this.viewClass},_getItemViewOptions:function(f){return{fxSpeed:this.fxSpeed,expanded:false,selectable:this.selecting,selected:_.contains(this.selected,f.id),draggable:this.dragging}},_setUpItemViewListeners:function(g){var f=this;g.on("all",function(){var h=Array.prototype.slice.call(arguments,0);h[0]="view:"+h[0];f.trigger.apply(f,h)});return f},_attachItems:function(f){this.$list(f).append(this.views.map(function(g){return g.$el}));return this},_renderEmptyMessage:function(f){this.debug("_renderEmptyMessage",f,this.searchFor);var g=this.searchFor?this.noneFoundMsg:this.emptyMsg;return this.$emptyMessage(f).text(g)},expandAll:function(){_.each(this.views,function(f){f.expand()})},collapseAll:function(){_.each(this.views,function(f){f.collapse()})},addItemView:function(i,j,h){this.log(this+".addItemView:",i);var g=this;if(!g._filterItem(i)){return undefined}var f=g._createItemView(i);g.views.push(f);$(f).queue("fx",[function(k){g.$emptyMessage().fadeOut(g.fxSpeed,k)},function(k){g.$list().append(f.render().$el);k()}]);return f},removeItemView:function(i,j,h){this.log(this+".removeItemView:",i);var g=this,f=g.viewFromModel(i);if(!f){return undefined}$({}).queue("fx",[function(k){f.$el.fadeOut(g.fxSpeed,k)},function(k){g.views=_.without(g.views,f);f.remove();if(!g.views.length){g._renderEmptyMessage().fadeIn(g.fxSpeed,k)}else{k()}}]);return f},viewFromModel:function(g){for(var h=0;h<this.views.length;h++){var f=this.views[h];if(f.model===g){return f}}return undefined},viewFromModelId:function(g){for(var f=0;f<this.views.length;f++){if(this.views[f].model.id===g){return this.views[f]}}return undefined},viewsWhereModel:function(f){return this.views.filter(function(g){var i=g.model.toJSON();for(var h in f){if(f.hasOwnProperty(h)){if(i[h]!==g.model.get(h)){return false}}}return true})},viewRange:function(i,h){if(i===h){return(i)?([i]):([])}var g=this.views.indexOf(i),f=this.views.indexOf(h);if(g===-1||f===-1){if(g===f){return[]}return(g===-1)?([h]):([i])}return(g<f)?this.views.slice(g,f+1):this.views.slice(f,g+1)},_renderSearch:function(f){f.find(".controls .search-input").searchInput({placeholder:this.searchPlaceholder,initialVal:this.searchFor,onfirstsearch:_.bind(this._firstSearch,this),onsearch:_.bind(this.searchItems,this),onclear:_.bind(this.clearSearch,this)});return f},_firstSearch:function(f){this.log("onFirstSearch",f);return this.searchItems(f)},searchItems:function(f){this.searchFor=f;this.trigger("search:searching",f,this);this.renderItems();return this},clearSearch:function(f){this.searchFor="";this.trigger("search:clear",this);this.renderItems();return this},showSelectors:function(f){f=(f!==undefined)?(f):(this.fxSpeed);this.selecting=true;this.$(".list-actions").slideDown(f);_.each(this.views,function(g){console.debug(g.$el);g.showSelector(f)})},hideSelectors:function(f){f=(f!==undefined)?(f):(this.fxSpeed);this.selecting=false;this.$(".list-actions").slideUp(f);_.each(this.views,function(g){g.hideSelector(f)});this.selected=[];this.lastSelected=null},toggleSelectors:function(){if(!this.selecting){this.showSelectors()}else{this.hideSelectors()}},selectAll:function(f){_.each(this.views,function(g){g.select(f)})},deselectAll:function(f){this.lastSelected=null;_.each(this.views,function(g){g.deselect(f)})},selectRange:function(h,g){var f=this.viewRange(h,g);_.each(f,function(i){i.select()});return f},getSelectedViews:function(){return _.filter(this.views,function(f){return f.selected})},getSelectedModels:function(){return new this.collection.constructor(_.map(this.getSelectedViews(),function(f){return f.model}))},_showLoadingIndicator:function(g,f,h){this.debug("_showLoadingIndicator",this.indicator,g,f,h);f=(f!==undefined)?(f):(this.fxSpeed);if(!this.indicator){this.indicator=new LoadingIndicator(this.$el,this.$el.parent());this.debug("\t created",this.indicator)}if(!this.$el.is(":visible")){this.indicator.show(0,h)}else{this.$el.fadeOut(f);this.indicator.show(g,f,h)}},_hideLoadingIndicator:function(f,g){this.debug("_hideLoadingIndicator",this.indicator,f,g);f=(f!==undefined)?(f):(this.fxSpeed);if(this.indicator){this.indicator.hide(f,g)}},scrollPosition:function(){return this.$scrollContainer().scrollTop()},scrollTo:function(f){this.$scrollContainer().scrollTop(f);return this},scrollToTop:function(){this.$scrollContainer().scrollTop(0);return this},scrollToItem:function(f){if(!f){return this}var g=f.$el.offset().top;this.$scrollContainer().scrollTop(g);return this},scrollToId:function(f){return this.scrollToItem(this.viewFromModelId(f))},events:{"click .select-all":"selectAll","click .deselect-all":"deselectAll"},toString:function(){return"ListPanel("+this.collection+")"}});e.prototype.templates=(function(){var g=b.wrapTemplate(["<div>",'<div class="controls"></div>','<div class="list-items"></div>','<div class="empty-message infomessagesmall"></div>',"</div>"]);var f=b.wrapTemplate(['<div class="controls">','<div class="title">','<div class="name"><%= view.title %></div>',"</div>",'<div class="subtitle"><%= view.subtitle %></div>','<div class="actions"></div>','<div class="messages"></div>','<div class="search">','<div class="search-input"></div>',"</div>",'<div class="list-actions">','<div class="btn-group">','<button class="select-all btn btn-default"','data-mode="select">',c("All"),"</button>",'<button class="deselect-all btn btn-default"','data-mode="select">',c("None"),"</button>","</div>","</div>","</div>"]);return{el:g,controls:f}}());var a=e.extend({modelCollectionKey:"contents",initialize:function(f){e.prototype.initialize.call(this,f);this.selecting=(f.selecting!==undefined)?f.selecting:false;this.setModel(this.model,f)},setModel:function(g,f){f=f||{};this.debug(this+".setModel:",g,f);this.freeModel();this.freeViews();if(g){this.model=g;if(this.logger){this.model.logger=this.logger}this._setUpModelListeners();this.collection.off();this.collection=(this.model[this.modelCollectionKey])?this.model[this.modelCollectionKey]:(f.collection||(new this.collectionClass([])));this._setUpCollectionListeners();this.trigger("new-model",this)}return this},freeModel:function(){if(this.model){this.stopListening(this.model)}return this},_setUpModelListeners:function(){this.log(this+"._setUpModelListeners",this.model);this.model.on("error",function(){this.trigger.apply(panel,arguments)},this);return this},_renderControls:function(g){this.debug(this+"(ListPanel)._renderControls");var h=this.model?this.model.toJSON():{},f=$(this.templates.controls(h,this));g.find(".controls").replaceWith(f);this.debug("\t .controls:",this.$(".controls"));this.debug("\t $controls:",f);return f},toString:function(){return"ModelListPanel("+this.model+")"}});a.prototype.templates=(function(){var f=b.wrapTemplate(['<div class="controls">','<div class="title">','<div class="name"><%= model.name %></div>',"</div>",'<div class="subtitle"><%= view.subtitle %></div>','<div class="actions"></div>','<div class="messages"></div>','<div class="search">','<div class="search-input"></div>',"</div>",'<div class="list-actions">','<div class="btn-group">','<button class="select-all btn btn-default"','data-mode="select">',c("All"),"</button>",'<button class="deselect-all btn btn-default"','data-mode="select">',c("None"),"</button>","</div>","</div>","</div>"]);return _.extend(_.clone(e.prototype.templates),{controls:f})}());return{ListPanel:e,ModelListPanel:a}});
\ No newline at end of file
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/packed/mvc/tools/tools-form.js
--- a/static/scripts/packed/mvc/tools/tools-form.js
+++ b/static/scripts/packed/mvc/tools/tools-form.js
@@ -1,1 +1,1 @@
-define(["mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets","mvc/tools/tools-section","mvc/tools/tools-tree"],function(g,k,i,a,f,d,h,j,c){var e=Backbone.Model.extend({initialize:function(l){this.url=galaxy_config.root+"api/tools/"+l.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(m){var l=this;this.options=m;this.model=new e({id:m.id});this.tree=new c(this);this.field_list={};this.input_list={};this.datasets=new h({history_id:this.options.history_id,success:function(){l._initializeToolForm()}})},_initializeToolForm:function(){var m=this;var n=new k.ButtonIcon({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(m.options.biostar_url+"/p/new/post/")}});var o=new k.ButtonIcon({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(m.options.biostar_url+"/t/"+m.options.id+"/")}});var l=new k.ButtonIcon({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",galaxy_config.root+"root?tool_id="+m.options.id)}});this.model.fetch({error:function(p){console.debug("tools-form::_initializeToolForm() : Attempt to fetch tool model failed.")},success:function(){m.inputs=m.model.get("inputs");m.portlet=new g.View({icon:"fa-wrench",title:"<b>"+m.model.get("name")+"</b> "+m.model.get("description"),buttons:{execute:new k.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){m._submit()}})},operations:{button_question:n,button_search:o,button_share:l}});if(!m.options.biostar_url){n.$el.hide();o.$el.hide()}m.message=new k.Message();m.portlet.append(m.message.$el);$(m.main_el).append(m.portlet.$el);if(m.options.help!=""){$(m.main_el).append(d.help(m.options.help))}if(m.options.citations){$(m.main_el).append(d.citations());var p=new i.ToolCitationCollection();p.tool_id=m.options.id;var q=new a.CitationListView({collection:p});q.render();p.fetch()}m.setElement(m.portlet.content());m.section=new j.View(m,{inputs:m.model.get("inputs")});m.portlet.append(m.section.$el);m.refresh();m._submit()}})},refresh:function(){this.tree.refresh();for(var l in this.field_list){this.field_list[l].trigger("change")}console.debug("tools-form::refresh() - Recreated tree structure. Refresh.")},_submit:function(){console.log(this.tree.finalize())}});return{View:b}});
\ No newline at end of file
+define(["mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets","mvc/tools/tools-section","mvc/tools/tools-tree","mvc/tools/tools-jobs"],function(h,l,j,a,f,d,i,k,c,g){var e=Backbone.Model.extend({initialize:function(m){this.url=galaxy_config.root+"api/tools/"+m.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(n){var m=this;this.options=n;this.model=new e({id:n.id});this.tree=new c(this);this.job_handler=new g(this);this.field_list={};this.input_list={};this.element_list={};this.datasets=new i({history_id:this.options.history_id,success:function(){m._initializeToolForm()}})},reset:function(){for(var m in this.element_list){this.element_list[m].reset()}},_initializeToolForm:function(){var n=this;var o=new l.ButtonIcon({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(n.options.biostar_url+"/p/new/post/")}});var p=new l.ButtonIcon({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(n.options.biostar_url+"/t/"+n.options.id+"/")}});var m=new l.ButtonIcon({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",galaxy_config.root+"root?tool_id="+n.options.id)}});this.model.fetch({error:function(q){console.debug("tools-form::_initializeToolForm() : Attempt to fetch tool model failed.")},success:function(){n.inputs=n.model.get("inputs");n.portlet=new h.View({icon:"fa-wrench",title:"<b>"+n.model.get("name")+"</b> "+n.model.get("description"),buttons:{execute:new l.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){n.job_handler.submit()}})},operations:{button_question:o,button_search:p,button_share:m}});if(!n.options.biostar_url){o.$el.hide();p.$el.hide()}n.message=new l.Message();n.portlet.append(n.message.$el);$(n.main_el).append(n.portlet.$el);if(n.options.help!=""){$(n.main_el).append(d.help(n.options.help))}if(n.options.citations){$(n.main_el).append(d.citations());var q=new j.ToolCitationCollection();q.tool_id=n.options.id;var r=new a.CitationListView({collection:q});r.render();q.fetch()}n.setElement(n.portlet.content());n.section=new k.View(n,{inputs:n.model.get("inputs")});n.portlet.append(n.section.$el);n.refresh()}})},refresh:function(){this.tree.refresh();for(var m in this.field_list){this.field_list[m].trigger("change")}console.debug("tools-form::refresh() - Recreated tree structure. Refresh.")}});return{View:b}});
\ No newline at end of file
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/packed/mvc/tools/tools-jobs.js
--- a/static/scripts/packed/mvc/tools/tools-jobs.js
+++ b/static/scripts/packed/mvc/tools/tools-jobs.js
@@ -1,1 +1,1 @@
-define(["utils/utils"],function(a){return Backbone.Model.extend({initialize:function(c,b){this.app=c;this.options=a.merge(b,this.optionsDefault)},submit:function(d,e,c){var b=this;a.request("POST",config.root+"api/tools",d,function(f){if(!f.outputs||f.outputs.length==0){c&&c()}else{console.log(f)}},function(f){var g="";if(f&&f.message&&f.message.data&&f.message.data.input){g=f.message.data.input+"."}c&&c()})}})});
\ No newline at end of file
+define(["utils/utils"],function(a){return Backbone.Model.extend({initialize:function(c,b){this.app=c;this.options=a.merge(b,this.optionsDefault)},submit:function(){var b=this;var c={tool_id:this.app.options.id,inputs:this.app.tree.finalize()};this.app.reset();a.request("POST",galaxy_config.root+"api/tools",c,function(d){if(!d.outputs||d.outputs.length==0){console.log(d)}b._refreshHdas()},function(d){if(d&&d.message&&d.message.data){var g=b.app.tree.match(d.message.data);for(var f in g){var e=g[f];if(!e){e="Please verify this parameter."}b.app.element_list[f].error(e)}}})},_refreshHdas:function(){if(parent.Galaxy&&parent.Galaxy.currHistoryPanel){parent.Galaxy.currHistoryPanel.refreshContents()}}})});
\ No newline at end of file
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/scripts/packed/mvc/tools/tools-tree.js
--- a/static/scripts/packed/mvc/tools/tools-tree.js
+++ b/static/scripts/packed/mvc/tools/tools-tree.js
@@ -1,1 +1,1 @@
-define([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},refresh:function(){this.dict={};this.xml=$("<div/>");if(!this.app.section){return{}}this._iterate(this.app.section.$el,this.dict,this.xml)},finalize:function(){var a=this;var b={};function c(k,l){for(var f in l){var d=l[f];if(d.input){var m=d.input;var h=k;if(k!=""){h+="|"}h+=m.name;switch(m.type){case"repeat":var g=0;for(var e in d){if(e.indexOf("section")!=-1){c(h+"_"+g++,d[e])}}break;case"conditional":var n=a.app.field_list[m.id].value();for(var e in m.cases){if(m.cases[e].value==n){c(h,l[m.id+"-section-"+e]);break}}break;default:var n=a.app.field_list[m.id].value();b[h]=n}}}}c("",this.dict);return b},findReferences:function(c,e){var g=[];var b=this;function d(h,j){var i=$(j).children();var l=[];var k=false;i.each(function(){var o=this;var n=$(o).attr("id");if(n!==c){var m=b.app.input_list[n];if(m){if(m.name==h){k=true;return false}if(m.data_ref==h&&m.type==e){l.push(n)}}}});if(!k){g=g.concat(l);i.each(function(){d(h,this)})}}var f=this.xml.find("#"+c);if(f.length>0){var a=this.app.input_list[c];if(a){d(a.name,f.parent())}}return g},_iterate:function(d,e,b){var a=this;var c=$(d).children();c.each(function(){var i=this;var h=$(i).attr("id");if($(i).hasClass("section-row")||$(i).hasClass("tab-pane")){e[h]={};var f=a.app.input_list[h];if(f){e[h]={input:f}}var g=$('<div id="'+h+'"/>');b.append(g);a._iterate(i,e[h],g)}else{a._iterate(i,e,b)}})}})});
\ No newline at end of file
+define([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},refresh:function(){this.dict={};this.xml=$("<div/>");if(!this.app.section){return{}}this._iterate(this.app.section.$el,this.dict,this.xml)},finalize:function(){var a=this;this.job_def={};this.job_ids={};function c(f,e,d){a.job_def[f]=d;a.job_ids[f]=e}function b(k,l){for(var f in l){var d=l[f];if(d.input){var m=d.input;var h=k;if(k!=""){h+="|"}h+=m.name;switch(m.type){case"repeat":var g=0;for(var e in d){if(e.indexOf("section")!=-1){b(h+"_"+g++,d[e])}}break;case"conditional":var n=a.app.field_list[m.id].value();c(h+"|"+m.test_param.name,m.id,n);for(var e in m.cases){if(m.cases[e].value==n){b(h,l[m.id+"-section-"+e]);break}}break;case"data":var n={id:a.app.field_list[m.id].value(),src:"hda"};c(h,m.id,n);break;case"boolean":var n=a.app.field_list[m.id].value();if(n==="true"){n=m.truevalue}else{n=m.falsevalue}c(h,m.id,n);break;default:c(h,m.id,a.app.field_list[m.id].value())}}}}b("",this.dict);return this.job_def},match:function(c){var a={};var b=this;function d(j,h){if(typeof h==="string"){var f=b.app.tree.job_ids[j];if(f){a[f]=h}}else{for(var g in h){var e=g;if(j!==""){e=j+"|"+e}d(e,h[g])}}}d("",c);return a},references:function(c,e){var g=[];var b=this;function d(h,j){var i=$(j).children();var l=[];var k=false;i.each(function(){var o=this;var n=$(o).attr("id");if(n!==c){var m=b.app.input_list[n];if(m){if(m.name==h){k=true;return false}if(m.data_ref==h&&m.type==e){l.push(n)}}}});if(!k){g=g.concat(l);i.each(function(){d(h,this)})}}var f=this.xml.find("#"+c);if(f.length>0){var a=this.app.input_list[c];if(a){d(a.name,f.parent())}}return g},_iterate:function(d,e,b){var a=this;var c=$(d).children();c.each(function(){var i=this;var h=$(i).attr("id");if($(i).hasClass("section-row")||$(i).hasClass("tab-pane")){e[h]={};var f=a.app.input_list[h];if(f){e[h]={input:f}}var g=$('<div id="'+h+'"/>');b.append(g);a._iterate(i,e[h],g)}else{a._iterate(i,e,b)}})}})});
\ No newline at end of file
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1644,7 +1644,9 @@
.list-item{border:1px solid #bfbfbf}.list-item .vertical-spacing{margin-bottom:8px}
.list-item .info-section{border-radius:3px;border:1px solid rgba(153,153,153,0.30000000000000004);padding:4px}
.list-item .padded{padding:6px 10px 6px 8px}
-.list-item .warnings [class$=messagesmall]{margin:6px 10px 2px 8px;font-size:90%}
+.list-item .warnings:not(:empty){padding-top:4px}
+.list-item .warnings [class$=messagesmall]{margin:6px 10px 2px 8px;font-size:90%}.list-item .warnings [class$=messagesmall]:first-child{margin-top:0px}
+.list-item .warnings [class$=messagesmall]:last-child{margin-bottom:0px}
.list-item .help-text{font-weight:normal;color:#555}
.list-item .selector{float:left;display:none;width:32px;height:32px;margin:0 0 -6px 0;padding:8px 0 2px 7px;font-size:80%;color:#333;cursor:pointer;vertical-align:middle}
.list-item .selector:hover{color:maroon}
@@ -1654,7 +1656,7 @@
.list-item .primary-actions .icon-btn:last-child{margin-left:0px;border-radius:0px 3px 3px 0px}
.list-item .primary-actions .icon-btn:only-child{margin:0px;border-radius:3px}
.list-item .primary-actions .icon-btn{margin-left:2px}
-.list-item .details{display:none;padding:0 10px 6px 8px}.list-item .details [class$=messagesmall]{margin:0px 0px 8px 0px}
+.list-item .details{display:none;padding:0 10px 6px 8px}.list-item .details>[class$=messagesmall]{margin:0px 0px 8px 0px}
.list-item .details label{margin:0px;padding:0px;font-weight:normal}
.list-item .details .prompt{font-weight:normal;color:#555}
.list-item .details .prompt:after{content:':';margin-right:4px}
@@ -1679,6 +1681,8 @@
.list-panel .controls .list-actions .btn{padding-top:2px;padding-bottom:2px;font-size:90%}
.list-panel .list-items .list-item:not(:last-child){border-bottom-width:0px}
.list-panel .empty-message{display:none;margin:0px}
+.list-item .details .list-panel{margin-top:8px;border-radius:3px;background:white;padding:4px}.list-item .details .list-panel .list-items{border:1px solid #bfbfbf;border-radius:3px}.list-item .details .list-panel .list-items .list-item:first-child{border-top-width:0px;border-radius:3px 3px 0px 0px}
+.list-item .details .list-panel .list-items .list-item:last-child{border-bottom-width:0px;border-radius:0px 0px 3px 3px}
.search-input .search-query{width:100%;padding-right:24px}
.search-input .search-clear,.search-input .search-loading{position:relative;display:inline-block;float:right;margin-top:-24px;margin-right:4px;font-size:1.4em;line-height:23px;color:grey}
.search-input .search-clear:hover{color:#303030}
@@ -1760,10 +1764,11 @@
.annotated-history-panel table.list-items .headers th{padding:8px}
.annotated-history-panel table.list-items>tbody>tr{cursor:pointer;border-bottom:1px solid grey}.annotated-history-panel table.list-items>tbody>tr>td{margin:0px;padding:0px;vertical-align:top}.annotated-history-panel table.list-items>tbody>tr>td:nth-child(1){width:50%}
.annotated-history-panel table.list-items>tbody>tr>td:nth-child(2){padding:8px 16px 8px 16px;white-space:pre-wrap}
-.annotated-history-panel table.list-items>tbody>tr .list-item{border:0px}
+.annotated-history-panel table.list-items>tbody>tr>td>.list-item{border:0px}
.annotated-history-panel .empty-message{margin-top:8px}
.history-panel .dataset-collection .subtitle{margin-top:2px;font-size:90%;color:#777}
.history-panel .dataset-collection-panel .controls{padding:0px}
+.history-panel .dataset-collection-panel .list-items{margin-top:0px}
body.historyPage{background:#dfe5f9;color:#000;margin:5px;border:0;padding:0}
div.historyLinks{margin:5px 5px}
div.historyItem{margin:0 -5px;padding:8px 10px;border-top:solid #bfbfbf 1px;border-right:none;word-wrap:break-word;background:#eee}div.historyItem .state-icon{display:inline-block;vertical-align:middle;width:16px;height:16px;background-position:0 1px;background-repeat:no-repeat}
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/style/src/less/history.less
--- a/static/style/src/less/history.less
+++ b/static/style/src/less/history.less
@@ -553,10 +553,10 @@
// do not html format
white-space: pre-wrap;
}
- }
- // tr has border - remove from items
- .list-item {
- border: 0px;
+ // tr has border - remove from items
+ & > .list-item {
+ border: 0px;
+ }
}
}
}
@@ -579,6 +579,9 @@
.controls {
padding: 0px;
}
+ .list-items {
+ margin-top: 0px;
+ }
}
}
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd static/style/src/less/list-item.less
--- a/static/style/src/less/list-item.less
+++ b/static/style/src/less/list-item.less
@@ -22,9 +22,18 @@
}
.warnings {
+ &:not(:empty) {
+ padding-top: 4px;
+ }
[class$=messagesmall] {
margin: @spacing-top @spacing-right ( @spacing-bottom - 4 ) @spacing-left;
font-size: 90%;
+ &:first-child {
+ margin-top: 0px;
+ }
+ &:last-child {
+ margin-bottom: 0px;
+ }
}
}
@@ -79,7 +88,7 @@
display: none;
padding: 0px @spacing-right @spacing-bottom @spacing-left;
- [class$=messagesmall] {
+ & > [class$=messagesmall] {
margin: 0px 0px 8px 0px;
}
@@ -160,3 +169,25 @@
margin: 0px;
}
}
+
+// ---------------------------------------------------------------------------- a list panel nested inside a list-item
+.list-item .details .list-panel {
+ margin-top: 8px;
+ border-radius: 3px;
+ background: white;
+ padding: 4px;
+ .list-items {
+ border: 1px solid @border-default-color;
+ border-radius: 3px;
+ .list-item {
+ &:first-child {
+ border-top-width: 0px;
+ border-radius: 3px 3px 0px 0px;
+ }
+ &:last-child {
+ border-bottom-width: 0px;
+ border-radius: 0px 0px 3px 3px;
+ }
+ }
+ }
+}
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd templates/webapps/galaxy/history/display.mako
--- a/templates/webapps/galaxy/history/display.mako
+++ b/templates/webapps/galaxy/history/display.mako
@@ -45,7 +45,7 @@
<div id="history-${ history_dict[ 'id' ] }" class="history-panel"></div><script type="text/javascript">
- var historyJSON = ${h.to_json_string( history_dict )},
+ var historyJSON = ${h.dumps( history_dict )},
hdaJSON = ${h.dumps( hda_dicts )};
require.config({
@@ -62,6 +62,7 @@
el : $( "#history-" + historyJSON.id ),
model : history
}).render();
+ console.debug( historyPanel.$el )
});
</script></%def>
diff -r deb003947e0e02de4613912b14832944954576a5 -r 618b02d13329adf2d01b72e9743a8fa00192c6fd templates/webapps/galaxy/root/history.mako
--- a/templates/webapps/galaxy/root/history.mako
+++ b/templates/webapps/galaxy/root/history.mako
@@ -22,23 +22,23 @@
require([
//'mvc/history/history-panel'
//'mvc/history/history-panel-annotated'
- //'mvc/history/history-panel-edit'
- 'mvc/history/history-panel-edit-current'
+ 'mvc/history/history-panel-edit'
+ //'mvc/history/history-panel-edit-current'
], function( historyPanel ){
$(function(){
// history module is already in the dpn chain from the panel. We can re-scope it here.
var historyModel = require( 'mvc/history/history-model' );
//window.panel = new historyPanel.HistoryPanel({
//window.panel = new historyPanel.AnnotatedHistoryPanel({
- //window.panel = new historyPanel.HistoryPanelEdit({
- window.panel = new historyPanel.CurrentHistoryPanel({
+ window.panel = new historyPanel.HistoryPanelEdit({
+ //window.panel = new historyPanel.CurrentHistoryPanel({
show_deleted : bootstrapped.show_deleted,
show_hidden : bootstrapped.show_hidden,
purgeAllowed : Galaxy.config.allow_user_dataset_purge,
model : new historyModel.History( bootstrapped.history, bootstrapped.hdas )
});
panel.render().$el.appendTo( 'body' );
- $( 'body' ).css( 'padding', '10px' );
+ //$( 'body' ).css( 'padding', '10px' );
});
});
});
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0