mirror of
https://github.com/ansible/awx.git
synced 2026-01-23 15:38:06 -03:30
Job detail page
Built new event viewer. Based on LogViewer.js that provides a common log viewing dialog. Event viewer dialog has the same look and feel.
This commit is contained in:
parent
52a463305f
commit
254c552734
@ -98,6 +98,7 @@ angular.module('Tower', [
|
||||
'LogViewerStatusDefinition',
|
||||
'LogViewerHelper',
|
||||
'LogViewerOptionsDefinition',
|
||||
'EventViewerHelper',
|
||||
'JobDetailHelper',
|
||||
'SocketIO'
|
||||
])
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
function JobDetailController ($rootScope, $scope, $compile, $routeParams, $log, ClearScope, Breadcrumbs, LoadBreadCrumbs, GetBasePath, Wait, Rest,
|
||||
ProcessErrors, SelectPlay, SelectTask, Socket, GetElapsed, FilterAllByHostName, DrawGraph, LoadHostSummary, ReloadHostSummaryList,
|
||||
JobIsFinished, SetTaskStyles, DigestEvent, UpdateDOM, ViewHostResults) {
|
||||
JobIsFinished, SetTaskStyles, DigestEvent, UpdateDOM, EventViewer) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
@ -1155,9 +1155,10 @@ function JobDetailController ($rootScope, $scope, $compile, $routeParams, $log,
|
||||
};
|
||||
|
||||
scope.viewHostResults = function(id) {
|
||||
ViewHostResults({
|
||||
EventViewer({
|
||||
scope: scope,
|
||||
id: id
|
||||
url: scope.job.related.job_events + '?id=' + id,
|
||||
title: 'Host Result'
|
||||
});
|
||||
};
|
||||
|
||||
@ -1165,5 +1166,5 @@ function JobDetailController ($rootScope, $scope, $compile, $routeParams, $log,
|
||||
|
||||
JobDetailController.$inject = [ '$rootScope', '$scope', '$compile', '$routeParams', '$log', 'ClearScope', 'Breadcrumbs', 'LoadBreadCrumbs', 'GetBasePath',
|
||||
'Wait', 'Rest', 'ProcessErrors', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed', 'FilterAllByHostName', 'DrawGraph',
|
||||
'LoadHostSummary', 'ReloadHostSummaryList', 'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'ViewHostResults'
|
||||
'LoadHostSummary', 'ReloadHostSummaryList', 'JobIsFinished', 'SetTaskStyles', 'DigestEvent', 'UpdateDOM', 'EventViewer'
|
||||
];
|
||||
|
||||
298
awx/ui/static/js/helpers/EventViewer.js
Normal file
298
awx/ui/static/js/helpers/EventViewer.js
Normal file
@ -0,0 +1,298 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* LogViewer.js
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('EventViewerHelper', ['ModalDialog', 'Utilities'])
|
||||
|
||||
.factory('EventViewer', ['$compile', 'CreateDialog', 'GetEvent', 'Wait', 'AddTable', 'GetBasePath', 'LookUpName', 'Empty', 'AddPreFormattedText',
|
||||
function($compile, CreateDialog, GetEvent, Wait, AddTable, GetBasePath, LookUpName, Empty, AddPreFormattedText) {
|
||||
return function(params) {
|
||||
var parent_scope = params.scope,
|
||||
url = params.url,
|
||||
title = params.title, //optional
|
||||
scope = parent_scope.$new(true);
|
||||
|
||||
if (scope.removeModalReady) {
|
||||
scope.removeModalReady();
|
||||
}
|
||||
scope.removeModalReady = scope.$on('ModalReady', function() {
|
||||
Wait('stop');
|
||||
$('#eventviewer-modal-dialog').dialog('open');
|
||||
});
|
||||
|
||||
if (scope.removeJobReady) {
|
||||
scope.removeJobReady();
|
||||
}
|
||||
scope.removeEventReady = scope.$on('EventReady', function(e, data) {
|
||||
var elem;
|
||||
|
||||
$('#status-form-container').empty();
|
||||
$('#stdout-form-container').empty();
|
||||
$('#stderr-form-container').empty();
|
||||
$('#traceback-form-container').empty();
|
||||
$('#eventview-tabs li:eq(1)').hide();
|
||||
$('#eventview-tabs li:eq(2)').hide();
|
||||
$('#eventview-tabs li:eq(3)').hide();
|
||||
|
||||
AddTable({ scope: scope, id: 'status-form-container', event: data });
|
||||
|
||||
if (data.stdout) {
|
||||
$('#eventview-tabs li:eq(1)').show();
|
||||
AddPreFormattedText({
|
||||
id: 'stdout-form-container',
|
||||
val: data.stdout
|
||||
});
|
||||
}
|
||||
|
||||
if (data.stderr) {
|
||||
$('#eventview-tabs li:eq(2)').show();
|
||||
AddPreFormattedText({
|
||||
id: 'stderr-form-container',
|
||||
val: data.stderr
|
||||
});
|
||||
}
|
||||
|
||||
if (data.traceback) {
|
||||
$('#eventview-tabs li:eq(3)').show();
|
||||
AddPreFormattedText({
|
||||
id: 'traceback-form-container',
|
||||
val: data.traceback
|
||||
});
|
||||
}
|
||||
|
||||
elem = angular.element(document.getElementById('eventviewer-modal-dialog'));
|
||||
$compile(elem)(scope);
|
||||
|
||||
CreateDialog({
|
||||
scope: scope,
|
||||
width: 675,
|
||||
height: 600,
|
||||
minWidth: 450,
|
||||
callback: 'ModalReady',
|
||||
id: 'eventviewer-modal-dialog',
|
||||
// onResizeStop: resizeText,
|
||||
title: ( (title) ? title : 'Event Details' ),
|
||||
onOpen: function() {
|
||||
$('#eventview-tabs a:first').tab('show');
|
||||
$('#dialog-ok-button').focus();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
GetEvent({
|
||||
url: url,
|
||||
scope: scope
|
||||
});
|
||||
|
||||
scope.modalOK = function() {
|
||||
$('#eventviewer-modal-dialog').dialog('close');
|
||||
scope.$destroy();
|
||||
};
|
||||
};
|
||||
}])
|
||||
|
||||
.factory('GetEvent', ['Wait', 'Rest', 'ProcessErrors', function(Wait, Rest, ProcessErrors) {
|
||||
return function(params) {
|
||||
var url = params.url,
|
||||
scope = params.scope;
|
||||
|
||||
function getStatus(data) {
|
||||
return (data.results[0].event === "runner_on_unreachable") ? "unreachable" : (data.results[0].event === "runner_on_skipped") ? 'skipped' : (data.results[0].failed) ? 'failed' :
|
||||
(data.results[0].changed) ? 'changed' : 'successful';
|
||||
}
|
||||
|
||||
Wait('start');
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data) {
|
||||
var key, event_data = {};
|
||||
if (data.results.length > 0 && data.results[0].event_data.res) {
|
||||
for (key in data.results[0].event_data) {
|
||||
if (key !== "res") {
|
||||
data.results[0].event_data.res[key] = data.results[0].event_data[key];
|
||||
}
|
||||
}
|
||||
if (data.results[0].event_data.res.ansible_facts) {
|
||||
// don't show fact gathering results
|
||||
delete data.results[0].event_data.res.ansible_facts;
|
||||
}
|
||||
data.results[0].event_data.res.status = getStatus(data);
|
||||
event_data = data.results[0].event_data.res;
|
||||
}
|
||||
else {
|
||||
data.results[0].event_data.status = getStatus(data);
|
||||
event_data = data.results[0].event_data;
|
||||
}
|
||||
// convert results to stdout
|
||||
if (event_data.results && typeof event_data.results === "object" && Array.isArray(event_data.results)) {
|
||||
event_data.stdout = "";
|
||||
event_data.results.forEach(function(row) {
|
||||
event_data.stdout += row + "\n";
|
||||
});
|
||||
delete event_data.results;
|
||||
}
|
||||
if (event_data.invocation) {
|
||||
for (key in event_data.invocation) {
|
||||
event_data[key] = event_data.invocation[key];
|
||||
}
|
||||
delete event_data.invocation;
|
||||
}
|
||||
event_data.parent = data.results[0].parent;
|
||||
event_data.play = data.results[0].play;
|
||||
event_data.task = data.results[0].task;
|
||||
event_data.created = data.results[0].created;
|
||||
event_data.role = data.results[0].role;
|
||||
event_data.host_id = data.results[0].host;
|
||||
event_data.host_name = data.results[0].host_name;
|
||||
event_data.id = data.results[0].id;
|
||||
event_data.parent = data.results[0].parent;
|
||||
scope.$emit('EventReady', event_data);
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to get event ' + url + '. GET returned: ' + status });
|
||||
});
|
||||
};
|
||||
}])
|
||||
|
||||
.factory('LookUpName', ['Rest', 'ProcessErrors', 'Empty', function(Rest, ProcessErrors, Empty) {
|
||||
return function(params) {
|
||||
var url = params.url,
|
||||
scope_var = params.scope_var,
|
||||
scope = params.scope;
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function(data) {
|
||||
if (scope_var === 'inventory_source') {
|
||||
scope[scope_var + '_name'] = data.summary_fields.group.name;
|
||||
}
|
||||
else if (!Empty(data.name)) {
|
||||
scope[scope_var + '_name'] = data.name;
|
||||
}
|
||||
if (!Empty(data.group)) {
|
||||
// Used for inventory_source
|
||||
scope.group = data.group;
|
||||
}
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Failed to retrieve ' + url + '. GET returned: ' + status });
|
||||
});
|
||||
};
|
||||
}])
|
||||
|
||||
.factory('AddTable', ['$compile', '$filter', 'Empty', function($compile, $filter, Empty) {
|
||||
return function(params) {
|
||||
var scope = params.scope,
|
||||
id = params.id,
|
||||
event = params.event,
|
||||
html = '', e;
|
||||
|
||||
function keyToLabel(key) {
|
||||
var label = '';
|
||||
switch(key) {
|
||||
case "id":
|
||||
label = "Event ID";
|
||||
break;
|
||||
case "parent":
|
||||
label = "Parent Event ID";
|
||||
break;
|
||||
case "rc":
|
||||
label = "Return Code";
|
||||
break;
|
||||
default:
|
||||
label = key.charAt(0).toUpperCase() + key.slice(1);
|
||||
label = label.replace(/(\_.)/g, function(match) {
|
||||
var res;
|
||||
res = match.replace(/\_/,'');
|
||||
res = ' ' + res.toUpperCase();
|
||||
return res;
|
||||
});
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
function parseJSON(obj) {
|
||||
var html = '', keys;
|
||||
if (typeof obj === "object") {
|
||||
html += "<table class=\"table eventviewer-status\">\n";
|
||||
html += "<tbody>\n";
|
||||
keys = Object.keys(obj).sort();
|
||||
keys.forEach(function(key) {
|
||||
var label;
|
||||
if (key !== "stdout" && key !== "stderr" && key !== "traceback" && key !== "host_id" && key !== "host") {
|
||||
label = keyToLabel(key);
|
||||
if (Empty(obj[key])) {
|
||||
// exclude empty items
|
||||
}
|
||||
else if (typeof obj[key] === "boolean" || typeof obj[key] === "number" || typeof obj[key] === "string") {
|
||||
html += "<tr><td class=\"key\">" + label + ":</td><td class=\"value\">";
|
||||
if (key === "status") {
|
||||
html += "<i class=\"fa icon-job-" + obj[key] + "\"></i> " + obj[key];
|
||||
}
|
||||
else if (key === "start" || key === "end" || key === "created") {
|
||||
html += $filter('date')(obj[key], 'MM/dd/yy HH:mm:ss');
|
||||
}
|
||||
else if (key === "host_name") {
|
||||
html += "<a href=\"#/home/hosts/?id=" + obj.host_id + "\" target=\"_blank\" " +
|
||||
"aw-tool-tip=\"Click to view host.<br />Opens in new tab or window.\" data-placement=\"right\" " +
|
||||
"ng-click=\"modalOK()\">" + obj[key] + "</a>";
|
||||
}
|
||||
else {
|
||||
html += obj[key];
|
||||
}
|
||||
|
||||
html += "</td></tr>\n";
|
||||
}
|
||||
else if (typeof obj[key] === "object" && Array.isArray(obj[key])) {
|
||||
html += "<tr><td class=\"key\">" + label + ":</td><td class=\"value\">";
|
||||
obj[key].forEach(function(row) {
|
||||
html += "[" + row + "],";
|
||||
});
|
||||
html = html.replace(/,$/,'');
|
||||
html += "</td></tr>\n";
|
||||
}
|
||||
else if (typeof obj[key] === "object") {
|
||||
html += "<tr><td class=\"key\">" + label + ":</td><td class=\"nested-table\">\n" + parseJSON(obj[key]) + "</td></tr>\n";
|
||||
}
|
||||
}
|
||||
});
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
}
|
||||
return html;
|
||||
}
|
||||
html = parseJSON(event);
|
||||
e = angular.element(document.getElementById(id));
|
||||
e.empty().html(html);
|
||||
$compile(e)(scope);
|
||||
};
|
||||
}])
|
||||
|
||||
.factory('AddTextarea', [ function() {
|
||||
return function(params) {
|
||||
var container_id = params.container_id,
|
||||
val = params.val,
|
||||
fld_id = params.fld_id,
|
||||
html;
|
||||
html = "<div class=\"form-group\">\n" +
|
||||
"<textarea id=\"" + fld_id + "\" class=\"form-control mono-space\" rows=\"12\" readonly>" + val + "</textarea>" +
|
||||
"</div>\n";
|
||||
$('#' + container_id).empty().html(html);
|
||||
};
|
||||
}])
|
||||
|
||||
.factory('AddPreFormattedText', [function() {
|
||||
return function(params) {
|
||||
var id = params.id,
|
||||
val = params.val,
|
||||
html;
|
||||
html = "<pre>" + val + "</pre>\n";
|
||||
$('#' + id).empty().html(html);
|
||||
};
|
||||
}]);
|
||||
@ -1168,124 +1168,4 @@ function($rootScope, $log, UpdatePlayStatus, UpdateHostStatus, AddHostResult, Ge
|
||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
||||
});
|
||||
};
|
||||
}])
|
||||
|
||||
.factory('ViewHostResults', ['$log', 'CreateDialog', 'Rest', 'ProcessErrors', 'Wait', function($log, CreateDialog, Rest, ProcessErrors, Wait) {
|
||||
return function(params) {
|
||||
var scope = params.scope,
|
||||
my_scope = params.scope.$new(),
|
||||
id = params.id,
|
||||
url;
|
||||
|
||||
function parseJSON(obj) {
|
||||
var html="", keys;
|
||||
if (typeof obj === "object") {
|
||||
html += "<table class=\"object-list\">\n";
|
||||
html += "<tbody>\n";
|
||||
keys = Object.keys(obj).sort();
|
||||
keys.forEach(function(key) {
|
||||
if (typeof obj[key] === "boolean" || typeof obj[key] === "number" || typeof obj[key] === "string") {
|
||||
html += "<tr><td class=\"key\">" + key + ":</td><td class=\"value";
|
||||
html += (key === "results" || key === "stdout" || key === "stderr") ? " mono-space" : "";
|
||||
html += "\">";
|
||||
html += (key === "status") ? "<i class=\"fa icon-job-" + obj[key] + "\"></i> " + obj[key] : obj[key];
|
||||
html += "</td></tr>\n";
|
||||
}
|
||||
else if (obj[key] === null || obj[key] === undefined) {
|
||||
// html += "<tr><td class=\"key\">" + key + ":</td><td class=\"value\">null</td></tr>\n";
|
||||
}
|
||||
else if (typeof obj[key] === "object" && Array.isArray(obj[key])) {
|
||||
html += "<tr><td class=\"key\">" + key + ":</td><td class=\"value";
|
||||
html += (key === "results" || key === "stdout" || key === "stderr") ? " mono-space" : "";
|
||||
html += "\">";
|
||||
obj[key].forEach(function(row) {
|
||||
html += "<p>" + row + "</p>";
|
||||
});
|
||||
html += "</td></tr>\n";
|
||||
}
|
||||
else if (typeof obj[key] === "object") {
|
||||
html += "<tr><td class=\"key\">" + key + ":</td><td class=\"nested-table\">\n" + parseJSON(obj[key]) + "</td></tr>\n";
|
||||
}
|
||||
});
|
||||
html += "</tbody>\n";
|
||||
html += "</table>\n";
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
if (my_scope.removeDataReady) {
|
||||
my_scope.removeDataReady();
|
||||
}
|
||||
my_scope.removeDataReady = my_scope.$on('DataReady', function(e, event_data, host) {
|
||||
//var html = "<div class=\"title-section\">\n";
|
||||
//html += "<h4>" + host.name + "</h4>\n";
|
||||
//html += (host.description && host.description !== "imported") ? "<h5>" + host.description + "</h5>" : "";
|
||||
//html += "<p>Event " + id + " details:</p>\n";
|
||||
//html += "</div>\n";
|
||||
var html = "<div class=\"results\">\n";
|
||||
event_data.host = host.name;
|
||||
html += parseJSON(event_data);
|
||||
html += "<div class=\"spacer\"></div>\n";
|
||||
html += "</div>\n";
|
||||
|
||||
$('#event-viewer-dialog').empty().html(html);
|
||||
|
||||
CreateDialog({
|
||||
scope: my_scope,
|
||||
width: 600,
|
||||
height: 550,
|
||||
minWidth: 450,
|
||||
callback: 'ModalReady',
|
||||
id: 'event-viewer-dialog',
|
||||
title: 'Host Results',
|
||||
onOpen: function() {
|
||||
$('#dialog-ok-button').focus();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (my_scope.removeModalReady) {
|
||||
my_scope.removeModalReady();
|
||||
}
|
||||
my_scope.removeModalReady = my_scope.$on('ModalReady', function() {
|
||||
Wait('stop');
|
||||
$('#event-viewer-dialog').dialog('open');
|
||||
});
|
||||
|
||||
url = scope.job.related.job_events + "?id=" + id;
|
||||
Wait('start');
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success( function(data) {
|
||||
var key;
|
||||
Wait('stop');
|
||||
if (data.results.length > 0 && data.results[0].event_data.res) {
|
||||
for (key in data.results[0].event_data) {
|
||||
if (key !== "res") {
|
||||
data.results[0].event_data.res[key] = data.results[0].event_data[key];
|
||||
}
|
||||
}
|
||||
if (data.results[0].event_data.res.ansible_facts) {
|
||||
delete data.results[0].event_data.res.ansible_facts;
|
||||
}
|
||||
data.results[0].event_data.res.status = (data.results[0].event === "runner_on_skipped") ? 'skipped' : (data.results[0].failed) ? 'failed' :
|
||||
(data.results[0].changed) ? 'changed' : 'successful';
|
||||
my_scope.$emit('DataReady', data.results[0].event_data.res, data.results[0].summary_fields.host, data.results[0].id);
|
||||
}
|
||||
else {
|
||||
data.results[0].event_data.status = (data.results[0].event === "runner_on_skipped") ? 'skipped' : (data.results[0].failed) ? 'failed' :
|
||||
(data.results[0].changed) ? 'changed' : 'successful';
|
||||
my_scope.$emit('DataReady', data.results[0].event_data, data.results[0].summary_fields.host, data.results[0].id);
|
||||
}
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + url + '. GET returned: ' + status });
|
||||
});
|
||||
|
||||
scope.modalOK = function() {
|
||||
$('#event-viewer-dialog').dialog('close');
|
||||
my_scope.$destroy();
|
||||
};
|
||||
};
|
||||
}]);
|
||||
|
||||
@ -51,6 +51,7 @@
|
||||
@import "codemirror.less";
|
||||
@import "angular-scheduler.less";
|
||||
@import "log-viewer.less";
|
||||
@import "event-viewer.less";
|
||||
@import "job-details.less";
|
||||
@import "jobs.less";
|
||||
@import "inventory-edit.less";
|
||||
@ -60,7 +61,6 @@
|
||||
@import "new-dashboard.less";
|
||||
|
||||
|
||||
|
||||
/* Bootstrap fix that's causing a right margin to appear
|
||||
whenver a modal is opened */
|
||||
body.modal-open {
|
||||
|
||||
32
awx/ui/static/less/event-viewer.less
Normal file
32
awx/ui/static/less/event-viewer.less
Normal file
@ -0,0 +1,32 @@
|
||||
/*********************************************
|
||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
*
|
||||
* event-viewer.less
|
||||
*
|
||||
* custom styles for EventViewer.js helper
|
||||
*
|
||||
*/
|
||||
|
||||
#eventviewer-modal-dialog {
|
||||
|
||||
textarea {
|
||||
overflow: scroll;
|
||||
}
|
||||
pre {
|
||||
overflow: scroll;
|
||||
word-wrap: normal;
|
||||
word-break: normal;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
|
||||
table.eventviewer-status {
|
||||
margin-top: 20px;
|
||||
|
||||
.key {
|
||||
font-weight: bold;
|
||||
}
|
||||
.value i {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
22
awx/ui/static/partials/eventviewer.html
Normal file
22
awx/ui/static/partials/eventviewer.html
Normal file
@ -0,0 +1,22 @@
|
||||
<div id="eventviewer-modal-dialog" title="Log View" style="display: none;">
|
||||
<ul id="eventview-tabs" class="nav nav-tabs">
|
||||
<li class="active"><a href="#status" id="status-link" data-toggle="tab" ng-click="toggleTab($event, 'status-link', 'eventview-tabs')">Status</a></li>
|
||||
<li><a href="#stdout" id="stdout-link" data-toggle="tab" ng-click="toggleTab($event, 'stdout-link', 'eventview-tabs')">Standard Out</a></li>
|
||||
<li><a href="#stderr" id="stderr-link" data-toggle="tab" ng-click="toggleTab($event, 'stderr-link', 'eventview-tabs')">Standard Error</a></li>
|
||||
<li><a href="#traceback" id="traceback-link" data-toggle="tab" ng-click="toggleTab($event, 'traceback-link', 'eventview-tabs')">Traceback</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="status">
|
||||
<div id="status-form-container"></div>
|
||||
</div>
|
||||
<div class="tab-pane" id="stdout">
|
||||
<div id="stdout-form-container"></div>
|
||||
</div>
|
||||
<div class="tab-pane" id="stderr">
|
||||
<div id="stderr-form-container"></div>
|
||||
</div>
|
||||
<div class="tab-pane" id="traceback">
|
||||
<div id="traceback-form-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -257,5 +257,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="event-viewer-dialog" style="display: none;"></div>
|
||||
<div ng-include="'/static/partials/eventviewer.html'"></div>
|
||||
|
||||
</div>
|
||||
|
||||
@ -158,6 +158,7 @@
|
||||
<script src="{{ STATIC_URL }}js/helpers/Variables.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/helpers/Schedules.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/helpers/LogViewer.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/helpers/EventViewer.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/helpers/JobDetail.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/helpers/JobTemplates.js"></script>
|
||||
<script src="{{ STATIC_URL }}js/widgets/JobStatus.js"></script>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user