Compare commits

..

22 Commits

Author SHA1 Message Date
Paweł Jastrzębski
d66f683104 Add DASHBOARD_PAGE_SIZE to settings
Add DASHBOARD_PAGE_SIZE to TEMPLATE.env and app.json

Parse dashboard page size value
2021-05-14 16:09:45 +00:00
CasperVerswijvelt
b44642e023 When daterange is 1 day, show hourly data in chart
Show hourly chart starting from ranges of 3 days and less

Use timedelta instead of checking days difference which did not work correctly

Fix hourly chart bug

Add click handler for going from daily to hourly chart view by clicking chart at specific date
2021-05-14 16:09:45 +00:00
R. Miles McCain
c12a7e9e71 Document ACTIVE_USER_TIMEDELTA 2021-05-14 16:09:45 +00:00
R. Miles McCain
0294d31ea4 Remove console warning from script 2021-05-14 16:09:45 +00:00
Paweł Jastrzębski
40cb5afbad Skip heartbeat if there is no response
Fix xhr callbacks
2021-05-14 16:09:45 +00:00
Paweł Jastrzębski
073bd94112 Update litepicker and add ranges plugin
Fix litepicker colors

Fix litepicker event

Add custom ranges to litepicker

Fix code style

Remove some date ranges

Fix date ranges

Replace yesterday date range with last 3 days

Update packages

Improve litepicker box shadow
2021-05-14 16:09:45 +00:00
CasperVerswijvelt
3a01fefcff Add custom location url from environment variable
Remove trailing dollar in long and lat placeholder
2021-05-14 16:09:45 +00:00
CasperVerswijvelt
14a7ec68f3 Make favicon not squish and add ellipsis overflow
General styling improvements

Many UI Improvements

- Consistent spacing between titles and content
- Removed many ugly text squishing by hiding overflowing text with ellipsis
- Fixed Service favicon being squisched by long service name
- Hide scrollbar in 'more session' screen when content isn't scrollable
- Fix apexcharts tooltips and labels being cut off by card class

Disable wrapping in table cells, prefer ellipsis

Ellipsis overflow for long url on hit page

Fix flex grow in header not working as intended

Remove forgotten truncatechars

Fix code checks, add button role and tabindex
2021-05-14 16:09:45 +00:00
CasperVerswijvelt
fdf2ab719b Use flag icons instead of emoji's 2021-05-14 16:09:45 +00:00
R. Miles McCain
737eeb5df4 Contextual date improvements 2021-05-14 16:09:45 +00:00
CasperVerswijvelt
cb4855e4fc Preserve date range in urls in side menu 2021-05-14 16:09:45 +00:00
CasperVerswijvelt
f4127cf9b1 Preserve date range query parameters 2021-05-14 16:09:45 +00:00
R. Miles McCain
159015de1c Update test for my new instance 2021-05-14 16:09:45 +00:00
Paweł Jastrzębski
a7548d7eba Fix currently_online
Make currently_online aware of SCRIPT_HEARTBEAT_FREQUENCY
2021-05-14 16:09:45 +00:00
R. Miles McCain
da87ddb18f Fix ingest when MMDB not found 2021-05-14 16:09:45 +00:00
R. Miles McCain
4a76ab32fc Improve service page when no hits are recorded 2021-05-14 16:09:45 +00:00
R. Miles McCain
4afeced7d3 Improve homepage when no services exist 2021-05-14 16:09:45 +00:00
CasperVerswijvelt
2a6efe1b7f Merge 2 steps 2021-05-14 16:09:44 +00:00
CasperVerswijvelt
07f3926a9c Show snippet on service page when not hits are recorded yet 2021-05-14 16:09:44 +00:00
R. Miles McCain
14ed0b7979 Merge branch 'docker-github-build' 2021-05-14 16:06:37 +00:00
CasperVerswijvelt
df6786e037 Change docker push tags 2021-04-26 18:21:31 +02:00
Casper Verswijvelt
6621625d90 Multi arch docker build 2021-04-26 17:36:38 +02:00
11 changed files with 126 additions and 22 deletions

