forked from GithubBackups/healthchecks
Better style for Log page.
This commit is contained in:
parent
3a8a41f7a5
commit
aa2bc72293
@ -1,6 +1,6 @@
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from hc.api.models import Check
|
from hc.api.models import Check, Ping
|
||||||
|
|
||||||
|
|
||||||
class LogTestCase(TestCase):
|
class LogTestCase(TestCase):
|
||||||
@ -13,12 +13,15 @@ class LogTestCase(TestCase):
|
|||||||
self.check = Check(user=self.alice)
|
self.check = Check(user=self.alice)
|
||||||
self.check.save()
|
self.check.save()
|
||||||
|
|
||||||
|
ping = Ping(owner=self.check)
|
||||||
|
ping.save()
|
||||||
|
|
||||||
def test_it_works(self):
|
def test_it_works(self):
|
||||||
url = "/checks/%s/log/" % self.check.code
|
url = "/checks/%s/log/" % self.check.code
|
||||||
|
|
||||||
self.client.login(username="alice", password="password")
|
self.client.login(username="alice", password="password")
|
||||||
r = self.client.get(url)
|
r = self.client.get(url)
|
||||||
self.assertContains(r, "Log for", status_code=200)
|
self.assertContains(r, "Dates and times are", status_code=200)
|
||||||
|
|
||||||
def test_it_handles_bad_uuid(self):
|
def test_it_handles_bad_uuid(self):
|
||||||
url = "/checks/not-uuid/log/"
|
url = "/checks/not-uuid/log/"
|
||||||
|
@ -161,10 +161,30 @@ def log(request, code):
|
|||||||
|
|
||||||
pings = Ping.objects.filter(owner=check).order_by("-created")[:100]
|
pings = Ping.objects.filter(owner=check).order_by("-created")[:100]
|
||||||
|
|
||||||
|
# Now go through pings, calculate time gaps, and decorate
|
||||||
|
# the pings list for convenient use in template
|
||||||
|
wrapped = []
|
||||||
|
for i, ping in enumerate(pings):
|
||||||
|
prev = timezone.now() if i == 0 else pings[i - 1].created
|
||||||
|
|
||||||
|
duration = prev - ping.created
|
||||||
|
if duration > check.timeout:
|
||||||
|
downtime = {"prev_date": prev, "date": ping.created}
|
||||||
|
if i > 0:
|
||||||
|
wrapped[-1]["status"] = "late"
|
||||||
|
|
||||||
|
if duration > check.timeout + check.grace:
|
||||||
|
downtime["down"] = True
|
||||||
|
if i > 0:
|
||||||
|
wrapped[-1]["status"] = "down"
|
||||||
|
|
||||||
|
wrapped.append(downtime)
|
||||||
|
|
||||||
|
wrapped.append({"ping": ping})
|
||||||
|
|
||||||
ctx = {
|
ctx = {
|
||||||
"check": check,
|
"check": check,
|
||||||
"pings": pings
|
"pings": wrapped
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(request, "front/log.html", ctx)
|
return render(request, "front/log.html", ctx)
|
||||||
|
18
static/css/bootstrap.css
vendored
18
static/css/bootstrap.css
vendored
@ -4541,6 +4541,24 @@ fieldset[disabled] .navbar-inverse .btn-link:hover,
|
|||||||
fieldset[disabled] .navbar-inverse .btn-link:focus {
|
fieldset[disabled] .navbar-inverse .btn-link:focus {
|
||||||
color: #444444;
|
color: #444444;
|
||||||
}
|
}
|
||||||
|
.breadcrumb {
|
||||||
|
padding: 8px 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
list-style: none;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.breadcrumb > li {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.breadcrumb > li + li:before {
|
||||||
|
content: "/\00a0";
|
||||||
|
padding: 0 5px;
|
||||||
|
color: #cccccc;
|
||||||
|
}
|
||||||
|
.breadcrumb > .active {
|
||||||
|
color: #777777;
|
||||||
|
}
|
||||||
.label {
|
.label {
|
||||||
display: inline;
|
display: inline;
|
||||||
padding: .2em .6em .3em;
|
padding: .2em .6em .3em;
|
||||||
|
@ -1,3 +1,87 @@
|
|||||||
.log-table .remote-addr, .log-table .ua {
|
#log th {
|
||||||
|
border-top: 0;
|
||||||
|
border-bottom: 1px solid #E5E5E5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log td {
|
||||||
|
color: #444;
|
||||||
|
padding: 16px 8px;
|
||||||
|
position: relative;
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 1px solid #E5E5E5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log .datetime {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log .date {
|
||||||
|
display: inline-block;
|
||||||
|
width: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log .protocol {
|
||||||
|
white-space: nowrap;
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log .ip {
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log td.ua {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#log .bullet {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -6px;
|
||||||
|
left: 0;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border: 2px solid #FFF;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #376f37;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log .tl {
|
||||||
|
position: absolute;
|
||||||
|
left: 4px;
|
||||||
|
width: 4px;
|
||||||
|
background: #5cb85c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log .top {
|
||||||
|
top: 0;
|
||||||
|
height: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log .bottom {
|
||||||
|
top: 50%;
|
||||||
|
height: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log .full-down {
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
background: #d9534f;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log .down { background: #d9534f; }
|
||||||
|
#log .late { background: #f0ad4e; }
|
||||||
|
|
||||||
|
#log .tl-cell {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log .downtime-cell {
|
||||||
|
border: 0;
|
||||||
|
font-size: small;
|
||||||
|
color: #d9534f;
|
||||||
}
|
}
|
2
stuff/bootstrap/bootstrap.less
vendored
2
stuff/bootstrap/bootstrap.less
vendored
@ -29,7 +29,7 @@
|
|||||||
@import "input-groups.less";
|
@import "input-groups.less";
|
||||||
@import "navs.less";
|
@import "navs.less";
|
||||||
@import "navbar.less";
|
@import "navbar.less";
|
||||||
// @import "breadcrumbs.less";
|
@import "breadcrumbs.less";
|
||||||
// @import "pagination.less";
|
// @import "pagination.less";
|
||||||
// @import "pager.less";
|
// @import "pager.less";
|
||||||
@import "labels.less";
|
@import "labels.less";
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
<link rel="stylesheet" href="{% static 'css/syntax.css' %}" type="text/css">
|
<link rel="stylesheet" href="{% static 'css/syntax.css' %}" type="text/css">
|
||||||
<link rel="stylesheet" href="{% static 'css/channels.css' %}" type="text/css">
|
<link rel="stylesheet" href="{% static 'css/channels.css' %}" type="text/css">
|
||||||
<link rel="stylesheet" href="{% static 'css/channel_checks.css' %}" type="text/css">
|
<link rel="stylesheet" href="{% static 'css/channel_checks.css' %}" type="text/css">
|
||||||
|
<link rel="stylesheet" href="{% static 'css/log.css' %}" type="text/css">
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
</head>
|
</head>
|
||||||
<body class="page-{{ page }}">
|
<body class="page-{{ page }}">
|
||||||
|
@ -5,39 +5,82 @@
|
|||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<h1>Log for “{{ check.name_then_code }}”</h1>
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="{% url 'hc-checks' %}">Checks</a></li>
|
||||||
|
<li>{{ check.name_then_code }}</li>
|
||||||
|
<li class="active">Log</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
{% if pings %}
|
{% if pings %}
|
||||||
|
|
||||||
|
<p class="log-notes">
|
||||||
|
Note: Dates and times are displayed in <strong>UTC</strong>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-striped log-table">
|
<table class="table" id="log">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Transport</th>
|
<th></th>
|
||||||
<th>Time</th>
|
<th class="datetime">
|
||||||
<th>Remote IP</th>
|
<span class="date">Date</span>
|
||||||
<th>User Agent</th>
|
<span class="time">Time</span>
|
||||||
|
</th>
|
||||||
|
<th class="ip">IP</th>
|
||||||
|
<th class="protocol">Protocol</th>
|
||||||
|
<th class="ua">User Agent</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for ping in pings %}
|
{% for record in pings %}
|
||||||
|
{% if record.ping %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td class="tl-cell">
|
||||||
{% if ping.scheme == "email" %}
|
<div class="tl top"></div>
|
||||||
Email
|
<div class="tl bottom {{ record.status }}"></div>
|
||||||
{% elif ping.scheme == "http" %}
|
<div class="bullet"></div>
|
||||||
HTTP
|
|
||||||
{% elif ping.scheme == "https" %}
|
|
||||||
HTTPS
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="datetime">
|
||||||
<span
|
<div>
|
||||||
data-toggle="tooltip"
|
<span class="date">
|
||||||
title="{{ ping.created }} GMT">
|
{{ record.ping.created|date:"N j" }}
|
||||||
{{ ping.created|naturaltime }}
|
</span>
|
||||||
</span>
|
<span class="time">
|
||||||
|
{{ record.ping.created|date:"H:i" }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="ip">
|
||||||
|
{{ record.ping.remote_addr|default:"" }}
|
||||||
|
</td>
|
||||||
|
<td class="protocol">
|
||||||
|
{{ record.ping.scheme }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="ua">
|
||||||
|
{{ record.ping.ua }}
|
||||||
</td>
|
</td>
|
||||||
<td class="remote-addr">{{ ping.remote_addr }}</td>
|
|
||||||
<td class="ua">{{ ping.ua }}</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
{% if record.down %}
|
||||||
|
<tr>
|
||||||
|
<td class="tl-cell">
|
||||||
|
<div class="tl full-down"></div>
|
||||||
|
</td>
|
||||||
|
<td class="downtime-cell" colspan="4">
|
||||||
|
<p>No ping received for {{ record.date|timesince:record.prev_date }}</p>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
<tr>
|
||||||
|
<td class="tl-cell">
|
||||||
|
<div class="tl top late"></div>
|
||||||
|
<div class="tl bottom"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user