forked from GithubBackups/healthchecks
Notification Channels WIP
This commit is contained in:
parent
63bdd841fc
commit
061fc4f6a9
@ -9,7 +9,7 @@ from django.http import HttpResponseBadRequest
|
|||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
|
|
||||||
from hc.accounts.forms import EmailForm
|
from hc.accounts.forms import EmailForm
|
||||||
from hc.api.models import Check
|
from hc.api.models import Channel, Check
|
||||||
from hc.lib.emails import send
|
from hc.lib.emails import send
|
||||||
|
|
||||||
|
|
||||||
@ -18,6 +18,13 @@ def _make_user(email):
|
|||||||
user = User(username=username, email=email)
|
user = User(username=username, email=email)
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
|
channel = Channel()
|
||||||
|
channel.user = user
|
||||||
|
channel.kind = "email"
|
||||||
|
channel.value = email
|
||||||
|
channel.email_verified = True
|
||||||
|
channel.save()
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
@ -29,6 +36,9 @@ def _associate_demo_check(request, user):
|
|||||||
if check.user is None:
|
if check.user is None:
|
||||||
check.user = user
|
check.user = user
|
||||||
check.save()
|
check.save()
|
||||||
|
|
||||||
|
check.assign_all_channels()
|
||||||
|
|
||||||
del request.session["welcome_code"]
|
del request.session["welcome_code"]
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from hc.api.models import Check, Ping
|
from hc.api.models import Channel, Check, Ping
|
||||||
|
|
||||||
|
|
||||||
class OwnershipListFilter(admin.SimpleListFilter):
|
class OwnershipListFilter(admin.SimpleListFilter):
|
||||||
@ -55,4 +55,10 @@ class PingsAdmin(admin.ModelAdmin):
|
|||||||
return obj.owner.name if obj.owner.name else obj.owner.code
|
return obj.owner.name if obj.owner.name else obj.owner.code
|
||||||
|
|
||||||
def email(self, obj):
|
def email(self, obj):
|
||||||
return obj.owner.user.email if obj.owner.user else None
|
return obj.owner.user.email if obj.owner.user else None
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Channel)
|
||||||
|
class ChannelsAdmin(admin.ModelAdmin):
|
||||||
|
list_select_related = ("user", )
|
||||||
|
list_display = ("id", "code", "user", "kind", "value")
|
||||||
|
30
hc/api/migrations/0010_channel.py
Normal file
30
hc/api/migrations/0010_channel.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
from django.conf import settings
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('api', '0009_auto_20150801_1250'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Channel',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, auto_created=True, verbose_name='ID', serialize=False)),
|
||||||
|
('code', models.UUIDField(editable=False, default=uuid.uuid4)),
|
||||||
|
('created', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('kind', models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('pd', 'PagerDuty')], max_length=20)),
|
||||||
|
('value', models.CharField(max_length=200, blank=True)),
|
||||||
|
('email_verified', models.BooleanField(default=False)),
|
||||||
|
('checks', models.ManyToManyField(to='api.Check')),
|
||||||
|
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
@ -13,6 +13,8 @@ from hc.lib.emails import send
|
|||||||
STATUSES = (("up", "Up"), ("down", "Down"), ("new", "New"))
|
STATUSES = (("up", "Up"), ("down", "Down"), ("new", "New"))
|
||||||
DEFAULT_TIMEOUT = td(days=1)
|
DEFAULT_TIMEOUT = td(days=1)
|
||||||
DEFAULT_GRACE = td(hours=1)
|
DEFAULT_GRACE = td(hours=1)
|
||||||
|
CHANNEL_KINDS = (("email", "Email"), ("webhook", "Webhook"),
|
||||||
|
("pd", "PagerDuty"))
|
||||||
|
|
||||||
|
|
||||||
class Check(models.Model):
|
class Check(models.Model):
|
||||||
@ -62,6 +64,11 @@ class Check(models.Model):
|
|||||||
|
|
||||||
return "down"
|
return "down"
|
||||||
|
|
||||||
|
def assign_all_channels(self):
|
||||||
|
for channel in Channel.objects.filter(user=self.user):
|
||||||
|
channel.checks.add(self)
|
||||||
|
channel.save()
|
||||||
|
|
||||||
|
|
||||||
class Ping(models.Model):
|
class Ping(models.Model):
|
||||||
owner = models.ForeignKey(Check)
|
owner = models.ForeignKey(Check)
|
||||||
@ -71,3 +78,13 @@ class Ping(models.Model):
|
|||||||
method = models.CharField(max_length=10, blank=True)
|
method = models.CharField(max_length=10, blank=True)
|
||||||
ua = models.CharField(max_length=200, blank=True)
|
ua = models.CharField(max_length=200, blank=True)
|
||||||
body = models.TextField(blank=True)
|
body = models.TextField(blank=True)
|
||||||
|
|
||||||
|
|
||||||
|
class Channel(models.Model):
|
||||||
|
code = models.UUIDField(default=uuid.uuid4, editable=False)
|
||||||
|
user = models.ForeignKey(User)
|
||||||
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
|
kind = models.CharField(max_length=20, choices=CHANNEL_KINDS)
|
||||||
|
value = models.CharField(max_length=200, blank=True)
|
||||||
|
email_verified = models.BooleanField(default=False)
|
||||||
|
checks = models.ManyToManyField(Check)
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
|
from hc.api.models import Channel
|
||||||
|
|
||||||
|
|
||||||
class TimeoutForm(forms.Form):
|
class TimeoutForm(forms.Form):
|
||||||
timeout = forms.IntegerField(min_value=60, max_value=604800)
|
timeout = forms.IntegerField(min_value=60, max_value=604800)
|
||||||
grace = forms.IntegerField(min_value=60, max_value=604800)
|
grace = forms.IntegerField(min_value=60, max_value=604800)
|
||||||
|
|
||||||
|
|
||||||
|
class AddChannelForm(forms.ModelForm):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Channel
|
||||||
|
fields = ['kind', 'value']
|
||||||
|
@ -3,14 +3,17 @@ from django.conf.urls import url
|
|||||||
from hc.front import views
|
from hc.front import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', views.index, name="hc-index"),
|
url(r'^$', views.index, name="hc-index"),
|
||||||
url(r'^checks/add/$', views.add_check, name="hc-add-check"),
|
url(r'^checks/add/$', views.add_check, name="hc-add-check"),
|
||||||
url(r'^checks/([\w-]+)/name/$', views.update_name, name="hc-update-name"),
|
url(r'^checks/([\w-]+)/name/$', views.update_name, name="hc-update-name"),
|
||||||
url(r'^checks/([\w-]+)/timeout/$', views.update_timeout, name="hc-update-timeout"),
|
url(r'^checks/([\w-]+)/timeout/$', views.update_timeout, name="hc-update-timeout"),
|
||||||
url(r'^checks/([\w-]+)/email/$', views.email_preview),
|
url(r'^checks/([\w-]+)/email/$', views.email_preview),
|
||||||
url(r'^checks/([\w-]+)/remove/$', views.remove, name="hc-remove-check"),
|
url(r'^checks/([\w-]+)/remove/$', views.remove, name="hc-remove-check"),
|
||||||
url(r'^checks/([\w-]+)/log/$', views.log, name="hc-log"),
|
url(r'^checks/([\w-]+)/log/$', views.log, name="hc-log"),
|
||||||
url(r'^pricing/$', views.pricing, name="hc-pricing"),
|
url(r'^pricing/$', views.pricing, name="hc-pricing"),
|
||||||
url(r'^docs/$', views.docs, name="hc-docs"),
|
url(r'^docs/$', views.docs, name="hc-docs"),
|
||||||
url(r'^about/$', views.about, name="hc-about"),
|
url(r'^about/$', views.about, name="hc-about"),
|
||||||
|
url(r'^channels/$', views.channels, name="hc-channels"),
|
||||||
|
url(r'^channels/add/$', views.add_channel, name="hc-add-channel"),
|
||||||
|
url(r'^channels/([\w-]+)/checks/$', views.channel_checks, name="hc-channel-checks"),
|
||||||
]
|
]
|
||||||
|
@ -7,8 +7,8 @@ from django.shortcuts import redirect, render
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from hc.api.decorators import uuid_or_400
|
from hc.api.decorators import uuid_or_400
|
||||||
from hc.api.models import Check, Ping
|
from hc.api.models import Channel, Check, Ping
|
||||||
from hc.front.forms import TimeoutForm
|
from hc.front.forms import AddChannelForm, TimeoutForm
|
||||||
|
|
||||||
|
|
||||||
def _welcome(request):
|
def _welcome(request):
|
||||||
@ -79,6 +79,9 @@ def add_check(request):
|
|||||||
|
|
||||||
check = Check(user=request.user)
|
check = Check(user=request.user)
|
||||||
check.save()
|
check.save()
|
||||||
|
|
||||||
|
check.assign_all_channels()
|
||||||
|
|
||||||
return redirect("hc-index")
|
return redirect("hc-index")
|
||||||
|
|
||||||
|
|
||||||
@ -169,3 +172,67 @@ def log(request, code):
|
|||||||
}
|
}
|
||||||
|
|
||||||
return render(request, "front/log.html", ctx)
|
return render(request, "front/log.html", ctx)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def channels(request):
|
||||||
|
if request.method == "POST":
|
||||||
|
code = request.POST["channel"]
|
||||||
|
channel = Channel.objects.get(code=code)
|
||||||
|
assert channel.user == request.user
|
||||||
|
|
||||||
|
channel.checks = []
|
||||||
|
print (request.POST)
|
||||||
|
for key in request.POST:
|
||||||
|
if key.startswith("check-"):
|
||||||
|
code = key[6:]
|
||||||
|
check = Check.objects.get(code=code)
|
||||||
|
assert check.user == request.user
|
||||||
|
channel.checks.add(check)
|
||||||
|
|
||||||
|
channel.save()
|
||||||
|
return redirect("hc-channels")
|
||||||
|
|
||||||
|
|
||||||
|
channels = Channel.objects.filter(user=request.user).order_by("created")
|
||||||
|
num_checks = Check.objects.filter(user=request.user).count()
|
||||||
|
|
||||||
|
ctx = {
|
||||||
|
"channels": channels,
|
||||||
|
"num_checks": num_checks
|
||||||
|
|
||||||
|
}
|
||||||
|
return render(request, "front/channels.html", ctx)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def add_channel(request):
|
||||||
|
assert request.method == "POST"
|
||||||
|
form = AddChannelForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
channel = form.save(commit=False)
|
||||||
|
channel.user = request.user
|
||||||
|
channel.save()
|
||||||
|
|
||||||
|
checks = Check.objects.filter(user=request.user)
|
||||||
|
channel.checks.add(*checks)
|
||||||
|
channel.save()
|
||||||
|
|
||||||
|
return redirect("hc-channels")
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@uuid_or_400
|
||||||
|
def channel_checks(request, code):
|
||||||
|
|
||||||
|
channel = Channel.objects.get(code=code)
|
||||||
|
assigned = set([check.code for check in channel.checks.all()])
|
||||||
|
checks = Check.objects.filter(user=request.user).order_by("created")
|
||||||
|
|
||||||
|
ctx = {
|
||||||
|
"checks": checks,
|
||||||
|
"assigned": assigned,
|
||||||
|
"channel": channel
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(request, "front/channel_checks.html", ctx)
|
||||||
|
26
static/css/channel_checks.css
Normal file
26
static/css/channel_checks.css
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
.channel-checks-table tr:first-child td {
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-checks-table td:first-child, .channel-checks-table th:first-child {
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-checks-table .check-all-cell {
|
||||||
|
background: #EEE;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-checks-table .check-all-cell .cbx-container {
|
||||||
|
background: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-checks-table input[type=checkbox]:checked + label:after {
|
||||||
|
font-family: 'Glyphicons Halflings';
|
||||||
|
content: "\e013";
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-checks-table label:after {
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-top: 2px;
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
44
static/css/channels.css
Normal file
44
static/css/channels.css
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
.channels-table {
|
||||||
|
margin-top: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.channels-table > tbody > tr > th {
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channels-table .channels-add-title {
|
||||||
|
border-top: 0;
|
||||||
|
padding-top: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
.channels-table .channels-add-help {
|
||||||
|
color: #888;
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.word-up {
|
||||||
|
color: #5cb85c;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
.word-down {
|
||||||
|
color: #d9534f;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
.preposition {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-unconfirmed {
|
||||||
|
font-size: small;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channels-help-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channels-table .channels-num-checks {
|
||||||
|
padding-left: 40px;
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,7 @@
|
|||||||
|
#checks-table {
|
||||||
|
margin-top: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
.my-checks-name.unnamed {
|
.my-checks-name.unnamed {
|
||||||
color: #999;
|
color: #999;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
38
static/js/channels.js
Normal file
38
static/js/channels.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
$(function() {
|
||||||
|
var placeholders = {
|
||||||
|
email: "address@example.org",
|
||||||
|
webhook: "http://",
|
||||||
|
pd: "service key"
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#add-check-kind").change(function() {
|
||||||
|
$(".channels-add-help p").hide();
|
||||||
|
|
||||||
|
var v = $("#add-check-kind").val();
|
||||||
|
$(".channels-add-help p." + v).show();
|
||||||
|
|
||||||
|
$("#add-check-value").attr("placeholder", placeholders[v]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".edit-checks").click(function() {
|
||||||
|
$("#checks-modal").modal("show");
|
||||||
|
var url = $(this).attr("href");
|
||||||
|
$.ajax(url).done(function(data) {
|
||||||
|
$("#checks-modal .modal-content").html(data);
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var $cm = $("#checks-modal");
|
||||||
|
$cm.on("click", "#toggle-all", function() {
|
||||||
|
var value = $(this).prop("checked");
|
||||||
|
$cm.find(".toggle").prop("checked", value);
|
||||||
|
console.log("aaa", value);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -21,6 +21,8 @@
|
|||||||
<link rel="stylesheet" href="{% static 'css/my_checks_desktop.css' %}" type="text/css">
|
<link rel="stylesheet" href="{% static 'css/my_checks_desktop.css' %}" type="text/css">
|
||||||
<link rel="stylesheet" href="{% static 'css/pricing.css' %}" type="text/css">
|
<link rel="stylesheet" href="{% static 'css/pricing.css' %}" type="text/css">
|
||||||
<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/channel_checks.css' %}" type="text/css">
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
</head>
|
</head>
|
||||||
<body class="page-{{ page }}">
|
<body class="page-{{ page }}">
|
||||||
|
47
templates/front/channel_checks.html
Normal file
47
templates/front/channel_checks.html
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
{% load compress humanize staticfiles hc_extras %}
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal">×</span></button>
|
||||||
|
<h4 class="update-timeout-title">Assign Checks to Channel {{ channel.value }}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="hidden" name="channel" value="{{ channel.code }}" />
|
||||||
|
<table class="table channel-checks-table">
|
||||||
|
<tr>
|
||||||
|
<th class="check-all-cell">
|
||||||
|
<input
|
||||||
|
id="toggle-all"
|
||||||
|
type="checkbox"
|
||||||
|
class="toggle" />
|
||||||
|
</th>
|
||||||
|
<th class="check-all-cell">
|
||||||
|
Check / Uncheck All
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
{% for check in checks %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="toggle"
|
||||||
|
data-toggle="checkbox-x"
|
||||||
|
{% if check.code in assigned %} checked {% endif %}
|
||||||
|
name="check-{{ check.code }}">
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ check.name|default:check.code }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Save</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
117
templates/front/channels.html
Normal file
117
templates/front/channels.html
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load compress humanize staticfiles hc_extras %}
|
||||||
|
|
||||||
|
{% block title %}Notification Channels - healthchecks.io{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<h1>Notification Channels</h1>
|
||||||
|
<table class="table channels-table">
|
||||||
|
<tr>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Value</th>
|
||||||
|
<th>Assigned Checks</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
{% for ch in channels %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{% if ch.kind == "email" %} Email {% endif %}
|
||||||
|
{% if ch.kind == "webhook" %} Webhook {% endif %}
|
||||||
|
{% if ch.kind == "pd" %} PagerDuty {% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="preposition">
|
||||||
|
{% if ch.kind == "email" %} to {% endif %}
|
||||||
|
{% if ch.kind == "pd" %} service key {% endif %}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{{ ch.value }}
|
||||||
|
|
||||||
|
{% if ch.kind == "email" and not ch.email_verified %}
|
||||||
|
<span class="channel-unconfirmed">(unconfirmed)
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="channels-num-checks">
|
||||||
|
<a
|
||||||
|
class="edit-checks"
|
||||||
|
href="{% url 'hc-channel-checks' ch.code %}">
|
||||||
|
{{ ch.checks.count }} of {{ num_checks }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
<tr>
|
||||||
|
<th colspan="2" class="channels-add-title">
|
||||||
|
Add Notification Channel
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<form method="post" action="{% url 'hc-add-channel' %}">
|
||||||
|
<td>
|
||||||
|
<select id="add-check-kind" class="form-control" name="kind">
|
||||||
|
<option value="email">Email</option>
|
||||||
|
<option value="webhook">Webhook</option>
|
||||||
|
<option value="pd">PagerDuty</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td class="form-inline">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input
|
||||||
|
id="add-check-value"
|
||||||
|
name="value"
|
||||||
|
class="form-control"
|
||||||
|
type="text"
|
||||||
|
placeholder="address@example.org" />
|
||||||
|
<button type="submit" class="btn btn-success">Add</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</form>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3" class="channels-add-help">
|
||||||
|
<p class="email">
|
||||||
|
Healthchecks.io will send an email to the specified
|
||||||
|
address when a check goes
|
||||||
|
<span class="word-up">up</span> or <span class="word-down">down</span>.
|
||||||
|
</p>
|
||||||
|
<p class="channels-help-hidden webhook">
|
||||||
|
Healthchecks.io will request the specified URL when
|
||||||
|
a check goes
|
||||||
|
<span class="word-down">down</span>.
|
||||||
|
</p>
|
||||||
|
<p class="channels-help-hidden pd">
|
||||||
|
Healthchecks.io will create an incident on PagerDuty when
|
||||||
|
a check goes
|
||||||
|
<span class="word-down">down</span> and will resolve it
|
||||||
|
when same check goes <span class="word-up">up</span>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="checks-modal" class="modal">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
{% compress js %}
|
||||||
|
<script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
|
||||||
|
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
||||||
|
<script src="{% static 'js/channels.js' %}"></script>
|
||||||
|
{% endcompress %}
|
||||||
|
{% endblock %}
|
Loading…
x
Reference in New Issue
Block a user