diff --git a/awx/main/tests/functional/conftest.py b/awx/main/tests/functional/conftest.py index 7305b95799..d7779237b4 100644 --- a/awx/main/tests/functional/conftest.py +++ b/awx/main/tests/functional/conftest.py @@ -1,5 +1,10 @@ import pytest +from django.core.urlresolvers import resolve +from django.utils.six.moves.urllib.parse import urlparse + +from awx.main.models.organization import Organization +from awx.main.models.ha import Instance from django.contrib.auth.models import User from rest_framework.test import ( @@ -105,13 +110,16 @@ def permissions(): @pytest.fixture def post(): - def rf(_cls, _user, _url, pk=None, kwargs={}, middleware=None): - view = _cls.as_view() - request = APIRequestFactory().post(_url, kwargs, format='json') + def rf(url, data, user=None, middleware=None, **kwargs): + view, view_args, view_kwargs = resolve(urlparse(url)[2]) + if 'format' not in kwargs: + kwargs['format'] = 'json' + request = APIRequestFactory().post(url, data, **kwargs) if middleware: middleware.process_request(request) - force_authenticate(request, user=_user) - response = view(request, pk=pk) + if user: + force_authenticate(request, user=user) + response = view(request, *view_args, **view_kwargs) if middleware: middleware.process_response(request, response) return response @@ -119,13 +127,101 @@ def post(): @pytest.fixture def get(): - def rf(_cls, _user, _url, pk=None, middleware=None): - view = _cls.as_view() - request = APIRequestFactory().get(_url, format='json') + def rf(url, user=None, middleware=None, **kwargs): + view, view_args, view_kwargs = resolve(urlparse(url)[2]) + if 'format' not in kwargs: + kwargs['format'] = 'json' + request = APIRequestFactory().get(url, **kwargs) if middleware: middleware.process_request(request) - force_authenticate(request, user=_user) - response = view(request, pk=pk) + if user: + force_authenticate(request, user=user) + response = view(request, *view_args, **view_kwargs) + if middleware: + middleware.process_response(request, response) + return response + return rf + +@pytest.fixture +def put(): + def rf(url, data, user=None, middleware=None, **kwargs): + view, view_args, view_kwargs = resolve(urlparse(url)[2]) + if 'format' not in kwargs: + kwargs['format'] = 'json' + request = APIRequestFactory().put(url, data, **kwargs) + if middleware: + middleware.process_request(request) + if user: + force_authenticate(request, user=user) + response = view(request, *view_args, **view_kwargs) + if middleware: + middleware.process_response(request, response) + return response + return rf + +@pytest.fixture +def patch(): + def rf(url, data, user=None, middleware=None, **kwargs): + view, view_args, view_kwargs = resolve(urlparse(url)[2]) + if 'format' not in kwargs: + kwargs['format'] = 'json' + request = APIRequestFactory().patch(url, data, **kwargs) + if middleware: + middleware.process_request(request) + if user: + force_authenticate(request, user=user) + response = view(request, *view_args, **view_kwargs) + if middleware: + middleware.process_response(request, response) + return response + return rf + +@pytest.fixture +def delete(): + def rf(url, user=None, middleware=None, **kwargs): + view, view_args, view_kwargs = resolve(urlparse(url)[2]) + if 'format' not in kwargs: + kwargs['format'] = 'json' + request = APIRequestFactory().delete(url, **kwargs) + if middleware: + middleware.process_request(request) + if user: + force_authenticate(request, user=user) + response = view(request, *view_args, **view_kwargs) + if middleware: + middleware.process_response(request, response) + return response + return rf + +@pytest.fixture +def head(): + def rf(url, user=None, middleware=None, **kwargs): + view, view_args, view_kwargs = resolve(urlparse(url)[2]) + if 'format' not in kwargs: + kwargs['format'] = 'json' + request = APIRequestFactory().head(url, **kwargs) + if middleware: + middleware.process_request(request) + if user: + force_authenticate(request, user=user) + response = view(request, *view_args, **view_kwargs) + if middleware: + middleware.process_response(request, response) + return response + return rf + +@pytest.fixture +def options(): + def rf(url, data, user=None, middleware=None, **kwargs): + view, view_args, view_kwargs = resolve(urlparse(url)[2]) + if 'format' not in kwargs: + kwargs['format'] = 'json' + request = APIRequestFactory().options(url, data, **kwargs) + if middleware: + middleware.process_request(request) + if user: + force_authenticate(request, user=user) + response = view(request, *view_args, **view_kwargs) if middleware: middleware.process_response(request, response) return response diff --git a/awx/main/tests/functional/test_activity_streams.py b/awx/main/tests/functional/test_activity_streams.py index cf2f81c9d9..64a2fcb61f 100644 --- a/awx/main/tests/functional/test_activity_streams.py +++ b/awx/main/tests/functional/test_activity_streams.py @@ -1,11 +1,6 @@ import mock import pytest -from awx.api.views import ( - ActivityStreamList, - ActivityStreamDetail, - OrganizationList, -) from awx.main.middleware import ActivityStreamMiddleware from awx.main.models.activity_stream import ActivityStream from django.core.urlresolvers import reverse @@ -17,7 +12,7 @@ def mock_feature_enabled(feature, bypass_database=None): @pytest.mark.django_db def test_get_activity_stream_list(monkeypatch, organization, get, user): url = reverse('api:activity_stream_list') - response = get(ActivityStreamList, user('admin', True), url) + response = get(url, user('admin', True)) assert response.status_code == 200 @@ -31,7 +26,7 @@ def test_basic_fields(monkeypatch, organization, get, user): aspk = activity_stream.pk url = reverse('api:activity_stream_detail', args=(aspk,)) - response = get(ActivityStreamDetail, user('admin', True), url, pk=aspk) + response = get(url, user('admin', True)) assert response.status_code == 200 assert 'related' in response.data @@ -46,8 +41,9 @@ def test_middleware_actor_added(monkeypatch, post, get, user): u = user('admin-poster', True) url = reverse('api:organization_list') - response = post(OrganizationList, u, url, - kwargs=dict(name='test-org', description='test-desc'), + response = post(url, + dict(name='test-org', description='test-desc'), + u, middleware=ActivityStreamMiddleware()) assert response.status_code == 201 @@ -55,7 +51,7 @@ def test_middleware_actor_added(monkeypatch, post, get, user): activity_stream = ActivityStream.objects.filter(organization__pk=org_id).first() url = reverse('api:activity_stream_detail', args=(activity_stream.pk,)) - response = get(ActivityStreamDetail, u, url, pk=activity_stream.pk) + response = get(url, u) assert response.status_code == 200 assert response.data['summary_fields']['actor']['username'] == 'admin-poster' diff --git a/awx/ui/client/legacy-styles/job-details.less b/awx/ui/client/legacy-styles/job-details.less index 32c88aae35..621e0267ca 100644 --- a/awx/ui/client/legacy-styles/job-details.less +++ b/awx/ui/client/legacy-styles/job-details.less @@ -549,7 +549,7 @@ word-break: break-all; word-wrap: break-word; padding: 9.5px; - ont-family: Fixed, monospace; + font-family: Fixed, monospace; max-height: 200px; } diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index b62191f36e..43ad6627fb 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -31,6 +31,7 @@ import systemTracking from './system-tracking/main'; import inventoryScripts from './inventory-scripts/main'; import permissions from './permissions/main'; import managementJobs from './management-jobs/main'; +import jobDetail from './job-detail/main'; // modules import setupMenu from './setup-menu/main'; @@ -43,8 +44,7 @@ import templateUrl from './shared/template-url/main'; import adhoc from './adhoc/main'; import login from './login/main'; import activityStream from './activity-stream/main'; -import {JobDetailController} from './controllers/JobDetail'; -import {JobStdoutController} from './controllers/JobStdout'; +import standardOut from './standard-out/main'; import {JobTemplatesList, JobTemplatesAdd, JobTemplatesEdit} from './controllers/JobTemplates'; import {LicenseController} from './controllers/License'; import {ScheduleEditController} from './controllers/Schedules'; @@ -95,6 +95,8 @@ var tower = angular.module('Tower', [ login.name, activityStream.name, footer.name, + jobDetail.name, + standardOut.name, 'templates', 'Utilities', 'LicenseHelper', @@ -293,83 +295,6 @@ var tower = angular.module('Tower', [ } }). - state('jobDetail', { - url: '/jobs/:id', - templateUrl: urlPrefix + 'partials/job_detail.html', - controller: JobDetailController, - ncyBreadcrumb: { - parent: 'jobs', - label: "{{ job.id }} - {{ job.name }}" - }, - resolve: { - features: ['FeaturesService', function(FeaturesService) { - return FeaturesService.get(); - }], - jobEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { - if (!$rootScope.event_socket) { - $rootScope.event_socket = Socket({ - scope: $rootScope, - endpoint: "job_events" - }); - $rootScope.event_socket.init(); - return true; - } else { - return true; - } - }] - } - }). - - state('jobsStdout', { - url: '/jobs/:id/stdout', - templateUrl: urlPrefix + 'partials/job_stdout.html', - controller: JobStdoutController, - ncyBreadcrumb: { - parent: 'jobDetail', - label: "STANDARD OUT" - }, - resolve: { - features: ['FeaturesService', function(FeaturesService) { - return FeaturesService.get(); - }], - jobEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { - if (!$rootScope.event_socket) { - $rootScope.event_socket = Socket({ - scope: $rootScope, - endpoint: "job_events" - }); - $rootScope.event_socket.init(); - return true; - } else { - return true; - } - }] - } - }). - - state('adHocJobStdout', { - url: '/ad_hoc_commands/:id', - templateUrl: urlPrefix + 'partials/job_stdout_adhoc.html', - controller: JobStdoutController, - resolve: { - features: ['FeaturesService', function(FeaturesService) { - return FeaturesService.get(); - }], - adhocEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { - if (!$rootScope.adhoc_event_socket) { - $rootScope.adhoc_event_socket = Socket({ - scope: $rootScope, - endpoint: "ad_hoc_command_events" - }); - $rootScope.adhoc_event_socket.init(); - return true; - } else { - return true; - } - }] - } - }). - state('jobTemplates', { url: '/job_templates', templateUrl: urlPrefix + 'partials/job_templates.html', @@ -1062,6 +987,9 @@ var tower = angular.module('Tower', [ $rootScope.$emit('JobStatusChange-jobs', data); } else if (/\/jobs\/(\d)+\/stdout/.test(urlToCheck) || /\/ad_hoc_commands\/(\d)+/.test(urlToCheck)) { + + // TODO: something will need to change here for stdout + $log.debug("sending status to standard out"); $rootScope.$emit('JobStatusChange-jobStdout', data); } else if (/\/jobs\/(\d)+/.test(urlToCheck)) { diff --git a/awx/ui/client/src/controllers/JobDetail.js b/awx/ui/client/src/controllers/JobDetail.js deleted file mode 100644 index af399872f4..0000000000 --- a/awx/ui/client/src/controllers/JobDetail.js +++ /dev/null @@ -1,1442 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - -/** - * @ngdoc function - * @name controllers.function:JobDetail - * @description This controller's for the Job Detail Page -*/ - - -export function JobDetailController ($location, $rootScope, $filter, $scope, $compile, $stateParams, $log, ClearScope, GetBasePath, Wait, Rest, - ProcessErrors, SelectPlay, SelectTask, Socket, GetElapsed, DrawGraph, LoadHostSummary, ReloadHostSummaryList, JobIsFinished, SetTaskStyles, DigestEvent, - UpdateDOM, EventViewer, DeleteJob, PlaybookRun, HostEventsViewer, LoadPlays, LoadTasks, LoadHosts, HostsEdit, ParseVariableString, GetChoices, fieldChoices, fieldLabels, EditSchedule) { - - ClearScope(); - - var job_id = $stateParams.id, - scope = $scope, - api_complete = false, - refresh_count = 0, - lastEventId = 0, - verbosity_options, - job_type_options; - - scope.plays = []; - - scope.previousTaskFailed = false; - - scope.$watch('job_status', function(job_status) { - if (job_status && job_status.explanation && job_status.explanation.split(":")[0] === "Previous Task Failed") { - scope.previousTaskFailed = true; - var taskObj = JSON.parse(job_status.explanation.substring(job_status.explanation.split(":")[0].length + 1)); - // return a promise from the options request with the permission type choices (including adhoc) as a param - var fieldChoice = fieldChoices({ - scope: $scope, - url: 'api/v1/unified_jobs/', - field: 'type' - }); - - // manipulate the choices from the options request to be set on - // scope and be usable by the list form - fieldChoice.then(function (choices) { - choices = - fieldLabels({ - choices: choices - }); - scope.explanation_fail_type = choices[taskObj.job_type]; - scope.explanation_fail_name = taskObj.job_name; - scope.explanation_fail_id = taskObj.job_id; - scope.task_detail = scope.explanation_fail_type + " failed for " + scope.explanation_fail_name + " with ID " + scope.explanation_fail_id + "."; - }); - } else { - scope.previousTaskFailed = false; - } - }, true); - - scope.$watch('plays', function(plays) { - for (var play in plays) { - if (plays[play].elapsed) { - plays[play].finishedTip = "Play completed at " + $filter("longDate")(plays[play].finished) + "."; - } else { - plays[play].finishedTip = "Play not completed."; - } - } - }); - scope.hosts = []; - scope.$watch('hosts', function(hosts) { - for (var host in hosts) { - if (hosts[host].ok) { - hosts[host].okTip = hosts[host].ok; - hosts[host].okTip += (hosts[host].ok === 1) ? " host event was" : " host events were"; - hosts[host].okTip += " ok."; - } else { - hosts[host].okTip = "No host events were ok."; - } - if (hosts[host].changed) { - hosts[host].changedTip = hosts[host].changed; - hosts[host].changedTip += (hosts[host].changed === 1) ? " host event" : " host events"; - hosts[host].changedTip += " changed."; - } else { - hosts[host].changedTip = "No host events changed."; - } - if (hosts[host].failed) { - hosts[host].failedTip = hosts[host].failed; - hosts[host].failedTip += (hosts[host].failed === 1) ? " host event" : " host events"; - hosts[host].failedTip += " failed."; - } else { - hosts[host].failedTip = "No host events failed."; - } - if (hosts[host].unreachable) { - hosts[host].unreachableTip = hosts[host].unreachable; - hosts[host].unreachableTip += (hosts[host].unreachable === 1) ? " host event was" : " hosts events were"; - hosts[host].unreachableTip += " unreachable"; - } else { - hosts[host].unreachableTip = "No host events were unreachable."; - } - } - }); - scope.tasks = []; - scope.$watch('tasks', function(tasks) { - for (var task in tasks) { - if (tasks[task].elapsed) { - tasks[task].finishedTip = "Task completed at " + $filter("longDate")(tasks[task].finished) + "."; - } else { - tasks[task].finishedTip = "Task not completed."; - } - if (tasks[task].successfulCount) { - tasks[task].successfulCountTip = tasks[task].successfulCount; - tasks[task].successfulCountTip += (tasks[task].successfulCount === 1) ? " host event was" : " host events were"; - tasks[task].successfulCountTip += " ok."; - } else { - tasks[task].successfulCountTip = "No host events were ok."; - } - if (tasks[task].changedCount) { - tasks[task].changedCountTip = tasks[task].changedCount; - tasks[task].changedCountTip += (tasks[task].changedCount === 1) ? " host event" : " host events"; - tasks[task].changedCountTip += " changed."; - } else { - tasks[task].changedCountTip = "No host events changed."; - } - if (tasks[task].skippedCount) { - tasks[task].skippedCountTip = tasks[task].skippedCount; - tasks[task].skippedCountTip += (tasks[task].skippedCount === 1) ? " host event was" : " hosts events were"; - tasks[task].skippedCountTip += " skipped."; - } else { - tasks[task].skippedCountTip = "No host events were skipped."; - } - if (tasks[task].failedCount) { - tasks[task].failedCountTip = tasks[task].failedCount; - tasks[task].failedCountTip += (tasks[task].failedCount === 1) ? " host event" : " host events"; - tasks[task].failedCountTip += " failed."; - } else { - tasks[task].failedCountTip = "No host events failed."; - } - if (tasks[task].unreachableCount) { - tasks[task].unreachableCountTip = tasks[task].unreachableCount; - tasks[task].unreachableCountTip += (tasks[task].unreachableCount === 1) ? " host event was" : " hosts events were"; - tasks[task].unreachableCountTip += " unreachable."; - } else { - tasks[task].unreachableCountTip = "No host events were unreachable."; - } - if (tasks[task].missingCount) { - tasks[task].missingCountTip = tasks[task].missingCount; - tasks[task].missingCountTip += (tasks[task].missingCount === 1) ? " host event was" : " host events were"; - tasks[task].missingCountTip += " missing."; - } else { - tasks[task].missingCountTip = "No host events were missing."; - } - } - }); - scope.hostResults = []; - - scope.hostResultsMaxRows = 200; - scope.hostSummariesMaxRows = 200; - scope.tasksMaxRows = 200; - scope.playsMaxRows = 200; - - // Set the following to true when 'Loading...' message desired - scope.playsLoading = true; - scope.tasksLoading = true; - scope.hostResultsLoading = true; - scope.hostSummariesLoading = true; - - // Turn on the 'Waiting...' message until events begin arriving - scope.waiting = true; - - scope.liveEventProcessing = true; // true while job is active and live events are arriving - scope.pauseLiveEvents = false; // control play/pause state of event processing - - scope.job_status = {}; - scope.job_id = job_id; - scope.auto_scroll = false; - - scope.searchPlaysEnabled = true; - scope.searchTasksEnabled = true; - scope.searchHostsEnabled = true; - scope.searchHostSummaryEnabled = true; - scope.search_play_status = 'all'; - scope.search_task_status = 'all'; - scope.search_host_status = 'all'; - scope.search_host_summary_status = 'all'; - - scope.haltEventQueue = false; - scope.processing = false; - scope.lessStatus = true; - - scope.host_summary = {}; - scope.host_summary.ok = 0; - scope.host_summary.changed = 0; - scope.host_summary.unreachable = 0; - scope.host_summary.failed = 0; - scope.host_summary.total = 0; - - scope.jobData = {}; - scope.jobData.hostSummaries = {}; - - verbosity_options = [ - { value: 0, label: 'Default' }, - { value: 1, label: 'Verbose' }, - { value: 3, label: 'Debug' } - ]; - - job_type_options = [ - { value: 'run', label: 'Run' }, - { value: 'check', label: 'Check' } - ]; - - GetChoices({ - scope: scope, - url: GetBasePath('unified_jobs'), - field: 'status', - variable: 'status_choices', - // callback: 'choicesReady' - }); - - scope.eventsHelpText = "
Successful
\n" + - "Changed
\n" + - "Unreachable
\n" + - "Failed
\n"; - function openSocket() { - $rootScope.event_socket.on("job_events-" + job_id, function(data) { - if (api_complete && data.id > lastEventId) { - scope.waiting = false; - data.event = data.event_name; - DigestEvent({ scope: scope, event: data }); - } - }); - } - openSocket(); - - if ($rootScope.removeJobStatusChange) { - $rootScope.removeJobStatusChange(); - } - $rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange-jobDetails', function(e, data) { - // if we receive a status change event for the current job indicating the job - // is finished, stop event queue processing and reload - if (parseInt(data.unified_job_id, 10) === parseInt(job_id,10)) { - if (data.status === 'failed' || data.status === 'canceled' || - data.status === 'error' || data.status === 'successful' || data.status === 'running') { - $scope.liveEventProcessing = false; - if ($rootScope.jobDetailInterval) { - window.clearInterval($rootScope.jobDetailInterval); - } - if (!scope.pauseLiveEvents) { - $scope.$emit('LoadJob'); //this is what is used for the refresh - } - } - } - }); - - if ($rootScope.removeJobSummaryComplete) { - $rootScope.removeJobSummaryComplete(); - } - $rootScope.removeJobSummaryComplete = $rootScope.$on('JobSummaryComplete', function() { - // the job host summary should now be available from the API - $log.debug('Trigging reload of job_host_summaries'); - scope.$emit('LoadHostSummaries'); - }); - - - if (scope.removeInitialLoadComplete) { - scope.removeInitialLoadComplete(); - } - scope.removeInitialLoadComplete = scope.$on('InitialLoadComplete', function() { - var url; - Wait('stop'); - - if (JobIsFinished(scope)) { - scope.liveEventProcessing = false; // signal that event processing is over and endless scroll - scope.pauseLiveEvents = false; // should be enabled - url = scope.job.related.job_events + '?event=playbook_on_stats'; - Rest.setUrl(url); - Rest.get() - .success(function(data) { - if (data.results.length > 0) { - LoadHostSummary({ - scope: scope, - data: data.results[0].event_data - }); - } - UpdateDOM({ scope: scope }); - }) - .error(function(data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + '. GET returned: ' + status }); - }); - if ($rootScope.jobDetailInterval) { - window.clearInterval($rootScope.jobDetailInterval); - } - $log.debug('Job completed!'); - $log.debug(scope.jobData); - } - else { - api_complete = true; //trigger events to start processing - if ($rootScope.jobDetailInterval) { - window.clearInterval($rootScope.jobDetailInterval); - } - $rootScope.jobDetailInterval = setInterval(function() { - UpdateDOM({ scope: scope }); - }, 2000); - } - }); - - if (scope.removeLoadHostSummaries) { - scope.removeLoadHostSummaries(); - } - scope.removeHostSummaries = scope.$on('LoadHostSummaries', function() { - if(scope.job){ - var url = scope.job.related.job_host_summaries + '?'; - url += '&page_size=' + scope.hostSummariesMaxRows + '&order=host_name'; - - Rest.setUrl(url); - Rest.get() - .success(function(data) { - scope.next_host_summaries = data.next; - if (data.results.length > 0) { - // only dump what's in memory when job_host_summaries is available. - scope.jobData.hostSummaries = {}; - } - data.results.forEach(function(event) { - var name; - if (event.host_name) { - name = event.host_name; - } - else { - name = "Successful
\n" + + "Changed
\n" + + "Unreachable
\n" + + "Failed
\n"; + function openSocket() { + $rootScope.event_socket.on("job_events-" + job_id, function(data) { + if (api_complete && data.id > lastEventId) { + scope.waiting = false; + data.event = data.event_name; + DigestEvent({ scope: scope, event: data }); + } + }); + } + openSocket(); + + if ($rootScope.removeJobStatusChange) { + $rootScope.removeJobStatusChange(); + } + $rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange-jobDetails', function(e, data) { + // if we receive a status change event for the current job indicating the job + // is finished, stop event queue processing and reload + if (parseInt(data.unified_job_id, 10) === parseInt(job_id,10)) { + if (data.status === 'failed' || data.status === 'canceled' || + data.status === 'error' || data.status === 'successful' || data.status === 'running') { + $scope.liveEventProcessing = false; + if ($rootScope.jobDetailInterval) { + window.clearInterval($rootScope.jobDetailInterval); + } + if (!scope.pauseLiveEvents) { + $scope.$emit('LoadJob'); //this is what is used for the refresh + } + } + } + }); + + if ($rootScope.removeJobSummaryComplete) { + $rootScope.removeJobSummaryComplete(); + } + $rootScope.removeJobSummaryComplete = $rootScope.$on('JobSummaryComplete', function() { + // the job host summary should now be available from the API + $log.debug('Trigging reload of job_host_summaries'); + scope.$emit('LoadHostSummaries'); + }); + + + if (scope.removeInitialLoadComplete) { + scope.removeInitialLoadComplete(); + } + scope.removeInitialLoadComplete = scope.$on('InitialLoadComplete', function() { + var url; + Wait('stop'); + + if (JobIsFinished(scope)) { + scope.liveEventProcessing = false; // signal that event processing is over and endless scroll + scope.pauseLiveEvents = false; // should be enabled + url = scope.job.related.job_events + '?event=playbook_on_stats'; + Rest.setUrl(url); + Rest.get() + .success(function(data) { + if (data.results.length > 0) { + LoadHostSummary({ + scope: scope, + data: data.results[0].event_data + }); + } + UpdateDOM({ scope: scope }); + }) + .error(function(data, status) { + ProcessErrors(scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + '. GET returned: ' + status }); + }); + if ($rootScope.jobDetailInterval) { + window.clearInterval($rootScope.jobDetailInterval); + } + $log.debug('Job completed!'); + $log.debug(scope.jobData); + } + else { + api_complete = true; //trigger events to start processing + if ($rootScope.jobDetailInterval) { + window.clearInterval($rootScope.jobDetailInterval); + } + $rootScope.jobDetailInterval = setInterval(function() { + UpdateDOM({ scope: scope }); + }, 2000); + } + }); + + if (scope.removeLoadHostSummaries) { + scope.removeLoadHostSummaries(); + } + scope.removeHostSummaries = scope.$on('LoadHostSummaries', function() { + if(scope.job){ + var url = scope.job.related.job_host_summaries + '?'; + url += '&page_size=' + scope.hostSummariesMaxRows + '&order=host_name'; + + Rest.setUrl(url); + Rest.get() + .success(function(data) { + scope.next_host_summaries = data.next; + if (data.results.length > 0) { + // only dump what's in memory when job_host_summaries is available. + scope.jobData.hostSummaries = {}; + } + data.results.forEach(function(event) { + var name; + if (event.host_name) { + name = event.host_name; + } + else { + name = "