diff --git a/TEMPLATE.env b/TEMPLATE.env
index 57c2d6e..efdba95 100644
--- a/TEMPLATE.env
+++ b/TEMPLATE.env
@@ -98,3 +98,6 @@ 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
+
+# Should background bars be scaled to full width?
+USE_RELATIVE_MAX_IN_BAR_VISUALIZATION=True
diff --git a/app.json b/app.json
index 3a62e51..7f54f36 100644
--- a/app.json
+++ b/app.json
@@ -132,6 +132,11 @@
"description": "How many services should be displayed on dashboard page?",
"value": "5",
"required": false
+ },
+ "USE_RELATIVE_MAX_IN_BAR_VISUALIZATION": {
+ "description": "Should background bars be scaled to full width?",
+ "value": "True",
+ "required": false
}
}
}
diff --git a/shynet/dashboard/templates/dashboard/includes/bar.html b/shynet/dashboard/templates/dashboard/includes/bar.html
new file mode 100644
index 0000000..a6ad23c
--- /dev/null
+++ b/shynet/dashboard/templates/dashboard/includes/bar.html
@@ -0,0 +1,6 @@
+{% load helpers %}
+
+
diff --git a/shynet/dashboard/templates/dashboard/pages/service.html b/shynet/dashboard/templates/dashboard/pages/service.html
index d005b1b..d249755 100644
--- a/shynet/dashboard/templates/dashboard/pages/service.html
+++ b/shynet/dashboard/templates/dashboard/pages/service.html
@@ -109,8 +109,20 @@
{% for location in stats.locations %}
- | {{location.location|default:"Unknown"|urldisplay}} |
- {{location.count|intcomma}} |
+
+ {% include 'dashboard/includes/bar.html' with count=location.count max=stats.locations.0.count total=stats.hit_count %}
+
+ {{location.location|default:"Unknown"|urldisplay}}
+
+ |
+
+
+ {{location.count|intcomma}}
+
+ ({{location.count|percent:stats.hit_count}})
+
+
+ |
{% empty %}
@@ -131,8 +143,20 @@
{% for referrer in stats.referrers %}
- | {{referrer.referrer|default:"Direct"|urldisplay}} |
- {{referrer.count|intcomma}} |
+
+ {% include 'dashboard/includes/bar.html' with count=referrer.count max=stats.referrers.0.count total=stats.session_count %}
+
+ {{referrer.referrer|default:"Direct"|urldisplay}}
+
+ |
+
+
+ {{referrer.count|intcomma}}
+
+ ({{referrer.count|percent:stats.session_count}})
+
+
+ |
{% empty %}
@@ -153,10 +177,20 @@
{% for country in stats.countries %}
- |
- {{country.country|country_name}}
+ |
+ {% include 'dashboard/includes/bar.html' with count=country.count max=stats.countries.0.count total=stats.session_count %}
+
+ {{country.country|country_name}}
+
+ |
+
+
+ {{country.count|intcomma}}
+
+ ({{country.count|percent:stats.session_count}})
+
+
|
- {{country.count|intcomma}} |
{% empty %}
@@ -177,10 +211,20 @@
{% for os in stats.operating_systems %}
- |
- {{os.os|iconify}}{{os.os|default:"Unknown"}}
+ |
+ {% include 'dashboard/includes/bar.html' with count=os.count max=stats.operating_systems.0.count total=stats.session_count %}
+
+ {{os.os|iconify}}{{os.os|default:"Unknown"}}
+
+ |
+
+
+ {{os.count|intcomma}}
+
+ ({{os.count|percent:stats.session_count}})
+
+
|
- {{os.count|intcomma}} |
{% empty %}
@@ -201,9 +245,21 @@
{% for browser in stats.browsers %}
- |
- {{browser.browser|iconify}}{{browser.browser|default:"Unknown"}} |
- {{browser.count|intcomma}} |
+
+ {% include 'dashboard/includes/bar.html' with count=browser.count max=stats.browsers.0.count total=stats.session_count %}
+
+
+ {{browser.browser|iconify}}{{browser.browser|default:"Unknown"}}
+
+ |
+
+
+ {{browser.count|intcomma}}
+
+ ({{browser.count|percent:stats.session_count}})
+
+
+ |
{% empty %}
@@ -224,8 +280,20 @@
{% for device_type in stats.device_types %}
- | {{device_type.device_type|default:"Unknown"|title}} |
- {{device_type.count|intcomma}} |
+
+ {% include 'dashboard/includes/bar.html' with count=device_type.count max=stats.device_types.0.count total=stats.session_count %}
+
+ {{device_type.device_type|default:"Unknown"|title}}
+
+ |
+
+
+ {{device_type.count|intcomma}}
+
+ ({{device_type.count|percent:stats.session_count}})
+
+
+ |
{% empty %}
@@ -243,4 +311,4 @@
sessions
→
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/shynet/dashboard/templatetags/helpers.py b/shynet/dashboard/templatetags/helpers.py
index f456be4..245bbfa 100644
--- a/shynet/dashboard/templatetags/helpers.py
+++ b/shynet/dashboard/templatetags/helpers.py
@@ -186,6 +186,7 @@ def urldisplay(url):
else:
return url
+
class ContextualURLNode(template.Node):
"""Extension of the Django URLNode to support including contextual parameters in URL outputs. In other words, URLs generated will keep the start and end date parameters."""
@@ -205,9 +206,13 @@ class ContextualURLNode(template.Node):
url_parts = list(urlparse(url))
query = dict(urllib.parse.parse_qsl(url_parts[4]))
- query.update({
- param: context.request.GET.get(param) for param in self.CONTEXT_PARAMS if param in context.request.GET and param not in query
- })
+ query.update(
+ {
+ param: context.request.GET.get(param)
+ for param in self.CONTEXT_PARAMS
+ if param in context.request.GET and param not in query
+ }
+ )
url_parts[4] = urllib.parse.urlencode(query)
@@ -224,7 +229,39 @@ class ContextualURLNode(template.Node):
def contextual_url(*args, **kwargs):
urlnode = url_tag(*args, **kwargs)
return ContextualURLNode(urlnode)
-
+
+
@register.filter
def location_url(session):
- return settings.LOCATION_URL.replace("$LATITUDE", str(session.latitude)).replace("$LONGITUDE", str(session.longitude))
+ return settings.LOCATION_URL.replace("$LATITUDE", str(session.latitude)).replace(
+ "$LONGITUDE", str(session.longitude)
+ )
+
+
+@register.filter
+def percent(value, total):
+ if total == 0:
+ return "N/A"
+
+ percent = value / total
+
+ if percent < 0.001:
+ return "<0.1%"
+
+ return f'{percent:.1%}'
+
+
+@register.simple_tag
+def bar_width(count, max, total):
+ if total == 0 or max == 0:
+ return "0"
+
+ if settings.USE_RELATIVE_MAX_IN_BAR_VISUALIZATION:
+ percent = count / max
+ else:
+ percent = count / total
+
+ if percent < 0.001:
+ return "0"
+
+ return f'{percent:.1%}'
diff --git a/shynet/shynet/settings.py b/shynet/shynet/settings.py
index bb9c24d..9c960c8 100644
--- a/shynet/shynet/settings.py
+++ b/shynet/shynet/settings.py
@@ -310,7 +310,10 @@ NPM_FILE_PATTERNS = {
"stimulus": [os.path.join("dist", "stimulus.umd.js")],
"inter-ui": [os.path.join("Inter (web)", "*")],
"@fortawesome": [os.path.join("fontawesome-free", "js", "all.min.js")],
- "flag-icon-css": [os.path.join("css", "flag-icon.min.css"), os.path.join("flags", "*")],
+ "flag-icon-css": [
+ os.path.join("css", "flag-icon.min.css"),
+ os.path.join("flags", "*"),
+ ],
}
# Shynet
@@ -346,7 +349,14 @@ BLOCK_ALL_IPS = os.getenv("BLOCK_ALL_IPS", "False") == "True"
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")
+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"))
+
+# Should background bars be scaled to full width?
+USE_RELATIVE_MAX_IN_BAR_VISUALIZATION = (
+ os.getenv("USE_RELATIVE_MAX_IN_BAR_VISUALIZATION", "True") == "True"
+)