Add charts

This commit is contained in:
R. Miles McCain 2020-04-12 17:23:46 -04:00
parent 2f06ecabd7
commit b7d84085a3
No known key found for this signature in database
GPG Key ID: 91CB47BDDF2671A5
5 changed files with 127 additions and 27 deletions

View File

@ -1,10 +1,12 @@
import uuid import uuid
import json
from django.apps import apps from django.apps import apps
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.db import models from django.db import models
from django.db.utils import NotSupportedError from django.db.utils import NotSupportedError
from django.utils import timezone from django.utils import timezone
from django.db.models.functions import TruncDate
def _default_uuid(): def _default_uuid():
@ -60,12 +62,9 @@ class Service(models.Model):
service=self, start_time__gt=timezone.now() - timezone.timedelta(seconds=10) service=self, start_time__gt=timezone.now() - timezone.timedelta(seconds=10)
).count() ).count()
sessions = ( sessions = Session.objects.filter(
Session.objects.filter(
service=self, start_time__gt=start_time, start_time__lt=end_time service=self, start_time__gt=start_time, start_time__lt=end_time
) ).order_by("-start_time")
.order_by("-start_time")
)
session_count = sessions.count() session_count = sessions.count()
hits = Hit.objects.filter( hits = Hit.objects.filter(
@ -135,6 +134,18 @@ class Service(models.Model):
] ]
) / max(session_count, 1) ) / max(session_count, 1)
session_chart_data = {
k["date"]: k["count"]
for k in sessions.annotate(date=TruncDate("start_time"))
.values("date")
.annotate(count=models.Count("uuid"))
.order_by("date")
}
for day_offset in range((end_time - start_time).days + 1):
day = (start_time + timezone.timedelta(days=day_offset)).date()
if day not in session_chart_data:
session_chart_data[day] = 0
return { return {
"currently_online": currently_online, "currently_online": currently_online,
"session_count": session_count, "session_count": session_count,
@ -150,5 +161,11 @@ class Service(models.Model):
"browsers": browsers, "browsers": browsers,
"devices": devices, "devices": devices,
"device_types": device_types, "device_types": device_types,
"session_chart_data": json.dumps(
[
{"x": str(key), "y": value}
for key, value in session_chart_data.items()
]
),
"online": True, "online": True,
} }

View File

@ -8,8 +8,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
{% include 'a17t/head.html' %} {% include 'a17t/head.html' %}
<script src="https://cdn.jsdelivr.net/npm/litepicker/dist/js/main.js"></script> <script src="https://cdn.jsdelivr.net/npm/litepicker/dist/js/main.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js" <script src="https://cdn.jsdelivr.net/npm/apexcharts@3.18.1/dist/apexcharts.min.js"
integrity="sha256-R4pqcOYV8lt7snxMQO/HSbVCFRPMdrhAFMH+vr9giYI=" crossorigin="anonymous"></script> integrity="sha256-RalQXBZdisB04aaBsm+6YZ0b/iRYjX1MZn90m19AnCY=" crossorigin="anonymous"></script>
{% block extra_head %} {% block extra_head %}
{% endblock %} {% endblock %}
</head> </head>

View File

@ -1,30 +1,36 @@
{% load humanize helpers %} {% load humanize helpers %}
<a class="card ~neutral !low service mb-6" href="{% url 'core:service' object.uuid %}"> <a class="card ~neutral !low service mb-6 p-0" href="{% url 'core:service' object.uuid %}">
{% with stats=object.stats %} {% with stats=object.stats %}
<div class="md:flex justify-between items-center"> <div class="p-4 md:flex justify-between">
<div class="mr-4 md:w-4/12"> <div class="md:w-4/12">
<h3 class="heading text-xl mr-2 mb-1"> <h3 class="heading text-xl mr-2 mb-1 text-purple-600">
{{object.name}} {{object.name}}
</h3> </h3>
{% include 'core/includes/stats_status_chip.html' %} {% include 'core/includes/stats_status_chip.html' %}
</div> </div>
<div class="mr-2"> <div class="grid grid-cols-2 md:grid-cols-4 gap-6">
<p class="font-medium text-sm">Sessions</p> <div>
<p class="text-xl text-purple-700 font-medium">{{stats.session_count|intcomma}}</p> <p>Sessions</p>
<p class="label">{{stats.session_count|intcomma}}</p>
</div> </div>
<div class="mr-2"> <div>
<p class="font-medium text-sm">Bounce Rate</p> <p>Bounce Rate</p>
<p class="text-xl text-purple-700 font-medium">{{stats.bounce_rate_pct|floatformat:"-1"}}%</p> <p class="label">{{stats.bounce_rate_pct|floatformat:"-1"}}%</p>
</div> </div>
<div class="mr-2"> <div>
<p class="font-medium text-sm">Avg. Duration</p> <p>Avg. Duration</p>
<p class="text-xl text-purple-700 font-medium">{{stats.avg_session_duration|naturaldelta}}</p> <p class="label">{{stats.avg_session_duration|naturaldelta}}</p>
</div> </div>
<div class="mr-2"> <div>
<p class="font-medium text-sm">Uptime</p> <p>Uptime</p>
<p class="text-xl text-purple-700 font-medium">99.9%</p> <p class="label">99.9%</p>
</div> </div>
</div> </div>
</div>
<hr class="sep h-4">
<div style="bottom: -1px;">
{% include 'core/includes/time_chart.html' with data=stats.session_chart_data sparkline=True height=100 %}
</div>
{% endwith %} {% endwith %}
</a> </a>

View File

@ -0,0 +1,76 @@
<div id="{{name|default:'timeChart'}}"></div>
<script>
var triggerMatchesChartOptions = {
dataLabels: {
enabled: false
},
tooltip: {
shared: false,
},
colors: ["#805AD5"],
chart: {
toolbar: {
show: false,
},
type: 'area',
height: {{height|default:"200"}},
offsetY: -1,
animations: {
enabled: false
},
sparkline: {
enabled: {% if sparkline %}true{% else %}false{% endif %},
},
fill: {
type: 'gradient',
gradient: {
shadeIntensity: 1,
inverseColors: false,
opacityFrom: 0.8,
opacityTo: 0,
stops: [0, 75, 100]
},
},
},
grid: {
padding: {
right: 0,
left: -8,
},
{% if not sparkline %}
xaxis: {
lines: {
show: true,
}
},
yaxis: {
lines: {
show: false,
}
},
show: true
{% endif %}
},
yaxis: {
labels: {
show: false,
formatter: val => val.toFixed(0)
},
padding: {
left: 0,
}
},
xaxis: {
type: "datetime",
},
stroke: {
width: 1.5,
},
series: [{
name: "{{unit|default:'Sessions'}}",
data: {{data|safe}}
}]
};
var triggerMatchesChart = new ApexCharts(document.querySelector("#{{name|default:'timeChart'}}"), triggerMatchesChartOptions);
triggerMatchesChart.render();
</script>

View File

@ -8,6 +8,7 @@
{% endblock %} {% endblock %}
{% block service_content %} {% block service_content %}
{% include 'core/includes/time_chart.html' with data=stats.session_chart_data %}
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6" id="stats"> <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6" id="stats">
<article class="card ~neutral !low"> <article class="card ~neutral !low">
<p class="label">Sessions</p> <p class="label">Sessions</p>