46
.github/workflows/build-docker.yml vendored Normal file
View File

@@ -0,0 +1,46 @@
name: Build docker images
on:
push:
tags:
- "*"
jobs:
publish_to_docker_hub:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Prepare tags
id: prep
run: |
DOCKER_IMAGE=milesmcc/shynet
VERSION=${GITHUB_REF#refs/tags/}
TAGS="${DOCKER_IMAGE}:${VERSION},${DOCKER_IMAGE}:latest"
echo ::set-output name=tags::${TAGS}
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Build and push advanced image
id: docker_build
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: ${{ steps.prep.outputs.tags }}

View File

@@ -1,4 +1,4 @@
FROM python:3-alpine
FROM python:alpine3.12
# Getting things ready
WORKDIR /usr/src/shynet

View File

@@ -91,4 +91,8 @@ AGGRESSIVE_HASH_SALTING=True
# - https://www.openstreetmap.org/?mlat=$LATITUDE&mlon=$LONGITUDE (default)
# - https://www.google.com/maps/search/?api=1&query=$LATITUDE,$LONGITUDE
# - https://www.mapquest.com/near-$LATITUDE,$LONGITUDE
LOCATION_URL=https://www.openstreetmap.org/?mlat=$LATITUDE&mlon=$LONGITUDE
LOCATION_URL=https://www.openstreetmap.org/?mlat=$LATITUDE&mlon=$LONGITUDE
# How many services should be displayed on dashboard page?
# Set to big number if you don't want pagination at all.
DASHBOARD_PAGE_SIZE=5

View File

@@ -127,6 +127,11 @@
"description": "Custom location url to link to in frontend.",
"value": "https://www.openstreetmap.org/?mlat=$LATITUDE&mlon=$LONGITUDE",
"required": false
},
"DASHBOARD_PAGE_SIZE": {
"description": "How many services should be displayed on dashboard page?",
"value": "5",
"required": false
}
}
}

View File

