Percents + visualization (#139)

* Black autoformat

* Add percent and divide filters

* Remove divide filter

* Add percents in brackets and visualization

* Apply percents and visualization to all data

* Switch absolute to relative

* Increase percent bar height

* Move bar to separated file

* Add USE_RELATIVE_MAX_IN_BAR_VISUALIZATION to settings

* Add flex items-center

* Move bar to left

* Remove spaces

* Fix USE_RELATIVE_MAX_IN_BAR_VISUALIZATION

* Remove unnecessary True

* Add bar_width tag

* Add flex-none to make flag not get squished

* Fix flex-none
This commit is contained in:
havk 2021-06-13 20:11:40 +02:00 committed by GitHub
parent f3a89bff78
commit fcea6d3be9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 152 additions and 23 deletions

View File

@ -98,3 +98,6 @@ LOCATION_URL=https://www.openstreetmap.org/?mlat=$LATITUDE&mlon=$LONGITUDE
# How many services should be displayed on dashboard page? # How many services should be displayed on dashboard page?
# Set to big number if you don't want pagination at all. # Set to big number if you don't want pagination at all.
DASHBOARD_PAGE_SIZE=5 DASHBOARD_PAGE_SIZE=5
# Should background bars be scaled to full width?
USE_RELATIVE_MAX_IN_BAR_VISUALIZATION=True

View File

@ -132,6 +132,11 @@
"description": "How many services should be displayed on dashboard page?", "description": "How many services should be displayed on dashboard page?",
"value": "5", "value": "5",
"required": false "required": false
},
"USE_RELATIVE_MAX_IN_BAR_VISUALIZATION": {
"description": "Should background bars be scaled to full width?",
"value": "True",
"required": false
} }
} }
} }

View File

@ -0,0 +1,6 @@
{% load helpers %}
<div
class="absolute h-6"
style="width: {% bar_width count max total %}; top: 6px; left: 0px; height: calc(100% - 12px); background-color: var(--color-urge-200-fallback)"
>
</div>

View File

