mirror of
https://github.com/ansible/awx.git
synced 2026-03-24 12:25:01 -02:30
Merge pull request #5968 from mabashian/jobs-list-sockets
Changes ui-side behavior in response to websocket job status updates on several lists Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
# Python
|
# Python
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
import datetime
|
||||||
import codecs
|
import codecs
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
@@ -1218,12 +1219,17 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
|
|||||||
status_data['instance_group_name'] = self.instance_group.name
|
status_data['instance_group_name'] = self.instance_group.name
|
||||||
else:
|
else:
|
||||||
status_data['instance_group_name'] = None
|
status_data['instance_group_name'] = None
|
||||||
|
elif status in ['successful', 'failed', 'canceled'] and self.finished:
|
||||||
|
status_data['finished'] = datetime.datetime.strftime(self.finished, "%Y-%m-%dT%H:%M:%S.%fZ")
|
||||||
status_data.update(self.websocket_emit_data())
|
status_data.update(self.websocket_emit_data())
|
||||||
status_data['group_name'] = 'jobs'
|
status_data['group_name'] = 'jobs'
|
||||||
|
if getattr(self, 'unified_job_template_id', None):
|
||||||
|
status_data['unified_job_template_id'] = self.unified_job_template_id
|
||||||
emit_channel_notification('jobs-status_changed', status_data)
|
emit_channel_notification('jobs-status_changed', status_data)
|
||||||
|
|
||||||
if self.spawned_by_workflow:
|
if self.spawned_by_workflow:
|
||||||
status_data['group_name'] = "workflow_events"
|
status_data['group_name'] = "workflow_events"
|
||||||
|
status_data['workflow_job_template_id'] = self.unified_job_template.id
|
||||||
emit_channel_notification('workflow_events-' + str(self.workflow_job_id), status_data)
|
emit_channel_notification('workflow_events-' + str(self.workflow_job_id), status_data)
|
||||||
except IOError: # includes socket errors
|
except IOError: # includes socket errors
|
||||||
logger.exception('%s failed to emit channel msg about status change', self.log_format)
|
logger.exception('%s failed to emit channel msg about status change', self.log_format)
|
||||||
|
|||||||
@@ -25,15 +25,15 @@ function ListJobsController (
|
|||||||
|
|
||||||
vm.strings = strings;
|
vm.strings = strings;
|
||||||
|
|
||||||
|
let newJobs = [];
|
||||||
|
|
||||||
// smart-search
|
// smart-search
|
||||||
const name = 'jobs';
|
const name = 'jobs';
|
||||||
const iterator = 'job';
|
const iterator = 'job';
|
||||||
let paginateQuerySet = {};
|
let paginateQuerySet = {};
|
||||||
|
|
||||||
let launchModalOpen = false;
|
let launchModalOpen = false;
|
||||||
let refreshAfterLaunchClose = false;
|
let newJobsTimerRunning = false;
|
||||||
let pendingRefresh = false;
|
|
||||||
let refreshTimerRunning = false;
|
|
||||||
|
|
||||||
vm.searchBasePath = SearchBasePath;
|
vm.searchBasePath = SearchBasePath;
|
||||||
|
|
||||||
@@ -104,23 +104,53 @@ function ListJobsController (
|
|||||||
$scope.$emit('updateCount', vm.job_dataset.count, 'jobs');
|
$scope.$emit('updateCount', vm.job_dataset.count, 'jobs');
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.$on('ws-jobs', () => {
|
const canAddRowsDynamically = () => {
|
||||||
if (!launchModalOpen) {
|
const orderByValue = _.get($state.params, 'job_search.order_by');
|
||||||
if (!refreshTimerRunning) {
|
const pageValue = _.get($state.params, 'job_search.page');
|
||||||
refreshJobs();
|
const idInValue = _.get($state.params, 'job_search.id__in');
|
||||||
} else {
|
|
||||||
pendingRefresh = true;
|
return (!idInValue && (!pageValue || pageValue === '1')
|
||||||
|
&& (orderByValue === '-finished' || orderByValue === '-started'));
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateJobRow = (msg) => {
|
||||||
|
// Loop across the jobs currently shown and update the row
|
||||||
|
// if it exists
|
||||||
|
for (let i = 0; i < vm.jobs.length; i++) {
|
||||||
|
if (vm.jobs[i].id === msg.unified_job_id) {
|
||||||
|
// Update the job status.
|
||||||
|
vm.jobs[i].status = msg.status;
|
||||||
|
if (msg.finished) {
|
||||||
|
vm.jobs[i].finished = msg.finished;
|
||||||
|
const orderByValue = _.get($state.params, 'job_search.order_by');
|
||||||
|
if (orderByValue === '-finished') {
|
||||||
|
// Attempt to sort the rows in the list by their finish
|
||||||
|
// timestamp in descending order
|
||||||
|
vm.jobs.sort((a, b) =>
|
||||||
|
(!b.finished) - (!a.finished)
|
||||||
|
|| new Date(b.finished) - new Date(a.finished));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
refreshAfterLaunchClose = true;
|
};
|
||||||
|
|
||||||
|
$scope.$on('ws-jobs', (e, msg) => {
|
||||||
|
if (msg.status === 'pending' && canAddRowsDynamically()) {
|
||||||
|
newJobs.push(msg.unified_job_id);
|
||||||
|
if (!launchModalOpen && !newJobsTimerRunning) {
|
||||||
|
fetchNewJobs();
|
||||||
|
}
|
||||||
|
} else if (!newJobs.includes(msg.unified_job_id)) {
|
||||||
|
updateJobRow(msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.$on('launchModalOpen', (evt, isOpen) => {
|
$scope.$on('launchModalOpen', (evt, isOpen) => {
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
if (!isOpen && refreshAfterLaunchClose) {
|
if (!isOpen && newJobs.length > 0) {
|
||||||
refreshAfterLaunchClose = false;
|
fetchNewJobs();
|
||||||
refreshJobs();
|
|
||||||
}
|
}
|
||||||
launchModalOpen = isOpen;
|
launchModalOpen = isOpen;
|
||||||
});
|
});
|
||||||
@@ -289,22 +319,49 @@ function ListJobsController (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function refreshJobs () {
|
const fetchNewJobs = () => {
|
||||||
qs.search(SearchBasePath, $state.params.job_search, { 'X-WS-Session-Quiet': true })
|
newJobsTimerRunning = true;
|
||||||
|
const newJobIdsFilter = newJobs.join(',');
|
||||||
|
newJobs = [];
|
||||||
|
const newJobsSearchParams = Object.assign({}, $state.params.job_search);
|
||||||
|
newJobsSearchParams.count_disabled = 1;
|
||||||
|
newJobsSearchParams.id__in = newJobIdsFilter;
|
||||||
|
delete newJobsSearchParams.page_size;
|
||||||
|
const stringifiedSearchParams = qs.encodeQueryset(newJobsSearchParams, false);
|
||||||
|
Rest.setUrl(`${vm.searchBasePath}${stringifiedSearchParams}`);
|
||||||
|
Rest.get()
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
vm.jobs = data.results;
|
vm.job_dataset.count += data.results.length;
|
||||||
vm.job_dataset = data;
|
const pageSize = parseInt($state.params.job_search.page_size, 10) || 20;
|
||||||
|
const joinedJobs = data.results.concat(vm.jobs);
|
||||||
|
vm.jobs = joinedJobs.length > pageSize
|
||||||
|
? joinedJobs.slice(0, pageSize)
|
||||||
|
: joinedJobs;
|
||||||
|
$timeout(() => {
|
||||||
|
if (canAddRowsDynamically()) {
|
||||||
|
if (newJobs.length > 0 && !launchModalOpen) {
|
||||||
|
fetchNewJobs();
|
||||||
|
} else {
|
||||||
|
newJobsTimerRunning = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Bail out - one of [order_by, page, id__in] params has changed since we
|
||||||
|
// received these new job messages
|
||||||
|
newJobs = [];
|
||||||
|
newJobsTimerRunning = false;
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
})
|
||||||
|
.catch(({ data, status }) => {
|
||||||
|
ProcessErrors($scope, data, status, null, {
|
||||||
|
hdr: strings.get('error.HEADER'),
|
||||||
|
msg: strings.get('error.CALL', {
|
||||||
|
path: `${vm.searchBasePath}${stringifiedSearchParams}`,
|
||||||
|
status
|
||||||
|
})
|
||||||
|
});
|
||||||
});
|
});
|
||||||
pendingRefresh = false;
|
};
|
||||||
refreshTimerRunning = true;
|
|
||||||
$timeout(() => {
|
|
||||||
if (pendingRefresh) {
|
|
||||||
refreshJobs();
|
|
||||||
} else {
|
|
||||||
refreshTimerRunning = false;
|
|
||||||
}
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
vm.isCollapsed = true;
|
vm.isCollapsed = true;
|
||||||
|
|
||||||
|
|||||||
@@ -113,11 +113,6 @@ function projectsListController (
|
|||||||
// And we found the affected project
|
// And we found the affected project
|
||||||
$log.debug(`Received event for project: ${project.name}`);
|
$log.debug(`Received event for project: ${project.name}`);
|
||||||
$log.debug(`Status changed to: ${data.status}`);
|
$log.debug(`Status changed to: ${data.status}`);
|
||||||
if (data.status === 'successful' || data.status === 'failed' || data.status === 'canceled') {
|
|
||||||
reloadList();
|
|
||||||
} else {
|
|
||||||
project.scm_update_tooltip = vm.strings.get('update.UPDATE_RUNNING');
|
|
||||||
}
|
|
||||||
project.status = data.status;
|
project.status = data.status;
|
||||||
buildTooltips(project);
|
buildTooltips(project);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ function ListTemplatesController(
|
|||||||
qs,
|
qs,
|
||||||
GetBasePath,
|
GetBasePath,
|
||||||
ngToast,
|
ngToast,
|
||||||
$timeout
|
|
||||||
) {
|
) {
|
||||||
const vm = this || {};
|
const vm = this || {};
|
||||||
const [jobTemplate, workflowTemplate] = resolvedModels;
|
const [jobTemplate, workflowTemplate] = resolvedModels;
|
||||||
@@ -32,10 +31,6 @@ function ListTemplatesController(
|
|||||||
const choices = workflowTemplate.options('actions.GET.type.choices')
|
const choices = workflowTemplate.options('actions.GET.type.choices')
|
||||||
.concat(jobTemplate.options('actions.GET.type.choices'));
|
.concat(jobTemplate.options('actions.GET.type.choices'));
|
||||||
|
|
||||||
let launchModalOpen = false;
|
|
||||||
let refreshAfterLaunchClose = false;
|
|
||||||
let pendingRefresh = false;
|
|
||||||
let refreshTimerRunning = false;
|
|
||||||
let paginateQuerySet = {};
|
let paginateQuerySet = {};
|
||||||
|
|
||||||
vm.strings = strings;
|
vm.strings = strings;
|
||||||
@@ -120,25 +115,39 @@ function ListTemplatesController(
|
|||||||
setToolbarSort();
|
setToolbarSort();
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
$scope.$on(`ws-jobs`, () => {
|
$scope.$on(`ws-jobs`, (e, msg) => {
|
||||||
if (!launchModalOpen) {
|
if (msg.unified_job_template_id && vm.templates) {
|
||||||
if (!refreshTimerRunning) {
|
const template = vm.templates.find((t) => t.id === msg.unified_job_template_id);
|
||||||
refreshTemplates();
|
if (template) {
|
||||||
} else {
|
if (msg.status === 'pending') {
|
||||||
pendingRefresh = true;
|
// This is a new job - add it to the front of the
|
||||||
}
|
// recent_jobs array
|
||||||
} else {
|
if (template.summary_fields.recent_jobs.length === 10) {
|
||||||
refreshAfterLaunchClose = true;
|
template.summary_fields.recent_jobs.pop();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
$scope.$on('launchModalOpen', (evt, isOpen) => {
|
template.summary_fields.recent_jobs.unshift({
|
||||||
evt.stopPropagation();
|
id: msg.unified_job_id,
|
||||||
if (!isOpen && refreshAfterLaunchClose) {
|
status: msg.status,
|
||||||
refreshAfterLaunchClose = false;
|
type: msg.type
|
||||||
refreshTemplates();
|
});
|
||||||
|
} else {
|
||||||
|
// This is an update to an existing job. Check to see
|
||||||
|
// if we have it in our array of recent_jobs
|
||||||
|
for (let i=0; i<template.summary_fields.recent_jobs.length; i++) {
|
||||||
|
const recentJob = template.summary_fields.recent_jobs[i];
|
||||||
|
if (recentJob.id === msg.unified_job_id) {
|
||||||
|
recentJob.status = msg.status;
|
||||||
|
if (msg.finished) {
|
||||||
|
recentJob.finished = msg.finished;
|
||||||
|
template.last_job_run = msg.finished;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
launchModalOpen = isOpen;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
vm.isInvalid = (template) => {
|
vm.isInvalid = (template) => {
|
||||||
@@ -265,15 +274,6 @@ function ListTemplatesController(
|
|||||||
vm.templates = vm.dataset.results;
|
vm.templates = vm.dataset.results;
|
||||||
})
|
})
|
||||||
.finally(() => Wait('stop'));
|
.finally(() => Wait('stop'));
|
||||||
pendingRefresh = false;
|
|
||||||
refreshTimerRunning = true;
|
|
||||||
$timeout(() => {
|
|
||||||
if (pendingRefresh) {
|
|
||||||
refreshTemplates();
|
|
||||||
} else {
|
|
||||||
refreshTimerRunning = false;
|
|
||||||
}
|
|
||||||
}, 5000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createErrorHandler(path, action) {
|
function createErrorHandler(path, action) {
|
||||||
@@ -483,8 +483,7 @@ ListTemplatesController.$inject = [
|
|||||||
'Wait',
|
'Wait',
|
||||||
'QuerySet',
|
'QuerySet',
|
||||||
'GetBasePath',
|
'GetBasePath',
|
||||||
'ngToast',
|
'ngToast'
|
||||||
'$timeout'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export default ListTemplatesController;
|
export default ListTemplatesController;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default
|
|||||||
templateUrl: templateUrl('home/dashboard/lists/job-templates/job-templates-list')
|
templateUrl: templateUrl('home/dashboard/lists/job-templates/job-templates-list')
|
||||||
};
|
};
|
||||||
|
|
||||||
function link(scope, element, attr) {
|
function link(scope) {
|
||||||
|
|
||||||
scope.$watch("data", function(data) {
|
scope.$watch("data", function(data) {
|
||||||
if (data) {
|
if (data) {
|
||||||
@@ -22,7 +22,7 @@ export default
|
|||||||
scope.noJobTemplates = true;
|
scope.noJobTemplates = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}, true);
|
||||||
|
|
||||||
scope.canAddJobTemplate = false;
|
scope.canAddJobTemplate = false;
|
||||||
let url = GetBasePath('job_templates');
|
let url = GetBasePath('job_templates');
|
||||||
|
|||||||
@@ -12,18 +12,152 @@ export default ['$scope','Wait', '$timeout', 'i18n',
|
|||||||
var dataCount = 0;
|
var dataCount = 0;
|
||||||
let launchModalOpen = false;
|
let launchModalOpen = false;
|
||||||
let refreshAfterLaunchClose = false;
|
let refreshAfterLaunchClose = false;
|
||||||
let pendingRefresh = false;
|
let pendingDashboardRefresh = false;
|
||||||
let refreshTimerRunning = false;
|
let dashboardTimerRunning = false;
|
||||||
|
let newJobsTimerRunning = false;
|
||||||
|
let newTemplatesTimerRunning = false;
|
||||||
|
let newJobs = [];
|
||||||
|
let newTemplates =[];
|
||||||
|
|
||||||
$scope.$on('ws-jobs', function () {
|
const fetchDashboardData = () => {
|
||||||
if (!launchModalOpen) {
|
Rest.setUrl(GetBasePath('dashboard'));
|
||||||
if (!refreshTimerRunning) {
|
Rest.get()
|
||||||
refreshLists();
|
.then(({data}) => {
|
||||||
|
$scope.dashboardData = data;
|
||||||
|
})
|
||||||
|
.catch(({data, status}) => {
|
||||||
|
ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), msg: i18n._(`Failed to get dashboard host graph data: ${status}`) });
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($scope.graphData) {
|
||||||
|
Rest.setUrl(`${GetBasePath('dashboard')}graphs/jobs/?period=${$scope.graphData.period}&job_type=${$scope.graphData.jobType}`);
|
||||||
|
Rest.setHeader({'X-WS-Session-Quiet': true});
|
||||||
|
Rest.get()
|
||||||
|
.then(function(value) {
|
||||||
|
if($scope.graphData.status === "successful" || $scope.graphData.status === "failed"){
|
||||||
|
delete value.data.jobs[$scope.graphData.status];
|
||||||
|
}
|
||||||
|
$scope.graphData.jobStatus = value.data;
|
||||||
|
})
|
||||||
|
.catch(function({data, status}) {
|
||||||
|
ProcessErrors(null, data, status, null, { hdr: i18n._('Error!'), msg: i18n._(`Failed to get dashboard graph data: ${status}`)});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingDashboardRefresh = false;
|
||||||
|
dashboardTimerRunning = true;
|
||||||
|
$timeout(() => {
|
||||||
|
if (pendingDashboardRefresh) {
|
||||||
|
fetchDashboardData();
|
||||||
} else {
|
} else {
|
||||||
pendingRefresh = true;
|
dashboardTimerRunning = false;
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchNewJobs = () => {
|
||||||
|
newJobsTimerRunning = true;
|
||||||
|
const newJobIdsFilter = newJobs.join(',');
|
||||||
|
newJobs = [];
|
||||||
|
Rest.setUrl(`${GetBasePath("unified_jobs")}?id__in=${newJobIdsFilter}&order_by=-finished&finished__isnull=false&type=workflow_job,job&count_disabled=1`);
|
||||||
|
Rest.get()
|
||||||
|
.then(({ data }) => {
|
||||||
|
const joinedJobs = data.results.concat($scope.dashboardJobsListData);
|
||||||
|
$scope.dashboardJobsListData =
|
||||||
|
joinedJobs.length > 5 ? joinedJobs.slice(0, 5) : joinedJobs;
|
||||||
|
$timeout(() => {
|
||||||
|
if (newJobs.length > 0) {
|
||||||
|
fetchNewJobs();
|
||||||
|
} else {
|
||||||
|
newJobsTimerRunning = false;
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
})
|
||||||
|
.catch(({ data, status }) => {
|
||||||
|
ProcessErrors($scope, data, status, null, {
|
||||||
|
hdr: i18n._('Error!'),
|
||||||
|
msg: i18n._(`Failed to get new jobs for dashboard: ${status}`)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchNewTemplates = () => {
|
||||||
|
newTemplatesTimerRunning = true;
|
||||||
|
const newTemplateIdsFilter = newTemplates.join(',');
|
||||||
|
newTemplates = [];
|
||||||
|
Rest.setUrl(`${GetBasePath("unified_job_templates")}?id__in=${newTemplateIdsFilter}&order_by=-last_job_run&last_job_run__isnull=false&type=workflow_job_template,job_template&count_disabled=1"`);
|
||||||
|
Rest.get()
|
||||||
|
.then(({ data }) => {
|
||||||
|
const joinedTemplates = data.results.concat($scope.dashboardJobTemplatesListData).sort((a, b) => new Date(b.last_job_run) - new Date(a.last_job_run));
|
||||||
|
$scope.dashboardJobTemplatesListData =
|
||||||
|
joinedTemplates.length > 5 ? joinedTemplates.slice(0, 5) : joinedTemplates;
|
||||||
|
$timeout(() => {
|
||||||
|
if (newTemplates.length > 0 && !launchModalOpen) {
|
||||||
|
fetchNewTemplates();
|
||||||
|
} else {
|
||||||
|
newTemplatesTimerRunning = false;
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
})
|
||||||
|
.catch(({ data, status }) => {
|
||||||
|
ProcessErrors($scope, data, status, null, {
|
||||||
|
hdr: i18n._('Error!'),
|
||||||
|
msg: i18n._(`Failed to get new templates for dashboard: ${status}`)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.$on('ws-jobs', function (e, msg) {
|
||||||
|
if (msg.status === 'successful' || msg.status === 'failed' || msg.status === 'canceled' || msg.status === 'error') {
|
||||||
|
newJobs.push(msg.unified_job_id);
|
||||||
|
if (!newJobsTimerRunning) {
|
||||||
|
fetchNewJobs();
|
||||||
|
}
|
||||||
|
if (!launchModalOpen) {
|
||||||
|
if (!dashboardTimerRunning) {
|
||||||
|
fetchDashboardData();
|
||||||
|
} else {
|
||||||
|
pendingDashboardRefresh = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
refreshAfterLaunchClose = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const template = $scope.dashboardJobTemplatesListData.find((t) => t.id === msg.unified_job_template_id);
|
||||||
|
if (template) {
|
||||||
|
if (msg.status === 'pending') {
|
||||||
|
if (template.summary_fields.recent_jobs.length === 10) {
|
||||||
|
template.summary_fields.recent_jobs.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
template.summary_fields.recent_jobs.unshift({
|
||||||
|
id: msg.unified_job_id,
|
||||||
|
status: msg.status,
|
||||||
|
type: msg.type
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
for (let i=0; i<template.summary_fields.recent_jobs.length; i++) {
|
||||||
|
const recentJob = template.summary_fields.recent_jobs[i];
|
||||||
|
if (recentJob.id === msg.unified_job_id) {
|
||||||
|
recentJob.status = msg.status;
|
||||||
|
if (msg.finished) {
|
||||||
|
recentJob.finished = msg.finished;
|
||||||
|
template.last_job_run = msg.finished;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.status === 'successful' || msg.status === 'failed' || msg.status === 'canceled') {
|
||||||
|
$scope.dashboardJobTemplatesListData.sort((a, b) => new Date(b.last_job_run) - new Date(a.last_job_run));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
refreshAfterLaunchClose = true;
|
newTemplates.push(msg.unified_job_template_id);
|
||||||
|
if (!launchModalOpen && !newTemplatesTimerRunning) {
|
||||||
|
fetchNewTemplates();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -31,7 +165,10 @@ export default ['$scope','Wait', '$timeout', 'i18n',
|
|||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
if (!isOpen && refreshAfterLaunchClose) {
|
if (!isOpen && refreshAfterLaunchClose) {
|
||||||
refreshAfterLaunchClose = false;
|
refreshAfterLaunchClose = false;
|
||||||
refreshLists();
|
fetchDashboardData();
|
||||||
|
if (newTemplates.length > 0) {
|
||||||
|
fetchNewTemplates();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
launchModalOpen = isOpen;
|
launchModalOpen = isOpen;
|
||||||
});
|
});
|
||||||
@@ -75,61 +212,6 @@ export default ['$scope','Wait', '$timeout', 'i18n',
|
|||||||
$scope.$emit('dashboardDataLoadComplete');
|
$scope.$emit('dashboardDataLoadComplete');
|
||||||
});
|
});
|
||||||
|
|
||||||
function refreshLists () {
|
|
||||||
Rest.setUrl(GetBasePath('dashboard'));
|
|
||||||
Rest.get()
|
|
||||||
.then(({data}) => {
|
|
||||||
$scope.dashboardData = data;
|
|
||||||
})
|
|
||||||
.catch(({data, status}) => {
|
|
||||||
ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), msg: i18n._(`Failed to get dashboard host graph data: ${status}`) });
|
|
||||||
});
|
|
||||||
|
|
||||||
Rest.setUrl(GetBasePath("unified_jobs") + "?order_by=-finished&page_size=5&finished__isnull=false&type=workflow_job,job&count_disabled=1");
|
|
||||||
Rest.setHeader({'X-WS-Session-Quiet': true});
|
|
||||||
Rest.get()
|
|
||||||
.then(({data}) => {
|
|
||||||
$scope.dashboardJobsListData = data.results;
|
|
||||||
})
|
|
||||||
.catch(({data, status}) => {
|
|
||||||
ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), msg: i18n._(`Failed to get dashboard jobs list: ${status}`) });
|
|
||||||
});
|
|
||||||
|
|
||||||
Rest.setUrl(GetBasePath("unified_job_templates") + "?order_by=-last_job_run&page_size=5&last_job_run__isnull=false&type=workflow_job_template,job_template&count_disabled=1");
|
|
||||||
Rest.get()
|
|
||||||
.then(({data}) => {
|
|
||||||
$scope.dashboardJobTemplatesListData = data.results;
|
|
||||||
})
|
|
||||||
.catch(({data, status}) => {
|
|
||||||
ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), msg: i18n._(`Failed to get dashboard jobs list: ${status}`) });
|
|
||||||
});
|
|
||||||
|
|
||||||
if ($scope.graphData) {
|
|
||||||
Rest.setUrl(`${GetBasePath('dashboard')}graphs/jobs/?period=${$scope.graphData.period}&job_type=${$scope.graphData.jobType}`);
|
|
||||||
Rest.setHeader({'X-WS-Session-Quiet': true});
|
|
||||||
Rest.get()
|
|
||||||
.then(function(value) {
|
|
||||||
if($scope.graphData.status === "successful" || $scope.graphData.status === "failed"){
|
|
||||||
delete value.data.jobs[$scope.graphData.status];
|
|
||||||
}
|
|
||||||
$scope.graphData.jobStatus = value.data;
|
|
||||||
})
|
|
||||||
.catch(function({data, status}) {
|
|
||||||
ProcessErrors(null, data, status, null, { hdr: i18n._('Error!'), msg: i18n._(`Failed to get dashboard graph data: ${status}`)});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pendingRefresh = false;
|
|
||||||
refreshTimerRunning = true;
|
|
||||||
$timeout(() => {
|
|
||||||
if (pendingRefresh) {
|
|
||||||
refreshLists();
|
|
||||||
} else {
|
|
||||||
refreshTimerRunning = false;
|
|
||||||
}
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
Wait('start');
|
Wait('start');
|
||||||
Rest.setUrl(GetBasePath('dashboard'));
|
Rest.setUrl(GetBasePath('dashboard'));
|
||||||
Rest.get()
|
Rest.get()
|
||||||
|
|||||||
@@ -42,21 +42,7 @@
|
|||||||
$scope.$on(`ws-jobs`, function(e, data){
|
$scope.$on(`ws-jobs`, function(e, data){
|
||||||
inventory_source = Find({ list: $scope.inventory_sources, key: 'id', val: data.inventory_source_id });
|
inventory_source = Find({ list: $scope.inventory_sources, key: 'id', val: data.inventory_source_id });
|
||||||
|
|
||||||
if (inventory_source === undefined || inventory_source === null) {
|
if (inventory_source) {
|
||||||
inventory_source = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if(data.status === 'failed' || data.status === 'successful'){
|
|
||||||
let path = GetBasePath('inventory') + $stateParams.inventory_id + '/inventory_sources';
|
|
||||||
|
|
||||||
qs.search(path, $state.params[`${list.iterator}_search`])
|
|
||||||
.then((searchResponse)=> {
|
|
||||||
$scope[`${list.iterator}_dataset`] = searchResponse.data;
|
|
||||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
|
||||||
_.forEach($scope[list.name], buildStatusIndicators);
|
|
||||||
optionsRequestDataProcessing();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
var status = GetSyncStatusMsg({
|
var status = GetSyncStatusMsg({
|
||||||
status: data.status
|
status: data.status
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,25 +4,45 @@
|
|||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
export default ['$scope', '$rootScope',
|
export default ['$scope', '$stateParams', 'Rest', 'GetBasePath', '$state', 'OrgJobTemplateList', 'OrgJobTemplateDataset',
|
||||||
'$stateParams', 'Rest', 'ProcessErrors',
|
function($scope, $stateParams, Rest, GetBasePath, $state, OrgJobTemplateList, Dataset) {
|
||||||
'GetBasePath', 'Wait',
|
|
||||||
'$state', 'OrgJobTemplateList', 'OrgJobTemplateDataset', 'QuerySet',
|
|
||||||
function($scope, $rootScope,
|
|
||||||
$stateParams, Rest, ProcessErrors,
|
|
||||||
GetBasePath, Wait,
|
|
||||||
$state, OrgJobTemplateList, Dataset, qs) {
|
|
||||||
|
|
||||||
var list = OrgJobTemplateList,
|
var list = OrgJobTemplateList,
|
||||||
orgBase = GetBasePath('organizations');
|
orgBase = GetBasePath('organizations');
|
||||||
|
|
||||||
$scope.$on(`ws-jobs`, function () {
|
$scope.$on(`ws-jobs`, function (e, msg) {
|
||||||
let path = GetBasePath(list.basePath) || GetBasePath(list.name);
|
if (msg.unified_job_template_id && $scope[list.name]) {
|
||||||
qs.search(path, $state.params[`${list.iterator}_search`])
|
const template = $scope[list.name].find((t) => t.id === msg.unified_job_template_id);
|
||||||
.then(function(searchResponse) {
|
if (template) {
|
||||||
$scope[`${list.iterator}_dataset`] = searchResponse.data;
|
if (msg.status === 'pending') {
|
||||||
$scope[list.name] = $scope[`${list.iterator}_dataset`].results;
|
// This is a new job - add it to the front of the
|
||||||
});
|
// recent_jobs array
|
||||||
|
if (template.summary_fields.recent_jobs.length === 10) {
|
||||||
|
template.summary_fields.recent_jobs.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
template.summary_fields.recent_jobs.unshift({
|
||||||
|
id: msg.unified_job_id,
|
||||||
|
status: msg.status,
|
||||||
|
type: msg.type
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// This is an update to an existing job. Check to see
|
||||||
|
// if we have it in our array of recent_jobs
|
||||||
|
for (let i=0; i<template.summary_fields.recent_jobs.length; i++) {
|
||||||
|
const recentJob = template.summary_fields.recent_jobs[i];
|
||||||
|
if (recentJob.id === msg.unified_job_id) {
|
||||||
|
recentJob.status = msg.status;
|
||||||
|
if (msg.finished) {
|
||||||
|
recentJob.finished = msg.finished;
|
||||||
|
template.last_job_run = msg.finished;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|||||||
@@ -90,9 +90,9 @@ export default ['$scope', '$filter', 'i18n', 'JobsStrings',
|
|||||||
$scope.sparkArray = sparkData;
|
$scope.sparkArray = sparkData;
|
||||||
$scope.placeholders = new Array(10 - sparkData.length);
|
$scope.placeholders = new Array(10 - sparkData.length);
|
||||||
}
|
}
|
||||||
$scope.$watchCollection('jobs', function(){
|
$scope.$watch('jobs', function(){
|
||||||
init();
|
init();
|
||||||
});
|
}, true);
|
||||||
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user