galaxy-commits
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 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
- 15302 discussions
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/65206cc6586c/
Changeset: 65206cc6586c
Branch: igv-local-dbkey
User: dannon
Date: 2014-09-12 19:14:24
Summary: Branch prune.
Affected #: 0 files
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: 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 12 Sep '14
by GitHub 12 Sep '14
12 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 12 Sep '14
by GitHub 12 Sep '14
12 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 12 Sep '14
by GitHub 12 Sep '14
12 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