Browse Source

UI for entering cron expression and setting timezone.

pull/109/head
Pēteris Caune 8 years ago
parent
commit
6ada656df4
10 changed files with 152 additions and 34 deletions
  1. +7
    -2
      hc/api/migrations/0027_auto_20161213_1059.py
  2. +6
    -1
      hc/api/models.py
  3. +4
    -1
      hc/front/forms.py
  4. +21
    -2
      hc/front/tests/test_update_timeout.py
  5. +6
    -0
      hc/front/views.py
  6. +8
    -0
      static/css/my_checks.css
  7. +36
    -14
      static/js/checks.js
  8. +46
    -13
      templates/front/my_checks.html
  9. +8
    -1
      templates/front/my_checks_desktop.html
  10. +10
    -0
      templates/front/my_checks_mobile.html

hc/api/migrations/0027_auto_20161205_0833.py → hc/api/migrations/0027_auto_20161213_1059.py View File


+ 6
- 1
hc/api/models.py View File

@ -22,6 +22,9 @@ STATUSES = (
) )
DEFAULT_TIMEOUT = td(days=1) DEFAULT_TIMEOUT = td(days=1)
DEFAULT_GRACE = td(hours=1) DEFAULT_GRACE = td(hours=1)
CHECK_KINDS = (("simple", "Simple"),
("cron", "Cron"))
CHANNEL_KINDS = (("email", "Email"), CHANNEL_KINDS = (("email", "Email"),
("webhook", "Webhook"), ("webhook", "Webhook"),
("hipchat", "HipChat"), ("hipchat", "HipChat"),
@ -52,9 +55,11 @@ class Check(models.Model):
code = models.UUIDField(default=uuid.uuid4, editable=False, db_index=True) code = models.UUIDField(default=uuid.uuid4, editable=False, db_index=True)
user = models.ForeignKey(User, blank=True, null=True) user = models.ForeignKey(User, blank=True, null=True)
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
kind = models.CharField(max_length=10, default="simple",
choices=CHECK_KINDS)
timeout = models.DurationField(default=DEFAULT_TIMEOUT) timeout = models.DurationField(default=DEFAULT_TIMEOUT)
grace = models.DurationField(default=DEFAULT_GRACE) grace = models.DurationField(default=DEFAULT_GRACE)
schedule = models.CharField(max_length=100, blank=True)
schedule = models.CharField(max_length=100, default="* * * * *")
tz = models.CharField(max_length=36, default="UTC") tz = models.CharField(max_length=36, default="UTC")
n_pings = models.IntegerField(default=0) n_pings = models.IntegerField(default=0)
last_ping = models.DateTimeField(null=True, blank=True) last_ping = models.DateTimeField(null=True, blank=True)


+ 4
- 1
hc/front/forms.py View File

@ -1,6 +1,6 @@
from django import forms from django import forms
from hc.front.validators import WebhookValidator from hc.front.validators import WebhookValidator
from hc.api.models import Channel
from hc.api.models import CHECK_KINDS, Channel
class NameTagsForm(forms.Form): class NameTagsForm(forms.Form):
@ -19,7 +19,10 @@ class NameTagsForm(forms.Form):
class TimeoutForm(forms.Form): class TimeoutForm(forms.Form):
kind = forms.ChoiceField(choices=CHECK_KINDS)
timeout = forms.IntegerField(min_value=60, max_value=2592000) timeout = forms.IntegerField(min_value=60, max_value=2592000)
schedule = forms.CharField(required=False, max_length=100)
tz = forms.CharField(required=False, max_length=36)
grace = forms.IntegerField(min_value=60, max_value=2592000) grace = forms.IntegerField(min_value=60, max_value=2592000)


+ 21
- 2
hc/front/tests/test_update_timeout.py View File

@ -13,22 +13,41 @@ class UpdateTimeoutTestCase(BaseTestCase):
def test_it_works(self): def test_it_works(self):
url = "/checks/%s/timeout/" % self.check.code url = "/checks/%s/timeout/" % self.check.code
payload = {"timeout": 3600, "grace": 60}
payload = {"kind": "simple", "timeout": 3600, "grace": 60}
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")
r = self.client.post(url, data=payload) r = self.client.post(url, data=payload)
self.assertRedirects(r, "/checks/") self.assertRedirects(r, "/checks/")
self.check.refresh_from_db() self.check.refresh_from_db()
self.assertEqual(self.check.kind, "simple")
self.assertEqual(self.check.timeout.total_seconds(), 3600) self.assertEqual(self.check.timeout.total_seconds(), 3600)
self.assertEqual(self.check.grace.total_seconds(), 60) self.assertEqual(self.check.grace.total_seconds(), 60)
# alert_after should be updated too # alert_after should be updated too
self.assertEqual(self.check.alert_after, self.check.get_alert_after()) self.assertEqual(self.check.alert_after, self.check.get_alert_after())
def test_it_saves_cron_expression(self):
url = "/checks/%s/timeout/" % self.check.code
payload = {
"kind": "cron",
"schedule": "* * * * *",
"tz": "UTC",
"timeout": 60,
"grace": 60
}
self.client.login(username="[email protected]", password="password")
r = self.client.post(url, data=payload)
self.assertRedirects(r, "/checks/")
self.check.refresh_from_db()
self.assertEqual(self.check.kind, "cron")
self.assertEqual(self.check.schedule, "* * * * *")
def test_team_access_works(self): def test_team_access_works(self):
url = "/checks/%s/timeout/" % self.check.code url = "/checks/%s/timeout/" % self.check.code
payload = {"timeout": 7200, "grace": 60}
payload = {"kind": "simple", "timeout": 7200, "grace": 60}
# Logging in as bob, not alice. Bob has team access so this # Logging in as bob, not alice. Bob has team access so this
# should work. # should work.


+ 6
- 0
hc/front/views.py View File

@ -163,12 +163,18 @@ def update_timeout(request, code):
form = TimeoutForm(request.POST) form = TimeoutForm(request.POST)
if form.is_valid(): if form.is_valid():
check.kind = form.cleaned_data["kind"]
check.timeout = td(seconds=form.cleaned_data["timeout"]) check.timeout = td(seconds=form.cleaned_data["timeout"])
check.grace = td(seconds=form.cleaned_data["grace"]) check.grace = td(seconds=form.cleaned_data["grace"])
check.schedule = form.cleaned_data["schedule"]
check.tz = form.cleaned_data["tz"]
if check.last_ping: if check.last_ping:
check.alert_after = check.get_alert_after() check.alert_after = check.get_alert_after()
check.save() check.save()
else:
assert 0, "form is not valid! %s" % form.errors
return redirect("hc-checks") return redirect("hc-checks")


+ 8
- 0
static/css/my_checks.css View File

@ -23,6 +23,14 @@
} }
#type-simple, #type-cron {
width: 70px;
}
#schedule-block {
margin: 0 50px;
}
#period-slider { #period-slider {
margin: 20px 50px 80px 50px; margin: 20px 50px 80px 50px;
} }


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