@@ -8,11 +8,14 @@
var Shynet = {
idempotency: null,
heartbeatTaskId: null,
skipHeartbeat: false,
sendHeartbeat: function () {
try {
if (document.hidden) {
if (document.hidden || Shynet.skipHeartbeat) {
return;
}
Shynet.skipHeartbeat = true;
var xhr = new XMLHttpRequest();
xhr.open(
"POST",
@@ -20,6 +23,12 @@ var Shynet = {
true
);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onload = function () {
Shynet.skipHeartbeat = false;
};
xhr.onerror = function () {
Shynet.skipHeartbeat = false;
};
xhr.send(
JSON.stringify({
idempotency: Shynet.idempotency,
@@ -30,13 +39,14 @@ var Shynet = {
window.performance.timing.navigationStart,
})
);
} catch (e) { }
} catch (e) {}
},
newPageLoad: function () {
if (Shynet.heartbeatTaskId != null) {
clearInterval(Shynet.heartbeatTaskId);
}
Shynet.idempotency = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
Shynet.skipHeartbeat = false;
Shynet.heartbeatTaskId = setInterval(Shynet.sendHeartbeat, parseInt("{{heartbeat_frequency}}"));
Shynet.sendHeartbeat();
}
@@ -51,4 +61,4 @@ window.addEventListener("load", Shynet.newPageLoad);
// -- START --
{{script_inject|safe}}
// -- END --
{% endif %}
{% endif %}

View File

@@ -8,12 +8,12 @@ from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models.functions import TruncDate
from django.db.models.functions import TruncDate, TruncHour
from django.db.utils import NotSupportedError
from django.shortcuts import reverse
from django.utils import timezone
# How long a session a needs to go without an update to no longer be considered 'active' (i.e., currently online)
ACTIVE_USER_TIMEDELTA = timezone.timedelta(
milliseconds=settings.SCRIPT_HEARTBEAT_FREQUENCY * 2
)
@@ -125,8 +125,10 @@ class Service(models.Model):
Session = apps.get_model("analytics", "Session")
Hit = apps.get_model("analytics", "Hit")
tz_now = timezone.now()
currently_online = Session.objects.filter(
service=self, last_seen__gt=timezone.now() - ACTIVE_USER_TIMEDELTA
service=self, last_seen__gt=tz_now - ACTIVE_USER_TIMEDELTA
).count()
sessions = Session.objects.filter(
@@ -210,17 +212,35 @@ class Service(models.Model):
if session_count == 0:
avg_session_duration = None
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
# Show hourly chart for date ranges of 3 days or less, otherwise daily chart
if (end_time - start_time).days < 3:
session_chart_tooltip_format = "MM/dd HH:mm"
session_chart_granularity = "hourly"
session_chart_data = {
k["hour"]: k["count"]
for k in sessions.annotate(hour=TruncHour("start_time"))
.values("hour")
.annotate(count=models.Count("uuid"))
.order_by("hour")
}
for hour_offset in range(int((end_time - start_time).total_seconds() / 3600) + 1):
hour = (start_time + timezone.timedelta(hours=hour_offset))
if hour not in session_chart_data:
session_chart_data[hour] = 0 if hour <= tz_now else None
else:
session_chart_tooltip_format = "MMM d"
session_chart_granularity = "daily"
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 if day <= tz_now.date() else None
return {
"currently_online": currently_online,
@@ -249,6 +269,8 @@ class Service(models.Model):
)
]
),
"session_chart_tooltip_format": session_chart_tooltip_format,
"session_chart_granularity": session_chart_granularity,
"online": True,
}

View File

@@ -51,7 +51,7 @@
</div>
<hr class="sep h-4">
<div style="bottom: -1px;">
{% include 'dashboard/includes/time_chart.html' with data=stats.session_chart_data sparkline=True height=100 name=object.uuid %}
{% include 'dashboard/includes/time_chart.html' with data=stats.session_chart_data sparkline=True height=100 name=object.uuid tooltip_format=stats.session_chart_tooltip_format granularity=stats.session_chart_granularity %}
</div>
{% endwith %}
</a>

View File

@@ -6,6 +6,9 @@
},
tooltip: {
shared: false,
x: {
format: '{{tooltip_format|default:"MMM d"}}',
},
},
colors: ["#805AD5"],
chart: {
@@ -34,6 +37,14 @@
stops: [0, 75, 100]
},
},
{% if granularity == "daily" and click_zoom %}
events: {
markerClick: function(event, chartContext, { seriesIndex, dataPointIndex, w: {config}}) {
const day = config.series[seriesIndex].data[dataPointIndex].x
window.location.href = `?startDate=${day}&endDate=${day}`
},
},
{% endif %}
},
grid: {
padding: {
@@ -63,6 +74,9 @@
},
xaxis: {
type: "datetime",
labels: {
datetimeUTC: false
},
},
stroke: {
width: 1.5,

View File

@@ -94,7 +94,7 @@
{% endwith %}
</div>
<div class="card overflow-visible ~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 tooltip_format=stats.session_chart_tooltip_format granularity=stats.session_chart_granularity click_zoom=True %}
</div>
{% endif %}
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">

View File

@@ -25,7 +25,7 @@ from .mixins import DateRangeMixin
class DashboardView(LoginRequiredMixin, DateRangeMixin, ListView):
model = Service
template_name = "dashboard/pages/dashboard.html"
paginate_by = 5
paginate_by = settings.DASHBOARD_PAGE_SIZE
def get_queryset(self):
return Service.objects.filter(

View File

@@ -347,3 +347,6 @@ AGGRESSIVE_HASH_SALTING = os.getenv("AGGRESSIVE_HASH_SALTING", "False") == "True
# What location url should be linked to in the frontend?
LOCATION_URL = os.getenv("LOCATION_URL", "https://www.openstreetmap.org/?mlat=$LATITUDE&mlon=$LONGITUDE")
# How many services should be displayed on dashboard page?
DASHBOARD_PAGE_SIZE = int(os.getenv("DASHBOARD_PAGE_SIZE", "5"))