Skip to content

Commit

Permalink
Add analytics update status
Browse files Browse the repository at this point in the history
  • Loading branch information
Markionium committed Apr 25, 2015
1 parent 51d5a3b commit 094aa16
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 61 deletions.
47 changes: 47 additions & 0 deletions src/main/analyticsstatus/analyticsstatus-directive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
angular.module('PEPFAR.approvals').directive('analyticsStatus', analyticsStatusDirective);

function analyticsStatusDirective() {
return {
restrict: 'E',
scope: true,
template: '<div class="analytics-status-update" ng-bind="analyticsStatusCtrl.getStatusText()"></div>',
controller: analyticsStatusCtrl,
controllerAs: 'analyticsStatusCtrl',
bindToController: true
};

function analyticsStatusCtrl(analyticsStatus, $timeout) {
var vm = this;
var analyticsUpdateInterval;

vm.getStatusText = getStatusText;

initialise();
function initialise() {
getStatusUpdate();
}

function getStatusUpdate() {
analyticsStatus.getIntervalSinceLastAnalyticsTableSuccess()
.then(function (intervalSinceLastAnalyticsTableSuccess) {

analyticsUpdateInterval = [
'Data was updated',
intervalSinceLastAnalyticsTableSuccess,
'ago'
].join(' ');
})
.catch(function (message) {
analyticsUpdateInterval = message;
$timeout(getStatusUpdate, 30000);
})
.finally(function () {
$timeout(getStatusUpdate, 30000);
});
}

function getStatusText() {
return analyticsUpdateInterval;
}
}
}
22 changes: 22 additions & 0 deletions src/main/analyticsstatus/analyticsstatus-service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
angular.module('PEPFAR.approvals').factory('analyticsStatus', analyticsStatus);

function analyticsStatus(Restangular, errorHandler, $q) {
return {
getIntervalSinceLastAnalyticsTableSuccess: getIntervalSinceLastAnalyticsTableSuccess
};

function getIntervalSinceLastAnalyticsTableSuccess() {
var NOT_FOUND_MESSAGE = 'Unable to find last updated time';

return Restangular.all('system').get('info')
.then(function (systemInfo) {
if (systemInfo.intervalSinceLastAnalyticsTableSuccess) {
return systemInfo.intervalSinceLastAnalyticsTableSuccess;
}
return $q.reject(NOT_FOUND_MESSAGE);
})
.catch(function () {
return $q.reject(NOT_FOUND_MESSAGE);
});
}
}
11 changes: 0 additions & 11 deletions src/main/analyticsstatus/analyticsstatus.js

This file was deleted.

3 changes: 3 additions & 0 deletions src/main/app.sass
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,9 @@ tr:nth-child(odd).selected
div.header-bar a.title-link
position: initial

.analytics-status-update
color: #BBB

@media (min-width: 768px)
.nav-tabs.nav-justified > li
width: 22%
Expand Down
11 changes: 10 additions & 1 deletion src/main/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,16 @@

<div class="info-wrap">
<div>
<h1 ng-bind="app.title">Data approval</h1><span class="status"><span class="prefix" translate>status</span><span ng-show="app.actionItems" ng-bind="app.actionItems" class="badge available-actions-dot"></span><span ng-bind="app.getStatus()"></span></span>
<h1 ng-bind="app.title">Data approval</h1>
<span class="status">
<span class="prefix" translate>status</span>
<span ng-show="app.actionItems"
ng-bind="app.actionItems"
class="badge available-actions-dot">
</span>
<span ng-bind="app.getStatus()"></span>
</span>
<analytics-status></analytics-status>
</div>
</div>

Expand Down
2 changes: 1 addition & 1 deletion src/main/manifest.webapp
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":"0.3.0","name":"Data Approval","description":"Approvals app for PEPFAR","icons":{"48":"img/icons/dataapproval.png"},"developer":{"url":"http://www.dhis2.org","name":"Mark Polak","company":"DHIS2 Core Team","email":"[email protected]"},"launch_path":"index.html","default_locale":"en","activities":{"dhis":{"href":"*"}}}
{"version":"0.3.1","name":"Data Approval","description":"Approvals app for PEPFAR","icons":{"48":"img/icons/dataapproval.png"},"developer":{"url":"http://www.dhis2.org","name":"Mark Polak","company":"DHIS2 Core Team","email":"[email protected]"},"launch_path":"index.html","default_locale":"en","activities":{"dhis":{"href":"*"}}}
3 changes: 3 additions & 0 deletions src/test/fixtures/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,9 @@

