Difference between revisions of "Adding Data to a Widget (Example)"

From WormBaseWiki
Jump to navigationJump to search
 
(44 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
== Introduction ==
 
== Introduction ==
A common form of feature request is add a piece of data to be displayed on a page.
+
A common form of feature request is adding some data to be displayed on a page.
  
 +
Here is an example that illustrates work flow required to add some data to a widget.
  
 +
Issue [https://github.com/WormBase/website/issues/2571 #2571] required showing the URL in the "URL" field on the "Overview" widget of an "Analysis" object (the analysis "OMA" for example).
  
Going through an issue example we are going to explain the work flow required to add some data to a widget.
+
Using the data flow graph [[File:DataLoadingWidget1.png|200px|thumb|Widget Loading]] we can see that data goes through 4 stages from the database to the UI - Rest, Conf, API and Template. Usually our work doesn't involve the Rest stage, but it sure does involve modifying the .conf (the configuration), .pm (the API) and .tt2 (the template) files.
 +
 
 +
If you go to the [http://staging.wormbase.org/resources/analysis/OMA#0312--10 OMA] page , you can view the database you are going to be working on by going to Tools -> Tree Display using the menu on the left side of the page.
 +
 
 +
== Formal Testing (before modification) ==
 +
 
 +
You have to do two tests when fixing any issue. One before fixing it and another one after it's fixed.  
  
Issue #2551 required showing the data under the "Former_designating_laboratory" field on the widget "Overview" of a "Gene class" (the Gene class "daf" for example).
+
Here we focus on API Tests, which check that an API module (the subroutine it has) successfully retrieves values from the database.
  
Using the data flow graph [[File:DataLoadingWidget1.png|200px|thumb|Widget Loading]] we can see that data goes through 4 stages from the database to the UI - Rest, Conf, API and Template. Usually our work doesn't involve the Rest stage, but it sure does involve modifying the .conf (the configuration), .pm (the API) and .tt2 (the template) files.
+
API Tests are located at <code>t/api_tests/</code> with the extension .t. '''A .t script usually test a single API module, such as one of the .pm file under lib/WormBase/API/Object/. It has a file name that matches the API module, which it tests.''' This convention helps with locating a test file, making it easier to add new test case.
 +
 
 +
* To add a test case, locate the test file as described above. Create one if you cannot find one by:
 +
** Copy the <code>template.t</code>, a sample test file, and name it according to which API module is being tested
 +
 
 +
* include a test case, which usually contains test for:
 +
** subroutine can be called on the API object
 +
** data is returned from the subroutine
 +
** data return is correct
  
Let's go back to our example. If you go to the "daf" page [http://staging.wormbase.org/resources/gene_class/daf#013--10], you can view the database you are going to be working on by going to Tools -> Tree Display using the menu on the left side of the page. Our field "Former_designating_laboratory" has two data objects under it, a time "19 Mar 2014 14:41:19" and a link to the lab "DR". In this example we are only going to care about displaying the time on the "Overview" widget (if you can't see a widget you can show it by clicking on it from the side menu).
+
<nowiki>
 +
    # This is a test that checks whether former_laboratory attribute is correctly returned
 +
    # related to #2551
 +
    sub test_former_designating_laboratory {
 +
        my $gene_class = $api->fetch({ class => 'Gene_class', name => 'daf' });
  
===First Step:===
+
        can_ok('WormBase::API::Object::Gene_class', ('former_laboratory'));
Add a field in the configuration file. The wormbase.conf file, which you can find under the main website directory contains default configurations for the WormBase application. Now under the "overview" element of the "gene_class" section add the Former Designating Laboratory field "fields former_laboratory". 
 
  
<nowiki> <gene_class>
+
        my $former_designating_laboratory = $gene_class->former_laboratory();
      #
 
<overview>
 
name overview
 
title Overview
 
display report
 
tooltip Gene class (eg Unc) overview.
 
fields name
 
fields other_names
 
fields description
 
fields laboratory
 
fields former_laboratory
 
#                      fields phenotypes
 
fields remarks
 
</overview> </nowiki>
 
  
===Second Step:===
+
        # Please keep test names/descriptions all lower case.
We are going to add a subroutine to the API of the Gene class object in order to grab the data from the database. You can find the API file we need to fix in lib/WormBase/API/Object/, then find the Gene_class object.
+
        isnt($former_designating_laboratory->{'data'}, undef, 'data returned');
 +
is($former_designating_laboratory->{'data'}->{'lab'}->{'id'}, 'DR', 'correct lab returned');
 +
is($former_designating_laboratory->{'data'}{'time'}, '19 Mar 2014 14:41:19', 'correct time returned');
 +
    }
 +
</nowiki>
  
We are going to add a subroutine and call it former_laboratory:
 
  
sub former_laboratory {
+
'''Make sure to read the instructions that are inside the template and to add the issue number in the comments.'''
    my $self = shift;
 
    my $object    = $self->object;
 
    # Access the field Former_designating_laboratory
 
    my $former_lab_time = $object->Former_designating_laboratory;
 
   
 
   
 
    return  { description => 'Former_designating_laboratory', data =>  "$former_lab_time" || undef };
 
                      }
 
  
Return a hash that contains the description of the field and the former lab time. The value of the "data" key should be "undef" if there is no data in the "Former_designating_laboratory" field. If the "data" is "undef" the template won't show a "Former designating laboratory" field on the UI.
+
* Run a test script with
 +
<code>API_TESTS=testFileNameWithoutExtension perl t/api.t</code>
  
===Third Step:===
+
And make sure that all the tests you included failed, because you didn't actually fix anything.
A template - with the file extension .tt2 - is responsible of view the data grabbed from the database on the the UI. Every widget in an object has its own separate template. So if you go to this directory root/templates/classes/gene_class/ which contains all the Gene class widgets you will find a template for the Overview widget with the name overview.tt2.  
 
  
We are going to add a new WRAPPER for our field. The key parameter should match our subroutine name that we made in the API file - which was "former_laboratory" -.
+
== Add a subroutine to the API module ==
 +
Add a subroutine "url" to the API file of the Analysis object in order to grab the data from the database.  
  
WRAPPER $field_block title="$title"||'Former Designating Laboratory' key="former_laboratory";
+
(The Analysis.pm - API file of the Gene class - is in the directory lib/WormBase/API/Object/.)
    #Access the value of the "data" key returned from the former_laboratory subroutine
 
    fields.former_laboratory.data;
 
END;
 
  
You can check out how "$field_block" works from the page_elements.tt2 template.
+
<nowiki>
"$field_block" looks of the data returned from former_laboratory if "undef" or not. If it is "undef" - which means there is no data in the that field - it disables the element of the field, and it isn't going to show on the UI.
+
sub url {
 +
    #An array reference "$self" to the array "@_" that contains the parameters passed to the subroutine
 +
    my $self = @_;
  
===Forth Step:===
+
    #Store the object parameter - which is the DB of the OMA analysis - in the variable "$object"
 +
    my $object = $self->object;
 +
   
 +
    #Store the data in the "URL" field in the variable "$url"
 +
    my $url = $object->'URL';
  
There should be a test for any modification you do. In this example what we need to test is the API because we need to know if the "former_laboratory" subroutine in the Gene_classes API is grabbing the data properly from the database or not. There is a standard template "template.t" you can find in the directory t/api_tests/ , and you can use for your API tests.  
+
    return {
 +
        description => 'the url of the analysis',
 +
        data        => "$former_lab_time" || undef,
 +
    };
 +
}
 +
</nowiki>
 +
 +
Always return a hash that has two keys; the "description" of the field added, and the "data" passed to the field. The value of the "data" can be a hash that contains multiple keys.
  
So you are going to make a copy of the template - using the command "cp t/api_tests/template.t t/api_tests/gene_class.t" - and modify it. Let's call the new test file "gene_class.t". This is how the original template looks like this:
+
The value of the "data" key should be "undef" if there is no data in the field inspected, and this is why "|| undef" is added. This is important because if the "data" is "undef" the template won't show the field added on the UI
  
#!/usr/bin/env perl
+
==Modify configuration file==
 +
Add the URL field "fields URL" to the overview element of the "analysis" section
  
# This is a unit test template for implementing tests that work
+
(The wormbase.conf - contains default configurations for the fields inside widgets - is in the main website directory.)  
# with a running WormBase Website instance.
 
#
 
# Unit tests are called automagically, just adhere to the following:
 
#
 
# 1. the unit test is placed in the t/api_tests folder
 
# 2. the filename and package name coincide (sans suffix)
 
# 3. unit test names have the prefix "test_"
 
#
 
# Actual tests are implemented at the bottom of this file. Please see:
 
#
 
# 1. gene_class
 
  
{
+
<nowiki>
    # Package name is the same as the filename (sans suffix, i.e. no .t ending)
+
<analysis>
    package template;
 
  
    # Limit the use of unsafe Perl constructs.
+
<overview>
    use strict;
+
name  overview
 +
title  Overview
 +
tooltip Concise overview of this analysis.
 +
display report
 +
fields name
 +
fields description
 +
fields title
 +
fields based_on_wb_release
 +
fields based_on_db_release
 +
fields project
 +
fields subproject
 +
fields conducted_by
 +
                        fields url
 +
</overview>
  
    # We use Test::More for all tests, so include that here.
+
      </analysis>
    use Test::More;
+
</nowiki>
  
    # This variable will hold a reference to a WormBase API object.
+
== Edit template: for displaying data ==
    my $api;
+
Add a WRAPPER to the overview widget - the widget we want to add the data to - template for the new 'URL' field. The key parameter should match the subroutine name that is in the API file.  
  
    # A setter method for passing on a WormBase API object from t/api.t to
+
(The overview.tt2 file is in the directory root/templates/classes/gene_class/)
    # the subs of this package.
 
    sub config {
 
        $api = $_[0];
 
    }
 
   
 
    # This is a test that checks whether former_laboratory attribute is correctly returned
 
    # related to #2551
 
    sub test_former_designating_laboratory {
 
        my $gene_class = $api->fetch({ class => 'Gene_class', name => 'daf' });
 
  
        can_ok('WormBase::API::Object::Gene_class', ('former_laboratory'));
+
<nowiki>
 +
WRAPPER $field_block title="URL" key="url";
 +
      fields.url.data;
 +
END;
 +
</nowiki>
  
        my $former_designating_laboratory = $gene_class->former_laboratory();
+
You can check out how "$field_block" works from the page_elements.tt2 template.
  
        # Please keep test names/descriptions all lower case.
+
== Formal Testing (after modification) ==
        isnt($former_designating_laboratory->{'data'}, undef, 'data returned');
 
is($former_designating_laboratory->{'data'}->{'lab'}->{'id'}, 'DR', 'correct lab returned');
 
is($former_designating_laboratory->{'data'}{'time'}, '19 Mar 2014 14:41:19', 'correct time returned');
 
    }
 
  
}
+
* Run a test script again with
 +
<code>API_TESTS=testFileNameWithoutExtension perl t/api.t</code>
  
1;
+
And make sure that all the tests were passed.
  
Make sure to read the instructions that are inside the template and to add the issue number in the comments.
+
==Test and Commit Changes==
 +
At last, test the web page on Dev site, and commit your code to git. If you have trouble doing that, it's good to check out [[Development workflow - webdev]].
  
===Step Sex:===
+
[[Category:Main Website (Web Dev)]]
The only thing left for you now is to commit your code to git. If you have trouble doing that it's good to check out [[Development workflow - webdev]].
 

Latest revision as of 18:45, 19 June 2014

Introduction

A common form of feature request is adding some data to be displayed on a page.

Here is an example that illustrates work flow required to add some data to a widget.

Issue #2571 required showing the URL in the "URL" field on the "Overview" widget of an "Analysis" object (the analysis "OMA" for example).

Using the data flow graph

Widget Loading

we can see that data goes through 4 stages from the database to the UI - Rest, Conf, API and Template. Usually our work doesn't involve the Rest stage, but it sure does involve modifying the .conf (the configuration), .pm (the API) and .tt2 (the template) files.

If you go to the OMA page , you can view the database you are going to be working on by going to Tools -> Tree Display using the menu on the left side of the page.

Formal Testing (before modification)

You have to do two tests when fixing any issue. One before fixing it and another one after it's fixed.

Here we focus on API Tests, which check that an API module (the subroutine it has) successfully retrieves values from the database.

API Tests are located at t/api_tests/ with the extension .t. A .t script usually test a single API module, such as one of the .pm file under lib/WormBase/API/Object/. It has a file name that matches the API module, which it tests. This convention helps with locating a test file, making it easier to add new test case.

  • To add a test case, locate the test file as described above. Create one if you cannot find one by:
    • Copy the template.t, a sample test file, and name it according to which API module is being tested
  • include a test case, which usually contains test for:
    • subroutine can be called on the API object
    • data is returned from the subroutine
    • data return is correct
    # This is a test that checks whether former_laboratory attribute is correctly returned
    # related to #2551
    sub test_former_designating_laboratory {
        my $gene_class = $api->fetch({ class => 'Gene_class', name => 'daf' });

        can_ok('WormBase::API::Object::Gene_class', ('former_laboratory'));

        my $former_designating_laboratory = $gene_class->former_laboratory();

        # Please keep test names/descriptions all lower case.
        isnt($former_designating_laboratory->{'data'}, undef, 'data returned');
	is($former_designating_laboratory->{'data'}->{'lab'}->{'id'}, 'DR', 'correct lab returned');
	is($former_designating_laboratory->{'data'}{'time'}, '19 Mar 2014 14:41:19', 'correct time returned');
    }
 


Make sure to read the instructions that are inside the template and to add the issue number in the comments.

  • Run a test script with

API_TESTS=testFileNameWithoutExtension perl t/api.t

And make sure that all the tests you included failed, because you didn't actually fix anything.

Add a subroutine to the API module

Add a subroutine "url" to the API file of the Analysis object in order to grab the data from the database.

(The Analysis.pm - API file of the Gene class - is in the directory lib/WormBase/API/Object/.)

sub url {
    #An array reference "$self" to the array "@_" that contains the parameters passed to the subroutine
    my $self = @_;

    #Store the object parameter - which is the DB of the OMA analysis - in the variable "$object" 
    my $object = $self->object; 
    
    #Store the data in the "URL" field in the variable "$url" 
    my $url = $object->'URL';

    return {
        description => 'the url of the analysis',
        data        => "$former_lab_time" || undef,
    };
}
 

Always return a hash that has two keys; the "description" of the field added, and the "data" passed to the field. The value of the "data" can be a hash that contains multiple keys.

The value of the "data" key should be "undef" if there is no data in the field inspected, and this is why "|| undef" is added. This is important because if the "data" is "undef" the template won't show the field added on the UI

Modify configuration file

Add the URL field "fields URL" to the overview element of the "analysis" section

(The wormbase.conf - contains default configurations for the fields inside widgets - is in the main website directory.)

 
	<analysis>

		<overview>
			name   overview
			title  Overview
			tooltip Concise overview of this analysis.
			display report
			fields name
			fields description
			fields title
			fields based_on_wb_release
			fields based_on_db_release
			fields project
			fields subproject
			fields conducted_by
                        fields url
		</overview>

       </analysis>
 

Edit template: for displaying data

Add a WRAPPER to the overview widget - the widget we want to add the data to - template for the new 'URL' field. The key parameter should match the subroutine name that is in the API file.

(The overview.tt2 file is in the directory root/templates/classes/gene_class/)

WRAPPER $field_block title="URL" key="url";
      fields.url.data;
 END;
 

You can check out how "$field_block" works from the page_elements.tt2 template.

Formal Testing (after modification)

  • Run a test script again with

API_TESTS=testFileNameWithoutExtension perl t/api.t

And make sure that all the tests were passed.

Test and Commit Changes

At last, test the web page on Dev site, and commit your code to git. If you have trouble doing that, it's good to check out Development workflow - webdev.