Changeset 1864


Ignore:
Timestamp:
May 23, 2011, 4:36:00 PM (6 years ago)
Author:
s.h.sikkema@…
Message:

in exporter: module error display improvements (ie. display on screen but still able to export); removed changes to simplewizard; removed unnecessary imports; should handle 'null' parent subject from samples correctly; should handle non number values from modules correctly; deselects module measurements in case of module error/no measurements; removed obsolete entry in topnav

Location:
trunk/grails-app
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/dbnp/studycapturing/AssayController.groovy

    r1830 r1864  
    139139                                flow.fieldMap = assayService.collectAssayTemplateFields(flow.assay)
    140140
     141                flash.errorMessage = flow.fieldMap.remove('ModuleError')
    141142                                flow.measurementTokens = flow.fieldMap.remove('Module Measurement Data')
    142143                        }.to "selectFields"
     
    147148                selectFields {
    148149                        on ("submit"){
     150               
    149151                                def fieldMapSelection = [:]
    150152
     
    173175                // collect the assay data according to user selecting
    174176                                def assayData           = assayService.collectAssayData(flow.assay, fieldMapSelection, measurementTokens)
     177
     178                flash.errorMessage      = assayData.remove('ModuleError')
     179
    175180                                flow.rowData            = assayService.convertColumnToRowStructure(assayData)
    176181
  • trunk/grails-app/controllers/dbnp/studycapturing/SimpleWizardController.groovy

    r1838 r1864  
    3737         */
    3838        def index = {
    39 //              if( params.id )
    40 //                      redirect( action: "simpleWizard", id: params.id );
    41 //              else
    42 //                      redirect( action: "simpleWizard" );
    4339        redirect action: 'simpleWizard', params: params
    4440        }
     
    5046                                if (!flow.study) retrievalError()
    5147
    52                 flow.inferDesign = params.inferDesign
    5348                                // Search for studies
    5449                                flow.studies = Study.giveWritableStudies( authenticationService.getLoggedInUser(), 100 )
     
    824819        def errors = [];
    825820
    826         if (flow.inferDesign) {
    827 
    828             println 'Entered infer design...'
    829 
    830             // find the indices of the classes of interest in the records
    831             def sampleIdx           = table[0].findIndexOf{it.class.name == 'dbnp.studycapturing.Sample'}
    832             def samplingEventIdx    = table[0].findIndexOf{it.class.name == 'dbnp.studycapturing.SamplingEvent'}
    833             def subjectIdx          = table[0].findIndexOf{it.class.name == 'dbnp.studycapturing.Subject'}
    834 
    835             // Check for duplicate samples
    836             def samples = table.collect{it[sampleIdx]}
    837 
    838             def uniques     = [] as Set
    839             def duplicates  = [] as Set
    840 
    841             // this approach separates the unique from the duplicate entries
    842             samples*.name.each {
    843                 uniques.add(it) || duplicates.add(it)
    844             }
    845 
    846             duplicates.each{ duplicateName ->
    847                 samples.findAll{it.name == duplicateName}.each{ sample ->
    848                     numInvalidEntities++
    849                     failedcells = addNonValidatingCells(failedcells, sample, flow)
    850                     errors += "(Sample) duplicate name: $duplicateName"
    851                 }
    852             }
    853 
    854             // A closure that returns a sub list of entities from a list that have
    855             // unique values of a property indicated by propertyName
    856             def uniqueEntitiesByProperty = { entities, propertyName ->
    857 
    858                entities*."$propertyName".unique().collect { uniquePropertyValue ->
    859 
    860                     entities.find{ it."$propertyName" == uniquePropertyValue }
    861 
    862                 }
    863             }
    864 
    865             def addToCollectionIfNonexistent = { parent, collectionName, entity, propertyName ->
    866 
    867                 if (!parent[collectionName].find{it[propertyName] == entity[propertyName]})
    868                     parent."addTo${collectionName.capitalize()}" entity
    869 
    870             }
    871 
    872             // collect unique subjects and sampling events from table
    873             def uniqueSubjects =
    874                 uniqueEntitiesByProperty(table.collect{it[subjectIdx]}, 'name')
    875             uniqueSubjects.each{
    876                 addToCollectionIfNonexistent study, 'subjects', it, 'name'
    877                 it.species = Term.findByName('Homo sapiens')
    878             }
    879 
    880             def uniqueSamplingEvents =
    881                 uniqueEntitiesByProperty(table.collect{it[samplingEventIdx]}, 'startTime')
    882             uniqueSamplingEvents.each{
    883                 it.setFieldValue( 'sampleTemplate', flow.sampleForm.template.Sample.name )
    884             }
    885 
    886             // create an event group for each unique sampling event (not much of a group, is it ...)
    887             def eventGroups = uniqueSamplingEvents.collect{
    888 
    889                 def eventGroupName = "Sampling_${it.sampleTemplate.name}_${new RelTime(it.startTime).toString()}"
    890 
    891                 def eventGroup = study.eventGroups.find{it.name == eventGroupName} ?: //EventGroup.findByParentAndName(study, eventGroupName) ?:
    892                     new EventGroup(name: eventGroupName)
    893 
    894                 eventGroup.addToSamplingEvents it
    895 
    896                 if (!study.eventGroups.find{it == eventGroup})
    897                     study.addToEventGroups eventGroup
    898 
    899                 if (!it.parent) study.addToSamplingEvents it
    900 
    901                 println eventGroup.name
    902 
    903                 eventGroup
    904 
    905             }
    906 
    907             table.each{ record ->
    908 
    909                 Sample sample = record[sampleIdx]
    910 
    911                 // gather all sample related entities
    912                 def correspondingSamplingEvent  = uniqueSamplingEvents.find {it.startTime == record[samplingEventIdx].startTime}
    913                 def correspondingSubject        = uniqueSubjects.find{it.name == record[subjectIdx].name}
    914                 def correspondingEventGroup     = eventGroups.find{correspondingSamplingEvent in it.samplingEvents}
    915 
    916                 addToCollectionIfNonexistent correspondingSamplingEvent, 'samples', sample, 'name'
    917 
    918                 sample.parentSubject = correspondingSubject
    919 
    920                 correspondingEventGroup.addToSamplingEvents correspondingSamplingEvent
    921 
    922                 if (!correspondingEventGroup.subjects.find{it.name == correspondingSubject.name})
    923                     correspondingEventGroup.addToSubjects correspondingSubject
    924 
    925                 addToCollectionIfNonexistent study, 'samples', sample, 'name'
    926 
    927             }
    928 
    929         } else {
    930             // Add all samples
    931             table.each { record ->
    932                 record.each { entity ->
    933                     if( entity ) {
    934                         // Determine entity class and add a parent. Add the entity to the study
    935                         def preferredIdentifier = importerService.givePreferredIdentifier( entity.class );
    936                         def equalClosure = { it.getIdentifier() == entity.getIdentifier() }
    937                         def entityName = entity.class.name[ entity.class.name.lastIndexOf( "." ) + 1 .. -1 ]
    938 
    939                         entity.parent = study
    940 
    941                         switch( entity.class ) {
    942                             case Sample:
    943                                 if( !study.samples?.find( equalClosure ) ) {
    944                                     study.addToSamples( entity );
     821        // Add all samples
     822        table.each { record ->
     823            record.each { entity ->
     824                if( entity ) {
     825                    // Determine entity class and add a parent. Add the entity to the study
     826                    def preferredIdentifier = importerService.givePreferredIdentifier( entity.class );
     827                    def equalClosure = { it.getIdentifier() == entity.getIdentifier() }
     828                    def entityName = entity.class.name[ entity.class.name.lastIndexOf( "." ) + 1 .. -1 ]
     829
     830                    entity.parent = study
     831
     832                    switch( entity.class ) {
     833                        case Sample:
     834                            if( !study.samples?.find( equalClosure ) ) {
     835                                study.addToSamples( entity );
     836                            }
     837
     838                            // If an eventgroup is created, add it to the study
     839                            // The eventgroup must have a unique name, but the user shouldn't be bothered with it
     840                            // Add 'group ' + samplename and it that is not unique, add a number to it
     841                            if( entity.parentEventGroup ) {
     842                                study.addToEventGroups( entity.parentEventGroup )
     843
     844                                entity.parentEventGroup.name = "Group " + entity.name
     845                                while( !entity.parentEventGroup.validate() ) {
     846                                    //entity.parentEventGroup.getErrors().each { println it }
     847                                    entity.parentEventGroup.name += "" + Math.floor( Math.random() * 100 )
    945848                                }
    946 
    947                                 // If an eventgroup is created, add it to the study
    948                                 // The eventgroup must have a unique name, but the user shouldn't be bothered with it
    949                                 // Add 'group ' + samplename and it that is not unique, add a number to it
    950                                 if( entity.parentEventGroup ) {
    951                                     study.addToEventGroups( entity.parentEventGroup )
    952 
    953                                     entity.parentEventGroup.name = "Group " + entity.name
    954                                     while( !entity.parentEventGroup.validate() ) {
    955                                         //entity.parentEventGroup.getErrors().each { println it }
    956                                         entity.parentEventGroup.name += "" + Math.floor( Math.random() * 100 )
     849                            }
     850
     851                            break;
     852                        case Subject:
     853                            if( !study.samples?.find( equalClosure ) ) {
     854
     855                                if( preferredIdentifier ) {
     856                                    // Subjects without a name should just be called 'subject'
     857                                    if( !entity.getFieldValue( preferredIdentifier.name ) )
     858                                        entity.setFieldValue( preferredIdentifier.name, "Subject" );
     859
     860                                    // Subjects should have unique names; if the user has entered the same name multiple times,
     861                                    // the subject will be renamed
     862                                    def baseName = entity.getFieldValue( preferredIdentifier.name )
     863                                    def counter = 2;
     864
     865                                    while( study.subjects?.find { it.getFieldValue( preferredIdentifier.name ) == entity.getFieldValue( preferredIdentifier.name ) } ) {
     866                                        entity.setFieldValue( preferredIdentifier.name, baseName + " (" + counter++ + ")" )
    957867                                    }
    958868                                }
    959869
    960                                 break;
    961                             case Subject:
    962                                 if( !study.samples?.find( equalClosure ) ) {
    963 
    964                                     if( preferredIdentifier ) {
    965                                         // Subjects without a name should just be called 'subject'
    966                                         if( !entity.getFieldValue( preferredIdentifier.name ) )
    967                                             entity.setFieldValue( preferredIdentifier.name, "Subject" );
    968 
    969                                         // Subjects should have unique names; if the user has entered the same name multiple times,
    970                                         // the subject will be renamed
    971                                         def baseName = entity.getFieldValue( preferredIdentifier.name )
    972                                         def counter = 2;
    973 
    974                                         while( study.subjects?.find { it.getFieldValue( preferredIdentifier.name ) == entity.getFieldValue( preferredIdentifier.name ) } ) {
    975                                             entity.setFieldValue( preferredIdentifier.name, baseName + " (" + counter++ + ")" )
    976                                         }
    977                                     }
    978 
    979                                     study.addToSubjects( entity );
    980 
    981                                 }
    982 
    983                                 break;
    984                             case Event:
    985                                 if( !study.events?.find( equalClosure ) ) {
    986                                     study.addToEvents( entity );
    987                                 }
    988                                 break;
    989                             case SamplingEvent:
    990                                 // Sampling events have a 'sampleTemplate' value, which should be filled by the
    991                                 // template that is chosen for samples.
    992                                 if( !entity.getFieldValue( 'sampleTemplate' ) ) {
    993                                     entity.setFieldValue( 'sampleTemplate', flow.sampleForm.template.Sample.name )
    994                                 }
    995 
    996                                 if( !study.samplingEvents?.find( equalClosure ) ) {
    997                                     study.addToSamplingEvents( entity );
    998                                 }
    999                                 break;
    1000                         }
    1001 
    1002                         if (!entity.validate()) {
    1003                             numInvalidEntities++;
    1004 
    1005                             // Add this field to the list of failed cells, in order to give the user feedback
    1006                             failedcells = addNonValidatingCells( failedcells, entity, flow )
    1007 
    1008                             // Also create a full list of errors
    1009                             def currentErrors = getHumanReadableErrors( entity )
    1010                             if( currentErrors ) {
    1011                                 currentErrors.each {
    1012                                     errors += "(" + entityName + ") " + it.value;
    1013                                 }
     870                                study.addToSubjects( entity );
     871
     872                            }
     873
     874                            break;
     875                        case Event:
     876                            if( !study.events?.find( equalClosure ) ) {
     877                                study.addToEvents( entity );
     878                            }
     879                            break;
     880                        case SamplingEvent:
     881                            // Sampling events have a 'sampleTemplate' value, which should be filled by the
     882                            // template that is chosen for samples.
     883                            if( !entity.getFieldValue( 'sampleTemplate' ) ) {
     884                                entity.setFieldValue( 'sampleTemplate', flow.sampleForm.template.Sample.name )
     885                            }
     886
     887                            if( !study.samplingEvents?.find( equalClosure ) ) {
     888                                study.addToSamplingEvents( entity );
     889                            }
     890                            break;
     891                    }
     892
     893                    if (!entity.validate()) {
     894                        numInvalidEntities++;
     895
     896                        // Add this field to the list of failed cells, in order to give the user feedback
     897                        failedcells = addNonValidatingCells( failedcells, entity, flow )
     898
     899                        // Also create a full list of errors
     900                        def currentErrors = getHumanReadableErrors( entity )
     901                        if( currentErrors ) {
     902                            currentErrors.each {
     903                                errors += "(" + entityName + ") " + it.value;
    1014904                            }
    1015905                        }
  • trunk/grails-app/domain/dbnp/studycapturing/EventGroup.groovy

    r1457 r1864  
    2222        static constraints = {
    2323                // Ensure that the event group name is unique within the study
    24                 name(unique:['parent']) 
     24                name(unique:['parent'])
    2525        }
    2626}
  • trunk/grails-app/services/dbnp/modules/ModuleCommunicationService.groovy

    r1852 r1864  
    1515package dbnp.modules
    1616
    17 import dbnp.studycapturing.*
    18 import dbnp.authentication.*
    1917import grails.converters.*
    2018import javax.servlet.http.HttpServletResponse
     
    7573        }
    7674
    77         /**
     75    /**
    7876         * Calls a rest method on a module
    7977         *
  • trunk/grails-app/services/dbnp/studycapturing/AssayService.groovy

    r1853 r1864  
    5050                }
    5151
     52        def moduleError = '', moduleMeasurements = []
     53
     54        try {
     55            moduleMeasurements = requestModuleMeasurementNames(assay)
     56        } catch (e) {
     57            moduleError = e.message
     58        }
     59
    5260                def samples = assay.samples
    5361                [               'Subject Data' :            getUsedTemplateFields( samples*."parentSubject".unique() ),
     
    5563                                        'Sample Data' :             getUsedTemplateFields( samples ),
    5664                                        'Event Group' :             [[name: 'name', comment: 'Name of Event Group', displayName: 'name']],
    57 
    58                                         // If module is not reachable, only the field 'module error' is returned, and is filled later on.
    59                                         'Module Measurement Data':  moduleCommunicationService.isModuleReachable(assay.module.url) ? requestModuleMeasurementNames(assay) : [ [ name: "Module error" ] ]
     65                                        'Module Measurement Data':  moduleMeasurements,
     66                    'ModuleError':              moduleError
    6067                ]
    6168
     
    8390                        headerFields.inject([:]) { map, headerField ->
    8491
    85                                 map + [(headerField.displayName): templateEntities.collect {
     92                                map + [(headerField.displayName): templateEntities.collect { entity ->
    8693
    8794                    // default to an empty string
    8895                    def val = ''
    8996
    90                     def field
    91                     try {
    92 
    93                         val = it.getFieldValue(headerField.name)
    94 
    95                         // Convert RelTime fields to human readable strings
    96                         field = it.getField(headerField.name)
    97                         if (field.type == TemplateFieldType.RELTIME)
    98                             val = new RelTime( val as long )
    99 
    100                     } catch (NoSuchFieldException e) { /* pass */ }
     97                    if (entity) {
     98                        def field
     99                        try {
     100
     101                            val = entity.getFieldValue(headerField.name)
     102
     103                            // Convert RelTime fields to human readable strings
     104                            field = entity.getField(headerField.name)
     105                            if (field.type == TemplateFieldType.RELTIME)
     106                                val = new RelTime( val as long )
     107
     108                        } catch (NoSuchFieldException e) { /* pass */ }
     109                    }
    101110
    102111                    (val instanceof Number) ? val : val.toString()}]
     
    177186                }
    178187
     188                def moduleError = '', moduleMeasurementData = [:]
     189
     190                if (measurementTokens) {
     191
     192            try {
     193                moduleMeasurementData = requestModuleMeasurements(assay, measurementTokens, samples)
     194            } catch (e) {
     195                moduleMeasurementData = ['error' : ['Module error, module not available or unknown assay'] * samples.size() ]
     196                moduleError =  e.message
     197            }
     198
     199                }
     200
    179201                [       'Subject Data' :            getFieldValues(samples, fieldMap['Subject Data'], 'parentSubject'),
    180202                                'Sampling Event Data' :     getFieldValues(samples, fieldMap['Sampling Event Data'], 'parentEvent'),
    181203                'Sample Data' :             getFieldValues(samples, fieldMap['Sample Data']),
    182204                'Event Group' :             eventFieldMap,
    183 
    184                 // If module is not reachable, only the message 'module not reachable' is given for each sample
    185                 'Module Measurement Data':  moduleCommunicationService.isModuleReachable(assay.module.url) ?
    186                                                 ( measurementTokens ? requestModuleMeasurements(assay, measurementTokens, samples) : [:] ) :
    187                                                 [ "Module error": [ "Module not reachable" ] * samples.size() ]
     205                'Module Measurement Data' : moduleMeasurementData,
     206                'ModuleError' :             moduleError
    188207                                ]
    189208        }
     
    249268
    250269                def path = moduleUrl + "/rest/getMeasurements/query"
    251         def query = "assayToken=$assay.assayUUID"
     270        def query = "assayToken=${assay.giveUUID()}"
    252271        def jsonArray
    253272
     
    274293         * @param assay                         Assay for which the module measurements should be retrieved
    275294         * @param measurementTokens     List with the names of the fields to be retrieved. Format: [ 'measurementName1', 'measurementName2' ]
    276          * @param samples                       Samples for which the module
     295         * @param samples                       Samples to collect measurements for
    277296         * @return
    278297         */
     
    329348                                                measurements << null
    330349                                        }  else {
    331                                                 measurements << ( moduleData[ valueIndex ] == JSONObject.NULL ? "" : moduleData[ valueIndex ].toDouble() );
     350
     351                        def val
     352                        def measurement = moduleData[ valueIndex ]
     353
     354                        if          (measurement == JSONObject.NULL)    val = ""
     355                        else if     (measurement instanceof Number)     val = measurement
     356                        else if     (measurement.isDouble())            val = measurement.toDouble()
     357                        else val =   measurement.toString()
     358                                                measurements << val
    332359                                        }
    333360                                } else {
     
    487514                        // transpose d into row wise data and combine with header rows
    488515                        headers + d.transpose()
    489                 }
     516                } else []
    490517
    491518        }
  • trunk/grails-app/taglib/dbnp/studycapturing/AssayExporterTagLib.groovy

    r1583 r1864  
    2121    def categorySelector = {attrs, body ->
    2222
     23        def categoryName = attrs.remove('category')
     24        attrs['class'] = 'category'
    2325        out << '<div class="element">'
    24         out << g.checkBox(name: attrs.ref, value: true, class: 'category')
    25         out << attrs.category
     26        out << g.checkBox(attrs)
     27        out << categoryName
    2628        out << '</div>'
    2729
  • trunk/grails-app/views/assay/assayExport/compileExportData.gsp

    r1841 r1864  
    1414  <body>
    1515
    16   <h1>Below you see a preview of the resulting file, click OK to generate it</h1>
     16  <h1>Below you see a preview of the resulting file, click OK to download</h1>
     17
     18  <g:if test="${errorMessage}">
     19  <div class="errormessage">${errorMessage}</div>
     20  </g:if>
    1721
    1822  <table>
  • trunk/grails-app/views/assay/assayExport/selectFields.gsp

    r1841 r1864  
    4040    <h1>Select the columns that you want to be included in the resulting file</h1>
    4141
     42    <g:if test="${errorMessage}">
     43    <div class="errormessage">${errorMessage}</div>
     44    </g:if>
     45
    4246    In this step you can make a selection from the available fields stored in the database related to the samples, including measurement data from a module (if available).
    4347
     
    4751      <g:each in="${fieldMap}" var="entry">
    4852
    49           <assayExporter:categorySelector category="${entry.key}" ref="cat_${catNum}"/>
     53          <assayExporter:categorySelector category="${entry.key}" name="cat_${catNum}" value="${true}" />
    5054
    5155          <assayExporter:fieldSelectors ref="cat_${catNum}" fields="${entry.value}"/>
     
    5559      </g:each>
    5660
    57       <assayExporter:categorySelector category="Measurements" ref="cat_${catNum}"/>
     61      <assayExporter:categorySelector category="Measurements" name="cat_${catNum}" value="${measurementTokens as Boolean}" />
    5862      <g:select name="measurementToken" id="measurementToken" from="${measurementTokens}" value="${measurementTokens}" class="field" multiple="true" />
    5963      <br /><br />
  • trunk/grails-app/views/common/_topnav.gsp

    r1841 r1864  
    1515      <ul class="subnav">
    1616                <li><g:link controller="simpleWizard" action="index">A complete study with straightforward design</g:link></li>
    17                 <li><g:link controller="simpleWizard" action="index" params="[inferDesign: true]">A complete study with inferred design</g:link></li>
     17                %{--<li><g:link controller="simpleWizard" action="index" params="[inferDesign: true]">A complete study with inferred design</g:link></li>--}%
    1818            <li><g:link controller="gdtImporter" action="index">A part of the study design</g:link></li>
    1919            <li><g:link controller="gdtImporter" action="index">A list of studies (choose Study)</g:link></li>
Note: See TracChangeset for help on using the changeset viewer.