library.organisationUnitsForLevelThree = {"organisationUnits":[{"id":"XOivy2uDpMF","name":"Angola"},{"id":"iD2i0aynOGm","name":"Asia Regional Program"},{"id":"l1KFEXKI4Dg","name":"Botswana"},{"id":"wChmwjpXOw2","name":"Burma"},{"id":"Qh4XMQJhbk8","name":"Burundi"},{"id":"XWZK2nop7pM","name":"Cambodia"},{"id":"bQQJe0cC1eD","name":"Cameroon"},{"id":"nBo9Y4yZubB","name":"Caribbean Region"},{"id":"vSu0nPMbq7b","name":"Central America Region"},{"id":"t25400wXrNB","name":"Central Asia Region"},{"id":"CZ9ysPg2dSk","name":"China"},{"id":"ds0ADyc9UCU","name":"Cote d'Ivoire"},{"id":"ANN4YCOufcP","name":"Democratic Republic of the Congo"},{"id":"NzelIFhEv3C","name":"Dominican Republic"},{"id":"IH1kchw86uA","name":"Ethiopia"},{"id":"y3zhsvdXlhN","name":"Ghana"},{"id":"PeOHqAwdtez","name":"Guyana"},{"id":"JTypsdEUNPw","name":"Haiti"},{"id":"skj3e4YSiJY","name":"India"},{"id":"W73PRZcjFIU","name":"Indonesia"},{"id":"HfVjCurKxh2","name":"Kenya"},{"id":"qllxzIjjurr","name":"Lesotho"},{"id":"lZsCb6y0KDX","name":"Malawi"},{"id":"h11OyvlPxpJ","name":"Mozambique"},{"id":"FFVkaV9Zk1S","name":"Namibia"},{"id":"PqlFzhuPcF1","name":"Nigeria"},{"id":"cl7jVQOW3Ks","name":"Papua New Guinea"},{"id":"XtxUYCsDWrR","name":"Rwanda"},{"id":"cDGPF739ZZr","name":"South Africa"},{"id":"WLG0z5NxQs8","name":"South Sudan"},{"id":"V0qMZH29CtN","name":"Swaziland"},{"id":"mdXu6iCbn2G","name":"Tanzania"},{"id":"FETQ6OmnsKB","name":"Uganda"},{"id":"ligZVIYs2rL","name":"Ukraine"},{"id":"YM6xn5QxNpY","name":"Vietnam"},{"id":"f5RoebaDLMx","name":"Zambia"},{"id":"a71G4Gtcttv","name":"Zimbabwe"}]};

library['system/info'] =
{"contextPath":"http://localhost:8080/dhis","userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.82 Safari/537.36 OPR/29.0.1795.41 (Edition beta)","calendar":"iso8601","dateFormat":"yyyy-mm-dd","serverDate":"2015-04-25T11:39:39.109+0000","lastAnalyticsTableSuccess":"2015-03-14T23:03:27.809+0000","intervalSinceLastAnalyticsTableSuccess":"996 h, 36 m, 11 s","version":"2.19-SNAPSHOT","revision":"19021","buildTime":"2015-04-25T10:57:02.000+0000","environmentVariable":"DHIS2_HOME","javaVersion":"1.7.0_25","javaVendor":"Oracle Corporation","javaHome":"/Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/jre","javaIoTmpDir":"/usr/local/apache-tomcat-8.0.5/temp","javaOpts":"-Xms512m -Xmx1024m -XX:MaxPermSize=256M","osName":"Mac OS X","osArchitecture":"x86_64","osVersion":"10.9.4","externalDirectory":"/Work/UIO/dhis","databaseInfo":{"type":"PostgreSQL","name":"dedupe","user":"postgres"},"memoryInfo":"Mem Total in JVM: 757 Free in JVM: 484 Max Limit: 989","cpuCores":4,"systemId":"4892b46d-b5dd-4d41-9a8b-2e39d8e445de"};

