Add stat comparison
This commit is contained in:
parent
1691eb4550
commit
2a0e5ea6bf
@ -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")
|
||||
|
||||
|
@ -12,17 +12,24 @@
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||
<div>
|
||||
<p>Sessions</p>
|
||||
<p class="label">{{stats.session_count|intcomma}}</p>
|
||||
<p class="label">
|
||||
{{stats.session_count|intcomma}}
|
||||
{% compare stats.compare.session_count stats.session_count "UP" %}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>Hits</p>
|
||||
<p class="label">{{stats.hit_count|intcomma}}</p>
|
||||
<p class="label">
|
||||
{{stats.hit_count|intcomma}}
|
||||
{% compare stats.compare.hit_count stats.hit_count "UP" %}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>Bounce Rate</p>
|
||||
<p class="label">
|
||||
{% 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 @@
|
||||
<p class="label">
|
||||
{% if stats.avg_session_duration != None %}
|
||||
{{stats.avg_session_duration|naturaldelta}}
|
||||
{% compare stats.compare.avg_session_duration stats.avg_session_duration "UP" %}
|
||||
{% else %}
|
||||
?
|
||||
{% endif %}
|
||||
|
@ -0,0 +1,7 @@
|
||||
{% load helpers %}
|
||||
|
||||
<span
|
||||
class="{{classes}} {% relative_stat_tone start end good good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %}"
|
||||
title="Compared against equal period prior">
|
||||
{% percent_change_display start end %}
|
||||
</span>
|
@ -12,16 +12,23 @@
|
||||
|
||||
{% block service_content %}
|
||||
<div class="grid grid-cols-2 gap-6 md:flex justify-between mb-6 card ~neutral !high px-6" id="stats">
|
||||
{% with classes="text-sm font-semibold" good_classes="text-green-400" bad_classes="text-red-400" neutral_classes="text-gray-400" %}
|
||||
<article class="">
|
||||
<p class="label text-gray-400">Sessions</p>
|
||||
<p class="heading">
|
||||
{{stats.session_count|intcomma}}
|
||||
<div>
|
||||
{% compare stats.compare.session_count stats.session_count "UP" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %}
|
||||
</div>
|
||||
</p>
|
||||
</article>
|
||||
<article class="">
|
||||
<p class="label text-gray-400">Hits</p>
|
||||
<p class="heading">
|
||||
{{stats.hit_count|intcomma}}
|
||||
<div>
|
||||
{% compare stats.compare.hit_count stats.hit_count "UP" classes=classes good_classes=good_classes bad_classes=bad_classes neutral_classes=neutral_classes %}
|
||||
</div>
|
||||
</p>
|
||||
</article>
|
||||
<article class="">
|
||||
@ -29,6 +36,9 @@
|
||||
<p class="heading">
|
||||
{% if stats.avg_load_time %}
|
||||
{{stats.avg_load_time|floatformat:"0"}}ms
|
||||
<div>
|
||||
{% 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 %}
|
||||
</div>
|
||||
{% else %}
|
||||
?
|
||||
{% endif %}
|
||||
@ -39,6 +49,9 @@
|
||||
<p class="heading">
|
||||
{% if stats.bounce_rate_pct %}
|
||||
{{stats.bounce_rate_pct|floatformat:"-1"}}%
|
||||
<div>
|
||||
{% 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 %}
|
||||
</div>
|
||||
{% else %}
|
||||
?
|
||||
{% endif %}
|
||||
@ -49,6 +62,9 @@
|
||||
<p class="heading">
|
||||
{% if stats.avg_session_duration %}
|
||||
{{stats.avg_session_duration|naturaldelta}}
|
||||
<div>
|
||||
{% 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 %}
|
||||
</div>
|
||||
{% else %}
|
||||
?
|
||||
{% endif %}
|
||||
@ -59,11 +75,15 @@
|
||||
<p class="heading">
|
||||
{% if stats.avg_hits_per_session %}
|
||||
{{stats.avg_hits_per_session|floatformat:"-1"}}
|
||||
<div>
|
||||
{% 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 %}
|
||||
</div>
|
||||
{% else %}
|
||||
?
|
||||
{% endif %}
|
||||
</p>
|
||||
</article>
|
||||
{% endwith %}
|
||||
</div>
|
||||
<div class="card ~neutral !low py-0 mb-6">
|
||||
{% include 'dashboard/includes/time_chart.html' with data=stats.session_chart_data %}
|
||||
|
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user