This commit is contained in:
Dannon Baker
2015-02-09 11:36:45 -05:00
32 changed files with 414 additions and 227 deletions
+14 -6
View File
@@ -1,12 +1,13 @@
# Contributing
This document briefly describes how to contribute to the
galaxy-central core project - also checkout the video of our [2013
Galaxy Community Conference
presentation](http://vimeo.com/channels/581875/73486255) on the
topic. For information on contributing more broadly to the Galaxy
ecosystem and a deeper discussion of some of these points - please see
the [Develop](https://wiki.galaxyproject.org/Develop/) section of the
galaxy-central core project - also checkout our 2013 Galaxy Community
Conference presentation] on the topic
([video](http://vimeo.com/channels/581875/73486255),
[presentation](https://wiki.galaxyproject.org/Documents/Presentations/GCC2013?action=AttachFile&do=view&target=BakerContribute.pdf)). For
information on contributing more broadly to the Galaxy ecosystem and a
deeper discussion of some of these points - please see the
[Develop](https://wiki.galaxyproject.org/Develop/) section of the
[Galaxy Wiki](https://wiki.galaxyproject.org/).
## Before you Begin
@@ -80,6 +81,13 @@ the [development mailing list](http://dev.list.galaxyproject.org/).
* A description of how to test the change.
## Ideas
Galaxy's [Trello board](http://bit.ly/gxytrello) is filled with bugs and ideas
for enhancements, but we maintain a [card](https://trello.com/c/eFdPIdIB) with
links to smaller issues we believe would make the best entry points for new
developers.
## A Quick Note about Tools
For the most part, Galaxy tools should be published to the
@@ -275,10 +275,16 @@ define(['utils/utils', 'mvc/tools/tools-form-base'],
/** Request a new model for an already created tool form and updates the form inputs
*/
_updateModel: function() {
// create the request dictionary
// link self
var self = this;
var current_state = this.tree.finalize();
// create the request dictionary
var current_state = {
tool_id : this.options.id,
tool_version : this.options.version,
inputs : this.tree.finalize()
}
// log tool state
console.debug('tools-form-workflow::_refreshForm() - Refreshing states.');
console.debug(current_state);
@@ -287,11 +293,11 @@ define(['utils/utils', 'mvc/tools/tools-form-base'],
var process_id = this.deferred.register();
// build model url for request
var model_url = galaxy_config.root + 'workflow/editor_form_post?tool_id=' + this.options.id + '&__is_dynamic__=False';
var model_url = galaxy_config.root + 'api/workflows/build_module';
// post job
Utils.request({
type : 'GET',
type : 'POST',
url : model_url,
data : current_state,
success : function(data) {
@@ -34,8 +34,7 @@ define([], function() {
this.field.skip = false;
var v = this.field.value && this.field.value();
this.field.skip = Boolean(options.optional &&
((this.default_value === undefined) ||
((this.field.validate && !this.field.validate()) || !v ||
(((this.field.validate && !this.field.validate()) || !v ||
(v == this.default_value) || (Number(v) == Number(this.default_value)) ||
(JSON.stringify(v) == JSON.stringify(this.default_value)))));
@@ -294,17 +294,20 @@ define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/ui/ui-portlet',
// get id
var id = input_def.id;
// add regular/default value if missing
if (input_def.value === undefined) {
input_def.value = null;
}
if (input_def.default_value === undefined) {
input_def.default_value = input_def.value;
}
// create input field
var field = this._createField(input_def);
// add to field list
this.app.field_list[id] = field;
// fix default value if missing
if (input_def.default_value === undefined) {
input_def.default_value = input_def.value;
}
// create input field wrapper
var input_element = new InputElement(this.app, {
label : input_def.label,
+40 -45
View File
@@ -10,13 +10,13 @@ return Backbone.Model.extend({
initialize: function(app) {
this.app = app;
},
/** Convert dictionary representation into tool api specific flat dictionary format.
*/
finalize: function(patch) {
// link this
var self = this;
// dictionary with api specific identifiers
this.map_dict = {};
@@ -24,24 +24,24 @@ return Backbone.Model.extend({
if (!this.app.section) {
return {};
}
// ensure that dictionary with patching functions exists
patch = patch || {};
// dictionary formatted for job submission or tool form update
var result_dict = {};
// prepare full dictionary
var dict = {};
// fill dictionary from dom
this._iterate(this.app.section.$el, dict);
// add identifier and value to job definition
function add(job_input_id, input_id, input_value) {
// add entry to result dictionary
result_dict[job_input_id] = input_value;
// backup id mapping
self.map_dict[job_input_id] = input_id;
};
@@ -53,21 +53,21 @@ return Backbone.Model.extend({
if (node.input) {
// get node
var input = node.input;
// create identifier
var job_input_id = identifier;
if (identifier != '') {
job_input_id += '|';
}
job_input_id += input.name;
// process input type
switch (input.type) {
// handle repeats
case 'repeat':
// section identifier
var section_label = 'section-';
// collect repeat block identifiers
var block_indices = [];
var block_prefix = null;
@@ -81,10 +81,10 @@ return Backbone.Model.extend({
}
}
}
// sort repeat blocks
block_indices.sort(function(a,b) { return a - b; });
// add to response dictionary in created order
var index = 0;
for (var i in block_indices) {
@@ -98,10 +98,10 @@ return Backbone.Model.extend({
if (patch[input.test_param.type]) {
value = patch[input.test_param.type](value);
}
// add conditional value
add (job_input_id + '|' + input.test_param.name, input.id, value);
// identify selected case
var selectedCase = self.matchCase(input, value);
if (selectedCase != -1) {
@@ -116,22 +116,17 @@ return Backbone.Model.extend({
// get field
var field = self.app.field_list[input.id];
if (field && field.value) {
// get and patch field value
// validate field value
var value = field.value();
if (patch[input.type]) {
value = patch[input.type](value);
}
// validate field value
if (field.skip) {
continue;
}
// validate field value
if (field.validate && !field.validate()) {
value = null;
}
// get and patch field value
if (patch[input.type]) {
value = patch[input.type](value);
}
// ignore certain values
if (input.ignore === undefined || (value !== null && input.ignore != value)) {
// add value to submission
@@ -149,20 +144,20 @@ return Backbone.Model.extend({
}
}
}
// start conversion
convert('', dict);
// return result
return result_dict;
},
/** Match job definition identifier to input element identifier
*/
match: function (job_input_id) {
return this.map_dict && this.map_dict[job_input_id];
},
/** Match conditional values to selected cases
*/
matchCase: function(input, value) {
@@ -174,27 +169,27 @@ return Backbone.Model.extend({
value = input.test_param.falsevalue || 'false';
}
}
// find selected case
for (var i in input.cases) {
if (input.cases[i].value == value) {
return i;
}
}
// selected case not found
return -1;
},
/** Matches identifier from api model to input elements
*/
matchModel: function(model, callback) {
// final result dictionary
var result = {};
// link this
var self = this;
// search throughout response
function search (id, head) {
for (var i in head) {
@@ -224,23 +219,23 @@ return Backbone.Model.extend({
}
}
}
// match all ids and return messages
search('', model.inputs);
// return matched results
return result;
},
/** Matches identifier from api response to input elements
*/
matchResponse: function(response) {
// final result dictionary
var result = {};
// link this
var self = this;
// search throughout response
function search (id, head) {
if (typeof head === 'string') {
@@ -262,14 +257,14 @@ return Backbone.Model.extend({
}
}
}
// match all ids and return messages
search('', response);
// return matched results
return result;
},
/** Iterate through the tool form dom and map it to the dictionary.
*/
_iterate: function(parent, dict) {
@@ -279,15 +274,15 @@ return Backbone.Model.extend({
children.each(function() {
// get child element
var child = this;
// get id
var id = $(child).attr('id');
// create new branch
if ($(child).hasClass('section-row')) {
// create sub dictionary
dict[id] = {};
// add input element if it exists
var input = self.app.input_list[id];
if (input) {
@@ -295,7 +290,7 @@ return Backbone.Model.extend({
input : input
}
}
// fill sub dictionary
self._iterate(child, dict[id]);
} else {
@@ -34,7 +34,7 @@ function MetricsLogger( options ){
var self = this;
///** get the current user's id from bootstrapped data or options */
self.userId = window.bootstrapped? window.bootstrapped.user.id: null;
self.userId = ( window.bootstrapped && window.bootstrapped.user )? window.bootstrapped.user.id: null;
self.userId = self.userId || options.userId || null;
/** the (optional) console to emit logs to */
@@ -16,8 +16,8 @@
"devDependencies": {
"grunt": "~0.4.1",
"grunt-cli": "~0.1.9",
"grunt-contrib-handlebars": "~0.5.10",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-handlebars": "^0.9.3",
"grunt-contrib-uglify": "~0.2.2",
"grunt-contrib-watch": "~0.5.3"
}
File diff suppressed because one or more lines are too long
+142 -47
View File
@@ -3,6 +3,9 @@ Providers that provide lists of lists generally where each line of a source
is further subdivided into multiple data (e.g. columns from a line).
"""
import urllib
import re
import line
_TODO = """
@@ -34,12 +37,13 @@ class ColumnarDataProvider( line.RegexLineDataProvider ):
'column_count' : 'int',
'column_types' : 'list:str',
'parse_columns' : 'bool',
'deliminator' : 'str'
'deliminator' : 'str',
'filters' : 'list:str'
}
def __init__( self, source, indeces=None,
column_count=None, column_types=None, parsers=None, parse_columns=True,
deliminator='\t', **kwargs ):
deliminator='\t', filters=None, **kwargs ):
"""
:param indeces: a list of indeces of columns to gather from each row
Optional: will default to `None`.
@@ -103,6 +107,104 @@ class ColumnarDataProvider( line.RegexLineDataProvider ):
# overwrite with user desired parsers
self.parsers.update( parsers or {} )
filters = filters or []
self.column_filters = []
for filter_ in filters:
parsed = self.parse_filter( filter_ )
#TODO: might be better to error on bad filter/None here
if callable( parsed ):
self.column_filters.append( parsed )
def parse_filter( self, filter_param_str ):
split = filter_param_str.split( '-', 3 )
if not len( split ) == 3:
return None
column, op, val = split
# better checking v. len and indeces
column = int( column )
if column > len( self.column_types ):
return None
if self.column_types[ column ] in ( 'float', 'int' ):
return self.create_numeric_filter( column, op, val )
if self.column_types[ column ] in ( 'str' ):
return self.create_string_filter( column, op, val )
if self.column_types[ column ] in ( 'list' ):
return self.create_list_filter( column, op, val )
return None
def create_numeric_filter( self, column, op, val ):
"""
Return an anonymous filter function that will be passed the array
of parsed columns. Return None if no filter function can be
created for the given params.
The function will compare the column at index `column` against `val`
using the given op where op is one of:
lt: less than, le: less than or equal to,
eq: equal to, ne: not equal to,
ge: greather than or equal to, gt: greater than
`val` is cast as float here and will return None if there's a parsing error.
"""
try:
val = float( val )
except ValueError:
return None
if 'lt' == op:
return lambda d: d[column] < val
elif 'le' == op:
return lambda d: d[column] <= val
elif 'eq' == op:
return lambda d: d[column] == val
elif 'ne' == op:
return lambda d: d[column] != val
elif 'ge' == op:
return lambda d: d[column] >= val
elif 'gt' == op:
return lambda d: d[column] > val
return None
def create_string_filter( self, column, op, val ):
"""
Return an anonymous filter function that will be passed the array
of parsed columns. Return None if no filter function can be
created for the given params.
The function will compare the column at index `column` against `val`
using the given op where op is one of:
eq: exactly matches,
has: the column contains the substring `val`,
re: the column matches the regular expression in `val`
"""
if 'eq' == op:
return lambda d: d[column] == val
elif 'has' == op:
return lambda d: val in d[column]
elif 're' == op:
val = urllib.unquote_plus( val )
val = re.compile( val )
return lambda d: val.match( d[column] ) is not None
return None
def create_list_filter( self, column, op, val ):
"""
Return an anonymous filter function that will be passed the array
of parsed columns. Return None if no filter function can be
created for the given params.
The function will compare the column at index `column` against `val`
using the given op where op is one of:
eq: the list `val` exactly matches the list in the column,
has: the list in the column contains the sublist `val`,
"""
if 'eq' == op:
val = self.parse_value( val, 'list' )
return lambda d: d[column] == val
elif 'has' == op:
return lambda d: val in d[column]
return None
def get_default_parsers( self ):
"""
Return parser dictionary keyed for each columnar type
@@ -140,6 +242,39 @@ class ColumnarDataProvider( line.RegexLineDataProvider ):
#'gffstrand': # -, +, ?, or '.' for None, etc.
}
def filter( self, line ):
line = super( ColumnarDataProvider, self ).filter( line )
if line == None:
return line
columns = self.parse_columns_from_line( line )
return self.filter_by_columns( columns )
def parse_columns_from_line( self, line ):
"""
Returns a list of the desired, parsed columns.
:param line: the line to parse
:type line: str
"""
#TODO: too much going on in this loop - the above should all be precomputed AMAP...
all_columns = line.split( self.deliminator )
# if no indeces were passed to init, return all columns
selected_indeces = self.selected_column_indeces or list( xrange( len( all_columns ) ) )
parsed_columns = []
for parser_index, column_index in enumerate( selected_indeces ):
parsed_columns.append( self.parse_column_at_index( all_columns, parser_index, column_index ) )
return parsed_columns
def parse_column_at_index( self, columns, parser_index, index ):
"""
Get the column type for the parser from `self.column_types` or `None`
if the type is unavailable.
"""
try:
return self.parse_value( columns[ index ], self.get_column_type( parser_index ) )
# if a selected index is not within columns, return None
except IndexError, index_err:
return None
def parse_value( self, val, type ):
"""
Attempt to parse and return the given value based on the given type.
@@ -173,51 +308,11 @@ class ColumnarDataProvider( line.RegexLineDataProvider ):
except IndexError, ind_err:
return None
def parse_column_at_index( self, columns, parser_index, index ):
"""
Get the column type for the parser from `self.column_types` or `None`
if the type is unavailable.
"""
try:
return self.parse_value( columns[ index ], self.get_column_type( parser_index ) )
# if a selected index is not within columns, return None
except IndexError, index_err:
return None
def parse_columns_from_line( self, line ):
"""
Returns a list of the desired, parsed columns.
:param line: the line to parse
:type line: str
"""
#TODO: too much going on in this loop - the above should all be precomputed AMAP...
all_columns = line.split( self.deliminator )
# if no indeces were passed to init, return all columns
selected_indeces = self.selected_column_indeces or list( xrange( len( all_columns ) ) )
parsed_columns = []
for parser_index, column_index in enumerate( selected_indeces ):
parsed_columns.append( self.parse_column_at_index( all_columns, parser_index, column_index ) )
return parsed_columns
def __iter__( self ):
parent_gen = super( ColumnarDataProvider, self ).__iter__()
for line in parent_gen:
columns = self.parse_columns_from_line( line )
yield columns
#TODO: implement column filters here and not below - flatten hierarchy
class FilteredByColumnDataProvider( ColumnarDataProvider ):
"""
Data provider that provide a list of columns from the lines of its source
_only_ if they pass a given filter function.
e.g. column #3 is type int and > N
"""
# TODO: how to do this and still have limit and offset work?
def __init__( self, source, **kwargs ):
raise NotImplementedError()
super( FilteredByColumnDataProvider, self ).__init__( source, **kwargs )
def filter_by_columns( self, columns ):
for filter_fn in self.column_filters:
if not filter_fn( columns ):
return None
return columns
class DictDataProvider( ColumnarDataProvider ):
@@ -7,7 +7,7 @@ try:
except ImportError:
# Not in Galaxy, map Galaxy job states to Pulsar ones.
from galaxy.util import enum
job_states = enum(RUNNING='running', OK='complete', QUEUED='queued')
job_states = enum(RUNNING='running', OK='complete', QUEUED='queued', ERROR="failed")
from ..job import BaseJobExec
@@ -59,10 +59,10 @@ class Slurm(BaseJobExec):
return 'scancel %s' % job_id
def get_status(self, job_ids=None):
return 'squeue -a -o \\"%A %t\\"'
return "squeue -a -o '%A %t'"
def get_single_status(self, job_id):
return 'squeue -a -o \\"%A %t\\" -j ' + job_id
return "squeue -a -o '%A %t' -j " + job_id
def parse_status(self, status, job_ids):
# Get status for each job, skipping header.
@@ -80,6 +80,7 @@ class Slurm(BaseJobExec):
# Job still on cluster and has state.
id, state = status[1].split()
return self._get_job_state(state)
# else line like "slurm_load_jobs error: Invalid job id specified"
return job_states.OK
def _get_job_state(self, state):
+55 -12
View File
@@ -199,6 +199,42 @@ class UserManager( base.ModelManager, deletable.PurgableManagerMixin ):
#TODO: use quota manager
return self.app.quota_agent.get_percent( user=user )
def tags_used( self, trans, user, tag_models=None ):
"""
Return a list of distinct 'user_tname:user_value' strings that the
given user has used.
"""
#TODO: simplify and unify with tag manager
if self.is_anonymous( user ):
return []
# get all the taggable model TagAssociations
if not tag_models:
tag_models = [ v.tag_assoc_class for v in self.app.tag_handler.item_tag_assoc_info.values() ]
# create a union of subqueries for each for this user - getting only the tname and user_value
all_tags_query = None
for tag_model in tag_models:
subq = ( self.app.model.context.query( tag_model.user_tname, tag_model.user_value )
.filter( tag_model.user == trans.user ) )
all_tags_query = subq if all_tags_query is None else all_tags_query.union( subq )
# if nothing init'd the query, bail
if all_tags_query is None:
return []
# boil the tag tuples down into a sorted list of DISTINCT name:val strings
tags = all_tags_query.distinct().all()
tags = [( ( name + ':' + val ) if val else name ) for name, val in tags ]
return sorted( tags )
def has_requests( self, trans, user ):
"""
"""
if self.is_anonymous( user ):
return False
request_types = self.app.security_agent.get_accessible_request_types( trans, user )
return ( user.requests or request_types )
class UserSerializer( base.ModelSerializer, deletable.PurgableSerializerMixin ):
@@ -214,21 +250,22 @@ class UserSerializer( base.ModelSerializer, deletable.PurgableSerializerMixin ):
'id', 'email', 'username'
])
self.add_view( 'detailed', [
'update_time',
'create_time',
'deleted',
'purged',
'active',
#'update_time',
#'create_time',
'total_disk_usage',
'nice_total_disk_usage',
'quota_percent'
# 'preferences',
# # all tags
# 'tags',
# # all annotations
# 'annotations'
#'deleted',
#'purged',
#'active',
#'preferences',
# all tags
'tags_used',
## all annotations
#'annotations'
], include_keys_from='summary' )
def add_serializers( self ):
@@ -240,7 +277,13 @@ class UserSerializer( base.ModelSerializer, deletable.PurgableSerializerMixin ):
'create_time' : self.serialize_date,
'update_time' : self.serialize_date,
'is_admin' : lambda t, i, k: self.user_manager.is_admin( t, i ),
'quota_percent' : lambda t, i, k: self.user_manager.quota( t, i )
'total_disk_usage' : lambda t, i, k: float( i.total_disk_usage ),
'quota_percent' : lambda t, i, k: self.user_manager.quota( t, i ),
'tags_used' : lambda t, i, k: self.user_manager.tags_used( t, i ),
#TODO: 'has_requests' is more apt
'requests' : lambda t, i, k: self.user_manager.has_requests( t, i )
})
def serialize_current_anonymous_user( self, trans, user, keys ):
+1 -2
View File
@@ -2250,13 +2250,12 @@ class Tool( object, Dictifiable ):
return tool_dict
def to_json (self, trans, **kwd):
def to_json (self, trans, kwd={}, is_dynamic=True):
"""
Recursively creates a tool dictionary containing repeats, dynamic options and updated states.
"""
job_id = kwd.get('__job_id__', None)
dataset_id = kwd.get('__dataset_id__', None)
is_dynamic = string_as_bool(kwd.get('__is_dynamic__', True))
# load job details if provided
job = None
+2
View File
@@ -1618,6 +1618,8 @@ class DrillDownSelectToolParameter( SelectToolParameter ):
return UnvalidatedValue( None )
initial_values = []
recurse_options( initial_values, self.get_options( trans=trans, other_values=context ) )
if len( initial_values ) == 0:
initial_values = None
return initial_values
def value_to_display_text( self, value, app ):
+1
View File
@@ -19,6 +19,7 @@ from framework.decorators import _future_expose_api_anonymous
from framework.decorators import _future_expose_api_raw
from framework.decorators import _future_expose_api_raw_anonymous
from framework.decorators import _future_expose_api_anonymous_and_sessionless
from framework.decorators import _future_expose_api_raw_anonymous_and_sessionless
from framework.formbuilder import form
from framework.formbuilder import FormBuilder
+3
View File
@@ -344,3 +344,6 @@ def _future_expose_api_raw( func ):
def _future_expose_api_raw_anonymous( func ):
return _future_expose_api( func, to_json=False, user_required=False )
def _future_expose_api_raw_anonymous_and_sessionless( func ):
return _future_expose_api( func, to_json=False, user_required=False, user_or_session_required=False )
+4 -4
View File
@@ -8,8 +8,8 @@ from galaxy import exceptions
from galaxy import util
from galaxy import model
from galaxy.web.base.controller import BaseAPIController
from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous
from galaxy.web import _future_expose_api_raw_anonymous as expose_api_raw_anonymous
from galaxy.web import _future_expose_api_anonymous_and_sessionless as expose_api_anonymous_and_sessionless
from galaxy.web import _future_expose_api_raw_anonymous_and_sessionless as expose_api_raw_anonymous_and_sessionless
import logging
@@ -28,7 +28,7 @@ class JobFilesAPIController( BaseAPIController ):
security model for tool execution.
"""
@expose_api_raw_anonymous
@expose_api_raw_anonymous_and_sessionless
def index( self, trans, job_id, **kwargs ):
"""
index( self, trans, job_id, **kwargs )
@@ -54,7 +54,7 @@ class JobFilesAPIController( BaseAPIController ):
path = kwargs.get("path", None)
return open(path, 'rb')
@expose_api_anonymous
@expose_api_anonymous_and_sessionless
def create( self, trans, job_id, payload, **kwargs ):
"""
create( self, trans, job_id, payload, **kwargs )
+3 -7
View File
@@ -76,14 +76,10 @@ class ToolsController( BaseAPIController, UsesVisualizationMixin ):
GET /api/tools/{tool_id}/build
Returns a tool model including dynamic parameters and updated values, repeats block etc.
"""
tool_id = urllib.unquote_plus( id )
tool_version = kwd.get( 'tool_version', None )
tool = self.app.toolbox.get_tool( tool_id, tool_version )
if not tool:
trans.response.status = 500
return { 'error': 'Could not find tool with id \'%s\'' % tool_id }
return tool.to_json(trans, **kwd)
tool = self._get_tool( id, tool_version=tool_version, user=trans.user )
return tool.to_json(trans, kwd)
@_future_expose_api
@web.require_admin
def reload( self, trans, tool_id, **kwd ):
@@ -6,6 +6,8 @@ from __future__ import absolute_import
import uuid
import logging
import copy
import urllib
from sqlalchemy import desc, or_, and_
from galaxy import exceptions, util
from galaxy.model.item_attrs import UsesAnnotations
@@ -17,6 +19,7 @@ from galaxy.web.base.controller import SharableMixin
from galaxy.workflow.extract import extract_workflow
from galaxy.workflow.run import invoke, queue_invoke
from galaxy.workflow.run_request import build_workflow_run_config
from galaxy.workflow.modules import module_factory
log = logging.getLogger(__name__)
@@ -305,6 +308,52 @@ class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin, UsesAnn
raise exceptions.RequestParameterInvalidException( message )
return self.workflow_contents_manager.workflow_to_dict( trans, stored_workflow, style="instance" )
@expose_api
def build_module( self, trans, payload={}):
"""
POST /api/workflows/build_module
Builds module details including a tool model for the workflow editor.
"""
tool_id = payload.get( 'tool_id', None )
tool_version = payload.get( 'tool_version', None )
tool_inputs = payload.get( 'inputs', None )
annotation = payload.get( 'annotation', '' )
# load tool
tool = self._get_tool( tool_id, tool_version=tool_version, user=trans.user )
# initialize module
trans.workflow_building_mode = True
module = module_factory.from_dict( trans, {
'type' : 'tool',
'tool_id' : tool.id,
'tool_state' : None
} )
# create tool model and default tool state (if missing)
tool_model = module.tool.to_json(trans, tool_inputs, is_dynamic=False)
module.state.inputs = copy.deepcopy(tool_model['state_inputs'])
return {
'tool_model' : tool_model,
'tool_state' : module.get_state(),
'data_inputs' : module.get_data_inputs(),
'data_outputs' : module.get_data_outputs(),
'tool_errors' : module.get_errors(),
'form_html' : module.get_config_form(),
'annotation' : annotation,
'post_job_actions' : module.get_post_job_actions(tool_inputs)
}
#
# -- Helper methods --
#
def _get_tool( self, id, tool_version=None, user=None ):
id = urllib.unquote_plus( id )
tool = self.app.toolbox.get_tool( id, tool_version )
if not tool or not tool.allow_user_access( user ):
raise exceptions.ObjectNotFound("Could not find tool with id '%s'" % id)
return tool
def __api_import_new_workflow( self, trans, payload, **kwd ):
data = payload['workflow']
+1
View File
@@ -217,6 +217,7 @@ def populate_api_routes( webapp, app ):
webapp.mapper.resource_with_deleted( 'user', 'users', path_prefix='/api' )
webapp.mapper.resource( 'genome', 'genomes', path_prefix='/api' )
webapp.mapper.resource( 'visualization', 'visualizations', path_prefix='/api' )
webapp.mapper.connect( '/api/workflows/build_module', action='build_module', controller="workflows" )
webapp.mapper.resource( 'workflow', 'workflows', path_prefix='/api' )
webapp.mapper.resource_with_deleted( 'history', 'histories', path_prefix='/api' )
webapp.mapper.connect( '/api/histories/{history_id}/citations', action='citations', controller="histories" )
@@ -609,7 +609,6 @@ class WorkflowController( BaseUIController, SharableMixin, UsesStoredWorkflowMix
This is used for the form shown in the right pane when a node
is selected.
"""
tool_state = incoming.pop('tool_state', None)
trans.workflow_building_mode = True
module = module_factory.from_dict( trans, {
@@ -617,22 +616,7 @@ class WorkflowController( BaseUIController, SharableMixin, UsesStoredWorkflowMix
'tool_id': tool_id,
'tool_state': tool_state
} )
# create tool model and default tool state (if missing)
if type == 'tool' and not tool_state:
tool_model = module.tool.to_json(trans, **incoming)
module.state.inputs = copy.deepcopy(tool_model['state_inputs'])
return {
'tool_model': tool_model,
'tool_state': module.get_state(),
'data_inputs': module.get_data_inputs(),
'data_outputs': module.get_data_outputs(),
'tool_errors': module.get_errors(),
'form_html': module.get_config_form(),
'annotation': annotation,
'post_job_actions': module.get_post_job_actions(incoming)
}
# update module state
module.update_state( incoming )
@@ -669,7 +653,8 @@ class WorkflowController( BaseUIController, SharableMixin, UsesStoredWorkflowMix
module = module_factory.new( trans, type, **kwargs )
tool_model = None
if type == 'tool':
tool_model = module.tool.to_json(trans)
tool_model = module.tool.to_json(trans, is_dynamic=False)
module.state.inputs = copy.deepcopy(tool_model['state_inputs'])
return {
'type': module.type,
'name': module.get_name(),
@@ -275,10 +275,16 @@ define(['utils/utils', 'mvc/tools/tools-form-base'],
/** Request a new model for an already created tool form and updates the form inputs
*/
_updateModel: function() {
// create the request dictionary
// link self
var self = this;
var current_state = this.tree.finalize();
// create the request dictionary
var current_state = {
tool_id : this.options.id,
tool_version : this.options.version,
inputs : this.tree.finalize()
}
// log tool state
console.debug('tools-form-workflow::_refreshForm() - Refreshing states.');
console.debug(current_state);
@@ -287,11 +293,11 @@ define(['utils/utils', 'mvc/tools/tools-form-base'],
var process_id = this.deferred.register();
// build model url for request
var model_url = galaxy_config.root + 'workflow/editor_form_post?tool_id=' + this.options.id + '&__is_dynamic__=False';
var model_url = galaxy_config.root + 'api/workflows/build_module';
// post job
Utils.request({
type : 'GET',
type : 'POST',
url : model_url,
data : current_state,
success : function(data) {
+1 -2
View File
@@ -34,8 +34,7 @@ define([], function() {
this.field.skip = false;
var v = this.field.value && this.field.value();
this.field.skip = Boolean(options.optional &&
((this.default_value === undefined) ||
((this.field.validate && !this.field.validate()) || !v ||
(((this.field.validate && !this.field.validate()) || !v ||
(v == this.default_value) || (Number(v) == Number(this.default_value)) ||
(JSON.stringify(v) == JSON.stringify(this.default_value)))));
+8 -5
View File
@@ -294,17 +294,20 @@ define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/ui/ui-portlet',
// get id
var id = input_def.id;
// add regular/default value if missing
if (input_def.value === undefined) {
input_def.value = null;
}
if (input_def.default_value === undefined) {
input_def.default_value = input_def.value;
}
// create input field
var field = this._createField(input_def);
// add to field list
this.app.field_list[id] = field;
// fix default value if missing
if (input_def.default_value === undefined) {
input_def.default_value = input_def.value;
}
// create input field wrapper
var input_element = new InputElement(this.app, {
label : input_def.label,
+40 -45
View File
@@ -10,13 +10,13 @@ return Backbone.Model.extend({
initialize: function(app) {
this.app = app;
},
/** Convert dictionary representation into tool api specific flat dictionary format.
*/
finalize: function(patch) {
// link this
var self = this;
// dictionary with api specific identifiers
this.map_dict = {};
@@ -24,24 +24,24 @@ return Backbone.Model.extend({
if (!this.app.section) {
return {};
}
// ensure that dictionary with patching functions exists
patch = patch || {};
// dictionary formatted for job submission or tool form update
var result_dict = {};
// prepare full dictionary
var dict = {};
// fill dictionary from dom
this._iterate(this.app.section.$el, dict);
// add identifier and value to job definition
function add(job_input_id, input_id, input_value) {
// add entry to result dictionary
result_dict[job_input_id] = input_value;
// backup id mapping
self.map_dict[job_input_id] = input_id;
};
@@ -53,21 +53,21 @@ return Backbone.Model.extend({
if (node.input) {
// get node
var input = node.input;
// create identifier
var job_input_id = identifier;
if (identifier != '') {
job_input_id += '|';
}
job_input_id += input.name;
// process input type
switch (input.type) {
// handle repeats
case 'repeat':
// section identifier
var section_label = 'section-';
// collect repeat block identifiers
var block_indices = [];
var block_prefix = null;
@@ -81,10 +81,10 @@ return Backbone.Model.extend({
}
}
}
// sort repeat blocks
block_indices.sort(function(a,b) { return a - b; });
// add to response dictionary in created order
var index = 0;
for (var i in block_indices) {
@@ -98,10 +98,10 @@ return Backbone.Model.extend({
if (patch[input.test_param.type]) {
value = patch[input.test_param.type](value);
}
// add conditional value
add (job_input_id + '|' + input.test_param.name, input.id, value);
// identify selected case
var selectedCase = self.matchCase(input, value);
if (selectedCase != -1) {
@@ -116,22 +116,17 @@ return Backbone.Model.extend({
// get field
var field = self.app.field_list[input.id];
if (field && field.value) {
// get and patch field value
// validate field value
var value = field.value();
if (patch[input.type]) {
value = patch[input.type](value);
}
// validate field value
if (field.skip) {
continue;
}
// validate field value
if (field.validate && !field.validate()) {
value = null;
}
// get and patch field value
if (patch[input.type]) {
value = patch[input.type](value);
}
// ignore certain values
if (input.ignore === undefined || (value !== null && input.ignore != value)) {
// add value to submission
@@ -149,20 +144,20 @@ return Backbone.Model.extend({
}
}
}
// start conversion
convert('', dict);
// return result
return result_dict;
},
/** Match job definition identifier to input element identifier
*/
match: function (job_input_id) {
return this.map_dict && this.map_dict[job_input_id];
},
/** Match conditional values to selected cases
*/
matchCase: function(input, value) {
@@ -174,27 +169,27 @@ return Backbone.Model.extend({
value = input.test_param.falsevalue || 'false';
}
}
// find selected case
for (var i in input.cases) {
if (input.cases[i].value == value) {
return i;
}
}
// selected case not found
return -1;
},
/** Matches identifier from api model to input elements
*/
matchModel: function(model, callback) {
// final result dictionary
var result = {};
// link this
var self = this;
// search throughout response
function search (id, head) {
for (var i in head) {
@@ -224,23 +219,23 @@ return Backbone.Model.extend({
}
}
}
// match all ids and return messages
search('', model.inputs);
// return matched results
return result;
},
/** Matches identifier from api response to input elements
*/
matchResponse: function(response) {
// final result dictionary
var result = {};
// link this
var self = this;
// search throughout response
function search (id, head) {
if (typeof head === 'string') {
@@ -262,14 +257,14 @@ return Backbone.Model.extend({
}
}
}
// match all ids and return messages
search('', response);
// return matched results
return result;
},
/** Iterate through the tool form dom and map it to the dictionary.
*/
_iterate: function(parent, dict) {
@@ -279,15 +274,15 @@ return Backbone.Model.extend({
children.each(function() {
// get child element
var child = this;
// get id
var id = $(child).attr('id');
// create new branch
if ($(child).hasClass('section-row')) {
// create sub dictionary
dict[id] = {};
// add input element if it exists
var input = self.app.input_list[id];
if (input) {
@@ -295,7 +290,7 @@ return Backbone.Model.extend({
input : input
}
}
// fill sub dictionary
self._iterate(child, dict[id]);
} else {
@@ -1 +1 @@
define(["utils/utils","mvc/tools/tools-form-base"],function(b,a){var c=a.extend({initialize:function(e){this.node=workflow.active_node;if(!this.node){console.debug("FAILED - tools-form-workflow:initialize() - Node not found in workflow.");return}this.post_job_actions=this.node.post_job_actions||{};this.options=e;this.options.text_enable="In Advance";this.options.text_disable="At Runtime";this.options.is_dynamic=false;this.options.narrow=true;this.options.initial_errors=true;this.options.cls_portlet="ui-portlet-narrow";b.deepeach(e.inputs,function(f){if(f.type){f.optional=(["data","data_hidden","hidden","drill_down","repeat","conditional"]).indexOf(f.type)==-1}});b.deepeach(e.inputs,function(f){if(f.type){if(f.type=="conditional"){f.test_param.optional=false}}});var d=this;b.get({url:galaxy_config.root+"api/datatypes",cache:true,success:function(f){d.datatypes=f;d._makeSections(e.inputs);a.prototype.initialize.call(d,e)}})},_makeSections:function(d){d[b.uuid()]={label:"Annotation / Notes",name:"annotation",type:"text",area:true,help:"Add an annotation or note for this step. It will be shown with the workflow.",value:this.node.annotation};var f=this.node.output_terminals&&Object.keys(this.node.output_terminals)[0];if(f){d[b.uuid()]={name:"pja__"+f+"__EmailAction",label:"Email notification",type:"boolean",value:String(Boolean(this.post_job_actions["EmailAction"+f])),ignore:"false",help:"An email notification will be send when the job has completed.",payload:{host:window.location.host}};d[b.uuid()]={name:"pja__"+f+"__DeleteIntermediatesAction",label:"Output cleanup",type:"boolean",value:String(Boolean(this.post_job_actions["DeleteIntermediatesAction"+f])),ignore:"false",help:"Delete intermediate outputs if they are not used as input for another job."};for(var e in this.node.output_terminals){d[b.uuid()]=this._makeSection(e)}}},_makeSection:function(h){var g=[];for(key in this.datatypes){g.push({0:this.datatypes[key],1:this.datatypes[key]})}g.sort(function(j,i){return j.label>i.label?1:j.label<i.label?-1:0});g.unshift({0:"Sequences",1:"Sequences"});g.unshift({0:"Roadmaps",1:"Roadmaps"});g.unshift({0:"Leave unchanged",1:""});var f={label:"Add Actions: '"+h+"'",type:"section",inputs:[{action:"RenameDatasetAction",argument:"newname",label:"Rename dataset",type:"text",value:"",ignore:"",help:'This action will rename the result dataset. Click <a href="https://wiki.galaxyproject.org/Learn/AdvancedWorkflow/Variables">here</a> for more information.'},{action:"ChangeDatatypeAction",argument:"newtype",label:"Change datatype",type:"select",ignore:"",options:g,help:"This action will change the datatype of the output to the indicated value."},{action:"TagDatasetAction",argument:"tags",label:"Tags",type:"text",value:"",ignore:"",help:"This action will set tags for the dataset."},{label:"Assign columns",type:"section",inputs:[{action:"ColumnSetAction",argument:"chromCol",label:"Chrom column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"startCol",label:"Start column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"endCol",label:"End column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"strandCol",label:"Strand column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"nameCol",label:"Name column",type:"integer",value:"",ignore:""}],help:"This action will set column assignments in the output dataset. Blank fields are ignored."}]};var d=this;function e(n,o){o=o||[];o.push(n);for(var m in n.inputs){var k=n.inputs[m];if(k.action){k.name="pja__"+h+"__"+k.action;if(k.argument){k.name+="__"+k.argument}if(k.payload){for(var s in k.payload){var q=k.payload[s];k.payload[k.name+"__"+s]=q;delete q}}var r=d.post_job_actions[k.action+h];if(r){for(var l in o){o[l].expand=true}if(k.argument){k.value=r.action_arguments&&r.action_arguments[k.argument]||k.value}else{k.value="true"}}}if(k.inputs){e(k,o.slice(0))}}}e(f);return f},_buildModel:function(){Galaxy.modal.show({title:"Coming soon...",body:"This feature has not been implemented yet.",buttons:{Close:function(){Galaxy.modal.hide()}}})},_updateModel:function(){var d=this;var e=this.tree.finalize();console.debug("tools-form-workflow::_refreshForm() - Refreshing states.");console.debug(e);var g=this.deferred.register();var f=galaxy_config.root+"workflow/editor_form_post?tool_id="+this.options.id+"&__is_dynamic__=False";b.request({type:"GET",url:f,data:e,success:function(h){d.node.update_field_data(h);d._errors(h&&h.tool_model);d.deferred.done(g);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(h)},error:function(h){d.deferred.done(g);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(h)}})}});return{View:c}});
define(["utils/utils","mvc/tools/tools-form-base"],function(b,a){var c=a.extend({initialize:function(e){this.node=workflow.active_node;if(!this.node){console.debug("FAILED - tools-form-workflow:initialize() - Node not found in workflow.");return}this.post_job_actions=this.node.post_job_actions||{};this.options=e;this.options.text_enable="In Advance";this.options.text_disable="At Runtime";this.options.is_dynamic=false;this.options.narrow=true;this.options.initial_errors=true;this.options.cls_portlet="ui-portlet-narrow";b.deepeach(e.inputs,function(f){if(f.type){f.optional=(["data","data_hidden","hidden","drill_down","repeat","conditional"]).indexOf(f.type)==-1}});b.deepeach(e.inputs,function(f){if(f.type){if(f.type=="conditional"){f.test_param.optional=false}}});var d=this;b.get({url:galaxy_config.root+"api/datatypes",cache:true,success:function(f){d.datatypes=f;d._makeSections(e.inputs);a.prototype.initialize.call(d,e)}})},_makeSections:function(d){d[b.uuid()]={label:"Annotation / Notes",name:"annotation",type:"text",area:true,help:"Add an annotation or note for this step. It will be shown with the workflow.",value:this.node.annotation};var f=this.node.output_terminals&&Object.keys(this.node.output_terminals)[0];if(f){d[b.uuid()]={name:"pja__"+f+"__EmailAction",label:"Email notification",type:"boolean",value:String(Boolean(this.post_job_actions["EmailAction"+f])),ignore:"false",help:"An email notification will be send when the job has completed.",payload:{host:window.location.host}};d[b.uuid()]={name:"pja__"+f+"__DeleteIntermediatesAction",label:"Output cleanup",type:"boolean",value:String(Boolean(this.post_job_actions["DeleteIntermediatesAction"+f])),ignore:"false",help:"Delete intermediate outputs if they are not used as input for another job."};for(var e in this.node.output_terminals){d[b.uuid()]=this._makeSection(e)}}},_makeSection:function(h){var g=[];for(key in this.datatypes){g.push({0:this.datatypes[key],1:this.datatypes[key]})}g.sort(function(j,i){return j.label>i.label?1:j.label<i.label?-1:0});g.unshift({0:"Sequences",1:"Sequences"});g.unshift({0:"Roadmaps",1:"Roadmaps"});g.unshift({0:"Leave unchanged",1:""});var f={label:"Add Actions: '"+h+"'",type:"section",inputs:[{action:"RenameDatasetAction",argument:"newname",label:"Rename dataset",type:"text",value:"",ignore:"",help:'This action will rename the result dataset. Click <a href="https://wiki.galaxyproject.org/Learn/AdvancedWorkflow/Variables">here</a> for more information.'},{action:"ChangeDatatypeAction",argument:"newtype",label:"Change datatype",type:"select",ignore:"",options:g,help:"This action will change the datatype of the output to the indicated value."},{action:"TagDatasetAction",argument:"tags",label:"Tags",type:"text",value:"",ignore:"",help:"This action will set tags for the dataset."},{label:"Assign columns",type:"section",inputs:[{action:"ColumnSetAction",argument:"chromCol",label:"Chrom column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"startCol",label:"Start column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"endCol",label:"End column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"strandCol",label:"Strand column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"nameCol",label:"Name column",type:"integer",value:"",ignore:""}],help:"This action will set column assignments in the output dataset. Blank fields are ignored."}]};var d=this;function e(n,o){o=o||[];o.push(n);for(var m in n.inputs){var k=n.inputs[m];if(k.action){k.name="pja__"+h+"__"+k.action;if(k.argument){k.name+="__"+k.argument}if(k.payload){for(var s in k.payload){var q=k.payload[s];k.payload[k.name+"__"+s]=q;delete q}}var r=d.post_job_actions[k.action+h];if(r){for(var l in o){o[l].expand=true}if(k.argument){k.value=r.action_arguments&&r.action_arguments[k.argument]||k.value}else{k.value="true"}}}if(k.inputs){e(k,o.slice(0))}}}e(f);return f},_buildModel:function(){Galaxy.modal.show({title:"Coming soon...",body:"This feature has not been implemented yet.",buttons:{Close:function(){Galaxy.modal.hide()}}})},_updateModel:function(){var d=this;var e={tool_id:this.options.id,tool_version:this.options.version,inputs:this.tree.finalize()};console.debug("tools-form-workflow::_refreshForm() - Refreshing states.");console.debug(e);var g=this.deferred.register();var f=galaxy_config.root+"api/workflows/build_module";b.request({type:"POST",url:f,data:e,success:function(h){d.node.update_field_data(h);d._errors(h&&h.tool_model);d.deferred.done(g);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(h)},error:function(h){d.deferred.done(g);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(h)}})}});return{View:c}});
@@ -1 +1 @@
define([],function(){return Backbone.View.extend({initialize:function(d,c){this.app=d;this.text_enable=d.options.text_enable||"Enable";this.text_disable=d.options.text_disable||"Disable";this.field=c.field;this.default_value=c.default_value;this.setElement(this._template(c));this.$field=this.$el.find(".ui-table-form-field");this.$title_optional=this.$el.find(".ui-table-form-title-optional");this.$error_text=this.$el.find(".ui-table-form-error-text");this.$error=this.$el.find(".ui-table-form-error");this.$field.prepend(this.field.$el);this.field.skip=false;var b=this.field.value&&this.field.value();this.field.skip=Boolean(c.optional&&((this.default_value===undefined)||((this.field.validate&&!this.field.validate())||!b||(b==this.default_value)||(Number(b)==Number(this.default_value))||(JSON.stringify(b)==JSON.stringify(this.default_value)))));this._refresh();var a=this;this.$title_optional.on("click",function(){a.field.skip=!a.field.skip;a._refresh()})},error:function(a){this.$error_text.html(a);this.$error.show();this.$el.addClass("ui-error")},reset:function(){this.$error.hide();this.$el.removeClass("ui-error")},_refresh:function(){if(!this.field.skip){this.$field.fadeIn("fast");this.$title_optional.html(this.text_disable)}else{this.reset();this.$field.hide();this.$title_optional.html(this.text_enable);this.field.value&&this.field.value(this.default_value)}this.app.trigger("refresh")},_template:function(a){var b='<div class="ui-table-form-element"><div class="ui-table-form-error ui-error"><span class="fa fa-arrow-down"/><span class="ui-table-form-error-text"/></div><div class="ui-table-form-title-strong">';if(a.optional){b+=a.label+'<span>&nbsp[<span class="ui-table-form-title-optional"/>]</span>'}else{b+=a.label}b+='</div><div class="ui-table-form-field">';if(a.help){b+='<div class="ui-table-form-info">'+a.help+"</div>"}b+="</div></div>";return b}})});
define([],function(){return Backbone.View.extend({initialize:function(d,c){this.app=d;this.text_enable=d.options.text_enable||"Enable";this.text_disable=d.options.text_disable||"Disable";this.field=c.field;this.default_value=c.default_value;this.setElement(this._template(c));this.$field=this.$el.find(".ui-table-form-field");this.$title_optional=this.$el.find(".ui-table-form-title-optional");this.$error_text=this.$el.find(".ui-table-form-error-text");this.$error=this.$el.find(".ui-table-form-error");this.$field.prepend(this.field.$el);this.field.skip=false;var b=this.field.value&&this.field.value();this.field.skip=Boolean(c.optional&&(((this.field.validate&&!this.field.validate())||!b||(b==this.default_value)||(Number(b)==Number(this.default_value))||(JSON.stringify(b)==JSON.stringify(this.default_value)))));this._refresh();var a=this;this.$title_optional.on("click",function(){a.field.skip=!a.field.skip;a._refresh()})},error:function(a){this.$error_text.html(a);this.$error.show();this.$el.addClass("ui-error")},reset:function(){this.$error.hide();this.$el.removeClass("ui-error")},_refresh:function(){if(!this.field.skip){this.$field.fadeIn("fast");this.$title_optional.html(this.text_disable)}else{this.reset();this.$field.hide();this.$title_optional.html(this.text_enable);this.field.value&&this.field.value(this.default_value)}this.app.trigger("refresh")},_template:function(a){var b='<div class="ui-table-form-element"><div class="ui-table-form-error ui-error"><span class="fa fa-arrow-down"/><span class="ui-table-form-error-text"/></div><div class="ui-table-form-title-strong">';if(a.optional){b+=a.label+'<span>&nbsp[<span class="ui-table-form-title-optional"/>]</span>'}else{b+=a.label}b+='</div><div class="ui-table-form-field">';if(a.help){b+='<div class="ui-table-form-info">'+a.help+"</div>"}b+="</div></div>";return b}})});
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
define(["utils/utils"],function(a){return Backbone.Model.extend({initialize:function(b){this.app=b},finalize:function(g){var b=this;this.map_dict={};if(!this.app.section){return{}}g=g||{};var f={};var e={};this._iterate(this.app.section.$el,e);function d(j,i,h){f[j]=h;b.map_dict[j]=i}function c(p,s){for(var n in s){var k=s[n];if(k.input){var u=k.input;var o=p;if(p!=""){o+="|"}o+=u.name;switch(u.type){case"repeat":var j="section-";var x=[];var r=null;for(var w in k){var q=w.indexOf(j);if(q!=-1){q+=j.length;x.push(parseInt(w.substr(q)));if(!r){r=w.substr(0,q)}}}x.sort(function(y,i){return y-i});var n=0;for(var l in x){c(o+"_"+n++,k[r+x[l]])}break;case"conditional":var v=b.app.field_list[u.id].value();if(g[u.test_param.type]){v=g[u.test_param.type](v)}d(o+"|"+u.test_param.name,u.id,v);var h=b.matchCase(u,v);if(h!=-1){c(o,s[u.id+"-section-"+h])}break;case"section":c("",k);break;default:var t=b.app.field_list[u.id];if(t&&t.value){var v=t.value();if(g[u.type]){v=g[u.type](v)}if(t.skip){continue}if(t.validate&&!t.validate()){v=null}if(u.ignore===undefined||(v!==null&&u.ignore!=v)){d(o,u.id,v);if(u.payload){for(var m in u.payload){d(m,u.id,u.payload[m])}}}}}}}}c("",e);return f},match:function(b){return this.map_dict&&this.map_dict[b]},matchCase:function(b,d){if(b.test_param.type=="boolean"){if(d=="true"){d=b.test_param.truevalue||"true"}else{d=b.test_param.falsevalue||"false"}}for(var c in b.cases){if(b.cases[c].value==d){return c}}return -1},matchModel:function(d,f){var b={};var c=this;function e(g,p){for(var m in p){var k=p[m];var n=k.name;if(g!=""){n=g+"|"+n}switch(k.type){case"repeat":for(var l in k.cache){e(n+"_"+l,k.cache[l])}break;case"conditional":var q=k.test_param&&k.test_param.value;var h=c.matchCase(k,q);if(h!=-1){e(n,k.cases[h].inputs)}break;default:var o=c.map_dict[n];if(o){f(o,k)}}}}e("",d.inputs);return b},matchResponse:function(d){var b={};var c=this;function e(l,j){if(typeof j==="string"){var g=c.map_dict[l];if(g){b[g]=j}}else{for(var h in j){var f=h;if(l!==""){var k="|";if(j instanceof Array){k="_"}f=l+k+f}e(f,j[h])}}}e("",d);return b},_iterate:function(d,e){var b=this;var c=$(d).children();c.each(function(){var h=this;var g=$(h).attr("id");if($(h).hasClass("section-row")){e[g]={};var f=b.app.input_list[g];if(f){e[g]={input:f}}b._iterate(h,e[g])}else{b._iterate(h,e)}})}})});
define(["utils/utils"],function(a){return Backbone.Model.extend({initialize:function(b){this.app=b},finalize:function(g){var b=this;this.map_dict={};if(!this.app.section){return{}}g=g||{};var f={};var e={};this._iterate(this.app.section.$el,e);function d(j,i,h){f[j]=h;b.map_dict[j]=i}function c(p,s){for(var n in s){var k=s[n];if(k.input){var u=k.input;var o=p;if(p!=""){o+="|"}o+=u.name;switch(u.type){case"repeat":var j="section-";var x=[];var r=null;for(var w in k){var q=w.indexOf(j);if(q!=-1){q+=j.length;x.push(parseInt(w.substr(q)));if(!r){r=w.substr(0,q)}}}x.sort(function(y,i){return y-i});var n=0;for(var l in x){c(o+"_"+n++,k[r+x[l]])}break;case"conditional":var v=b.app.field_list[u.id].value();if(g[u.test_param.type]){v=g[u.test_param.type](v)}d(o+"|"+u.test_param.name,u.id,v);var h=b.matchCase(u,v);if(h!=-1){c(o,s[u.id+"-section-"+h])}break;case"section":c("",k);break;default:var t=b.app.field_list[u.id];if(t&&t.value){var v=t.value();if(t.validate&&!t.validate()){v=null}if(g[u.type]){v=g[u.type](v)}if(u.ignore===undefined||(v!==null&&u.ignore!=v)){d(o,u.id,v);if(u.payload){for(var m in u.payload){d(m,u.id,u.payload[m])}}}}}}}}c("",e);return f},match:function(b){return this.map_dict&&this.map_dict[b]},matchCase:function(b,d){if(b.test_param.type=="boolean"){if(d=="true"){d=b.test_param.truevalue||"true"}else{d=b.test_param.falsevalue||"false"}}for(var c in b.cases){if(b.cases[c].value==d){return c}}return -1},matchModel:function(d,f){var b={};var c=this;function e(g,p){for(var m in p){var k=p[m];var n=k.name;if(g!=""){n=g+"|"+n}switch(k.type){case"repeat":for(var l in k.cache){e(n+"_"+l,k.cache[l])}break;case"conditional":var q=k.test_param&&k.test_param.value;var h=c.matchCase(k,q);if(h!=-1){e(n,k.cases[h].inputs)}break;default:var o=c.map_dict[n];if(o){f(o,k)}}}}e("",d.inputs);return b},matchResponse:function(d){var b={};var c=this;function e(l,j){if(typeof j==="string"){var g=c.map_dict[l];if(g){b[g]=j}}else{for(var h in j){var f=h;if(l!==""){var k="|";if(j instanceof Array){k="_"}f=l+k+f}e(f,j[h])}}}e("",d);return b},_iterate:function(d,e){var b=this;var c=$(d).children();c.each(function(){var h=this;var g=$(h).attr("id");if($(h).hasClass("section-row")){e[g]={};var f=b.app.input_list[g];if(f){e[g]={input:f}}b._iterate(h,e[g])}else{b._iterate(h,e)}})}})});
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -34,7 +34,7 @@ function MetricsLogger( options ){
var self = this;
///** get the current user's id from bootstrapped data or options */
self.userId = window.bootstrapped? window.bootstrapped.user.id: null;
self.userId = ( window.bootstrapped && window.bootstrapped.user )? window.bootstrapped.user.id: null;
self.userId = self.userId || options.userId || null;
/** the (optional) console to emit logs to */
+1 -1
View File
@@ -10,7 +10,7 @@ ${h.css('base', 'jquery-ui/smoothness/jquery-ui')}
## This avoids making two separate requests since the classic form requires the mako anyway.
params = dict(trans.request.params)
params['__dataset_id__'] = params.get('id', None)
self.form_config = tool.to_json(trans, **params)
self.form_config = tool.to_json(trans, params)
self.form_config.update({
'id' : tool.id,
'job_id' : trans.security.encode_id( job.id ) if job else None,
@@ -6,11 +6,9 @@
## TEMPORARY: create tool dictionary in mako while both tool forms are in use.
## This avoids making two separate requests since the classic form requires the mako anyway.
from galaxy.tools.parameters import params_to_incoming
incoming = {
'__is_dynamic__' : False
}
incoming = {}
params_to_incoming( incoming, tool.inputs, module.state.inputs, trans.app, to_html=False)
self.form_config = tool.to_json(trans, **incoming)
self.form_config = tool.to_json(trans, incoming, is_dynamic=False)
self.form_config.update({
'id' : tool.id,
'job_id' : trans.security.encode_id( job.id ) if job else None,