← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 17753: more work in refactoring; respecting program relationship settings in relationship widget; popup ...

 

------------------------------------------------------------
revno: 17753
committer: Abyot Asalefew Gizaw <abyota@xxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2014-12-19 17:52:40 +0100
message:
  more work in refactoring; respecting program relationship settings in relationship widget; popup for relationship details
modified:
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/notes/notes-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/notes/notes.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/profile/profile-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/registration.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/report/tei-report-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/app.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/controllers.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/views/home.html
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/services.js


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js	2014-12-16 15:44:11 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js	2014-12-19 16:52:40 +0000
@@ -9,6 +9,7 @@
                 TEIService, 
                 TEService,
                 OptionSetService,
+                EnrollmentService,
                 ProgramFactory,
                 CurrentSelection) {
     //dashboard items   
@@ -56,25 +57,33 @@
                 TEService.get($scope.selectedTei.trackedEntity).then(function(te){                    
                     $scope.trackedEntity = te;
 
-                    ProgramFactory.getAll().then(function(programs){  
-
-                        $scope.programs = [];
-                        
-                        //get programs valid for the selected ou and tei
-                        angular.forEach(programs, function(program){
-                            if(program.organisationUnits.hasOwnProperty($scope.selectedOrgUnit.id) &&
-                               program.trackedEntity.id === $scope.selectedTei.trackedEntity){
-                                $scope.programs.push(program);
-                            }
-
-                            if($scope.selectedProgramId && program.id === $scope.selectedProgramId){
-                                $scope.selectedProgram = program;
-                            }
-                        }); 
-                        
-                        //broadcast selected items for dashboard controllers
-                        CurrentSelection.set({tei: $scope.selectedTei, te: $scope.trackedEntity, pr: $scope.selectedProgram, enrollment: null, optionSets: $scope.optionSets});
-                        $scope.broadCastSelections();                        
+                    //get enrollments for the selected tei
+                    EnrollmentService.getByEntity($scope.selectedTeiId).then(function(response){                    
+
+                        var selectedEnrollment = null;
+                        if(response.enrollments.length === 1 && response.enrollments[0].status === 'ACTIVE'){
+                            selectedEnrollment = response.enrollments[0];                            
+                        }
+                        
+                        ProgramFactory.getAll().then(function(programs){
+                            $scope.programs = [];
+
+                            //get programs valid for the selected ou and tei
+                            angular.forEach(programs, function(program){
+                                if(program.organisationUnits.hasOwnProperty($scope.selectedOrgUnit.id) &&
+                                   program.trackedEntity.id === $scope.selectedTei.trackedEntity){
+                                    $scope.programs.push(program);
+                                }
+
+                                if($scope.selectedProgramId && program.id === $scope.selectedProgramId || selectedEnrollment && selectedEnrollment.program === program.id){
+                                    $scope.selectedProgram = program;
+                                }
+                            }); 
+
+                            //broadcast selected items for dashboard controllers
+                            CurrentSelection.set({tei: $scope.selectedTei, te: $scope.trackedEntity, prs: $scope.programs, pr: $scope.selectedProgram, enrollment: selectedEnrollment, optionSets: $scope.optionSets});
+                            $scope.broadCastSelections();                        
+                        });
                     });
                 });            
             });    
@@ -101,7 +110,7 @@
         $scope.trackedEntity = selections.te;
         $scope.optionSets = selections.optionSets;
         
-        CurrentSelection.set({tei: $scope.selectedTei, te: $scope.trackedEntity, pr: $scope.selectedProgram, enrollment: null, optionSets: $scope.optionSets});
+        CurrentSelection.set({tei: $scope.selectedTei, te: $scope.trackedEntity, prs: $scope.programs, pr: $scope.selectedProgram, enrollment: null, optionSets: $scope.optionSets});
         $timeout(function() { 
             $rootScope.$broadcast('selectedItems', {programExists: $scope.programs.length > 0});            
         }, 100); 

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js	2014-12-16 15:48:16 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js	2014-12-19 16:52:40 +0000
@@ -40,7 +40,7 @@
     $scope.showEventColors = false;
     
     //listen for the selected items
-    $scope.$on('dashboardWidgets', function(event, args) {  
+    $scope.$on('dashboardWidgets', function() {  
         $scope.showDataEntryDiv = false;
         $scope.showEventCreationDiv = false;
         $scope.showDummyEventDiv = false;        
@@ -60,19 +60,20 @@
         $scope.optionSets = selections.optionSets;
         $scope.selectedProgramWithStage = [];
         
-        if($scope.selectedOrgUnit && $scope.selectedProgram && $scope.selectedEntity && $scope.selectedEnrollment){            
-            angular.forEach($scope.selectedProgram.programStages, function(st){                
-                ProgramStageFactory.get(st.id).then(function(stage){
+        if($scope.selectedOrgUnit && $scope.selectedProgram && $scope.selectedEntity && $scope.selectedEnrollment){
+            
+            ProgramStageFactory.getByProgram($scope.selectedProgram).then(function(stages){
+                
+                angular.forEach(stages, function(stage){
                     if(stage.openAfterEnrollment){
                         $scope.currentStage = stage;
                     }
                     $scope.selectedProgramWithStage[stage.id] = stage;
                 });
-            });
-            
-            setTimeout(function () {
+                
                 $scope.getEvents();
-            }, 100);
+                
+            });
         }
     });
     
@@ -104,16 +105,17 @@
                                 dhis2Event.sortingDate = dhis2Event.eventDate;
                             }                       
 
-                            dhis2Event.statusColor = EventUtils.getEventStatusColor(dhis2Event);  
-                            //dhis2Event = EventUtils.setEventOrgUnitName(dhis2Event);
+                            dhis2Event.statusColor = EventUtils.getEventStatusColor(dhis2Event);
                             
                             if($scope.currentStage && $scope.currentStage.id === dhis2Event.programStage){
                                 $scope.currentEvent = dhis2Event;                                
                                 $scope.showDataEntry($scope.currentEvent, true);
                             }
                         } 
-                    }                    
+                    }
                 });
+                
+                $scope.dhis2Events = orderByFilter($scope.dhis2Events, '-sortingDate');
             }
             
             $scope.dummyEvents = $scope.checkForEventCreation($scope.dhis2Events, $scope.selectedProgram);

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry.html	2014-12-08 16:37:23 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry.html	2014-12-19 16:52:40 +0000
@@ -103,7 +103,7 @@
                         {{'due_date'| translate}}
                     </span>
                     <span ng-if="!currentEvent.eventDate && currentEvent.status !== 'SKIPPED'">
-                        <a href ng-click="enableRescheduling()" title="{{ schedulingEnabled ? 'disable_rescheduling' : 'enable_rescheduling' | translate}}"><span class="text-primary bold">{{'due_date'| translate}}</span></a>                        
+                        <a href ng-click="enableRescheduling()" title="{{ schedulingEnabled ? 'disable_rescheduling' : 'enable_rescheduling' | translate}}"><span class="text-primary bold">{{'reschedule_duedate'| translate}}</span></a>                        
                     </span>                    
                     <input type="text" 
                            placeholder="{{dhis2CalendarFormat.keyDateFormat}}"
@@ -153,7 +153,7 @@
             <table class="table table-striped dhis2-table-hover">
                 <tr ng-repeat="note in currentEvent.notes">
                     <td class="overflow-ellipsis">
-                        <d2-pop-over content="note" template="note.html" details="{{'details'| translate}}">
+                        <d2-pop-over content="note" template="popover.html" details="{{'details'| translate}}">
                             <div>{{note.value}}</div>
                         </d2-pop-over>
                         <script type="text/ng-template" id="note.html">

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment-controller.js	2014-12-16 15:44:11 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/enrollment/enrollment-controller.js	2014-12-19 16:52:40 +0000
@@ -32,6 +32,8 @@
         $scope.selectedEntity = selections.te;
         $scope.selectedProgram = selections.pr;
         $scope.optionSets = selections.optionSets;
