musician new dashborad

This commit is contained in:
Jorge Pastor 2024-06-19 13:41:34 +02:00
parent a00d1eff9f
commit 17e0497ed8
8 changed files with 224 additions and 294 deletions

View File

@ -14,7 +14,8 @@ class CustomContextMixin(ContextMixin):
context = super().get_context_data(**kwargs)
# generate services menu items
services_menu = [
{'icon': 'globe-europe', 'pattern_name': 'musician:dashboard', 'title': _('Domains')},
{'icon': 'home', 'pattern_name': 'musician:dashboard', 'title': _('Dashboard')},
{'icon': 'globe-europe', 'pattern_name': 'musician:domain-list', 'title': _('Domains')},
{'icon': 'envelope', 'pattern_name': 'musician:address-list', 'title': _('Mails')},
{'icon': 'mail-bulk', 'pattern_name': 'musician:mailing-lists', 'title': _('Mailing lists')},
{'icon': 'database', 'pattern_name': 'musician:database-list', 'title': _('Databases')},

View File

@ -10,157 +10,97 @@
<p>{% trans "It's the first time you log into the system, welcome on board!" %}</p>
{% endif %}
<div class="alert alert-secondary" role="alert">
{% blocktrans %} The disk space of resources is updated weekly {% endblocktrans %}
</div>
<!-- Deck account -->
<div class="card-deck">
<div class="card resource-usage resource-account">
<div class="card-body">
<h5 class="card-title">{{ account.verbose_name }}</h5>
<div class="text-center">
{% if account.data and account.data.used %}
{{ account.data.used|floatformat }} {{ account.data.unit }}
{% endif %}
</div>
{% if account.data.progres_bar %}
<div class="progress">
<div class="progress-bar bg-secondary" style="width: {{ account.data.percent }}%"></div>
</div>
{% endif %}
{% if account.data.alert %}
<div class="text-center mt-4">
{{ account.data.alert }}
</div>
{% endif %}
</div>
<ul class="list-group">
{% for name, obj_data in account.objects.items %}
<li class="list-group-item d-flex justify-content-between align-items-center">
{{ name }}
<span class="badge badge-primary badge-pill">{{ obj_data.ac.used }} {{ obj_data.ac.unit }}</span>
</li>
{% endfor %}
</ul>
</div>
</div>
<!-- Deck resources -->
<div class="card-deck">
{% for resource, usage in resource_usage.items %}
<div class="card resource-usage resource-{{ resource }}">
<div class="card-body">
<div class="card-body" data-toggle="collapse" data-target="#collapse-{{ resource }}">
<h5 class="card-title">{{ usage.verbose_name }}</h5>
{% include "musician/components/usage_progress_bar.html" with detail=usage.data %}
<div class="text-center">
{% if usage.data and usage.data.used %}
{{ usage.data.used|floatformat }} {{ usage.data.unit }}
{% endif %}
</div>
{% if usage.data.progres_bar %}
<div class="progress">
<div class="progress-bar bg-secondary" style="width: {{ usage.data.percent }}%"></div>
</div>
{% endif %}
{% if usage.data.alert %}
<div class="text-center mt-4">
{{ usage.data.alert }}
</div>
{% endif %}
</div>
<div id="collapse-{{ resource }}" class="collapse">
<ul class="list-group">
{% for obj_data in usage.objects %}
<li class="list-group-item d-flex justify-content-between align-items-center">
{{ obj_data }}
<span class="badge badge-primary badge-pill">{{ obj_data.used }} {{ obj_data.resource.unit }}</span>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endfor %}
<div class="card resource-usage resource-notifications">
<div class="card-body">
<h5 class="card-title">{% trans "Notifications" %}</h5>
{% for message in notifications %}
<p class="card-text">{{ message }}</p>
{% empty %}
<p class="card-text">{% trans "There is no notifications at this time." %}</p>
{% endfor %}
</div>
</div>
</div>
<h1 class="service-name">{% trans "Your domains and websites" %}</h1>
<p class="service-description">{% trans "Dashboard page description." %}</p>
<!-- card domains -->
<div class="card resource-usage resource-domains">
<div class="card-body" data-toggle="collapse" data-target="#collapse-domains">
<h5 class="card-title">{% trans "Domains" %}</h5>
<div class="text-center">{{ domains|length }} {% trans "Domains" %}</div>
</div>
<div id="collapse-domains" class="collapse">
<ul class="list-group">
{% for domain in domains %}
<div class="card service-card">
<div class="card-header">
<div class="row">
<div class="col-md">
<strong>{{ domain.name }}</strong>
</div>
<div class="col-md-8">
{% with domain.websites.0 as website %}
{% with website.contents.0 as content %}
<a href="{% url 'musician:domain-detail' domain.id %}" class="btn btn-primary">{% trans "View DNS records" %}</a>
<!-- <button type="button" class="btn text-secondary" data-toggle="modal" data-target="#configDetailsModal"
data-domain="{{ domain.name }}" data-website="{{ website|yesno:'true,false' }}" data-webapp-type="{{ content.webapp.type }}" data-root-path="{{ content.path }}"
data-url="{% url 'musician:domain-detail' domain.id %}">
{% trans "view configuration" %} <strong class="fas fa-tools"></strong>
</button> -->
{% endwith %}
{% endwith %}
</div>
<div class="col-md text-right">
{% comment "@slamora: orchestra doesn't have this information [won't fix] See issue #2" %}
{% trans "Expiration date" %}: <strong>{{ domain.expiration_date|date:"SHORT_DATE_FORMAT" }}</strong>
{% endcomment %}
</div>
</div>
</div><!-- /card-header-->
<div class="card-body row text-center">
<div class="col-6 col-md-3 col-lg-2 border-right">
<h4>{% trans "Mail" %}</h4>
<p class="card-text"><i class="fas fa-envelope fa-3x"></i></p>
<p class="card-text text-dark">
{{ domain.addresses.count }} {% trans "mail addresses created" %}
</p>
<a class="stretched-link" href="{% url 'musician:address-list' %}?domain={{ domain.id }}"></a>
</div>
<div class="col-6 col-md-3 col-lg-2 border-right">
<h4>{% trans "Mail list" %}</h4>
<p class="card-text"><i class="fas fa-mail-bulk fa-3x"></i></p>
<a class="stretched-link" href="{% url 'musician:mailing-lists' %}?domain={{ domain.id }}"></a>
</div>
<div class="col-6 col-md-3 col-lg-2 border-right">
<h4>{% trans "Software as a Service" %}</h4>
<p class="card-text"><i class="fas fa-fire fa-3x"></i></p>
<p class="card-text text-dark">{% trans "Nothing installed" %}</p>
<a class="stretched-link" href="{% url 'musician:saas-list' %}?domain={{ domain.id }}"></a>
</div>
<div class="d-none d-lg-block col-lg-1"></div>
<!--
<div class="col-6 col-md-3 col-lg-4">
<h4>{% trans "Disk usage" %}</h4>
<p class="card-text"><i class="fas fa-hdd fa-3x"></i></p>
<div class="w-75 m-auto">
{% include "musician/components/usage_progress_bar.html" with detail=domain.usage %}
</div>
</div>
-->
<div class="d-none d-lg-block col-lg-1"></div>
</div>
</div>
<li class="list-group-item d-flex justify-content-between align-items-center">
{{ domain }}
<a href="{% url 'musician:domain-list'%}" rel="noopener noreferrer"><i class="fas fa-external-link-alt"></i></a>
</li>
{% endfor %}
</ul>
</div>
</div>
<!-- configuration details modal -->
<div class="modal fade" id="configDetailsModal" tabindex="-1" role="dialog" aria-labelledby="configDetailsModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title text-secondary" id="configDetailsModalLabel">{% trans "Configuration details" %}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="domain-ftp pb-3 border-bottom">
<h6 class="pl-4 mb-4">{% trans "FTP access:" %}</h6>
{# Translators: domain configuration detail modal #}
<p>
{% blocktrans %}E-mail us at {{ support_email_anchor }} to get details concerning FTP access.{% endblocktrans %}
</p>
{% comment %}
<!-- hidden until API provides FTP information -->
<label>{% trans "Username" %}:</label> <span id="config-username" class="font-weight-bold">username</span><br/>
<label>{% trans "Password:" %}</label> <span id="config-password" class="font-weight-bold">password</span>
{% endcomment %}
</div>
<div class="domain-website pt-4">
<div id="no-website"><h6 class="pl-4">{% trans "No website configured." %}</h6></div>
<div id="config-website">
<label>{% trans "Root directory:" %}</label> <span id="config-root-path" class="font-weight-bold">root directory</span>
<label>{% trans "Type:" %}</label><span id="config-webapp-type" class="font-weight-bold">type</span>
</div>
</div>
</div>
<div class="modal-footer">
<a href="#domain-detail" class="btn btn-primary">{% trans "View DNS records" %}</a>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extrascript %}
<script>
$('#configDetailsModal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget); // Button that triggered the modal
var modal = $(this);
// Extract info from data-* attributes
modal.find('.modal-title').text(button.data('domain'));
modal.find('.modal-body #config-webapp-type').text(button.data('webapp-type'));
modal.find('.modal-body #config-root-path').text(button.data('root-path'));
modal.find('.modal-footer .btn').attr('href', button.data('url'));
var nowebsite = modal.find('.modal-body #no-website');
var websitecfg = modal.find('.modal-body #config-website');
if(button.data('website')) {
nowebsite.hide();
websitecfg.show();
} else {
nowebsite.show();
websitecfg.hide();
}
})
</script>
{% endblock %}

