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:
|
if end_time is None:
|
||||||
end_time = timezone.now()
|
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")
|
Session = apps.get_model("analytics", "Session")
|
||||||
Hit = apps.get_model("analytics", "Hit")
|
Hit = apps.get_model("analytics", "Hit")
|
||||||
|
|
||||||
|
@ -12,17 +12,24 @@
|
|||||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<p>Sessions</p>
|
<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>
|
||||||
<div>
|
<div>
|
||||||
<p>Hits</p>
|
<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>
|
||||||
<div>
|
<div>
|
||||||
<p>Bounce Rate</p>
|
<p>Bounce Rate</p>
|
||||||
<p class="label">
|
<p class="label">
|
||||||
{% if stats.bounce_rate_pct != None %}
|
{% if stats.bounce_rate_pct != None %}
|
||||||
{{stats.bounce_rate_pct|floatformat:"-1"}}%
|
{{stats.bounce_rate_pct|floatformat:"-1"}}%
|
||||||
|
{% compare stats.compare.bounce_rate_pct stats.bounce_rate_pct "DOWN" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
?
|
?
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -33,6 +40,7 @@
|
|||||||
<p class="label">
|
<p class="label">
|
||||||
{% if stats.avg_session_duration != None %}
|
{% if stats.avg_session_duration != None %}
|
||||||
{{stats.avg_session_duration|naturaldelta}}
|
{{stats.avg_session_duration|naturaldelta}}
|
||||||
|
{% compare stats.compare.avg_session_duration stats.avg_session_duration "UP" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
?
|
?
|
||||||
{% endif %}
|
{% 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 %}
|
{% block service_content %}
|
||||||
<div class="grid grid-cols-2 gap-6 md:flex justify-between mb-6 card ~neutral !high px-6" id="stats">
|
<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="">
|
<article class="">
|
||||||
<p class="label text-gray-400">Sessions</p>
|
<p class="label text-gray-400">Sessions</p>
|
||||||
<p class="heading">
|
<p class="heading">
|
||||||
{{stats.session_count|intcomma}}
|
{{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>
|
</p>
|
||||||
</article>
|
</article>
|
||||||
<article class="">
|
<article class="">
|
||||||
<p class="label text-gray-400">Hits</p>
|
<p class="label text-gray-400">Hits</p>
|
||||||
<p class="heading">
|
<p class="heading">
|
||||||
{{stats.hit_count|intcomma}}
|
{{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>
|
</p>
|
||||||
</article>
|
</article>
|
||||||
<article class="">
|
<article class="">
|
||||||
@ -29,6 +36,9 @@
|
|||||||
<p class="heading">
|
<p class="heading">
|
||||||
{% if stats.avg_load_time %}
|
{% if stats.avg_load_time %}
|
||||||
{{stats.avg_load_time|floatformat:"0"}}ms
|
{{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 %}
|
{% else %}
|
||||||
?
|
?
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -39,6 +49,9 @@
|
|||||||
<p class="heading">
|
<p class="heading">
|
||||||
{% if stats.bounce_rate_pct %}
|
{% if stats.bounce_rate_pct %}
|
||||||
{{stats.bounce_rate_pct|floatformat:"-1"}}%
|
{{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 %}
|
{% else %}
|
||||||
?
|
?
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -49,6 +62,9 @@
|
|||||||
<p class="heading">
|
<p class="heading">
|
||||||
{% if stats.avg_session_duration %}
|
{% if stats.avg_session_duration %}
|
||||||
{{stats.avg_session_duration|naturaldelta}}
|
{{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 %}
|
{% else %}
|
||||||
?
|
?
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -59,11 +75,15 @@
|
|||||||
<p class="heading">
|
<p class="heading">
|
||||||
{% if stats.avg_hits_per_session %}
|
{% if stats.avg_hits_per_session %}
|
||||||
{{stats.avg_hits_per_session|floatformat:"-1"}}
|
{{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 %}
|
{% else %}
|
||||||
?
|
?
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
</article>
|
</article>
|
||||||
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
<div class="card ~neutral !low py-0 mb-6">
|
<div class="card ~neutral !low py-0 mb-6">
|
||||||
{% include 'dashboard/includes/time_chart.html' with data=stats.session_chart_data %}
|
{% include 'dashboard/includes/time_chart.html' with data=stats.session_chart_data %}
|
||||||
|
@ -30,6 +30,7 @@ def flag_emoji(isocode):
|
|||||||
except:
|
except:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def country_name(isocode):
|
def country_name(isocode):
|
||||||
try:
|
try:
|
||||||
@ -37,6 +38,72 @@ def country_name(isocode):
|
|||||||
except:
|
except:
|
||||||
return "Unknown"
|
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
|
@register.filter
|
||||||
def startswith(text, starts):
|
def startswith(text, starts):
|
||||||
if isinstance(text, str):
|
if isinstance(text, str):
|
||||||
|
Loading…
Reference in New Issue
Block a user