mirror of
https://github.com/healthchecks/healthchecks.git
synced 2025-04-11 15:51:19 +00:00
Show "Badges" and "Settings" in top navigation. Fixes #234
This commit is contained in:
parent
7c13adbf18
commit
178b0ff95c
20 changed files with 382 additions and 186 deletions
|
@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
### Improvements
|
||||
- Add the EMAIL_USE_VERIFICATION configuration setting (#232)
|
||||
- Show "Badges" and "Settings" in top navigation (#234)
|
||||
|
||||
|
||||
## 1.6.0 - 2019-04-01
|
||||
|
|
|
@ -9,7 +9,7 @@ class BadgesTestCase(BaseTestCase):
|
|||
Check.objects.create(project=self.bobs_project, tags="bobs-tag")
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get("/accounts/profile/badges/")
|
||||
r = self.client.get("/projects/%s/badges/" % self.project.code)
|
||||
self.assertContains(r, "foo.svg")
|
||||
self.assertContains(r, "a-B_1.svg")
|
||||
|
||||
|
@ -27,6 +27,6 @@ class BadgesTestCase(BaseTestCase):
|
|||
self.project.save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get("/accounts/profile/badges/")
|
||||
r = self.client.get("/projects/%s/badges/" % self.project.code)
|
||||
self.assertContains(r, "badge/alices-badge-key/")
|
||||
self.assertContains(r, "badge/alices-badge-key/")
|
||||
|
|
|
@ -5,17 +5,22 @@ from hc.test import BaseTestCase
|
|||
from hc.accounts.models import Member
|
||||
|
||||
|
||||
class ProfileTestCase(BaseTestCase):
|
||||
class ProjectTestCase(BaseTestCase):
|
||||
def setUp(self):
|
||||
super(ProfileTestCase, self).setUp()
|
||||
super(ProjectTestCase, self).setUp()
|
||||
|
||||
self.url = "/projects/%s/settings/" % self.project.code
|
||||
|
||||
def test_it_checks_access(self):
|
||||
self.client.login(username="bob@example.org", password="password")
|
||||
self.client.login(username="charlie@example.org", password="password")
|
||||
r = self.client.get(self.url)
|
||||
self.assertEqual(r.status_code, 404)
|
||||
|
||||
def test_it_allows_team_access(self):
|
||||
self.client.login(username="bob@example.org", password="password")
|
||||
r = self.client.get(self.url)
|
||||
self.assertContains(r, "Change Project Name")
|
||||
|
||||
def test_it_shows_api_keys(self):
|
||||
self.project.api_key_readonly = "R" * 32
|
||||
self.project.save()
|
||||
|
@ -78,6 +83,13 @@ class ProfileTestCase(BaseTestCase):
|
|||
" Alice's Project on %s" % settings.SITE_NAME)
|
||||
self.assertEqual(mail.outbox[0].subject, subj)
|
||||
|
||||
def test_it_requires_owner_to_add_team_member(self):
|
||||
self.client.login(username="bob@example.org", password="password")
|
||||
|
||||
form = {"invite_team_member": "1", "email": "frank@example.org"}
|
||||
r = self.client.post(self.url, form)
|
||||
self.assertEqual(r.status_code, 403)
|
||||
|
||||
def test_it_checks_team_size(self):
|
||||
self.profile.team_limit = 0
|
||||
self.profile.save()
|
||||
|
@ -100,6 +112,13 @@ class ProfileTestCase(BaseTestCase):
|
|||
self.bobs_profile.refresh_from_db()
|
||||
self.assertEqual(self.bobs_profile.current_project, None)
|
||||
|
||||
def test_it_requires_owner_to_remove_team_member(self):
|
||||
self.client.login(username="bob@example.org", password="password")
|
||||
|
||||
form = {"remove_team_member": "1", "email": "bob@example.org"}
|
||||
r = self.client.post(self.url, form)
|
||||
self.assertEqual(r.status_code, 403)
|
||||
|
||||
def test_it_checks_membership_when_removing_team_member(self):
|
||||
self.client.login(username="charlie@example.org", password="password")
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ urlpatterns = [
|
|||
|
||||
path('profile/', views.profile, name="hc-profile"),
|
||||
path('profile/notifications/', views.notifications, name="hc-notifications"),
|
||||
path('profile/badges/', views.badges, name="hc-badges"),
|
||||
path('close/', views.close, name="hc-close"),
|
||||
|
||||
path('unsubscribe_reports/<str:username>/',
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from datetime import timedelta as td
|
||||
import uuid
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
|
@ -10,7 +9,8 @@ from django.contrib.auth import authenticate
|
|||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.models import User
|
||||
from django.core import signing
|
||||
from django.http import HttpResponseForbidden, HttpResponseBadRequest
|
||||
from django.http import (HttpResponseForbidden, HttpResponseBadRequest,
|
||||
HttpResponseNotFound)
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.utils.timezone import now
|
||||
from django.urls import resolve, Resolver404
|
||||
|
@ -23,7 +23,6 @@ from hc.accounts.forms import (ChangeEmailForm, EmailPasswordForm,
|
|||
ExistingEmailForm)
|
||||
from hc.accounts.models import Profile, Project, Member
|
||||
from hc.api.models import Channel, Check
|
||||
from hc.lib.badges import get_badge_url
|
||||
from hc.payments.models import Subscription
|
||||
|
||||
NEXT_WHITELIST = ("hc-checks",
|
||||
|
@ -238,12 +237,22 @@ def add_project(request):
|
|||
|
||||
@login_required
|
||||
def project(request, code):
|
||||
project = get_object_or_404(Project, code=code, owner=request.user)
|
||||
if request.user.is_superuser:
|
||||
q = Project.objects
|
||||
else:
|
||||
q = request.profile.projects()
|
||||
|
||||
try:
|
||||
project = q.get(code=code)
|
||||
except Project.DoesNotExist:
|
||||
return HttpResponseNotFound()
|
||||
|
||||
is_owner = project.owner_id == request.user.id
|
||||
ctx = {
|
||||
"page": "project",
|
||||
"project": project,
|
||||
"show_api_keys": False,
|
||||
"is_owner": is_owner,
|
||||
"show_api_keys": "show_api_keys" in request.GET,
|
||||
"project_name_status": "default",
|
||||
"api_status": "default",
|
||||
"team_status": "default"
|
||||
|
@ -267,7 +276,7 @@ def project(request, code):
|
|||
elif "show_api_keys" in request.POST:
|
||||
ctx["show_api_keys"] = True
|
||||
elif "invite_team_member" in request.POST:
|
||||
if not project.can_invite():
|
||||
if not is_owner or not project.can_invite():
|
||||
return HttpResponseForbidden()
|
||||
|
||||
form = InviteTeamMemberForm(request.POST)
|
||||
|
@ -284,6 +293,9 @@ def project(request, code):
|
|||
ctx["team_status"] = "success"
|
||||
|
||||
elif "remove_team_member" in request.POST:
|
||||
if not is_owner:
|
||||
return HttpResponseForbidden()
|
||||
|
||||
form = RemoveTeamMemberForm(request.POST)
|
||||
if form.is_valid():
|
||||
q = User.objects
|
||||
|
@ -354,37 +366,6 @@ def notifications(request):
|
|||
return render(request, "accounts/notifications.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
def badges(request):
|
||||
badge_sets = []
|
||||
for project in request.profile.projects():
|
||||
tags = set()
|
||||
for check in Check.objects.filter(project=project):
|
||||
tags.update(check.tags_list())
|
||||
|
||||
sorted_tags = sorted(tags, key=lambda s: s.lower())
|
||||
sorted_tags.append("*") # For the "overall status" badge
|
||||
|
||||
urls = []
|
||||
for tag in sorted_tags:
|
||||
if not re.match("^[\w-]+$", tag) and tag != "*":
|
||||
continue
|
||||
|
||||
urls.append({
|
||||
"svg": get_badge_url(project.badge_key, tag),
|
||||
"json": get_badge_url(project.badge_key, tag, format="json"),
|
||||
})
|
||||
|
||||
badge_sets.append({"project": project, "urls": urls})
|
||||
|
||||
ctx = {
|
||||
"page": "profile",
|
||||
"badges": badge_sets
|
||||
}
|
||||
|
||||
return render(request, "accounts/badges.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
def set_password(request, token):
|
||||
if not request.profile.check_token(token, "set-password"):
|
||||
|
|
|
@ -50,6 +50,7 @@ channel_urls = [
|
|||
urlpatterns = [
|
||||
path('', views.index, name="hc-index"),
|
||||
path('projects/<uuid:code>/checks/', views.my_checks, name="hc-checks"),
|
||||
path('projects/<uuid:code>/badges/', views.badges, name="hc-badges"),
|
||||
path('projects/<uuid:code>/checks/add/', views.add_check, name="hc-add-check"),
|
||||
path('checks/cron_preview/', views.cron_preview),
|
||||
path('projects/<uuid:code>/checks/status/', views.status, name="hc-status"),
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from datetime import datetime, timedelta as td
|
||||
import json
|
||||
import re
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from croniter import croniter
|
||||
|
@ -29,6 +30,7 @@ from hc.front.schemas import telegram_callback
|
|||
from hc.front.templatetags.hc_extras import (num_down_title, down_title,
|
||||
sortchecks)
|
||||
from hc.lib import jsonschema
|
||||
from hc.lib.badges import get_badge_url
|
||||
import pytz
|
||||
from pytz.exceptions import UnknownTimeZoneError
|
||||
import requests
|
||||
|
@ -441,6 +443,7 @@ def log(request, code):
|
|||
|
||||
limit = check.project.owner_profile.ping_log_limit
|
||||
ctx = {
|
||||
"project": check.project,
|
||||
"check": check,
|
||||
"events": _get_events(check, limit),
|
||||
"limit": limit,
|
||||
|
@ -459,6 +462,7 @@ def details(request, code):
|
|||
|
||||
ctx = {
|
||||
"page": "details",
|
||||
"project": check.project,
|
||||
"check": check,
|
||||
"channels": channels,
|
||||
"timezones": pytz.all_timezones
|
||||
|
@ -515,6 +519,38 @@ def status_single(request, code):
|
|||
return JsonResponse(doc)
|
||||
|
||||
|
||||
@login_required
|
||||
def badges(request, code):
|
||||
project = _get_project_for_user(request, code)
|
||||
|
||||
tags = set()
|
||||
for check in Check.objects.filter(project=project):
|
||||
tags.update(check.tags_list())
|
||||
|
||||
sorted_tags = sorted(tags, key=lambda s: s.lower())
|
||||
sorted_tags.append("*") # For the "overall status" badge
|
||||
|
||||
urls = []
|
||||
for tag in sorted_tags:
|
||||
if not re.match("^[\w-]+$", tag) and tag != "*":
|
||||
continue
|
||||
|
||||
urls.append({
|
||||
"tag": tag,
|
||||
"svg": get_badge_url(project.badge_key, tag),
|
||||
"json": get_badge_url(project.badge_key, tag, format="json"),
|
||||
})
|
||||
|
||||
ctx = {
|
||||
"have_tags": len(urls) > 1,
|
||||
"page": "badges",
|
||||
"project": project,
|
||||
"badges": urls
|
||||
}
|
||||
|
||||
return render(request, "front/badges.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
def channels(request):
|
||||
if request.method == "POST":
|
||||
|
@ -547,6 +583,7 @@ def channels(request):
|
|||
|
||||
ctx = {
|
||||
"page": "channels",
|
||||
"project": request.project,
|
||||
"profile": request.project.owner_profile,
|
||||
"channels": channels,
|
||||
"enable_pushbullet": settings.PUSHBULLET_CLIENT_ID is not None,
|
||||
|
|
|
@ -41,6 +41,10 @@ body {
|
|||
font-size: small;
|
||||
}
|
||||
|
||||
#global-links > li > a {
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.navbar-default .navbar-nav > li.active > a, .navbar-default .navbar-nav > li > a:hover {
|
||||
border-bottom: 5px solid #eee;
|
||||
|
@ -48,6 +52,11 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.navbar-default .navbar-brand, .navbar-default .navbar-brand:hover {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.navbar-text {
|
||||
font-size: small;
|
||||
}
|
||||
|
@ -115,3 +124,16 @@ pre {
|
|||
.badge-down {
|
||||
background-color: #d9534f;
|
||||
}
|
||||
|
||||
.dropdown-menu > li.project-item a {
|
||||
min-width: 200px;
|
||||
padding: 6px 20px 3px 20px;
|
||||
}
|
||||
|
||||
.project-item .name {
|
||||
display: inline-block;
|
||||
max-width: 130px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{% load compress static hc_extras %}
|
||||
|
||||
{% block title %}Account Settings - {% site_name %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<h1 class="settings-title">Settings <small>{{ request.user.email }}</small></h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<li><a href="{% url 'hc-profile' %}">Account</a></li>
|
||||
{% if show_pricing %}
|
||||
<li><a href="{% url 'hc-billing' %}">Billing</a></li>
|
||||
{% endif %}
|
||||
<li><a href="{% url 'hc-notifications' %}">Email Reports</a></li>
|
||||
<li class="active"><a href="{% url 'hc-badges' %}">Badges</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-10">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body settings-block">
|
||||
<h2 class="settings-title">Status Badges</h2>
|
||||
<p id="badges-description">
|
||||
{% site_name %} provides status badges for each of the tags
|
||||
you have used. Additionally, the "{% site_name %}"
|
||||
badge shows the overall status of all checks in a
|
||||
project. The badges have public, but hard-to-guess
|
||||
URLs. You can use them in your READMEs,
|
||||
dashboards or status pages.
|
||||
</p>
|
||||
|
||||
<div id="b-format" class="btn-group" data-toggle="buttons">
|
||||
<label id="show-svg" class="btn btn-default active">
|
||||
<input type="radio" autocomplete="off" checked> SVG
|
||||
</label>
|
||||
<label id="show-json" class="btn btn-default">
|
||||
<input type="radio" autocomplete="off"> JSON
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<table id="badges-svg" class="badges table">
|
||||
{% for badge_set in badges %}
|
||||
<tr>
|
||||
<th colspan="2">{{ badge_set.project }}</th>
|
||||
</tr>
|
||||
{% for urldict in badge_set.urls %}
|
||||
<tr>
|
||||
<td>
|
||||
<img src="{{ urldict.svg }}" alt="" />
|
||||
</td>
|
||||
<td class="svg-url">
|
||||
<code>{{ urldict.svg }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
<table id="badges-json" class="badges table">
|
||||
{% for badge_set in badges %}
|
||||
<tr>
|
||||
<th colspan="2">{{ badge_set.project }}</th>
|
||||
</tr>
|
||||
|
||||
{% for urldict in badge_set.urls %}
|
||||
<tr>
|
||||
<td class="json-response" data-url="{{ urldict.json }}">
|
||||
</td>
|
||||
<td class="json-url">
|
||||
<code>{{ urldict.json }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</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/badges.js' %}"></script>
|
||||
{% endcompress %}
|
||||
{% endblock %}
|
|
@ -19,7 +19,6 @@
|
|||
<li><a href="{% url 'hc-profile' %}">Account</a></li>
|
||||
<li class="active"><a href="{% url 'hc-billing' %}">Billing</a></li>
|
||||
<li><a href="{% url 'hc-notifications' %}">Email Reports</a></li>
|
||||
<li><a href="{% url 'hc-badges' %}">Badges</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
<li><a href="{% url 'hc-billing' %}">Billing</a></li>
|
||||
{% endif %}
|
||||
<li class="active"><a href="{% url 'hc-notifications' %}">Email Reports</a></li>
|
||||
<li><a href="{% url 'hc-badges' %}">Badges</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
<li><a href="{% url 'hc-billing' %}">Billing</a></li>
|
||||
{% endif %}
|
||||
<li><a href="{% url 'hc-notifications' %}">Email Reports</a></li>
|
||||
<li><a href="{% url 'hc-badges' %}">Badges</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base.html" %}
|
||||
{% extends "base_project.html" %}
|
||||
{% load compress static hc_extras %}
|
||||
|
||||
{% block title %}Project Settings - {{ project }}{% endblock %}
|
||||
|
@ -7,7 +7,6 @@
|
|||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-sm-9 col-md-6">
|
||||
<h1 class="settings-title">Project Settings</h1>
|
||||
{% for message in messages %}
|
||||
<p class="alert alert-{{ message.tags }}">{{ message }}</p>
|
||||
{% endfor %}
|
||||
|
@ -103,10 +102,12 @@
|
|||
<td>{{ member.user.email }} </td>
|
||||
<td>Member</td>
|
||||
<td>
|
||||
{% if is_owner %}
|
||||
<a
|
||||
href="#"
|
||||
data-email="{{ member.user.email }}"
|
||||
class="pull-right member-remove">Remove</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -121,7 +122,8 @@
|
|||
|
||||
<br />
|
||||
|
||||
{% if project.can_invite %}
|
||||
{% if is_owner %}
|
||||
{% if project.can_invite%}
|
||||
<a
|
||||
href="#"
|
||||
class="btn btn-primary pull-right"
|
||||
|
@ -134,6 +136,7 @@
|
|||
<a href="{% url 'hc-pricing' %}">upgrade your account!</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if team_member_invited %}
|
||||
|
@ -149,6 +152,7 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if is_owner %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body settings-block">
|
||||
{% csrf_token %}
|
||||
|
@ -163,6 +167,7 @@
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -88,18 +88,7 @@
|
|||
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul id="nav-main-sections" class="nav navbar-nav">
|
||||
{% if request.user.is_authenticated and request.profile.current_project %}
|
||||
<li {% if page == 'checks' %} class="active" {% endif %}>
|
||||
<a href="{% url 'hc-checks' request.profile.current_project.code %}">Checks</a>
|
||||
</li>
|
||||
|
||||
<li {% if page == 'channels' %} class="active" {% endif %}>
|
||||
<a href="{% url 'hc-channels' %}">Integrations</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<ul id="global-links" class="nav navbar-nav navbar-right">
|
||||
{% if show_pricing %}
|
||||
<li {% if page == 'pricing' %} class="active" {% endif %}>
|
||||
<a href="{% url 'hc-pricing' %}">Pricing</a>
|
||||
|
@ -110,29 +99,18 @@
|
|||
<a href="{% url 'hc-docs' %}">Docs</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
{% if request.user.is_authenticated %}
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
{% if request.user.is_authenticated %}
|
||||
<li class="dropdown">
|
||||
<a id="nav-email" href="#" class="dropdown-toggle" data-toggle="dropdown" role="button">
|
||||
|
||||
{% if check %}
|
||||
{{ check.project }}
|
||||
{% elif request.profile.current_project %}
|
||||
{{ request.profile.current_project }}
|
||||
{% else %}
|
||||
{{ request.user.email }}
|
||||
{% endif %}
|
||||
|
||||
Account
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="dropdown-header">Projects</li>
|
||||
{% for project in request.profile.annotated_projects %}
|
||||
<li class="dropdown-header">{{ project }}</li>
|
||||
<li>
|
||||
<a href="{% url 'hc-checks' project.code %}">
|
||||
Checks
|
||||
{{ project }}
|
||||
{% if project.n_down %}
|
||||
<span class="badge badge-down pull-right">
|
||||
{{ project.n_down }}
|
||||
|
@ -140,24 +118,17 @@
|
|||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% if project.owner_id == request.user.id %}
|
||||
<li>
|
||||
<a href="{% url 'hc-project-settings' project.code %}">Project Settings</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li role="separator" class="divider"></li>
|
||||
{% endfor %}
|
||||
|
||||
<li role="separator" class="divider"></li>
|
||||
<li><a href="{% url 'hc-profile' %}">Account Settings</a></li>
|
||||
<li><a href="{% url 'hc-logout' %}">Log Out</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
{% elif page != "login" %}
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
{% elif page != "login" %}
|
||||
<li><a href="{% url 'hc-login' %}">Sign In</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% if show_search %}
|
||||
<form class="navbar-form navbar-right hidden-xs hidden-sm">
|
||||
|
|
169
templates/base_project.html
Normal file
169
templates/base_project.html
Normal file
|
@ -0,0 +1,169 @@
|
|||
<!DOCTYPE html>{% load compress staticfiles hc_extras %}
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{% block title %}{% site_name %} - Monitor Cron Jobs. Get Notified When Your Cron Jobs Fail{% endblock %}</title>
|
||||
{% block description %}
|
||||
<meta name="description" content="Monitor and Get Notified When Your Cron Jobs Fail. Free alternative to Cronitor and Dead Man's Snitch.">
|
||||
{% endblock %}
|
||||
{% block keywords %}
|
||||
<meta name="keywords" content="healthchecks, monitor cron jobs, cron monitoring, cron job syntax, health checks, crontab cheat sheet, crontab monitoring, cronjob monitoring, cron dashboard">
|
||||
{% endblock %}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="apple-mobile-web-app-title" content="{% site_name %}">
|
||||
<meta name="application-name" content="{% site_name %}">
|
||||
<link rel="icon" type="image/x-icon" href="{% static 'img/favicon.ico' %}">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{% static 'img/apple-touch-180.png' %}">
|
||||
|
||||
{% compress css %}
|
||||
<link rel="stylesheet" href="{% static 'css/bootstrap.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/icomoon.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/nouislider.min.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/nouislider.pips.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/bootstrap-select.min.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/snippet-copy.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/base.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/docs.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/docs_cron.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/welcome.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/my_checks.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/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">
|
||||
<link rel="stylesheet" href="{% static 'css/details.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/log.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/add_pushover.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/add_webhook.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/settings.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/ping_details.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/profile.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/checkbox.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/radio.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/billing.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/login.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/projects.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/add_project_modal.css' %}" type="text/css">
|
||||
{% endcompress %}
|
||||
</head>
|
||||
<body class="page-{{ page }}">
|
||||
{% debug_warning %}
|
||||
<nav class="navbar navbar-default">
|
||||
<div class="container{% if page == "checks" or page == "details" %}-fluid{% endif %}">
|
||||
<div class="navbar-header">
|
||||
<button
|
||||
type="button"
|
||||
class="navbar-toggle collapsed"
|
||||
data-toggle="collapse"
|
||||
data-target="#navbar"
|
||||
aria-expanded="false"
|
||||
aria-controls="navbar">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
|
||||
<a class="navbar-brand" href="/">
|
||||
{{ project }}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul id="nav-main-sections" class="nav navbar-nav">
|
||||
{% if project %}
|
||||
<li {% if page == 'checks' %} class="active" {% endif %}>
|
||||
<a href="{% url 'hc-checks' project.code %}">Checks</a>
|
||||
</li>
|
||||
|
||||
<li {% if page == 'channels' %} class="active" {% endif %}>
|
||||
<a href="{% url 'hc-channels' %}">Integrations</a>
|
||||
</li>
|
||||
|
||||
<li {% if page == 'badges' %} class="active" {% endif %}>
|
||||
<a href="{% url 'hc-badges' project.code %}">Badges</a>
|
||||
</li>
|
||||
|
||||
<li {% if page == 'project' %} class="active" {% endif %}>
|
||||
<a href="{% url 'hc-project-settings' project.code %}">Settings</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
{% if request.user.is_authenticated %}
|
||||
<ul id="global-links" class="nav navbar-nav navbar-right">
|
||||
{% if show_pricing %}
|
||||
<li {% if page == 'pricing' %} class="active" {% endif %}>
|
||||
<a href="{% url 'hc-pricing' %}">Pricing</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<li {% if page == 'docs' %} class="active" {% endif %}>
|
||||
<a href="{% url 'hc-docs' %}">Docs</a>
|
||||
</li>
|
||||
|
||||
<li class="dropdown">
|
||||
<a id="nav-email" href="#" class="dropdown-toggle" data-toggle="dropdown" role="button">
|
||||
Account
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="dropdown-header">Projects</li>
|
||||
{% for project in request.profile.annotated_projects %}
|
||||
<li class="project-item">
|
||||
<a href="{% url 'hc-checks' project.code %}">
|
||||
<span class="name">{{ project }}</span>
|
||||
{% if project.n_down %}
|
||||
<span class="badge badge-down pull-right">
|
||||
{{ project.n_down }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
||||
<li role="separator" class="divider"></li>
|
||||
<li><a href="{% url 'hc-profile' %}">Account Settings</a></li>
|
||||
<li><a href="{% url 'hc-logout' %}">Log Out</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
{% elif page != "login" %}
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="{% url 'hc-login' %}">Sign In</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{% block containers %}
|
||||
<div class="container{% if page == "checks" or page == "details" %}-fluid{% endif %}">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container{% if page == "checks" or page == "details" %}-fluid{% endif %}">
|
||||
<ul>
|
||||
<li>
|
||||
Powered by Healthchecks open-source project
|
||||
(<a href="https://github.com/healthchecks/healthchecks">github</a>,
|
||||
<a href="https://healthchecks.io">healthchecks.io</a>)
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
{% block scripts %}
|
||||
{% compress js %}
|
||||
<script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
|
||||
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
||||
{% endcompress %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
86
templates/front/badges.html
Normal file
86
templates/front/badges.html
Normal file
|
@ -0,0 +1,86 @@
|
|||
{% extends "base_project.html" %}
|
||||
{% load compress static hc_extras %}
|
||||
|
||||
{% block title %}Account Settings - {% site_name %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-sm-10">
|
||||
<h1>Status Badges</h1>
|
||||
|
||||
<p id="badges-description">
|
||||
{% site_name %} provides status badges for each of the tags
|
||||
you have used. Additionally, the "{% site_name %}"
|
||||
badge shows the overall status of all checks in a
|
||||
project. The badges have public, but hard-to-guess
|
||||
URLs. You can use them in your READMEs,
|
||||
dashboards or status pages.
|
||||
</p>
|
||||
|
||||
<div id="b-format" class="btn-group" data-toggle="buttons">
|
||||
<label id="show-svg" class="btn btn-default active">
|
||||
<input type="radio" autocomplete="off" checked> SVG
|
||||
</label>
|
||||
<label id="show-json" class="btn btn-default">
|
||||
<input type="radio" autocomplete="off"> JSON
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<table id="badges-svg" class="badges table">
|
||||
{% if have_tags %}
|
||||
<tr>
|
||||
<th colspan="2">Tags</th>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% for urldict in badges %}
|
||||
{% if urldict.tag == "*" %}
|
||||
<tr>
|
||||
<th colspan="2">Overall Status</th>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<img src="{{ urldict.svg }}" alt="" />
|
||||
</td>
|
||||
<td class="svg-url">
|
||||
<code>{{ urldict.svg }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<table id="badges-json" class="badges table">
|
||||
{% if have_tags %}
|
||||
<tr>
|
||||
<th colspan="2">Tags</th>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% for urldict in badges %}
|
||||
{% if urldict.tag == "*" %}
|
||||
<tr>
|
||||
<th colspan="2">Overall Status</th>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
<tr>
|
||||
<td class="json-response" data-url="{{ urldict.json }}">
|
||||
</td>
|
||||
<td class="json-url">
|
||||
<code>{{ urldict.json }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</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/badges.js' %}"></script>
|
||||
{% endcompress %}
|
||||
{% endblock %}
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base.html" %}
|
||||
{% extends "base_project.html" %}
|
||||
{% load compress humanize static hc_extras %}
|
||||
|
||||
{% block title %}Integrations - {% site_name %}{% endblock %}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base.html" %}
|
||||
{% extends "base_project.html" %}
|
||||
{% load compress humanize static hc_extras %}
|
||||
|
||||
{% block title %}{{ check|down_title }}{% endblock %}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "base.html" %}
|
||||
{% extends "base_project.html" %}
|
||||
{% load compress humanize staticfiles hc_extras %}
|
||||
|
||||
{% block title %}My Checks - {% site_name %}{% endblock %}
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
{% extends "base.html" %}
|
||||
{% extends "base_project.html" %}
|
||||
{% load compress static hc_extras %}
|
||||
|
||||
{% block title %}{{ num_down|num_down_title }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
{% if tags %}
|
||||
<div id="my-checks-tags" class="col-sm-12">
|
||||
<div id="my-checks-tags" class="col-sm-9">
|
||||
{% for tag, status in tags %}
|
||||
<div class="btn btn-xs {{ status }} {% if tag in selected_tags %}checked{% endif%}">{{ tag }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col-sm-3">
|
||||
<input id="search" type="text" placeholder="Filter by check name…" class="form-control" value="{{ search }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
|
Loading…
Add table
Reference in a new issue