Browse Source

Toggle integrations on/off on "My Checks" page.

pull/178/head
Pēteris Caune 7 years ago
parent
commit
83a2ff17e6
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
13 changed files with 123 additions and 65 deletions
  1. +17
    -0
      hc/api/models.py
  2. +2
    -2
      hc/front/tests/test_channel_checks.py
  3. +1
    -0
      hc/front/urls.py
  4. +24
    -1
      hc/front/views.py
  5. +6
    -2
      static/css/base.css
  6. +21
    -38
      static/css/my_checks_desktop.css
  7. +5
    -1
      static/css/my_checks_mobile.css
  8. +14
    -0
      static/js/checks.js
  9. +3
    -3
      templates/base.html
  10. +1
    -1
      templates/front/channel_checks.html
  11. +1
    -10
      templates/front/my_checks.html
  12. +23
    -4
      templates/front/my_checks_desktop.html
  13. +5
    -3
      templates/front/my_checks_mobile.html

+ 17
- 0
hc/api/models.py View File

@ -240,6 +240,23 @@ class Channel(models.Model):
email_verified = models.BooleanField(default=False)
checks = models.ManyToManyField(Check)
def __str__(self):
if self.kind == "email":
return "Email to %s" % self.value
elif self.kind == "sms":
if self.sms_label:
return "SMS to %s" % self.sms_label
return "SMS to %s" % self.sms_number
elif self.kind == "slack":
return "Slack %s" % self.slack.channel
elif self.kind == "telegram":
return "Telegram %s" % self.telegram_name
return self.get_kind_display()
def icon_url(self):
return settings.STATIC_URL + "img/integrations/%s.png" % self.kind
def assign_all_checks(self):
checks = Check.objects.filter(user=self.user)
self.checks.add(*checks)


+ 2
- 2
hc/front/tests/test_channel_checks.py View File

@ -15,7 +15,7 @@ class ChannelChecksTestCase(BaseTestCase):
self.client.login(username="[email protected]", password="password")
r = self.client.get(url)
self.assertContains(r, "Assign Checks to Channel", status_code=200)
self.assertContains(r, "Assign Checks to Integration", status_code=200)
def test_team_access_works(self):
url = "/integrations/%s/checks/" % self.channel.code
@ -24,7 +24,7 @@ class ChannelChecksTestCase(BaseTestCase):
# should work.
self.client.login(username="[email protected]", password="password")
r = self.client.get(url)
self.assertContains(r, "Assign Checks to Channel", status_code=200)
self.assertContains(r, "Assign Checks to Integration", status_code=200)
def test_it_checks_owner(self):
# channel does not belong to mallory so this should come back


+ 1
- 0
hc/front/urls.py View File

@ -9,6 +9,7 @@ check_urls = [
path('remove/', views.remove_check, name="hc-remove-check"),
path('log/', views.log, name="hc-log"),
path('last_ping/', views.ping_details, name="hc-last-ping"),
path('channels/<uuid:channel_code>/enabled', views.switch_channel, name="hc-switch-channel"),
path('pings/<int:n>/', views.ping_details, name="hc-ping-details"),
]


+ 24
- 1
hc/front/views.py View File

@ -59,16 +59,20 @@ def my_checks(request):
request.profile.sort = request.GET["sort"]
request.profile.save()
checks = list(Check.objects.filter(user=request.team.user))
checks = list(Check.objects.filter(user=request.team.user).prefetch_related("channel_set"))
sortchecks(checks, request.profile.sort)
tags_statuses, num_down = _tags_statuses(checks)
pairs = list(tags_statuses.items())
pairs.sort(key=lambda pair: pair[0].lower())
channels = Channel.objects.filter(user=request.team.user)
channels = list(channels.order_by("created"))
ctx = {
"page": "checks",
"checks": checks,
"channels": channels,
"num_down": num_down,
"now": timezone.now(),
"tags": pairs,
@ -104,6 +108,25 @@ def status(request):
})
@login_required
@require_POST
def switch_channel(request, code, channel_code):
check = get_object_or_404(Check, code=code)
if check.user_id != request.team.user.id:
return HttpResponseForbidden()
channel = get_object_or_404(Channel, code=channel_code)
if channel.user_id != request.team.user.id:
return HttpResponseForbidden()
if request.POST.get("state") == "on":
channel.checks.add(check)
else:
channel.checks.remove(check)
return HttpResponse()
def _welcome_check(request):
check = None
if "welcome_code" in request.session:


