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:
parent
f3a89bff78
commit
fcea6d3be9
@ -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
|
||||||
|
5
app.json
5
app.json
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
6
shynet/dashboard/templates/dashboard/includes/bar.html
Normal file
6
shynet/dashboard/templates/dashboard/includes/bar.html
Normal 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>
|
@ -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>
|
||||||
|
@ -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)
|
||||||
|
|
||||||
@ -225,6 +230,38 @@ 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%}'
|
||||||
|
@ -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"
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user