Add charts
This commit is contained in:
		
							parent
							
								
									2f06ecabd7
								
							
						
					
					
						commit
						b7d84085a3
					
				@ -1,10 +1,12 @@
 | 
			
		||||
import uuid
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
from django.apps import apps
 | 
			
		||||
from django.contrib.auth.models import AbstractUser
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.db.utils import NotSupportedError
 | 
			
		||||
from django.utils import timezone
 | 
			
		||||
from django.db.models.functions import TruncDate
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _default_uuid():
 | 
			
		||||
@ -60,12 +62,9 @@ class Service(models.Model):
 | 
			
		||||
            service=self, start_time__gt=timezone.now() - timezone.timedelta(seconds=10)
 | 
			
		||||
        ).count()
 | 
			
		||||
 | 
			
		||||
        sessions = (
 | 
			
		||||
            Session.objects.filter(
 | 
			
		||||
                service=self, start_time__gt=start_time, start_time__lt=end_time
 | 
			
		||||
            )
 | 
			
		||||
            .order_by("-start_time")
 | 
			
		||||
        )
 | 
			
		||||
        sessions = Session.objects.filter(
 | 
			
		||||
            service=self, start_time__gt=start_time, start_time__lt=end_time
 | 
			
		||||
        ).order_by("-start_time")
 | 
			
		||||
        session_count = sessions.count()
 | 
			
		||||
 | 
			
		||||
        hits = Hit.objects.filter(
 | 
			
		||||
@ -135,6 +134,18 @@ class Service(models.Model):
 | 
			
		||||
                ]
 | 
			
		||||
            ) / 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 {
 | 
			
		||||
            "currently_online": currently_online,
 | 
			
		||||
            "session_count": session_count,
 | 
			
		||||
@ -150,5 +161,11 @@ class Service(models.Model):
 | 
			
		||||
            "browsers": browsers,
 | 
			
		||||
            "devices": devices,
 | 
			
		||||
            "device_types": device_types,
 | 
			
		||||
            "session_chart_data": json.dumps(
 | 
			
		||||
                [
 | 
			
		||||
                    {"x": str(key), "y": value}
 | 
			
		||||
                    for key, value in session_chart_data.items()
 | 
			
		||||
                ]
 | 
			
		||||
            ),
 | 
			
		||||
            "online": True,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -8,8 +8,8 @@
 | 
			
		||||
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
  {% include 'a17t/head.html' %}
 | 
			
		||||
  <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"
 | 
			
		||||
    integrity="sha256-R4pqcOYV8lt7snxMQO/HSbVCFRPMdrhAFMH+vr9giYI=" crossorigin="anonymous"></script>
 | 
			
		||||
  <script src="https://cdn.jsdelivr.net/npm/apexcharts@3.18.1/dist/apexcharts.min.js"
 | 
			
		||||
    integrity="sha256-RalQXBZdisB04aaBsm+6YZ0b/iRYjX1MZn90m19AnCY=" crossorigin="anonymous"></script>
 | 
			
		||||
  {% block extra_head %}
 | 
			
		||||
  {% endblock %}
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
@ -1,30 +1,36 @@
 | 
			
		||||
{% 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 %}
 | 
			
		||||
    <div class="md:flex justify-between items-center">
 | 
			
		||||
        <div class="mr-4 md:w-4/12">
 | 
			
		||||
            <h3 class="heading text-xl mr-2 mb-1">
 | 
			
		||||
    <div class="p-4 md:flex justify-between">
 | 
			
		||||
        <div class="md:w-4/12">
 | 
			
		||||
            <h3 class="heading text-xl mr-2 mb-1 text-purple-600">
 | 
			
		||||
                {{object.name}}
 | 
			
		||||
            </h3>
 | 
			
		||||
            {% include 'core/includes/stats_status_chip.html' %}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="mr-2">
 | 
			
		||||
            <p class="font-medium text-sm">Sessions</p>
 | 
			
		||||
            <p class="text-xl text-purple-700 font-medium">{{stats.session_count|intcomma}}</p>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="mr-2">
 | 
			
		||||
            <p class="font-medium text-sm">Bounce Rate</p>
 | 
			
		||||
            <p class="text-xl text-purple-700 font-medium">{{stats.bounce_rate_pct|floatformat:"-1"}}%</p>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="mr-2">
 | 
			
		||||
            <p class="font-medium text-sm">Avg. Duration</p>
 | 
			
		||||
            <p class="text-xl text-purple-700 font-medium">{{stats.avg_session_duration|naturaldelta}}</p>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="mr-2">
 | 
			
		||||
            <p class="font-medium text-sm">Uptime</p>
 | 
			
		||||
            <p class="text-xl text-purple-700 font-medium">99.9%</p>
 | 
			
		||||
        <div class="grid grid-cols-2 md:grid-cols-4 gap-6">
 | 
			
		||||
            <div>
 | 
			
		||||
                <p>Sessions</p>
 | 
			
		||||
                <p class="label">{{stats.session_count|intcomma}}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div>
 | 
			
		||||
                <p>Bounce Rate</p>
 | 
			
		||||
                <p class="label">{{stats.bounce_rate_pct|floatformat:"-1"}}%</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div>
 | 
			
		||||
                <p>Avg. Duration</p>
 | 
			
		||||
                <p class="label">{{stats.avg_session_duration|naturaldelta}}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div>
 | 
			
		||||
                <p>Uptime</p>
 | 
			
		||||
                <p class="label">99.9%</p>
 | 
			
		||||
            </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 %}
 | 
			
		||||
</a>
 | 
			
		||||
							
								
								
									
										76
									
								
								shynet/core/templates/core/includes/time_chart.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								shynet/core/templates/core/includes/time_chart.html
									
									
									
									
									
										Normal 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>
 | 
			
		||||
@ -8,6 +8,7 @@
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% 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">
 | 
			
		||||
    <article class="card ~neutral !low">
 | 
			
		||||
        <p class="label">Sessions</p>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user