mirror of
https://github.com/ansible/awx.git
synced 2026-05-09 18:37:36 -02:30
Merge branch 'devel' of github.com:ansible/ansible-tower into 11th-hour
This commit is contained in:
@@ -503,7 +503,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#graph-section svg{
|
#graph-section svg{
|
||||||
margin-top: 15px;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
path.slice{
|
path.slice{
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ export default
|
|||||||
angular.module('JobDetailHelper', ['Utilities', 'RestServices', 'ModalDialog'])
|
angular.module('JobDetailHelper', ['Utilities', 'RestServices', 'ModalDialog'])
|
||||||
|
|
||||||
.factory('DigestEvent', ['$rootScope', '$log', 'UpdatePlayStatus', 'UpdateHostStatus', 'AddHostResult',
|
.factory('DigestEvent', ['$rootScope', '$log', 'UpdatePlayStatus', 'UpdateHostStatus', 'AddHostResult',
|
||||||
'GetElapsed', 'UpdateTaskStatus', 'DrawGraph', 'LoadHostSummary', 'JobIsFinished', 'AddNewTask', 'AddNewPlay',
|
'GetElapsed', 'UpdateTaskStatus', 'JobIsFinished', 'AddNewTask', 'AddNewPlay',
|
||||||
function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, GetElapsed,
|
function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, GetElapsed,
|
||||||
UpdateTaskStatus, DrawGraph, LoadHostSummary, JobIsFinished, AddNewTask, AddNewPlay) {
|
UpdateTaskStatus, JobIsFinished, AddNewTask, AddNewPlay, longDateFilter) {
|
||||||
return function(params) {
|
return function(params) {
|
||||||
|
|
||||||
var scope = params.scope,
|
var scope = params.scope,
|
||||||
@@ -185,7 +185,7 @@ export default
|
|||||||
};
|
};
|
||||||
}])
|
}])
|
||||||
|
|
||||||
.factory('GetElapsed', [ function() {
|
.factory('GetElapsed', [function() {
|
||||||
return function(params) {
|
return function(params) {
|
||||||
var start = params.start,
|
var start = params.start,
|
||||||
end = params.end,
|
end = params.end,
|
||||||
@@ -299,7 +299,7 @@ export default
|
|||||||
};
|
};
|
||||||
}])
|
}])
|
||||||
|
|
||||||
.factory('AddNewTask', ['DrawGraph', 'UpdatePlayStatus', 'SetActivePlay', 'SetActiveTask', function(DrawGraph, UpdatePlayStatus, SetActivePlay, SetActiveTask) {
|
.factory('AddNewTask', ['UpdatePlayStatus', 'SetActivePlay', 'SetActiveTask', function(UpdatePlayStatus, SetActivePlay, SetActiveTask) {
|
||||||
return function(params) {
|
return function(params) {
|
||||||
var scope = params.scope,
|
var scope = params.scope,
|
||||||
event = params.event,
|
event = params.event,
|
||||||
@@ -363,15 +363,15 @@ export default
|
|||||||
scope.job_status.status = 'failed';
|
scope.job_status.status = 'failed';
|
||||||
}
|
}
|
||||||
if (JobIsFinished(scope) && !Empty(modified)) {
|
if (JobIsFinished(scope) && !Empty(modified)) {
|
||||||
scope.job_status.finished = modified;
|
scope.job_status.finished = longDateFilter(modified)
|
||||||
}
|
}
|
||||||
if (!Empty(started) && Empty(scope.job_status.started)) {
|
if (!Empty(started) && Empty(scope.job_status.started)) {
|
||||||
scope.job_status.started = started;
|
scope.job_status.started = longDateFilter(modified)
|
||||||
}
|
}
|
||||||
if (!Empty(scope.job_status.finished) && !Empty(scope.job_status.started)) {
|
if (!Empty(scope.job_status.finished) && !Empty(scope.job_status.started)) {
|
||||||
scope.job_status.elapsed = GetElapsed({
|
scope.job_status.elapsed = GetElapsed({
|
||||||
start: scope.job_status.started,
|
start: started,
|
||||||
end: scope.job_status.finished
|
end: finished
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -488,15 +488,6 @@ export default
|
|||||||
counter = params.counter,
|
counter = params.counter,
|
||||||
h, host;
|
h, host;
|
||||||
|
|
||||||
/*
|
|
||||||
scope.host_summary.ok += (status === 'successful') ? 1 : 0;
|
|
||||||
scope.host_summary.changed += (status === 'changed') ? 1 : 0;
|
|
||||||
scope.host_summary.unreachable += (status === 'unreachable') ? 1 : 0;
|
|
||||||
scope.host_summary.failed += (status === 'failed') ? 1 : 0;
|
|
||||||
scope.host_summary.total = scope.host_summary.ok + scope.host_summary.changed + scope.host_summary.unreachable +
|
|
||||||
scope.host_summary.failed;
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (scope.jobData.hostSummaries[host_id] !== undefined) {
|
if (scope.jobData.hostSummaries[host_id] !== undefined) {
|
||||||
scope.jobData.hostSummaries[host_id].ok += (status === 'successful') ? 1 : 0;
|
scope.jobData.hostSummaries[host_id].ok += (status === 'successful') ? 1 : 0;
|
||||||
scope.jobData.hostSummaries[host_id].changed += (status === 'changed') ? 1 : 0;
|
scope.jobData.hostSummaries[host_id].changed += (status === 'changed') ? 1 : 0;
|
||||||
@@ -517,29 +508,6 @@ export default
|
|||||||
status: (status === 'failed' || status === 'unreachable') ? 'failed' : 'successful'
|
status: (status === 'failed' || status === 'unreachable') ? 'failed' : 'successful'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.host_summary.ok = 0;
|
|
||||||
scope.host_summary.changed = 0;
|
|
||||||
scope.host_summary.unreachable = 0;
|
|
||||||
scope.host_summary.failed = 0;
|
|
||||||
for (h in scope.jobData.hostSummaries) {
|
|
||||||
host = scope.jobData.hostSummaries[h];
|
|
||||||
if (host.ok > 0 && host.failed === 0 && host.unreachable === 0 && host.changed === 0) {
|
|
||||||
scope.host_summary.ok++;
|
|
||||||
}
|
|
||||||
if (host.changed > 0 && host.failed === 0 && host.unreachable === 0) {
|
|
||||||
scope.host_summary.changed++;
|
|
||||||
}
|
|
||||||
if (host.failed > 0) {
|
|
||||||
scope.host_summary.failed++;
|
|
||||||
}
|
|
||||||
if (host.unreachable > 0) {
|
|
||||||
scope.host_summary.unreachable++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scope.host_summary.total = scope.host_summary.ok + scope.host_summary.changed + scope.host_summary.unreachable +
|
|
||||||
scope.host_summary.failed;
|
|
||||||
|
|
||||||
UpdateTaskStatus({
|
UpdateTaskStatus({
|
||||||
scope: scope,
|
scope: scope,
|
||||||
task_id: task_id,
|
task_id: task_id,
|
||||||
@@ -822,7 +790,6 @@ export default
|
|||||||
url += (scope.search_task_name) ? '&task__icontains=' + scope.search_task_name : '';
|
url += (scope.search_task_name) ? '&task__icontains=' + scope.search_task_name : '';
|
||||||
url += (scope.search_task_status === 'failed') ? '&failed=true' : '';
|
url += (scope.search_task_status === 'failed') ? '&failed=true' : '';
|
||||||
url += '&page_size=' + scope.tasksMaxRows + '&order=id';
|
url += '&page_size=' + scope.tasksMaxRows + '&order=id';
|
||||||
|
|
||||||
scope.plays.every(function(p, idx) {
|
scope.plays.every(function(p, idx) {
|
||||||
if (p.id === scope.selectedPlay) {
|
if (p.id === scope.selectedPlay) {
|
||||||
play = scope.plays[idx];
|
play = scope.plays[idx];
|
||||||
@@ -931,7 +898,7 @@ export default
|
|||||||
}])
|
}])
|
||||||
|
|
||||||
// Call when the selected task needs to change
|
// Call when the selected task needs to change
|
||||||
.factory('SelectTask', ['LoadHosts', function(LoadHosts) {
|
.factory('SelectTask', ['JobDetailService', function(JobDetailService) {
|
||||||
return function(params) {
|
return function(params) {
|
||||||
var scope = params.scope,
|
var scope = params.scope,
|
||||||
id = params.id,
|
id = params.id,
|
||||||
@@ -946,239 +913,52 @@ export default
|
|||||||
scope.tasks[idx].taskActiveClass = '';
|
scope.tasks[idx].taskActiveClass = '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
var params = {
|
||||||
LoadHosts({
|
parent: scope.selectedTask,
|
||||||
scope: scope,
|
event__startswith: 'runner',
|
||||||
callback: callback,
|
page_size: scope.hostResultsMaxRows,
|
||||||
clear: true
|
order: 'host_name,counter',
|
||||||
|
};
|
||||||
|
JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){
|
||||||
|
scope.hostResults = JobDetailService.processHostEvents(res.results)
|
||||||
|
scope.hostResultsLoading = false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}])
|
}])
|
||||||
|
|
||||||
// Refresh the list of hosts
|
|
||||||
.factory('LoadHosts', ['Rest', 'ProcessErrors', function(Rest, ProcessErrors) {
|
|
||||||
return function(params) {
|
|
||||||
var scope = params.scope,
|
|
||||||
callback = params.callback,
|
|
||||||
url;
|
|
||||||
|
|
||||||
scope.hostResults = [];
|
|
||||||
|
|
||||||
if (scope.selectedTask) {
|
|
||||||
// If we have a selected task, then get the list of hosts
|
|
||||||
url = scope.job.related.job_events + '?parent=' + scope.selectedTask + '&';
|
|
||||||
url += (scope.search_host_name) ? 'host__name__icontains=' + scope.search_host_name + '&' : '';
|
|
||||||
url += (scope.search_host_status === 'failed') ? 'failed=true&' : '';
|
|
||||||
url += 'event__startswith=runner&page_size=' + scope.hostResultsMaxRows + '&order=host_name,counter';
|
|
||||||
scope.hostResultsLoading = true;
|
|
||||||
Rest.setUrl(url);
|
|
||||||
Rest.get()
|
|
||||||
.success(function(data) {
|
|
||||||
scope.next_host_results = data.next;
|
|
||||||
scope.hostResults = [];
|
|
||||||
data.results.forEach(function(event) {
|
|
||||||
var status, status_text, item, msg;
|
|
||||||
if (event.event === "runner_on_skipped") {
|
|
||||||
status = 'skipped';
|
|
||||||
}
|
|
||||||
else if (event.event === "runner_on_unreachable") {
|
|
||||||
status = 'unreachable';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful';
|
|
||||||
}
|
|
||||||
switch(status) {
|
|
||||||
case "successful":
|
|
||||||
status_text = 'OK';
|
|
||||||
break;
|
|
||||||
case "changed":
|
|
||||||
status_text = "Changed";
|
|
||||||
break;
|
|
||||||
case "failed":
|
|
||||||
status_text = "Failed";
|
|
||||||
break;
|
|
||||||
case "unreachable":
|
|
||||||
status_text = "Unreachable";
|
|
||||||
break;
|
|
||||||
case "skipped":
|
|
||||||
status_text = "Skipped";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.event_data && event.event_data.res) {
|
|
||||||
item = event.event_data.res.item;
|
|
||||||
if (typeof item === "object") {
|
|
||||||
item = JSON.stringify(item);
|
|
||||||
item = item.replace(/\"/g,'').replace(/:/g,': ').replace(/,/g,', ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = '';
|
|
||||||
if (event.event_data && event.event_data.res) {
|
|
||||||
if (typeof event.event_data.res === 'object') {
|
|
||||||
msg = event.event_data.res.msg;
|
|
||||||
} else {
|
|
||||||
msg = event.event_data.res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.event !== "runner_on_no_hosts") {
|
|
||||||
scope.hostResults.push({
|
|
||||||
id: event.id,
|
|
||||||
status: status,
|
|
||||||
status_text: status_text,
|
|
||||||
host_id: event.host,
|
|
||||||
task_id: event.parent,
|
|
||||||
name: event.event_data.host,
|
|
||||||
created: event.created,
|
|
||||||
msg: msg,
|
|
||||||
item: item
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
scope.hostResultsLoading = false;
|
|
||||||
|
|
||||||
if (callback) {
|
|
||||||
scope.$emit(callback);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.error(function(data, status) {
|
|
||||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
|
||||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (callback) {
|
|
||||||
scope.$emit(callback);
|
|
||||||
}
|
|
||||||
//$('#hosts-table-detail').mCustomScrollbar("update");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
|
|
||||||
// Refresh the list of hosts in the hosts summary section
|
|
||||||
.factory('ReloadHostSummaryList', ['Rest', 'ProcessErrors', function(Rest, ProcessErrors) {
|
|
||||||
return function(params) {
|
|
||||||
var scope = params.scope,
|
|
||||||
callback = params.callback,
|
|
||||||
url;
|
|
||||||
|
|
||||||
url = scope.job.related.job_host_summaries + '?';
|
|
||||||
url += (scope.search_host_summary_name) ? 'host_name__icontains=' + scope.search_host_summary_name + '&': '';
|
|
||||||
url += (scope.search_host_summary_status === 'failed') ? 'failed=true&' : '';
|
|
||||||
url += '&page_size=' + scope.hostSummariesMaxRows + '&order=host_name';
|
|
||||||
|
|
||||||
scope.hosts = [];
|
|
||||||
scope.hostSummariesLoading = true;
|
|
||||||
|
|
||||||
Rest.setUrl(url);
|
|
||||||
Rest.get()
|
|
||||||
.success(function(data) {
|
|
||||||
scope.next_host_summaries = data.next;
|
|
||||||
scope.hosts = [];
|
|
||||||
data.results.forEach(function(event) {
|
|
||||||
var name;
|
|
||||||
if (event.host_name) {
|
|
||||||
name = event.host_name;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
name = "<deleted host>";
|
|
||||||
}
|
|
||||||
scope.hosts.push({
|
|
||||||
id: name,
|
|
||||||
name: event.host_name,
|
|
||||||
ok: event.ok,
|
|
||||||
changed: event.changed,
|
|
||||||
unreachable: event.dark,
|
|
||||||
failed: event.failures,
|
|
||||||
status: (event.failed) ? 'failed' : 'successful'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
scope.hostSummariesLoading = false;
|
|
||||||
|
|
||||||
if (callback) {
|
|
||||||
scope.$emit(callback);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.error(function(data, status) {
|
|
||||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
|
||||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
|
|
||||||
.factory('LoadHostSummary', [ function() {
|
|
||||||
return function(params) {
|
|
||||||
var scope = params.scope,
|
|
||||||
data = params.data,
|
|
||||||
host;
|
|
||||||
scope.host_summary.ok = 0;
|
|
||||||
for (host in data.ok) {
|
|
||||||
if (!data.changed[host] && !data.dark[host] && !data.failures[host]) {
|
|
||||||
scope.host_summary.ok += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scope.host_summary.changed = 0;
|
|
||||||
for (host in data.changed) {
|
|
||||||
if (!data.dark[host] && !data.failures[host]) {
|
|
||||||
scope.host_summary.changed += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scope.host_summary.unreachable = 0;
|
|
||||||
for (host in data.dark) {
|
|
||||||
scope.host_summary.unreachable += 1;
|
|
||||||
}
|
|
||||||
scope.host_summary.failed = 0;
|
|
||||||
for (host in data.failures) {
|
|
||||||
scope.host_summary.failed += 1;
|
|
||||||
}
|
|
||||||
scope.host_summary.total = scope.host_summary.ok + scope.host_summary.changed +
|
|
||||||
scope.host_summary.unreachable + scope.host_summary.failed;
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
|
|
||||||
|
|
||||||
.factory('DrawGraph', ['DonutChart', function(DonutChart) {
|
.factory('DrawGraph', ['DonutChart', function(DonutChart) {
|
||||||
return function(params) {
|
return function(params) {
|
||||||
var scope = params.scope,
|
var count = params.count,
|
||||||
graph_data = [];
|
graph_data = [];
|
||||||
|
|
||||||
// Ready the data
|
// Ready the data
|
||||||
if (scope.host_summary.ok) {
|
if (count.ok.length > 0) {
|
||||||
graph_data.push({
|
graph_data.push({
|
||||||
label: 'OK',
|
label: 'OK',
|
||||||
value: scope.host_summary.ok,
|
value: count.ok.length,
|
||||||
color: '#60D66F'
|
color: '#60D66F'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (scope.host_summary.changed) {
|
if (count.changed.length > 0) {
|
||||||
graph_data.push({
|
graph_data.push({
|
||||||
label: 'CHANGED',
|
label: 'CHANGED',
|
||||||
value: scope.host_summary.changed,
|
value: count.changed.length,
|
||||||
color: '#FF9900'
|
color: '#FF9900'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (scope.host_summary.unreachable) {
|
if (count.unreachable.length > 0) {
|
||||||
graph_data.push({
|
graph_data.push({
|
||||||
label: 'UNREACHABLE',
|
label: 'UNREACHABLE',
|
||||||
value: scope.host_summary.unreachable,
|
value: count.unreachable.length,
|
||||||
color: '#FF0000'
|
color: '#FF0000'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (scope.host_summary.failed) {
|
if (count.failures.length > 0) {
|
||||||
graph_data.push({
|
graph_data.push({
|
||||||
label: 'FAILED',
|
label: 'FAILED',
|
||||||
value: scope.host_summary.failed,
|
value: count.failures.length,
|
||||||
color: '#ff5850'
|
color: '#ff5850'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
scope.graph_data = graph_data;
|
|
||||||
var total_count = 0, gd_obj;
|
|
||||||
for (gd_obj in graph_data) {
|
|
||||||
total_count += graph_data[gd_obj].value;
|
|
||||||
}
|
|
||||||
scope.total_count_for_graph = total_count;
|
|
||||||
DonutChart({
|
DonutChart({
|
||||||
data: graph_data
|
data: graph_data
|
||||||
});
|
});
|
||||||
@@ -1220,44 +1000,42 @@ export default
|
|||||||
"font-family": 'Open Sans',
|
"font-family": 'Open Sans',
|
||||||
"font-style": "normal",
|
"font-style": "normal",
|
||||||
"font-weight":400,
|
"font-weight":400,
|
||||||
"src": "url(/static/assets/OpenSans-Regular.ttf)"
|
"src": "url(/static/assets/OpenSans-Regular.ttf)",
|
||||||
|
"width": 500,
|
||||||
|
"height": 300,
|
||||||
});
|
});
|
||||||
|
|
||||||
d3.select(element.find(".nv-label text")[0])
|
d3.select(element.find(".nv-label text")[0])
|
||||||
.attr("class", "DashboardGraphs-hostStatusLabel--successful")
|
.attr("class", "HostSummary-graph--successful")
|
||||||
.style({
|
.style({
|
||||||
"font-family": 'Open Sans',
|
"font-family": 'Open Sans',
|
||||||
"text-anchor": "start",
|
|
||||||
"font-size": "16px",
|
"font-size": "16px",
|
||||||
"text-transform" : "uppercase",
|
"text-transform" : "uppercase",
|
||||||
"fill" : colors[0],
|
"fill" : colors[0],
|
||||||
"src": "url(/static/assets/OpenSans-Regular.ttf)"
|
"src": "url(/static/assets/OpenSans-Regular.ttf)"
|
||||||
});
|
});
|
||||||
d3.select(element.find(".nv-label text")[1])
|
d3.select(element.find(".nv-label text")[1])
|
||||||
.attr("class", "DashboardGraphs-hostStatusLabel--failed")
|
.attr("class", "HostSummary-graph--changed")
|
||||||
.style({
|
.style({
|
||||||
"font-family": 'Open Sans',
|
"font-family": 'Open Sans',
|
||||||
"text-anchor" : "end !imporant",
|
|
||||||
"font-size": "16px",
|
"font-size": "16px",
|
||||||
"text-transform" : "uppercase",
|
"text-transform" : "uppercase",
|
||||||
"fill" : colors[1],
|
"fill" : colors[1],
|
||||||
"src": "url(/static/assets/OpenSans-Regular.ttf)"
|
"src": "url(/static/assets/OpenSans-Regular.ttf)"
|
||||||
});
|
});
|
||||||
d3.select(element.find(".nv-label text")[2])
|
d3.select(element.find(".nv-label text")[2])
|
||||||
.attr("class", "DashboardGraphs-hostStatusLabel--successful")
|
.attr("class", "HostSummary-graph--failed")
|
||||||
.style({
|
.style({
|
||||||
"font-family": 'Open Sans',
|
"font-family": 'Open Sans',
|
||||||
"text-anchor" : "end !imporant",
|
|
||||||
"font-size": "16px",
|
"font-size": "16px",
|
||||||
"text-transform" : "uppercase",
|
"text-transform" : "uppercase",
|
||||||
"fill" : colors[2],
|
"fill" : colors[2],
|
||||||
"src": "url(/static/assets/OpenSans-Regular.ttf)"
|
"src": "url(/static/assets/OpenSans-Regular.ttf)"
|
||||||
});
|
});
|
||||||
d3.select(element.find(".nv-label text")[3])
|
d3.select(element.find(".nv-label text")[3])
|
||||||
.attr("class", "DashboardGraphs-hostStatusLabel--failed")
|
.attr("class", "HostSummary-graph--unreachable")
|
||||||
.style({
|
.style({
|
||||||
"font-family": 'Open Sans',
|
"font-family": 'Open Sans',
|
||||||
"text-anchor" : "end !imporant",
|
|
||||||
"font-size": "16px",
|
"font-size": "16px",
|
||||||
"text-transform" : "uppercase",
|
"text-transform" : "uppercase",
|
||||||
"fill" : colors[3],
|
"fill" : colors[3],
|
||||||
@@ -1274,7 +1052,8 @@ export default
|
|||||||
idx = 0,
|
idx = 0,
|
||||||
result = [],
|
result = [],
|
||||||
newKeys = [],
|
newKeys = [],
|
||||||
plays = JSON.parse(JSON.stringify(scope.jobData.plays)),
|
//plays = JSON.parse(JSON.stringify(scope.jobData.plays)),
|
||||||
|
plays = scope.jobData.plays,
|
||||||
filteredListX = [],
|
filteredListX = [],
|
||||||
filteredListA = [],
|
filteredListA = [],
|
||||||
filteredListB = [],
|
filteredListB = [],
|
||||||
@@ -1363,7 +1142,8 @@ export default
|
|||||||
|
|
||||||
if (scope.activePlay && scope.jobData.plays[scope.activePlay]) {
|
if (scope.activePlay && scope.jobData.plays[scope.activePlay]) {
|
||||||
|
|
||||||
tasks = JSON.parse(JSON.stringify(scope.jobData.plays[scope.activePlay].tasks));
|
//tasks = JSON.parse(JSON.stringify(scope.jobData.plays[scope.activePlay].tasks));
|
||||||
|
tasks = scope.jobData.plays[scope.activePlay].tasks;
|
||||||
|
|
||||||
// Only draw tasks that are in the 'active' list
|
// Only draw tasks that are in the 'active' list
|
||||||
for (key in tasks) {
|
for (key in tasks) {
|
||||||
@@ -1437,7 +1217,8 @@ export default
|
|||||||
if (scope.activePlay && scope.activeTask && scope.jobData.plays[scope.activePlay] &&
|
if (scope.activePlay && scope.activeTask && scope.jobData.plays[scope.activePlay] &&
|
||||||
scope.jobData.plays[scope.activePlay].tasks[scope.activeTask]) {
|
scope.jobData.plays[scope.activePlay].tasks[scope.activeTask]) {
|
||||||
|
|
||||||
hostResults = JSON.parse(JSON.stringify(scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].hostResults));
|
//hostResults = JSON.parse(JSON.stringify(scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].hostResults));
|
||||||
|
hostResults = scope.jobData.plays[scope.activePlay].tasks[scope.activeTask].hostResults;
|
||||||
|
|
||||||
if (scope.search_host_name) {
|
if (scope.search_host_name) {
|
||||||
for (key in hostResults) {
|
for (key in hostResults) {
|
||||||
@@ -1498,88 +1279,20 @@ export default
|
|||||||
};
|
};
|
||||||
}])
|
}])
|
||||||
|
|
||||||
.factory('DrawHostSummaries', [ function() {
|
.factory('UpdateDOM', ['DrawPlays', 'DrawTasks', 'DrawHostResults',
|
||||||
return function(params) {
|
function(DrawPlays, DrawTasks, DrawHostResults) {
|
||||||
var scope = params.scope,
|
|
||||||
result = [],
|
|
||||||
filteredListA = [],
|
|
||||||
filteredListB = [],
|
|
||||||
idx = 0,
|
|
||||||
hostSummaries,
|
|
||||||
key,
|
|
||||||
keys = Object.keys(scope.jobData.hostSummaries);
|
|
||||||
if (keys.length > 0) {
|
|
||||||
hostSummaries = JSON.parse(JSON.stringify(scope.jobData.hostSummaries));
|
|
||||||
if (scope.search_host_summary_name) {
|
|
||||||
for (key in hostSummaries) {
|
|
||||||
if (hostSummaries[key].name.indexOf(scope.search_host_summary_name) > 0) {
|
|
||||||
filteredListA[key] = hostSummaries[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
filteredListA = hostSummaries;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scope.search_host_summary_status === 'failed') {
|
|
||||||
for (key in filteredListA) {
|
|
||||||
if (filteredListA[key].status === 'failed' || filteredListA[key].status === 'unreachable') {
|
|
||||||
filteredListB[key] = filteredListA[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
filteredListB = filteredListA;
|
|
||||||
}
|
|
||||||
|
|
||||||
keys = Object.keys(filteredListB);
|
|
||||||
|
|
||||||
keys.sort(function(a,b) {
|
|
||||||
if (filteredListB[a].name > filteredListB[b].name) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (filteredListB[a].name < filteredListB[b].name) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
// a must be equal to b
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
while (idx < keys.length && result.length < scope.hostSummariesMaxRows) {
|
|
||||||
result.push(filteredListB[keys[idx]]);
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setTimeout( function() {
|
|
||||||
scope.$apply( function() {
|
|
||||||
scope.hosts = result;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
|
|
||||||
.factory('UpdateDOM', ['DrawPlays', 'DrawTasks', 'DrawHostResults', 'DrawHostSummaries', 'DrawGraph',
|
|
||||||
function(DrawPlays, DrawTasks, DrawHostResults, DrawHostSummaries, DrawGraph) {
|
|
||||||
return function(params) {
|
return function(params) {
|
||||||
var scope = params.scope;
|
var scope = params.scope;
|
||||||
|
|
||||||
if (!scope.pauseLiveEvents) {
|
if (!scope.pauseLiveEvents) {
|
||||||
DrawPlays({ scope: scope });
|
DrawPlays({ scope: scope });
|
||||||
DrawTasks({ scope: scope });
|
DrawTasks({ scope: scope });
|
||||||
DrawHostResults({ scope: scope });
|
DrawHostResults({ scope: scope });
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawHostSummaries({ scope: scope });
|
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
scope.playsLoading = false;
|
scope.playsLoading = false;
|
||||||
scope.tasksLoading = false;
|
scope.tasksLoading = false;
|
||||||
scope.hostResultsLoading = false;
|
scope.hostResultsLoading = false;
|
||||||
scope.LoadHostSummaries = false;
|
|
||||||
},100);
|
},100);
|
||||||
|
|
||||||
if (scope.host_summary.total > 0) {
|
|
||||||
DrawGraph({ scope: scope, resize: true });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}]);
|
}]);
|
||||||
|
|||||||
@@ -752,9 +752,9 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm,
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
// Submit request to run a playbook
|
// Submit request to run a playbook
|
||||||
.factory('PlaybookRun', ['$location','$stateParams', 'LaunchJob', 'PromptForPasswords', 'Rest', 'GetBasePath', 'Alert', 'ProcessErrors', 'Wait', 'Empty',
|
.factory('PlaybookRun', ['$location', '$state', '$stateParams', 'LaunchJob', 'PromptForPasswords', 'Rest', 'GetBasePath', 'Alert', 'ProcessErrors', 'Wait', 'Empty',
|
||||||
'PromptForCredential', 'PromptForVars', 'PromptForSurvey' , 'CreateLaunchDialog',
|
'PromptForCredential', 'PromptForVars', 'PromptForSurvey' , 'CreateLaunchDialog',
|
||||||
function ($location, $stateParams, LaunchJob, PromptForPasswords, Rest, GetBasePath, Alert, ProcessErrors, Wait, Empty,
|
function ($location, $state, $stateParams, LaunchJob, PromptForPasswords, Rest, GetBasePath, Alert, ProcessErrors, Wait, Empty,
|
||||||
PromptForCredential, PromptForVars, PromptForSurvey, CreateLaunchDialog) {
|
PromptForCredential, PromptForVars, PromptForSurvey, CreateLaunchDialog) {
|
||||||
return function (params) {
|
return function (params) {
|
||||||
var //parent_scope = params.scope,
|
var //parent_scope = params.scope,
|
||||||
@@ -803,7 +803,8 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm,
|
|||||||
var job = data.job || data.system_job;
|
var job = data.job || data.system_job;
|
||||||
if((scope.portalMode===false || scope.$parent.portalMode===false ) && Empty(data.system_job) ||
|
if((scope.portalMode===false || scope.$parent.portalMode===false ) && Empty(data.system_job) ||
|
||||||
(base === 'home')){
|
(base === 'home')){
|
||||||
$location.path('/jobs/' + job);
|
// use $state.go with reload: true option to re-instantiate sockets in
|
||||||
|
$state.go('jobDetail', {id: job}, {reload: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export default
|
|||||||
scope.viewJobDetails = function(job) {
|
scope.viewJobDetails = function(job) {
|
||||||
|
|
||||||
var goToJobDetails = function(state) {
|
var goToJobDetails = function(state) {
|
||||||
$state.go(state, {id: job.id});
|
$state.go(state, {id: job.id}, {reload:true});
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(job.type) {
|
switch(job.type) {
|
||||||
|
|||||||
@@ -173,8 +173,8 @@ export default
|
|||||||
}
|
}
|
||||||
$state.go("^");
|
$state.go("^");
|
||||||
});
|
});
|
||||||
|
|
||||||
scope.saveSchedule = function() {
|
scope.saveSchedule = function() {
|
||||||
|
schedule.extra_data = scope.serializedExtraVars;
|
||||||
SchedulePost({
|
SchedulePost({
|
||||||
scope: scope,
|
scope: scope,
|
||||||
url: url,
|
url: url,
|
||||||
@@ -192,6 +192,7 @@ export default
|
|||||||
Rest.get()
|
Rest.get()
|
||||||
.success(function(data) {
|
.success(function(data) {
|
||||||
schedule = data;
|
schedule = data;
|
||||||
|
scope.serializedExtraVars = schedule.extra_data;
|
||||||
if(schedule.extra_data.hasOwnProperty('granularity')){
|
if(schedule.extra_data.hasOwnProperty('granularity')){
|
||||||
scope.isFactCleanup = true;
|
scope.isFactCleanup = true;
|
||||||
}
|
}
|
||||||
@@ -312,7 +313,6 @@ export default
|
|||||||
schedule = (params.schedule) ? params.schedule : {},
|
schedule = (params.schedule) ? params.schedule : {},
|
||||||
callback = params.callback,
|
callback = params.callback,
|
||||||
newSchedule, rrule, extra_vars;
|
newSchedule, rrule, extra_vars;
|
||||||
|
|
||||||
if (scheduler.isValid()) {
|
if (scheduler.isValid()) {
|
||||||
Wait('start');
|
Wait('start');
|
||||||
newSchedule = scheduler.getValue();
|
newSchedule = scheduler.getValue();
|
||||||
@@ -326,14 +326,16 @@ export default
|
|||||||
"older_than": scope.scheduler_form.keep_amount.$viewValue + scope.scheduler_form.keep_unit.$viewValue.value,
|
"older_than": scope.scheduler_form.keep_amount.$viewValue + scope.scheduler_form.keep_unit.$viewValue.value,
|
||||||
"granularity": scope.scheduler_form.granularity_keep_amount.$viewValue + scope.scheduler_form.granularity_keep_unit.$viewValue.value
|
"granularity": scope.scheduler_form.granularity_keep_amount.$viewValue + scope.scheduler_form.granularity_keep_unit.$viewValue.value
|
||||||
};
|
};
|
||||||
|
schedule.extra_data = JSON.stringify(extra_vars);
|
||||||
} else if (scope.cleanupJob) {
|
} else if (scope.cleanupJob) {
|
||||||
extra_vars = {
|
extra_vars = {
|
||||||
"days" : scope.scheduler_form.schedulerPurgeDays.$viewValue
|
"days" : scope.scheduler_form.schedulerPurgeDays.$viewValue
|
||||||
};
|
};
|
||||||
|
schedule.extra_data = JSON.stringify(extra_vars);
|
||||||
|
}
|
||||||
|
else if (scope.serializedExtraVars){
|
||||||
|
schedule.extra_data = scope.serializedExtraVars;
|
||||||
}
|
}
|
||||||
schedule.extra_data = JSON.stringify(extra_vars);
|
|
||||||
|
|
||||||
|
|
||||||
Rest.setUrl(url);
|
Rest.setUrl(url);
|
||||||
if (mode === 'add') {
|
if (mode === 'add') {
|
||||||
Rest.post(schedule)
|
Rest.post(schedule)
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
<div class="HostEvent-details--left">
|
<div class="HostEvent-details--left">
|
||||||
<div class="HostEvent-field">
|
<div class="HostEvent-field">
|
||||||
<div class="HostEvent-title">EVENT</div>
|
<div class="HostEvent-title">EVENT</div>
|
||||||
<span class="HostEvent-field--content"></span>
|
<span class="HostEvent-field--content"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="HostEvent-field">
|
<div class="HostEvent-field">
|
||||||
<span class="HostEvent-field--label">HOST</span>
|
<span class="HostEvent-field--label">HOST</span>
|
||||||
<span class="HostEvent-field--content">
|
<span class="HostEvent-field--content">
|
||||||
<a ui-sref="jobDetail.host-events({hostName: event.host_name})">{{event.host_name || "No result found"}}</a></span>
|
<a ui-sref="jobDetail.host-events({hostName: event.host_name})">{{event.host_name || "No result found"}}</a></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="HostEvent-field">
|
<div class="HostEvent-field">
|
||||||
<span class="HostEvent-field--label">STATUS</span>
|
<span class="HostEvent-field--label">STATUS</span>
|
||||||
<span class="HostEvent-field--content">
|
<span class="HostEvent-field--content">
|
||||||
<a class="HostEvents-status">
|
<a class="HostEvents-status">
|
||||||
<i class="fa fa-circle" ng-class="processEventStatus"></i>
|
<i class="fa fa-circle" ng-class="processEventStatus(event).class"></i>
|
||||||
</a>
|
</a>
|
||||||
{{event.status || "No result found"}}
|
{{processEventStatus(event).status || "No result found"}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="HostEvent-field">
|
<div class="HostEvent-field">
|
||||||
<span class="HostEvent-field--label">ID</span>
|
<span class="HostEvent-field--label">ID</span>
|
||||||
<span class="HostEvent-field--content">{{event.id || "No result found"}}</span>
|
<span class="HostEvent-field--content">{{event.id || "No result found"}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="HostEvent-field">
|
<div class="HostEvent-field">
|
||||||
<span class="HostEvent-field--label">CREATED</span>
|
<span class="HostEvent-field--label">CREATED</span>
|
||||||
<span class="HostEvent-field--content">{{event.created || "No result found"}}</span>
|
<span class="HostEvent-field--content">{{event.created || "No result found"}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="HostEvent-field">
|
<div class="HostEvent-field">
|
||||||
<span class="HostEvent-field--label">PLAY</span>
|
<span class="HostEvent-field--label">PLAY</span>
|
||||||
<span class="HostEvent-field--content">{{event.play || "No result found"}}</span>
|
<span class="HostEvent-field--content">{{event.play || "No result found"}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="HostEvent-field">
|
<div class="HostEvent-field">
|
||||||
<span class="HostEvent-field--label">TASK</span>
|
<span class="HostEvent-field--label">TASK</span>
|
||||||
<span class="HostEvent-field--content">{{event.task || "No result found"}}</span>
|
<span class="HostEvent-field--content">{{event.task || "No result found"}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="HostEvent-field">
|
<div class="HostEvent-field">
|
||||||
<span class="HostEvent-field--label">MODULE</span>
|
<span class="HostEvent-field--label">MODULE</span>
|
||||||
<span class="HostEvent-field--content">{{event.event_data.res.invocation.module_name || "No result found"}}</span>
|
<span class="HostEvent-field--content">{{event.event_data.res.invocation.module_name || "No result found"}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="HostEvent-details--right" ng-show="event.event_data.res">
|
<div class="HostEvent-details--right" ng-show="event.event_data.res">
|
||||||
<div class="HostEvent-title">RESULTS</div>
|
<div class="HostEvent-title">RESULTS</div>
|
||||||
<!-- discard any objects in the ansible response until we decide to flatten them -->
|
<!-- discard any objects in the ansible response until we decide to flatten them -->
|
||||||
<div class="HostEvent-field" ng-repeat="(key, value) in results = event.event_data.res track by $index" ng-if="processResults(value)">
|
<div class="HostEvent-field" ng-repeat="(key, value) in results = event.event_data.res track by $index" ng-if="processResults(value)">
|
||||||
<span class="HostEvent-field--label">{{key}}</span>
|
<span class="HostEvent-field--label">{{key}}</span>
|
||||||
<span class="HostEvent-field--content">{{value}}</span>
|
<span class="HostEvent-field--content">{{value}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div id="HostEvent" class="HostEvent modal fade" role="dialog">
|
<div id="HostEvent" class="HostEvent modal" role="dialog">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<!-- modal body -->
|
<!-- modal body -->
|
||||||
@@ -14,8 +14,7 @@
|
|||||||
<!-- view navigation buttons -->
|
<!-- view navigation buttons -->
|
||||||
<button ui-sref="jobDetail.host-event.details" type="button" class="btn btn-sm btn-default" >Details</button>
|
<button ui-sref="jobDetail.host-event.details" type="button" class="btn btn-sm btn-default" >Details</button>
|
||||||
<button ui-sref="jobDetail.host-event.json" type="button" class="btn btn-sm btn-default ">JSON</button>
|
<button ui-sref="jobDetail.host-event.json" type="button" class="btn btn-sm btn-default ">JSON</button>
|
||||||
<button ng-show="event.stdout" ui-sref="jobDetail.host-event.stdout" type="button" class="btn btn-sm btn-default ">Standard Out</button>
|
<button ng-show="stdout" ui-sref="jobDetail.host-event.stdout" type="button" class="btn btn-sm btn-default ">Standard Out</button>
|
||||||
<button ng-show="event.timing" ui-sref="jobDetail.host-event.timing" type="button" class="btn btn-sm btn-default ">Timing</button>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="HostEvent-body">
|
<div class="HostEvent-body">
|
||||||
|
|||||||
@@ -1,13 +1,2 @@
|
|||||||
<div class="EventHost-stdoutPanel Panel">
|
<textarea id="HostEvent-stdout" class="HostEvent-stdout">
|
||||||
<div class="StandardOut-panelHeader">
|
</textarea>
|
||||||
<div class="StandardOut-panelHeaderText">STANDARD OUT</div>
|
|
||||||
<div class="StandardOut-panelHeaderActions">
|
|
||||||
<a href="/api/v1/jobs/{{ job.id }}/stdout?format=txt_download&token={{ token }}">
|
|
||||||
<button class="StandardOut-actionButton" aw-tool-tip="Download Output" data-placement="top">
|
|
||||||
<i class="fa fa-download"></i>
|
|
||||||
</button>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<standard-out-log stdout-endpoint="event._stdout"></standard-out-log>
|
|
||||||
</div>
|
|
||||||
@@ -49,6 +49,7 @@
|
|||||||
width: 80px;
|
width: 80px;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
.HostEvent-field{
|
.HostEvent-field{
|
||||||
.OnePlusTwo-left--detailsRow;
|
.OnePlusTwo-left--detailsRow;
|
||||||
@@ -58,12 +59,17 @@
|
|||||||
}
|
}
|
||||||
.HostEvent-details--left, .HostEvent-details--right{
|
.HostEvent-details--left, .HostEvent-details--right{
|
||||||
vertical-align:top;
|
vertical-align:top;
|
||||||
width:270px;
|
width:265px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.HostEvent-details--left{
|
||||||
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
.HostEvent-details--right{
|
.HostEvent-details--right{
|
||||||
.HostEvent-field--label{
|
.HostEvent-field--label{
|
||||||
width: 170px;
|
width: auto;
|
||||||
|
}
|
||||||
|
.HostEvent-field--content{
|
||||||
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,68 +4,76 @@
|
|||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
|
|
||||||
export default
|
export default
|
||||||
['$stateParams', '$scope', '$state', 'Wait', 'JobDetailService', 'moment', 'event',
|
['$stateParams', '$scope', '$state', 'Wait', 'JobDetailService', 'event',
|
||||||
function($stateParams, $scope, $state, Wait, JobDetailService, moment, event){
|
function($stateParams, $scope, $state, Wait, JobDetailService, event){
|
||||||
// Avoid rendering objects in the details fieldset
|
|
||||||
// ng-if="processResults(value)" via host-event-details.partial.html
|
|
||||||
$scope.processResults = function(value){
|
|
||||||
if (typeof value == 'object'){return false}
|
|
||||||
else {return true}
|
|
||||||
};
|
|
||||||
|
|
||||||
var codeMirror = function(){
|
$scope.processEventStatus = JobDetailService.processEventStatus;
|
||||||
var el = $('#HostEvent-json')[0];
|
$scope.hostResults = [];
|
||||||
var editor = CodeMirror.fromTextArea(el, {
|
// Avoid rendering objects in the details fieldset
|
||||||
lineNumbers: true,
|
// ng-if="processResults(value)" via host-event-details.partial.html
|
||||||
mode: {name: "javascript", json: true}
|
$scope.processResults = function(value){
|
||||||
});
|
if (typeof value == 'object'){return false;}
|
||||||
editor.getDoc().setValue(JSON.stringify($scope.json, null, 4));
|
else {return true;}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.getActiveHostIndex = function(){
|
var codeMirror = function(el, json){
|
||||||
var result = $scope.hostResults.filter(function( obj ) {
|
var container = $(el)[0];
|
||||||
return obj.id == $scope.event.id;
|
var editor = CodeMirror.fromTextArea(container, {
|
||||||
});
|
lineNumbers: true,
|
||||||
return $scope.hostResults.indexOf(result[0])
|
mode: {name: "javascript", json: true}
|
||||||
};
|
});
|
||||||
|
editor.setSize("100%", 300)
|
||||||
|
editor.getDoc().setValue(JSON.stringify(json, null, 4));
|
||||||
|
};
|
||||||
|
|
||||||
$scope.showPrev = function(){
|
$scope.getActiveHostIndex = function(){
|
||||||
return $scope.getActiveHostIndex() != 0
|
var result = $scope.hostResults.filter(function( obj ) {
|
||||||
};
|
return obj.id == $scope.event.id;
|
||||||
|
});
|
||||||
|
return $scope.hostResults.indexOf(result[0]);
|
||||||
|
};
|
||||||
|
|
||||||
$scope.showNext = function(){
|
$scope.showPrev = function(){
|
||||||
return $scope.getActiveHostIndex() < $scope.hostResults.indexOf($scope.hostResults[$scope.hostResults.length - 1])
|
return $scope.getActiveHostIndex() != 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.goNext = function(){
|
$scope.showNext = function(){
|
||||||
var index = $scope.getActiveHostIndex() + 1;
|
return $scope.getActiveHostIndex() < $scope.hostResults.indexOf($scope.hostResults[$scope.hostResults.length - 1]);
|
||||||
var id = $scope.hostResults[index].id;
|
};
|
||||||
$state.go('jobDetail.host-event.details', {eventId: id})
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.goPrev = function(){
|
$scope.goNext = function(){
|
||||||
var index = $scope.getActiveHostIndex() - 1;
|
var index = $scope.getActiveHostIndex() + 1;
|
||||||
var id = $scope.hostResults[index].id;
|
var id = $scope.hostResults[index].id;
|
||||||
$state.go('jobDetail.host-event.details', {eventId: id})
|
$state.go('jobDetail.host-event.details', {eventId: id});
|
||||||
};
|
};
|
||||||
|
|
||||||
var init = function(){
|
$scope.goPrev = function(){
|
||||||
$scope.event = event.data.results[0];
|
var index = $scope.getActiveHostIndex() - 1;
|
||||||
$scope.event.created = moment($scope.event.created).format();
|
var id = $scope.hostResults[index].id;
|
||||||
$scope.processEventStatus = JobDetailService.processEventStatus($scope.event);
|
$state.go('jobDetail.host-event.details', {eventId: id});
|
||||||
$scope.hostResults = $stateParams.hostResults;
|
};
|
||||||
$scope.json = JobDetailService.processJson($scope.event);
|
|
||||||
if ($state.current.name == 'jobDetail.host-event.json'){
|
var init = function(){
|
||||||
codeMirror();
|
$scope.event = event;
|
||||||
}
|
JobDetailService.getJobEventChildren($stateParams.taskId).success(function(res){
|
||||||
try {
|
$scope.hostResults = res.results;
|
||||||
$scope.stdout = $scope.event.event_data.res.stdout
|
});
|
||||||
}
|
$scope.json = JobDetailService.processJson($scope.event);
|
||||||
catch(err){
|
if ($state.current.name == 'jobDetail.host-event.json'){
|
||||||
$scope.sdout = null;
|
codeMirror('#HostEvent-json', $scope.json);
|
||||||
}
|
}
|
||||||
$('#HostEvent').modal('show');
|
try {
|
||||||
};
|
$scope.stdout = JobDetailService.processJson($scope.event.event_data.res)
|
||||||
init();
|
if ($state.current.name == 'jobDetail.host-event.stdout'){
|
||||||
}];
|
codeMirror('#HostEvent-stdout', $scope.stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(err){
|
||||||
|
$scope.sdout = null;
|
||||||
|
}
|
||||||
|
$('#HostEvent').modal('show');
|
||||||
|
};
|
||||||
|
init();
|
||||||
|
}];
|
||||||
@@ -8,79 +8,51 @@
|
|||||||
|
|
||||||
var hostEventModal = {
|
var hostEventModal = {
|
||||||
name: 'jobDetail.host-event',
|
name: 'jobDetail.host-event',
|
||||||
url: '/host-event/:eventId',
|
url: '/task/:taskId/host-event/:eventId',
|
||||||
controller: 'HostEventController',
|
controller: 'HostEventController',
|
||||||
params:{
|
|
||||||
hostResults: {
|
|
||||||
value: null,
|
|
||||||
squash: false,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
templateUrl: templateUrl('job-detail/host-event/host-event-modal'),
|
templateUrl: templateUrl('job-detail/host-event/host-event-modal'),
|
||||||
resolve: {
|
resolve: {
|
||||||
features: ['FeaturesService', function(FeaturesService){
|
features: ['FeaturesService', function(FeaturesService){
|
||||||
return FeaturesService.get();
|
return FeaturesService.get();
|
||||||
}],
|
}],
|
||||||
event: ['JobDetailService','$stateParams', function(JobDetailService, $stateParams) {
|
event: ['JobDetailService','$stateParams', 'moment', function(JobDetailService, $stateParams, moment) {
|
||||||
return JobDetailService.getRelatedJobEvents($stateParams.id, {
|
return JobDetailService.getRelatedJobEvents($stateParams.id, {
|
||||||
id: $stateParams.eventId
|
id: $stateParams.eventId,
|
||||||
}).success(function(res){ return res.results[0]})
|
}).then(function(res){
|
||||||
|
res.data.results[0].created = moment(res.data.results[0].created).format('MMMM Do YYYY, h:mm:ss a');
|
||||||
|
return res.data.results[0];
|
||||||
|
});
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
onExit: function($state){
|
onExit: function($state){
|
||||||
// close the modal
|
// close the modal
|
||||||
// using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X"
|
// using an onExit event to handle cases where the user navs away using the url bar / back and not modal "X"
|
||||||
$('#HostEvent').modal('hide');
|
$('#HostEvent').modal('hide');
|
||||||
// hacky way to handle user browsing away via URL bar
|
// hacky way to handle user browsing away via URL bar
|
||||||
$('.modal-backdrop').remove();
|
$('.modal-backdrop').remove();
|
||||||
$('body').removeClass('modal-open');
|
$('body').removeClass('modal-open');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
var hostEventDetails = {
|
var hostEventDetails = {
|
||||||
name: 'jobDetail.host-event.details',
|
name: 'jobDetail.host-event.details',
|
||||||
url: '/details',
|
url: '/details',
|
||||||
controller: 'HostEventController',
|
controller: 'HostEventController',
|
||||||
templateUrl: templateUrl('job-detail/host-event/host-event-details'),
|
templateUrl: templateUrl('job-detail/host-event/host-event-details'),
|
||||||
resolve: {
|
};
|
||||||
features: ['FeaturesService', function(FeaturesService){
|
|
||||||
return FeaturesService.get();
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var hostEventJson = {
|
var hostEventJson = {
|
||||||
name: 'jobDetail.host-event.json',
|
name: 'jobDetail.host-event.json',
|
||||||
url: '/json',
|
url: '/json',
|
||||||
controller: 'HostEventController',
|
controller: 'HostEventController',
|
||||||
templateUrl: templateUrl('job-detail/host-event/host-event-json'),
|
templateUrl: templateUrl('job-detail/host-event/host-event-json')
|
||||||
resolve: {
|
|
||||||
features: ['FeaturesService', function(FeaturesService){
|
|
||||||
return FeaturesService.get();
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var hostEventTiming = {
|
|
||||||
name: 'jobDetail.host-event.timing',
|
|
||||||
url: '/timing',
|
|
||||||
controller: 'HostEventController',
|
|
||||||
templateUrl: templateUrl('job-detail/host-event/host-event-timing'),
|
|
||||||
resolve: {
|
|
||||||
features: ['FeaturesService', function(FeaturesService){
|
|
||||||
return FeaturesService.get();
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var hostEventStdout = {
|
var hostEventStdout = {
|
||||||
name: 'jobDetail.host-event.stdout',
|
name: 'jobDetail.host-event.stdout',
|
||||||
url: '/stdout',
|
url: '/stdout',
|
||||||
controller: 'HostEventController',
|
controller: 'HostEventController',
|
||||||
templateUrl: templateUrl('job-detail/host-event/host-event-stdout'),
|
templateUrl: templateUrl('job-detail/host-event/host-event-stdout')
|
||||||
resolve: {
|
|
||||||
features: ['FeaturesService', function(FeaturesService){
|
|
||||||
return FeaturesService.get();
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export {hostEventDetails, hostEventJson, hostEventTiming, hostEventStdout, hostEventModal}
|
export {hostEventDetails, hostEventJson, hostEventStdout, hostEventModal}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
import {hostEventModal, hostEventDetails, hostEventTiming,
|
import {hostEventModal, hostEventDetails,
|
||||||
hostEventJson, hostEventStdout} from './host-event.route';
|
hostEventJson, hostEventStdout} from './host-event.route';
|
||||||
import controller from './host-event.controller';
|
import controller from './host-event.controller';
|
||||||
|
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
.run(['$stateExtender', function($stateExtender){
|
.run(['$stateExtender', function($stateExtender){
|
||||||
$stateExtender.addState(hostEventModal);
|
$stateExtender.addState(hostEventModal);
|
||||||
$stateExtender.addState(hostEventDetails);
|
$stateExtender.addState(hostEventDetails);
|
||||||
$stateExtender.addState(hostEventTiming);
|
|
||||||
$stateExtender.addState(hostEventJson);
|
$stateExtender.addState(hostEventJson);
|
||||||
$stateExtender.addState(hostEventStdout);
|
$stateExtender.addState(hostEventStdout);
|
||||||
}]);
|
}]);
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
@import "awx/ui/client/src/shared/branding/colors.less";
|
@import "awx/ui/client/src/shared/branding/colors.less";
|
||||||
@import "awx/ui/client/src/shared/branding/colors.default.less";
|
@import "awx/ui/client/src/shared/branding/colors.default.less";
|
||||||
|
|
||||||
|
.HostEvents .CodeMirror{
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
.HostEvents .modal-footer{
|
.HostEvents .modal-footer{
|
||||||
border: 0;
|
border: 0;
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
|
|||||||
@@ -72,7 +72,8 @@
|
|||||||
if (filter == 'ok'){
|
if (filter == 'ok'){
|
||||||
return JobDetailService.getRelatedJobEvents($stateParams.id, {
|
return JobDetailService.getRelatedJobEvents($stateParams.id, {
|
||||||
host_name: $stateParams.hostName,
|
host_name: $stateParams.hostName,
|
||||||
event: 'runner_on_ok',
|
or__field__event: 'runner_on_ok',
|
||||||
|
or__field__event: 'runner_on_ok_async',
|
||||||
changed: false
|
changed: false
|
||||||
})
|
})
|
||||||
.success(function(res){
|
.success(function(res){
|
||||||
|
|||||||
@@ -36,9 +36,9 @@
|
|||||||
<td class=HostEvents-table--cell>
|
<td class=HostEvents-table--cell>
|
||||||
<!-- status circles -->
|
<!-- status circles -->
|
||||||
<a class="HostEvents-status">
|
<a class="HostEvents-status">
|
||||||
<i class="fa fa-circle" ng-class="processEventStatus(event)"></i>
|
<i class="fa fa-circle" ng-class="processEventStatus(event).class"></i>
|
||||||
</a>
|
</a>
|
||||||
{{event.status}}
|
{{processEventStatus(event).status}}
|
||||||
</td>
|
</td>
|
||||||
<td class=HostEvents-table--cell>{{event.play}}</td>
|
<td class=HostEvents-table--cell>{{event.play}}</td>
|
||||||
<td class=HostEvents-table--cell>{{event.task}}</td>
|
<td class=HostEvents-table--cell>{{event.task}}</td>
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
.HostSummary-graph--successful{
|
||||||
|
text-anchor: start !important;
|
||||||
|
}
|
||||||
|
.HostSummary-graph--failed{
|
||||||
|
text-anchor: end !important;
|
||||||
|
}
|
||||||
|
.HostSummary-graph--changed{
|
||||||
|
text-anchor: end !important;
|
||||||
|
}
|
||||||
|
.HostSUmmary-graph--unreachable{}
|
||||||
|
.HostSummary-loading{
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*************************************************
|
||||||
|
* Copyright (c) 2016 Ansible, Inc.
|
||||||
|
*
|
||||||
|
* All Rights Reserved
|
||||||
|
*************************************************/
|
||||||
|
|
||||||
|
export default
|
||||||
|
['$scope', '$rootScope', '$stateParams', 'Wait', 'JobDetailService', 'jobSocket', 'DrawGraph', function($scope, $rootScope, $stateParams, Wait, JobDetailService, jobSocket, DrawGraph){
|
||||||
|
|
||||||
|
var page_size = 200;
|
||||||
|
|
||||||
|
$scope.loading = $scope.hosts.length > 0 ? false : true;
|
||||||
|
$scope.filter = 'all';
|
||||||
|
$scope.search = null;
|
||||||
|
|
||||||
|
var buildTooltips = function(hosts){
|
||||||
|
// status waterfall: unreachable > failed > changed > ok > skipped
|
||||||
|
var count, grammar, text = {};
|
||||||
|
count = {
|
||||||
|
ok : _.filter(hosts, function(o){
|
||||||
|
return o.failures === 0 && o.changed === 0 && o.ok > 0;
|
||||||
|
}),
|
||||||
|
skipped : _.filter(hosts, function(o){
|
||||||
|
return o.skipped > 0;
|
||||||
|
}),
|
||||||
|
unreachable : _.filter(hosts, function(o){
|
||||||
|
return o.dark > 0;
|
||||||
|
}),
|
||||||
|
failures : _.filter(hosts, function(o){
|
||||||
|
return o.failed === true;
|
||||||
|
}),
|
||||||
|
changed : _.filter(hosts, function(o){
|
||||||
|
return o.changed > 0;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
var grammar = function(n, status){
|
||||||
|
var dict = {
|
||||||
|
0: 'No host events were ',
|
||||||
|
1: ' host event was ',
|
||||||
|
2: ' host events were '
|
||||||
|
};
|
||||||
|
if (n >= 2){
|
||||||
|
return n + dict[2] + status;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return n !== 0 ? n + dict[n] + status : dict[n] + status;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_.forIn(count, function(value, key){
|
||||||
|
text[key] = grammar(value.length, key);
|
||||||
|
});
|
||||||
|
return {count, text}
|
||||||
|
};
|
||||||
|
var socketListener = function(){
|
||||||
|
// emitted by the API in the same function used to persist host summary data
|
||||||
|
// JobEvent.update_host_summary_from_stats() from /awx/main.models.jobs.py
|
||||||
|
jobSocket.on('summary_complete', function(data) {
|
||||||
|
// discard socket msgs we don't care about in this context
|
||||||
|
if ($stateParams.id == data['unified_job_id']){
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// UnifiedJob.def socketio_emit_status() from /awx/main.models.unified_jobs.py
|
||||||
|
jobSocket.on('status_changed', function(data) {
|
||||||
|
if ($stateParams.id == data['unified_job_id']){
|
||||||
|
$scope.status = data['status'];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.getNextPage = function(){
|
||||||
|
if ($scope.next){
|
||||||
|
JobDetailService.getNextPage($scope.next).success(function(res){
|
||||||
|
res.results.forEach(function(key, index){
|
||||||
|
$scope.hosts.push(res.results[index]);
|
||||||
|
})
|
||||||
|
$scope.hosts.push(res.results);
|
||||||
|
$scope.next = res.next;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
$scope.search = function(){
|
||||||
|
Wait('start')
|
||||||
|
JobDetailService.getJobHostSummaries($stateParams.id, {
|
||||||
|
page_size: page_size,
|
||||||
|
host_name__icontains: $scope.searchTerm,
|
||||||
|
}).success(function(res){
|
||||||
|
$scope.hosts = res.results;
|
||||||
|
$scope.next = res.next;
|
||||||
|
Wait('stop')
|
||||||
|
})
|
||||||
|
};
|
||||||
|
$scope.setFilter = function(filter){
|
||||||
|
$scope.filter = filter;
|
||||||
|
var getAll = function(){
|
||||||
|
Wait('start');
|
||||||
|
JobDetailService.getJobHostSummaries($stateParams.id, {
|
||||||
|
page_size: page_size
|
||||||
|
}).success(function(res){
|
||||||
|
Wait('stop')
|
||||||
|
$scope.hosts = res.results;
|
||||||
|
$scope.next = res.next;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var getFailed = function(){
|
||||||
|
Wait('start');
|
||||||
|
JobDetailService.getJobHostSummaries($stateParams.id, {
|
||||||
|
page_size: page_size,
|
||||||
|
failed: true
|
||||||
|
}).success(function(res){
|
||||||
|
Wait('stop')
|
||||||
|
$scope.hosts = res.results;
|
||||||
|
$scope.next = res.next;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var get = filter == 'all' ? getAll() : getFailed()
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.$watchCollection('hosts', function(curr, prev){
|
||||||
|
$scope.tooltips = buildTooltips(curr);
|
||||||
|
DrawGraph({count: $scope.tooltips.count, resize:true});
|
||||||
|
});
|
||||||
|
|
||||||
|
var init = function(){
|
||||||
|
Wait('start');
|
||||||
|
JobDetailService.getJobHostSummaries($stateParams.id, {page_size: page_size})
|
||||||
|
.success(function(res){
|
||||||
|
$scope.hosts = res.results;
|
||||||
|
$scope.next = res.next;
|
||||||
|
Wait('stop');
|
||||||
|
});
|
||||||
|
JobDetailService.getJob($stateParams.id)
|
||||||
|
.success(function(res){
|
||||||
|
$scope.status = status;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
socketListener();
|
||||||
|
init();
|
||||||
|
}];
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
|
||||||
|
<div id="hosts-summary-section" class="section">
|
||||||
|
<div class="JobDetail-searchHeaderRow" ng-hide="hosts.length == 0">
|
||||||
|
<div class="JobDetail-searchContainer form-group">
|
||||||
|
<div class="search-name">
|
||||||
|
<form ng-submit="search()">
|
||||||
|
<input type="text" class="JobDetail-searchInput form-control List-searchInput" id="search_host_summary_name" ng-model="searchTerm" placeholder="Host Name" />
|
||||||
|
<a class="List-searchInputIcon search-icon" ng-click="search()"><i class="fa fa-search"></i></a>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="JobDetail-tableToggleContainer form-group">
|
||||||
|
<div class="btn-group" >
|
||||||
|
<button
|
||||||
|
ng-click="setFilter('all')"
|
||||||
|
class="JobDetail-tableToggle btn btn-xs" ng-class="{'btn-default': filter == 'failed', 'btn-primary': filter == 'all'}">All</button>
|
||||||
|
<button ng-click="setFilter('failed')"
|
||||||
|
ng-class="{'btn-default': filter == 'all', 'btn-primary': filter == 'failed'}" class="JobDetail-tableToggle btn btn-xs">Failed</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-header" ng-hide="hosts.length == 0">
|
||||||
|
<table class="table table-condensed">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="List-tableHeader col-lg-6 col-md-6 col-sm-6 col-xs-6">Hosts</th>
|
||||||
|
<th class="List-tableHeader JobDetail-tableHeader col-lg-6 col-md-5 col-sm-5 col-xs-5">Completed Tasks</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="hosts-summary-table" class="table-detail" lr-infinite-scroll="getNextPage" scroll-threshold="10" time-threshold="500">
|
||||||
|
<table class="table">
|
||||||
|
<tbody>
|
||||||
|
<tr class="List-tableRow" ng-repeat="host in hosts track by $index" id="{{ host.id }}" ng-class-even="'List-tableRow--evenRow'" ng-class-odd="'List-tableRow--oddRow'">
|
||||||
|
<td class="List-tableCell name col-lg-6 col-md-6 col-sm-6 col-xs-6">
|
||||||
|
<a ui-sref="jobDetail.host-events({hostName: host.host_name})" aw-tool-tip="View events" data-placement="top">{{ host.host_name }}</a>
|
||||||
|
</td>
|
||||||
|
<td class="List-tableCell col-lg-6 col-md-5 col-sm-5 col-xs-5 badge-column">
|
||||||
|
<a ui-sref="jobDetail.host-events({hostName: host.host_name, filter: 'ok'})" aw-tool-tip="{{ tooltips.text.ok }}" data-placement="top" ng-hide="host.ok == 0"><span class="badge successful-hosts">{{ host.ok - host.changed }}</span></a>
|
||||||
|
<a ui-sref="jobDetail.host-events({hostName: host.host_name, filter: 'changed'})" aw-tool-tip="{{ tooltips.text.changed }}" data-placement="top" ng-hide="host.changed == 0"><span class="badge changed-hosts">{{ host.changed }}</span></a>
|
||||||
|
<a ui-sref="jobDetail.host-events({hostName: host.host_name, filter: 'skipped'})" aw-tool-tip="{{ tooltips.text.skipped }}" data-placement="top" ng-hide="host.skipped == 0"><span class="badge skipped-hosts">{{ host.skipped }}</span></a>
|
||||||
|
<a ui-sref="jobDetail.host-events({hostName: host.host_name, filter: 'unreachable'})" aw-tool-tip="{{ tooltips.text.unreachable}}" data-placement="top" ng-hide="host.dark == 0"><span class="badge unreachable-hosts">{{ host.dark }}</span></a>
|
||||||
|
<a ui-sref="jobDetail.host-events({hostName: host.name, filter: 'failed'})" aw-tool-tip="{{ tooltips.text.failures}}" data-placement="top" ng-hide="host.failed == 0"><span class="badge failed-hosts">{{ host.failures }}</span></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr ng-show="hosts.length === 0 && status === 'pending'">
|
||||||
|
<td colspan="5" class="col-lg-12 HostSummary-loading">Waiting...</td>
|
||||||
|
</tr>
|
||||||
|
<tr ng-show="hosts.length === 0 && status === 'running' ">
|
||||||
|
<td colspan="5" class="col-lg-12 HostSummary-loading">Loading...</td>
|
||||||
|
</tr>
|
||||||
|
<tr ng-show="status === 'failed' || status === 'successful' && hosts.length === 0 ">
|
||||||
|
<td colspan="2" class="col-lg-12 HostSummary-loading">No matching hosts</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroll-spinner" id="hostSummariesMoreRows">
|
||||||
|
<i class="fa fa-cog fa-spin"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div><!-- section -->
|
||||||
|
|
||||||
|
<div id="graph-section" class="JobDetail-graphSection">
|
||||||
|
<svg></svg>
|
||||||
|
</div>
|
||||||
@@ -2,28 +2,26 @@
|
|||||||
|
|
||||||
@import '../shared/branding/colors.less';
|
@import '../shared/branding/colors.less';
|
||||||
@import '../shared/branding/colors.default.less';
|
@import '../shared/branding/colors.default.less';
|
||||||
|
@import '../shared/layouts/one-plus-one.less';
|
||||||
|
|
||||||
|
@breakpoint-md: 1200px;
|
||||||
|
@breakpoint-sm: 420px;
|
||||||
|
|
||||||
.JobDetail{
|
.JobDetail{
|
||||||
display: flex;
|
.OnePlusOne-container(100%, @breakpoint-md);
|
||||||
flex-direction: row;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.JobDetail-leftSide{
|
.JobDetail-leftSide{
|
||||||
flex: 1 0 auto;
|
.OnePlusOne-panel--left(100%, @breakpoint-md);
|
||||||
width: 50%;
|
|
||||||
padding-right: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.JobDetail-rightSide{
|
.JobDetail-rightSide{
|
||||||
flex: 1 0 auto;
|
.OnePlusOne-panel--right(100%, @breakpoint-md);
|
||||||
width: 50%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.JobDetail-panelHeader{
|
.JobDetail-panelHeader{
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.JobDetail-expandContainer{
|
.JobDetail-expandContainer{
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
@@ -62,11 +60,17 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding-top: 25px;
|
padding-top: 25px;
|
||||||
|
@media screen and(max-width: @breakpoint-sm){
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.JobDetail-resultRow{
|
.JobDetail-resultRow{
|
||||||
width: 50%;
|
width: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@media screen and(max-width: @breakpoint-sm){
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.JobDetail-resultRowLabel{
|
.JobDetail-resultRowLabel{
|
||||||
@@ -78,6 +82,9 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: normal!important;
|
font-weight: normal!important;
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
|
@media screen and(max-width: @breakpoint-md){
|
||||||
|
flex: 2.5 0 auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.JobDetail-resultRow--variables{
|
.JobDetail-resultRow--variables{
|
||||||
@@ -109,10 +116,16 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
margin-top: 25px;
|
margin-top: 25px;
|
||||||
|
@media screen and(max-width: @breakpoint-sm){
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.JobDetail-searchContainer{
|
.JobDetail-searchContainer{
|
||||||
flex: 1 0 auto;
|
flex: 2 0 auto;
|
||||||
|
@media screen and(max-width: @breakpoint-sm){
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.JobDetail-tableToggleContainer{
|
.JobDetail-tableToggleContainer{
|
||||||
|
|||||||
@@ -14,18 +14,17 @@ export default
|
|||||||
[ '$location', '$rootScope', '$filter', '$scope', '$compile',
|
[ '$location', '$rootScope', '$filter', '$scope', '$compile',
|
||||||
'$stateParams', '$log', 'ClearScope', 'GetBasePath', 'Wait',
|
'$stateParams', '$log', 'ClearScope', 'GetBasePath', 'Wait',
|
||||||
'ProcessErrors', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed',
|
'ProcessErrors', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed',
|
||||||
'DrawGraph', 'LoadHostSummary', 'ReloadHostSummaryList',
|
|
||||||
'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'PlaybookRun',
|
'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'DeleteJob', 'PlaybookRun',
|
||||||
'LoadPlays', 'LoadTasks', 'LoadHosts', 'HostsEdit',
|
'LoadPlays', 'LoadTasks', 'HostsEdit',
|
||||||
'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels',
|
'ParseVariableString', 'GetChoices', 'fieldChoices', 'fieldLabels',
|
||||||
'EditSchedule', 'ParseTypeChange', 'JobDetailService',
|
'EditSchedule', 'ParseTypeChange', 'JobDetailService',
|
||||||
function(
|
function(
|
||||||
$location, $rootScope, $filter, $scope, $compile, $stateParams,
|
$location, $rootScope, $filter, $scope, $compile, $stateParams,
|
||||||
$log, ClearScope, GetBasePath, Wait, ProcessErrors,
|
$log, ClearScope, GetBasePath, Wait, ProcessErrors,
|
||||||
SelectPlay, SelectTask, Socket, GetElapsed, DrawGraph,
|
SelectPlay, SelectTask, Socket, GetElapsed,
|
||||||
LoadHostSummary, ReloadHostSummaryList, JobIsFinished,
|
JobIsFinished,
|
||||||
SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob,
|
SetTaskStyles, DigestEvent, UpdateDOM, DeleteJob,
|
||||||
PlaybookRun, LoadPlays, LoadTasks, LoadHosts,
|
PlaybookRun, LoadPlays, LoadTasks,
|
||||||
HostsEdit, ParseVariableString, GetChoices, fieldChoices,
|
HostsEdit, ParseVariableString, GetChoices, fieldChoices,
|
||||||
fieldLabels, EditSchedule, ParseTypeChange, JobDetailService
|
fieldLabels, EditSchedule, ParseTypeChange, JobDetailService
|
||||||
) {
|
) {
|
||||||
@@ -82,38 +81,6 @@ export default
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
scope.hosts = [];
|
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.tasks = [];
|
||||||
scope.$watch('tasks', function(tasks) {
|
scope.$watch('tasks', function(tasks) {
|
||||||
for (var task in tasks) {
|
for (var task in tasks) {
|
||||||
@@ -169,7 +136,6 @@ export default
|
|||||||
scope.hostResults = [];
|
scope.hostResults = [];
|
||||||
|
|
||||||
scope.hostResultsMaxRows = 200;
|
scope.hostResultsMaxRows = 200;
|
||||||
scope.hostSummariesMaxRows = 200;
|
|
||||||
scope.tasksMaxRows = 200;
|
scope.tasksMaxRows = 200;
|
||||||
scope.playsMaxRows = 200;
|
scope.playsMaxRows = 200;
|
||||||
|
|
||||||
@@ -177,7 +143,6 @@ export default
|
|||||||
scope.playsLoading = true;
|
scope.playsLoading = true;
|
||||||
scope.tasksLoading = true;
|
scope.tasksLoading = true;
|
||||||
scope.hostResultsLoading = true;
|
scope.hostResultsLoading = true;
|
||||||
scope.hostSummariesLoading = true;
|
|
||||||
|
|
||||||
// Turn on the 'Waiting...' message until events begin arriving
|
// Turn on the 'Waiting...' message until events begin arriving
|
||||||
scope.waiting = true;
|
scope.waiting = true;
|
||||||
@@ -192,11 +157,9 @@ export default
|
|||||||
scope.searchPlaysEnabled = true;
|
scope.searchPlaysEnabled = true;
|
||||||
scope.searchTasksEnabled = true;
|
scope.searchTasksEnabled = true;
|
||||||
scope.searchHostsEnabled = true;
|
scope.searchHostsEnabled = true;
|
||||||
scope.searchHostSummaryEnabled = true;
|
|
||||||
scope.search_play_status = 'all';
|
scope.search_play_status = 'all';
|
||||||
scope.search_task_status = 'all';
|
scope.search_task_status = 'all';
|
||||||
scope.search_host_status = 'all';
|
scope.search_host_status = 'all';
|
||||||
scope.search_host_summary_status = 'all';
|
|
||||||
|
|
||||||
scope.haltEventQueue = false;
|
scope.haltEventQueue = false;
|
||||||
scope.processing = false;
|
scope.processing = false;
|
||||||
@@ -204,13 +167,6 @@ export default
|
|||||||
scope.lessDetail = false;
|
scope.lessDetail = false;
|
||||||
scope.lessEvents = true;
|
scope.lessEvents = 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 = {};
|
||||||
scope.jobData.hostSummaries = {};
|
scope.jobData.hostSummaries = {};
|
||||||
|
|
||||||
@@ -230,7 +186,6 @@ export default
|
|||||||
url: GetBasePath('unified_jobs'),
|
url: GetBasePath('unified_jobs'),
|
||||||
field: 'status',
|
field: 'status',
|
||||||
variable: 'status_choices',
|
variable: 'status_choices',
|
||||||
// callback: 'choicesReady'
|
|
||||||
});
|
});
|
||||||
|
|
||||||
scope.eventsHelpText = "<p><i class=\"fa fa-circle successful-hosts-color\"></i> Successful</p>\n" +
|
scope.eventsHelpText = "<p><i class=\"fa fa-circle successful-hosts-color\"></i> Successful</p>\n" +
|
||||||
@@ -244,6 +199,7 @@ export default
|
|||||||
data.event = data.event_name;
|
data.event = data.event_name;
|
||||||
DigestEvent({ scope: scope, event: data });
|
DigestEvent({ scope: scope, event: data });
|
||||||
}
|
}
|
||||||
|
UpdateDOM({ scope: scope });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
openSocket();
|
openSocket();
|
||||||
@@ -258,9 +214,6 @@ export default
|
|||||||
if (data.status === 'failed' || data.status === 'canceled' ||
|
if (data.status === 'failed' || data.status === 'canceled' ||
|
||||||
data.status === 'error' || data.status === 'successful' || data.status === 'running') {
|
data.status === 'error' || data.status === 'successful' || data.status === 'running') {
|
||||||
$scope.liveEventProcessing = false;
|
$scope.liveEventProcessing = false;
|
||||||
if ($rootScope.jobDetailInterval) {
|
|
||||||
window.clearInterval($rootScope.jobDetailInterval);
|
|
||||||
}
|
|
||||||
if (!scope.pauseLiveEvents) {
|
if (!scope.pauseLiveEvents) {
|
||||||
$scope.$emit('LoadJob'); //this is what is used for the refresh
|
$scope.$emit('LoadJob'); //this is what is used for the refresh
|
||||||
}
|
}
|
||||||
@@ -274,10 +227,9 @@ export default
|
|||||||
$rootScope.removeJobSummaryComplete = $rootScope.$on('JobSummaryComplete', function() {
|
$rootScope.removeJobSummaryComplete = $rootScope.$on('JobSummaryComplete', function() {
|
||||||
// the job host summary should now be available from the API
|
// the job host summary should now be available from the API
|
||||||
$log.debug('Trigging reload of job_host_summaries');
|
$log.debug('Trigging reload of job_host_summaries');
|
||||||
scope.$emit('LoadHostSummaries');
|
scope.$emit('InitialLoadComplete');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (scope.removeInitialLoadComplete) {
|
if (scope.removeInitialLoadComplete) {
|
||||||
scope.removeInitialLoadComplete();
|
scope.removeInitialLoadComplete();
|
||||||
}
|
}
|
||||||
@@ -292,75 +244,21 @@ export default
|
|||||||
};
|
};
|
||||||
JobDetailService.getRelatedJobEvents(scope.job.id, params)
|
JobDetailService.getRelatedJobEvents(scope.job.id, params)
|
||||||
.success(function(data) {
|
.success(function(data) {
|
||||||
if (data.results.length > 0) {
|
|
||||||
LoadHostSummary({
|
|
||||||
scope: scope,
|
|
||||||
data: data.results[0].event_data
|
|
||||||
});
|
|
||||||
}
|
|
||||||
UpdateDOM({ scope: scope });
|
UpdateDOM({ scope: scope });
|
||||||
})
|
})
|
||||||
.error(function(data, status) {
|
.error(function(data, status) {
|
||||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
msg: 'Call to ' + url + '. GET returned: ' + status });
|
||||||
});
|
});
|
||||||
if ($rootScope.jobDetailInterval) {
|
|
||||||
window.clearInterval($rootScope.jobDetailInterval);
|
|
||||||
}
|
|
||||||
$log.debug('Job completed!');
|
$log.debug('Job completed!');
|
||||||
$log.debug(scope.jobData);
|
$log.debug(scope.jobData);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
api_complete = true; //trigger events to start processing
|
api_complete = true; //trigger events to start processing
|
||||||
if ($rootScope.jobDetailInterval) {
|
UpdateDOM({ scope: scope})
|
||||||
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 params = {
|
|
||||||
page_size: scope.hostSummariesMaxRows,
|
|
||||||
order: 'host_name'
|
|
||||||
};
|
|
||||||
JobDetailService.getJobHostSummaries(scope.job.id, params)
|
|
||||||
.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 = "<deleted host>";
|
|
||||||
}
|
|
||||||
scope.jobData.hostSummaries[event.host] = {
|
|
||||||
id: event.host,
|
|
||||||
name: name,
|
|
||||||
ok: event.ok,
|
|
||||||
changed: event.changed,
|
|
||||||
unreachable: event.dark,
|
|
||||||
failed: event.failures,
|
|
||||||
status: (event.failed) ? 'failed' : 'successful'
|
|
||||||
};
|
|
||||||
});
|
|
||||||
scope.$emit('InitialLoadComplete');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
if (scope.removeLoadHosts) {
|
if (scope.removeLoadHosts) {
|
||||||
scope.removeLoadHosts();
|
scope.removeLoadHosts();
|
||||||
}
|
}
|
||||||
@@ -376,81 +274,22 @@ export default
|
|||||||
var params = {
|
var params = {
|
||||||
parent: task.id,
|
parent: task.id,
|
||||||
event__startswith: 'runner',
|
event__startswith: 'runner',
|
||||||
page_size: scope.hostResultsMaxRows
|
|
||||||
};
|
};
|
||||||
JobDetailService.getRelatedJobEvents(scope.job.id, params)
|
JobDetailService.getRelatedJobEvents(scope.job.id, params)
|
||||||
.success(function(data) {
|
.success(function(data) {
|
||||||
var idx, event, status, status_text, item, msg;
|
var event, status, status_text, item, msg;
|
||||||
if (data.results.length > 0) {
|
if (data.results.length > 0) {
|
||||||
lastEventId = data.results[0].id;
|
lastEventId = data.results[0].id;
|
||||||
}
|
}
|
||||||
scope.next_host_results = data.next;
|
scope.next_host_results = data.next;
|
||||||
for (idx=data.results.length - 1; idx >= 0; idx--) {
|
task.hostResults = JobDetailService.processHostEvents(data.results);
|
||||||
event = data.results[idx];
|
scope.$emit('InitialLoadComplete');
|
||||||
if (event.event === "runner_on_skipped") {
|
|
||||||
status = 'skipped';
|
|
||||||
}
|
|
||||||
else if (event.event === "runner_on_unreachable") {
|
|
||||||
status = 'unreachable';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
status = (event.failed) ? 'failed' : (event.changed) ? 'changed' : 'successful';
|
|
||||||
}
|
|
||||||
switch(status) {
|
|
||||||
case "successful":
|
|
||||||
status_text = 'OK';
|
|
||||||
break;
|
|
||||||
case "changed":
|
|
||||||
status_text = "Changed";
|
|
||||||
break;
|
|
||||||
case "failed":
|
|
||||||
status_text = "Failed";
|
|
||||||
break;
|
|
||||||
case "unreachable":
|
|
||||||
status_text = "Unreachable";
|
|
||||||
break;
|
|
||||||
case "skipped":
|
|
||||||
status_text = "Skipped";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.event_data && event.event_data.res) {
|
|
||||||
item = event.event_data.res.item;
|
|
||||||
if (typeof item === "object") {
|
|
||||||
item = JSON.stringify(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = '';
|
|
||||||
if (event.event_data && event.event_data.res) {
|
|
||||||
if (typeof event.event_data.res === 'object') {
|
|
||||||
msg = event.event_data.res.msg;
|
|
||||||
} else {
|
|
||||||
msg = event.event_data.res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.event !== "runner_on_no_hosts") {
|
|
||||||
task.hostResults[event.id] = {
|
|
||||||
id: event.id,
|
|
||||||
status: status,
|
|
||||||
status_text: status_text,
|
|
||||||
host_id: event.host,
|
|
||||||
task_id: event.parent,
|
|
||||||
name: event.event_data.host,
|
|
||||||
created: event.created,
|
|
||||||
msg: msg,
|
|
||||||
counter: event.counter,
|
|
||||||
item: item
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scope.$emit('LoadHostSummaries');
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
scope.$emit('LoadHostSummaries');
|
scope.$emit('InitialLoadComplete');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
scope.$emit('LoadHostSummaries');
|
scope.$emit('InitialLoadComplete');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -559,10 +398,10 @@ export default
|
|||||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
msg: 'Call to ' + url + '. GET returned: ' + status });
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
scope.$emit('LoadHostSummaries');
|
scope.$emit('InitialLoadComplete');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
scope.$emit('LoadHostSummaries');
|
scope.$emit('InitialLoadComplete');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -570,12 +409,6 @@ export default
|
|||||||
scope.removeLoadPlays();
|
scope.removeLoadPlays();
|
||||||
}
|
}
|
||||||
scope.removeLoadPlays = scope.$on('LoadPlays', function(e, events_url) {
|
scope.removeLoadPlays = scope.$on('LoadPlays', function(e, events_url) {
|
||||||
|
|
||||||
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.plays = {};
|
scope.jobData.plays = {};
|
||||||
var params = {
|
var params = {
|
||||||
order_by: 'id'
|
order_by: 'id'
|
||||||
@@ -659,13 +492,6 @@ export default
|
|||||||
scope.jobData.plays[event.id].status_text = 'No matching hosts';
|
scope.jobData.plays[event.id].status_text = 'No matching hosts';
|
||||||
scope.jobData.plays[event.id].status_tip = "Event ID: " + event.id + "<br />Status: No matching hosts";
|
scope.jobData.plays[event.id].status_tip = "Event ID: " + event.id + "<br />Status: No matching hosts";
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.host_summary.ok += ok;
|
|
||||||
scope.host_summary.changed += changed;
|
|
||||||
scope.host_summary.unreachable += (event.unreachable_count) ? event.unreachable_count : 0;
|
|
||||||
scope.host_summary.failed += failed;
|
|
||||||
scope.host_summary.total = scope.host_summary.ok + scope.host_summary.changed + scope.host_summary.unreachable +
|
|
||||||
scope.host_summary.failed;
|
|
||||||
});
|
});
|
||||||
if (scope.activePlay && scope.jobData.plays[scope.activePlay]) {
|
if (scope.activePlay && scope.jobData.plays[scope.activePlay]) {
|
||||||
scope.jobData.plays[scope.activePlay].playActiveClass = 'JobDetail-tableRow--selected';
|
scope.jobData.plays[scope.activePlay].playActiveClass = 'JobDetail-tableRow--selected';
|
||||||
@@ -685,7 +511,6 @@ export default
|
|||||||
scope.playsLoading = true;
|
scope.playsLoading = true;
|
||||||
scope.tasksLoading = true;
|
scope.tasksLoading = true;
|
||||||
scope.hostResultsLoading = true;
|
scope.hostResultsLoading = true;
|
||||||
scope.LoadHostSummaries = true;
|
|
||||||
|
|
||||||
// Load the job record
|
// Load the job record
|
||||||
JobDetailService.getJob(job_id)
|
JobDetailService.getJob(job_id)
|
||||||
@@ -769,7 +594,6 @@ export default
|
|||||||
scope.playsLoading = false;
|
scope.playsLoading = false;
|
||||||
scope.tasksLoading = false;
|
scope.tasksLoading = false;
|
||||||
scope.hostResultsLoading = false;
|
scope.hostResultsLoading = false;
|
||||||
scope.hostSummariesLoading = false;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
scope.job_status.finished = null;
|
scope.job_status.finished = null;
|
||||||
@@ -811,10 +635,6 @@ export default
|
|||||||
// First time. User just loaded page.
|
// First time. User just loaded page.
|
||||||
scope.$emit('LoadJob');
|
scope.$emit('LoadJob');
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// Check if the graph needs to redraw
|
|
||||||
setTimeout(function() { DrawGraph({ scope: scope, resize: true }); }, 500);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
scope.adjustSize = function() {
|
scope.adjustSize = function() {
|
||||||
@@ -859,11 +679,6 @@ export default
|
|||||||
$('#tasks-table-detail').height(120 + (height * 0.20));
|
$('#tasks-table-detail').height(120 + (height * 0.20));
|
||||||
$('#hosts-table-detail').height(150 + (height * 0.70));
|
$('#hosts-table-detail').height(150 + (height * 0.70));
|
||||||
}
|
}
|
||||||
// Summary table height adjusting.
|
|
||||||
height = ($('#job-detail-container').height() / 2) - $('#hosts-summary-section .JobDetail-searchHeaderRow').outerHeight() -
|
|
||||||
$('#hosts-summary-section .table-header').outerHeight() - 20;
|
|
||||||
// $('#hosts-summary-table').height(height);
|
|
||||||
//$('#hosts-summary-table').mCustomScrollbar("update");
|
|
||||||
scope.$emit('RefreshCompleted');
|
scope.$emit('RefreshCompleted');
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -912,52 +727,6 @@ export default
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
scope.toggleSummary = function(hide) {
|
|
||||||
var docw, doch, height = $('#job-detail-container').height(), slide_width;
|
|
||||||
if (!hide) {
|
|
||||||
docw = $(window).width();
|
|
||||||
doch = $(window).height();
|
|
||||||
slide_width = (docw < 840) ? '100%' : '80%';
|
|
||||||
$('#summary-button').hide();
|
|
||||||
$('.overlay').css({
|
|
||||||
width: $(document).width(),
|
|
||||||
height: $(document).height()
|
|
||||||
}).show();
|
|
||||||
|
|
||||||
// Adjust the summary table height
|
|
||||||
$('#job-summary-container .job_well').height(height - 18).css({
|
|
||||||
'box-shadow': '-3px 3px 5px 0 #ccc'
|
|
||||||
});
|
|
||||||
height = Math.floor($('#job-detail-container').height() * 0.5) -
|
|
||||||
$('#hosts-summary-section .header').outerHeight() -
|
|
||||||
$('#hosts-summary-section .table-header').outerHeight() -
|
|
||||||
$('#hide-summary-button').outerHeight() -
|
|
||||||
$('#summary-search-section').outerHeight() -
|
|
||||||
$('#hosts-summary-section .header').outerHeight() -
|
|
||||||
$('#hosts-summary-section .legend').outerHeight();
|
|
||||||
$('#hosts-summary-table').height(height - 50);
|
|
||||||
//$('#hosts-summary-table').mCustomScrollbar("update");
|
|
||||||
|
|
||||||
$('#hide-summary-button').show();
|
|
||||||
|
|
||||||
$('#job-summary-container').css({
|
|
||||||
top: 0,
|
|
||||||
right: 0,
|
|
||||||
width: slide_width,
|
|
||||||
'z-index': 1090,
|
|
||||||
'padding-right': '15px',
|
|
||||||
'padding-left': '15px'
|
|
||||||
}).show('slide', {'direction': 'right'});
|
|
||||||
|
|
||||||
setTimeout(function() { DrawGraph({ scope: scope, resize: true }); }, 500);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$('.overlay').hide();
|
|
||||||
$('#summary-button').show();
|
|
||||||
$('#job-summary-container').hide('slide', {'direction': 'right'});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.objectIsEmpty = function(obj) {
|
scope.objectIsEmpty = function(obj) {
|
||||||
if (angular.isObject(obj)) {
|
if (angular.isObject(obj)) {
|
||||||
return (Object.keys(obj).length > 0) ? false : true;
|
return (Object.keys(obj).length > 0) ? false : true;
|
||||||
@@ -965,6 +734,17 @@ export default
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
scope.toggleLessEvents = function() {
|
||||||
|
if (!scope.lessEvents) {
|
||||||
|
$('#events-summary').slideUp(200);
|
||||||
|
scope.lessEvents = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#events-summary').slideDown(200);
|
||||||
|
scope.lessEvents = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
scope.toggleLessStatus = function() {
|
scope.toggleLessStatus = function() {
|
||||||
if (!scope.lessStatus) {
|
if (!scope.lessStatus) {
|
||||||
$('#job-status-form').slideUp(200);
|
$('#job-status-form').slideUp(200);
|
||||||
@@ -987,18 +767,6 @@ export default
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
scope.toggleLessEvents = function() {
|
|
||||||
if (!scope.lessEvents) {
|
|
||||||
$('#events-summary').slideUp(200);
|
|
||||||
scope.lessEvents = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$('#events-summary').slideDown(200);
|
|
||||||
scope.lessEvents = false;
|
|
||||||
DrawGraph({scope:scope});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.filterPlayStatus = function() {
|
scope.filterPlayStatus = function() {
|
||||||
scope.search_play_status = (scope.search_play_status === 'all') ? 'failed' : 'all';
|
scope.search_play_status = (scope.search_play_status === 'all') ? 'failed' : 'all';
|
||||||
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
|
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
|
||||||
@@ -1037,6 +805,9 @@ export default
|
|||||||
scope.searchTasksEnabled = true;
|
scope.searchTasksEnabled = true;
|
||||||
}
|
}
|
||||||
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
|
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
|
||||||
|
if (scope.search_task_status === 'failed'){
|
||||||
|
params.failed = true;
|
||||||
|
}
|
||||||
LoadTasks({
|
LoadTasks({
|
||||||
scope: scope
|
scope: scope
|
||||||
});
|
});
|
||||||
@@ -1058,66 +829,24 @@ export default
|
|||||||
scope.searchHostsEnabled = true;
|
scope.searchHostsEnabled = true;
|
||||||
}
|
}
|
||||||
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
|
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
|
||||||
LoadHosts({
|
scope.hostResultsLoading = true;
|
||||||
scope: scope
|
var params = {
|
||||||
|
parent: scope.selectedTask,
|
||||||
|
event__startswith: 'runner',
|
||||||
|
page_size: scope.hostResultsMaxRows,
|
||||||
|
order: 'host_name,counter',
|
||||||
|
host_name__icontains: scope.search_host_name
|
||||||
|
}
|
||||||
|
if (scope.search_host_status === 'failed'){
|
||||||
|
params.failed = true;
|
||||||
|
}
|
||||||
|
JobDetailService.getRelatedJobEvents(scope.job.id, params).success(function(res){
|
||||||
|
scope.hostResults = JobDetailService.processHostEvents(res.results)
|
||||||
|
scope.hostResultsLoading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
scope.searchHostsKeyPress = function(e) {
|
|
||||||
if (e.keyCode === 13) {
|
|
||||||
scope.searchHosts();
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.searchHostSummary = function() {
|
|
||||||
if (scope.search_host_summary_name) {
|
|
||||||
scope.searchHostSummaryEnabled = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
scope.searchHostSummaryEnabled = true;
|
|
||||||
}
|
|
||||||
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
|
|
||||||
ReloadHostSummaryList({
|
|
||||||
scope: scope
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.searchHostSummaryKeyPress = function(e) {
|
|
||||||
if (e.keyCode === 13) {
|
|
||||||
scope.searchHostSummary();
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.filterTaskStatus = function() {
|
|
||||||
scope.search_task_status = (scope.search_task_status === 'all') ? 'failed' : 'all';
|
|
||||||
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
|
|
||||||
LoadTasks({
|
|
||||||
scope: scope
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.filterHostStatus = function() {
|
|
||||||
scope.search_host_status = (scope.search_host_status === 'all') ? 'failed' : 'all';
|
|
||||||
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
|
|
||||||
LoadHosts({
|
|
||||||
scope: scope
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.filterHostSummaryStatus = function() {
|
|
||||||
scope.search_host_summary_status = (scope.search_host_summary_status === 'all') ? 'failed' : 'all';
|
|
||||||
if (!scope.liveEventProcessing || scope.pauseLiveEvents) {
|
|
||||||
ReloadHostSummaryList({
|
|
||||||
scope: scope
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (scope.removeDeleteFinished) {
|
if (scope.removeDeleteFinished) {
|
||||||
scope.removeDeleteFinished();
|
scope.removeDeleteFinished();
|
||||||
@@ -1354,41 +1083,6 @@ export default
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
scope.hostSummariesScrollDown = function() {
|
|
||||||
// check for more hosts when user scrolls to bottom of host summaries list...
|
|
||||||
if (((!scope.liveEventProcessing) || (scope.liveEventProcessing && scope.pauseLiveEvents)) && scope.next_host_summaries) {
|
|
||||||
scope.hostSummariesLoading = true;
|
|
||||||
JobDetailService.getNextPage(scope.next_host_summaries)
|
|
||||||
.success(function(data) {
|
|
||||||
scope.next_host_summaries = data.next;
|
|
||||||
data.results.forEach(function(row) {
|
|
||||||
var name;
|
|
||||||
if (row.host_name) {
|
|
||||||
name = row.host_name;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
name = "<deleted host>";
|
|
||||||
}
|
|
||||||
scope.hosts.push({
|
|
||||||
id: row.id,
|
|
||||||
name: name,
|
|
||||||
ok: row.ok,
|
|
||||||
changed: row.changed,
|
|
||||||
unreachable: row.dark,
|
|
||||||
failed: row.failures
|
|
||||||
});
|
|
||||||
});
|
|
||||||
$('#hostSummariesMoreRows').fadeOut();
|
|
||||||
scope.hostSummariesLoading = false;
|
|
||||||
})
|
|
||||||
.error(function(data, status) {
|
|
||||||
$('#hostSummariesMoreRows').fadeOut();
|
|
||||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
|
||||||
msg: 'Call to ' + scope.next_host_summaries + '. GET returned: ' + status });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.refresh = function(){
|
scope.refresh = function(){
|
||||||
$scope.$emit('LoadJob');
|
$scope.$emit('LoadJob');
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
|
|
||||||
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.started">
|
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.started">
|
||||||
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Started</label>
|
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Started</label>
|
||||||
<div class="JobDetail-resultRowText">{{ job_status.started | date:'MM/dd/yy HH:mm:ss' }}</div>
|
<div class="JobDetail-resultRowText">{{ job_status.started | date:'M/d/yy HH:mm:ss a' }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_type">
|
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_type">
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
|
|
||||||
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.started">
|
<div class="form-group JobDetail-resultRow toggle-show" ng-show="job_status.started">
|
||||||
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Finished</label>
|
<label class="JobDetail-resultRowLabel col-lg-2 col-md-2 col-sm-2 col-xs-3 control-label">Finished</label>
|
||||||
<div class="JobDetail-resultRowText">{{ job_status.finished | date:'MM/dd/yy HH:mm:ss' }}</div>
|
<div class="JobDetail-resultRowText">{{ job_status.finished | date:'M/d/yy HH:mm:ss a' }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group JobDetail-resultRow toggle-show" ng-show="created_by">
|
<div class="form-group JobDetail-resultRow toggle-show" ng-show="created_by">
|
||||||
@@ -344,7 +344,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr class="List-tableRow cursor-pointer" ng-class-odd="'List-tableRow--oddRow'" ng-class-even="'List-tableRow--evenRow'" ng-repeat="result in results = (hostResults) track by $index">
|
<tr class="List-tableRow cursor-pointer" ng-class-odd="'List-tableRow--oddRow'" ng-class-even="'List-tableRow--evenRow'" ng-repeat="result in results = (hostResults) track by $index">
|
||||||
<td class="List-tableCell col-lg-4 col-md-3 col-sm-3 col-xs-3 status-column">
|
<td class="List-tableCell col-lg-4 col-md-3 col-sm-3 col-xs-3 status-column">
|
||||||
<a ui-sref="jobDetail.host-event.details({eventId: result.id, hostResults: hostResults})" aw-tool-tip="Event ID: {{ result.id }}<br \>Status: {{ result.status_text }}. Click for details" data-placement="top"><i ng-show="result.status_text != 'Unreachable'" class="JobDetail-statusIcon fa icon-job-{{ result.status }}"></i><span ng-show="result.status_text != 'Unreachable'">{{ result.name }}</span><i ng-show="result.status_text == 'Unreachable'" class="JobDetail-statusIcon fa icon-job-unreachable"></i><span ng-show="result.status_text == 'Unreachable'">{{ result.name }}</span></a>
|
<a ui-sref="jobDetail.host-event.details({eventId: result.id, taskId: selectedTask})" aw-tool-tip="Event ID: {{ result.id }}<br \>Status: {{ result.status_text }}. Click for details" data-placement="top"><i ng-show="result.status_text != 'Unreachable'" class="JobDetail-statusIcon fa icon-job-{{ result.status }}"></i><span ng-show="result.status_text != 'Unreachable'">{{ result.name }}</span><i ng-show="result.status_text == 'Unreachable'" class="JobDetail-statusIcon fa icon-job-unreachable"></i><span ng-show="result.status_text == 'Unreachable'">{{ result.name }}</span></a>
|
||||||
</td>
|
</td>
|
||||||
<td class="List-tableCell col-lg-3 col-md-4 col-sm-3 col-xs-3 item-column">{{ result.item }}</td>
|
<td class="List-tableCell col-lg-3 col-md-4 col-sm-3 col-xs-3 item-column">{{ result.item }}</td>
|
||||||
<td class="List-tableCell col-lg-3 col-md-4 col-sm-3 col-xs-3">{{ result.msg }}</td>
|
<td class="List-tableCell col-lg-3 col-md-4 col-sm-3 col-xs-3">{{ result.msg }}</td>
|
||||||
@@ -388,75 +388,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="events-summary" style="display:none">
|
<!-- Host Summary view -->
|
||||||
|
<div id="events-summary" ng-hide="lessEvents">
|
||||||
<div id="hosts-summary-section" class="section">
|
<div ui-view="host-summary@jobDetail"></div>
|
||||||
|
</div>
|
||||||
<div class="JobDetail-searchHeaderRow">
|
|
||||||
<div class="JobDetail-searchContainer form-group">
|
|
||||||
<div class="search-name">
|
|
||||||
<input type="text" class="JobDetail-searchInput form-control List-searchInput" id="search_host_summary_name" ng-model="search_host_summary_name" placeholder="Host Name" ng-keypress="searchHostSummaryKeyPress($event)" >
|
|
||||||
<a class="List-searchInputIcon search-icon" ng-show="searchHostSummaryEnabled" ng-click="searchHostSummary()"><i class="fa fa-search"></i></a>
|
|
||||||
<a class="List-searchInputIcon search-icon" ng-show="!searchHostSummaryEnabled" ng-click="search_host_summary_name=''; searchHostSummary()"><i class="fa fa-times"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="JobDetail-tableToggleContainer form-group">
|
|
||||||
<div class="btn-group" aw-toggle-button data-after-toggle="filterHostSummaryStatus">
|
|
||||||
<button class="JobDetail-tableToggle btn btn-xs btn-primary active">All</button>
|
|
||||||
<button class="JobDetail-tableToggle btn btn-xs btn-default">Failed</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="table-header">
|
|
||||||
<table class="table table-condensed">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="List-tableHeader col-lg-6 col-md-6 col-sm-6 col-xs-6">Hosts</th>
|
|
||||||
<th class="List-tableHeader JobDetail-tableHeader col-lg-6 col-md-5 col-sm-5 col-xs-5">Completed Tasks</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="hosts-summary-table" class="table-detail" lr-infinite-scroll="hostSummariesScrollDown" scroll-threshold="10" time-threshold="500">
|
|
||||||
<table class="table">
|
|
||||||
<tbody>
|
|
||||||
<tr class="List-tableRow" ng-repeat="host in summaryList = (hosts) track by $index" id="{{ host.id }}" ng-class-even="'List-tableRow--evenRow'" ng-class-odd="'List-tableRow--oddRow'">
|
|
||||||
<td class="List-tableCell name col-lg-6 col-md-6 col-sm-6 col-xs-6">
|
|
||||||
<a ui-sref="jobDetail.host-events({hostName: host.name})" aw-tool-tip="View events" data-placement="top">{{ host.name }}</a>
|
|
||||||
</td>
|
|
||||||
<td class="List-tableCell col-lg-6 col-md-5 col-sm-5 col-xs-5 badge-column">
|
|
||||||
<a ui-sref="jobDetail.host-events({hostName: host.name, hostId: host.id, filter: 'ok'})" aw-tool-tip="{{ host.okTip }}" data-tip-watch="host.okTip" data-placement="top" ng-hide="host.ok == 0"><span class="badge successful-hosts">{{ host.ok }}</span></a>
|
|
||||||
<a ui-sref="jobDetail.host-events({hostName: host.name, hostId: host.id, filter: 'changed'})" aw-tool-tip="{{ host.changedTip }}" data-tip-watch="host.changedTip" data-placement="top" ng-hide="host.changed == 0"><span class="badge changed-hosts">{{ host.changed }}</span></a>
|
|
||||||
<a ui-sref="jobDetail.host-events({hostName: host.name, hostId: host.id, filter: 'unreachable'})" aw-tool-tip="{{ host.unreachableTip }}" data-tip-watch="host.unreachableTip" data-placement="top" ng-hide="host.unreachable == 0"><span class="badge unreachable-hosts">{{ host.unreachable }}</span></a>
|
|
||||||
<a ui-sref="jobDetail.host-events({hostName: host.name, hostId: host.id, filter: 'failed'})" aw-tool-tip="{{ host.failedTip }}" data-tip-watch="host.failedTip" data-placement="top" ng-hide="host.failed == 0"><span class="badge failed-hosts">{{ host.failed }}</span></a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr ng-show="summaryList.length === 0 && waiting">
|
|
||||||
<td colspan="5" class="col-lg-12 loading-info">Waiting...</td>
|
|
||||||
</tr>
|
|
||||||
<tr ng-show="summaryList.length === 0 && hostSummariesLoading && !waiting">
|
|
||||||
<td colspan="5" class="col-lg-12 loading-info">Loading...</td>
|
|
||||||
</tr>
|
|
||||||
<tr ng-show="summaryList.length === 0 && !hostSummariesLoading && !waiting">
|
|
||||||
<td colspan="2" class="col-lg-12 loading-info">No matching hosts</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="scroll-spinner" id="hostSummariesMoreRows">
|
|
||||||
<i class="fa fa-cog fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div><!-- section -->
|
|
||||||
|
|
||||||
<div id="graph-section" class="JobDetail-graphSection">
|
|
||||||
<svg width="100%" height="100%"></svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!--end of events summary-->
|
|
||||||
</div>
|
</div>
|
||||||
<!-- end of events summary-->
|
<!-- end of events summary-->
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
/*************************************************
|
/*************************************************
|
||||||
* Copyright (c) 2015 Ansible, Inc.
|
* Copyright (c) 2016 Ansible, Inc.
|
||||||
*
|
*
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*************************************************/
|
*************************************************/
|
||||||
|
|
||||||
import {templateUrl} from '../shared/template-url/template-url.factory';
|
import {templateUrl} from '../shared/template-url/template-url.factory';
|
||||||
|
import HostSummaryController from './host-summary/host-summary.controller';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'jobDetail',
|
name: 'jobDetail',
|
||||||
url: '/jobs/:id',
|
url: '/jobs/:id',
|
||||||
templateUrl: templateUrl('job-detail/job-detail'),
|
|
||||||
controller: 'JobDetailController',
|
|
||||||
ncyBreadcrumb: {
|
ncyBreadcrumb: {
|
||||||
parent: 'jobs',
|
parent: 'jobs',
|
||||||
label: "{{ job.id }} - {{ job.name }}"
|
label: "{{ job.id }} - {{ job.name }}"
|
||||||
@@ -26,10 +25,32 @@ export default {
|
|||||||
endpoint: "job_events"
|
endpoint: "job_events"
|
||||||
});
|
});
|
||||||
$rootScope.event_socket.init();
|
$rootScope.event_socket.init();
|
||||||
|
// returns should really be providing $rootScope.event_socket
|
||||||
|
// otherwise, we have to inject the entire $rootScope into the controller
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}],
|
||||||
|
jobSocket: ['Socket', '$rootScope', function(Socket, $rootScope) {
|
||||||
|
var job_socket = Socket({
|
||||||
|
scope: $rootScope,
|
||||||
|
endpoint: "jobs"
|
||||||
|
});
|
||||||
|
job_socket.init();
|
||||||
|
// returns should really be providing $rootScope.job_socket
|
||||||
|
// otherwise, we have to inject the entire $rootScope into the controller
|
||||||
|
return job_socket;
|
||||||
}]
|
}]
|
||||||
|
},
|
||||||
|
views: {
|
||||||
|
'': {
|
||||||
|
templateUrl: templateUrl('job-detail/job-detail'),
|
||||||
|
controller: 'JobDetailController',
|
||||||
|
},
|
||||||
|
'host-summary@jobDetail': {
|
||||||
|
templateUrl: templateUrl('job-detail/host-summary/host-summary'),
|
||||||
|
controller: HostSummaryController
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
export default
|
export default
|
||||||
['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', function($rootScope, Rest, GetBasePath, ProcessErrors){
|
['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', function($rootScope, Rest, GetBasePath, ProcessErrors){
|
||||||
return {
|
return {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
For ES6
|
* For ES6
|
||||||
it might be useful to set some default params here, e.g.
|
* it might be useful to set some default params here, e.g.
|
||||||
getJobHostSummaries: function(id, page_size=200, order='host_name'){}
|
* getJobHostSummaries: function(id, page_size=200, order='host_name'){}
|
||||||
without ES6, we'd have to supply defaults like this:
|
* without ES6, we'd have to supply defaults like this:
|
||||||
this.page_size = params.page_size ? params.page_size : 200;
|
* this.page_size = params.page_size ? params.page_size : 200;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// the the API passes through Ansible's event_data response
|
// the the API passes through Ansible's event_data response
|
||||||
// we need to massage away the verbose and redundant properties
|
// we need to massage away the verbose and redundant properties
|
||||||
|
|
||||||
processJson: function(data){
|
processJson: function(data){
|
||||||
// a deep copy
|
// a deep copy
|
||||||
var result = $.extend(true, {}, data);
|
var result = $.extend(true, {}, data);
|
||||||
@@ -28,7 +27,7 @@ export default
|
|||||||
// remove ignored properties
|
// remove ignored properties
|
||||||
Object.keys(result).forEach(function(key, index){
|
Object.keys(result).forEach(function(key, index){
|
||||||
if (ignored.indexOf(key) > -1) {
|
if (ignored.indexOf(key) > -1) {
|
||||||
delete result[key]
|
delete result[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -37,154 +36,209 @@ export default
|
|||||||
result.event_data = {};
|
result.event_data = {};
|
||||||
Object.keys(data.event_data.res).forEach(function(key, index){
|
Object.keys(data.event_data.res).forEach(function(key, index){
|
||||||
if (ignored.indexOf(key) > -1) {
|
if (ignored.indexOf(key) > -1) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
result.event_data[key] = data.event_data.res[key];
|
result.event_data[key] = data.event_data.res[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch(err){result.event_data = null;}
|
catch(err){result.event_data = undefined;}
|
||||||
|
|
||||||
return result
|
return result;
|
||||||
},
|
},
|
||||||
|
// Return Ansible's passed-through response msg on a job_event
|
||||||
processEventStatus: function(event){
|
processEventMsg: function(event){
|
||||||
// Generate a helper class for job_event statuses
|
return typeof event.event_data.res === 'object' ? event.event_data.res.msg : event.event_data.res;
|
||||||
// the stack for which status to display is
|
},
|
||||||
// unreachable > failed > changed > ok
|
// Return only Ansible's passed-through response item on a job_event
|
||||||
// uses the API's runner events and convenience properties .failed .changed to determine status.
|
processEventItem: function(event){
|
||||||
// see: job_event_callback.py
|
try{
|
||||||
if (event.event == 'runner_on_unreachable'){
|
var item = event.event_data.res.item;
|
||||||
event.status = 'Unreachable';
|
return typeof item === 'object' ? JSON.stringify(item) : item;
|
||||||
return 'HostEvents-status--unreachable'
|
|
||||||
}
|
|
||||||
// equiv to 'runner_on_error' && 'runner on failed'
|
|
||||||
if (event.failed){
|
|
||||||
event.status = 'Failed';
|
|
||||||
return 'HostEvents-status--failed'
|
|
||||||
}
|
|
||||||
// catch the changed case before ok, because both can be true
|
|
||||||
if (event.changed){
|
|
||||||
event.status = 'Changed';
|
|
||||||
return 'HostEvents-status--changed'
|
|
||||||
}
|
|
||||||
if (event.event == 'runner_on_ok'){
|
|
||||||
event.status = 'OK';
|
|
||||||
return 'HostEvents-status--ok'
|
|
||||||
}
|
|
||||||
if (event.event == 'runner_on_skipped'){
|
|
||||||
event.status = 'Skipped';
|
|
||||||
return 'HostEvents-status--skipped'
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
// study a case where none of these apply
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// GET events related to a job run
|
|
||||||
// e.g.
|
|
||||||
// ?event=playbook_on_stats
|
|
||||||
// ?parent=206&event__startswith=runner&page_size=200&order=host_name,counter
|
|
||||||
getRelatedJobEvents: function(id, params){
|
|
||||||
var url = GetBasePath('jobs');
|
|
||||||
url = url + id + '/job_events/?';
|
|
||||||
Object.keys(params).forEach(function(key, index) {
|
|
||||||
// the API is tolerant of extra ampersands
|
|
||||||
// ?&event=playbook_on_start == ?event=playbook_on_stats
|
|
||||||
url = url + '&' + key + '=' + params[key];
|
|
||||||
});
|
|
||||||
Rest.setUrl(url);
|
|
||||||
return Rest.get()
|
|
||||||
.success(function(data){
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
.error(function(data, status) {
|
|
||||||
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
|
||||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// GET job host summaries related to a job run
|
|
||||||
// e.g. ?page_size=200&order=host_name
|
|
||||||
getJobHostSummaries: function(id, params){
|
|
||||||
var url = GetBasePath('jobs');
|
|
||||||
url = url + id + '/job_host_summaries/?'
|
|
||||||
Object.keys(params).forEach(function(key, index) {
|
|
||||||
// the API is tolerant of extra ampersands
|
|
||||||
url = url + '&' + key + '=' + params[key];
|
|
||||||
});
|
|
||||||
Rest.setUrl(url);
|
|
||||||
return Rest.get()
|
|
||||||
.success(function(data){
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
.error(function(data, status) {
|
|
||||||
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
|
||||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// GET job plays related to a job run
|
|
||||||
// e.g. ?page_size=200
|
|
||||||
getJobPlays: function(id, params){
|
|
||||||
var url = GetBasePath('jobs');
|
|
||||||
url = url + id + '/job_plays/?';
|
|
||||||
Object.keys(params).forEach(function(key, index) {
|
|
||||||
// the API is tolerant of extra ampersands
|
|
||||||
url = url + '&' + key + '=' + params[key];
|
|
||||||
});
|
|
||||||
Rest.setUrl(url);
|
|
||||||
return Rest.get()
|
|
||||||
.success(function(data){
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
.error(function(data, status) {
|
|
||||||
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
|
||||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getJobTasks: function(id, params){
|
|
||||||
var url = GetBasePath('jobs');
|
|
||||||
url = url + id + '/job_tasks/?';
|
|
||||||
Object.keys(params).forEach(function(key, index) {
|
|
||||||
// the API is tolerant of extra ampersands
|
|
||||||
url = url + '&' + key + '=' + params[key];
|
|
||||||
});
|
|
||||||
Rest.setUrl(url);
|
|
||||||
return Rest.get()
|
|
||||||
.success(function(data){
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
.error(function(data, status) {
|
|
||||||
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
|
||||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getJob: function(id){
|
|
||||||
var url = GetBasePath('jobs');
|
|
||||||
url = url + id;
|
|
||||||
Rest.setUrl(url);
|
|
||||||
return Rest.get()
|
|
||||||
.success(function(data){
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
.error(function(data, status) {
|
|
||||||
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
|
||||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// GET next set of paginated results
|
|
||||||
// expects 'next' param returned by the API e.g.
|
|
||||||
// "/api/v1/jobs/51/job_plays/?order_by=id&page=2&page_size=1"
|
|
||||||
getNextPage: function(url){
|
|
||||||
return Rest.get()
|
|
||||||
.success(function(data){
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
.error(function(data, status) {
|
|
||||||
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
|
||||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
catch(err){return;}
|
||||||
}
|
},
|
||||||
];
|
// Generate a helper class for job_event statuses
|
||||||
|
// the stack for which status to display is
|
||||||
|
// unreachable > failed > changed > ok
|
||||||
|
// uses the API's runner events and convenience properties .failed .changed to determine status.
|
||||||
|
// see: job_event_callback.py for more filters to support
|
||||||
|
processEventStatus: function(event){
|
||||||
|
if (event.event === 'runner_on_unreachable'){
|
||||||
|
return {
|
||||||
|
class: 'HostEvents-status--unreachable',
|
||||||
|
status: 'unreachable'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// equiv to 'runner_on_error' && 'runner on failed'
|
||||||
|
if (event.failed){
|
||||||
|
return {
|
||||||
|
class: 'HostEvents-status--failed',
|
||||||
|
status: 'failed'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// catch the changed case before ok, because both can be true
|
||||||
|
if (event.changed){
|
||||||
|
return {
|
||||||
|
class: 'HostEvents-status--changed',
|
||||||
|
status: 'changed'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (event.event === 'runner_on_ok' || event.event === 'runner_on_async_ok'){
|
||||||
|
return {
|
||||||
|
class: 'HostEvents-status--ok',
|
||||||
|
status: 'ok'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (event.event === 'runner_on_skipped'){
|
||||||
|
return {
|
||||||
|
class: 'HostEvents-status--skipped',
|
||||||
|
status: 'skipped'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Consumes a response from this.getRelatedJobEvents(id, params)
|
||||||
|
// returns an array for view logic to iterate over to build host result rows
|
||||||
|
processHostEvents: function(data){
|
||||||
|
var self = this;
|
||||||
|
var results = [];
|
||||||
|
data.forEach(function(event){
|
||||||
|
if (event.event !== 'runner_on_no_hosts'){
|
||||||
|
var status = self.processEventStatus(event);
|
||||||
|
var msg = self.processEventMsg(event);
|
||||||
|
var item = self.processEventItem(event);
|
||||||
|
results.push({
|
||||||
|
id: event.id,
|
||||||
|
status: status.status,
|
||||||
|
status_text: _.head(status.status).toUpperCase() + _.tail(status.status),
|
||||||
|
host_id: event.host,
|
||||||
|
task_id: event.parent,
|
||||||
|
name: event.event_data.host,
|
||||||
|
created: event.created,
|
||||||
|
msg: typeof msg === 'undefined' ? undefined : msg,
|
||||||
|
item: typeof item === 'undefined' ? undefined : item
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
},
|
||||||
|
// GET events related to a job run
|
||||||
|
// e.g.
|
||||||
|
// ?event=playbook_on_stats
|
||||||
|
// ?parent=206&event__startswith=runner&page_size=200&order=host_name,counter
|
||||||
|
getRelatedJobEvents: function(id, params){
|
||||||
|
var url = GetBasePath('jobs');
|
||||||
|
url = url + id + '/job_events/?';
|
||||||
|
Object.keys(params).forEach(function(key, index) {
|
||||||
|
// the API is tolerant of extra ampersands
|
||||||
|
// ?&event=playbook_on_start == ?event=playbook_on_stats
|
||||||
|
url = url + '&' + key + '=' + params[key];
|
||||||
|
});
|
||||||
|
Rest.setUrl(url);
|
||||||
|
return Rest.get()
|
||||||
|
.success(function(data){
|
||||||
|
return data;
|
||||||
|
})
|
||||||
|
.error(function(data, status) {
|
||||||
|
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||||
|
msg: 'Call to ' + url + '. GET returned: ' + status });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getJobEventChildren: function(id){
|
||||||
|
var url = GetBasePath('job_events');
|
||||||
|
url = url + id + '/children/';
|
||||||
|
Rest.setUrl(url);
|
||||||
|
return Rest.get()
|
||||||
|
.success(function(data){
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
.error(function(data, status) {
|
||||||
|
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||||
|
msg: 'Call to ' + url + '. GET returned: ' + status });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// GET job host summaries related to a job run
|
||||||
|
// e.g. ?page_size=200&order=host_name
|
||||||
|
getJobHostSummaries: function(id, params){
|
||||||
|
var url = GetBasePath('jobs');
|
||||||
|
url = url + id + '/job_host_summaries/?';
|
||||||
|
Object.keys(params).forEach(function(key, index) {
|
||||||
|
// the API is tolerant of extra ampersands
|
||||||
|
url = url + '&' + key + '=' + params[key];
|
||||||
|
});
|
||||||
|
Rest.setUrl(url);
|
||||||
|
return Rest.get()
|
||||||
|
.success(function(data){
|
||||||
|
return data;
|
||||||
|
})
|
||||||
|
.error(function(data, status) {
|
||||||
|
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||||
|
msg: 'Call to ' + url + '. GET returned: ' + status });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// GET job plays related to a job run
|
||||||
|
// e.g. ?page_size=200
|
||||||
|
getJobPlays: function(id, params){
|
||||||
|
var url = GetBasePath('jobs');
|
||||||
|
url = url + id + '/job_plays/?';
|
||||||
|
Object.keys(params).forEach(function(key, index) {
|
||||||
|
// the API is tolerant of extra ampersands
|
||||||
|
url = url + '&' + key + '=' + params[key];
|
||||||
|
});
|
||||||
|
Rest.setUrl(url);
|
||||||
|
return Rest.get()
|
||||||
|
.success(function(data){
|
||||||
|
return data;
|
||||||
|
})
|
||||||
|
.error(function(data, status) {
|
||||||
|
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||||
|
msg: 'Call to ' + url + '. GET returned: ' + status });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getJobTasks: function(id, params){
|
||||||
|
var url = GetBasePath('jobs');
|
||||||
|
url = url + id + '/job_tasks/?';
|
||||||
|
Object.keys(params).forEach(function(key, index) {
|
||||||
|
// the API is tolerant of extra ampersands
|
||||||
|
url = url + '&' + key + '=' + params[key];
|
||||||
|
});
|
||||||
|
Rest.setUrl(url);
|
||||||
|
return Rest.get()
|
||||||
|
.success(function(data){
|
||||||
|
return data;
|
||||||
|
})
|
||||||
|
.error(function(data, status) {
|
||||||
|
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||||
|
msg: 'Call to ' + url + '. GET returned: ' + status });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getJob: function(id){
|
||||||
|
var url = GetBasePath('jobs');
|
||||||
|
url = url + id;
|
||||||
|
Rest.setUrl(url);
|
||||||
|
return Rest.get()
|
||||||
|
.success(function(data){
|
||||||
|
return data;
|
||||||
|
})
|
||||||
|
.error(function(data, status) {
|
||||||
|
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||||
|
msg: 'Call to ' + url + '. GET returned: ' + status });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// GET next set of paginated results
|
||||||
|
// expects 'next' param returned by the API e.g.
|
||||||
|
// "/api/v1/jobs/51/job_plays/?order_by=id&page=2&page_size=1"
|
||||||
|
getNextPage: function(url){
|
||||||
|
Rest.setUrl(url);
|
||||||
|
return Rest.get()
|
||||||
|
.success(function(data){
|
||||||
|
return data;
|
||||||
|
})
|
||||||
|
.error(function(data, status) {
|
||||||
|
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||||
|
msg: 'Call to ' + url + '. GET returned: ' + status });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}];
|
||||||
@@ -9,7 +9,7 @@ export default
|
|||||||
angular.module('AllJobsDefinition', ['sanitizeFilter', 'capitalizeFilter'])
|
angular.module('AllJobsDefinition', ['sanitizeFilter', 'capitalizeFilter'])
|
||||||
.value( 'AllJobsList', {
|
.value( 'AllJobsList', {
|
||||||
|
|
||||||
name: 'all_jobs',
|
name: 'jobs',
|
||||||
basePath: 'unified_jobs',
|
basePath: 'unified_jobs',
|
||||||
iterator: 'all_job',
|
iterator: 'all_job',
|
||||||
editTitle: 'All Jobs',
|
editTitle: 'All Jobs',
|
||||||
@@ -18,8 +18,9 @@ export default
|
|||||||
well: false,
|
well: false,
|
||||||
fields: {
|
fields: {
|
||||||
status: {
|
status: {
|
||||||
label: 'Status',
|
label: '',
|
||||||
columnClass: 'List-staticColumn--smallStatus',
|
searchLabel: 'Status',
|
||||||
|
columnClass: 'col-lg-1 col-md-1 col-sm-2 col-xs-2 List-staticColumn--smallStatus',
|
||||||
awToolTip: "{{ all_job.status_tip }}",
|
awToolTip: "{{ all_job.status_tip }}",
|
||||||
awTipPlacement: "right",
|
awTipPlacement: "right",
|
||||||
dataTitle: "{{ all_job.status_popover_title }}",
|
dataTitle: "{{ all_job.status_popover_title }}",
|
||||||
@@ -30,13 +31,10 @@ export default
|
|||||||
searchType: 'select',
|
searchType: 'select',
|
||||||
nosort: true,
|
nosort: true,
|
||||||
searchOptions: [
|
searchOptions: [
|
||||||
{ name: "Success", value: "successful" },
|
|
||||||
{ name: "Error", value: "error" },
|
|
||||||
{ name: "Failed", value: "failed" },
|
|
||||||
{ name: "Canceled", value: "canceled" }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
id: {
|
id: {
|
||||||
|
key: true,
|
||||||
label: 'ID',
|
label: 'ID',
|
||||||
ngClick:"viewJobDetails(all_job)",
|
ngClick:"viewJobDetails(all_job)",
|
||||||
searchType: 'int',
|
searchType: 'int',
|
||||||
@@ -45,6 +43,7 @@ export default
|
|||||||
dataPlacement: 'top'
|
dataPlacement: 'top'
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
|
key: true,
|
||||||
label: 'Name',
|
label: 'Name',
|
||||||
columnClass: 'col-lg-3 col-md-3 col-sm-4 col-xs-6',
|
columnClass: 'col-lg-3 col-md-3 col-sm-4 col-xs-6',
|
||||||
ngClick: "viewJobDetails(all_job)",
|
ngClick: "viewJobDetails(all_job)",
|
||||||
|
|||||||
@@ -11,14 +11,12 @@ export default
|
|||||||
|
|
||||||
name: 'job_templates',
|
name: 'job_templates',
|
||||||
iterator: 'job_template',
|
iterator: 'job_template',
|
||||||
// selectTitle: 'Add Job Template',
|
|
||||||
editTitle: 'Job Templates',
|
editTitle: 'Job Templates',
|
||||||
listTitle: 'Job Templates',
|
listTitle: 'Job Templates',
|
||||||
// selectInstructions: "Click on a row to select it, and click Finished when done. Use the <i class=\"icon-plus\"></i> " +
|
|
||||||
// "button to create a new job template.",
|
|
||||||
index: false,
|
index: false,
|
||||||
hover: true,
|
hover: true,
|
||||||
well: true,
|
well: true,
|
||||||
|
searchSize: 'col-lg-8 col-md-8 col-sm-12 col-xs-12',
|
||||||
|
|
||||||
fields: {
|
fields: {
|
||||||
name: {
|
name: {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export default
|
|||||||
hover: true,
|
hover: true,
|
||||||
well: true,
|
well: true,
|
||||||
listTitle: 'Jobs',
|
listTitle: 'Jobs',
|
||||||
|
searchSize: 'col-lg-8 col-md-8 col-sm-12 col-xs-12',
|
||||||
|
|
||||||
fields: {
|
fields: {
|
||||||
status: {
|
status: {
|
||||||
@@ -27,23 +28,9 @@ export default
|
|||||||
searchable: true,
|
searchable: true,
|
||||||
nosort: true,
|
nosort: true,
|
||||||
searchType: 'select',
|
searchType: 'select',
|
||||||
searchOptions: [
|
searchOptions: [],
|
||||||
{ name: "Success", value: "successful" },
|
searchLabel: 'Status'
|
||||||
{ name: "Error", value: "error" },
|
|
||||||
{ name: "Failed", value: "failed" },
|
|
||||||
{ name: "Canceled", value: "canceled" }
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
/*
|
|
||||||
id: {
|
|
||||||
label: 'ID',
|
|
||||||
key: true,
|
|
||||||
noLink: true, //undocumented: 'key' above will automatically made the fields a link, but 'noLink' will override this setting
|
|
||||||
desc: true,
|
|
||||||
searchType: 'int',
|
|
||||||
columnClass: 'col-xs-2 List-staticColumnAdjacent',
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
name: {
|
name: {
|
||||||
key: true,
|
key: true,
|
||||||
label: 'Name',
|
label: 'Name',
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export default
|
|||||||
filter: "longDate",
|
filter: "longDate",
|
||||||
searchable: false,
|
searchable: false,
|
||||||
columnClass: "List-staticColumn--schedulerTime hidden-xs"
|
columnClass: "List-staticColumn--schedulerTime hidden-xs"
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@@ -51,9 +51,6 @@ export default
|
|||||||
if (scope.searchCleanup) {
|
if (scope.searchCleanup) {
|
||||||
scope.searchCleanup();
|
scope.searchCleanup();
|
||||||
}
|
}
|
||||||
// if (!Empty(parent_scope) && parent_scope.restoreSearch) {
|
|
||||||
// parent_scope.restoreSearch();
|
|
||||||
// }
|
|
||||||
else {
|
else {
|
||||||
Wait('stop');
|
Wait('stop');
|
||||||
}
|
}
|
||||||
@@ -69,6 +66,7 @@ export default
|
|||||||
height: 470,
|
height: 470,
|
||||||
minWidth: 200,
|
minWidth: 200,
|
||||||
callback: 'PromptForDaysFacts',
|
callback: 'PromptForDaysFacts',
|
||||||
|
resizable: false,
|
||||||
onOpen: function(){
|
onOpen: function(){
|
||||||
scope.$watch('prompt_for_days_facts_form.$invalid', function(invalid) {
|
scope.$watch('prompt_for_days_facts_form.$invalid', function(invalid) {
|
||||||
if (invalid === true) {
|
if (invalid === true) {
|
||||||
@@ -113,41 +111,40 @@ export default
|
|||||||
fieldScope.keep_amount = 30;
|
fieldScope.keep_amount = 30;
|
||||||
fieldScope.granularity_keep_amount = 1;
|
fieldScope.granularity_keep_amount = 1;
|
||||||
},
|
},
|
||||||
buttons: [{
|
buttons: [
|
||||||
"label": "Cancel",
|
{
|
||||||
"onClick": function() {
|
"label": "Launch",
|
||||||
$(this).dialog('close');
|
"onClick": function() {
|
||||||
|
var extra_vars = {
|
||||||
|
"older_than": scope.keep_amount+scope.keep_unit.value,
|
||||||
|
"granularity": scope.granularity_keep_amount+scope.granularity_keep_unit.value
|
||||||
|
},
|
||||||
|
data = {};
|
||||||
|
data.extra_vars = JSON.stringify(extra_vars);
|
||||||
|
|
||||||
},
|
Rest.setUrl(defaultUrl);
|
||||||
"icon": "fa-times",
|
Rest.post(data)
|
||||||
"class": "btn btn-default",
|
.success(function() {
|
||||||
"id": "prompt-for-days-facts-cancel"
|
Wait('stop');
|
||||||
},{
|
$("#prompt-for-days-facts").dialog("close");
|
||||||
"label": "Launch",
|
$("#configure-tower-dialog").dialog('close');
|
||||||
"onClick": function() {
|
$location.path('/jobs/');
|
||||||
var extra_vars = {
|
})
|
||||||
"older_than": scope.keep_amount+scope.keep_unit.value,
|
.error(function(data, status) {
|
||||||
"granularity": scope.granularity_keep_amount+scope.granularity_keep_unit.value
|
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||||
|
msg: 'Failed updating job ' + scope.job_template_id + ' with variables. POST returned: ' + status });
|
||||||
|
});
|
||||||
},
|
},
|
||||||
data = {};
|
"class": "btn btn-primary",
|
||||||
data.extra_vars = JSON.stringify(extra_vars);
|
"id": "prompt-for-days-facts-launch",
|
||||||
|
|
||||||
Rest.setUrl(defaultUrl);
|
|
||||||
Rest.post(data)
|
|
||||||
.success(function() {
|
|
||||||
Wait('stop');
|
|
||||||
$("#prompt-for-days-facts").dialog("close");
|
|
||||||
$("#configure-tower-dialog").dialog('close');
|
|
||||||
$location.path('/jobs/');
|
|
||||||
})
|
|
||||||
.error(function(data, status) {
|
|
||||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
|
||||||
msg: 'Failed updating job ' + scope.job_template_id + ' with variables. POST returned: ' + status });
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
"icon": "fa-rocket",
|
{
|
||||||
"class": "btn btn-primary",
|
"label": "Cancel",
|
||||||
"id": "prompt-for-days-facts-launch"
|
"onClick": function() {
|
||||||
|
$(this).dialog('close');
|
||||||
|
},
|
||||||
|
"class": "btn btn-default",
|
||||||
|
"id": "prompt-for-days-facts-cancel"
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -162,12 +159,8 @@ export default
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.submitJob = function (id, name) {
|
$scope.submitJob = function (id, name, card) {
|
||||||
Wait('start');
|
Wait('start');
|
||||||
if(this.configure_job.job_type === "cleanup_facts"){
|
|
||||||
scope.submitCleanupJob(id, name);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
defaultUrl = GetBasePath('system_job_templates')+id+'/launch/';
|
defaultUrl = GetBasePath('system_job_templates')+id+'/launch/';
|
||||||
CreateDialog({
|
CreateDialog({
|
||||||
id: 'prompt-for-days' ,
|
id: 'prompt-for-days' ,
|
||||||
@@ -177,6 +170,7 @@ export default
|
|||||||
height: 300,
|
height: 300,
|
||||||
minWidth: 200,
|
minWidth: 200,
|
||||||
callback: 'PromptForDays',
|
callback: 'PromptForDays',
|
||||||
|
resizable: false,
|
||||||
onOpen: function(){
|
onOpen: function(){
|
||||||
scope.$watch('prompt_for_days_form.$invalid', function(invalid) {
|
scope.$watch('prompt_for_days_form.$invalid', function(invalid) {
|
||||||
if (invalid === true) {
|
if (invalid === true) {
|
||||||
@@ -191,16 +185,8 @@ export default
|
|||||||
scope.prompt_for_days_form.$setPristine();
|
scope.prompt_for_days_form.$setPristine();
|
||||||
scope.prompt_for_days_form.$invalid = false;
|
scope.prompt_for_days_form.$invalid = false;
|
||||||
},
|
},
|
||||||
buttons: [{
|
buttons: [
|
||||||
"label": "Cancel",
|
{
|
||||||
"onClick": function() {
|
|
||||||
$(this).dialog('close');
|
|
||||||
|
|
||||||
},
|
|
||||||
"icon": "fa-times",
|
|
||||||
"class": "btn btn-default",
|
|
||||||
"id": "prompt-for-days-cancel"
|
|
||||||
},{
|
|
||||||
"label": "Launch",
|
"label": "Launch",
|
||||||
"onClick": function() {
|
"onClick": function() {
|
||||||
var extra_vars = {"days": scope.days_to_keep },
|
var extra_vars = {"days": scope.days_to_keep },
|
||||||
@@ -220,9 +206,17 @@ export default
|
|||||||
msg: 'Failed updating job ' + scope.job_template_id + ' with variables. POST returned: ' + status });
|
msg: 'Failed updating job ' + scope.job_template_id + ' with variables. POST returned: ' + status });
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"icon": "fa-rocket",
|
|
||||||
"class": "btn btn-primary",
|
"class": "btn btn-primary",
|
||||||
"id": "prompt-for-days-launch"
|
"id": "prompt-for-days-launch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Cancel",
|
||||||
|
"onClick": function() {
|
||||||
|
$(this).dialog('close');
|
||||||
|
|
||||||
|
},
|
||||||
|
"class": "btn btn-default",
|
||||||
|
"id": "prompt-for-days-cancel"
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -235,6 +229,14 @@ export default
|
|||||||
$('#prompt-for-days').dialog('open');
|
$('#prompt-for-days').dialog('open');
|
||||||
Wait('stop');
|
Wait('stop');
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.chooseRunJob = function(id, name) {
|
||||||
|
if(id === 4) {
|
||||||
|
// Run only for 'Cleanup Fact Details'
|
||||||
|
$scope.submitCleanupJob(id, name);
|
||||||
|
} else {
|
||||||
|
$scope.submitJob(id, name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<h3 class="MgmtCards-label"> {{ card.name }}</h3>
|
<h3 class="MgmtCards-label"> {{ card.name }}</h3>
|
||||||
<div class="MgmtCards-actionItems">
|
<div class="MgmtCards-actionItems">
|
||||||
<button class="MgmtCards-actionItem List-actionButton"
|
<button class="MgmtCards-actionItem List-actionButton"
|
||||||
ng-click='submitCleanupJob(card.id, card.name)'>
|
ng-click='chooseRunJob(card.id, card.name)'>
|
||||||
<i class="MgmtCards-actionItemIcon fa fa-rocket"></i>
|
<i class="MgmtCards-actionItemIcon fa fa-rocket"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="MgmtCards-actionItem List-actionButton"
|
<button class="MgmtCards-actionItem List-actionButton"
|
||||||
|
|||||||
@@ -114,3 +114,12 @@
|
|||||||
margin-right: 0px;
|
margin-right: 0px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#prompt-for-days-facts, #prompt-for-days {
|
||||||
|
overflow-x: hidden;
|
||||||
|
font-family: "Open Sans";
|
||||||
|
.label-text {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -155,13 +155,13 @@ export default
|
|||||||
Rest.post({})
|
Rest.post({})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
ngToast.success({
|
ngToast.success({
|
||||||
content: `<i class="fa fa-check-circle Toast-successIcon"></i> Test Notification Success: <b>${name}</b> `,
|
content: `<i class="fa fa-check-circle Toast-successIcon"></i> <b>${name}:</b> Notification Succeeded.`,
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
ngToast.danger({
|
ngToast.danger({
|
||||||
content: 'Test Notification Failure'
|
content: `<i class="fa fa-check-circle Toast-successIcon"></i> <b>${name}:</b> Notification Failed.`,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ export function PortalModeJobsController($scope, $state, $rootScope, GetBasePath
|
|||||||
id: 'portal-jobs',
|
id: 'portal-jobs',
|
||||||
mode: 'edit',
|
mode: 'edit',
|
||||||
scope: $scope,
|
scope: $scope,
|
||||||
searchSize: 'col-md-10 col-xs-12'
|
|
||||||
});
|
});
|
||||||
|
|
||||||
SearchInit({
|
SearchInit({
|
||||||
|
|||||||
@@ -34,7 +34,15 @@ export default
|
|||||||
resolve: {
|
resolve: {
|
||||||
features: ['FeaturesService', function(FeaturesService) {
|
features: ['FeaturesService', function(FeaturesService) {
|
||||||
return FeaturesService.get();
|
return FeaturesService.get();
|
||||||
}]
|
}],
|
||||||
|
JobTemplateExtraVars: ['Rest', 'GetBasePath', 'ToJSON', '$stateParams', function(Rest, GetBasePath, ToJSON, $stateParams) {
|
||||||
|
var defaultUrl = GetBasePath('job_templates') + $stateParams.id + '/';
|
||||||
|
Rest.setUrl(defaultUrl);
|
||||||
|
return Rest.get().then(function(res){
|
||||||
|
// handle unescaped newlines
|
||||||
|
return JSON.parse(JSON.stringify(res.data.extra_vars))
|
||||||
|
});
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$stateExtender.addState({
|
$stateExtender.addState({
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export default ['$compile', '$state', '$stateParams', 'AddSchedule', 'Wait', '$scope', '$rootScope', 'CreateSelect2', function($compile, $state, $stateParams, AddSchedule, Wait, $scope, $rootScope, CreateSelect2) {
|
export default ['$compile', '$state', '$stateParams', 'AddSchedule', 'Wait', '$scope', '$rootScope', 'CreateSelect2', 'ParseTypeChange', 'JobTemplateExtraVars', function($compile, $state, $stateParams, AddSchedule, Wait, $scope, $rootScope, CreateSelect2, ParseTypeChange, JobTemplateExtraVars) {
|
||||||
$scope.$on("ScheduleFormCreated", function(e, scope) {
|
$scope.$on("ScheduleFormCreated", function(e, scope) {
|
||||||
$scope.hideForm = false;
|
$scope.hideForm = false;
|
||||||
$scope = angular.extend($scope, scope);
|
$scope = angular.extend($scope, scope);
|
||||||
@@ -41,10 +41,35 @@ export default ['$compile', '$state', '$stateParams', 'AddSchedule', 'Wait', '$s
|
|||||||
|
|
||||||
$scope.hideForm = true;
|
$scope.hideForm = true;
|
||||||
|
|
||||||
|
|
||||||
$scope.formCancel = function() {
|
$scope.formCancel = function() {
|
||||||
$state.go("^");
|
$state.go("^");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.parseType = 'yaml';
|
||||||
|
$scope.extraVars = JobTemplateExtraVars === '' ? '---' : JobTemplateExtraVars;
|
||||||
|
ParseTypeChange({
|
||||||
|
scope: $scope,
|
||||||
|
variable: 'extraVars',
|
||||||
|
parse_variable: 'parseType',
|
||||||
|
field_id: 'SchedulerForm-extraVars'
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.$watch('extraVars', function(){
|
||||||
|
if ($scope.parseType === 'yaml'){
|
||||||
|
try{
|
||||||
|
$scope.serializedExtraVars = jsyaml.safeLoad($scope.extraVars);
|
||||||
|
}
|
||||||
|
catch(err){ return; }
|
||||||
|
}
|
||||||
|
else if ($scope.parseType === 'json'){
|
||||||
|
try{
|
||||||
|
$scope.serializedExtraVars = JSON.parse($scope.extraVars);
|
||||||
|
}
|
||||||
|
catch(err){ return; }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
AddSchedule({
|
AddSchedule({
|
||||||
scope: $scope,
|
scope: $scope,
|
||||||
callback: 'SchedulesRefresh',
|
callback: 'SchedulesRefresh',
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export default ['$compile', '$state', '$stateParams', 'EditSchedule', 'Wait', '$scope', '$rootScope', 'CreateSelect2', function($compile, $state, $stateParams, EditSchedule, Wait, $scope, $rootScope, CreateSelect2) {
|
export default ['$compile', '$state', '$stateParams', 'EditSchedule', 'Wait', '$scope', '$rootScope', 'CreateSelect2', 'ParseTypeChange', function($compile, $state, $stateParams, EditSchedule, Wait, $scope, $rootScope, CreateSelect2, ParseTypeChange) {
|
||||||
$scope.$on("ScheduleFormCreated", function(e, scope) {
|
$scope.$on("ScheduleFormCreated", function(e, scope) {
|
||||||
$scope.hideForm = false;
|
$scope.hideForm = false;
|
||||||
$scope = angular.extend($scope, scope);
|
$scope = angular.extend($scope, scope);
|
||||||
@@ -41,13 +41,49 @@ export default ['$compile', '$state', '$stateParams', 'EditSchedule', 'Wait', '$
|
|||||||
});
|
});
|
||||||
|
|
||||||
$scope.isEdit = true;
|
$scope.isEdit = true;
|
||||||
|
|
||||||
$scope.hideForm = true;
|
$scope.hideForm = true;
|
||||||
|
$scope.parseType = 'yaml';
|
||||||
|
|
||||||
$scope.formCancel = function() {
|
$scope.formCancel = function() {
|
||||||
$state.go("^");
|
$state.go("^");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$scope.$on('ScheduleFound', function(){
|
||||||
|
if ($scope.parseType === 'yaml'){
|
||||||
|
try{
|
||||||
|
$scope.extraVars = '---\n' + jsyaml.safeDump($scope.serializedExtraVars);
|
||||||
|
}
|
||||||
|
catch(err){ return; }
|
||||||
|
}
|
||||||
|
else if ($scope.parseType === 'json'){
|
||||||
|
try{
|
||||||
|
$scope.extraVars = JSON.stringify($scope.serializedExtraVars, null, ' ');
|
||||||
|
}
|
||||||
|
catch(err){ return; }
|
||||||
|
}
|
||||||
|
ParseTypeChange({
|
||||||
|
scope: $scope,
|
||||||
|
variable: 'extraVars',
|
||||||
|
parse_variable: 'parseType',
|
||||||
|
field_id: 'SchedulerForm-extraVars'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.$watch('extraVars', function(){
|
||||||
|
if ($scope.parseType === 'yaml'){
|
||||||
|
try{
|
||||||
|
$scope.serializedExtraVars = jsyaml.safeLoad($scope.extraVars);
|
||||||
|
}
|
||||||
|
catch(err){ return; }
|
||||||
|
}
|
||||||
|
else if ($scope.parseType === 'json'){
|
||||||
|
try{
|
||||||
|
$scope.serializedExtraVars = JSON.parse($scope.extraVars);
|
||||||
|
}
|
||||||
|
catch(err){ return; }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
EditSchedule({
|
EditSchedule({
|
||||||
scope: $scope,
|
scope: $scope,
|
||||||
id: parseInt($stateParams.schedule_id),
|
id: parseInt($stateParams.schedule_id),
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,8 @@ export default ['$scope', 'Refresh', 'tagSearchService',
|
|||||||
function($scope, Refresh, tagSearchService) {
|
function($scope, Refresh, tagSearchService) {
|
||||||
// JSONify passed field elements that can be searched
|
// JSONify passed field elements that can be searched
|
||||||
$scope.list = JSON.parse($scope.list);
|
$scope.list = JSON.parse($scope.list);
|
||||||
|
// Access config lines from list spec
|
||||||
|
$scope.listConfig = $scope.$parent.list;
|
||||||
// Grab options for the left-dropdown of the searchbar
|
// Grab options for the left-dropdown of the searchbar
|
||||||
tagSearchService.getSearchTypes($scope.list, $scope.endpoint)
|
tagSearchService.getSearchTypes($scope.list, $scope.endpoint)
|
||||||
.then(function(searchTypes) {
|
.then(function(searchTypes) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<div class="TagSearch row">
|
<div class="TagSearch row">
|
||||||
<div class="col-lg-4 col-md-8 col-sm-12 col-xs-12">
|
<div ng-class="listConfig.searchSize || 'col-lg-4 col-md-8 col-sm-12 col-xs-12'">
|
||||||
<div class="TagSearch-bar">
|
<div class="TagSearch-bar">
|
||||||
<div class="TagSearch-typeDropdown"
|
<div class="TagSearch-typeDropdown"
|
||||||
ng-click="toggleTypeDropdown()"
|
ng-click="toggleTypeDropdown()"
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ angular.module('ApiLoader', ['Utilities'])
|
|||||||
.success(function (data) {
|
.success(function (data) {
|
||||||
data.base = base;
|
data.base = base;
|
||||||
$rootScope.defaultUrls = data;
|
$rootScope.defaultUrls = data;
|
||||||
|
// tiny hack to side-step api/v1/job_events not being a visible endpoint @ GET api/v1/
|
||||||
|
if (!$rootScope.defaultUrls['job_events']){
|
||||||
|
$rootScope.defaultUrls['job_events'] = '/api/v1/job_events/';
|
||||||
|
}
|
||||||
Store('api', data);
|
Store('api', data);
|
||||||
})
|
})
|
||||||
.error(function (data, status) {
|
.error(function (data, status) {
|
||||||
|
|||||||
@@ -171,10 +171,11 @@
|
|||||||
<div style="padding-bottom:15px;">For facts collected older than the time period specified,
|
<div style="padding-bottom:15px;">For facts collected older than the time period specified,
|
||||||
save one fact scan (snapshot) per time window (frequency).
|
save one fact scan (snapshot) per time window (frequency).
|
||||||
For example, facts older than 30 days are purged, while one
|
For example, facts older than 30 days are purged, while one
|
||||||
weekly fact scan is kept.<br>
|
weekly fact scan is kept.<br> <br>
|
||||||
Caution: Setting both numerical variables to "0" will delete all facts.<br>
|
|
||||||
|
CAUTION: Setting both numerical variables to "0" will delete all facts.<br><br>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group ">
|
<div class="form-group">
|
||||||
<label for="description">
|
<label for="description">
|
||||||
<span class="label-text">
|
<span class="label-text">
|
||||||
Select a time period after which to remove old facts
|
Select a time period after which to remove old facts
|
||||||
|
|||||||
Reference in New Issue
Block a user