From 2a0e5ea6bf9796d796e1f51759004e6e23608ef0 Mon Sep 17 00:00:00 2001 From: "R. Miles McCain" Date: Mon, 20 Apr 2020 21:15:32 -0400 Subject: [PATCH] Add stat comparison --- shynet/core/models.py | 7 ++ .../dashboard/includes/service_overview.html | 12 +++- .../dashboard/includes/stat_comparison.html | 7 ++ .../templates/dashboard/pages/service.html | 20 ++++++ shynet/dashboard/templatetags/helpers.py | 67 +++++++++++++++++++ 5 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 shynet/dashboard/templates/dashboard/includes/stat_comparison.html diff --git a/shynet/core/models.py b/shynet/core/models.py index 8625204..540f8e2 100644 --- a/shynet/core/models.py +++ b/shynet/core/models.py @@ -59,6 +59,13 @@ class Service(models.Model): if end_time is None: end_time = timezone.now() + main_data = self.get_relative_stats(start_time, end_time) + comparison_data = self.get_relative_stats(start_time - (end_time - start_time), start_time) + main_data["compare"] = comparison_data + + return main_data + + def get_relative_stats(self, start_time, end_time): Session = apps.get_model("analytics", "Session") Hit = apps.get_model("analytics", "Hit") diff --git a/shynet/dashboard/templates/dashboard/includes/service_overview.html b/shynet/dashboard/templates/dashboard/includes/service_overview.html index 53981e7..4394890 100644 --- a/shynet/dashboard/templates/dashboard/includes/service_overview.html +++ b/shynet/dashboard/templates/dashboard/includes/service_overview.html @@ -12,17 +12,24 @@

Sessions

-

{{stats.session_count|intcomma}}

+

+ {{stats.session_count|intcomma}} + {% compare stats.compare.session_count stats.session_count "UP" %} +

Hits

-

{{stats.hit_count|intcomma}}

+

+ {{stats.hit_count|intcomma}} + {% compare stats.compare.hit_count stats.hit_count "UP" %} +

Bounce Rate

{% if stats.bounce_rate_pct != None %} {{stats.bounce_rate_pct|floatformat:"-1"}}% + {% compare stats.compare.bounce_rate_pct stats.bounce_rate_pct "DOWN" %} {% else %} ? {% endif %} @@ -33,6 +40,7 @@

{% if stats.avg_session_duration != None %} {{stats.avg_session_duration|naturaldelta}} + {% compare stats.compare.avg_session_duration stats.avg_session_duration "UP" %} {% else %} ? {% endif %} diff --git a/shynet/dashboard/templates/dashboard/includes/stat_comparison.html b/shynet/dashboard/templates/dashboard/includes/stat_comparison.html new file mode 100644 index 0000000..5e24eee --- /dev/null +++ b/shynet/dashboard/templates/dashboard/includes/stat_comparison.html @@ -0,0 +1,7 @@ +{% load helpers %} + + + {% percent_change_display start end %} + \ No newline at end of file diff --git a/shynet/dashboard/templates/dashboard/pages/service.html b/shynet/dashboard/templates/dashboard/pages/service.html index 1d45a9e..303256a 100644 --- a/shynet/dashboard/templates/dashboard/pages/service.html +++ b/shynet/dashboard/templates/dashboard/pages/service.html @@ -12,16 +12,23 @@ {% block service_content %}

+ {% with classes="text-sm font-semibold" good_classes="text-green-400" bad_classes="text-red-400" neutral_classes="text-gray-400" %}

Sessions

{{stats.session_count|intcomma}} +

+ {% compare stats.compare.session_count stats.session_count "UP" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %} +

Hits

{{stats.hit_count|intcomma}} +

+ {% compare stats.compare.hit_count stats.hit_count "UP" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %} +

@@ -29,6 +36,9 @@

{% if stats.avg_load_time %} {{stats.avg_load_time|floatformat:"0"}}ms +

+ {% compare stats.compare.avg_load_time stats.avg_load_time "DOWN" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %} +
{% else %} ? {% endif %} @@ -39,6 +49,9 @@

{% if stats.bounce_rate_pct %} {{stats.bounce_rate_pct|floatformat:"-1"}}% +

+ {% compare stats.compare.bounce_rate_pct stats.bounce_rate_pct "DOWN" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %} +
{% else %} ? {% endif %} @@ -49,6 +62,9 @@

{% if stats.avg_session_duration %} {{stats.avg_session_duration|naturaldelta}} +

+ {% compare stats.compare.avg_session_duration stats.avg_session_duration "UP" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %} +
{% else %} ? {% endif %} @@ -59,11 +75,15 @@

{% if stats.avg_hits_per_session %} {{stats.avg_hits_per_session|floatformat:"-1"}} +

+ {% compare stats.compare.avg_hits_per_session stats.avg_hits_per_session "UP" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %} +
{% else %} ? {% endif %}

+ {% endwith %}
{% include 'dashboard/includes/time_chart.html' with data=stats.session_chart_data %} diff --git a/shynet/dashboard/templatetags/helpers.py b/shynet/dashboard/templatetags/helpers.py index 60a0aea..8efb4a2 100644 --- a/shynet/dashboard/templatetags/helpers.py +++ b/shynet/dashboard/templatetags/helpers.py @@ -30,6 +30,7 @@ def flag_emoji(isocode): except: return "" + @register.filter def country_name(isocode): try: @@ -37,6 +38,72 @@ def country_name(isocode): except: return "Unknown" + +@register.simple_tag +def relative_stat_tone( + start, + end, + good="UP", + good_classes=None, + bad_classes=None, + neutral_classes=None, +): + good_classes = good_classes or "~positive" + bad_classes = bad_classes or "~critical" + neutral_classes = neutral_classes or "~neutral" + + if start == None or end == None or start == end: + return neutral_classes + if good == "UP": + return good_classes if start <= end else bad_classes + elif good == "DOWN": + return bad_classes if start <= end else good_classes + else: + return neutral_classes + + +@register.simple_tag +def percent_change_display(start, end): + if start == None or end == None: + return SafeString("Δ n/a") + if start == end: + direction = "" + else: + direction = "↑ " if end > start else "↓ " + + if start == 0 and end != 0: + pct_change = "100%" + else: + change = int(round(100 * abs(end - start) / start)) + if change > 999: + return "> 999%" + else: + pct_change = str(change) + "%" + + return SafeString(direction + pct_change) + + +@register.inclusion_tag("dashboard/includes/stat_comparison.html") +def compare( + start, + end, + good, + classes="badge", + good_classes=None, + bad_classes=None, + neutral_classes=None, +): + return { + "start": start, + "end": end, + "good": good, + "classes": classes, + "good_classes": good_classes, + "bad_classes": bad_classes, + "neutral_classes": neutral_classes, + } + + @register.filter def startswith(text, starts): if isinstance(text, str):