+ 6
- 2
static/css/base.css View File

@ -48,11 +48,15 @@ body {
}
}
.navbar-text {
font-size: small;
}
.page-checks .container-fluid {
/* Fluid below 1320px, but max width capped to 1320px ... */
max-width: 1320px;
}
.status {
font-size: 24px;
}
@ -86,4 +90,4 @@ pre {
.jumbotron p {
font-weight: 300;
}
}

+ 21
- 38
static/css/my_checks_desktop.css View File

@ -11,11 +11,6 @@
font-style: italic;
}
table.table tr > th.th-name {
padding-left: 21px;
}
#checks-table .indicator-cell {
text-align: center;
}
@ -24,10 +19,6 @@ table.table tr > th.th-name {
border-top: 0;
}
#checks-table th {
border-top: 0;
}
#checks-table a.default {
color: #333;
}
@ -41,26 +32,33 @@ table.table tr > th.th-name {
border-top: 1px solid #f1f1f1;
}
#checks-table .my-checks-name {
#checks-table .my-checks-name,
#checks-table .integrations,
#checks-table .timeout-grace,
#checks-table .last-ping,
#checks-table .last-ping-never {
border: 1px solid rgba(0, 0, 0, 0);
padding: 6px;
display: block;
}
#checks-table tr:hover .my-checks-name {
#checks-table tr:hover .my-checks-name,
#checks-table tr:hover .integrations,
#checks-table tr:hover .timeout-grace,
#checks-table tr:hover .last-ping {
border: 1px dotted #AAA;
cursor: pointer;
}
#checks-table > tbody > tr > th.th-name,
#checks-table > tbody > tr > th.th-integrations,
#checks-table > tbody > tr > th.th-period,
#checks-table > tbody > tr > th.th-last-ping {
padding-left: 15px;
}
#checks-table .timeout-grace {
border: 1px solid rgba(0, 0, 0, 0);
padding: 6px;
display: block;
#checks-table .integrations img {
padding: 10px 2px;
width: 24px;
}
.timeout-grace .cron-expression {
@ -71,26 +69,6 @@ table.table tr > th.th-name {
max-width: 120px;
}
#checks-table tr:hover .timeout-grace {
border: 1px dotted #AAA;
cursor: pointer;
}
#checks-table .last-ping {
border: 1px solid rgba(0, 0, 0, 0);
padding: 6px;
}
#checks-table .last-ping-never {
padding: 7px;
}
#checks-table tr:hover .last-ping {
border: 1px dotted #AAA;
cursor: pointer;
}
.checks-subline {
color: #888;
white-space: nowrap;
@ -139,7 +117,9 @@ tr:hover .copy-link {
opacity: 1
}
#checks-table .url-cell {
#checks-table .url-cell,
#checks-table .integrations-cell,
#checks-table .timeout-cell {
white-space: nowrap;
}
@ -147,7 +127,6 @@ tr:hover .copy-link {
color: #888;
}
.my-checks-url {
font-family: "Lucida Console", Monaco, monospace;
font-size: 11.7px;
@ -156,3 +135,7 @@ tr:hover .copy-link {
color: #333;
}
.integrations-cell .off {
filter: grayscale(100%);
opacity: 0.3;
}

+ 5
- 1
static/css/my_checks_mobile.css View File

@ -56,4 +56,8 @@
.label-down {
background-color: #d9534f;
}
}
#checks-list .base {
color: #888;
}

+ 14
- 0
static/js/checks.js View File