View File

@ -1,111 +0,0 @@
{% extends "musician/base.html" %}
{% load i18n %}
{% block content %}
<h2 style="margin-top: 10px;">{% trans "Welcome back" %} <strong>{{ profile.username }}</strong></h2>
{% if profile.last_login %}
<p>{% blocktrans with last_login=profile.last_login|date:"SHORT_DATE_FORMAT" %}Last time you logged in was: {{ last_login }}{% endblocktrans %}</p>
{% else %}
<p>{% trans "It's the first time you log into the system, welcome on board!" %}</p>
{% endif %}
<!-- Deck account -->
<div class="card-deck">
<div class="card resource-usage resource-account">
<div class="card-body">
<h5 class="card-title">{{ account.verbose_name }}</h5>
<div class="text-center">
{% if account.data and account.data.used %}
{{ account.data.used|floatformat }} {{ account.data.unit }}
{% endif %}
</div>
{% if account.data.progres_bar %}
<div class="progress">
<div class="progress-bar bg-secondary" style="width:{{ account.data.percent }}%"></div>
</div>
{% endif %}
{% if account.data.alert %}
<div class="text-center mt-4">
{{ account.data.alert }}
</div>
{% endif %}
</div>
<ul class="list-group">
{% for name, obj_data in account.objects.items %}
<li class="list-group-item d-flex justify-content-between align-items-center">
{{ name }}
<span class="badge badge-primary badge-pill">{{ obj_data.ac.used }} {{ obj_data.ac.unit }}</span>
</li>
{% endfor %}
</ul>
</div>
</div>
<!-- Deck resources -->
<div class="card-deck">
{% for resource, usage in resource_usage.items %}
<div class="card resource-usage resource-{{ resource }}">
<div class="card-body" data-toggle="collapse" data-target="#collapse-{{ resource }}">
<h5 class="card-title">{{ usage.verbose_name }}</h5>
<div class="text-center">
{% if usage.data and usage.data.used %}
{{ usage.data.used|floatformat }} {{ usage.data.unit }}
{% endif %}
</div>
{% if usage.data.progres_bar %}
<div class="progress">
<div class="progress-bar bg-secondary" style="width: {{ usage.data.percent }}%"></div>
</div>
{% endif %}
{% if usage.data.alert %}
<div class="text-center mt-4">
{{ usage.data.alert }}
</div>
{% endif %}
</div>
<div id="collapse-{{ resource }}" class="collapse">
<ul class="list-group">
{% for obj_data in usage.objects %}
<li class="list-group-item d-flex justify-content-between align-items-center">
{{ obj_data }}
<span class="badge badge-primary badge-pill">{{ obj_data.used }} {{ obj_data.resource.unit }}</span>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endfor %}
<!-- card domains -->
<div class="card resource-usage resource-domains">
<div class="card-body" data-toggle="collapse" data-target="#collapse-domains">
<h5 class="card-title">{% trans "Domains" %}</h5>
<div class="text-center">{{ domains|length }} {% trans "Domains" %}</div>
</div>
<div id="collapse-domains" class="collapse">
<ul class="list-group">
{% for domain in domains %}
<li class="list-group-item d-flex justify-content-between align-items-center">
{{ domain }}
<a href="{% url 'musician:dashboard'%}" rel="noopener noreferrer"><i class="fas fa-external-link-alt"></i></a>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
<!-- <div class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item" src="{{ history_disk }}" allowfullscreen></iframe>
</div>
<div class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item" src="{{ history_traffic }}" allowfullscreen></iframe>
</div> -->
{% endblock %}

