basic dashboard

This commit is contained in:
meeb 2020-12-11 18:12:08 +11:00
parent c006204bea
commit ba4423ac57
6 changed files with 153 additions and 6 deletions

View File

@ -27,6 +27,8 @@ $footer-text-colour: $colour-near-white;
$footer-link-colour: $colour-near-black; $footer-link-colour: $colour-near-black;
$footer-link-hover-colour: $colour-orange; $footer-link-hover-colour: $colour-orange;
$dash-desc-border: $colour-near-black;
$form-label-text-colour: $colour-near-black; $form-label-text-colour: $colour-near-black;
$form-input-border-colour: $colour-light-blue; $form-input-border-colour: $colour-light-blue;
$form-input-border-active-colour: $colour-orange; $form-input-border-active-colour: $colour-orange;

View File

@ -6,6 +6,10 @@ strong {
white-space: nowrap; white-space: nowrap;
} }
.no-para-margin-top {
margin-block-start: 0;
}
.no-margin-bottom { .no-margin-bottom {
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }

View File

@ -143,6 +143,29 @@ main {
} }
} }
.dashcard {
text-align: center;
h3 {
font-size: 2.5rem;
padding: 0;
margin: 0;
}
h4 {
text-align: left;
font-size: 1.5rem;
padding: 0 0 0.5rem 0;
margin: 0;
}
.desc {
border-bottom: 1px $dash-desc-border solid;
padding: 0 0 0.5rem 0;
margin: 0 0 0.5rem 0;
}
.collection-item {
text-align: left;
}
}
.pagination { .pagination {
width: 100%; width: 100%;
padding-top: 1rem; padding-top: 1rem;

View File

@ -1,4 +1,4 @@
{% extends 'base.html' %} {% extends 'base.html' %}{% load humanize %}
{% block headtitle %}Dashboard{% endblock %} {% block headtitle %}Dashboard{% endblock %}
@ -8,11 +8,93 @@
<h1 class="truncate">Dashboard</h1> <h1 class="truncate">Dashboard</h1>
</div> </div>
</div> </div>
{% if num_sources == 0 %}
<div class="row"> <div class="row">
<div class="col s12"> <div class="col s12">
<div class="card"> <p class="no-para-margin-top">
You don't have any media sources added. To get started, head over to the
<a href="{% url 'sync:sources' %}">sources</a> page and add some.
</p>
<a href="{% url 'sync:sources' %}" class="btn">Add a source <i class="fas fa-fw fa-play"></i></a>
</div>
</div>
{% endif %}
<div class="row no-margin-bottom">
<div class="col s12 m6 xl3">
<div class="card dashcard">
<a href="{% url 'sync:sources' %}">
<div class="card-content">
<h3>{{ num_sources }}</h3>
<div class="desc truncate">source{{ num_sources|pluralize }}</div>
<div class="truncate"><strong>{{ num_video_sources }}</strong> video, <strong>{{ num_audio_sources }}</strong> audio</div>
</div>
</a>
</div>
</div>
<div class="col s12 m6 xl3">
<div class="card dashcard">
<a href="{% url 'sync:media' %}">
<div class="card-content">
<h3>{{ num_media }}</h3>
<div class="desc truncate">media</div>
<div class="truncate"><strong>{{ num_downloaded_media }}</strong> downloaded</div>
</div>
</a>
</div>
</div>
<div class="col s12 m6 xl3">
<div class="card dashcard">
<a href="{% url 'sync:tasks' %}">
<div class="card-content">
<h3>{{ num_tasks }}</h3>
<div class="desc truncate">scheduled task{{ num_tasks|pluralize }}</div>
<div class="truncate"><strong>{{ num_completed_tasks }}</strong> completed</div>
</div>
</a>
</div>
</div>
<div class="col s12 m6 xl3">
<div class="card dashcard">
<a href="{% url 'sync:media' %}">
<div class="card-content">
<h3>{{ disk_usage_bytes|filesizeformat }}</h3>
<div class="desc truncate">{{ disk_usage_bytes|intcomma }} bytes</div>
<div class="truncate">Avg. <strong>{{ average_bytes_per_media|filesizeformat }}</strong> per media</div>
</div>
</a>
</div>
</div>
<div class="col s12 l6">
<div class="card dashcard">
<div class="card-content"> <div class="card-content">
intro <h4>Latest downloads</h4>
<div class="collection">
{% for media in latest_downloads %}
<a href="{% url 'sync:media-item' pk=media.pk %}" class="collection-item">
<div class="truncate"><strong>{{ media.name }}</strong> ({{ media.source }})</div>
<div class="truncate"><strong>{{ media.download_date|timesince:now }}</strong> ago from &quot;{{ media.source.name }}&quot;</div>
</a>
{% empty %}
<span class="collection-item">No media has been downloaded.</span>
{% endfor %}
</div>
</div>
</div>
</div>
<div class="col s12 l6">
<div class="card dashcard">
<div class="card-content">
<h4>Largest downloads</h4>
<div class="collection">
{% for media in largest_downloads %}
<a href="{% url 'sync:media-item' pk=media.pk %}" class="collection-item">
<div class="truncate">{{ media.name }}</div>
<div class="truncate"><strong>{{ media.downloaded_filesize|filesizeformat }}</strong>{% if media.downloaded_format %} in {{ media.downloaded_format }}{% endif %}</div>
</a>
{% empty %}
<span class="collection-item">No media has been downloaded.</span>
{% endfor %}
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -7,7 +7,7 @@ from django.views.generic.edit import (FormView, FormMixin, CreateView, UpdateVi
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
from django.http import HttpResponse from django.http import HttpResponse
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.db.models import Count from django.db.models import Q, Count, Sum
from django.forms import ValidationError from django.forms import ValidationError
from django.utils.text import slugify from django.utils.text import slugify
from django.utils import timezone from django.utils import timezone
@ -32,8 +32,43 @@ class DashboardView(TemplateView):
template_name = 'sync/dashboard.html' template_name = 'sync/dashboard.html'
def dispatch(self, request, *args, **kwargs): def get_context_data(self, *args, **kwargs):
return super().dispatch(request, *args, **kwargs) data = super().get_context_data(*args, **kwargs)
data['now'] = timezone.now()
# Sources
data['num_sources'] = Source.objects.all().count()
data['num_video_sources'] = Source.objects.filter(
~Q(source_resolution=Source.SOURCE_RESOLUTION_AUDIO)
).count()
data['num_audio_sources'] = data['num_sources'] - data['num_video_sources']
data['num_failed_sources'] = Source.objects.filter(has_failed=True).count()
# Media
data['num_media'] = Media.objects.all().count()
data['num_downloaded_media'] = Media.objects.filter(downloaded=True).count()
# Tasks
data['num_tasks'] = Task.objects.all().count()
data['num_completed_tasks'] = CompletedTask.objects.all().count()
# Disk usage
disk_usage = Media.objects.filter(
downloaded=True, downloaded_filesize__isnull=False
).aggregate(Sum('downloaded_filesize'))
data['disk_usage_bytes'] = disk_usage['downloaded_filesize__sum']
if not data['disk_usage_bytes']:
data['disk_usage_bytes'] = 0
if data['disk_usage_bytes'] and data['num_downloaded_media']:
data['average_bytes_per_media'] = round(data['disk_usage_bytes'] /
data['num_downloaded_media'])
else:
data['average_bytes_per_media'] = 0
# Latest downloads
data['latest_downloads'] = Media.objects.filter(
downloaded=True
).order_by('-download_date')[:10]
# Largest downloads
data['largest_downloads'] = Media.objects.filter(
downloaded=True, downloaded_filesize__isnull=False
).order_by('-downloaded_filesize')[:10]
return data
class SourcesView(ListView): class SourcesView(ListView):

View File

@ -17,6 +17,7 @@ INSTALLED_APPS = [
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'django.contrib.humanize',
'sass_processor', 'sass_processor',
'background_task', 'background_task',
'common', 'common',