@ -91,11 +91,9 @@ $(function () {
$('[data-toggle="tooltip"]').tooltip(); $('[data-toggle="tooltip"]').tooltip();
$(".my-checks-name").click(function() { $(".my-checks-name").click(function() {
var $this = $(this);
$("#update-name-form").attr("action", $this.data("url"));
$("#update-name-input").val($this.data("name"));
$("#update-tags-input").val($this.data("tags"));
$("#update-name-form").attr("action", this.dataset.url);
$("#update-name-input").val(this.dataset.name);
$("#update-tags-input").val(this.dataset.tags);
$('#update-name-modal').modal("show"); $('#update-name-modal').modal("show");
$("#update-name-input").focus(); $("#update-name-input").focus();
@ -103,21 +101,45 @@ $(function () {
}); });
$(".timeout-grace").click(function() { $(".timeout-grace").click(function() {
var $this = $(this);
$("#update-timeout-form").attr("action", this.dataset.url);
periodSlider.noUiSlider.set(this.dataset.timeout);
graceSlider.noUiSlider.set(this.dataset.grace);
$("#schedule").val(this.dataset.schedule);
$("#tz").val(this.dataset.tz);
if (this.dataset.kind == "cron") {
$("#type-simple").removeClass("active");
$("#type-cron").addClass("active");
$("#type-cron input").prop("checked", true);
$("#period-block").hide();
$("#schedule-block").show();
} else {
$("#type-simple").addClass("active");
$("#type-simple input").prop("checked", true);
$("#type-cron").removeClass("active");
$("#period-block").show();
$("#schedule-block").hide();
}
$("#update-timeout-form").attr("action", $this.data("url"));
periodSlider.noUiSlider.set($this.data("timeout"))
graceSlider.noUiSlider.set($this.data("grace"))
$('#update-timeout-modal').modal({"show":true, "backdrop":"static"}); $('#update-timeout-modal').modal({"show":true, "backdrop":"static"});
return false; return false;
}); });
$(".check-menu-remove").click(function() {
var $this = $(this);
$("#type-simple").click(function() {
$("#period-block").show();
$("#schedule-block").hide();
});
$("#type-cron").click(function() {
$("#period-block").hide();
$("#schedule-block").show();
});
$("#remove-check-form").attr("action", $this.data("url"));
$(".remove-check-name").text($this.data("name"));
$(".check-menu-remove").click(function() {
$("#remove-check-form").attr("action", this.dataset.url);
$(".remove-check-name").text(this.dataset.name);
$('#remove-check-modal').modal("show"); $('#remove-check-modal').modal("show");
return false; return false;


+ 46
- 13
templates/front/my_checks.html View File

@ -118,20 +118,42 @@
<input type="hidden" name="grace" id="update-timeout-grace" /> <input type="hidden" name="grace" id="update-timeout-grace" />
<div class="modal-content"> <div class="modal-content">
<div class="modal-body"> <div class="modal-body">
<div class="update-timeout-info text-center">
<span
class="update-timeout-label"
data-toggle="tooltip"
title="Expected time between pings.">
Period
</span>
<span
id="period-slider-value"
class="update-timeout-value">
1 day
</span>
<div id="period-block">
<div class="update-timeout-info text-center">
<span
class="update-timeout-label"
data-toggle="tooltip"
title="Expected time between pings.">
Period
</span>
<span
id="period-slider-value"
class="update-timeout-value">
1 day
</span>
</div>
<div id="period-slider"></div>
</div>
<div id="schedule-block">
<div class="form-group">
<label for="schedule">
Cron expression
<a href="https://en.wikipedia.org/wiki/Cron#Overview">(reference)</a>
</label>
<input
type="text"
class="form-control input-lg"
id="schedule"
name="schedule"
placeholder="* * * * *">
</div>
<div class="form-group">
<label for="schedule">Server's Timezone</label>
<select id="tz" name="tz" class="form-control">
<option>UTC</option>
</select>
</div>
</div> </div>
<div id="period-slider"></div>
<div class="update-timeout-info text-center"> <div class="update-timeout-info text-center">
<span <span
@ -162,6 +184,17 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<div class="btn-group pull-left" data-toggle="buttons">
<label id="type-simple" class="btn btn-default">
<input type="radio" name="kind" value="simple" autocomplete="off">
Simple
</label>
<label id="type-cron" class="btn btn-default">
<input type="radio" name="kind" value="cron" autocomplete="off">
Cron
</label>
</div>
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Save</button> <button type="submit" class="btn btn-primary">Save</button>
</div> </div>


+ 8
- 1
templates/front/my_checks_desktop.html View File

@ -52,10 +52,17 @@
<td class="timeout-cell"> <td class="timeout-cell">
<span <span
data-url="{% url 'hc-update-timeout' check.code %}" data-url="{% url 'hc-update-timeout' check.code %}"
data-kind="{{ check.kind }}"
data-timeout="{{ check.timeout.total_seconds }}" data-timeout="{{ check.timeout.total_seconds }}"
data-grace="{{ check.grace.total_seconds }}" data-grace="{{ check.grace.total_seconds }}"
data-schedule="{{ check.schedule }}"
data-tz="{{ check.tz }}"
class="timeout-grace"> class="timeout-grace">
{{ check.timeout|hc_duration }}
{% if check.kind == "simple" %}
{{ check.timeout|hc_duration }}
{% elif check.kind == "cron" %}
{{ check.schedule }}
{% endif %}
<br /> <br />
<span class="checks-subline"> <span class="checks-subline">
{{ check.grace|hc_duration }} {{ check.grace|hc_duration }}


+ 10
- 0
templates/front/my_checks_mobile.html View File

@ -46,10 +46,17 @@
</td> </td>
</tr> </tr>
{% endif %} {% endif %}
{% if check.kind == "simple " %}
<tr> <tr>
<th>Period</th> <th>Period</th>
<td>{{ check.timeout|hc_duration }}</td> <td>{{ check.timeout|hc_duration }}</td>
</tr> </tr>
{% elif check.kind == "cron" %}
<tr>
<th>Schedule</th>
<td>{{ check.schedule }}</td>
</tr>
{% endif %}
<tr> <tr>
<th>Grace Time</th> <th>Grace Time</th>
<td>{{ check.grace|hc_duration }}</td> <td>{{ check.grace|hc_duration }}</td>
@ -79,9 +86,12 @@
<a <a
href="#" href="#"
data-kind="{{ check.kind }}"
data-url="{% url 'hc-update-timeout' check.code %}" data-url="{% url 'hc-update-timeout' check.code %}"
data-timeout="{{ check.timeout.total_seconds }}" data-timeout="{{ check.timeout.total_seconds }}"
data-grace="{{ check.grace.total_seconds }}" data-grace="{{ check.grace.total_seconds }}"
data-schedule="{{ check.schedule }}"
data-tz="{{ check.tz }}"
class="btn btn-default timeout-grace">Change Period</a> class="btn btn-default timeout-grace">Change Period</a>
<a href="{% url 'hc-log' check.code %}" class="btn btn-default">Log</a> <a href="{% url 'hc-log' check.code %}" class="btn btn-default">Log</a>


Loading…
Cancel
Save