diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js
index d551d6af11..cab1d896e0 100644
--- a/awx/ui/static/js/app.js
+++ b/awx/ui/static/js/app.js
@@ -18,11 +18,13 @@ if ($basePath) {
urlPrefix = $basePath;
}
+
angular.module('Tower', [
'ngRoute',
'ngSanitize',
'ngCookies',
'RestServices',
+ 'DataServices',
'AuthService',
'Utilities',
'LicenseHelper',
@@ -131,7 +133,6 @@ angular.module('Tower', [
.constant('AngularScheduler.useTimezone', true)
.constant('AngularScheduler.showUTCField', true)
.constant('$timezones.definitions.location', urlPrefix + 'lib/angular-tz-extensions/tz/data')
-
.config(['$routeProvider',
function ($routeProvider) {
diff --git a/awx/ui/static/js/services/job-status-graph-data.js b/awx/ui/static/js/services/job-status-graph-data.js
new file mode 100644
index 0000000000..638774177b
--- /dev/null
+++ b/awx/ui/static/js/services/job-status-graph-data.js
@@ -0,0 +1,36 @@
+angular.module('DataServices', [])
+ .service('jobStatusGraphData',
+ ["RestServices",
+ "GetBasePath",
+ "ProcessErrors",
+ "$rootScope",
+ "$q",
+ JobStatusGraphData]);
+
+function JobStatusGraphData(Rest, getBasePath, processErrors, $rootScope, $q) {
+ var callbacks = {};
+ var currentCallbackId = 0;
+
+ function getData() {
+ return Rest.get();
+ }
+
+ return {
+ setupWatcher: function() {
+ $rootScope.$on('JobStatusChange', function() {
+ getData().then(function(result) {
+ $rootScope.
+ $broadcast('DataReceived:JobStatusGraph',
+ result);
+ });
+ });
+ },
+ get: function(period, jobType) {
+
+ this.setupWatcher();
+
+ return getData();
+
+ }
+ };
+}
diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html
index 59572635ff..0a4310d75f 100644
--- a/awx/ui/templates/ui/index.html
+++ b/awx/ui/templates/ui/index.html
@@ -81,6 +81,7 @@
+
diff --git a/awx/ui/tests/unit/services/job-status-graph-data-test.js b/awx/ui/tests/unit/services/job-status-graph-data-test.js
index 692104c9db..e36014b500 100644
--- a/awx/ui/tests/unit/services/job-status-graph-data-test.js
+++ b/awx/ui/tests/unit/services/job-status-graph-data-test.js
@@ -1,3 +1,94 @@
-describe("JobStatusGraphDataFactory", function() {
- it('should fail', function() { expect(true).to.be.true; });
+describe('Job Status Graph Data Service', function() {
+
+ var q;
+
+ var jobStatusGraphData, httpBackend, rootScope, timeout;
+
+ var jobStatusChange = {
+ $on: sinon.spy(),
+ };
+
+ function flushPromises() {
+ window.setTimeout(function() {
+ inject(function($rootScope) {
+ $rootScope.$apply();
+ });
+ }, 100);
+ }
+
+ var restStub = {
+ setUrl: angular.noop,
+ reset: function() {
+ delete restStub.deferred;
+ },
+ get: function() {
+ if (angular.isUndefined(restStub.deferred)) {
+ restStub.deferred = q.defer();
+ }
+
+ return restStub.deferred.promise;
+ },
+ succeed: function(value) {
+ restStub.deferred.resolve(value);
+ },
+ fail: function(value) {
+ restStub.deferred.reject(value);
+ }
+ };
+
+ beforeEach(module("Tower"));
+
+ beforeEach(module(function($provide) {
+
+ $provide.value("$cookieStore", { get: angular.noop });
+
+ $provide.value('RestServices', restStub);
+ }));
+
+ afterEach(function() {
+ restStub.reset();
+ });
+
+ beforeEach(inject(function(_jobStatusGraphData_, $httpBackend, $q, $rootScope, $timeout) {
+ jobStatusGraphData = _jobStatusGraphData_;
+ httpBackend = $httpBackend;
+ rootScope = $rootScope;
+ timeout = $timeout;
+ $httpBackend.expectGET('/static/js/local_config.js').respond({
+ });
+ q = $q;
+ }));
+
+ it('returns a promise to be fulfilled when data comes in', function() {
+ var firstResult = "result";
+
+ var result = jobStatusGraphData.get('', '');
+
+ restStub.succeed(firstResult);
+
+ flushPromises();
+
+ return expect(result).to.eventually.equal(firstResult);;
+ });
+
+ it('broadcasts event when data is received', function() {
+ var expected = "value";
+ var result = q.defer();
+ jobStatusGraphData.setupWatcher();
+
+ inject(function($rootScope) {
+ $rootScope.$on('DataReceived:JobStatusGraph', function(e, data) {
+ result.resolve(data);
+ });
+ $rootScope.$emit('JobStatusChange');
+ restStub.succeed(expected);
+ flushPromises();
+ });
+
+ return expect(result.promise).to.eventually.equal(expected);
+ });
+
+ xit('processes errors through error handler', function() {
+ });
+
});