@ -109,8 +109,20 @@
<tbody> <tbody>
{% for location in stats.locations %} {% for location in stats.locations %}
<tr> <tr>
<td class="truncate w-full max-w-0">{{location.location|default:"Unknown"|urldisplay}}</td> <td class="truncate w-full max-w-0 relative">
<td class="rf">{{location.count|intcomma}}</td> {% include 'dashboard/includes/bar.html' with count=location.count max=stats.locations.0.count total=stats.hit_count %}
<div class="relative flex items-center">
{{location.location|default:"Unknown"|urldisplay}}
</div>
</td>
<td>
<div class="flex justify-end items-center">
{{location.count|intcomma}}
<span class="text-xs rf" style="min-width: 48px">
({{location.count|percent:stats.hit_count}})
</span>
</div>
</td>
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
@ -131,8 +143,20 @@
<tbody> <tbody>
{% for referrer in stats.referrers %} {% for referrer in stats.referrers %}
<tr> <tr>
<td class="truncate w-full max-w-0">{{referrer.referrer|default:"Direct"|urldisplay}}</td> <td class="truncate w-full max-w-0 relative">
<td class="rf">{{referrer.count|intcomma}}</td> {% include 'dashboard/includes/bar.html' with count=referrer.count max=stats.referrers.0.count total=stats.session_count %}
<div class="relative flex items-center">
{{referrer.referrer|default:"Direct"|urldisplay}}
</div>
</td>
<td>
<div class="flex justify-end items-center">
{{referrer.count|intcomma}}
<span class="text-xs rf" style="min-width: 48px">
({{referrer.count|percent:stats.session_count}})
</span>
</div>
</td>
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
@ -153,10 +177,20 @@
<tbody> <tbody>
{% for country in stats.countries %} {% for country in stats.countries %}
<tr> <tr>
<td class="truncate w-full max-w-0" title="{{country.country|country_name}}"> <td class="truncate w-full max-w-0 relative" title="{{country.country|country_name}}">
<span class="{{country.country|flag_class}}"></span> {{country.country|country_name}} {% include 'dashboard/includes/bar.html' with count=country.count max=stats.countries.0.count total=stats.session_count %}
<div class="relative flex items-center">
<span class="flex-none {{country.country|flag_class}}"></span> {{country.country|country_name}}
</div>
</td>
<td>
<div class="flex justify-end items-center">
{{country.count|intcomma}}
<span class="text-xs rf" style="min-width: 48px">
({{country.count|percent:stats.session_count}})
</span>
</div>
</td> </td>
<td class="rf">{{country.count|intcomma}}</td>
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
@ -177,10 +211,20 @@
<tbody> <tbody>
{% for os in stats.operating_systems %} {% for os in stats.operating_systems %}
<tr> <tr>
<td class="flex items-center truncate w-full max-w-0" title="{{os.os|default:'Unknown'}}"> <td class="flex items-center truncate w-full max-w-0 relative" title="{{os.os|default:'Unknown'}}">
{{os.os|iconify}}<span>{{os.os|default:"Unknown"}}</span> {% include 'dashboard/includes/bar.html' with count=os.count max=stats.operating_systems.0.count total=stats.session_count %}
<div class="relative flex items-center">
{{os.os|iconify}}<span>{{os.os|default:"Unknown"}}</span>
</div>
</td>
<td>
<div class="flex justify-end items-center">
{{os.count|intcomma}}
<span class="text-xs rf" style="min-width: 48px">
({{os.count|percent:stats.session_count}})
</span>
</div>
</td> </td>
<td class="rf">{{os.count|intcomma}}</td>
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
@ -201,9 +245,21 @@
<tbody> <tbody>
{% for browser in stats.browsers %} {% for browser in stats.browsers %}
<tr> <tr>
<td class="flex items-center truncate w-full max-w-0" title="{{browser.browser|default:'Unknown'}}"> <td class="flex items-center truncate w-full max-w-0 relative" title="{{browser.browser|default:'Unknown'}}">
{{browser.browser|iconify}}<span>{{browser.browser|default:"Unknown"}}</span></td> {% include 'dashboard/includes/bar.html' with count=browser.count max=stats.browsers.0.count total=stats.session_count %}
<td class="rf">{{browser.count|intcomma}}</td> </div>
<div class="relative flex items-center">
{{browser.browser|iconify}}<span>{{browser.browser|default:"Unknown"}}</span>
</div>
</td>
<td>
<div class="flex justify-end items-center">
{{browser.count|intcomma}}
<span class="text-xs rf" style="min-width: 48px">
({{browser.count|percent:stats.session_count}})
</span>
</div>
</td>
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
@ -224,8 +280,20 @@
<tbody> <tbody>
{% for device_type in stats.device_types %} {% for device_type in stats.device_types %}
<tr> <tr>
<td class="truncate w-full max-w-0">{{device_type.device_type|default:"Unknown"|title}}</td> <td class="truncate w-full max-w-0 relative">
<td class="rf">{{device_type.count|intcomma}}</td> {% include 'dashboard/includes/bar.html' with count=device_type.count max=stats.device_types.0.count total=stats.session_count %}
<div class="relative flex items-center">
{{device_type.device_type|default:"Unknown"|title}}
</div>
</td>
<td>
<div class="flex justify-end items-center">
{{device_type.count|intcomma}}
<span class="text-xs rf" style="min-width: 48px">
({{device_type.count|percent:stats.session_count}})
</span>
</div>
</td>
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
@ -243,4 +311,4 @@
sessions sessions
&rarr;</a> &rarr;</a>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -186,6 +186,7 @@ def urldisplay(url):
else: else:
return url return url
class ContextualURLNode(template.Node): 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.""" """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)) url_parts = list(urlparse(url))
query = dict(urllib.parse.parse_qsl(url_parts[4])) query = dict(urllib.parse.parse_qsl(url_parts[4]))
query.update({ 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 {
}) 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) url_parts[4] = urllib.parse.urlencode(query)
@ -224,7 +229,39 @@ class ContextualURLNode(template.Node):
def contextual_url(*args, **kwargs): def contextual_url(*args, **kwargs):
urlnode = url_tag(*args, **kwargs) urlnode = url_tag(*args, **kwargs)
return ContextualURLNode(urlnode) return ContextualURLNode(urlnode)
@register.filter @register.filter
def location_url(session): 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%}'

View File

@ -310,7 +310,10 @@ NPM_FILE_PATTERNS = {
"stimulus": [os.path.join("dist", "stimulus.umd.js")], "stimulus": [os.path.join("dist", "stimulus.umd.js")],
"inter-ui": [os.path.join("Inter (web)", "*")], "inter-ui": [os.path.join("Inter (web)", "*")],
"@fortawesome": [os.path.join("fontawesome-free", "js", "all.min.js")], "@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 # 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" AGGRESSIVE_HASH_SALTING = os.getenv("AGGRESSIVE_HASH_SALTING", "False") == "True"
# What location url should be linked to in the frontend? # 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? # How many services should be displayed on dashboard page?
DASHBOARD_PAGE_SIZE = int(os.getenv("DASHBOARD_PAGE_SIZE", "5")) 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"
)