View File

@ -2,7 +2,7 @@
{% load i18n %}
{% block content %}
<a class="btn-arrow-left" href="{% url 'musician:dashboard' %}">{% trans "Go back" %}</a>
<a class="btn-arrow-left" href="{% url 'musician:domain-list' %}">{% trans "Go back" %}</a>
<h1 class="service-name">
{% trans "DNS settings for" %} <span class="font-weight-light">{{ object.name }}</span>

View File

@ -0,0 +1,133 @@
{% extends "musician/base.html" %}
{% load i18n %}
{% block content %}
<h1 class="service-name">{% trans "Your domains" %}</h1>
{% for domain in domains %}
<div class="card service-card">
<div class="card-header">
<div class="row">
<div class="col-md">
<strong>{{ domain.name }}</strong>
</div>
<div class="col-md-8">
{% with domain.websites.0 as website %}
{% with website.contents.0 as content %}
<a href="{% url 'musician:domain-detail' domain.id %}" class="btn btn-primary">{% trans "View DNS records" %}</a>
<!-- <button type="button" class="btn text-secondary" data-toggle="modal" data-target="#configDetailsModal"
data-domain="{{ domain.name }}" data-website="{{ website|yesno:'true,false' }}" data-webapp-type="{{ content.webapp.type }}" data-root-path="{{ content.path }}"
data-url="{% url 'musician:domain-detail' domain.id %}">
{% trans "view configuration" %} <strong class="fas fa-tools"></strong>
</button> -->
{% endwith %}
{% endwith %}
</div>
<div class="col-md text-right">
{% comment "@slamora: orchestra doesn't have this information [won't fix] See issue #2" %}
{% trans "Expiration date" %}: <strong>{{ domain.expiration_date|date:"SHORT_DATE_FORMAT" }}</strong>
{% endcomment %}
</div>
</div>
</div><!-- /card-header-->
<div class="card-body row text-center">
<div class="col-6 col-md-3 col-lg-2 border-right">
<h4>{% trans "Mail" %}</h4>
<p class="card-text"><i class="fas fa-envelope fa-3x"></i></p>
<p class="card-text text-dark">
{{ domain.addresses.count }} {% trans "mail addresses created" %}
</p>
<a class="stretched-link" href="{% url 'musician:address-list' %}?domain={{ domain.id }}"></a>
</div>
<div class="col-6 col-md-3 col-lg-2 border-right">
<h4>{% trans "Mail list" %}</h4>
<p class="card-text"><i class="fas fa-mail-bulk fa-3x"></i></p>
<a class="stretched-link" href="{% url 'musician:mailing-lists' %}?domain={{ domain.id }}"></a>
</div>
<div class="col-6 col-md-3 col-lg-2 border-right">
<h4>{% trans "Software as a Service" %}</h4>
<p class="card-text"><i class="fas fa-fire fa-3x"></i></p>
<p class="card-text text-dark">{% trans "Nothing installed" %}</p>
<a class="stretched-link" href="{% url 'musician:saas-list' %}?domain={{ domain.id }}"></a>
</div>
<div class="d-none d-lg-block col-lg-1"></div>
<!--
<div class="col-6 col-md-3 col-lg-4">
<h4>{% trans "Disk usage" %}</h4>
<p class="card-text"><i class="fas fa-hdd fa-3x"></i></p>
<div class="w-75 m-auto">
{% include "musician/components/usage_progress_bar.html" with detail=domain.usage %}
</div>
</div>
-->
<div class="d-none d-lg-block col-lg-1"></div>
</div>
</div>
{% endfor %}
<!-- configuration details modal -->
<div class="modal fade" id="configDetailsModal" tabindex="-1" role="dialog" aria-labelledby="configDetailsModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title text-secondary" id="configDetailsModalLabel">{% trans "Configuration details" %}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="domain-ftp pb-3 border-bottom">
<h6 class="pl-4 mb-4">{% trans "FTP access:" %}</h6>
{# Translators: domain configuration detail modal #}
<p>
{% blocktrans %}E-mail us at {{ support_email_anchor }} to get details concerning FTP access.{% endblocktrans %}
</p>
{% comment %}
<!-- hidden until API provides FTP information -->
<label>{% trans "Username" %}:</label> <span id="config-username" class="font-weight-bold">username</span><br/>
<label>{% trans "Password:" %}</label> <span id="config-password" class="font-weight-bold">password</span>
{% endcomment %}
</div>
<div class="domain-website pt-4">
<div id="no-website"><h6 class="pl-4">{% trans "No website configured." %}</h6></div>
<div id="config-website">
<label>{% trans "Root directory:" %}</label> <span id="config-root-path" class="font-weight-bold">root directory</span>
<label>{% trans "Type:" %}</label><span id="config-webapp-type" class="font-weight-bold">type</span>
</div>
</div>
</div>
<div class="modal-footer">
<a href="#domain-detail" class="btn btn-primary">{% trans "View DNS records" %}</a>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extrascript %}
<script>
$('#configDetailsModal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget); // Button that triggered the modal
var modal = $(this);
// Extract info from data-* attributes
modal.find('.modal-title').text(button.data('domain'));
modal.find('.modal-body #config-webapp-type').text(button.data('webapp-type'));
modal.find('.modal-body #config-root-path').text(button.data('root-path'));
modal.find('.modal-footer .btn').attr('href', button.data('url'));
var nowebsite = modal.find('.modal-body #no-website');
var websitecfg = modal.find('.modal-body #config-website');
if(button.data('website')) {
nowebsite.hide();
websitecfg.show();
} else {
nowebsite.show();
websitecfg.hide();
}
})
</script>
{% endblock %}

