mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-15 03:32:53 -06:00
review updates
This commit is contained in:
parent
f092c107b5
commit
41f92ef8e6
@ -120,6 +120,43 @@ class TemplateLanguageChoices(ChoiceSet):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Log Levels for Reports and Scripts
|
||||||
|
#
|
||||||
|
|
||||||
|
class LogLevelChoices(ChoiceSet):
|
||||||
|
|
||||||
|
LOG_DEFAULT = 'default'
|
||||||
|
LOG_SUCCESS = 'sucess'
|
||||||
|
LOG_INFO = 'info'
|
||||||
|
LOG_WARNING = 'warning'
|
||||||
|
LOG_FAILURE = 'failure'
|
||||||
|
|
||||||
|
CHOICES = (
|
||||||
|
(LOG_DEFAULT, 'Default'),
|
||||||
|
(LOG_SUCCESS, 'Success'),
|
||||||
|
(LOG_INFO, 'Info'),
|
||||||
|
(LOG_WARNING, 'Warning'),
|
||||||
|
(LOG_FAILURE, 'Failure'),
|
||||||
|
)
|
||||||
|
|
||||||
|
CLASS_MAP = (
|
||||||
|
(LOG_DEFAULT, 'default'),
|
||||||
|
(LOG_SUCCESS, 'success'),
|
||||||
|
(LOG_INFO, 'info'),
|
||||||
|
(LOG_WARNING, 'warning'),
|
||||||
|
(LOG_FAILURE, 'danger'),
|
||||||
|
)
|
||||||
|
|
||||||
|
LEGACY_MAP = (
|
||||||
|
(LOG_DEFAULT, 0),
|
||||||
|
(LOG_SUCCESS, 10),
|
||||||
|
(LOG_INFO, 20),
|
||||||
|
(LOG_WARNING, 30),
|
||||||
|
(LOG_FAILURE, 40),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Job results
|
# Job results
|
||||||
#
|
#
|
||||||
|
@ -1,17 +1,3 @@
|
|||||||
# Report logging levels
|
|
||||||
LOG_DEFAULT = 0
|
|
||||||
LOG_SUCCESS = 10
|
|
||||||
LOG_INFO = 20
|
|
||||||
LOG_WARNING = 30
|
|
||||||
LOG_FAILURE = 40
|
|
||||||
LOG_LEVEL_CODES = {
|
|
||||||
LOG_DEFAULT: 'default',
|
|
||||||
LOG_SUCCESS: 'success',
|
|
||||||
LOG_INFO: 'info',
|
|
||||||
LOG_WARNING: 'warning',
|
|
||||||
LOG_FAILURE: 'failure',
|
|
||||||
}
|
|
||||||
|
|
||||||
# Webhook content types
|
# Webhook content types
|
||||||
HTTP_CONTENT_TYPE_JSON = 'application/json'
|
HTTP_CONTENT_TYPE_JSON = 'application/json'
|
||||||
|
|
||||||
|
@ -9,8 +9,7 @@ from django.db.models import Q
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django_rq import job
|
from django_rq import job
|
||||||
|
|
||||||
from .choices import JobResultStatusChoices
|
from .choices import JobResultStatusChoices, LogLevelChoices
|
||||||
from .constants import *
|
|
||||||
from .models import JobResult
|
from .models import JobResult
|
||||||
|
|
||||||
|
|
||||||
@ -77,7 +76,8 @@ def run_report(job_result, *args, **kwargs):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
report.run(job_result)
|
report.run(job_result)
|
||||||
except Exception:
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
job_result.set_status(JobResultStatusChoices.STATUS_ERRORED)
|
job_result.set_status(JobResultStatusChoices.STATUS_ERRORED)
|
||||||
logging.error(f"Error during execution of report {job_result.name}")
|
logging.error(f"Error during execution of report {job_result.name}")
|
||||||
|
|
||||||
@ -153,15 +153,15 @@ class Report(object):
|
|||||||
def full_name(self):
|
def full_name(self):
|
||||||
return '.'.join([self.__module__, self.__class__.__name__])
|
return '.'.join([self.__module__, self.__class__.__name__])
|
||||||
|
|
||||||
def _log(self, obj, message, level=LOG_DEFAULT):
|
def _log(self, obj, message, level=LogLevelChoices.LOG_DEFAULT):
|
||||||
"""
|
"""
|
||||||
Log a message from a test method. Do not call this method directly; use one of the log_* wrappers below.
|
Log a message from a test method. Do not call this method directly; use one of the log_* wrappers below.
|
||||||
"""
|
"""
|
||||||
if level not in LOG_LEVEL_CODES:
|
if level not in LogLevelChoices.as_dict():
|
||||||
raise Exception("Unknown logging level: {}".format(level))
|
raise Exception("Unknown logging level: {}".format(level))
|
||||||
self._results[self.active_test]['log'].append((
|
self._results[self.active_test]['log'].append((
|
||||||
timezone.now().isoformat(),
|
timezone.now().isoformat(),
|
||||||
LOG_LEVEL_CODES.get(level),
|
level,
|
||||||
str(obj) if obj else None,
|
str(obj) if obj else None,
|
||||||
obj.get_absolute_url() if getattr(obj, 'get_absolute_url', None) else None,
|
obj.get_absolute_url() if getattr(obj, 'get_absolute_url', None) else None,
|
||||||
message,
|
message,
|
||||||
@ -171,7 +171,7 @@ class Report(object):
|
|||||||
"""
|
"""
|
||||||
Log a message which is not associated with a particular object.
|
Log a message which is not associated with a particular object.
|
||||||
"""
|
"""
|
||||||
self._log(None, message, level=LOG_DEFAULT)
|
self._log(None, message, level=LogLevelChoices.LOG_DEFAULT)
|
||||||
self.logger.info(message)
|
self.logger.info(message)
|
||||||
|
|
||||||
def log_success(self, obj, message=None):
|
def log_success(self, obj, message=None):
|
||||||
@ -179,7 +179,7 @@ class Report(object):
|
|||||||
Record a successful test against an object. Logging a message is optional.
|
Record a successful test against an object. Logging a message is optional.
|
||||||
"""
|
"""
|
||||||
if message:
|
if message:
|
||||||
self._log(obj, message, level=LOG_SUCCESS)
|
self._log(obj, message, level=LogLevelChoices.LOG_SUCCESS)
|
||||||
self._results[self.active_test]['success'] += 1
|
self._results[self.active_test]['success'] += 1
|
||||||
self.logger.info(f"Success | {obj}: {message}")
|
self.logger.info(f"Success | {obj}: {message}")
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ class Report(object):
|
|||||||
"""
|
"""
|
||||||
Log an informational message.
|
Log an informational message.
|
||||||
"""
|
"""
|
||||||
self._log(obj, message, level=LOG_INFO)
|
self._log(obj, message, level=LogLevelChoices.LOG_INFO)
|
||||||
self._results[self.active_test]['info'] += 1
|
self._results[self.active_test]['info'] += 1
|
||||||
self.logger.info(f"Info | {obj}: {message}")
|
self.logger.info(f"Info | {obj}: {message}")
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ class Report(object):
|
|||||||
"""
|
"""
|
||||||
Log a warning.
|
Log a warning.
|
||||||
"""
|
"""
|
||||||
self._log(obj, message, level=LOG_WARNING)
|
self._log(obj, message, level=LogLevelChoices.LOG_WARNING)
|
||||||
self._results[self.active_test]['warning'] += 1
|
self._results[self.active_test]['warning'] += 1
|
||||||
self.logger.info(f"Warning | {obj}: {message}")
|
self.logger.info(f"Warning | {obj}: {message}")
|
||||||
|
|
||||||
@ -203,7 +203,7 @@ class Report(object):
|
|||||||
"""
|
"""
|
||||||
Log a failure. Calling this method will automatically mark the report as failed.
|
Log a failure. Calling this method will automatically mark the report as failed.
|
||||||
"""
|
"""
|
||||||
self._log(obj, message, level=LOG_FAILURE)
|
self._log(obj, message, level=LogLevelChoices.LOG_FAILURE)
|
||||||
self._results[self.active_test]['failure'] += 1
|
self._results[self.active_test]['failure'] += 1
|
||||||
self.logger.info(f"Failure | {obj}: {message}")
|
self.logger.info(f"Failure | {obj}: {message}")
|
||||||
self.failed = True
|
self.failed = True
|
||||||
|
@ -19,11 +19,10 @@ from mptt.forms import TreeNodeChoiceField, TreeNodeMultipleChoiceField
|
|||||||
from mptt.models import MPTTModel
|
from mptt.models import MPTTModel
|
||||||
|
|
||||||
from extras.api.serializers import ScriptOutputSerializer
|
from extras.api.serializers import ScriptOutputSerializer
|
||||||
from extras.choices import JobResultStatusChoices
|
from extras.choices import JobResultStatusChoices, LogLevelChoices
|
||||||
from extras.models import JobResult
|
from extras.models import JobResult
|
||||||
from ipam.formfields import IPAddressFormField, IPNetworkFormField
|
from ipam.formfields import IPAddressFormField, IPNetworkFormField
|
||||||
from ipam.validators import MaxPrefixLengthValidator, MinPrefixLengthValidator, prefix_validator
|
from ipam.validators import MaxPrefixLengthValidator, MinPrefixLengthValidator, prefix_validator
|
||||||
from .constants import LOG_DEFAULT, LOG_FAILURE, LOG_INFO, LOG_SUCCESS, LOG_WARNING
|
|
||||||
from utilities.exceptions import AbortTransaction
|
from utilities.exceptions import AbortTransaction
|
||||||
from utilities.forms import DynamicModelChoiceField, DynamicModelMultipleChoiceField
|
from utilities.forms import DynamicModelChoiceField, DynamicModelMultipleChoiceField
|
||||||
from .forms import ScriptForm
|
from .forms import ScriptForm
|
||||||
@ -324,23 +323,23 @@ class BaseScript:
|
|||||||
|
|
||||||
def log_debug(self, message):
|
def log_debug(self, message):
|
||||||
self.logger.log(logging.DEBUG, message)
|
self.logger.log(logging.DEBUG, message)
|
||||||
self.log.append((LOG_DEFAULT, message))
|
self.log.append((LogLevelChoices.LOG_DEFAULT, message))
|
||||||
|
|
||||||
def log_success(self, message):
|
def log_success(self, message):
|
||||||
self.logger.log(logging.INFO, message) # No syslog equivalent for SUCCESS
|
self.logger.log(logging.INFO, message) # No syslog equivalent for SUCCESS
|
||||||
self.log.append((LOG_SUCCESS, message))
|
self.log.append((LogLevelChoices.LOG_SUCCESS, message))
|
||||||
|
|
||||||
def log_info(self, message):
|
def log_info(self, message):
|
||||||
self.logger.log(logging.INFO, message)
|
self.logger.log(logging.INFO, message)
|
||||||
self.log.append((LOG_INFO, message))
|
self.log.append((LogLevelChoices.LOG_INFO, message))
|
||||||
|
|
||||||
def log_warning(self, message):
|
def log_warning(self, message):
|
||||||
self.logger.log(logging.WARNING, message)
|
self.logger.log(logging.WARNING, message)
|
||||||
self.log.append((LOG_WARNING, message))
|
self.log.append((LogLevelChoices.LOG_WARNING, message))
|
||||||
|
|
||||||
def log_failure(self, message):
|
def log_failure(self, message):
|
||||||
self.logger.log(logging.ERROR, message)
|
self.logger.log(logging.ERROR, message)
|
||||||
self.log.append((LOG_FAILURE, message))
|
self.log.append((LogLevelChoices.LOG_FAILURE, message))
|
||||||
|
|
||||||
# Convenience functions
|
# Convenience functions
|
||||||
|
|
||||||
@ -428,11 +427,15 @@ def run_script(data, request, commit=True, *args, **kwargs):
|
|||||||
try:
|
try:
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
script.output = script.run(**kwargs)
|
script.output = script.run(**kwargs)
|
||||||
job_result.status = JobResultStatusChoices.STATUS_COMPLETED
|
job_result.data = ScriptOutputSerializer(script).data
|
||||||
|
job_result.set_status(JobResultStatusChoices.STATUS_COMPLETED)
|
||||||
|
|
||||||
if not commit:
|
if not commit:
|
||||||
raise AbortTransaction()
|
raise AbortTransaction()
|
||||||
|
|
||||||
except AbortTransaction:
|
except AbortTransaction:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
stacktrace = traceback.format_exc()
|
stacktrace = traceback.format_exc()
|
||||||
script.log_failure(
|
script.log_failure(
|
||||||
@ -440,7 +443,8 @@ def run_script(data, request, commit=True, *args, **kwargs):
|
|||||||
)
|
)
|
||||||
logger.error(f"Exception raised during script execution: {e}")
|
logger.error(f"Exception raised during script execution: {e}")
|
||||||
commit = False
|
commit = False
|
||||||
job_result.status = JobResultStatusChoices.STATUS_FAILED
|
job_result.set_status(JobResultStatusChoices.STATUS_ERRORED)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
if not commit:
|
if not commit:
|
||||||
# Delete all pending changelog entries
|
# Delete all pending changelog entries
|
||||||
@ -449,10 +453,6 @@ def run_script(data, request, commit=True, *args, **kwargs):
|
|||||||
"Database changes have been reverted automatically."
|
"Database changes have been reverted automatically."
|
||||||
)
|
)
|
||||||
|
|
||||||
job_result.data = ScriptOutputSerializer(script).data
|
|
||||||
job_result.completed = timezone.now()
|
|
||||||
job_result.save()
|
|
||||||
|
|
||||||
logger.info(f"Script completed in {job_result.duration}")
|
logger.info(f"Script completed in {job_result.duration}")
|
||||||
|
|
||||||
# Delete any previous terminal state results
|
# Delete any previous terminal state results
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from django import template
|
from django import template
|
||||||
|
|
||||||
from extras.constants import LOG_DEFAULT, LOG_FAILURE, LOG_INFO, LOG_SUCCESS, LOG_WARNING
|
from extras.choices import LogLevelChoices
|
||||||
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
@ -11,28 +11,7 @@ def log_level(level):
|
|||||||
"""
|
"""
|
||||||
Display a label indicating a syslog severity (e.g. info, warning, etc.).
|
Display a label indicating a syslog severity (e.g. info, warning, etc.).
|
||||||
"""
|
"""
|
||||||
# TODO: we should convert this to a choices class
|
return {
|
||||||
levels = {
|
'name': LogLevelChoices.as_dict()[level],
|
||||||
'default': {
|
'class': dict(LogLevelChoices.CLASS_MAP)[level]
|
||||||
'name': 'Default',
|
|
||||||
'class': 'default'
|
|
||||||
},
|
|
||||||
'success': {
|
|
||||||
'name': 'Success',
|
|
||||||
'class': 'success',
|
|
||||||
},
|
|
||||||
'info': {
|
|
||||||
'name': 'Info',
|
|
||||||
'class': 'info'
|
|
||||||
},
|
|
||||||
'warning': {
|
|
||||||
'name': 'Warning',
|
|
||||||
'class': 'warning'
|
|
||||||
},
|
|
||||||
'failure': {
|
|
||||||
'name': 'Failure',
|
|
||||||
'class': 'danger'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return levels[level]
|
|
||||||
|
@ -453,8 +453,22 @@ class ScriptListView(ContentTypePermissionRequiredMixin, View):
|
|||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
|
|
||||||
|
scripts = get_scripts(use_names=True)
|
||||||
|
script_content_type = ContentType.objects.get(app_label='extras', model='script')
|
||||||
|
results = {
|
||||||
|
r.name: r
|
||||||
|
for r in JobResult.objects.filter(
|
||||||
|
obj_type=script_content_type,
|
||||||
|
status__in=JobResultStatusChoices.TERMINAL_STATE_CHOICES
|
||||||
|
).defer('data')
|
||||||
|
}
|
||||||
|
|
||||||
|
for _scripts in scripts.values():
|
||||||
|
for script in _scripts.values():
|
||||||
|
script.result = results.get(script.full_name)
|
||||||
|
|
||||||
return render(request, 'extras/script_list.html', {
|
return render(request, 'extras/script_list.html', {
|
||||||
'scripts': get_scripts(use_names=True),
|
'scripts': scripts,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,10 +3,8 @@ var timeout = 1000;
|
|||||||
|
|
||||||
function updatePendingStatusLabel(status){
|
function updatePendingStatusLabel(status){
|
||||||
var labelClass;
|
var labelClass;
|
||||||
if (status.value === 'failed'){
|
if (status.value === 'failed' || status.value === 'errored'){
|
||||||
labelClass = 'danger';
|
labelClass = 'danger';
|
||||||
} else if (status.value === 'pending'){
|
|
||||||
labelClass = 'default';
|
|
||||||
} else if (status.value === 'running'){
|
} else if (status.value === 'running'){
|
||||||
labelClass = 'warning';
|
labelClass = 'warning';
|
||||||
} else if (status.value === 'completed'){
|
} else if (status.value === 'completed'){
|
||||||
@ -33,7 +31,7 @@ $(document).ready(function(){
|
|||||||
context: this,
|
context: this,
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
updatePendingStatusLabel(data.status);
|
updatePendingStatusLabel(data.status);
|
||||||
if (data.status.value === 'completed' || data.status.value === 'failed'){
|
if (data.status.value === 'completed' || data.status.value === 'failed' || data.status.value === 'errored'){
|
||||||
jobTerminatedAction()
|
jobTerminatedAction()
|
||||||
} else {
|
} else {
|
||||||
setTimeout(checkPendingResult, timeout);
|
setTimeout(checkPendingResult, timeout);
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
{% if result.status == 'failed' %}
|
{% if result.status == 'failed' %}
|
||||||
<label class="label label-danger">Failed</label>
|
<label class="label label-danger">Failed</label>
|
||||||
|
{% elif result.status == 'errored' %}
|
||||||
|
<label class="label label-danger">Errored</label>
|
||||||
{% elif result.status == 'pending' %}
|
{% elif result.status == 'pending' %}
|
||||||
<label class="label label-default">Pending</label>
|
<label class="label label-default">Pending</label>
|
||||||
{% elif result.status == 'running' %}
|
{% elif result.status == 'running' %}
|
||||||
<label class="label label-warning">Running</label>
|
<label class="label label-warning">Running</label>
|
||||||
{% elif result.status == 'completed' %}
|
{% elif result.status == 'completed' %}
|
||||||
<label class="label label-success">Passed</label>
|
<label class="label label-success">Completed</label>
|
||||||
{% else %}
|
{% else %}
|
||||||
<label class="label label-default">N/A</label>
|
<label class="label label-default">N/A</label>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<span id="pending-result-label">{% include 'extras/inc/job_label.html' with result=result %}</span>
|
<span id="pending-result-label">{% include 'extras/inc/job_label.html' with result=result %}</span>
|
||||||
</p>
|
</p>
|
||||||
{% if result.completed %}
|
{% if result.completed and result.status != 'errored' %}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<strong>Report Methods</strong>
|
<strong>Report Methods</strong>
|
||||||
@ -97,8 +97,10 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
{% elif result.status == 'errored' %}
|
||||||
|
<div class="well">Error during report execution</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="well">Pending results</div>
|
<div class="well">Pending results</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,15 +4,17 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% block title %}Scripts{% endblock %}</h1>
|
<h1>{% block title %}Scripts{% endblock %}</h1>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-9">
|
||||||
{% if scripts %}
|
{% if scripts %}
|
||||||
{% for module, module_scripts in scripts.items %}
|
{% for module, module_scripts in scripts.items %}
|
||||||
<h3><a name="module.{{ module }}"></a>{{ module|bettertitle }}</h3>
|
<h3><a name="module.{{ module }}"></a>{{ module|bettertitle }}</h3>
|
||||||
<table class="table table-hover table-headings reports">
|
<table class="table table-hover table-headings reports">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-3">Name</th>
|
<th>Name</th>
|
||||||
<th class="col-md-9">Description</th>
|
<th>Status</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th class="text-right">Last Run</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -21,7 +23,15 @@
|
|||||||
<td>
|
<td>
|
||||||
<a href="{% url 'extras:script' module=script.module name=class_name %}" name="script.{{ class_name }}"><strong>{{ script }}</strong></a>
|
<a href="{% url 'extras:script' module=script.module name=class_name %}" name="script.{{ class_name }}"><strong>{{ script }}</strong></a>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{% include 'extras/inc/job_label.html' with result=script.result %}
|
||||||
|
</td>
|
||||||
<td>{{ script.Meta.description }}</td>
|
<td>{{ script.Meta.description }}</td>
|
||||||
|
{% if script.result %}
|
||||||
|
<td class="text-right">{{ script.result.created }}</td>
|
||||||
|
{% else %}
|
||||||
|
<td class="text-right text-muted">Never</td>
|
||||||
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -34,5 +44,26 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
{% if scripts %}
|
||||||
|
<div class="panel panel-default">
|
||||||
|
{% for module, module_scripts in scripts.items %}
|
||||||
|
<div class="panel-heading">
|
||||||
|
<strong>{{ module|bettertitle }}</strong>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
{% for class_name, script in module_scripts.items %}
|
||||||
|
<a href="#script.{{ class_name }}" class="list-group-item">
|
||||||
|
<i class="fa fa-list-alt"></i> {{ script.name }}
|
||||||
|
<div class="pull-right">
|
||||||
|
{% include 'extras/inc/job_label.html' with result=script.result %}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
<span id="pending-result-label">{% include 'extras/inc/job_label.html' with result=result %}</span>
|
<span id="pending-result-label">{% include 'extras/inc/job_label.html' with result=result %}</span>
|
||||||
</p>
|
</p>
|
||||||
<div role="tabpanel" class="tab-pane active" id="log">
|
<div role="tabpanel" class="tab-pane active" id="log">
|
||||||
{% if result.completed %}
|
{% if result.completed and result.status != 'errored' %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
@ -76,6 +76,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% elif result.stats == 'errored' %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="well">Error during script execution</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
|
Loading…
Reference in New Issue
Block a user