mirror of
https://github.com/ansible/awx.git
synced 2026-05-19 23:07:42 -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,
|
||||||
@@ -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)
|
||||||
// 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;
|
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);
|
schedule.extra_data = JSON.stringify(extra_vars);
|
||||||
|
}
|
||||||
|
else if (scope.serializedExtraVars){
|
||||||
|
schedule.extra_data = scope.serializedExtraVars;
|
||||||
|
}
|
||||||
Rest.setUrl(url);
|
Rest.setUrl(url);
|
||||||
if (mode === 'add') {
|
if (mode === 'add') {
|
||||||
Rest.post(schedule)
|
Rest.post(schedule)
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
<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">
|
||||||
|
|||||||
@@ -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,63 +4,71 @@
|
|||||||
* 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){
|
||||||
|
|
||||||
|
$scope.processEventStatus = JobDetailService.processEventStatus;
|
||||||
|
$scope.hostResults = [];
|
||||||
// Avoid rendering objects in the details fieldset
|
// Avoid rendering objects in the details fieldset
|
||||||
// ng-if="processResults(value)" via host-event-details.partial.html
|
// ng-if="processResults(value)" via host-event-details.partial.html
|
||||||
$scope.processResults = function(value){
|
$scope.processResults = function(value){
|
||||||
if (typeof value == 'object'){return false}
|
if (typeof value == 'object'){return false;}
|
||||||
else {return true}
|
else {return true;}
|
||||||
};
|
};
|
||||||
|
|
||||||
var codeMirror = function(){
|
var codeMirror = function(el, json){
|
||||||
var el = $('#HostEvent-json')[0];
|
var container = $(el)[0];
|
||||||
var editor = CodeMirror.fromTextArea(el, {
|
var editor = CodeMirror.fromTextArea(container, {
|
||||||
lineNumbers: true,
|
lineNumbers: true,
|
||||||
mode: {name: "javascript", json: true}
|
mode: {name: "javascript", json: true}
|
||||||
});
|
});
|
||||||
editor.getDoc().setValue(JSON.stringify($scope.json, null, 4));
|
editor.setSize("100%", 300)
|
||||||
|
editor.getDoc().setValue(JSON.stringify(json, null, 4));
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.getActiveHostIndex = function(){
|
$scope.getActiveHostIndex = function(){
|
||||||
var result = $scope.hostResults.filter(function( obj ) {
|
var result = $scope.hostResults.filter(function( obj ) {
|
||||||
return obj.id == $scope.event.id;
|
return obj.id == $scope.event.id;
|
||||||
});
|
});
|
||||||
return $scope.hostResults.indexOf(result[0])
|
return $scope.hostResults.indexOf(result[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.showPrev = function(){
|
$scope.showPrev = function(){
|
||||||
return $scope.getActiveHostIndex() != 0
|
return $scope.getActiveHostIndex() != 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.showNext = function(){
|
$scope.showNext = function(){
|
||||||
return $scope.getActiveHostIndex() < $scope.hostResults.indexOf($scope.hostResults[$scope.hostResults.length - 1])
|
return $scope.getActiveHostIndex() < $scope.hostResults.indexOf($scope.hostResults[$scope.hostResults.length - 1]);
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.goNext = 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});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.goPrev = function(){
|
$scope.goPrev = 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(){
|
var init = function(){
|
||||||
$scope.event = event.data.results[0];
|
$scope.event = event;
|
||||||
$scope.event.created = moment($scope.event.created).format();
|
JobDetailService.getJobEventChildren($stateParams.taskId).success(function(res){
|
||||||
$scope.processEventStatus = JobDetailService.processEventStatus($scope.event);
|
$scope.hostResults = res.results;
|
||||||
$scope.hostResults = $stateParams.hostResults;
|
});
|
||||||
$scope.json = JobDetailService.processJson($scope.event);
|
$scope.json = JobDetailService.processJson($scope.event);
|
||||||
if ($state.current.name == 'jobDetail.host-event.json'){
|
if ($state.current.name == 'jobDetail.host-event.json'){
|
||||||
codeMirror();
|
codeMirror('#HostEvent-json', $scope.json);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$scope.stdout = $scope.event.event_data.res.stdout
|
$scope.stdout = JobDetailService.processJson($scope.event.event_data.res)
|
||||||
|
if ($state.current.name == 'jobDetail.host-event.stdout'){
|
||||||
|
codeMirror('#HostEvent-stdout', $scope.stdout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(err){
|
catch(err){
|
||||||
$scope.sdout = null;
|
$scope.sdout = null;
|
||||||
|
|||||||
@@ -8,23 +8,20 @@
|
|||||||
|
|
||||||
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){
|
||||||
@@ -35,52 +32,27 @@ var hostEventModal = {
|
|||||||
$('.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,73 +244,19 @@ 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) {
|
||||||
@@ -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,76 +388,11 @@
|
|||||||
</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 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>
|
</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>
|
|
||||||
<!-- 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,16 +3,15 @@ export default
|
|||||||
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,51 +36,93 @@ 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
|
||||||
|
processEventMsg: function(event){
|
||||||
|
return typeof event.event_data.res === 'object' ? event.event_data.res.msg : event.event_data.res;
|
||||||
|
},
|
||||||
|
// Return only Ansible's passed-through response item on a job_event
|
||||||
|
processEventItem: function(event){
|
||||||
|
try{
|
||||||
|
var item = event.event_data.res.item;
|
||||||
|
return typeof item === 'object' ? JSON.stringify(item) : item;
|
||||||
|
}
|
||||||
|
catch(err){return;}
|
||||||
},
|
},
|
||||||
|
|
||||||
processEventStatus: function(event){
|
|
||||||
// Generate a helper class for job_event statuses
|
// Generate a helper class for job_event statuses
|
||||||
// the stack for which status to display is
|
// the stack for which status to display is
|
||||||
// unreachable > failed > changed > ok
|
// unreachable > failed > changed > ok
|
||||||
// uses the API's runner events and convenience properties .failed .changed to determine status.
|
// uses the API's runner events and convenience properties .failed .changed to determine status.
|
||||||
// see: job_event_callback.py
|
// see: job_event_callback.py for more filters to support
|
||||||
if (event.event == 'runner_on_unreachable'){
|
processEventStatus: function(event){
|
||||||
event.status = 'Unreachable';
|
if (event.event === 'runner_on_unreachable'){
|
||||||
return 'HostEvents-status--unreachable'
|
return {
|
||||||
|
class: 'HostEvents-status--unreachable',
|
||||||
|
status: 'unreachable'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
// equiv to 'runner_on_error' && 'runner on failed'
|
// equiv to 'runner_on_error' && 'runner on failed'
|
||||||
if (event.failed){
|
if (event.failed){
|
||||||
event.status = 'Failed';
|
return {
|
||||||
return 'HostEvents-status--failed'
|
class: 'HostEvents-status--failed',
|
||||||
|
status: 'failed'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// catch the changed case before ok, because both can be true
|
// catch the changed case before ok, because both can be true
|
||||||
if (event.changed){
|
if (event.changed){
|
||||||
event.status = 'Changed';
|
return {
|
||||||
return 'HostEvents-status--changed'
|
class: 'HostEvents-status--changed',
|
||||||
|
status: 'changed'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (event.event == 'runner_on_ok'){
|
if (event.event === 'runner_on_ok' || event.event === 'runner_on_async_ok'){
|
||||||
event.status = 'OK';
|
return {
|
||||||
return 'HostEvents-status--ok'
|
class: 'HostEvents-status--ok',
|
||||||
|
status: 'ok'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (event.event == 'runner_on_skipped'){
|
if (event.event === 'runner_on_skipped'){
|
||||||
event.status = 'Skipped';
|
return {
|
||||||
return 'HostEvents-status--skipped'
|
class: 'HostEvents-status--skipped',
|
||||||
}
|
status: 'skipped'
|
||||||
else{
|
};
|
||||||
// study a case where none of these apply
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// 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
|
// GET events related to a job run
|
||||||
// e.g.
|
// e.g.
|
||||||
// ?event=playbook_on_stats
|
// ?event=playbook_on_stats
|
||||||
@@ -95,6 +136,19 @@ export default
|
|||||||
url = url + '&' + key + '=' + params[key];
|
url = url + '&' + key + '=' + params[key];
|
||||||
});
|
});
|
||||||
Rest.setUrl(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 });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getJobEventChildren: function(id){
|
||||||
|
var url = GetBasePath('job_events');
|
||||||
|
url = url + id + '/children/';
|
||||||
|
Rest.setUrl(url);
|
||||||
return Rest.get()
|
return Rest.get()
|
||||||
.success(function(data){
|
.success(function(data){
|
||||||
return data
|
return data
|
||||||
@@ -108,7 +162,7 @@ export default
|
|||||||
// e.g. ?page_size=200&order=host_name
|
// e.g. ?page_size=200&order=host_name
|
||||||
getJobHostSummaries: function(id, params){
|
getJobHostSummaries: function(id, params){
|
||||||
var url = GetBasePath('jobs');
|
var url = GetBasePath('jobs');
|
||||||
url = url + id + '/job_host_summaries/?'
|
url = url + id + '/job_host_summaries/?';
|
||||||
Object.keys(params).forEach(function(key, index) {
|
Object.keys(params).forEach(function(key, index) {
|
||||||
// the API is tolerant of extra ampersands
|
// the API is tolerant of extra ampersands
|
||||||
url = url + '&' + key + '=' + params[key];
|
url = url + '&' + key + '=' + params[key];
|
||||||
@@ -116,7 +170,7 @@ export default
|
|||||||
Rest.setUrl(url);
|
Rest.setUrl(url);
|
||||||
return Rest.get()
|
return Rest.get()
|
||||||
.success(function(data){
|
.success(function(data){
|
||||||
return data
|
return data;
|
||||||
})
|
})
|
||||||
.error(function(data, status) {
|
.error(function(data, status) {
|
||||||
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||||
@@ -135,7 +189,7 @@ export default
|
|||||||
Rest.setUrl(url);
|
Rest.setUrl(url);
|
||||||
return Rest.get()
|
return Rest.get()
|
||||||
.success(function(data){
|
.success(function(data){
|
||||||
return data
|
return data;
|
||||||
})
|
})
|
||||||
.error(function(data, status) {
|
.error(function(data, status) {
|
||||||
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||||
@@ -152,7 +206,7 @@ export default
|
|||||||
Rest.setUrl(url);
|
Rest.setUrl(url);
|
||||||
return Rest.get()
|
return Rest.get()
|
||||||
.success(function(data){
|
.success(function(data){
|
||||||
return data
|
return data;
|
||||||
})
|
})
|
||||||
.error(function(data, status) {
|
.error(function(data, status) {
|
||||||
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||||
@@ -165,7 +219,7 @@ export default
|
|||||||
Rest.setUrl(url);
|
Rest.setUrl(url);
|
||||||
return Rest.get()
|
return Rest.get()
|
||||||
.success(function(data){
|
.success(function(data){
|
||||||
return data
|
return data;
|
||||||
})
|
})
|
||||||
.error(function(data, status) {
|
.error(function(data, status) {
|
||||||
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||||
@@ -176,15 +230,15 @@ export default
|
|||||||
// expects 'next' param returned by the API e.g.
|
// expects 'next' param returned by the API e.g.
|
||||||
// "/api/v1/jobs/51/job_plays/?order_by=id&page=2&page_size=1"
|
// "/api/v1/jobs/51/job_plays/?order_by=id&page=2&page_size=1"
|
||||||
getNextPage: function(url){
|
getNextPage: function(url){
|
||||||
|
Rest.setUrl(url);
|
||||||
return Rest.get()
|
return Rest.get()
|
||||||
.success(function(data){
|
.success(function(data){
|
||||||
return data
|
return data;
|
||||||
})
|
})
|
||||||
.error(function(data, status) {
|
.error(function(data, status) {
|
||||||
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!',
|
||||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
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,16 +111,8 @@ 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() {
|
|
||||||
$(this).dialog('close');
|
|
||||||
|
|
||||||
},
|
|
||||||
"icon": "fa-times",
|
|
||||||
"class": "btn btn-default",
|
|
||||||
"id": "prompt-for-days-facts-cancel"
|
|
||||||
},{
|
|
||||||
"label": "Launch",
|
"label": "Launch",
|
||||||
"onClick": function() {
|
"onClick": function() {
|
||||||
var extra_vars = {
|
var extra_vars = {
|
||||||
@@ -145,9 +135,16 @@ 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-facts-launch"
|
"id": "prompt-for-days-facts-launch",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Cancel",
|
||||||
|
"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,6 +34,14 @@ 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))
|
||||||
|
});
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="SchedulerFormTarget">
|
<div id="SchedulerFormTarget">
|
||||||
|
|
||||||
<form class="form Form"
|
<form class="form Form"
|
||||||
role="form"
|
role="form"
|
||||||
name="scheduler_form_new"
|
name="scheduler_form_new"
|
||||||
@@ -526,47 +525,6 @@
|
|||||||
<div class="RepeatFrequencyOptions-subFormBorderFixer"
|
<div class="RepeatFrequencyOptions-subFormBorderFixer"
|
||||||
ng-show="schedulerFrequency.value && schedulerFrequency.value !== 'none'">
|
ng-show="schedulerFrequency.value && schedulerFrequency.value !== 'none'">
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="factDetailsNote" ng-if="isFactCleanup"><span class="factDetailsHeader">Note:</span> For facts collected older than the time period specified, save one fact scan (snapshot) per time window (frequency). For example, facts older than 30 days are purged, while one weekly fact scan is kept.
|
|
||||||
Caution: Setting both numerical variables to "0" will delete all facts.</div> -->
|
|
||||||
|
|
||||||
<!-- <div class="form-group" ng-if="cleanupJob && !isFactCleanup">
|
|
||||||
<label class="Form-inputLabel"><span class="red-text">*</span> Days of data to keep</label>
|
|
||||||
<input type="number" class="form-control input-sm" name="schedulerPurgeDays" id="schedulerPurgeDays" min="1" ng-model="schedulerPurgeDays" required placeholder="Days of data to keep">
|
|
||||||
<div class="error" ng-show="scheduler_form.schedulerPurgeDays.$dirty && scheduler_form.schedulerPurgeDays.$error.required">A value is required.</div>
|
|
||||||
<div class="error" ng-show="scheduler_form.schedulerPurgeDays.$error.number">This is not a valid number.</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group cleanupStretcher factDaysToKeepCompacter" ng-if="isFactCleanup">
|
|
||||||
<div class="col-md-12">
|
|
||||||
<label class="Form-inputLabel"><span class="red-text">*</span> Select a time period after which to remove old facts</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 inputSpacer inputCompactMobile">
|
|
||||||
<input type="number" id="keep_amount" name="keep_amount" ng-model="keep_amount" ng-required="true" class="form-control input-sm" aw-min=0 aw-max=9999 integer></input>
|
|
||||||
<div class="error" ng-show="scheduler_form.keep_amount.$dirty && scheduler_form.keep_amount.$error.required">Please enter the number of days you would like to keep this data.</div>
|
|
||||||
<div class="error survey_error" ng-show="scheduler_form.keep_amount.$error.number || scheduler_form.keep_amount.$error.integer" >Please enter a valid number.</div>
|
|
||||||
<div class="error survey_error" ng-show="scheduler_form.keep_amount.$error.awMin">Please enter a non-negative number.</div>
|
|
||||||
<div class="error survey_error" ng-show="scheduler_form.keep_amount.$error.awMax">Please enter a number smaller than 9999.</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 inputSpacer">
|
|
||||||
<select id="keep_unit" name="keep_unit" ng-model="keep_unit" ng-options="type.label for type in keep_unit_choices track by type.value" ng-required="true" class="form-control input-sm"></select>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<!-- <div class="form-group cleanupStretcher" ng-if="isFactCleanup">
|
|
||||||
<div class="col-md-12">
|
|
||||||
<label class="Form-inputLabel"><span class="red-text">*</span> Select a frequency for snapshot retention</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 inputSpacer inputCompactMobile">
|
|
||||||
<input type="number" class="form-control input-sm" id="granularity_keep_amount" name="granularity_keep_amount" ng-model="granularity_keep_amount" ng-required="true" aw-min=0 aw-max=9999 >
|
|
||||||
<div class="error" ng-show="scheduler_form.granularity_keep_amount.$dirty && scheduler_form.granularity_keep_amount.$error.required">Please enter the number of days you would like to keep this data.</div>
|
|
||||||
<div class="error survey_error" ng-show="scheduler_form.granularity_keep_amount.$error.number || scheduler_form.granularity_keep_amount.$error.integer" >Please enter a valid number.</div>
|
|
||||||
<div class="error survey_error" ng-show="scheduler_form.granularity_keep_amount.$error.awMin">Please enter a non-negative number.</div>
|
|
||||||
<div class="error survey_error" ng-show="scheduler_form.granularity_keep_amount.$error.awMax">Please enter a number smaller than 9999.</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 inputSpacer">
|
|
||||||
<select id="granularity_keep_unit" name="granularity_keep_unit" ng-model="granularity_keep_unit" ng-options="type.label for type in granularity_keep_unit_choices track by type.value" ng-required="true" class="form-control input-sm"></select>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
</form>
|
</form>
|
||||||
<div class="SchedulerFormDetail-container
|
<div class="SchedulerFormDetail-container
|
||||||
SchedulerFormDetail-container--error"
|
SchedulerFormDetail-container--error"
|
||||||
@@ -632,8 +590,33 @@
|
|||||||
{{ occurrence.local }}
|
{{ occurrence.local }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="form-group Form-formGroup Form-textAreaLabel">
|
||||||
|
<label for="Scheduler-extraVars">
|
||||||
|
<span class="Form-inputLabel">
|
||||||
|
Extra Variables
|
||||||
|
</span>
|
||||||
|
<!-- tooltip -->
|
||||||
|
<a aw-pop-over="<p>Pass extra command line variables to the playbook. This is the -e or --extra-vars command line parameter for ansible-playbook. Provide key/value pairs using either YAML or JSON.</p>JSON:<br />
|
||||||
|
<blockquote>{<br />"somevar": "somevalue",<br />"password": "magic"<br /> }</blockquote>
|
||||||
|
YAML:<br />
|
||||||
|
<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>"
|
||||||
|
data-placement="right" data-container="body" over-title="Extra Variables" class="help-link" data-original-title="" title="" tabindex="-1">
|
||||||
|
<i class="fa fa-question-circle"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="parse-selection">
|
||||||
|
<input type="radio" ng-model="parseType" ng-change="parseTypeChange()" value="yaml"><span class="parse-label">YAML</span>
|
||||||
|
<input type="radio" ng-model="parseType" ng-change="parseTypeChange()" value="json"> <span class="parse-label">JSON</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</label>
|
||||||
|
<div>
|
||||||
|
<textarea rows="6" ng-model="extraVars" name="Scheduler-extraVars" class="form-control" id="SchedulerForm-extraVars"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="buttons Form-buttons">
|
<div class="buttons Form-buttons">
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="btn btn-sm Form-saveButton"
|
class="btn btn-sm Form-saveButton"
|
||||||
|
|||||||
@@ -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,8 +171,9 @@
|
|||||||
<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">
|
||||||
|
|||||||
Reference in New Issue
Block a user