details: http://www.bx.psu.edu/hg/galaxy/rev/397800eff312 changeset: 2546:397800eff312 user: Kanwei Li <kanwei@gmail.com> date: Thu Aug 06 15:25:18 2009 -0400 description: Merging trunk 7 file(s) affected in this change: templates/base_panels.mako templates/dataset/errors.tmpl templates/dataset/validation.tmpl templates/requests/select_request_type.mako test-data/s2fq_out1.tabular test-data/s2fq_out2.tabular test-data/s2fq_out3.tabular diffs (truncated from 6105 to 3000 lines): diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py Thu Aug 06 15:19:02 2009 -0400 +++ b/lib/galaxy/model/__init__.py Thu Aug 06 15:25:18 2009 -0400 @@ -1121,15 +1121,18 @@ self.content = content class Request( object ): + states = Bunch( UNSUBMITTED = 'Unsubmitted', + SUBMITTED = 'Submitted', + COMPLETE = 'Complete') def __init__(self, name=None, desc=None, request_type=None, user=None, - form_values=None, library=None, submitted=False): + form_values=None, library=None, state=False): self.name = name self.desc = desc self.type = request_type self.values = form_values self.user = user self.library = library - self.submitted = submitted + self.state = state self.samples_list = [] def add_sample(self, sample_name=None, sample_desc=None, sample_values=None): # create a form_values row @@ -1151,6 +1154,18 @@ if s.name == sample_name: return s return False + def submitted(self): + if self.state == self.states.SUBMITTED: + return True + return False + def unsubmitted(self): + if self.state == self.states.UNSUBMITTED: + return True + return False + def complete(self): + if self.state == self.states.COMPLETE: + return True + return False class RequestType( object ): def __init__(self, name=None, desc=None, request_form=None, sample_form=None): @@ -1160,12 +1175,12 @@ self.sample_form = sample_form class Sample( object ): - def __init__(self, name=None, desc=None, request=None, form_values=None): + def __init__(self, name=None, desc=None, request=None, form_values=None, bar_code=None): self.name = name self.desc = desc self.request = request self.values = form_values - + self.bar_code = bar_code def current_state(self): return self.events[0].state @@ -1180,6 +1195,37 @@ self.sample = sample self.state = sample_state self.comment = comment + +class UserAddress( object ): + def __init__(self, user=None, desc=None, name=None, institution=None, + address=None, city=None, state=None, postal_code=None, + country=None, phone=None): + self.user = user + self.desc = desc + self.name = name + self.institution = institution + self.address = address + self.city = city + self.state = state + self.postal_code = postal_code + self.country = country + self.phone = phone + def display(self): + return self.name+'<br/>'+ \ + self.institution+'<br/>'+ \ + self.address+'<br/>'+ \ + self.city+' '+self.state+' '+self.postal_code+'<br/>'+ \ + self.country+'<br/>'+ \ + 'Phone: '+self.phone + def get_html(self): + return self.name+'<br/>'+ \ + self.institution+'<br/>'+ \ + self.address+'<br/>'+ \ + self.city+' '+self.state+' '+self.postal_code+'<br/>'+ \ + self.country+'<br/>'+ \ + 'Phone: '+self.phone + + diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/model/mapping.py --- a/lib/galaxy/model/mapping.py Thu Aug 06 15:19:02 2009 -0400 +++ b/lib/galaxy/model/mapping.py Thu Aug 06 15:25:18 2009 -0400 @@ -46,7 +46,24 @@ Column( "external", Boolean, default=False ), Column( "deleted", Boolean, index=True, default=False ), Column( "purged", Boolean, index=True, default=False ) ) - + +UserAddress.table = Table( "user_address", metadata, + Column( "id", Integer, primary_key=True), + Column( "create_time", DateTime, default=now ), + Column( "update_time", DateTime, default=now, onupdate=now ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "desc", TrimmedString( 255 )), + Column( "name", TrimmedString( 255 ), nullable=False), + Column( "institution", TrimmedString( 255 )), + Column( "address", TrimmedString( 255 ), nullable=False), + Column( "city", TrimmedString( 255 ), nullable=False), + Column( "state", TrimmedString( 255 ), nullable=False), + Column( "postal_code", TrimmedString( 255 ), nullable=False), + Column( "country", TrimmedString( 255 ), nullable=False), + Column( "phone", TrimmedString( 255 )), + Column( "deleted", Boolean, index=True, default=False ), + Column( "purged", Boolean, index=True, default=False ) ) + History.table = Table( "history", metadata, Column( "id", Integer, primary_key=True), Column( "create_time", DateTime, default=now ), @@ -558,7 +575,8 @@ Column( "name", TrimmedString( 255 ), nullable=False ), Column( "desc", TEXT ), Column( "request_form_id", Integer, ForeignKey( "form_definition.id" ), index=True ), - Column( "sample_form_id", Integer, ForeignKey( "form_definition.id" ), index=True ) ) + Column( "sample_form_id", Integer, ForeignKey( "form_definition.id" ), index=True ), + Column( "deleted", Boolean, index=True, default=False ) ) FormValues.table = Table('form_values', metadata, Column( "id", Integer, primary_key=True), @@ -577,8 +595,15 @@ Column( "request_type_id", Integer, ForeignKey( "request_type.id" ), index=True ), Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), Column( "library_id", Integer, ForeignKey( "library.id" ), index=True ), - Column( "submitted", Boolean, index=True, default=False ), + Column( "state", TrimmedString( 255 ), index=True ), Column( "deleted", Boolean, index=True, default=False ) ) + +RequestState_table = Table('request_state', metadata, + Column( "id", Integer, primary_key=True), + Column( "create_time", DateTime, default=now ), + Column( "update_time", DateTime, default=now, onupdate=now ), + Column( "name", TrimmedString( 255 ), nullable=False ), + Column( "desc", TEXT )) Sample.table = Table('sample', metadata, Column( "id", Integer, primary_key=True), @@ -615,13 +640,14 @@ # relationships between the model objects. assign_mapper( context, Sample, Sample.table, - properties=dict( events=relation( SampleEvent, backref="sample", - order_by=desc(SampleEvent.table.c.update_time) ), - values=relation( FormValues, - primaryjoin=( Sample.table.c.form_values_id == FormValues.table.c.id ) ), - request=relation( Request, - primaryjoin=( Sample.table.c.request_id == Request.table.c.id ) ), - ) ) + properties=dict( + events=relation( SampleEvent, backref="sample", + order_by=desc(SampleEvent.table.c.update_time) ), + values=relation( FormValues, + primaryjoin=( Sample.table.c.form_values_id == FormValues.table.c.id ) ), + request=relation( Request, + primaryjoin=( Sample.table.c.request_id == Request.table.c.id ) ), + ) ) assign_mapper( context, FormValues, FormValues.table, properties=dict( form_definition=relation( FormDefinition, @@ -673,6 +699,15 @@ assign_mapper( context, SampleState, SampleState.table, properties=None ) + +assign_mapper( context, UserAddress, UserAddress.table, + properties=dict( + user=relation( User, + primaryjoin=( UserAddress.table.c.user_id == User.table.c.id ), + backref='addresses', + order_by=desc(UserAddress.table.c.update_time)), + ) ) + assign_mapper( context, ValidationError, ValidationError.table ) @@ -749,7 +784,9 @@ galaxy_sessions=relation( GalaxySession, order_by=desc( GalaxySession.table.c.update_time ) ), stored_workflow_menu_entries=relation( StoredWorkflowMenuEntry, backref="user", cascade="all, delete-orphan", - collection_class=ordering_list( 'order_index' ) ) + collection_class=ordering_list( 'order_index' ) ), +# addresses=relation( UserAddress, +# primaryjoin=( User.table.c.id == UserAddress.table.c.user_id ) ) ) ) assign_mapper( context, Group, Group.table, diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/model/migrate/versions/0009_request_table.py --- a/lib/galaxy/model/migrate/versions/0009_request_table.py Thu Aug 06 15:19:02 2009 -0400 +++ b/lib/galaxy/model/migrate/versions/0009_request_table.py Thu Aug 06 15:25:18 2009 -0400 @@ -32,7 +32,7 @@ col.create( Request_table ) assert col is Request_table.c.submitted except Exception, e: - log.debug( "Adding column 'submitted' to submitted table failed: %s" % ( str( e ) ) ) + log.debug( "Adding column 'submitted' to request table failed: %s" % ( str( e ) ) ) # Add 1 column to the sample table try: @@ -46,7 +46,7 @@ col.create( Sample_table ) assert col is Sample_table.c.bar_code except Exception, e: - log.debug( "Adding column 'bar_code' to submitted table failed: %s" % ( str( e ) ) ) + log.debug( "Adding column 'bar_code' to sample table failed: %s" % ( str( e ) ) ) def downgrade(): pass \ No newline at end of file diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/model/migrate/versions/0012_user_address.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/galaxy/model/migrate/versions/0012_user_address.py Thu Aug 06 15:25:18 2009 -0400 @@ -0,0 +1,118 @@ +from sqlalchemy import * +from sqlalchemy.orm import * +from sqlalchemy.exceptions import * +from migrate import * +from migrate.changeset import * + +import datetime +now = datetime.datetime.utcnow + +import sys, logging +log = logging.getLogger( __name__ ) +log.setLevel(logging.DEBUG) +handler = logging.StreamHandler( sys.stdout ) +format = "%(name)s %(levelname)s %(asctime)s %(message)s" +formatter = logging.Formatter( format ) +handler.setFormatter( formatter ) +log.addHandler( handler ) + +# Need our custom types, but don't import anything else from model +from galaxy.model.custom_types import * + +metadata = MetaData( migrate_engine ) +db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, transactional=False ) ) + + +UserAddress_table = Table( "user_address", metadata, + Column( "id", Integer, primary_key=True), + Column( "create_time", DateTime, default=now ), + Column( "update_time", DateTime, default=now, onupdate=now ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "desc", TEXT), + Column( "name", TrimmedString( 255 ), nullable=False), + Column( "institution", TrimmedString( 255 )), + Column( "address", TrimmedString( 255 ), nullable=False), + Column( "city", TrimmedString( 255 ), nullable=False), + Column( "state", TrimmedString( 255 ), nullable=False), + Column( "postal_code", TrimmedString( 255 ), nullable=False), + Column( "country", TrimmedString( 255 ), nullable=False), + Column( "phone", TrimmedString( 255 )), + Column( "deleted", Boolean, index=True, default=False ), + Column( "purged", Boolean, index=True, default=False ) ) + +#RequestState_table = Table('request_state', metadata, +# Column( "id", Integer, primary_key=True), +# Column( "create_time", DateTime, default=now ), +# Column( "update_time", DateTime, default=now, onupdate=now ), +# Column( "name", TrimmedString( 255 ), nullable=False ), +# Column( "desc", TEXT )) + +def upgrade(): + # Load existing tables + metadata.reflect() + + # Add all of the new tables above + try: + UserAddress_table.create() + except Exception, e: + log.debug( "Creating user_address table failed: %s" % str( e ) ) +# try: +# RequestState_table.create() +# except Exception, e: +# log.debug( "Creating request_state table failed: %s" % str( e ) ) + + # Add 1 column to the request_type table + try: + RequestType_table = Table( "request_type", metadata, autoload=True ) + except NoSuchTableError: + RequestType_table = None + log.debug( "Failed loading table request_type" ) + if RequestType_table: + try: + col = Column( "deleted", Boolean, index=True, default=False ) + col.create( RequestType_table ) + assert col is RequestType_table.c.deleted + except Exception, e: + log.debug( "Adding column 'deleted' to request_type table failed: %s" % ( str( e ) ) ) + + # Delete the submitted column + try: + Request_table = Table( "request", metadata, autoload=True ) + except NoSuchTableError: + Request_table = None + log.debug( "Failed loading table request" ) + if Request_table: + try: + Request_table.c.submitted.drop() + except Exception, e: + log.debug( "Deleting column 'submitted' to request table failed: %s" % ( str( e ) ) ) + try: + col = Column( "state", TrimmedString( 255 ), index=True ) + col.create( Request_table ) + assert col is Request_table.c.state + except Exception, e: + log.debug( "Adding column 'state' to request table failed: %s" % ( str( e ) ) ) +# +# # new column which points to the current state in the request_state table +# try: +# col = Column( "request_state_id", Integer, index=True ) +# col.create( Request_table ) +# assert col is Request_table.c.request_state_id +# except Exception, e: +# log.debug( "Adding column 'request_state_id' to request table failed: %s" % ( str( e ) ) ) +# # Add 1 foreign key constraint to the form_definition_current table +# if RequestState_table and Request_table: +# try: +# cons = ForeignKeyConstraint( [Request_table.c.request_state_id], +# [RequestState_table.c.id], +# name='request_request_state_id_fk' ) +# # Create the constraint +# cons.create() +# except Exception, e: +# log.debug( "Adding foreign key constraint 'request_request_state_id_fk' to table 'request' failed: %s" % ( str( e ) ) ) + + +def downgrade(): + pass + + diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/tools/test.py --- a/lib/galaxy/tools/test.py Thu Aug 06 15:19:02 2009 -0400 +++ b/lib/galaxy/tools/test.py Thu Aug 06 15:25:18 2009 -0400 @@ -25,7 +25,7 @@ for input_name, input_value in self.tool.inputs.items(): if isinstance( input_value, grouping.Conditional ) or isinstance( input_value, grouping.Repeat ): self.__expand_grouping_for_data_input(name, value, extra, input_name, input_value) - elif isinstance( self.tool.inputs[name], parameters.DataToolParameter ): + elif isinstance( self.tool.inputs[name], parameters.DataToolParameter ) and ( value, extra ) not in self.required_files: self.required_files.append( ( value, extra ) ) except: pass self.inputs.append( ( name, value, extra ) ) @@ -37,7 +37,7 @@ if name != grouping_value.test_param.name: for case in grouping_value.cases: for case_input_name, case_input_value in case.inputs.items(): - if case_input_name == name and isinstance( case_input_value, basic.DataToolParameter ): + if case_input_name == name and isinstance( case_input_value, basic.DataToolParameter ) and ( value, extra ) not in self.required_files: self.required_files.append( ( value, extra ) ) return True elif isinstance( case_input_value, grouping.Conditional ): @@ -49,6 +49,6 @@ # with the same name ( "input2" ) is not yet supported in our test code ( the lat one added is the only # one used ). for input_name, input_value in grouping_value.inputs.items(): - if input_name == name and isinstance( input_value, basic.DataToolParameter ): + if input_name == name and isinstance( input_value, basic.DataToolParameter ) and ( value, extra ) not in self.required_files: self.required_files.append( ( value, extra ) ) return True diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/web/controllers/admin.py --- a/lib/galaxy/web/controllers/admin.py Thu Aug 06 15:19:02 2009 -0400 +++ b/lib/galaxy/web/controllers/admin.py Thu Aug 06 15:25:18 2009 -0400 @@ -2120,12 +2120,19 @@ params = util.Params( kwd ) msg = util.restore_text( params.get( 'msg', '' ) ) messagetype = params.get( 'messagetype', 'done' ) + show_filter = util.restore_text( params.get( 'show_filter', 'Active' ) ) forms = self._get_all_forms(trans, all_versions=True) + request_types_list = trans.app.model.RequestType.query().all() + if show_filter == 'All': + request_types = request_types_list + elif show_filter == 'Deleted': + request_types = [rt for rt in request_types_list if rt.deleted] + else: + request_types = [rt for rt in request_types_list if not rt.deleted] return trans.fill_template( '/admin/requests/manage_request_types.mako', - request_types=trans.app.model.RequestType.query().all(), + request_types=request_types, forms=forms, - deleted=False, - show_deleted=False, + show_filter=show_filter, msg=msg, messagetype=messagetype ) @web.expose @@ -2155,13 +2162,10 @@ forms=self._get_all_forms(trans, all_versions=False), msg=msg, messagetype='error') - return trans.fill_template( '/admin/requests/manage_request_types.mako', - request_types=trans.app.model.RequestType.query().all(), - forms=self._get_all_forms(trans, all_versions=True), - deleted=False, - show_deleted=False, - msg=msg, - messagetype=messagetype ) + return trans.response.send_redirect( web.url_for( controller='admin', + action='manage_request_types', + msg='Request type <b>%s</b> has been created' % st.name, + messagetype='done') ) elif params.get('edit', False) == 'True': rt = trans.app.model.RequestType.get(int(util.restore_text( params.id ))) ss_list = trans.app.model.SampleState.filter(trans.app.model.SampleState.table.c.request_type_id == rt.id).all() @@ -2197,8 +2201,8 @@ ss.delete() ss.flush() # unsubmitted state - ss = trans.app.model.SampleState('Unsubmitted', 'Sample not yet submitted', rt) - ss.flush() + #ss = trans.app.model.SampleState('Unsubmitted', 'Sample not yet submitted', rt) + ##ss.flush() for i in range( num_states ): name = util.restore_text( params.get( 'new_element_name_%i' % i, None )) desc = util.restore_text( params.get( 'new_element_description_%i' % i, None )) @@ -2206,3 +2210,31 @@ ss.flush() msg = "The new request type named '%s' with %s state(s) has been created" % (rt.name, num_states) return rt, msg + + @web.expose + @web.require_admin + def delete_request_type( self, trans, **kwd ): + params = util.Params( kwd ) + msg = util.restore_text( params.get( 'msg', '' ) ) + messagetype = params.get( 'messagetype', 'done' ) + rt = trans.app.model.RequestType.get(int(util.restore_text( params.request_type_id ))) + rt.deleted = True + rt.flush() + return trans.response.send_redirect( web.url_for( controller='admin', + action='manage_request_types', + msg='Request type <b>%s</b> has been deleted' % rt.name, + messagetype='done') ) + + @web.expose + @web.require_admin + def undelete_request_type( self, trans, **kwd ): + params = util.Params( kwd ) + msg = util.restore_text( params.get( 'msg', '' ) ) + messagetype = params.get( 'messagetype', 'done' ) + rt = trans.app.model.RequestType.get(int(util.restore_text( params.request_type_id ))) + rt.deleted = False + rt.flush() + return trans.response.send_redirect( web.url_for( controller='admin', + action='manage_request_types', + msg='Request type <b>%s</b> has been deleted' % rt.name, + messagetype='done') ) diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/web/controllers/dataset.py --- a/lib/galaxy/web/controllers/dataset.py Thu Aug 06 15:19:02 2009 -0400 +++ b/lib/galaxy/web/controllers/dataset.py Thu Aug 06 15:25:18 2009 -0400 @@ -44,7 +44,7 @@ @web.expose def errors( self, trans, id ): dataset = model.HistoryDatasetAssociation.get( id ) - return trans.fill_template( "dataset/errors.tmpl", dataset=dataset ) + return trans.fill_template( "dataset/errors.mako", dataset=dataset ) @web.expose def stderr( self, trans, id ): diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/web/controllers/forms.py --- a/lib/galaxy/web/controllers/forms.py Thu Aug 06 15:19:02 2009 -0400 +++ b/lib/galaxy/web/controllers/forms.py Thu Aug 06 15:25:18 2009 -0400 @@ -29,13 +29,19 @@ params = util.Params( kwd ) msg = util.restore_text( params.get( 'msg', '' ) ) messagetype = params.get( 'messagetype', 'done' ) - return self._show_forms_list(trans, msg, messagetype) - def _show_forms_list(self, trans, msg, messagetype): + show_filter = params.get( 'show_filter', 'Active' ) + return self._show_forms_list(trans, msg, messagetype, show_filter) + def _show_forms_list(self, trans, msg, messagetype, show_filter='Active'): fdc_list = trans.app.model.FormDefinitionCurrent.query().all() + if show_filter == 'All': + forms_list = fdc_list + elif show_filter == 'Deleted': + forms_list = [form for form in fdc_list if form.deleted] + else: + forms_list = [form for form in fdc_list if not form.deleted] return trans.fill_template( '/admin/forms/manage_forms.mako', - fdc_list=fdc_list, - deleted=False, - show_deleted=False, + fdc_list=forms_list, + show_filter=show_filter, msg=msg, messagetype=messagetype ) def _get_all_forms(self, trans, all_versions=False): @@ -73,7 +79,34 @@ self.num_add_fields = 0 fd, msg = self.__save_form(trans, fdc_id=None, **kwd) self.__get_saved_form(fd) - return self._show_forms_list(trans, msg, messagetype) + return trans.response.send_redirect( web.url_for( controller='forms', + action='edit', + form_id=fd.id, + show_form=True) ) + @web.expose + @web.require_admin + def delete( self, trans, **kwd ): + params = util.Params( kwd ) + msg = util.restore_text( params.get( 'msg', '' ) ) + messagetype = params.get( 'messagetype', 'done' ) + fd = trans.app.model.FormDefinition.get(int(util.restore_text( params.form_id ))) + fd.form_definition_current.deleted = True + fd.form_definition_current.flush() + return self._show_forms_list(trans, + msg='The form definition named %s is deleted.' % fd.name, + messagetype='done') + @web.expose + @web.require_admin + def undelete( self, trans, **kwd ): + params = util.Params( kwd ) + msg = util.restore_text( params.get( 'msg', '' ) ) + messagetype = params.get( 'messagetype', 'done' ) + fd = trans.app.model.FormDefinition.get(int(util.restore_text( params.form_id ))) + fd.form_definition_current.deleted = False + fd.form_definition_current.flush() + return self._show_forms_list(trans, + msg='The form definition named %s is undeleted.' % fd.name, + messagetype='done') @web.expose @web.require_admin def edit( self, trans, **kwd ): @@ -241,15 +274,22 @@ ''' import csv fields = [] - reader = csv.reader(open(csv_file)) - for row in reader: - options = row[5].split(',') - fields.append({'label': row[0], - 'helptext': row[1], - 'visible': row[2], - 'required': row[3], - 'type': row[4], - 'selectlist': options}) + try: + reader = csv.reader(open(csv_file)) + for row in reader: + options = row[5].split(',') + fields.append({'label': row[0], + 'helptext': row[1], + 'visible': row[2], + 'required': row[3], + 'type': row[4], + 'selectlist': options}) + except: + return trans.response.send_redirect( web.url_for( controller='forms', + action='new', + status='error', + message='Error in importing <b>%s</b> file' % csv_file, + **kwd)) return fields def __save_form(self, trans, fdc_id=None, **kwd): diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/web/controllers/requests.py --- a/lib/galaxy/web/controllers/requests.py Thu Aug 06 15:19:02 2009 -0400 +++ b/lib/galaxy/web/controllers/requests.py Thu Aug 06 15:25:18 2009 -0400 @@ -14,6 +14,7 @@ title = "Sequencing Requests" model_class = model.Request default_sort_key = "-create_time" + show_filter = model.Request.states.UNSUBMITTED columns = [ grids.GridColumn( "Name", key="name", link=( lambda item: iff( item.deleted, None, dict( operation="show_request", id=item.id ) ) ), @@ -23,18 +24,23 @@ link=( lambda item: iff( item.deleted, None, dict( operation="show_request", id=item.id ) ) ), ), grids.GridColumn( "Type", key="request_type_id", method='get_request_type'), grids.GridColumn( "Last update", key="update_time", format=time_ago ), - grids.GridColumn( "Submitted", method='submitted'), + grids.GridColumn( "State", key='state'), ] operations = [ -# grids.GridOperation( "Edit", allow_multiple=False, condition=( lambda item: not item.deleted ) ), - grids.GridOperation( "Submit", allow_multiple=False, condition=( lambda item: not item.submitted ) ) -# grids.GridOperation( "Delete", condition=( lambda item: not item.deleted ) ), -# grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ) ), + grids.GridOperation( "Submit", allow_multiple=False, condition=( lambda item: not item.deleted and item.unsubmitted() and item.samples ) ), + grids.GridOperation( "Edit", allow_multiple=False, condition=( lambda item: not item.deleted and item.unsubmitted() ) ), + grids.GridOperation( "Delete", allow_multiple=False, condition=( lambda item: not item.deleted and item.unsubmitted() ) ), + grids.GridOperation( "Undelete", allow_multiple=False, condition=( lambda item: item.deleted ) ) + ] standard_filters = [ - grids.GridColumnFilter( "Active", args=dict( deleted=False ) ), + grids.GridColumnFilter( model.Request.states.UNSUBMITTED, + args=dict( state=model.Request.states.UNSUBMITTED, deleted=False ) ), + grids.GridColumnFilter( model.Request.states.SUBMITTED, + args=dict( state=model.Request.states.SUBMITTED, deleted=False ) ), + grids.GridColumnFilter( model.Request.states.COMPLETE, args=dict( state=model.Request.states.COMPLETE, deleted=False ) ), grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ), - grids.GridColumnFilter( "All", args=dict( deleted='All' ) ) + grids.GridColumnFilter( "All", args={} ) ] #default_filter = dict( deleted=False ) def get_current_item( self, trans ): @@ -45,10 +51,8 @@ return query.filter_by( user=trans.user ) def number_of_samples(self, trans, request): return str(len(request.samples)) - def submitted(self, trans, request): - if request.submitted: - return 'Yes' - return 'No' + def get_state(self, trans, request): + return request.state @@ -73,6 +77,8 @@ List all request made by the current user ''' status = message = None + self.request_grid.default_filter = dict(state=trans.app.model.Request.states.UNSUBMITTED, + deleted=False) if 'operation' in kwargs: operation = kwargs['operation'].lower() if operation == "show_request": @@ -81,6 +87,23 @@ elif operation == "submit": id = trans.security.decode_id(kwargs['id']) return self.__submit(trans, id) + elif operation == "delete": + id = trans.security.decode_id(kwargs['id']) + return self.__delete_request(trans, id) + elif operation == "undelete": + id = trans.security.decode_id(kwargs['id']) + return self.__undelete_request(trans, id) + elif operation == "edit": + id = trans.security.decode_id(kwargs['id']) + return self.__edit_request(trans, id) + if 'show_filter' in kwargs.keys(): + if kwargs['show_filter'] == 'All': + self.request_grid.default_filter = {} + elif kwargs['show_filter'] == 'Deleted': + self.request_grid.default_filter = dict(deleted=True) + else: + self.request_grid.default_filter = dict(state=kwargs['show_filter'], deleted=False) + self.request_grid.show_filter = kwargs.get('show_filter', trans.app.model.Request.states.UNSUBMITTED) # Render the list view return self.request_grid( trans, template='/requests/grid.mako', **kwargs ) @@ -94,21 +117,19 @@ message="Invalid request ID", **kwd) ) self.current_samples = [] + self.edit_mode = False for s in request.samples: self.current_samples.append([s.name, s.values.content]) if add_sample: self.current_samples.append(['Sample_%i' % (len(self.current_samples)+1),['' for field in request.type.sample_form.fields]]) - # selectfield of all samples - copy_list = SelectField('copy_sample') - copy_list.add_option('None', -1, selected=True) - for i, s in enumerate(self.current_samples): - copy_list.add_option(i+1, i) self.details_state = 'Show request details' return trans.fill_template( '/requests/show_request.mako', request=request, request_details=self.request_details(trans, id), current_samples = self.current_samples, - sample_copy=copy_list, details_state=self.details_state) + sample_copy=self.__copy_sample(), + details_state=self.details_state, + edit_mode=self.edit_mode) def request_details(self, trans, id): ''' Shows the request details @@ -128,19 +149,37 @@ value=request.create_time, helptext='')) # library associated - request_details.append(dict(label='Library', - value=request.library.name, - helptext='Associated library where the resultant \ - dataset will be stored')) + if request.library: + request_details.append(dict(label='Library', + value=request.library.name, + helptext='Associated library where the resultant \ + dataset will be stored')) + else: + request_details.append(dict(label='Library', + value=None, + helptext='Associated library where the resultant \ + dataset will be stored')) + # form fields for index, field in enumerate(request.type.request_form.fields): if field['required']: req = 'Required' else: req = 'Optional' - request_details.append(dict(label=field['label'], - value=request.values.content[index], - helptext=field['helptext']+' ('+req+')')) + if field['type'] == 'AddressField': + if request.values.content[index]: + request_details.append(dict(label=field['label'], + value=trans.app.model.UserAddress.get(int(request.values.content[index])).get_html(), + helptext=field['helptext']+' ('+req+')')) + else: + request_details.append(dict(label=field['label'], + value=None, + helptext=field['helptext']+' ('+req+')')) + + else: + request_details.append(dict(label=field['label'], + value=request.values.content[index], + helptext=field['helptext']+' ('+req+')')) return request_details def __update_samples(self, request, **kwd): @@ -156,6 +195,13 @@ for field_index in range(len(request.type.sample_form.fields)): sample_values.append(util.restore_text( params.get( 'sample_%i_field_%i' % (sample_index, field_index), '' ) )) self.current_samples.append([sample_name, sample_values]) + + def __copy_sample(self): + copy_list = SelectField('copy_sample') + copy_list.add_option('None', -1, selected=True) + for i, s in enumerate(self.current_samples): + copy_list.add_option(s[0], i) + return copy_list @web.expose def show_request(self, trans, **kwd): params = util.Params( kwd ) @@ -169,7 +215,28 @@ status='error', message="Invalid request ID", **kwd) ) - if params.get('add_sample_button', False) == 'Add New': + if params.get('import_samples_button', False) == 'Import samples': + import traceback + try: + fname = params.get('import_samples', '') + import csv + reader = csv.reader(open(fname)) + for row in reader: + self.current_samples.append([row[0], row[1:]]) + return trans.fill_template( '/requests/show_request.mako', + request=request, + request_details=self.request_details(trans, request.id), + current_samples=self.current_samples, + sample_copy=self.__copy_sample(), + details_state=self.details_state, + edit_mode=self.edit_mode) + except: + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + status='error', + message='Error in importing <b>%s</b> samples file' % fname, + **kwd)) + elif params.get('add_sample_button', False) == 'Add New': # save the all (saved+unsaved) sample info in 'current_samples' self.__update_samples(request, **kwd) # add an empty or filled sample @@ -182,17 +249,14 @@ else: self.current_samples.append([self.current_samples[src_sample_index][0]+'_%i' % (len(self.current_samples)+1), [val for val in self.current_samples[src_sample_index][1]]]) - # selectfield of all samples - copy_list = SelectField('copy_sample') - copy_list.add_option('None', -1, selected=True) - for i, s in enumerate(self.current_samples): - copy_list.add_option(i+1, i) return trans.fill_template( '/requests/show_request.mako', request=request, request_details=self.request_details(trans, request.id), - current_samples = self.current_samples, - sample_copy=copy_list, details_state=self.details_state) - if params.get('save_samples_button', False) == 'Save': + current_samples=self.current_samples, + sample_copy=self.__copy_sample(), + details_state=self.details_state, + edit_mode=self.edit_mode) + elif params.get('save_samples_button', False) == 'Save': # update current_samples self.__update_samples(request, **kwd) # check for duplicate sample names @@ -211,35 +275,59 @@ msg = "This request has <b>%i</b> samples with the name <b>%s</b>.\nSamples belonging to a request must have unique names." % (count, sample_name) break if msg: - copy_list = SelectField('copy_sample') - copy_list.add_option('None', -1, selected=True) - for i, s in enumerate(self.current_samples): - copy_list.add_option(i+1, i) return trans.fill_template( '/requests/show_request.mako', request=request, request_details=self.request_details(trans, request.id), current_samples = self.current_samples, - sample_copy=copy_list, details_state=self.details_state, + sample_copy=self.__copy_sample(), details_state=self.details_state, messagetype='error', msg=msg) # save all the new/unsaved samples entered by the user - for index in range(len(self.current_samples)-len(request.samples)): - sample_index = index + len(request.samples) - sample_name = util.restore_text( params.get( 'sample_%i_name' % sample_index, '' ) ) - sample_values = [] - for field_index in range(len(request.type.sample_form.fields)): - sample_values.append(util.restore_text( params.get( 'sample_%i_field_%i' % (sample_index, field_index), '' ) )) - form_values = trans.app.model.FormValues(request.type.sample_form, sample_values) - form_values.flush() - s = trans.app.model.Sample(sample_name, '', request, form_values) - s.flush() - # set the initial state - state = s.request.type.states[0] - event = trans.app.model.SampleEvent(s, state) - event.flush() + if not self.edit_mode: + for index in range(len(self.current_samples)-len(request.samples)): + sample_index = index + len(request.samples) + sample_name = util.restore_text( params.get( 'sample_%i_name' % sample_index, '' ) ) + sample_values = [] + for field_index in range(len(request.type.sample_form.fields)): + sample_values.append(util.restore_text( params.get( 'sample_%i_field_%i' % (sample_index, field_index), '' ) )) + form_values = trans.app.model.FormValues(request.type.sample_form, sample_values) + form_values.flush() + s = trans.app.model.Sample(sample_name, '', request, form_values) + s.flush() + else: + for index in range(len(self.current_samples)): + sample_index = index + sample_name = self.current_samples[sample_index][0] + new_sample_name = util.restore_text( params.get( 'sample_%i_name' % sample_index, '' ) ) + sample_values = [] + for field_index in range(len(request.type.sample_form.fields)): + sample_values.append(util.restore_text( params.get( 'sample_%i_field_%i' % (sample_index, field_index), '' ) )) + sample = request.has_sample(sample_name) + if sample: + form_values = trans.app.model.FormValues.get(sample.values.id) + form_values.content = sample_values + form_values.flush() + sample.name = new_sample_name + sample.flush() return trans.response.send_redirect( web.url_for( controller='requests', action='list', operation='show_request', id=trans.security.encode_id(request.id)) ) + elif params.get('edit_samples_button', False) == 'Edit samples': + self.edit_mode = True + return trans.fill_template( '/requests/show_request.mako', + request=request, + request_details=self.request_details(trans, request.id), + current_samples=self.current_samples, + sample_copy=self.__copy_sample(), + details_state=self.details_state, + edit_mode=self.edit_mode) + elif params.get('cancel_changes_button', False) == 'Cancel': + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + operation='show_request', + id=trans.security.encode_id(request.id)) ) + + @web.expose def delete_sample(self, trans, **kwd): params = util.Params( kwd ) @@ -253,16 +341,15 @@ s.delete() s.flush() request.flush() - del self.current_samples[sample_index] - copy_list = SelectField('copy_sample') - copy_list.add_option('None', -1, selected=True) - for i, s in enumerate(self.current_samples): - copy_list.add_option(i+1, i) + del self.current_samples[sample_index] return trans.fill_template( '/requests/show_request.mako', request=request, request_details=self.request_details(trans, request.id), current_samples = self.current_samples, - sample_copy=copy_list, details_state=self.details_state) + sample_copy=self.__copy_sample(), + details_state=self.details_state, + edit_mode=self.edit_mode) + @web.expose def toggle_request_details(self, trans, **kwd): params = util.Params( kwd ) @@ -272,121 +359,95 @@ if self.details_state == 'Show request details': self.details_state = 'Hide request details' elif self.details_state == 'Hide request details': - self.details_state = 'Show request details' - copy_list = SelectField('copy_sample') - copy_list.add_option('None', -1, selected=True) - for i, s in enumerate(self.current_samples): - copy_list.add_option(i+1, i) + self.details_state = 'Show request details' return trans.fill_template( '/requests/show_request.mako', request=request, request_details=self.request_details(trans, request.id), current_samples = self.current_samples, - sample_copy=copy_list, details_state=self.details_state) + sample_copy=self.__copy_sample(), + details_state=self.details_state, + edit_mode=self.edit_mode) + def __select_request_type(self, trans, rtid): + rt_ids = ['none'] + for rt in trans.app.model.RequestType.query().all(): + if not rt.deleted: + rt_ids.append(str(rt.id)) + select_reqtype = SelectField('select_request_type', + refresh_on_change=True, + refresh_on_change_values=rt_ids[1:]) + if rtid == 'none': + select_reqtype.add_option('Select one', 'none', selected=True) + else: + select_reqtype.add_option('Select one', 'none') + for rt in trans.app.model.RequestType.query().all(): + if not rt.deleted: + if rtid == rt.id: + select_reqtype.add_option(rt.name, rt.id, selected=True) + else: + select_reqtype.add_option(rt.name, rt.id) + return select_reqtype @web.expose def new(self, trans, **kwd): params = util.Params( kwd ) msg = util.restore_text( params.get( 'msg', '' ) ) messagetype = params.get( 'messagetype', 'done' ) if params.get('select_request_type', False) == 'True': - return trans.fill_template( '/requests/select_request_type.mako', - request_types=trans.app.model.RequestType.query().all(), - libraries=self.get_authorized_libs(trans), + return trans.fill_template( '/requests/new_request.mako', + select_request_type=self.__select_request_type(trans, 'none'), + widgets=[], msg=msg, - messagetype=messagetype ) + messagetype=messagetype) elif params.get('create', False) == 'True': - return self.__show_request_form(trans=trans, - request=None, **kwd) - elif params.get('save', False) == 'True': - request_type = trans.app.model.RequestType.get(int(params.request_type_id)) - msg = self.__validate(trans, - [('name','Name')], - request_type.request_form.fields, - **kwd) - if msg: - kwd['create'] = 'True' - return trans.response.send_redirect( web.url_for( controller='requests', - action='new', - msg=msg, - messagetype='error', - **kwd) ) - request = self.__save_request(trans, None, **kwd) - msg = 'The new request named %s has been created' % request.name - request_type_id = int(util.restore_text( params.request_type_id )) - if params.get('create_request_button', False) == 'Save': - return trans.response.send_redirect( web.url_for( controller='requests', - action='list', - msg=msg , - messagetype='done') ) - elif params.get('create_request_samples_button', False) == 'Add samples': - new_kwd = {} - new_kwd['id'] = trans.security.encode_id(request.id) - new_kwd['operation'] = 'show_request' - new_kwd['add_sample'] = True - return trans.response.send_redirect( web.url_for( controller='requests', - action='list', - msg=msg , - messagetype='done', - **new_kwd) ) + if params.get('create_request_button', False) == 'Save' \ + or params.get('create_request_samples_button', False) == 'Add samples': + request_type = trans.app.model.RequestType.get(int(params.select_request_type)) + if not util.restore_text(params.get('name', '')): + msg = 'Please enter the <b>Name</b> of the request' + kwd['create'] = 'True' + kwd['messagetype'] = 'error' + kwd['msg'] = msg + kwd['create_request_button'] = None + kwd['create_request_samples_button'] = None + return trans.response.send_redirect( web.url_for( controller='requests', + action='new', + **kwd) ) + request = self.__save_request(trans, None, **kwd) + msg = 'The new request named %s has been created' % request.name + if params.get('create_request_button', False) == 'Save': + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + msg=msg , + messagetype='done') ) + elif params.get('create_request_samples_button', False) == 'Add samples': + new_kwd = {} + new_kwd['id'] = trans.security.encode_id(request.id) + new_kwd['operation'] = 'show_request' + new_kwd['add_sample'] = True + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + msg=msg , + messagetype='done', + **new_kwd) ) + else: + return self.__show_request_form(trans, **kwd) + elif params.get('refresh', False) == 'true': + return self.__show_request_form(trans, **kwd) - def __validate(self, trans, main_fields=[], form_fields=[], **kwd): - ''' - Validates the request entered by the user - ''' - params = util.Params( kwd ) - for field, field_name in main_fields: - if not util.restore_text(params.get(field, '')): - return 'Please enter the <b>%s</b> of the request' % field_name - # check rest of the fields of the form - for index, field in enumerate(form_fields): - if not util.restore_text(params.get('field_%i' % index, None)) \ - and field['required'] == 'required': - return 'Please enter the <b>%s</b> field of the request' % field['label'] - return None - def __save_request(self, trans, request_id=None, **kwd): - ''' - This method saves a new request if request_id is None. - ''' - params = util.Params( kwd ) - if not request_id: - request_type = trans.app.model.RequestType.get(int(params.request_type_id )) - else: - # TODO editing - pass - name = util.restore_text(params.get('name', '')) - desc = util.restore_text(params.get('desc', '')) - try: - library_id = int(util.restore_text(params.get('library_id', None))) - except: - msg = "Sequencing request could not be saved. Invalid library" - return trans.response.send_redirect( web.url_for( controller='requests', - action='list', - status='error', - message=msg, - **kwd) ) - values = [] - for index, field in enumerate(request_type.request_form.fields): - values.append(util.restore_text(params.get('field_%i' % index, ''))) - if not request_id: - form_values = trans.app.model.FormValues(request_type.request_form, values) - form_values.flush() - request = trans.app.model.Request(name, desc, request_type, - trans.user, form_values, - trans.app.model.Library.get(library_id), - submitted=False) - request.flush() - else: - # TODO editing - pass - return request - def __show_request_form(self, trans, request=None, **kwd): + + def __show_request_form(self, trans, **kwd): params = util.Params( kwd ) msg = util.restore_text( params.get( 'msg', '' ) ) messagetype = params.get( 'messagetype', 'done' ) - request_type = trans.app.model.RequestType.get(int(params.request_type_id)) - if request: - form_values = request.values - else: - form_values = None + try: + request_type = trans.app.model.RequestType.get(int(params.select_request_type)) + except: + return trans.fill_template( '/requests/new_request.mako', + select_request_type=self.__select_request_type(trans, 'none'), + widgets=[], + msg=msg, + messagetype=messagetype) + form_values = None + select_request_type = self.__select_request_type(trans, request_type.id) # list of widgets to be rendered on the request form widgets = [] widgets.append(dict(label='Name', @@ -397,53 +458,305 @@ widget=TextField('desc', 40, util.restore_text( params.get( 'desc', '' ) )), helptext='(Optional)')) + # libraries selectbox libraries = self.get_authorized_libs(trans) - if libraries: - libui = self.__library_ui(libraries, **kwd) - widgets.append(libui) + libui = self.__library_ui(libraries, **kwd) + widgets = widgets + libui widgets = self.__create_form(trans, request_type.request_form_id, widgets, form_values, **kwd) title = 'Add a new request of type: %s' % request_type.name return trans.fill_template( '/requests/new_request.mako', - request_form_id=request_type.request_form_id, - request_type=request_type, - widgets=widgets, - title=title, - msg=msg, - messagetype=messagetype) + select_request_type=select_request_type, + request_type=request_type, + widgets=widgets, + msg=msg, + messagetype=messagetype) - def __library_ui(self, libraries, **kwd): + def __library_ui(self, libraries, request=None, **kwd): params = util.Params( kwd ) - create_lib_str = 'Create a new library' - value = int(params.get( 'library_id', 0 )) - if not value: # if no library previously selected - # show the selectbox with 'create a new library' option selected - lib_list = SelectField('library_id', refresh_on_change=True, - refresh_on_change_values=[create_lib_str]) - #lib_list.add_option(create_lib_str, 0, selected=True) - for lib in libraries: + lib_id = params.get( 'library_id', 'none' ) + lib_list = SelectField('library_id', refresh_on_change=True, + refresh_on_change_values=['new']) + if request and lib_id == 'none': + if request.library: + lib_id = str(request.library.id) + if lib_id == 'none': + lib_list.add_option('Select one', 'none', selected=True) + else: + lib_list.add_option('Select one', 'none') + for lib in libraries: + if str(lib.id) == lib_id: + lib_list.add_option(lib.name, lib.id, selected=True) + else: lib_list.add_option(lib.name, lib.id) - widget = dict(label='Library', - widget=lib_list, - helptext='Associated library where the resultant \ - dataset will be stored.') - else: # if some library previously selected - # show the selectbox with some library selected - lib_list = SelectField('library_id', refresh_on_change=True, - refresh_on_change_values=[create_lib_str]) - #lib_list.add_option(create_lib_str, 0) - for lib in libraries: - if value == lib.id: - lib_list.add_option(lib.name, lib.id, selected=True) + if lib_id == 'new': + lib_list.add_option('Create a new library', 'new', selected=True) + else: + lib_list.add_option('Create a new library', 'new') + widget = dict(label='Library', + widget=lib_list, + helptext='Associated library where the resultant \ + dataset will be stored.') + if lib_id == 'new': + new_lib = dict(label='Create a new Library', + widget=TextField('new_library_name', 40, + util.restore_text( params.get( 'new_library_name', '' ) )), + helptext='Enter a library name here to request a new library') + return [widget, new_lib] + else: + return [widget] + + def __create_form(self, trans, form_id, widgets=[], form_values=None, **kwd): + params = util.Params( kwd ) + form = trans.app.model.FormDefinition.get(form_id) + # form fields + for index, field in enumerate(form.fields): + # value of the field + if field['type'] == 'CheckboxField': + value = util.restore_text( params.get( 'field_%i' % index, False ) ) + else: + value = util.restore_text( params.get( 'field_%i' % index, '' ) ) + if not value: + if form_values: + value = str(form_values.content[index]) + # create the field + fw = eval(field['type'])('field_%i' % index) + if field['type'] == 'TextField': + fw.set_size(40) + fw.value = value + elif field['type'] == 'TextArea': + fw.set_size(3, 40) + fw.value = value + elif field['type'] == 'AddressField': + fw.user = trans.user + fw.value = value + fw.params = params + elif field['type'] == 'SelectField': + for option in field['selectlist']: + if option == value: + fw.add_option(option, option, selected=True) + else: + fw.add_option(option, option) + elif field['type'] == 'CheckboxField': + fw.checked = value + # require/optional + if field['required'] == 'required': + req = 'Required' + else: + req = 'Optional' + widgets.append(dict(label=field['label'], + widget=fw, + helptext=field['helptext']+' ('+req+')')) + return widgets + def __validate(self, trans, request): + ''' + Validates the request entered by the user + ''' + empty_fields = [] + if not request.library: + empty_fields.append('Library') + # check rest of the fields of the form + for index, field in enumerate(request.type.request_form.fields): + if field['required'] == 'required' and request.values.content[index] in ['', None]: + empty_fields.append(field['label']) + if empty_fields: + msg = 'Fill the following fields of the request <b>%s</b> before submitting<br/>' % request.name + for ef in empty_fields: + msg = msg + '<b>' +ef + '</b><br/>' + return msg + return None + def __save_request(self, trans, request=None, **kwd): + ''' + This method saves a new request if request_id is None. + ''' + params = util.Params( kwd ) + request_type = trans.app.model.RequestType.get(int(params.select_request_type)) + name = util.restore_text(params.get('name', '')) + desc = util.restore_text(params.get('desc', '')) + # library + try: + library = trans.app.model.Library.get(int(params.get('library_id', None))) + except: + library = None + # fields + values = [] + for index, field in enumerate(request_type.request_form.fields): + if field['type'] == 'AddressField': + value = util.restore_text(params.get('field_%i' % index, '')) + if value == 'new': + # save this new address in the list of this user's addresses + user_address = trans.app.model.UserAddress( user=trans.user ) + user_address.desc = util.restore_text(params.get('field_%i_short_desc' % index, '')) + user_address.name = util.restore_text(params.get('field_%i_name' % index, '')) + user_address.institution = util.restore_text(params.get('field_%i_institution' % index, '')) + user_address.address = util.restore_text(params.get('field_%i_address1' % index, ''))+' '+util.restore_text(params.get('field_%i_address2' % index, '')) + user_address.city = util.restore_text(params.get('field_%i_city' % index, '')) + user_address.state = util.restore_text(params.get('field_%i_state' % index, '')) + user_address.postal_code = util.restore_text(params.get('field_%i_postal_code' % index, '')) + user_address.country = util.restore_text(params.get('field_%i_country' % index, '')) + user_address.phone = util.restore_text(params.get('field_%i_phone' % index, '')) + user_address.flush() + trans.user.refresh() + values.append(int(user_address.id)) + elif value == unicode('none'): + values.append('') else: - lib_list.add_option(lib.name, lib.id) - widget = dict(label='Library', - widget=lib_list, - helptext='Associated library where the resultant \ - dataset will be stored.') - return widget - + values.append(int(value)) + else: + values.append(util.restore_text(params.get('field_%i' % index, ''))) + form_values = trans.app.model.FormValues(request_type.request_form, values) + form_values.flush() + if not request: + request = trans.app.model.Request(name, desc, request_type, + trans.user, form_values, + library=library, + state=trans.app.model.Request.states.UNSUBMITTED) + request.flush() + else: + request.name = name + request.desc = desc + request.type = request_type + request.user = trans.user + request.values = form_values + request.library = library + request.state = trans.app.model.Request.states.UNSUBMITTED + request.flush() + return request + @web.expose + def edit(self, trans, **kwd): + params = util.Params( kwd ) + msg = util.restore_text( params.get( 'msg', '' ) ) + messagetype = params.get( 'messagetype', 'done' ) + try: + request = trans.app.model.Request.get(int(params.get('request_id', None))) + except: + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + status='error', + message="Invalid request ID", + **kwd) ) + if params.get('show', False) == 'True': + return self.__edit_request(trans, request.id, **kwd) + elif params.get('save_changes_request_button', False) == 'Save changes' \ + or params.get('edit_samples_button', False) == 'Edit samples': + request_type = trans.app.model.RequestType.get(int(params.select_request_type)) + if not util.restore_text(params.get('name', '')): + msg = 'Please enter the <b>Name</b> of the request' + kwd['messagetype'] = 'error' + kwd['msg'] = msg + kwd['show'] = 'True' + return trans.response.send_redirect( web.url_for( controller='requests', + action='edit', + **kwd) ) + request = self.__save_request(trans, request, **kwd) + msg = 'The changes made to the request named %s has been saved' % request.name + if params.get('save_changes_request_button', False) == 'Save changes': + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + message=msg , + status='done') ) + elif params.get('edit_samples_button', False) == 'Edit samples': + new_kwd = {} + new_kwd['request_id'] = request.id + new_kwd['edit_samples_button'] = 'Edit samples' + return trans.response.send_redirect( web.url_for( controller='requests', + action='show_request', + msg=msg , + messagetype='done', + **new_kwd) ) + elif params.get('refresh', False) == 'true': + return self.__edit_request(trans, request.id, **kwd) + + def __edit_request(self, trans, id, **kwd): + try: + request = trans.app.model.Request.get(id) + except: + msg = "Invalid request ID" + log.warn( msg ) + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + status='error', + message=msg) ) + params = util.Params( kwd ) + msg = util.restore_text( params.get( 'msg', '' ) ) + messagetype = params.get( 'messagetype', 'done' ) + select_request_type = self.__select_request_type(trans, request.type.id) + # list of widgets to be rendered on the request form + widgets = [] + if util.restore_text( params.get( 'name', '' ) ): + name = util.restore_text( params.get( 'name', '' ) ) + else: + name = request.name + widgets.append(dict(label='Name', + widget=TextField('name', 40, name), + helptext='(Required)')) + if util.restore_text( params.get( 'desc', '' ) ): + desc = util.restore_text( params.get( 'desc', '' ) ) + else: + desc = request.desc + widgets.append(dict(label='Description', + widget=TextField('desc', 40, desc), + helptext='(Optional)')) + + # libraries selectbox + libraries = self.get_authorized_libs(trans) + libui = self.__library_ui(libraries, request, **kwd) + widgets = widgets + libui + widgets = self.__create_form(trans, request.type.request_form_id, widgets, + request.values, **kwd) + return trans.fill_template( '/requests/edit_request.mako', + select_request_type=select_request_type, + request_type=request.type, + request=request, + widgets=widgets, + msg=msg, + messagetype=messagetype) + return self.__show_request_form(trans) + def __delete_request(self, trans, id): + try: + request = trans.app.model.Request.get(id) + except: + msg = "Invalid request ID" + log.warn( msg ) + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + status='error', + message=msg, + **kwd) ) + # change request's submitted field + if not request.unsubmitted(): + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + status='error', + message='This request cannot be deleted as it is already been submitted', + **kwd) ) + request.deleted = True + request.flush() + kwd = {} + kwd['id'] = trans.security.encode_id(request.id) + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + **kwd) ) + def __undelete_request(self, trans, id): + try: + request = trans.app.model.Request.get(id) + except: + msg = "Invalid request ID" + log.warn( msg ) + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + status='error', + message=msg, + **kwd) ) + # change request's submitted field + request.deleted = False + request.flush() + kwd = {} + kwd['id'] = trans.security.encode_id(request.id) + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + **kwd) ) def __submit(self, trans, id): try: request = trans.app.model.Request.get(id) @@ -455,13 +768,21 @@ status='error', message=msg, **kwd) ) + msg = self.__validate(trans, request) + if msg: + return trans.response.send_redirect( web.url_for( controller='requests', + action='edit', + messagetype = 'error', + msg=msg, + request_id=request.id, + show='True') ) # get the new state - new_state = request.type.states[1] + new_state = request.type.states[0] for s in request.samples: event = trans.app.model.SampleEvent(s, new_state, 'Samples submitted to the system') event.flush() # change request's submitted field - request.submitted = True + request.state = request.states.SUBMITTED request.flush() kwd = {} kwd['id'] = trans.security.encode_id(request.id) @@ -482,54 +803,28 @@ status='error', message=msg, **kwd) ) + msg = self.__validate(trans, request) + if msg: + return trans.response.send_redirect( web.url_for( controller='requests', + action='edit', + messagetype = 'error', + msg=msg, + request_id=request.id, + show='True') ) # get the new state - new_state = request.type.states[1] + new_state = request.type.states[0] for s in request.samples: event = trans.app.model.SampleEvent(s, new_state, 'Samples submitted to the system') event.flush() # change request's submitted field - request.submitted = True + request.state = request.states.SUBMITTED request.flush() ## TODO kwd['id'] = trans.security.encode_id(request.id) return trans.response.send_redirect( web.url_for( controller='requests', action='list', **kwd) ) - def __create_form(self, trans, form_id, widgets=[], form_values=None, **kwd): - params = util.Params( kwd ) - form = trans.app.model.FormDefinition.get(form_id) - # form fields - for index, field in enumerate(form.fields): - # value of the field - if field['type'] == 'CheckboxField': - value = util.restore_text( params.get( 'field_%i' % index, False ) ) - else: - value = util.restore_text( params.get( 'field_%i' % index, '' ) ) - # create the field - fw = eval(field['type'])('field_%i' % index) - if field['type'] == 'TextField': - fw.set_size(40) - fw.value = value - elif field['type'] == 'TextArea': - fw.set_size(3, 40) - fw.value = value - elif field['type'] == 'SelectField': - for option in field['selectlist']: - if option == value: - fw.add_option(option, option, selected=True) - else: - fw.add_option(option, option) - elif field['type'] == 'CheckboxField': - fw.checked = value - # require/optional - if field['required'] == 'required': - req = 'Required' - else: - req = 'Optional' - widgets.append(dict(label=field['label'], - widget=fw, - helptext=field['helptext']+' ('+req+')')) - return widgets + @web.expose def show_events(self, trans, **kwd): params = util.Params( kwd ) diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/web/controllers/requests_admin.py --- a/lib/galaxy/web/controllers/requests_admin.py Thu Aug 06 15:19:02 2009 -0400 +++ b/lib/galaxy/web/controllers/requests_admin.py Thu Aug 06 15:25:18 2009 -0400 @@ -26,6 +26,7 @@ link=( lambda item: iff( item.deleted, None, dict( operation="show_request", id=item.id ) ) ), ), grids.GridColumn( "Type", key="request_type_id", method='get_request_type'), grids.GridColumn( "Last update", key="update_time", format=time_ago ), + grids.GridColumn( "State", key='state'), grids.GridColumn( "User", key="user_id", method='get_user') ] @@ -36,9 +37,10 @@ # grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ) ), ] standard_filters = [ - grids.GridColumnFilter( "Active", args=dict( deleted=False ) ), - grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ), - grids.GridColumnFilter( "All", args=dict( deleted='All' ) ) + grids.GridColumnFilter( model.Request.states.SUBMITTED, + args=dict( state=model.Request.states.SUBMITTED, deleted=False ) ), + grids.GridColumnFilter( model.Request.states.COMPLETE, args=dict( state=model.Request.states.COMPLETE, deleted=False ) ), + grids.GridColumnFilter( "All", args=dict( deleted=False ) ) ] def get_user(self, trans, request): return trans.app.model.User.get(request.user_id).email @@ -48,7 +50,8 @@ request_type = trans.app.model.RequestType.get(request.request_type_id) return request_type.name def apply_default_filter( self, trans, query ): - return query.filter_by(submitted=True) + return query.filter(or_(self.model_class.state==self.model_class.states.SUBMITTED, + self.model_class.state==self.model_class.states.COMPLETE)) def number_of_samples(self, trans, request): return str(len(request.samples)) @@ -59,13 +62,6 @@ @web.require_admin def index( self, trans ): return trans.fill_template( "/admin/requests/index.mako" ) - def get_authorized_libs(self, trans): - all_libraries = trans.app.model.Library.filter(trans.app.model.Library.table.c.deleted == False).order_by(trans.app.model.Library.name).all() - authorized_libraries = [] - for library in all_libraries: - if trans.app.security_agent.allow_action(trans.user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=library) or trans.app.security_agent.allow_action(trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library) or trans.app.security_agent.allow_action(trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=library) or trans.app.security_agent.check_folder_contents(trans.user, library) or trans.app.security_agent.show_library_item(trans.user, library): - authorized_libraries.append(library) - return authorized_libraries @web.expose @web.require_admin def list( self, trans, **kwargs ): @@ -73,11 +69,19 @@ List all request made by the current user ''' status = message = None + self.request_grid.default_filter = dict(state=trans.app.model.Request.states.SUBMITTED, + deleted=False) if 'operation' in kwargs: operation = kwargs['operation'].lower() if operation == "show_request": id = trans.security.decode_id(kwargs['id']) return self.__show_request(trans, id) + + if 'show_filter' in kwargs.keys(): + if kwargs['show_filter'] == 'All': + self.request_grid.default_filter = dict(deleted=False) + else: + self.request_grid.default_filter = dict(state=kwargs['show_filter'], deleted=False) # Render the list view return self.request_grid( trans, template='/admin/requests/grid.mako', **kwargs ) def __show_request(self, trans, id): @@ -122,7 +126,6 @@ Shows the request details ''' request = trans.app.model.Request.get(id) - libraries = self.get_authorized_libs(trans) # list of widgets to be rendered on the request form request_details = [] # main details @@ -152,55 +155,124 @@ req = 'Required' else: req = 'Optional' - request_details.append(dict(label=field['label'], - value=request.values.content[index], - helptext=field['helptext']+' ('+req+')')) + if field['type'] == 'AddressField': + if request.values.content[index]: + request_details.append(dict(label=field['label'], + value=trans.app.model.UserAddress.get(int(request.values.content[index])).get_html(), + helptext=field['helptext']+' ('+req+')')) + else: + request_details.append(dict(label=field['label'], + value=None, + helptext=field['helptext']+' ('+req+')')) + else: + request_details.append(dict(label=field['label'], + value=request.values.content[index], + helptext=field['helptext']+' ('+req+')')) return request_details @web.expose @web.require_admin def bar_codes(self, trans, **kwd): params = util.Params( kwd ) - request_id = params.get('request_id', None) - if request_id: - request_id = int(request_id) - request = trans.app.model.Request.get(request_id) - return trans.fill_template( '/admin/samples/bar_codes.mako', - samples_list=[s for s in request.samples], - user=request.user, - request=request) + try: + request = trans.app.model.Request.get(int(params.get('request_id', None))) + except: + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + status='error', + message="Invalid request ID", + **kwd) ) + widgets = [] + for index, sample in enumerate(request.samples): + if sample.bar_code: + bc = sample.bar_code + else: + bc = util.restore_text(params.get('sample_%i_bar_code' % index, '')) + widgets.append(TextField('sample_%i_bar_code' % index, + 40, + bc)) + return trans.fill_template( '/admin/samples/bar_codes.mako', + samples_list=[s for s in request.samples], + user=request.user, request=request, widgets=widgets) @web.expose @web.require_admin def save_bar_codes(self, trans, **kwd): params = util.Params( kwd ) - request_id = params.get('request_id', None) - if request_id: - request_id = int(request_id) - request = trans.app.model.Request.get(request_id) - # validate - # bar codes need to be globally unique - unique = True - for index in range(len(request.samples)): - bar_code = util.restore_text(params.get('sample_%i_bar_code' % index, '')) - all_samples = trans.app.model.Sample.query.all() - for sample in all_samples: - if bar_code == sample.bar_code: - unique = False - if not unique: - return trans.fill_template( '/admin/samples/bar_codes.mako', - samples_list=[s for s in request.samples], - user=request.user, - request=request, - messagetype='error', - msg='Samples cannot have same bar code.') + try: + request = trans.app.model.Request.get(int(params.get('request_id', None))) + except: + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + status='error', + message="Invalid request ID", + **kwd) ) + # validate + # bar codes need to be globally unique + msg = '' + for index in range(len(request.samples)): + bar_code = util.restore_text(params.get('sample_%i_bar_code' % index, '')) + # check for empty bar code + if not bar_code.strip(): + msg = 'Please fill the bar code for sample <b>%s</b>.' % request.samples[index].name + break + # check all the unsaved bar codes + count = 0 + for i in range(len(request.samples)): + if bar_code == util.restore_text(params.get('sample_%i_bar_code' % i, '')): + count = count + 1 + if count > 1: + msg = '''The bar code <b>%s</b> of sample <b>%s</b> already belongs + another sample in this request. The sample bar codes must + be unique throughout the system''' % \ + (bar_code, request.samples[index].name) + break + # check all the saved bar codes + all_samples = trans.app.model.Sample.query.all() + for sample in all_samples: + if bar_code == sample.bar_code: + msg = '''The bar code <b>%s</b> of sample <b>%s</b> already + belongs another sample. The sample bar codes must be + unique throughout the system''' % \ + (bar_code, request.samples[index].name) + break + if msg: + break + if msg: + widgets = [] for index, sample in enumerate(request.samples): - bar_code = util.restore_text(params.get('sample_%i_bar_code' % index, '')) - sample.bar_code = bar_code - sample.flush() + if sample.bar_code: + bc = sample.bar_code + else: + bc = util.restore_text(params.get('sample_%i_bar_code' % index, '')) + widgets.append(TextField('sample_%i_bar_code' % index, + 40, + util.restore_text(params.get('sample_%i_bar_code' % index, '')))) + return trans.fill_template( '/admin/samples/bar_codes.mako', + samples_list=[s for s in request.samples], + user=request.user, request=request, widgets=widgets, messagetype='error', + msg=msg) + # now save the bar codes + for index, sample in enumerate(request.samples): + bar_code = util.restore_text(params.get('sample_%i_bar_code' % index, '')) + sample.bar_code = bar_code + sample.flush() return trans.response.send_redirect( web.url_for( controller='requests_admin', action='list', operation='show_request', id=trans.security.encode_id(request.id)) ) + def __set_request_state(self, request): + # check if all the samples of the current request are in the final state + complete = True + for s in request.samples: + if s.current_state().id != request.type.states[-1].id: + complete = False + if complete: + request.state = request.states.COMPLETE + else: + request.state = request.states.SUBMITTED + request.flush() + + def change_state(self, trans, sample): possible_states = sample.request.type.states curr_state = sample.current_state() @@ -236,6 +308,7 @@ and trans.app.model.SampleState.table.c.id == selected_state)[0] event = trans.app.model.SampleEvent(sample, new_state, comments) event.flush() + self.__set_request_state(sample.request) return trans.response.send_redirect( web.url_for( controller='requests_admin', action='show_events', sample_id=sample.id)) diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/web/controllers/root.py --- a/lib/galaxy/web/controllers/root.py Thu Aug 06 15:19:02 2009 -0400 +++ b/lib/galaxy/web/controllers/root.py Thu Aug 06 15:25:18 2009 -0400 @@ -547,29 +547,29 @@ # return trans.fill_template( "/root/masthead.mako", brand=brand, wiki_url=wiki_url, # blog_url=blog_url,bugs_email=bugs_email, screencasts_url=screencasts_url, admin_user=admin_user, active_view=active_view ) - @web.expose - def dataset_errors( self, trans, id=None, **kwd ): - """View/fix errors associated with dataset""" - data = trans.app.model.HistoryDatasetAssociation.get( id ) - p = kwd - if p.get("fix_errors", None): - # launch tool to create new, (hopefully) error free dataset - tool_params = {} - tool_params["tool_id"] = 'fix_errors' - tool_params["runtool_btn"] = 'T' - tool_params["input"] = id - tool_params["ext"] = data.ext - # send methods selected - repair_methods = data.datatype.repair_methods( data ) - methods = [] - for method, description in repair_methods: - if method in p: methods.append(method) - tool_params["methods"] = ",".join(methods) - url = "/tool_runner/index?" + urllib.urlencode(tool_params) - trans.response.send_redirect(url) - else: - history = trans.app.model.History.get( data.history_id ) - return trans.fill_template('dataset/validation.tmpl', data=data, history=history) + # @web.expose + # def dataset_errors( self, trans, id=None, **kwd ): + # """View/fix errors associated with dataset""" + # data = trans.app.model.HistoryDatasetAssociation.get( id ) + # p = kwd + # if p.get("fix_errors", None): + # # launch tool to create new, (hopefully) error free dataset + # tool_params = {} + # tool_params["tool_id"] = 'fix_errors' + # tool_params["runtool_btn"] = 'T' + # tool_params["input"] = id + # tool_params["ext"] = data.ext + # # send methods selected + # repair_methods = data.datatype.repair_methods( data ) + # methods = [] + # for method, description in repair_methods: + # if method in p: methods.append(method) + # tool_params["methods"] = ",".join(methods) + # url = "/tool_runner/index?" + urllib.urlencode(tool_params) + # trans.response.send_redirect(url) + # else: + # history = trans.app.model.History.get( data.history_id ) + # return trans.fill_template('dataset/validation.tmpl', data=data, history=history) # ---- Debug methods ---------------------------------------------------- diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/web/controllers/user.py --- a/lib/galaxy/web/controllers/user.py Thu Aug 06 15:19:02 2009 -0400 +++ b/lib/galaxy/web/controllers/user.py Thu Aug 06 15:25:18 2009 -0400 @@ -21,7 +21,7 @@ require_login_creation_template = require_login_template % " If you don't already have an account, <a href='%s'>you may create one</a>." class User( BaseController ): - + edit_address_id = None @web.expose def index( self, trans, **kwd ): return trans.fill_template( '/user/index.mako', user=trans.get_user() ) @@ -224,3 +224,186 @@ else: # User not logged in, history group must be only public return trans.show_error_message( "You must be logged in to change your default permitted actions." ) + + @web.expose + def manage_addresses(self, trans, **kwd): + if trans.user: + params = util.Params( kwd ) + show_filter = util.restore_text( params.get( 'show_filter', 'Active' ) ) + if show_filter == 'All': + addresses = [address for address in trans.user.addresses] + elif show_filter == 'Deleted': + addresses = [address for address in trans.user.addresses if address.deleted] + else: + addresses = [address for address in trans.user.addresses if not address.deleted] + return trans.fill_template( 'user/address.mako', + addresses=addresses, + show_filter=show_filter) + else: + # User not logged in, history group must be only public + return trans.show_error_message( "You must be logged in to change your default permitted actions." ) + + @web.expose + def new_address( self, trans, short_desc='', name='', institution='', address1='', + address2='', city='', state='', postal_code='', country='', phone='' ): + if trans.app.config.require_login: + refresh_frames = [ 'masthead', 'history', 'tools' ] + else: + refresh_frames = [ 'masthead', 'history' ] + if not trans.app.config.allow_user_creation and not trans.user_is_admin(): + return trans.show_error_message( 'User registration is disabled. Please contact your Galaxy administrator for an account.' ) + short_desc_error = name_error = institution_error = address1_error = city_error = None + address2_error = state_error = postal_code_error = country_error = phone_error = None + if short_desc: + if not len( short_desc ): + short_desc_error = 'Enter a short description for this address' + elif not len( name ): + name_error = 'Enter the full name' + elif not len( institution ): + institution_error = 'Enter the institution associated with the user' + elif not len ( address1 ): + address1_error = 'Enter the address' + elif not len( city ): + city_error = 'Enter the city' + elif not len( state ): + state_error = 'Enter the state/province/region' + elif not len( postal_code ): + postal_code_error = 'Enter the postal code' + elif not len( country ): + country_error = 'Enter the country' + else: + user_address = trans.app.model.UserAddress( user=trans.user, desc=short_desc, + name=name, institution=institution, + address=address1+' '+address2, city=city, + state=state, postal_code=postal_code, + country=country, phone=phone) + user_address.flush() + return trans.response.send_redirect( web.url_for( controller='user', + action='manage_addresses', + msg='Address <b>%s</b> has been added' % user_address.desc, + messagetype='done') ) + + return trans.show_form( + web.FormBuilder( web.url_for(), "New address", submit_text="Save" ) + .add_text( "short_desc", "Short address description", value=short_desc, error=short_desc_error ) + .add_text( "name", "Name", value=name, error=name_error ) + .add_text( "institution", "Institution", value=institution, error=institution_error ) + .add_text( "address1", "Address Line 1", value=address1, error=address1_error ) + .add_text( "address2", "Address Line 2", value=address2, error=address2_error ) + .add_text( "city", "City", value=city, error=city_error ) + .add_text( "state", "State/Province/Region", value=state, error=state_error ) + .add_text( "postal_code", "Postal Code", value=postal_code, error=postal_code_error ) + .add_text( "country", "Country", value=country, error=country_error ) + .add_text( "phone", "Phone", value=phone, error=phone_error ) ) + + + @web.expose + def edit_address( self, trans, address_id=None, short_desc='', name='', institution='', address1='', + address2='', city='', state='', postal_code='', country='', phone='' ): + import sys + + if trans.app.config.require_login: + refresh_frames = [ 'masthead', 'history', 'tools' ] + else: + refresh_frames = [ 'masthead', 'history' ] + if not trans.app.config.allow_user_creation and not trans.user_is_admin(): + return trans.show_error_message( 'User registration is disabled. Please contact your Galaxy administrator for an account.' ) + short_desc_error = name_error = institution_error = address1_error = city_error = None + address2_error = state_error = postal_code_error = country_error = phone_error = None + if short_desc: + if not len( short_desc ): + short_desc_error = 'Enter a short description for this address' + elif not len( name ): + name_error = 'Enter the full name' + elif not len( institution ): + institution_error = 'Enter the institution associated with the user' + elif not len ( address1 ): + address1_error = 'Enter the address' + elif not len( city ): + city_error = 'Enter the city' + elif not len( state ): + state_error = 'Enter the state/province/region' + elif not len( postal_code ): + postal_code_error = 'Enter the postal code' + elif not len( country ): + country_error = 'Enter the country' + else: + if self.edit_address_id: + try: + user_address = trans.app.model.UserAddress.get(int(self.edit_address_id)) + except: + return trans.response.send_redirect( web.url_for( controller='user', + action='manage_addresses', + msg='Invalid address ID', + messagetype='error') ) + user_address.desc = short_desc + user_address.name = name + user_address.institution = institution + user_address.address = address1+' '+address2 + user_address.city = city + user_address.state = state + user_address.postal_code = postal_code + user_address.country = country + user_address.phone = phone + user_address.flush() + self.edit_address_id = None + return trans.response.send_redirect( web.url_for( controller='user', + action='manage_addresses', + msg='Changes made to address <b>%s</b> are saved.' % user_address.desc, + messagetype='done') ) + self.edit_address_id = address_id + return trans.show_form( + web.FormBuilder( web.url_for(), "Edit address", submit_text="Save changes" ) + .add_text( "short_desc", "Short address description", value=short_desc, error=short_desc_error ) + .add_text( "name", "Name", value=name, error=name_error ) + .add_text( "institution", "Institution", value=institution, error=institution_error ) + .add_text( "address1", "Address Line 1", value=address1, error=address1_error ) + .add_text( "address2", "Address Line 2", value=address2, error=address2_error ) + .add_text( "city", "City", value=city, error=city_error ) + .add_text( "state", "State/Province/Region", value=state, error=state_error ) + .add_text( "postal_code", "Postal Code", value=postal_code, error=postal_code_error ) + .add_text( "country", "Country", value=country, error=country_error ) + .add_text( "phone", "Phone", value=phone, error=phone_error ) ) + + @web.expose + def delete_address( self, trans, address_id=None): + if trans.app.config.require_login: + refresh_frames = [ 'masthead', 'history', 'tools' ] + else: + refresh_frames = [ 'masthead', 'history' ] + if not trans.app.config.allow_user_creation and not trans.user_is_admin(): + return trans.show_error_message( 'User registration is disabled. Please contact your Galaxy administrator for an account.' ) + try: + user_address = trans.app.model.UserAddress.get(int(address_id)) + except: + return trans.fill_template( 'user/address.mako', + msg='Invalid address ID', + messagetype='error' ) + user_address.deleted = True + user_address.flush() + return trans.response.send_redirect( web.url_for( controller='user', + action='manage_addresses', + msg='Address <b>%s</b> deleted' % user_address.desc, + messagetype='done') ) + + @web.expose + def undelete_address( self, trans, address_id=None): + if trans.app.config.require_login: + refresh_frames = [ 'masthead', 'history', 'tools' ] + else: + refresh_frames = [ 'masthead', 'history' ] + if not trans.app.config.allow_user_creation and not trans.user_is_admin(): + return trans.show_error_message( 'User registration is disabled. Please contact your Galaxy administrator for an account.' ) + try: + user_address = trans.app.model.UserAddress.get(int(address_id)) + except: + return trans.fill_template( 'user/address.mako', + msg='Invalid address ID', + messagetype='error' ) + user_address.deleted = False + user_address.flush() + return trans.response.send_redirect( web.url_for( controller='user', + action='manage_addresses', + msg='Address <b>%s</b> is restored' % user_address.desc, + messagetype='done') ) + diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/web/form_builder.py --- a/lib/galaxy/web/form_builder.py Thu Aug 06 15:19:02 2009 -0400 +++ b/lib/galaxy/web/form_builder.py Thu Aug 06 15:25:18 2009 -0400 @@ -11,7 +11,7 @@ raise TypeError( "Abstract Method" ) @staticmethod def form_field_types(): - return ['TextField', 'TextArea', 'SelectField', 'CheckboxField'] + return ['TextField', 'TextArea', 'SelectField', 'CheckboxField', 'AddressField'] class TextField(BaseField): """ @@ -340,6 +340,64 @@ recurse_options( rval, self.options, expanded_options ) rval.append( '</ul></div>' ) return '\n'.join( rval ) + +class AddressField(BaseField): + @staticmethod + def fields(): + return [ ( "short_desc", "Short address description"), + ( "name", "Name" ), + ( "institution", "Institution" ), + ( "address1", "Address Line 1" ), + ( "address2", "Address Line 2" ), + ( "city", "City" ), + ( "state", "State/Province/Region" ), + ( "postal_code", "Postal Code" ), + ( "country", "Country" ), + ( "phone", "Phone" ) ] + def __init__(self, name, user=None, value=None, params=None): + self.name = name + self.user = user + self.value = value + self.select_address = None + self.params = params + def get_html(self): + from galaxy import util + address_html = '' + add_ids = ['none'] + for a in self.user.addresses: + add_ids.append(str(a.id)) + add_ids.append('new') + self.select_address = SelectField(self.name, + refresh_on_change=True, + refresh_on_change_values=add_ids) + if self.value == 'none': + self.select_address.add_option('Select one', 'none', selected=True) + else: + self.select_address.add_option('Select one', 'none') + for a in self.user.addresses: + if not a.deleted: + if self.value == str(a.id): + self.select_address.add_option(a.desc, str(a.id), selected=True) + # display this address + address_html = '''<div class="form-row"> + %s + </div>''' % a.get_html() + else: + self.select_address.add_option(a.desc, str(a.id)) + if self.value == 'new': + self.select_address.add_option('Add a new address', 'new', selected=True) + for field_name, label in self.fields(): + add_field = TextField(self.name+'_'+field_name, + 40, + util.restore_text( self.params.get( self.name+'_'+field_name, '' ) )) + address_html += ''' <div class="form-row"> + <label>%s</label> + %s + </div> + ''' % (label, add_field.get_html()) + else: + self.select_address.add_option('Add a new address', 'new') + return self.select_address.get_html()+address_html def get_suite(): diff -r 2489f9da0d29 -r 397800eff312 lib/galaxy/web/framework/helpers/grids.py --- a/lib/galaxy/web/framework/helpers/grids.py Thu Aug 06 15:19:02 2009 -0400 +++ b/lib/galaxy/web/framework/helpers/grids.py Thu Aug 06 15:25:18 2009 -0400 @@ -43,6 +43,8 @@ query = column.filter( query, column_filter, filter_args ) # Carry filter along to newly generated urls extra_url_args[ "f-" + column.key ] = column_filter + if filter_args: + query = query.filter_by( **filter_args ) # Process sort arguments sort_key = sort_order = None if 'sort' in kwargs: diff -r 2489f9da0d29 -r 397800eff312 static/june_2007_style/blue/library.css --- a/static/june_2007_style/blue/library.css Thu Aug 06 15:19:02 2009 -0400 +++ b/static/june_2007_style/blue/library.css Thu Aug 06 15:25:18 2009 -0400 @@ -12,4 +12,6 @@ pre.peek{background:white;color:black;width:100%;overflow:auto;} pre.peek th{color:white;background:#023858;} a.expandLink{text-decoration:none;} -span.expandLink{width:100%;height:100%;display:block;} +span.expandLink{width:16px;height:16px;display:inline-block;vertical-align:middle;background:url(../images/silk/resultset_next.png);} +.folderRow.expanded span.expandLink{background:url(../images/silk/resultset_bottom.png);} +.folderRow span.rowIcon{width:16px;height:16px;display:inline-block;vertical-align:middle;background:url(../images/silk/folder.png);} diff -r 2489f9da0d29 -r 397800eff312 static/june_2007_style/library.css.tmpl --- a/static/june_2007_style/library.css.tmpl Thu Aug 06 15:19:02 2009 -0400 +++ b/static/june_2007_style/library.css.tmpl Thu Aug 06 15:25:18 2009 -0400 @@ -69,7 +69,22 @@ } span.expandLink { - width: 100%; - height: 100%; - display: block; + width: 16px; + height: 16px; + display: inline-block; + vertical-align: middle; + background: url(../images/silk/resultset_next.png); } + +.folderRow.expanded span.expandLink { + background: url(../images/silk/resultset_bottom.png); +} + +.folderRow span.rowIcon { + width: 16px; + height: 16px; + display: inline-block; + vertical-align: middle; + background: url(../images/silk/folder.png); +} + diff -r 2489f9da0d29 -r 397800eff312 static/june_2007_style/process_css.py --- a/static/june_2007_style/process_css.py Thu Aug 06 15:19:02 2009 -0400 +++ b/static/june_2007_style/process_css.py Thu Aug 06 15:25:18 2009 -0400 @@ -139,7 +139,7 @@ pad = 10 - class SpriteGroup(): + class SpriteGroup( object ): def __init__( self, name ): self.name = name self.offset = 0 @@ -152,7 +152,7 @@ self.offset += sprite.image.size[1] + pad return sprite - class Sprite(): + class Sprite( object ): def __init__( self, fname, offset ): self.fname = fname self.image = Image.open( os.path.join( image_dir, fname ) ) diff -r 2489f9da0d29 -r 397800eff312 templates/admin/forms/create_form.mako --- a/templates/admin/forms/create_form.mako Thu Aug 06 15:19:02 2009 -0400 +++ b/templates/admin/forms/create_form.mako Thu Aug 06 15:25:18 2009 -0400 @@ -26,7 +26,7 @@ <div style="clear: both"></div> </div> <div class="form-row"> - <input type="submit" name="save_form" value="Save"/> + <input type="submit" name="save_form" value="Add fields"/> </div> </form> </div> diff -r 2489f9da0d29 -r 397800eff312 templates/admin/forms/edit_form.mako --- a/templates/admin/forms/edit_form.mako Thu Aug 06 15:19:02 2009 -0400 +++ b/templates/admin/forms/edit_form.mako Thu Aug 06 15:25:18 2009 -0400 @@ -84,7 +84,7 @@ <div style="clear: both"></div> </div> %endfor - <div class="toolFormTitle">Sample fields (${len(form.fields)})</div> + <div class="toolFormTitle">Fields (${len(form.fields)})</div> %for ctr, field in enumerate(field_details): ${render_field( ctr, field )} %endfor diff -r 2489f9da0d29 -r 397800eff312 templates/admin/forms/manage_forms.mako --- a/templates/admin/forms/manage_forms.mako Thu Aug 06 15:19:02 2009 -0400 +++ b/templates/admin/forms/manage_forms.mako Thu Aug 06 15:25:18 2009 -0400 @@ -3,6 +3,10 @@ <%def name="title()">Manage Form Definitions</%def> + +%if msg: + ${render_msg( msg, messagetype )} +%endif ## Render a row <%def name="render_row( form, ctr )"> @@ -12,11 +16,18 @@ <tr> %endif <td> - <b><a href="${h.url_for( controller='forms', action='edit', form_id=form.id, read_only=True )}">${form.name}</a></b> + <a href="${h.url_for( controller='forms', action='edit', form_id=form.id, read_only=True )}">${form.name}</a> <a id="form-${form.id}-popup" class="popup-arrow" style="display: none;">▼</a> - <div popupmenu="form-${form.id}-popup"> - <a class="action-button" href="${h.url_for( action='edit', form_id=form.id, show_form=True )}">Edit form definition</a> - </div> + %if form.form_definition_current.deleted: + <div popupmenu="form-${form.id}-popup"> + <a class="action-button" href="${h.url_for( action='undelete', form_id=form.id )}">Undelete</a> + </div> + %else: + <div popupmenu="form-${form.id}-popup"> + <a class="action-button" href="${h.url_for( action='edit', form_id=form.id, show_form=True )}">Edit form definition</a> + <a class="action-button" confirm="Click OK to delete the form ${form.name}." href="${h.url_for( action='delete', form_id=form.id )}">Delete</a> + </div> + %endif </td> <td><i>${form.desc}</i></td> </tr> @@ -24,36 +35,33 @@ <h2> - %if deleted: - Deleted - %endif Forms </h2> - - <ul class="manage-table-actions"> - %if not deleted: - <li> - <a class="action-button" href="${h.url_for( controller='forms', action='new', new=True )}"> - <img src="${h.url_for('/static/images/silk/add.png')}" /> - <span>Define a new form</span></a> - </li> - %endif + <li> + <a class="action-button" href="${h.url_for( controller='forms', action='new', new=True )}"> + <img src="${h.url_for('/static/images/silk/add.png')}" /> + <span>Define a new form</span></a> + </li> </ul> - -%if msg: - ${render_msg( msg, messagetype )} -%endif - +<div class="grid-header"> + ##<span class="title">Filter:</span> + %for i, filter in enumerate( ['Active', 'Deleted', 'All'] ): + %if i > 0: + <span>|</span> + %endif + %if show_filter == filter: + <span class="filter"><a href="${h.url_for( controller='forms', action='manage', show_filter=filter )}"><b>${filter}</b></a></span> + %else: + <span class="filter"><a href="${h.url_for( controller='forms', action='manage', show_filter=filter )}">${filter}</a></span> + %endif + %endfor +</div> %if not fdc_list: - %if deleted: - There are no deleted forms - %else: - There are no forms. - %endif + There are no forms. %else: <table class="grid"> <thead> @@ -70,4 +78,4 @@ %endfor </tbody> </table> -%endif +%endif \ No newline at end of file diff -r 2489f9da0d29 -r 397800eff312 templates/admin/requests/grid.mako --- a/templates/admin/requests/grid.mako Thu Aug 06 15:19:02 2009 -0400 +++ b/templates/admin/requests/grid.mako Thu Aug 06 15:25:18 2009 -0400 @@ -76,15 +76,27 @@ <div class="grid-header"> <h2>${grid.title}</h2> -## %if len(query.all()): -## <span class="title">Filter:</span> -## %for i, filter in enumerate( grid.standard_filters ): -## %if i > 0: -## <span>|</span> -## %endif -## <span class="filter"><a href="${url( filter.get_url_args() )}">${filter.label}</a></span> -## %endfor -## %endif + ##%if len(query.all()): + ##<span class="title">Filter:</span> + %for i, filter in enumerate( grid.standard_filters ): + %if i > 0: + <span>|</span> + %endif + %if 'state' in grid.default_filter: + %if grid.default_filter['state'] == filter.label: + <span class="filter"><a href="${h.url_for( controller='requests_admin', action='list', show_filter=filter.label )}"><b>${filter.label}</b></a></span> + %else: + <span class="filter"><a href="${h.url_for( controller='requests_admin', action='list', show_filter=filter.label )}">${filter.label}</a></span> + %endif + %else: + %if filter.label == 'All': + <span class="filter"><a href="${h.url_for( controller='requests_admin', action='list', show_filter=filter.label )}"><b>${filter.label}</b></a></span> + %else: + <span class="filter"><a href="${h.url_for( controller='requests_admin', action='list', show_filter=filter.label )}">${filter.label}</a></span> + %endif + %endif + %endfor + ##%endif </div> @@ -95,7 +107,7 @@ <table class="grid"> <thead> <tr> - <th></th> + ##<th></th> %for column in grid.columns: %if column.visible: <% @@ -137,9 +149,9 @@ %endif > ## Item selection column - <td style="width: 1.5em;"> - <input type="checkbox" name="id" value=${trans.security.encode_id( item.id )} class="grid-row-select-checkbox" /> - </td> + ##<td style="width: 1.5em;"> + ## <input type="checkbox" name="id" value=${trans.security.encode_id( item.id )} class="grid-row-select-checkbox" /> + ##</td> ## Data columns %for column in grid.columns: %if column.visible: diff -r 2489f9da0d29 -r 397800eff312 templates/admin/requests/manage_request_types.mako --- a/templates/admin/requests/manage_request_types.mako Thu Aug 06 15:19:02 2009 -0400 +++ b/templates/admin/requests/manage_request_types.mako Thu Aug 06 15:25:18 2009 -0400 @@ -3,10 +3,11 @@ <%def name="title()">request Types</%def> +%if msg: + ${render_msg( msg, messagetype )} +%endif + <h2> - %if deleted: - Deleted - %endif Request Types </h2> @@ -16,16 +17,21 @@ </li> </ul> -%if msg: - ${render_msg( msg, messagetype )} -%endif - +<div class="grid-header"> + ##<span class="title">Filter:</span> + %for i, filter in enumerate( ['Active', 'Deleted', 'All'] ): + %if i > 0: + <span>|</span> + %endif + %if show_filter == filter: + <span class="filter"><a href="${h.url_for( controller='admin', action='manage_request_types', show_filter=filter )}"><b>${filter}</b></a></span> + %else: + <span class="filter"><a href="${h.url_for( controller='admin', action='manage_request_types', show_filter=filter )}">${filter}</a></span> + %endif + %endfor +</div> %if not request_types: - %if deleted: - There are no deleted request types - %else: - There are no request types. - %endif + There are no request types. %else: <table class="grid"> <thead> @@ -39,7 +45,19 @@ <tbody> %for request_type in request_types: <tr> - <td><b><a href="${h.url_for( controller='admin', action='request_type', edit='True', id=request_type.id)}">${request_type.name}</a></b></td> + <td> + <a href="${h.url_for( controller='admin', action='request_type', edit='True', id=request_type.id)}">${request_type.name}</a> + <a id="request_type-${request_type.id}-popup" class="popup-arrow" style="display: none;">▼</a> + %if request_type.deleted: + <div popupmenu="request_type-${request_type.id}-popup"> + <a class="action-button" href="${h.url_for( action='undelete_request_type', request_type_id=request_type.id )}">Undelete</a> + </div> + %else: + <div popupmenu="request_type-${request_type.id}-popup"> + <a class="action-button" confirm="Click OK to delete the request type ${request_type.name}." href="${h.url_for( action='delete_request_type', request_type_id=request_type.id )}">Delete</a> + </div> + %endif + </td> <td><i>${request_type.desc}</i></td> <td><a href="${h.url_for( controller='forms', action='edit', form_id=request_type.request_form.id, read_only=True)}">${request_type.request_form.name}</a></td> <td><a href="${h.url_for( controller='forms', action='edit', form_id=request_type.sample_form.id, read_only=True)}">${request_type.sample_form.name}</a></td> diff -r 2489f9da0d29 -r 397800eff312 templates/admin/samples/bar_codes.mako --- a/templates/admin/samples/bar_codes.mako Thu Aug 06 15:19:02 2009 -0400 +++ b/templates/admin/samples/bar_codes.mako Thu Aug 06 15:25:18 2009 -0400 @@ -1,12 +1,14 @@ <%inherit file="/base.mako"/> <%namespace file="/message.mako" import="render_msg" /> -<h2>Bar codes for Samples of Request "${request.name}"</h2> -<h3>User: ${user.email}</h3> %if msg: ${render_msg( msg, messagetype )} %endif + + +<h2>Bar codes for Samples of Request "${request.name}"</h2> +<h3>User: ${user.email}</h3> <ul class="manage-table-actions"> <li> @@ -31,7 +33,7 @@ <td><b><a>${sample.name}</a></b></td> <td><a>${sample.desc}</a></td> <td> - <input type="text" name="sample_${index}_bar_code" value=${sample.bar_code} size="40"/> + ${widgets[index].get_html()} </td> </tr> %endfor diff -r 2489f9da0d29 -r 397800eff312 templates/base_panels.mako --- a/templates/base_panels.mako Thu Aug 06 15:19:02 2009 -0400 +++ b/templates/base_panels.mako Thu Aug 06 15:25:18 2009 -0400 @@ -149,15 +149,17 @@ ${tab( "workflow", "Workflow", h.url_for( controller='workflow', action='index' ))} ${tab( "libraries", "Libraries", h.url_for( controller='library', action='index' ))} - - <td class="tab"> - <a>Lab</a> - <div class="submenu"> - <ul> - <li><a target="requests" href="${h.url_for( controller='requests', action='index' )}">Sequencing Requests</a></li> - </ul> - </div> - </td> + + %if trans.request_types(): + <td class="tab"> + <a>Lab</a> + <div class="submenu"> + <ul> + <li><a target="requests" href="${h.url_for( controller='requests', action='index' )}">Sequencing Requests</a></li> + </ul> + </div> + </td> + %endif %if app.config.get_bool( 'enable_tracks', False ): <td class="tab"> diff -r 2489f9da0d29 -r 397800eff312 templates/dataset/errors.mako --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/dataset/errors.mako Thu Aug 06 15:25:18 2009 -0400 @@ -0,0 +1,72 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> + <head> + <title>Dataset generation errors</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <link href="/static/style/base.css" rel="stylesheet" type="text/css" /> + <style> + pre + { + background: white; + color: black; + border: dotted black 1px; + overflow: auto; + padding: 10px; + } + </style> + </head> + + <body> + <h2>Dataset generation errors</h2> + <p><b>Dataset ${dataset.hid}: ${dataset.display_name()}</b></p> + + %if dataset.creating_job_associations: + <% job = dataset.creating_job_associations[0].job %> + %if job.traceback: + The Galaxy framework encountered the following error while attempting to run the tool: + <pre>${job.traceback}</pre> + %endif + %if job.stderr or job.info: + Tool execution generated the following error message: + %if job.stderr: + <pre>${job.stderr}</pre> + %elif job.info: + <pre>${job.info}</pre> + %endif + %else: + Tool execution did not generate any error messages. + %endif + %if job.stdout: + The tool produced the following additional output: + <pre>${job.stdout}</pre> + %endif + %else: + The tool did not create any additional job / error info. + %endif + + <h2>Report this error to the Galaxy Team</h2> + <p> + The Galaxy team regularly reviews errors that occur in the application. + However, if you would like to provide additional information (such as + what you were trying to do when the error occurred) and a contact e-mail + address, we will be better able to investigate your problem and get back + to you. + </p> + <div class="toolForm"> + <div class="toolFormTitle">Error Report</div> + <div class="toolFormBody"> + <form name="report_error" action="${h.url_for( action='report_error')}" method="post" > + <input type="hidden" name="id" value="${dataset.id}" /> + <div class="form-row"> + <label>Your email</label> + <input type="text" name="email" size="40" /> + </div> + <div class="form-row"> + <label>Message</label> + <textarea name="message", rows="10" cols="40" /> + </div> + </form> + </div> + </div> + </body> +</html> diff -r 2489f9da0d29 -r 397800eff312 templates/dataset/errors.tmpl --- a/templates/dataset/errors.tmpl Thu Aug 06 15:19:02 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -<html> - <head> - <title>Dataset generation errors</title> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <link href="/static/style/base.css" rel="stylesheet" type="text/css" /> - <style> - pre - { - background: white; - color: black; - border: dotted black 1px; - overflow: auto; - padding: 10px; - } - </style> - </head> - - <body> - <h2>Dataset generation errors</h2> - <p><b>Dataset $dataset.hid: $dataset.display_name</b></p> - - #if $dataset.creating_job_associations - #set job = $dataset.creating_job_associations[0].job - #if job.traceback - The Galaxy framework encountered the following error while attempting to run the tool: - <pre>${job.traceback}</pre> - #end if - #if $job.stderr or $job.info - Tool execution generated the following error message: - #if $job.stderr - <pre>${job.stderr}</pre> - #elif $job.info - <pre>${job.info}</pre> - #end if - #else - Tool execution did not generate any error messages. - #end if - #if $job.stdout - The tool produced the following additional output: - <pre>${job.stdout}</pre> - #end if - #else - The tool did not create any additional job / error info. - #end if - - <h2>Report this error to the Galaxy Team</h2> - <p> - The Galaxy team regularly reviews errors that occur in the application. - However, if you would like to provide additional information (such as - what you were trying to do when the error occurred) and a contact e-mail - address, we will be better able to investigate your problem and get back - to you. - </p> - <div class="toolForm"> - <div class="toolFormTitle">Error Report</div> - <div class="toolFormBody"> - <form name="report_error" action="${h.url_for( action='report_error')}" method="post" > - <input type="hidden" name="id" value="$dataset.id" /> - <table> - <tr valign="top"><td>Your Email:</td><td><input type="text" name="email" size="40" /></td></tr> - <tr valign="top"><td>Message:</td><td><textarea name="message", rows="10" cols="40" /></textarea></td></tr> - <tr><td></td><td><input type="submit" value="Report"> - </table> - </form> - </div> - </div> - </body> -</html> diff -r 2489f9da0d29 -r 397800eff312 templates/dataset/validation.tmpl --- a/templates/dataset/validation.tmpl Thu Aug 06 15:19:02 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -<html> - -<head> -<title>Galaxy</title> -<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> -<link href="/static/style/base.css" rel="stylesheet" type="text/css" /> -<script type="text/javascript" src="/static/universe.js">var dummy1=0;</script> -</head> - -<body onLoad="frame_dw();"> - -<div class="toolForm"> - <div class="toolFormTitle">Dataset Errors: $data.name</div> - <div class="toolFormBody"> - <form action="/dataset_errors" method="post" > - - <table> - <tr><td>Name:</td><td>$data.name</td></tr> - <tr><td>Info:</td><td>$data.info<input type="hidden" name="id" value="$data.id"></td></tr> - <tr><td>Errors:</td><td>$len($data.validation_errors)</td></tr> - </table> - #if len($data.validation_errors) > 0: - <table> - <tr><td>Displaying the first 10 errors:</td></tr> - #for count in range(min(len($data.validation_errors),10)): - <tr><td>$data.validation_errors[count].message</td></tr> - #end for - #if $data.datatype.repair_methods($data): - #for $option, $description in $data.datatype.repair_methods($data): - <tr><td><input type="checkbox" name="$option" value="true" />$description</td></tr> - #end for - <tr><td><input type="submit" name="fix_errors" value="Submit"></td></tr> - #end if - </table> - #end if - </form> - </div> -</div> - - -</body> - -</html> \ No newline at end of file diff -r 2489f9da0d29 -r 397800eff312 templates/library/browse_library.mako --- a/templates/library/browse_library.mako Thu Aug 06 15:19:02 2009 -0400 +++ b/templates/library/browse_library.mako Thu Aug 06 15:25:18 2009 -0400 @@ -1,5 +1,5 @@ <%inherit file="/base.mako"/> -<%namespace file="common.mako" import="render_dataset" /> +## <%namespace file="common.mako" import="render_dataset" /> <%namespace file="/message.mako" import="render_msg" /> <% from galaxy import util %> @@ -10,102 +10,144 @@ </%def> <% + def name_sorted( l ): return sorted( l, lambda a, b: cmp( a.name.lower(), b.name.lower() ) ) + +class RowCounter( object ): + def __init__( self ): + self.count = 0 + def increment( self ): + self.count += 1 + def __str__( self ): + return str( self.count ) + %> <script type="text/javascript"> $( document ).ready( function () { - // Check/uncheck boxes in subfolders. - $("input.folderCheckbox").click( function() { - if ( $(this).is(":checked") ) { - //$(this).parent().children().find("input[type=checkbox]").each( function() { this.checked = true; }); - $(this).parent().next("ul").find("input[type=checkbox]").each( function() { this.checked = true; }); - } else { - //$(this).parent().children().find("input[type=checkbox]").each( function() { this.checked = false; }); - $(this).parent().next("ul").find("input[type=checkbox]").each( function() { this.checked = false; }); - } - }); - // If you uncheck a lower level checkbox, uncheck the boxes above it - // (since deselecting a child means the parent is not fully selected any - // more). - $("input[type=checkbox]").click( function() { - if ( ! $(this).is(":checked") ) { - //var folder_rows = $(this).parents("ul").next("li.folderRow"); - //var folder_rows = $(this).parents("ul").children("li.folderRow"); - var folder_rows = $(this).parents("ul").prev("li.folderRow"); - //$(folder_rows).children("input[type=checkbox]").not(this).each( function() { - $(folder_rows).find("input[type=checkbox]").each( function() { - this.checked = false; + $("#library-grid").each( function() { + // Recursively fill in children and descendents of each row + var process_row = function( q, parents ) { + // Find my index + var index = $(q).parent().children().index( $(q) ); + // Find my immediate children + var children = $(q).siblings().filter( "[parent='" + index + "']" ); + // Recursively handle them + var descendents = children; + children.each( function() { + child_descendents = process_row( $(this), parents.add( q ) ); + descendents = descendents.add( child_descendents ); }); - } - }); - // Handle the hide/show triangles - $("span.expandLink").wrap( "<a href='#' class='expandLink'></a>" ).click( function() { - var contents = $(this).parents("li:first").next("ul"); - if ( this.id == "libraryRow" ) { - var icon_open = "${h.url_for( '/static/images/silk/book_open.png' )}"; - var icon_closed = "${h.url_for( '/static/images/silk/book.png' )}"; - } else { - var icon_open = "${h.url_for( '/static/images/silk/folder_page.png' )}"; - var icon_closed = "${h.url_for( '/static/images/silk/folder.png' )}"; - } - if ( contents.is(":visible") ) { - contents.slideUp("fast"); - $(this).find("img.expanderIcon").each( function() { this.src = "${h.url_for( '/static/images/silk/resultset_next.png' )}"; }); - $(this).find("img.rowIcon").each( function() { this.src = icon_closed; }); - } else { - contents.slideDown("fast"); - $(this).find("img.expanderIcon").each( function() { this.src = "${h.url_for( '/static/images/silk/resultset_bottom.png' )}"; }); - $(this).find("img.rowIcon").each( function() { this.src = icon_open; }); - } - }); - // Hide all dataset bodies - $("div.historyItemBody").hide(); - // Handle the dataset body hide/show link. - $("div.historyItemWrapper").each( function() { - var id = this.id; - var li = $(this).parent(); - var body = $(this).children( "div.historyItemBody" ); - var peek = body.find( "pre.peek" ) - $(this).children( ".historyItemTitleBar" ).find( ".historyItemTitle" ).wrap( "<a href='#'></a>" ).click( function() { - if ( body.is(":visible") ) { - if ( $.browser.mozilla ) { peek.css( "overflow", "hidden" ) } - body.slideUp( "fast" ); - li.removeClass( "datasetHighlighted" ); - } - else { - body.slideDown( "fast", function() { - if ( $.browser.mozilla ) { peek.css( "overflow", "auto" ); } - }); - li.addClass( "datasetHighlighted" ); - } - return false; - }); + // Set up expand / hide link + $(q).find( "span.expandLink").wrap( "<a href='#' class='expandLink'></a>" ).click( function() { + if ( children.is( ":visible" ) ) { + descendents.hide(); + descendents.removeClass( "expanded" ); + q.removeClass( "expanded" ); + // expanded = false; + } else { + children.show(); + q.addClass( "expanded" ); + // expanded = true; + } + }); + // Check/uncheck boxes in subfolders. + q.children( "td" ).children( "input[type=checkbox]" ).click( function() { + if ( $(this).is(":checked") ) { + descendents.find( "input[type=checkbox]").attr( 'checked', true ); + } else { + descendents.find( "input[type=checkbox]").attr( 'checked', false ); + // If you uncheck a lower level checkbox, uncheck the boxes above it + // (since deselecting a child means the parent is not fully selected any + // more). + parents.children( "td" ).children( "input[type=checkbox]" ).attr( "checked", false ); + } + }); + // return descendents for use by parent + return descendents; + } + $(this).find( "tbody tr" ).not( "[parent]").each( function() { + descendents = process_row( $(this), $([]) ); + descendents.hide(); + }); }); }); </script> -<![if gte IE 7]> -<script type="text/javascript"> - $( document ).ready( function() { - // Add rollover effect to any image with a 'rollover' attribute - preload_images = {} - $( "img[rollover]" ).each( function() { - var r = $(this).attr('rollover'); - var s = $(this).attr('src'); - preload_images[r] = true; - $(this).hover( - function() { $(this).attr( 'src', r ) }, - function() { $(this).attr( 'src', s ) } - ) - }) - for ( r in preload_images ) { $( "<img>" ).attr( "src", r ) } - }) -</script> -<![endif]> +<%def name="render_dataset( library_dataset, selected, library, pad, parent, row_conter )"> + <% + ## The received data must always be a LibraryDataset object, but the object id passed to methods from the drop down menu + ## should be the underlying ldda id to prevent id collision ( which could happen when displaying children, which are always + ## lddas ). We also need to make sure we're displaying the latest version of this library_dataset, so we display the attributes + ## from the ldda. + ldda = library_dataset.library_dataset_dataset_association + if ldda.user: + uploaded_by = ldda.user.email + else: + uploaded_by = 'anonymous' + if ldda == ldda.library_dataset.library_dataset_dataset_association: + current_version = True + else: + current_version = False + %> -<%def name="render_folder( folder, folder_pad, created_ldda_ids, library_id )"> + <tr class="datasetRow" + %if parent is not None: + parent="${parent}" + style="display: none;" + %endif + > + <td style="padding-left: ${pad+20}px;"> + + + %if selected: + <input type="checkbox" name="ldda_ids" value="${ldda.id}" checked/> + %else: + <input type="checkbox" name="ldda_ids" value="${ldda.id}"/> + %endif + + <a href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, info=True )}"><b>${ldda.name[:60]}</b></a> + <a id="dataset-${ldda.id}-popup" class="popup-arrow" style="display: none;">▼</a> + + <div popupmenu="dataset-${ldda.id}-popup"> + %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): + <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, edit_info=True )}">Edit this dataset's information</a> + %else: + <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, information=True )}">View this dataset's information</a> + %endif + ## We're disabling the ability to add templates at the LDDA and LibraryDataset level, but will leave this here for possible future use + ##%if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=ldda.library_dataset ): + ## <a class="action-button" href="${h.url_for( controller='library', action='info_template', library_id=library.id, library_dataset_id=library_dataset.id, new_template=True )}">Add an information template to this dataset</a> + ##%endif + %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=ldda.dataset ) and trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=ldda.library_dataset ): + <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, permissions=True )}">Edit this dataset's permissions</a> + %if current_version and trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): + <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, replace_id=library_dataset.id )}">Upload a new version of this dataset</a> + %endif + %endif + %if ldda.has_data: + <a class="action-button" href="${h.url_for( controller='library', action='datasets', library_id=library.id, ldda_ids=str( ldda.id ), do_action='add' )}">Import this dataset into your current history</a> + <a class="action-button" href="${h.url_for( controller='library', action='download_dataset_from_folder', id=ldda.id, library_id=library.id )}">Download this dataset</a> + %endif + </div> + + </td> + <td>${ldda.message}</td> + <td>${uploaded_by}</td> + <td>${ldda.create_time.strftime( "%Y-%m-%d" )}</td> + </tr> + + <% + my_row = row_counter.count + row_counter.increment() + %> + + +</%def> + + +<%def name="render_folder( folder, folder_pad, created_ldda_ids, library_id, parent=None, row_counter=None )"> <% def show_folder(): if trans.app.security_agent.check_folder_contents( trans.user, folder ) or trans.app.security_agent.show_library_item( trans.user, folder ): @@ -119,27 +161,36 @@ else: pad = folder_pad + 20 if folder_pad == 0: - expander = "/static/images/silk/resultset_bottom.png" - folder_img = "/static/images/silk/folder_page.png" subfolder = False else: - expander = "/static/images/silk/resultset_next.png" - folder_img = "/static/images/silk/folder.png" subfolder = True created_ldda_id_list = util.listify( created_ldda_ids ) if created_ldda_id_list: created_ldda_ids = [ int( ldda_id ) for ldda_id in created_ldda_id_list ] + my_row = None %> %if not root_folder: - <li class="folderRow libraryOrFolderRow" style="padding-left: ${pad}px;"> - <input type="checkbox" class="folderCheckbox" style="float: left;"/> - <div class="rowTitle"> - <span class="expandLink"><img src="${h.url_for( expander )}" class="expanderIcon"/><img src="${h.url_for( folder_img )}" class="rowIcon"/> + <tr class="folderRow libraryOrFolderRow" + %if parent is not None: + parent="${parent}" + style="display: none;" + %endif + > + <td style="padding-left: ${folder_pad}px;"> + + <span class="expandLink"></span> + + <input type="checkbox" class="folderCheckbox"/> + + <span class="rowIcon"></span> + ${folder.name} %if folder.description: <i>- ${folder.description}</i> %endif + <a id="folder_img-${folder.id}-popup" class="popup-arrow" style="display: none;">▼</a> + <div popupmenu="folder_img-${folder.id}-popup"> %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=folder ): <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library_id, folder_id=folder.id )}">Add datasets to this folder</a> @@ -167,125 +218,135 @@ %endif </div> </div> - </li> + <td colspan="3"></td> + </tr> + <% + my_row = row_counter.count + row_counter.increment() + %> %endif - %if subfolder: - <ul id="subFolder" style="display: none;"> - %else: - <ul> - %endif - %for child_folder in name_sorted( folder.active_folders ): - ${render_folder( child_folder, pad, created_ldda_ids, library_id )} - %endfor - %for library_dataset in name_sorted( folder.active_datasets ): - <% - selected = created_ldda_ids and library_dataset.library_dataset_dataset_association.id in created_ldda_ids - %> - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.DATASET_ACCESS, dataset=library_dataset.library_dataset_dataset_association.dataset ): - <li class="datasetRow" style="padding-left: ${pad + 20}px;">${render_dataset( library_dataset, selected, library )}</li> - %endif - %endfor - </ul> +