@ -175,6 +175,19 @@ $(function () {
return false;
});
$(".integrations img").click(function() {
var isOff = $(this).toggleClass("off").hasClass("off");
var token = $('input[name=csrfmiddlewaretoken]').val();
$.ajax({
url: this.dataset.url,
type: "post",
headers: {"X-CSRFToken": token},
data: {"state": isOff ? "off" : "on"}
});
return false;
});
$(".last-ping-cell").on("click", ".last-ping", function() {
$("#ping-details-body").text("Updating...");
$('#ping-details-modal').modal("show");
@ -192,6 +205,7 @@ $(function () {
return false;
});
// Filtering by tags
$("#my-checks-tags button").click(function() {
// .active has not been updated yet by bootstrap code,


+ 3
- 3
templates/base.html View File

@ -49,7 +49,7 @@
</head>
<body class="page-{{ page }}">
<nav class="navbar navbar-default">
<div class="container">
<div class="container{% if page == "checks" %}-fluid{% endif %}">
<div class="navbar-header">
<button
type="button"
@ -158,13 +158,13 @@
</nav>
{% block containers %}
<div class="container">
<div class="container{% if page == "checks" %}-fluid{% endif %}">
{% block content %}{% endblock %}
</div>
{% endblock %}
<footer class="footer">
<div class="container">
<div class="container{% if page == "checks" %}-fluid{% endif %}">
<ul>
<li>
Powered by Healthchecks open-source project


+ 1
- 1
templates/front/channel_checks.html View File

@ -5,7 +5,7 @@
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="update-timeout-title">Assign Checks to Channel</h4>
<h4 class="update-timeout-title">Assign Checks to Integration</h4>
</div>
<input type="hidden" name="channel" value="{{ channel.code }}" />


+ 1
- 10
templates/front/my_checks.html View File

@ -5,15 +5,6 @@
{% block content %}
<div class="row">
<div class="col-sm-12">
<h1>
{% if request.team == request.user.profile %}
My Checks
{% else %}
{{ request.team.team_name }}
{% endif %}
</h1>
</div>
{% if tags %}
<div id="my-checks-tags" class="col-sm-12">
{% for tag, status in tags %}
@ -99,7 +90,7 @@
class="form-control" />
<span class="help-block">
Optionally, assign tags for easy filtering.
Use tags for easy filtering and for status badges.
Separate multiple tags with spaces.
</span>
</div>


+ 23
- 4
templates/front/my_checks_desktop.html View File

@ -1,5 +1,5 @@
{% load hc_extras %}
<table id="checks-table" class="table hidden-xs">
{% load hc_extras staticfiles %}
<table id="checks-table" class="table hidden-xs hidden-sm">
<tr>
<th></th>
<th class="th-name">
@ -18,6 +18,7 @@
{% endif %}
</th>
<th>Ping URL</th>
<th class="th-integrations">Integrations</th>
<th class="th-period">
Period <br />
<span class="checks-subline">Grace</span>
@ -69,8 +70,26 @@
copy
</button>
</td>
<td class="integrations-cell">
{% if channels|length < 8 %}
<div class="integrations">
{% spaceless %}
{% for channel in channels %}
<img
data-toggle="tooltip"
data-url="{% url 'hc-switch-channel' check.code channel.code %}"
title="{{ channel }}"
src="{{ channel.icon_url }}"
{% if channel in check.channel_set.all %}{% else %}class="off"{% endif %} />
{% endfor %}
{% endspaceless %}
</div>
{% else %}
{{ check.channel_set.all|length }} of {{ channels|length }}
{% endif %}
</td>
<td class="timeout-cell">
<span
<div
data-url="{% url 'hc-update-timeout' check.code %}"
data-kind="{{ check.kind }}"
data-timeout="{{ check.timeout.total_seconds }}"
@ -87,7 +106,7 @@
<span class="checks-subline">
{{ check.grace|hc_duration }}
</span>
</span>
</div>
</td>
<td id="lpd-{{ check.code}}" class="last-ping-cell">
{% include "front/last_ping_cell.html" with check=check %}


+ 5
- 3
templates/front/my_checks_mobile.html View File

@ -1,6 +1,6 @@
{% load hc_extras humanize %}
<ul id="checks-list" class="visible-xs">
<ul id="checks-list" class="visible-xs visible-sm">
{% for check in checks %}
<li>
<h2>
@ -8,7 +8,9 @@
{{ check.name|default:"unnamed" }}
</span>
<code>{{ check.code }}</code>
<code>
<span class="base hidden-xs">{{ ping_endpoint }}</span>{{ check.code }}
</code>
</h2>
<a
@ -42,7 +44,7 @@
</td>
</tr>
{% endif %}
{% if check.kind == "simple " %}
{% if check.kind == "simple" %}
<tr>
<th>Period</th>
<td>{{ check.timeout|hc_duration }}</td>


Loading…
Cancel
Save