diff --git a/hc/front/urls.py b/hc/front/urls.py index 8eea9776..314959c4 100644 --- a/hc/front/urls.py +++ b/hc/front/urls.py @@ -44,6 +44,7 @@ urlpatterns = [ url(r'^checks/$', views.my_checks, name="hc-checks"), url(r'^checks/add/$', views.add_check, name="hc-add-check"), url(r'^checks/cron_preview/$', views.cron_preview), + url(r'^checks/status/$', views.status), url(r'^checks/([\w-]+)/', include(check_urls)), url(r'^integrations/', include(channel_urls)), diff --git a/hc/front/views.py b/hc/front/views.py index 9f8eb298..62d7cf55 100644 --- a/hc/front/views.py +++ b/hc/front/views.py @@ -8,7 +8,7 @@ from django.contrib.auth.decorators import login_required from django.core import signing from django.db.models import Count from django.http import (Http404, HttpResponse, HttpResponseBadRequest, - HttpResponseForbidden) + HttpResponseForbidden, JsonResponse) from django.shortcuts import get_object_or_404, redirect, render from django.template.loader import render_to_string from django.urls import reverse @@ -34,6 +34,24 @@ import requests VALID_SORT_VALUES = ("name", "-name", "last_ping", "-last_ping", "created") +def _tags_statuses(checks): + tags, down, grace = {}, {}, {} + for check in checks: + if check.get_status() == "down": + for tag in check.tags_list(): + down[tag] = "down" + elif check.in_grace_period(): + for tag in check.tags_list(): + grace[tag] = "grace" + else: + for tag in check.tags_list(): + tags[tag] = "up" + + tags.update(grace) + tags.update(down) + return tags + + @login_required def my_checks(request): if request.GET.get("sort") in VALID_SORT_VALUES: @@ -42,35 +60,41 @@ def my_checks(request): checks = list(Check.objects.filter(user=request.team.user)) - tags, down_tags, grace_tags = set(), set(), set() - for check in checks: - status = check.get_status() - for tag in check.tags_list(): - tags.add(tag) - - if status == "down": - down_tags.add(tag) - elif check.in_grace_period(): - grace_tags.add(tag) - - can_add_more = len(checks) < request.team.check_limit + pairs = list(_tags_statuses(checks).items()) + pairs.sort(key=lambda pair: pair[0].lower()) ctx = { "page": "checks", "checks": checks, "now": timezone.now(), - "tags": sorted(tags, key=lambda s: s.lower()), - "down_tags": down_tags, - "grace_tags": grace_tags, + "tags": pairs, "ping_endpoint": settings.PING_ENDPOINT, "timezones": all_timezones, - "can_add_more": can_add_more, + "can_add_more": len(checks) < request.team.check_limit, "sort": request.profile.sort } return render(request, "front/my_checks.html", ctx) +@login_required +def status(request): + checks = list(Check.objects.filter(user=request.team.user)) + + details = [] + for check in checks: + status = "grace" if check.in_grace_period() else check.get_status() + + ctx = {"check": check} + details.append({ + "code": str(check.code), + "status": status, + "last_ping": render_to_string("front/last_ping_cell.html", ctx) + }) + + return JsonResponse({"details": details, "tags": _tags_statuses(checks)}) + + def _welcome_check(request): check = None if "welcome_code" in request.session: diff --git a/static/css/base.css b/static/css/base.css index 655c9a19..a8e277ac 100644 --- a/static/css/base.css +++ b/static/css/base.css @@ -58,7 +58,7 @@ body { } .status.icon-up { color: #5cb85c; } -.status.icon-up.new, .status.icon-paused { color: #CCC; } +.status.icon-new, .status.icon-paused { color: #CCC; } .status.icon-grace { color: #f0ad4e; } .status.icon-down { color: #d9534f; } diff --git a/static/css/icomoon.css b/static/css/icomoon.css index 6c42598c..eb78dad5 100644 --- a/static/css/icomoon.css +++ b/static/css/icomoon.css @@ -60,7 +60,7 @@ .icon-delete:before { content: "\e901"; } -.icon-up:before, .icon-ok:before { +.icon-new:before, .icon-up:before, .icon-ok:before { content: "\e902"; } .icon-clippy:before { diff --git a/static/css/my_checks.css b/static/css/my_checks.css index 7454d1da..861acc8a 100644 --- a/static/css/my_checks.css +++ b/static/css/my_checks.css @@ -1,3 +1,22 @@ +#my-checks-tags button.up { + color: #333; + background-color: #fff; + border-color: #ccc; +} + +#my-checks-tags button.grace { + color: #fff; + background-color: #f0ad4e; + border-color: #eea236; +} + + +#my-checks-tags button.down { + color: #fff; + background-color: #d9534f; + border-color: #d43f3a; +} + @media (min-width: 992px) { #update-timeout-modal .modal-dialog, #last-ping-modal .modal-dialog { width: 800px; diff --git a/static/js/checks.js b/static/js/checks.js index 1973fa3f..2d4822ec 100644 --- a/static/js/checks.js +++ b/static/js/checks.js @@ -175,7 +175,7 @@ $(function () { return false; }); - $(".last-ping").click(function() { + $(".last-ping-cell").on("click", ".last-ping", function() { $("#last-ping-body").text("Updating..."); $('#last-ping-modal').modal("show"); @@ -235,7 +235,15 @@ $(function () { return false; }); - $('[data-toggle="tooltip"]').tooltip(); + $('[data-toggle="tooltip"]').tooltip({ + title: function() { + var cssClasses = this.getAttribute("class"); + if (cssClasses.indexOf("icon-new") > -1) + return "New. Has never received a ping."; + if (cssClasses.indexOf("icon-paused") > -1) + return "Monitoring paused. Ping to resume."; + } + }); $(".usage-examples").click(function(e) { var a = e.target; @@ -249,6 +257,24 @@ $(function () { return false; }); + // Auto-refresh + function refresh() { + $.getJSON("/checks/status/", function(data) { + for(var i=0, el; el=data.details[i]; i++) { + $("#check-desktop-" + el.code + " .indicator-cell span").attr("class", "status icon-" + el.status); + $("#check-desktop-" + el.code + " .last-ping-cell").html(el.last_ping); + } + + $("#my-checks-tags button").each(function(a) { + var status = data.tags[this.innerText]; + if (status) { + this.setAttribute("class", "btn btn-xs " + status); + } + }); + }); + } + + // Copy to clipboard var clipboard = new Clipboard('button.copy-link'); $("button.copy-link").mouseout(function(e) { setTimeout(function() { diff --git a/templates/front/docs.html b/templates/front/docs.html index a13a7d86..484788dd 100644 --- a/templates/front/docs.html +++ b/templates/front/docs.html @@ -204,7 +204,7 @@ using the "-command" argument:

- + New. diff --git a/templates/front/last_ping_cell.html b/templates/front/last_ping_cell.html new file mode 100644 index 00000000..e712098f --- /dev/null +++ b/templates/front/last_ping_cell.html @@ -0,0 +1,12 @@ +{% load humanize %} + +{% if check.last_ping %} +
+ {{ check.last_ping|naturaltime }} + {% if check.has_confirmation_link %} +
confirmation link + {% endif %} +
+{% else %} +
Never
+{% endif %} \ No newline at end of file diff --git a/templates/front/my_checks.html b/templates/front/my_checks.html index 8b35bb96..ba0eff16 100644 --- a/templates/front/my_checks.html +++ b/templates/front/my_checks.html @@ -17,14 +17,8 @@ {% if tags %}
- {% for tag in tags %} - {% if tag in down_tags %} - - {% elif tag in grace_tags %} - - {% else %} - - {% endif %} + {% for tag, status in tags %} + {% endfor %}
{% endif %} diff --git a/templates/front/my_checks_desktop.html b/templates/front/my_checks_desktop.html index ae2a553b..1ab35a09 100644 --- a/templates/front/my_checks_desktop.html +++ b/templates/front/my_checks_desktop.html @@ -1,4 +1,4 @@ -{% load hc_extras humanize %} +{% load hc_extras %} @@ -28,20 +28,12 @@ {% for check in checks|sortchecks:sort %} - + -