diff --git a/runtests.py b/runtests.py
index 672c275..ac76ef7 100644
--- a/runtests.py
+++ b/runtests.py
@@ -41,4 +41,4 @@ def run_tests(*test_args):
if __name__ == '__main__':
- run_tests(*sys.argv[1:])
\ No newline at end of file
+ run_tests(*sys.argv[1:])
diff --git a/tests/test_views.py b/tests/test_views.py
index 41f34cb..2e1505b 100644
--- a/tests/test_views.py
+++ b/tests/test_views.py
@@ -118,3 +118,10 @@ def test_response_404_when_none_specified(self):
def tearDown(self):
pass
+
+
+class TestWatchmanDashboard(unittest.TestCase):
+ def test_dashboard_response_code(self):
+ request = RequestFactory().get('/')
+ response = views.dashboard(request)
+ self.assertEqual(response.status_code, 200)
diff --git a/watchman/templates/watchman/dashboard.html b/watchman/templates/watchman/dashboard.html
new file mode 100644
index 0000000..d5d1875
--- /dev/null
+++ b/watchman/templates/watchman/dashboard.html
@@ -0,0 +1,87 @@
+{% load i18n %}
+
+
+
+
+
+
+
+
+
+
+ {% block content %}
+
+
{% trans 'System Status' %}
+
+ {% if overall_status %}
+ {% trans 'All systems up and running!' %}
+ {% else %}
+ {% trans 'WARNING - Some systems down!' %}
+ {% endif %}{# overall_status #}
+
+
+
+
+
+
+ {% trans 'Type' %}
+ {% trans 'Name' %}
+ {% trans 'Status' %}
+
+
+
+ {% for type in checks %}
+ {% for status in type.statuses %}
+
+ {{ type.type|title }}
+ {{ status.name|title }}
+
+ {% if status.ok %}
+ {% trans 'OK' %}
+
+ {% else %}
+
+ {% trans 'ERROR!' %}
+
+ {% endif %}{# status.ok #}
+
+
+ {% endfor %}{# for status in type.statuses #}
+ {% empty %}
+
+ {% trans 'No checks indicated.' %}
+
+ {% endfor %}{# for type in checks #}
+
+
+
+ {% if not overall_status %}
{% trans 'Click an error button to see the full traceback' %} {% endif %}{# overall_status #}
+
+ {% endblock %}{# status_content #}
+
+
+ {% for type in checks %}
+ {% for status in type.statuses %}
+ {% if not status.ok %}
+
+
+
+
+
+
{{ status.error }}
+
{{ status.traceback }}
+
+
+
+
+
+ {% endif %}{# not status.ok #}
+ {% endfor %}{# for type in checks #}
+ {% endfor %}{# for status in type.statuses #}
+
+
diff --git a/watchman/urls.py b/watchman/urls.py
index fdb1f57..01ec8b0 100644
--- a/watchman/urls.py
+++ b/watchman/urls.py
@@ -5,4 +5,5 @@
urlpatterns = patterns(
'',
url(r'^$', 'watchman.views.status', name="status"),
+ url(r'^dashboard/$', 'watchman.views.dashboard', name="dashboard"),
)
diff --git a/watchman/views.py b/watchman/views.py
index d2363d3..fcc9004 100644
--- a/watchman/views.py
+++ b/watchman/views.py
@@ -3,6 +3,8 @@
from __future__ import unicode_literals
from django.http import Http404
+from django.shortcuts import render
+from django.utils.translation import ugettext as _
from jsonview.decorators import json_view
from watchman.decorators import token_required
@@ -28,6 +30,87 @@ def status(request):
response.update(check())
if len(response) == 0:
- raise Http404('No checks found')
+ raise Http404(_('No checks found'))
return response
+
+
+@token_required
+def dashboard(request):
+ check_types = []
+
+ for check in get_checks(None, None):
+ if callable(check):
+ _check = check()
+
+ for _type in _check:
+ # For other systems (eg: email, storage) _check[_type] is a
+ # dictionary of status
+ #
+ # Example:
+ # {
+ # 'ok': True, # Status
+ # }
+ #
+ # Example:
+ # {
+ # 'ok': False, # Status
+ # 'error': "RuntimeError",
+ # 'stacktrace': "...",
+ # }
+ #
+ # For some systems (eg: cache, database) _check[_type] is a
+ # list of dictionaries of dictionaries of statuses
+ #
+ # Example:
+ # [
+ # {
+ # 'default': { # Cache/database name
+ # 'ok': True, # Status
+ # }
+ # },
+ # {
+ # 'non-default': { # Cache/database name
+ # 'ok': False, # Status
+ # 'error': "RuntimeError",
+ # 'stacktrace': "...",
+ # }
+ # },
+ # ]
+ #
+ statuses = []
+
+ if type(_check[_type]) == dict:
+ result = _check[_type]
+ statuses = [{
+ 'name': '',
+ 'ok': result['ok'],
+ 'error': '' if result['ok'] else result['error'],
+ 'stacktrace': '' if result['ok'] else result['stacktrace'],
+ }]
+
+ type_overall_status = _check[_type]['ok']
+
+ elif type(_check[_type]) == list:
+ for result in _check[_type]:
+ for name in result:
+ statuses.append({
+ 'name': name,
+ 'ok': result[name]['ok'],
+ 'error': '' if result[name]['ok'] else result[name]['error'],
+ 'stacktrace': '' if result[name]['ok'] else result[name]['stacktrace'],
+ })
+
+ type_overall_status = all([s['ok'] for s in statuses])
+
+ check_types.append({
+ 'type': _type,
+ 'ok': type_overall_status,
+ 'statuses': statuses})
+
+ overall_status = all([type_status['ok'] for type_status in check_types])
+
+ return render(request, 'watchman/dashboard.html', {
+ 'checks': check_types,
+ 'overall_status': overall_status
+ })