View File

@ -17,8 +17,8 @@ urlpatterns = [
path('auth/login/', views.LoginView.as_view(), name='login'),
path('auth/logout/', views.LogoutView.as_view(), name='logout'),
path('dashboard/', views.DashboardView.as_view(), name='dashboard'),
path('dashboard2/', views.DashboardView2.as_view(), name='dashboard2'),
path('domains/', views.DomainListView.as_view(), name='domain-list'),
path('domains/<int:pk>/', views.DomainDetailView.as_view(), name='domain-detail'),
path('domains/<int:pk>/add-record/', views.DomainAddRecordView.as_view(), name='domain-add-record'),
path('domains/<int:pk>/records/<int:record_pk>/update/', views.DomainUpdateRecordView.as_view(), name='domain-update-record'),

View File

@ -22,4 +22,4 @@ def get_bootstraped_percent_exact(value, total):
percent = 100 * float(value)/float(total)
except (TypeError, ZeroDivisionError):
return 0
return percent
return int(percent)

View File

@ -24,6 +24,9 @@ from django.views.generic.edit import (CreateView, DeleteView, FormView,
from django.views.generic.list import ListView
from requests.exceptions import HTTPError
from django.urls import reverse
from django.db.models import Q
from orchestra import get_version
from orchestra.contrib.bills.models import Bill
from orchestra.contrib.databases.models import Database
@ -57,10 +60,9 @@ from .lists.views import *
logger = logging.getLogger(__name__)
from django.urls import reverse
from django.db.models import Q
class DashboardView2(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
template_name = "musician/dashboard2.html"
class DashboardView(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
template_name = "musician/dashboard.html"
extra_context = {
# Translators: This message appears on the page title
'title': _('Dashboard'),
@ -193,28 +195,17 @@ class DashboardView2(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
}
class DashboardView(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
template_name = "musician/dashboard.html"
class DomainListView(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
template_name = "musician/domain_list.html"
extra_context = {
# Translators: This message appears on the page title
'title': _('Dashboard'),
'title': _('Domains'),
}
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
domains = self.orchestra.retrieve_domain_list()
# TODO(@slamora) update when backend supports notifications
notifications = []
# show resource usage based on plan definition
profile_type = context['profile'].type
# TODO(@slamora) update when backend provides resource usage data
resource_usage = {
'mailbox': self.get_mailbox_usage(profile_type),
}
support_email = getattr(settings, "USER_SUPPORT_EMAIL", "suport@pangea.org")
support_email_anchor = format_html(
"<a href='mailto:{}'>{}</a>",
@ -223,35 +214,11 @@ class DashboardView(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
)
context.update({
'domains': domains,
'resource_usage': resource_usage,
'notifications': notifications,
"support_email_anchor": support_email_anchor,
})
return context
def get_mailbox_usage(self, profile_type):
allowed_mailboxes = ALLOWED_RESOURCES[profile_type]['mailbox']
total_mailboxes = len(self.orchestra.retrieve_mailbox_list())
mailboxes_left = allowed_mailboxes - total_mailboxes
alert = ''
if mailboxes_left < 0:
alert = format_html("<span class='text-danger'>{} extra mailboxes</span>", mailboxes_left * -1)
elif mailboxes_left <= 1:
alert = format_html("<span class='text-warning'>{} mailbox left</span>", mailboxes_left)
return {
'verbose_name': _('Mailboxes'),
'data': {
'used': total_mailboxes,
'total': allowed_mailboxes,
'alert': alert,
'unit': 'mailboxes',
'percent': get_bootstraped_percent(total_mailboxes, allowed_mailboxes),
},
}
class ProfileView(CustomContextMixin, UserTokenRequiredMixin, TemplateView):
template_name = "musician/profile.html"