+        $scope.programs = selections.prs;
+        $scope.selectedEnrollment = selections.enrollment;
         
         $scope.programExists = args.programExists;
         
@@ -101,16 +103,10 @@
     };
         
     $scope.showNewEnrollment = function(){       
-        if($scope.showEnrollmentDiv){//this is hiding enrollment div
-            /*currently the only way to cancel enrollment window is by going through
-            * the main dashboard controller. Here I am mixing program and programId, 
-            * as I didn't want to refetch program from server, the main dashboard
-            * has already fetched the programs. With the ID passed to it, it will
-            * pass back the actual program than ID. 
-            */
-           $scope.selectedProgram = ($location.search()).program;
-           $scope.broadCastSelections('mainDashboard');
+        if($scope.showEnrollmentDiv){
+            $scope.hideEnrollmentDiv();
         }
+        
         $scope.showEnrollmentDiv = !$scope.showEnrollmentDiv;
         
         if($scope.showEnrollmentDiv){
@@ -147,7 +143,6 @@
             tei.attributes.push({attribute: attribute.id, value: attribute.value, type: attribute.valueType, displayName: attribute.name});                        
         });
         
-        console.log('Finally:  ', tei);
         var enrollment = {trackedEntityInstance: tei.trackedEntityInstance,
                             program: $scope.selectedProgram.id,
                             status: 'ACTIVE',
@@ -197,7 +192,7 @@
     };
     
     $scope.broadCastSelections = function(listeners){
-        CurrentSelection.set({tei: $scope.selectedTei, te: $scope.selectedEntity, pr: $scope.selectedProgram, enrollment: $scope.selectedEnrollment, optionSets: $scope.optionSets});
+        CurrentSelection.set({tei: $scope.selectedTei, te: $scope.selectedEntity, prs: $scope.programs, pr: $scope.selectedProgram, enrollment: $scope.selectedEnrollment, optionSets: $scope.optionSets});
         $timeout(function(){
             $rootScope.$broadcast(listeners, {});
         }, 100);

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/notes/notes-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/notes/notes-controller.js	2014-12-09 23:24:16 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/notes/notes-controller.js	2014-12-19 16:52:40 +0000
@@ -2,7 +2,6 @@
         function($scope,
                 storage,
                 DateUtils,
-                TEIService,
                 EnrollmentService,
                 CurrentSelection,
                 orderByFilter) {
@@ -18,12 +17,11 @@
     $scope.showMessagingDiv = false;
     $scope.showNotesDiv = true;
     
-    $scope.$on('dashboardWidgets', function(event, args) {
+    $scope.$on('dashboardWidgets', function() {
         $scope.selectedEnrollment = null;
         var selections = CurrentSelection.get();                    
         $scope.selectedTei = angular.copy(selections.tei);
         $scope.selectedProgram = selections.pr;
-        $scope.optionSets = selections.optionSets;
         
         var selections = CurrentSelection.get();
         if(selections.enrollment){
@@ -38,20 +36,17 @@
             });
         }
         
-        if($scope.selectedProgram && $scope.selectedTei){
+        if($scope.selectedTei){
             //check if the selected TEI has any of the contact attributes
             //that can be used for communication
-            TEIService.processAttributes($scope.selectedTei, $scope.selectedProgram, $scope.selectedEnrollment, $scope.optionSets).then(function(tei){
-                $scope.selectedTei = tei; 
-                var continueLoop = true;
-                for(var i=0; i<$scope.selectedTei.attributes.length && continueLoop; i++){
-                    if( ($scope.selectedTei.attributes[i].type === 'phoneNumber' && $scope.selectedTei.attributes[i].show) || 
-                        ($scope.selectedTei.attributes[i].type === 'email' && $scope.selectedTei.attributes[i].show) ){
-                        $scope.messagingPossible = true;
-                        continueLoop = false;
-                    }
+            var continueLoop = true;
+            for(var i=0; i<$scope.selectedTei.attributes.length && continueLoop; i++){
+                if( ($scope.selectedTei.attributes[i].type === 'phoneNumber' && $scope.selectedTei.attributes[i].show) || 
+                    ($scope.selectedTei.attributes[i].type === 'email' && $scope.selectedTei.attributes[i].show) ){
+                    $scope.messagingPossible = true;
+                    continueLoop = false;
                 }
-            });
+            }
         }
     });
    
@@ -74,7 +69,7 @@
             var e = angular.copy($scope.selectedEnrollment);
 
             e.notes = [newNote];
-            EnrollmentService.update(e).then(function(data){
+            EnrollmentService.update(e).then(function(){
                 $scope.note = '';
                 $scope.addNoteField = false; //note is added, hence no need to show note field.                
             });

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/notes/notes.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/notes/notes.html	2014-10-24 11:10:47 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/notes/notes.html	2014-12-19 16:52:40 +0000
@@ -39,7 +39,7 @@
                 <table class="table table-striped dhis2-table-hover">
                     <tr ng-repeat="note in selectedEnrollment.notes| filter:noteSearchText">
                         <td>
-                            <d2-pop-over content="note" template="note.html" details="{{'details'| translate}}">
+                            <d2-pop-over content="note" template="popover.html" details="{{'details'| translate}}">
                                 <div>{{note.value}}</div>
                             </d2-pop-over>
                             <script type="text/ng-template" id="note.html">

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/profile/profile-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/profile/profile-controller.js	2014-12-16 15:44:11 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/profile/profile-controller.js	2014-12-19 16:52:40 +0000
@@ -29,7 +29,7 @@
 
         //display only those attributes that belong to the selected program
         //if no program, display attributesInNoProgram
-        TEIService.processAttributes($scope.selectedTei, $scope.selectedProgram, $scope.selectedEnrollment, $scope.optionSets).then(function(tei){
+        TEIService.processAttributes($scope.selectedTei, $scope.selectedProgram, $scope.selectedEnrollment).then(function(tei){
             $scope.selectedTei = tei;
         });
     });
@@ -52,6 +52,9 @@
         //get tei attributes and their values
         //but there could be a case where attributes are non-mandatory and
         //form comes empty, in this case enforce at least one value
+        
+        console.log('the tei:  ', $scope.selectedTei);
+        
         $scope.formEmpty = true;
         var tei = angular.copy($scope.selectedTei);
         tei.attributes = [];

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js	2014-12-08 15:56:07 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js	2014-12-19 16:52:40 +0000
@@ -39,11 +39,19 @@
         if($scope.selectedProgram){
             AttributesFactory.getByProgram($scope.selectedProgram).then(function(atts){
                 $scope.attributes = atts;
+                $scope.attributesById = [];
+                angular.forEach(atts, function(att){
+                    $scope.attributesById[att.id] = att;
+                });
             });           
         }
         else{            
             AttributesFactory.getWithoutProgram().then(function(atts){
                 $scope.attributes = atts;
+                $scope.attributesById = [];
+                angular.forEach(atts, function(att){
+                    $scope.attributesById[att.id] = att;
+                });
             });
         }
     };
@@ -66,9 +74,10 @@
         //get tei attributes and their values
         //but there could be a case where attributes are non-mandatory and
         //registration form comes empty, in this case enforce at least one value
-        $scope.valueExists = false;
-        var registrationAttributes = [];    
-        angular.forEach($scope.attributes, function(attribute){            
+        $scope.valueExists = false;          
+        var result = TEIService.reconstructForWebApi($scope.attributes, $scope.attributesById, $scope.optionSets);
+        $scope.valueExists = result.formEmpty;
+        /*angular.forEach($scope.attributes, function(attribute){            
             var val = attribute.value;
             if(!angular.isUndefined(val)){
                 
@@ -81,7 +90,7 @@
                 registrationAttributes.push({attribute: attribute.id, value: val});
                 $scope.valueExists = true;
             } 
-        });       
+        });*/       
         
         if(!$scope.valueExists){
             //registration form is empty
@@ -89,7 +98,7 @@
         }
         
         //prepare tei model and do registration
-        $scope.tei = {trackedEntity: selectedTrackedEntity, orgUnit: $scope.selectedOrgUnit.id, attributes: registrationAttributes };   
+        $scope.tei = {trackedEntity: selectedTrackedEntity, orgUnit: $scope.selectedOrgUnit.id, attributes: result.attributes };   
         var teiId = '';
         TEIService.register($scope.tei).then(function(tei){
             

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/registration.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/registration.html	2014-11-28 14:54:12 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/registration.html	2014-12-19 16:52:40 +0000
@@ -1,5 +1,6 @@
 <div ng-controller="RelativeRegistrationController" class="modal-dialog">    
     <hr>
+
     <form name="outerForm" novalidate>
 
         <select ng-model="selectedProgramForRelative"

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js	2014-12-16 15:44:11 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js	2014-12-19 16:52:40 +0000
@@ -6,11 +6,13 @@
                 $route,
                 $translate,
                 CurrentSelection,
+                TEIService,
                 RelationshipFactory) {
     $rootScope.showAddRelationshipDiv = false;
     $scope.relationshipTypes = []; 
     $scope.relationships = [];
-    $scope.addRelationshipLabel = $translate('add');
+    $scope.addRelationshipLabel = $translate('add');   
+            
     RelationshipFactory.getAll().then(function(rels){
         $scope.relationshipTypes = rels;    
         angular.forEach(rels, function(rel){
@@ -20,12 +22,14 @@
     
     //listen for the selected entity       
     $scope.$on('dashboardWidgets', function(event, args) { 
+         $scope.relatedTeis = [];
         $scope.selections = CurrentSelection.get();
         $scope.optionSets = $scope.selections.optionSets;
         $scope.selectedTei = angular.copy($scope.selections.tei);        
         $scope.trackedEntity = $scope.selections.te;
         $scope.selectedEnrollment = $scope.selections.enrollment;
         $scope.selectedProgram = $scope.selections.pr;
+        $scope.programs = $scope.selections.pr;
         
         if($scope.selectedProgram && $scope.selectedProgram.relationshipText){
             $scope.addRelationshipLabel = $scope.selectedProgram.relationshipText;
@@ -33,6 +37,17 @@
         else{
             $scope.addRelationshipLabel = $translate('add');
         }
+        
+        angular.forEach($scope.selectedTei.relationships, function(rel){
+            var teiId = rel.trackedEntityInstanceA;
+            if($scope.selectedTei.trackedEntityInstance === rel.trackedEntityInstanceA){
+                teiId = rel.trackedEntityInstanceB;
+            }
+            
+            TEIService.get(teiId, $scope.optionSets).then(function(tei){
+                $scope.relatedTeis[teiId] = tei.data;
+            });
+        });
     });
     
     $scope.showAddRelationship = function() {
@@ -52,6 +67,9 @@
                     },
                     selectedTei: function(){
                         return $scope.selectedTei;
+                    },
+                    selectedProgram: function(){
+                        return $scope.selectedProgram;
                     }
                 }
             });
@@ -63,15 +81,23 @@
     };    
     
     $scope.showDashboard = function(rel){
-        var relativeTeiId = '';
+        
+        var dashboardProgram = null, relativeTeiId = '';
+        
+        if($scope.selectedProgram && $scope.selectedProgram.relationshipType){
+            if($scope.selectedProgram.relationshipType.id === rel.relationship && $scope.selectedProgram.relatedProgram ){
+                dashboardProgram = $scope.selectedProgram.relatedProgram.id;
+            }
+        }        
+        
         if($scope.selectedTei.trackedEntityInstance === rel.trackedEntityInstanceA){
             relativeTeiId = rel.trackedEntityInstanceB;
         }
         else{
             relativeTeiId = rel.trackedEntityInstanceA;
         }          
-                
-        $location.path('/dashboard').search({tei: relativeTeiId, program: null}); 
+    
+        $location.path('/dashboard').search({tei: relativeTeiId, program: dashboardProgram}); 
         $route.reload();                                 
     };
 })
@@ -84,7 +110,6 @@
             OperatorFactory,
             AttributesFactory,
             EntityQueryFactory,
-            ProgramFactory,
             TEIService,
             TEIGridService,
             DialogService,
@@ -92,12 +117,14 @@
             storage,
             $modalInstance, 
             relationshipTypes,
+            selectedProgram,
             selections,
-            DateUtils,
             selectedTei){
     
     $scope.relationshipTypes = relationshipTypes;
-    $scope.selectedTei = selectedTei;    
+    $scope.selectedProgram = selectedProgram;
+    $scope.selectedTei = selectedTei;
+    $scope.programs = selections.prs;
 
     $scope.relationshipSources = ['search_from_existing','register_new'];
     $scope.selectedRelationshipSource = {};   
@@ -107,31 +134,43 @@
     $scope.selectedOrgUnit = storage.get('SELECTED_OU');
     $scope.optionSets = selections.optionSets;
     $scope.selectedTeiForDisplay = angular.copy($scope.selectedTei);       
-   
-    ProgramFactory.getAll().then(function(programs){
-        $scope.programs = [];
-        angular.forEach(programs, function(program){                            
-            if(program.organisationUnits.hasOwnProperty($scope.selectedOrgUnit.id)){                                
-                $scope.programs.push(program);
-            }
-        });
-
-        if(angular.isObject($scope.programs) && $scope.programs.length === 1){
-            $scope.selectedProgramForRelative = $scope.programs[0];
-            AttributesFactory.getByProgram($scope.selectedProgramForRelative).then(function(atts){
-                $scope.attributes = atts;
-                $scope.attributes = $scope.generateAttributeFilters($scope.attributes);
-                $scope.gridColumns = $scope.generateGridColumns($scope.attributes);
-            });
-        }   
-        else{
-            AttributesFactory.getWithoutProgram().then(function(atts){
-                $scope.attributes = atts;
-                $scope.attributes = $scope.generateAttributeFilters($scope.attributes);
-                $scope.gridColumns = $scope.generateGridColumns($scope.attributes);
-            });
-        }
-    });    
+    
+    if(angular.isObject($scope.programs) && $scope.programs.length === 1){
+        $scope.selectedProgramForRelative = $scope.programs[0];        
+    } 
+    
+    if($scope.selectedProgram){
+        if($scope.selectedProgram.relatedProgram){
+            angular.forEach($scope.programs, function(pr){
+                if(pr.id === $scope.selectedProgram.relatedProgram.id){
+                    $scope.selectedProgramForRelative = pr;
+                }
+            });
+        }
+        
+        if($scope.selectedProgram.relationshipType){
+            angular.forEach($scope.relationshipTypes, function(rel){
+                if(rel.id === $scope.selectedProgram.relationshipType.id){
+                    $scope.relationship.selected = rel;
+                }
+            });
+        }
+    }    
+    
+    if($scope.selectedProgramForRelative){
+        AttributesFactory.getByProgram($scope.selectedProgramForRelative).then(function(atts){
+            $scope.attributes = atts;
+            $scope.attributes = $scope.generateAttributeFilters($scope.attributes);
+            $scope.gridColumns = $scope.generateGridColumns($scope.attributes);
+        });
+    }   
+    else{
+        AttributesFactory.getWithoutProgram().then(function(atts){
+            $scope.attributes = atts;
+            $scope.attributes = $scope.generateAttributeFilters($scope.attributes);
+            $scope.gridColumns = $scope.generateGridColumns($scope.attributes);
+        });
+    }    
     
     //set attributes as per selected program
     $scope.setAttributesForSearch = function(program){
@@ -175,7 +214,7 @@
     $scope.searchMode = {listAll: 'LIST_ALL', freeText: 'FREE_TEXT', attributeBased: 'ATTRIBUTE_BASED'};      
     
     //listen for selections
-    $scope.$on('relationship', function(event, args) { 
+    $scope.$on('relationship', function() { 
         var relationshipInfo = CurrentSelection.getRelationshipInfo();
         $scope.teiForRelationship = relationshipInfo.tei;
     });
@@ -367,32 +406,27 @@
                 $scope,
                 $timeout,
                 AttributesFactory,
-                ProgramFactory,
                 TEService,
                 TEIService,
                 EnrollmentService,
                 DialogService,
                 CurrentSelection,
+                OptionSetService,
                 DateUtils,
                 storage) {
     $scope.selectedOrgUnit = storage.get('SELECTED_OU');
     $scope.enrollment = {enrollmentDate: '', incidentDate: ''};    
     
-    ProgramFactory.getAll().then(function(programs){
-        $scope.programs = [];
-        angular.forEach(programs, function(program){                            
-            if(program.organisationUnits.hasOwnProperty($scope.selectedOrgUnit.id)){                                
-                $scope.programs.push(program);
-            }
+    var selections = CurrentSelection.get();
+    $scope.optionSets = selections.optionSets;
+    $scope.programs = selections.prs;    
+  
+    if(angular.isObject($scope.programs) && $scope.programs.length === 1){
+        $scope.selectedProgramForRelative = $scope.programs[0];
+        AttributesFactory.getByProgram($scope.selectedProgramForRelative).then(function(atts){
+            $scope.attributes = atts;
         });
-
-        if(angular.isObject($scope.programs) && $scope.programs.length === 1){
-            $scope.selectedProgramForRelative = $scope.programs[0];
-            AttributesFactory.getByProgram($scope.selectedProgramForRelative).then(function(atts){
-                $scope.attributes = atts;
-            });
-        }                
-    });
+    }  
     
     //watch for selection of program
     $scope.$watch('selectedProgramForRelative', function() {        
@@ -436,13 +470,17 @@
         var registrationAttributes = [];    
         angular.forEach($scope.attributes, function(attribute){
             var val = attribute.value;
-            if(!angular.isUndefined(val)){
-                
+            if(!angular.isUndefined(val)){                
                 if(attribute.valueType === 'date'){
                     val = DateUtils.formatFromUserToApi(val);
                 }
-                if(attribute.valueType === 'optionSet' && $scope.optionSets.optionCodesByName[  '"' + val + '"']){   
-                    val = $scope.optionSets.optionCodesByName[  '"' + val + '"'];
+                if(attribute.valueType === 'optionSet' &&
+                        attribute.optionSet &&
+                        attribute.optionSet.id &&                
+                        $scope.optionSets[attribute.optionSet.id] &&
+                        $scope.optionSets[attribute.optionSet.id].options ){  
+                    
+                    val = OptionSetService.getCode($scope.optionSets[attribute.optionSet.id].options, val);
                 }
                 registrationAttributes.push({attribute: attribute.id, value: val});
                 $scope.valueExists = true;

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship.html	2014-11-28 14:54:12 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship.html	2014-12-19 16:52:40 +0000
@@ -1,11 +1,10 @@
 <div class="panel panel-info" ng-controller="RelationshipController">
     <div class="panel-heading handle bold">
-
         <a href ng-click="showAddRelationship()"><span ng-class="{'light-blue': showAddRelationshipDiv}">{{relationshipWidget.title| translate}}</span></a>
         <span class="nav-pills" ng-if="selectedTei">
             | <a href ng-click="showAddRelationship()" title="{{'add_relationship'| translate}}"><span ng-class="{'light-blue': !showAddRelationshipDiv}">{{addRelationshipLabel}}</span></a>
         </span>        
-        
+
         <span class="pull-right">
             <a class="small-horizonal-spacing" href ng-click="expandCollapse(relationshipWidget)">
                 <span ng-show="relationshipWidget.expand"><i class="fa fa-chevron-up" title="{{'collapse'| translate}}"></i></span>
@@ -17,13 +16,32 @@
     <div ng-show="relationshipWidget.expand" class="panel-body dashboard-widget-container">
         <div ng-show="selectedTei && !selectedTei.relationships" class="alert alert-warning">{{'no_relationship'| translate}}</div> 
         <div ng-show="!selectedTei" class="alert alert-danger">{{'relationship_not_possible'| translate}}</div> 
-        
+
         <div ng-show="selectedTei" class="remove-default-padding">
             <table class="table table-striped dhis2-table-hover">
                 <tr ng-click="showDashboard(rel)" ng-repeat="rel in selectedTei.relationships" title="{{'go_to_dashboard'| translate}}">
-                    <td>
-                        <span ng-if="selectedTei.trackedEntityInstance === rel.trackedEntityInstanceA">{{relationships[rel.relationship].bIsToA}}</span>
-                        <span ng-if="selectedTei.trackedEntityInstance === rel.trackedEntityInstanceB">{{relationships[rel.relationship].aIsToB}}</span>                        
+                     <td>                        
+                        <d2-pop-over content="relatedTeis[rel.trackedEntityInstanceB]" template="popover.html" details="{{'details'| translate}}" ng-if="selectedTei.trackedEntityInstance === rel.trackedEntityInstanceA">
+                            <div>{{relationships[rel.relationship].bIsToA}}</div>
+                        </d2-pop-over>
+                        
+                        <d2-pop-over content="relatedTeis[rel.trackedEntityInstanceA]" template="popover.html" details="{{'details'| translate}}" ng-if="selectedTei.trackedEntityInstance === rel.trackedEntityInstanceB">
+                            <div>{{relationships[rel.relationship].aIsToB}}</div>
+                        </d2-pop-over>                
+                        
+                        <script type="text/ng-template" id="popover.html">                            
+                            <table class="table table-striped table-bordered">
+                                <tr ng-repeat="att in content.attributes">
+                                    <td>
+                                        {{att.displayName}}
+                                    </td>
+                                    <td>
+                                        {{att.value}}
+                                    </td>                                    
+                                </tr>
+                            </table>
+                        </script>
+                        
                     </td> 
                 </tr>
             </table>

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/report/tei-report-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/report/tei-report-controller.js	2014-12-08 15:56:07 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/report/tei-report-controller.js	2014-12-19 16:52:40 +0000
@@ -106,7 +106,7 @@
 
         //process tei attributes, this is to have consistent display so that the tei 
         //contains program attributes whether it has value or not
-        TEIService.processAttributes($scope.selectedTei, $scope.selectedProgram, null, $scope.optionSets).then(function(tei){
+        TEIService.processAttributes($scope.selectedTei, $scope.selectedProgram, null).then(function(tei){
             $scope.tei = tei;  
         });
         

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties	2014-12-10 08:11:56 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties	2014-12-19 16:52:40 +0000
@@ -186,6 +186,7 @@
 show_hide_messaging=Show/hide messaging form
 messaging=Messaging
 scheduling=Scheduling
+reschedule_duedate=Reschedule due date
 reschedule=Reschedule
 rescheduling=Rescheduling
 scheduling_messaging=Scheduling and Messaging
@@ -261,4 +262,6 @@
 log_out=Log out
 about_dhis2=About DHIS 2
 missing_translation_file=Missing Translation File
-missing_translation_using_default=No translation file is found for the selected locale. Using default translation (English).
\ No newline at end of file
+missing_translation_using_default=No translation file is found for the selected locale. Using default translation (English).
+loading_tree=Loading orgunit tree
+loading_metadata=Loading meta-data
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/app.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/app.js	2014-12-15 14:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/app.js	2014-12-19 16:52:40 +0000
@@ -13,7 +13,7 @@
          'trackerCaptureControllers',
          'd2Directives',
          'd2Filters',
-         'd2Services',
+         //'d2Services',
          'd2Controllers',
          'angularLocalStorage',
          'ui.select2',

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/controllers.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/controllers.js	2014-12-16 15:44:11 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/controllers.js	2014-12-19 16:52:40 +0000
@@ -22,6 +22,7 @@
     $scope.ouModes = [{name: 'SELECTED'}, {name: 'CHILDREN'}, {name: 'DESCENDANTS'}, {name: 'ACCESSIBLE'}];         
     $scope.selectedOuMode = $scope.ouModes[0];
     $scope.dashboardProgramId = ($location.search()).program; 
+    $scope.treeLoaded = false;
     
     //Paging
     $scope.pager = {pageSize: 50, page: 1, toolBarDisplay: 5};   

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js	2014-12-16 15:44:11 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js	2014-12-19 16:52:40 +0000
@@ -443,7 +443,7 @@
             });
             
             return def.promise;
-        },
+        },        
         get: function(entityUid, optionSets){            
             var promise = $http.get(  '../api/trackedEntityInstances/' +  entityUid );
             this.convertFromApiToUser(promise, optionSets).then(function(response){
@@ -500,38 +500,106 @@
             });
             return promise;
         },
-        processAttributes: function(selectedTei, selectedProgram, selectedEnrollment, optionSets){
+        processAttributes: function(selectedTei, selectedProgram, selectedEnrollment){
             var def = $q.defer();            
             if(selectedTei.attributes){
                 if(selectedProgram && selectedEnrollment){
                     //show attribute for selected program and enrollment
                     AttributesFactory.getByProgram(selectedProgram).then(function(atts){
-                        selectedTei.attributes = AttributesFactory.showRequiredAttributes(atts,selectedTei.attributes, true, optionSets);
+                        selectedTei.attributes = AttributesFactory.showRequiredAttributes(atts,selectedTei.attributes, true);
                         def.resolve(selectedTei);
                     }); 
                 }
                 if(selectedProgram && !selectedEnrollment){
                     //show attributes for selected program            
                     AttributesFactory.getByProgram(selectedProgram).then(function(atts){    
-                        selectedTei.attributes = AttributesFactory.showRequiredAttributes(atts,selectedTei.attributes, false, optionSets);
+                        selectedTei.attributes = AttributesFactory.showRequiredAttributes(atts,selectedTei.attributes, false);
                         def.resolve(selectedTei);
                     }); 
                 }
                 if(!selectedProgram && !selectedEnrollment){
                     //show attributes in no program            
                     AttributesFactory.getWithoutProgram().then(function(atts){                
-                        selectedTei.attributes = AttributesFactory.showRequiredAttributes(atts,selectedTei.attributes, false, optionSets);     
+                        selectedTei.attributes = AttributesFactory.showRequiredAttributes(atts,selectedTei.attributes, false);     
                         def.resolve(selectedTei);
                     });
                 }
             }       
             return def.promise;
+        },
+        reconstructForWebApi: function(tei, attributes, attributesById, optionSets){
+            var registrationAttributes = [];
+            var formEmpty = true;
+            angular.forEach(attributes, function(att){            
+                if(att.valueType === 'trueOnly'){ 
+                    if(!tei[att.id]){
+                        registrationAttributes.push({attribute: att.id, value: ''});
+                        formEmpty = false;                    
+                    }
+                    else{
+                        registrationAttributes.push({attribute: att.id, value: 'true'});
+                        formEmpty = false;
+                    }
+                }            
+                else{
+                    if(tei[att.id] !== '' && tei[att.id]){
+
+                        var val = tei[att.id];                    
+                        if(att.valueType === 'date'){   
+                            val = DateUtils.formatFromUserToApi(val);
+                        }   
+
+                        if(att.valueType === 'optionSet' && attributesById[att.id] && attributesById[att.id].optionSet && optionSets[attributesById[att.id].optionSet.id]){                        
+                            val = OptionSetService.getCode(optionSets[attributesById[att.id].optionSet.id].options, val);
+                        }
+
+                        registrationAttributes.push({attribute: att.id, value: val});
+                        formEmpty = false;
+                    }
+                }                        
+            });
+
+            return {attributes: registrationAttributes, formEmpty: formEmpty};
+        },
+        reconstructForUser: function(tei, attributes, attributesById, optionSets){
+            var registrationAttributes = [];
+            var formEmpty = true;
+            angular.forEach(attributes, function(att){            
+                if(att.valueType === 'trueOnly'){ 
+                    if(!tei[att.id]){
+                        registrationAttributes.push({attribute: att.id, value: ''});
+                        formEmpty = false;                    
+                    }
+                    else{
+                        registrationAttributes.push({attribute: att.id, value: 'true'});
+                        formEmpty = false;
+                    }
+                }            
+                else{
+                    if(tei[att.id] !== '' && tei[att.id]){
+
+                        var val = tei[att.id];                    
+                        if(att.valueType === 'date'){   
+                            val = DateUtils.formatFromApiToUser(val);
+                        }   
+
+                        if(att.valueType === 'optionSet' && attributesById[att.id] && attributesById[att.id].optionSet && optionSets[attributesById[att.id].optionSet.id]){                        
+                            val = OptionSetService.getName(optionSets[attributesById[att.id].optionSet.id].options, val);
+                        }
+
+                        registrationAttributes.push({attribute: att.id, value: val});
+                        formEmpty = false;
+                    }
+                }                        
+            });
+
+            return {attributes: registrationAttributes, formEmpty: formEmpty};
         }
     };
 })
 
 /* Factory for getting tracked entity attributes */
-.factory('AttributesFactory', function($q, $rootScope, TCStorageService, orderByFilter, DateUtils) {      
+.factory('AttributesFactory', function($q, $rootScope, TCStorageService, orderByFilter) {      
 
     return {
         getAll: function(){
@@ -606,7 +674,7 @@
             });            
             return def.promise();            
         },
-        showRequiredAttributes: function(requiredAttributes, teiAttributes, fromEnrollment, optionSets){        
+        showRequiredAttributes: function(requiredAttributes, teiAttributes, fromEnrollment){        
             
             //first reset teiAttributes
             for(var j=0; j<teiAttributes.length; j++){
@@ -1140,4 +1208,4 @@
             return e;
         }
     }; 
-});
+});
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js	2014-12-15 14:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js	2014-12-19 16:52:40 +0000
@@ -12,10 +12,6 @@
 var i18n_sync_failed = 'Upload to server failed, please try again later';
 var i18n_uploading_data_notification = 'Uploading locally stored data to the server';
 
-var PROGRAMS_METADATA = 'TRACKER_PROGRAMS';
-
-var TRACKER_VALUES = 'TRACKER_VALUES';
-
 var optionSetsInPromise = [];
 
 dhis2.tc.store = null;
@@ -149,50 +145,48 @@
     });
 }
 
+// -----------------------------------------------------------------------------
+// Metadata downloading
+// -----------------------------------------------------------------------------
+
 function downloadMetaData()
 {
+    console.log('Loading required meta-data');
     var def = $.Deferred();
     var promise = def.promise();
 
-    promise = promise.then( dhis2.tc.store.open );
-    promise = promise.then( getUserProfile );
+    promise = promise.then( dhis2.tc.store.open );    
     promise = promise.then( getCalendarSetting );
-    promise = promise.then( getLoginDetails );
-    promise = promise.then( getRelationships );
-    promise = promise.then( getAttributes );
-    promise = promise.then( getOptionSetsForAttributes );
+    promise = promise.then( getRelationships );       
     promise = promise.then( getTrackedEntities );
     promise = promise.then( getMetaPrograms );     
     promise = promise.then( getPrograms );     
     promise = promise.then( getProgramStages );    
-    promise = promise.then( getOptionSetsForPrograms );
+    promise = promise.then( getOptionSetsForDataElements );
+    promise = promise.then( getTrackedEntityAttributes );
+    promise = promise.then( getOptionSetsForAttributes );
     promise = promise.then( getMetaTrackedEntityForms );
     promise = promise.then( getTrackedEntityForms );        
     promise.done(function() {
-        console.log( 'Finished loading meta-data' );
-        selection.responseReceived();
+        
+        //Enable ou selection after meta-data has downloaded
+        $( "#orgUnitTree" ).removeClass( "disable-clicks" );
+        
+        console.log( 'Finished loading meta-data' );        
+        selection.responseReceived(); 
     });
 
     def.resolve();
-}
-
-function getUserProfile()
-{
-    var def = $.Deferred();
-
-    $.ajax({
-        url: '../api/me/profile',
-        type: 'GET'
-    }).done(function(response) {
-        localStorage['USER_PROFILE'] = JSON.stringify(response);
-        def.resolve();
-    });
-
-    return def.promise();
-}
+    
+}
+
 
 function getCalendarSetting()
 {
+    if(localStorage['CALENDAR_SETTING']){
+       return; 
+    }
+    
     var def = $.Deferred();
 
     $.ajax({
@@ -201,117 +195,57 @@
     }).done(function(response) {
         localStorage['CALENDAR_SETTING'] = JSON.stringify(response);
         def.resolve();
+    }).fail(function(){
+        def.resolve();
     });
 
     return def.promise();
 }
 
-function getLoginDetails()
-{
-    var def = $.Deferred();
-
-    $.ajax({
-        url: '../api/me',
-        type: 'GET'
-    }).done( function(response) {            
-        localStorage['LOGIN_DETAILS'] = JSON.stringify(response);           
-        def.resolve();
-    });
-    
-    return def.promise(); 
-}
-
 function getRelationships()
-{
-    var def = $.Deferred();
-
-    $.ajax({
-        url: '../api/relationshipTypes.json?paging=false&fields=id,name,aIsToB,bIsToA,displayName',
-        type: 'GET'
-    }).done(function(response) {        
-        dhis2.tc.store.setAll( 'relationshipTypes', response.relationshipTypes );
-        def.resolve();        
-    });
-
-    return def.promise();
-}
-
-function getAttributes()
-{
-    var def = $.Deferred();
-
-    $.ajax({
-        url: '../api/trackedEntityAttributes.json',
-        type: 'GET',
-        data: 'paging=false&fields=id,name,version,description,valueType,inherit,displayOnVisitSchedule,displayInListNoProgram,unique,optionSet[id,version]'
-    }).done(function(response) {
-        dhis2.tc.store.setAll( 'attributes', response.trackedEntityAttributes );        
-        def.resolve(response.trackedEntityAttributes);        
-    });
-
-    return def.promise();
-}
-
-function getOptionSetsForAttributes( attributes )
-{
-    if( !attributes ){
-        return;
-    }
-    
-    var mainDef = $.Deferred();
-    var mainPromise = mainDef.promise();
-
-    var def = $.Deferred();
-    var promise = def.promise();
-
-    var builder = $.Deferred();
-    var build = builder.promise();    
-
-    _.each( _.values( attributes ), function ( attribute ) {
-        if( attribute.optionSet && attribute.optionSet.id ){
-            build = build.then(function() {
-                var d = $.Deferred();
-                var p = d.promise();
-                dhis2.tc.store.get('optionSets', attribute.optionSet.id).done(function(obj) {                    
-                    if((!obj || obj.version !== attribute.optionSet.version) && !optionSetsInPromise[attribute.optionSet.id]) {
-                        optionSetsInPromise[attribute.optionSet.id] = attribute.optionSet.id;
-                        promise = promise.then( getOptionSet( attribute.optionSet.id ) );
-                    }
-                    d.resolve();
-                });
-
-                return p;
-            });
-        }                      
-    });
-
-    build.done(function() {
-        def.resolve();
-
-        promise = promise.done( function () {
-            mainDef.resolve();
-        } );
-    });
-
-    builder.resolve();
-
-    return mainPromise;    
+{    
+    dhis2.tc.store.getKeys( 'relationshipTypes').done(function(res){        
+        if(res.length > 0){
+            return;
+        }
+        var def = $.Deferred();
+
+        $.ajax({
+            url: '../api/relationshipTypes.json?paging=false&fields=id,name,aIsToB,bIsToA,displayName',
+            type: 'GET'
+        }).done(function(response) {        
+            dhis2.tc.store.setAll( 'relationshipTypes', response.relationshipTypes );
+            def.resolve();        
+        }).fail(function(){
+            def.resolve();
+        });
+
+        return def.promise();
+    });    
 }
 
 function getTrackedEntities()
 {
-    var def = $.Deferred();
-
-    $.ajax({
-        url: '../api/trackedEntities',
-        type: 'GET',
-        data: 'viewClass=detailed&paging=false'
-    }).done(function(response) {
-        dhis2.tc.store.setAll( 'trackedEntities', response.trackedEntities );        
-        def.resolve();
-    });
-
-    return def.promise();
+    dhis2.tc.store.getKeys('trackedEntities').done(function(res){
+        if(res.length > 0){
+            return;
+        }
+        
+        var def = $.Deferred();
+
+        $.ajax({
+            url: '../api/trackedEntities',
+            type: 'GET',
+            data: 'viewClass=detailed&paging=false'
+        }).done(function(response) {
+            dhis2.tc.store.setAll( 'trackedEntities', response.trackedEntities );        
+            def.resolve();
+        }).fail(function(){
+            def.resolve();
+        });
+
+        return def.promise();
+    });    
 }
 
 function getMetaPrograms()
@@ -321,21 +255,16 @@
     $.ajax({
         url: '../api/programs.json',
         type: 'GET',
-        data:'filter=type:eq:1&paging=false&fields=id,name,version,programTrackedEntityAttributes[displayInList,mandatory,trackedEntityAttribute[id]],programStages[id,version,programStageDataElements[dataElement[id,optionSet[id,version]]]]'
+        data:'filter=type:eq:1&paging=false&fields=id,version,programTrackedEntityAttributes[trackedEntityAttribute[id,optionSet[id,version]]],programStages[id,version,programStageDataElements[dataElement[optionSet[id,version]]]]'
     }).done( function(response) {          
         var programs = [];
         _.each( _.values( response.programs ), function ( program ) { 
-            if( program.programStages &&
-                program.programStages.length &&
-                program.programStages[0].programStageDataElements &&
-                program.programStages[0].programStageDataElements.length ) {
-            
-                programs.push(program);
-            }  
-            
+            programs.push(program);
         });
         
         def.resolve( programs );
+    }).fail(function(){
+        def.resolve( null );
     });
     
     return def.promise(); 
@@ -378,6 +307,8 @@
         promise = promise.done( function () {
             mainDef.resolve( programs );
         } );
+    }).fail(function(){
+        mainDef.resolve( null );
     });
 
     builder.resolve();
@@ -391,22 +322,27 @@
         return $.ajax( {
             url: '../api/programs.json',
             type: 'GET',
-            data: 'paging=false&filter=id:eq:' + id +'&fields=id,name,type,version,dataEntryMethod,relationshipText,relationshipFromA,dateOfEnrollmentDescription,dateOfIncidentDescription,displayIncidentDate,ignoreOverdueEvents,realionshipText,relationshipFromA,selectEnrollmentDatesInFuture,selectIncidentDatesInFuture,onlyEnrollOnce,externalAccess,displayOnAllOrgunit,registration,trackedEntity[id,name,description],userRoles[id,name],organisationUnits[id,name],programStages[id,name,version,minDaysFromStart,standardInterval,generatedByEnrollmentDate,reportDateDescription,repeatable,autoGenerateEvent,openAfterEnrollment,reportDateToUse],programTrackedEntityAttributes[displayInList,mandatory,allowFutureDate,trackedEntityAttribute[id]]'
+            data: 'paging=false&filter=id:eq:' + id +'&fields=id,name,type,version,dataEntryMethod,dateOfEnrollmentDescription,dateOfIncidentDescription,displayIncidentDate,ignoreOverdueEvents,selectEnrollmentDatesInFuture,selectIncidentDatesInFuture,onlyEnrollOnce,externalAccess,displayOnAllOrgunit,registration,relationshipText,relationshipFromA,relatedProgram[id,name],relationshipType[id,name],trackedEntity[id,name,description],userRoles[id,name],organisationUnits[id,name],programStages[id,name,sortOrder,version,minDaysFromStart,reportDateDescription,repeatable,autoGenerateEvent,generatedByEnrollmentDate],programTrackedEntityAttributes[displayInList,mandatory,allowFutureDate,trackedEntityAttribute[id,unique]]'
         }).done( function( response ){
             
             _.each( _.values( response.programs ), function ( program ) { 
                 
                 var ou = {};
-                _.each(_.values( program.organisationUnits), function(o){
-                    ou[o.id] = o.name;
-                });
+                if(program.organisationUnits){
+                    _.each(_.values( program.organisationUnits), function(o){
+                        ou[o.id] = o.name;
+                    });
+                }
 
                 program.organisationUnits = ou;
 
                 var ur = {};
-                _.each(_.values( program.userRoles), function(u){
-                    ur[u.id] = u.name;
-                });
+                
+                if(program.userRoles){
+                    _.each(_.values( program.userRoles), function(u){
+                        ur[u.id] = u.name;
+                    });
+                }                
 
                 program.userRoles = ur;
 
@@ -417,7 +353,7 @@
     };
 }
 
-function getProgramStages( programs )
+function getTrackedEntityAttributes( programs )
 {
     if( !programs ){
         return;
@@ -434,19 +370,21 @@
 
     _.each( _.values( programs ), function ( program ) {
         
-        _.each(_.values(program.programStages), function(programStage){
-            build = build.then(function() {
-                var d = $.Deferred();
-                var p = d.promise();
-                dhis2.tc.store.get('programStages', programStage.id).done(function(obj) {
-                    if(!obj || obj.version !== programStage.version) {
-                        promise = promise.then( getProgramStage( programStage.id ) );
-                    }
-                    d.resolve();
-                });
-                return p;
-            });            
-        });                     
+        if(program.programTrackedEntityAttributes){
+            _.each(_.values(program.programTrackedEntityAttributes), function(teAttribute){
+                build = build.then(function() {
+                    var d = $.Deferred();
+                    var p = d.promise();
+                    dhis2.tc.store.get('attributes', teAttribute.trackedEntityAttribute.id).done(function(obj) {
+                        if(!obj || obj.version !== teAttribute.trackedEntityAttribute.version) {
+                            promise = promise.then( getAttribute( teAttribute.trackedEntityAttribute.id ) );
+                        }
+                        d.resolve();
+                    });
+                    return p;
+                });            
+            });
+        }                             
     });
 
     build.done(function() {
@@ -455,6 +393,8 @@
         promise = promise.done( function () {
             mainDef.resolve( programs );
         } );
+    }).fail(function(){
+        mainDef.resolve( null );
     });
 
     builder.resolve();
@@ -462,22 +402,23 @@
     return mainPromise;    
 }
 
-function getProgramStage( id )
+function getAttribute( id )
 {
     return function() {
         return $.ajax( {
-            url: '../api/programStages.json',
+            url: '../api/trackedEntityAttributes.json',
             type: 'GET',
-            data: 'filter=id:eq:' + id +'&fields=id,name,version,dataEntryForm,captureCoordinates,blockEntryForm,autoGenerateEvent,openAfterEnrollment,reportDateToUse,reportDateDescription,minDaysFromStart,standardInterval,repeatable,programStageDataElements[displayInReports,allowProvidedElsewhere,allowFutureDate,compulsory,dataElement[id,name,formName,type,numberType,optionSet[id]]]'
+            data: 'filter=id:eq:' + id +'&fields=id,name,code,version,description,valueType,inherit,displayOnVisitSchedule,displayInListNoProgram,unique,optionSet[id,version]'
         }).done( function( response ){            
-            _.each( _.values( response.programStages ), function( programStage ) {
-                dhis2.tc.store.set( 'programStages', programStage );
+            _.each( _.values( response.trackedEntityAttributes ), function( teAttribute ) {
+                dhis2.tc.store.set( 'attributes', teAttribute );
             });
         });
     };
 }
 
-function getOptionSetsForPrograms( programs )
+
+function getOptionSetsForAttributes( programs )
 {
     if( !programs ){
         return;
@@ -493,16 +434,17 @@
     var build = builder.promise();    
 
     _.each( _.values( programs ), function ( program ) {
-        _.each(_.values( program.programStages), function( programStage) {
-            _.each(_.values( programStage.programStageDataElements), function(prStDe){            
-                if( prStDe.dataElement.optionSet && prStDe.dataElement.optionSet.id ){
+        
+        if(program.programTrackedEntityAttributes){
+            _.each(_.values( program.programTrackedEntityAttributes), function( teAttribute) {           
+                if( teAttribute.trackedEntityAttribute.optionSet && teAttribute.trackedEntityAttribute.optionSet.id ){
                     build = build.then(function() {
                         var d = $.Deferred();
                         var p = d.promise();
-                        dhis2.tc.store.get('optionSets', prStDe.dataElement.optionSet.id).done(function(obj) {                            
-                            if((!obj || obj.version !== prStDe.dataElement.optionSet.version) && !optionSetsInPromise[prStDe.dataElement.optionSet.id]) {                                
-                                optionSetsInPromise[prStDe.dataElement.optionSet.id] = prStDe.dataElement.optionSet.id;                                
-                                promise = promise.then( getOptionSet( prStDe.dataElement.optionSet.id ) );
+                        dhis2.tc.store.get('optionSets', teAttribute.trackedEntityAttribute.optionSet.id).done(function(obj) {                            
+                            if((!obj || obj.version !== teAttribute.trackedEntityAttribute.optionSet.version) && !optionSetsInPromise[teAttribute.trackedEntityAttribute.optionSet.id]) {                                
+                                optionSetsInPromise[teAttribute.trackedEntityAttribute.optionSet.id] = teAttribute.trackedEntityAttribute.optionSet.id;                                
+                                promise = promise.then( getOptionSet( teAttribute.trackedEntityAttribute.optionSet.id ) );
                             }
                             d.resolve();
                         });
@@ -511,15 +453,139 @@
                     });
                 }            
             });
-        });                              
-    });
-
-    build.done(function() {
-        def.resolve();
-
-        promise = promise.done( function () {
-            mainDef.resolve( programs );
-        } );
+        }                                      
+    });
+
+    build.done(function() {
+        def.resolve();
+
+        promise = promise.done( function () {
+            mainDef.resolve( programs );
+        } );
+    }).fail(function(){
+        mainDef.resolve( null );
+    });
+
+    builder.resolve();
+
+    return mainPromise;    
+}
+
+function getProgramStages( programs )
+{
+    if( !programs ){
+        return;
+    }
+    
+    var mainDef = $.Deferred();
+    var mainPromise = mainDef.promise();
+
+    var def = $.Deferred();
+    var promise = def.promise();
+
+    var builder = $.Deferred();
+    var build = builder.promise();
+
+    _.each( _.values( programs ), function ( program ) {
+        
+        if(program.programStages){
+            _.each(_.values(program.programStages), function(programStage){
+                build = build.then(function() {
+                    var d = $.Deferred();
+                    var p = d.promise();
+                    dhis2.tc.store.get('programStages', programStage.id).done(function(obj) {
+                        if(!obj || obj.version !== programStage.version) {
+                            promise = promise.then( getProgramStage( programStage.id ) );
+                        }
+                        d.resolve();
+                    });
+                    return p;
+                });            
+            });
+        }                             
+    });
+
+    build.done(function() {
+        def.resolve();
+
+        promise = promise.done( function () {
+            mainDef.resolve( programs );
+        } );
+    }).fail(function(){
+        mainDef.resolve( null );
+    });
+
+    builder.resolve();
+
+    return mainPromise;    
+}
+
+function getProgramStage( id )
+{
+    return function() {
+        return $.ajax( {
+            url: '../api/programStages.json',
+            type: 'GET',
+            data: 'filter=id:eq:' + id +'&fields=id,name,sortOrder,version,dataEntryForm,captureCoordinates,blockEntryForm,autoGenerateEvent,generatedByEnrollmentDate,reportDateDescription,minDaysFromStart,repeatable,programStageDataElements[displayInReports,allowProvidedElsewhere,allowFutureDate,compulsory,dataElement[id,code,name,formName,type,optionSet[id]]]'
+        }).done( function( response ){            
+            _.each( _.values( response.programStages ), function( programStage ) {
+                dhis2.tc.store.set( 'programStages', programStage );
+            });
+        });
+    };
+}
+
+function getOptionSetsForDataElements( programs )
+{
+    if( !programs ){
+        return;
+    }
+    
+    var mainDef = $.Deferred();
+    var mainPromise = mainDef.promise();
+
+    var def = $.Deferred();
+    var promise = def.promise();
+
+    var builder = $.Deferred();
+    var build = builder.promise();    
+
+    _.each( _.values( programs ), function ( program ) {
+        
+        if(program.programStages){
+            _.each(_.values( program.programStages), function( programStage) {
+                
+                if(programStage.programStageDataElements){
+                    _.each(_.values( programStage.programStageDataElements), function(prStDe){            
+                        if( prStDe.dataElement.optionSet && prStDe.dataElement.optionSet.id ){
+                            build = build.then(function() {
+                                var d = $.Deferred();
+                                var p = d.promise();
+                                dhis2.tc.store.get('optionSets', prStDe.dataElement.optionSet.id).done(function(obj) {                            
+                                    if((!obj || obj.version !== prStDe.dataElement.optionSet.version) && !optionSetsInPromise[prStDe.dataElement.optionSet.id]) {                                
+                                        optionSetsInPromise[prStDe.dataElement.optionSet.id] = prStDe.dataElement.optionSet.id;                                
+                                        promise = promise.then( getOptionSet( prStDe.dataElement.optionSet.id ) );
+                                    }
+                                    d.resolve();
+                                });
+
+                                return p;
+                            });
+                        }            
+                    });
+                }                
+            });
+        }                                      
+    });
+
+    build.done(function() {
+        def.resolve();
+
+        promise = promise.done( function () {
+            mainDef.resolve( programs );
+        } );
+    }).fail(function(){
+        mainDef.resolve( null );
     });
 
     builder.resolve();
@@ -565,6 +631,9 @@
         });
         
         def.resolve( trackedEntityForms );
+        
+    }).fail(function(){
+        def.resolve( null );
     });
     
     return def.promise(); 
@@ -607,6 +676,8 @@
         promise = promise.done( function () {
             mainDef.resolve();
         } );
+    }).fail(function(){
+        mainDef.resolve();
     });
 
     builder.resolve();

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css	2014-12-16 15:44:11 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css	2014-12-19 16:52:40 +0000
@@ -529,7 +529,7 @@
     font-size: 14px;
 }
 
-input[type=number], input[type=text], input[type=password], textarea, select {
+input[type=number], input[type=text], input[type=email], input[type=password], textarea, select {
     border: 1px solid #aaa;
     padding: 2px 6px;
     font-size: 14px;
@@ -636,6 +636,7 @@
     font-size: 14px;
     line-height: 1.0;
     color: #555;
+    padding: 2px 6px;
     margin-bottom: 5px;
     margin-top: 5px;
     vertical-align: middle;
@@ -824,6 +825,10 @@
     font-weight: bold;
 }
 
+.disable-clicks {
+    pointer-events: none;
+}
+
 @media print {
     #header, #leftBar, .not-printable {
         display: none;

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/views/home.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/views/home.html	2014-12-16 07:54:45 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/views/home.html	2014-12-19 16:52:40 +0000
@@ -41,11 +41,17 @@
         </ul>
     </div>
     <img id="ouwt_loader" src="../images/ajax-loader-bar.gif"/>
+    <div class="small-horizonal-spacing" ng-if='!treeLoaded'>
+        {{'loading_tree'| translate}}
+    </div> 
 </div>
 
 <div class="page" id="mainPage">
     
-    <img src="../images/ajax-loader-bar.gif" alt="{{'in_progress'| translate}}" ng-if="!selectedOrgUnit"/>
+    <div ng-if="!selectedOrgUnit">
+        <img src="../images/ajax-loader-bar.gif" alt="{{'in_progress'| translate}}" ng-if="!selectedOrgUnit"/><br>
+        {{'loading_metadata'| translate}}
+    </div> 
 
     <div ng-show="selectedOrgUnit">
 		
@@ -88,7 +94,9 @@
                 <input type="text" class="form-control" ng-disabled='true' value="{{selectedOrgUnit.name}}">
             </div>
         </div>
-        <div class="row"> 
+        <div class="row">
+            
+            <!-- program selection begins -->
             <div id="selectDropDownParent" class="input-group col-md-4">            
                 <button type="button" class="select-dropdown-button form-control" ng-show="programs.length > 0">{{selectedProgram ? selectedProgram.name : 'please_select_a_program'| translate}}</button>
                 <button type="button" class="select-dropdown-button form-control" ng-show="programs.length < 1" ng-disabled="true">{{programs.length > 0 ? 'please_select_a_program' : 'no_program_exists' | translate}}</button>
@@ -104,6 +112,9 @@
                     </ul>
                 </div>                
             </div>
+            <!-- program selection ends -->
+            
+            <!-- simple/advanced search begins -->
             <div id="searchDropDownParent" class="input-group col-md-4 not-printable">
                 <input type="text" placeholder="{{'type_here_for_simple_search'| translate}}" ng-model="searchText" class="form-control expanded" d2-enter="search(searchMode.freeText)" ng-class="{true: 'invalid-input'} [!searchText && emptySearchText]" ng-focus="showHideSearch()" ng-disabled="showRegistrationDiv || showReportDiv">
                 <div class="input-group-btn">
@@ -112,6 +123,7 @@
                     <div id="searchDropDown" class="dropdown-menu dropdown-menu-right">
                         <form name="searchForm">
                             <div class="search-container-main">
+                                
                                 <div class="search-container">    
                                     <table data-stop-propagation="true" class="table-borderless table-striped">
                                         <tr>
@@ -224,7 +236,10 @@
                         </form>
                     </div>
                 </div>                
-            </div>        
+            </div>
+            <!-- simple/advanced search ends -->
+            
+            <!--search/registration buttons begin-->
             <div class="col-md-4 trim not-printable">            
                 <button type="button" 
                         class="btn btn-success"
@@ -245,6 +260,8 @@
                     {{'print'| translate}}
                 </button>
             </div>
+            <!--search/registration buttons end-->
+            
         </div>
         <!--- search, registration and reporting menu ends -->
 

=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/services.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/services.js	2014-12-18 11:50:32 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/services.js	2014-12-19 16:52:40 +0000
@@ -165,10 +165,7 @@
             }            
             var calendarSetting = CalendarService.getSetting();
             dateValue = moment(dateValue, 'YYYY-MM-DD')._d;
-            dateValue = Date.parse(dateValue);     
-            //dateValue = $filter('date')(dateValue, calendarSetting.keyDateFormat); 
-            //return dateValue;
-            return $filter('date')(dateValue, calendarSetting.keyDateFormat);
+            return $filter('date')(this.getDate(dateValue), calendarSetting.keyDateFormat); 
         }
     };
 })