function getFixture(key) {
return library[key];
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/karma.conf.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module.exports = function( config ) {
config.set({
basePath: '../../src/main',
frameworks: ['jasmine'],
frameworks: ['jasmine', 'sinon'],

preprocessors: {
'../main/**/*.html': 'html2js',
Expand Down
54 changes: 54 additions & 0 deletions src/test/specs/analyticsstatus/analyticsstatus-directive_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
describe('Analytis status directive', function () {
var element;
var scope;
var $timeout;

beforeEach(module('PEPFAR.approvals', function ($provide) {
$provide.factory('analyticsStatus', function ($q) {
return {
getIntervalSinceLastAnalyticsTableSuccess: jasmine.createSpy()
.andReturn($q.when(fixtures.get('system/info').intervalSinceLastAnalyticsTableSuccess))
};
});
}));
beforeEach(inject(function ($injector) {
$rootScope = $injector.get('$rootScope');
$compile = $injector.get('$compile');
$timeout = $injector.get('$timeout');
element = angular.element('<analytics-status></analytics-status>');

scope = $rootScope.$new();
element = $compile(element)(scope).children().first();
scope.$digest();
}));

it('should compile to a div', function () {
expect(element.prop('tagName')).toBe('DIV');
});

it('should show the time of the last update', function () {
expect(element[0].textContent).toEqual('Data was updated 996 h, 36 m, 11 s ago');
});

it('should update the time after a certain period', inject(function (analyticsStatus, $q) {
expect(element[0].textContent).toEqual('Data was updated 996 h, 36 m, 11 s ago');

analyticsStatus.getIntervalSinceLastAnalyticsTableSuccess
.andReturn($q.when('0 h, 36 m, 11 s'));

$timeout.flush(30000);

expect(element[0].textContent).toEqual('Data was updated 0 h, 36 m, 11 s ago');
}));

it('should not display anything if the status update failed', inject(function (analyticsStatus, $q) {
expect(element[0].textContent).toEqual('Data was updated 996 h, 36 m, 11 s ago');

analyticsStatus.getIntervalSinceLastAnalyticsTableSuccess
.andReturn($q.reject('Unable to find last updated time'));

$timeout.flush(30000);

expect(element[0].textContent).toEqual('Unable to find last updated time');
}));
});
80 changes: 55 additions & 25 deletions src/test/specs/analyticsstatus/analyticsstatus-service_spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
describe('Analytics status service', function () {
var service;

beforeEach(module('PEPFAR.approvals'));
beforeEach(module('d2-rest'));
beforeEach(module('PEPFAR.approvals', function ($provide) {
$provide.factory('errorHandler', function () {
return {
warn: jasmine.createSpy('errorHandler.warn')
};
})
}));
beforeEach(inject(function ($injector) {
service = $injector.get('analyticsStatus');
}));
Expand All @@ -11,49 +18,72 @@ describe('Analytics status service', function () {
});

it('should return a promise object', function () {
expect(service.get()).toBeAPromiseLikeObject();
expect(service.getIntervalSinceLastAnalyticsTableSuccess()).toBeAPromiseLikeObject();
});

describe('get function', function () {
var $httpBackend, approvalLevels;
describe('getStatus', function () {
var $httpBackend;
var systemInfoRequest;

beforeEach(inject(function (_$httpBackend_) {
$httpBackend = _$httpBackend_;

$httpBackend.expectGET('/dhis/api/organisationUnitLevels?fields=level,displayName&paging=false')
.respond(200, fixtures.get('orgUnitLevels'));
$httpBackend.expectGET('/dhis/api/dataApprovalLevels?fields=id,name,displayName,orgUnitLevel,level,categoryOptionGroupSet%5Bid,name%5D')
.respond(200, fixtures.get('approvalLevels'));

service.get().then(function (data) {
approvalLevels = data;
});

$httpBackend.flush();
systemInfoRequest = $httpBackend.expectGET('/dhis/api/system/info');
systemInfoRequest.respond(200, fixtures.get('system/info'));
}));

afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});

it('should return an array of with approval level objects', function () {
expect(approvalLevels.length).toBe(4);
it('should ask for system/info from the server', function () {
service.getIntervalSinceLastAnalyticsTableSuccess();

$httpBackend.flush();
});

it('should have a getLevelNames function on the result', function () {
expect(approvalLevels.getCategoryOptionGroupSetIdsForLevels).toBeAFunction();
it('should return the string of for the time', function () {
var intervalText;

service.getIntervalSinceLastAnalyticsTableSuccess()
.then(function (data) {
intervalText = data;
});

$httpBackend.flush();

expect(intervalText).toEqual('996 h, 36 m, 11 s');
});

it('should give an array when the level names when calling getLevelNames on the result', function () {
expect(approvalLevels.getCategoryOptionGroupSetIdsForLevels()).toEqual([ { level: 3, cogsId: 'bw8KHXzxd9i' }, { level: 4, cogsId: 'BOyWrF33hiR' }]);
it('should show message on missing property', function () {
var intervalText;

systemInfoRequest.respond(200, {});

service.getIntervalSinceLastAnalyticsTableSuccess()
.catch(function (data) {
intervalText = data;
});

$httpBackend.flush();

expect(intervalText).toEqual('Unable to find last updated time');
});

it('should add the name of the org unit level to the approval level if it is available', function () {
expect(approvalLevels[0].levelName).toBe('Global');
expect(approvalLevels[1].levelName).toBe('Country');
expect(approvalLevels[2].levelName).toBe('Funding Agency');
expect(approvalLevels[3].levelName).toBe('Implementing Partner');
it('should show not found message on http error', function () {
var intervalText;

systemInfoRequest.respond(200, {});

service.getIntervalSinceLastAnalyticsTableSuccess()
.catch(function (data) {
intervalText = data;
});

$httpBackend.flush();

expect(intervalText).toEqual('Unable to find last updated time');
});
});
});
37 changes: 15 additions & 22 deletions src/test/specs/mechanisms/mechanisms-service_spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
describe('Mechanisms service', function () {
var mechanismsService;
var $httpBackend;
var $rootScope;
var $log;
var server;
var apiUrlWithCorrectParameters = ['/dhis/api/categories?',
'fields=id,name,categoryOptions%5Bid,name,organisationUnits%5Bid,name%5D,',
'categoryOptionCombos%5Bid,name%5D,categoryOptionGroups%5Bid,name,categoryOptionGroupSet%5Bid%5D%5D&',
Expand All @@ -13,13 +15,21 @@ describe('Mechanisms service', function () {
beforeEach(module('d2-rest'));
beforeEach(module('PEPFAR.approvals', function ($provide) {
$provide.factory('AppManifest', function () {
return {activities: {dhis: '/'}};
return {activities: {dhis: '/'}};
});
}));

beforeEach(inject(function (_mechanismsService_, _$httpBackend_, _$log_) {
beforeEach(inject(function (_mechanismsService_, _$httpBackend_, _$log_, _$rootScope_) {
server = window.sinon.fakeServer.create();
server.respondWith('GET', apiUrlWithCorrectParameters, [
404,
{ "Content-Type": "application/json" },
'Error'
]);

mechanismsService = _mechanismsService_;
$httpBackend = _$httpBackend_;
$rootScope = _$rootScope_;
$log = _$log_;

//TODO: If we mock the approvalLevelsService we will not have to do the http call
Expand Down Expand Up @@ -52,37 +62,20 @@ describe('Mechanisms service', function () {

mechanismsService.getData();

$httpBackend.expectGET(apiUrlWithCorrectParameters).respond(200);
server.respond();
});

it('should only return the data and not the added rest functions', function () {
var mechanisms = [];

$httpBackend.expectGET(apiUrlWithCorrectParameters).respond(200, angular.copy(categoriesFromApi));

mechanismsService.period = '2014';
mechanismsService.categories = ['dsetId1', 'dsetId2', 'dsetId3'];

mechanismsService.getData().then(function (data) {
mechanisms = data
});
$httpBackend.flush();

expect(mechanisms[0].getRestangularUrl).not.toBeDefined();
expect(mechanisms[0].restangularCollection).not.toBeDefined();
expect(mechanisms[0].getDataOnly).not.toBeDefined();
});

it('should reject when the request fails', function () {
var catchSpy = jasmine.createSpy();

$httpBackend.expectGET(apiUrlWithCorrectParameters).respond(404);

mechanismsService.period = '2014';
mechanismsService.categories = ['dsetId1', 'dsetId2', 'dsetId3'];

mechanismsService.getData().catch(catchSpy);
$httpBackend.flush();
server.respond();
$rootScope.$apply();

expect(catchSpy).toHaveBeenCalled();
});
Expand Down

0 comments on commit 094aa16

Please sign in to comment.