2157: configure datatables via html5 data attributes r=mergify[bot] a=ghostwheel42

## What type of PR?

bug-fix

## What does this PR do?

allows to sort most columns as a human would expect

### Related issue(s)
- closes #2154 

## Prerequisites
Before we can consider review and merge, please make sure the following list is done and checked.
If an entry in not applicable, you can check it or remove it from the list.

- [ ] In case of feature or enhancement: documentation updated accordingly
- [ ] Unless it's docs or a minor change: add [changelog](https://mailu.io/master/contributors/workflow.html#changelog) entry file.


Co-authored-by: Alexander Graf <ghostwheel42@users.noreply.github.com>
main
bors[bot] 2 years ago committed by GitHub
commit cf6da1492e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -57,6 +57,7 @@ def create_app_from_config(config):
return dict( return dict(
signup_domains= signup_domains, signup_domains= signup_domains,
config = app.config, config = app.config,
get_locale = utils.get_locale,
) )
# Jinja filters # Jinja filters

@ -1,7 +1,7 @@
{%- import "macros.html" as macros %} {%- import "macros.html" as macros %}
{%- import "bootstrap/utils.html" as utils %} {%- import "bootstrap/utils.html" as utils %}
<!doctype html> <!doctype html>
<html lang="{{ session['language'] }}" data-static="/static/"> <html lang="{{ get_locale() }}" data-static="/static/">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
@ -34,8 +34,8 @@
<ul class="navbar-nav ml-auto"> <ul class="navbar-nav ml-auto">
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link" data-toggle="dropdown" href="#" aria-expanded="false"> <a class="nav-link" data-toggle="dropdown" href="#" aria-expanded="false">
<i class="fas fa-language text-xl" aria-hidden="true" title="{% trans %}change language{% endtrans %}"></i><span class="sr-only">Language</span> <i class="fas fa-language text-xl" aria-hidden="true" title="{% trans %}change language{% endtrans %}"></i><span class="sr-only">{% trans %}change language{% endtrans %}</span>
<span class="badge badge-primary navbar-badge">{{ session['language'] }}</span></a> <span class="badge badge-primary navbar-badge">{{ get_locale() }}</span></a>
<div class="dropdown-menu dropdown-menu-right p-0" id="mailu-languages"> <div class="dropdown-menu dropdown-menu-right p-0" id="mailu-languages">
{%- for locale in config.translations.values() %} {%- for locale in config.translations.values() %}
<a class="dropdown-item{% if locale|string() == session['language'] %} active{% endif %}" href="{{ url_for('sso.set_language', language=locale) }}">{{ locale.get_language_name().title() }}</a> <a class="dropdown-item{% if locale|string() == session['language'] %} active{% endif %}" href="{{ url_for('sso.set_language', language=locale) }}">{{ locale.get_language_name().title() }}</a>

@ -36,6 +36,12 @@
</a> </a>
</li> </li>
{%- endif %} {%- endif %}
<li class="nav-item" role="none">
<a href="{{ url_for('sso.login') }}" class="nav-link" role="menuitem">
<i class="nav-icon fas fa-sign-in-alt"></i>
<p>{% trans %}Sign in{% endtrans %}</p>
</a>
</li>
{#- {#-
User self-registration is only available when User self-registration is only available when
- Admin is available - Admin is available

@ -14,7 +14,7 @@
{%- call macros.table() %} {%- call macros.table() %}
<thead> <thead>
<tr> <tr>
<th>{% trans %}Actions{% endtrans %}</th> <th data-orderable="false">{% trans %}Actions{% endtrans %}</th>
<th>{% trans %}Email{% endtrans %}</th> <th>{% trans %}Email{% endtrans %}</th>
</tr> </tr>
</thead> </thead>

@ -16,7 +16,7 @@
{%- call macros.table() %} {%- call macros.table() %}
<thead> <thead>
<tr> <tr>
<th>{% trans %}Actions{% endtrans %}</th> <th data-orderable="false">{% trans %}Actions{% endtrans %}</th>
<th>{% trans %}Email{% endtrans %}</th> <th>{% trans %}Email{% endtrans %}</th>
<th>{% trans %}Destination{% endtrans %}</th> <th>{% trans %}Destination{% endtrans %}</th>
<th>{% trans %}Comment{% endtrans %}</th> <th>{% trans %}Comment{% endtrans %}</th>
@ -34,8 +34,8 @@
<td>{{ alias }}</td> <td>{{ alias }}</td>
<td>{{ alias.destination|join(', ') or '-' }}</td> <td>{{ alias.destination|join(', ') or '-' }}</td>
<td>{{ alias.comment or '' }}</td> <td>{{ alias.comment or '' }}</td>
<td>{{ alias.created_at | format_date }}</td> <td data-sort="{{ alias.created_at or '0000-00-00' }}">{{ alias.created_at | format_date }}</td>
<td>{{ alias.updated_at | format_date }}</td> <td data-sort="{{ alias.updated_at or '0000-00-00' }}">{{ alias.updated_at | format_date }}</td>
</tr> </tr>
{%- endfor %} {%- endfor %}
</tbody> </tbody>

@ -16,7 +16,7 @@
{%- call macros.table() %} {%- call macros.table() %}
<thead> <thead>
<tr> <tr>
<th>{% trans %}Actions{% endtrans %}</th> <th data-orderable="false">{% trans %}Actions{% endtrans %}</th>
<th>{% trans %}Name{% endtrans %}</th> <th>{% trans %}Name{% endtrans %}</th>
<th>{% trans %}Created{% endtrans %}</th> <th>{% trans %}Created{% endtrans %}</th>
<th>{% trans %}Last edit{% endtrans %}</th> <th>{% trans %}Last edit{% endtrans %}</th>
@ -29,8 +29,8 @@
<a href="{{ url_for('.alternative_delete', alternative=alternative.name) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a> <a href="{{ url_for('.alternative_delete', alternative=alternative.name) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
</td> </td>
<td>{{ alternative }}</td> <td>{{ alternative }}</td>
<td>{{ alternative.created_at | format_date }}</td> <td data-sort="{{ alternative.created_at or '0000-00-00' }}">{{ alternative.created_at | format_date }}</td>
<td>{{ alternative.updated_at | format_date }}</td> <td data-sort="{{ alternative.updated_at or '0000-00-00' }}">{{ alternative.updated_at | format_date }}</td>
</tr> </tr>
{%- endfor %} {%- endfor %}
</tbody> </tbody>

@ -1,7 +1,7 @@
{%- import "macros.html" as macros %} {%- import "macros.html" as macros %}
{%- import "bootstrap/utils.html" as utils %} {%- import "bootstrap/utils.html" as utils %}
<!doctype html> <!doctype html>
<html lang="{{ session['language'] }}" data-static="/static/"> <html lang="{{ get_locale() }}" data-static="/static/">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
@ -34,8 +34,8 @@
<ul class="navbar-nav ml-auto"> <ul class="navbar-nav ml-auto">
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link" data-toggle="dropdown" href="#" aria-expanded="false"> <a class="nav-link" data-toggle="dropdown" href="#" aria-expanded="false">
<i class="fas fa-language text-xl" aria-hidden="true" title="{% trans %}change language{% endtrans %}"></i><span class="sr-only">Language</span> <i class="fas fa-language text-xl" aria-hidden="true" title="{% trans %}change language{% endtrans %}"></i><span class="sr-only">{% trans %}change language{% endtrans %}</span>
<span class="badge badge-primary navbar-badge">{{ session['language'] }}</span></a> <span class="badge badge-primary navbar-badge">{{ get_locale() }}</span></a>
<div class="dropdown-menu dropdown-menu-right p-0" id="mailu-languages"> <div class="dropdown-menu dropdown-menu-right p-0" id="mailu-languages">
{%- for locale in config.translations.values() %} {%- for locale in config.translations.values() %}
<a class="dropdown-item{% if locale|string() == session['language'] %} active{% endif %}" href="{{ url_for('.set_language', language=locale) }}">{{ locale.get_language_name().title() }}</a> <a class="dropdown-item{% if locale|string() == session['language'] %} active{% endif %}" href="{{ url_for('.set_language', language=locale) }}">{{ locale.get_language_name().title() }}</a>

@ -9,7 +9,6 @@
{%- endblock %} {%- endblock %}
{%- block content %} {%- block content %}
<div>If you use an Apple device, <a href="/apple.mobileconfig">click here to autoconfigure it.</a></div>
{%- call macros.table(title=_("Incoming mail"), datatable=False) %} {%- call macros.table(title=_("Incoming mail"), datatable=False) %}
<tbody> <tbody>
<tr> <tr>
@ -59,4 +58,8 @@
</tr> </tr>
</tbody> </tbody>
{%- endcall %} {%- endcall %}
<blockquote>
{% trans %}If you use an Apple device,{% endtrans %}
<a href="/apple.mobileconfig">{% trans %}click here to autoconfigure it.{% endtrans %}</a>
</blockquote>
{%- endblock %} {%- endblock %}

@ -11,15 +11,16 @@
{%- endblock %} {%- endblock %}
{%- block content %} {%- block content %}
{%- call macros.table() %} {%- call macros.table(order='[[2,"asc"]]') %}
<thead> <thead>
<tr> <tr>
<th>{% trans %}Actions{% endtrans %}</th> <th data-orderable="false">{% trans %}Actions{% endtrans %}</th>
<th>{% trans %}Manage{% endtrans %}</th> <th data-orderable="false">{% trans %}Manage{% endtrans %}</th>
<th>{% trans %}Domain name{% endtrans %}</th> <th>{% trans %}Domain name{% endtrans %}</th>
<th>{% trans %}Mailbox count{% endtrans %}</th> <th>{% trans %}Mailbox count{% endtrans %}</th>
<th>{% trans %}Alias count{% endtrans %}</th> <th>{% trans %}Alias count{% endtrans %}</th>
<th>{% trans %}Comment{% endtrans %}</th> <th>{% trans %}Comment{% endtrans %}</th>
<th>{% trans %}Enable sign-up{% endtrans %}</th>
<th>{% trans %}Created{% endtrans %}</th> <th>{% trans %}Created{% endtrans %}</th>
<th>{% trans %}Last edit{% endtrans %}</th> <th>{% trans %}Last edit{% endtrans %}</th>
</tr> </tr>
@ -43,11 +44,12 @@
{%- endif %} {%- endif %}
</td> </td>
<td>{{ domain.name }}</td> <td>{{ domain.name }}</td>
<td>{{ domain.users | count }} / {{ '∞' if domain.max_users == -1 else domain.max_users }}</td> <td data-order="{{ domain.users | count }}">{{ domain.users | count }} / {{ '∞' if domain.max_users == -1 else domain.max_users }}</td>
<td>{{ domain.aliases | count }} / {{ '∞' if domain.max_aliases == -1 else domain.max_aliases }}</td> <td data-order="{{ domain.aliases | count }}">{{ domain.aliases | count }} / {{ '∞' if domain.max_aliases == -1 else domain.max_aliases }}</td>
<td>{{ domain.comment or '' }}</td> <td>{{ domain.comment or '' }}</td>
<td>{{ domain.created_at | format_date }}</td> <td data-sort="{{ domain.signup_enabled }}">{% if domain.signup_enabled %}{% trans %}yes{% endtrans %}{% else %}{% trans %}no{% endtrans %}{% endif %}</td>
<td>{{ domain.updated_at | format_date }}</td> <td data-order="{{ domain.created_at or '0000-00-00' }}">{{ domain.created_at | format_date }}</td>
<td data-order="{{ domain.updated_at or '0000-00-00' }}">{{ domain.updated_at | format_date }}</td>
</tr> </tr>
{%- endfor %} {%- endfor %}
</tbody> </tbody>

@ -16,7 +16,7 @@
{%- call macros.table() %} {%- call macros.table() %}
<thead> <thead>
<tr> <tr>
<th>{% trans %}Actions{% endtrans %}</th> <th data-orderable="false">{% trans %}Actions{% endtrans %}</th>
<th>{% trans %}Endpoint{% endtrans %}</th> <th>{% trans %}Endpoint{% endtrans %}</th>
<th>{% trans %}Username{% endtrans %}</th> <th>{% trans %}Username{% endtrans %}</th>
<th>{% trans %}Keep emails{% endtrans %}</th> <th>{% trans %}Keep emails{% endtrans %}</th>
@ -35,11 +35,11 @@
</td> </td>
<td>{{ fetch.protocol }}{{ 's' if fetch.tls else '' }}://{{ fetch.host }}:{{ fetch.port }}</td> <td>{{ fetch.protocol }}{{ 's' if fetch.tls else '' }}://{{ fetch.host }}:{{ fetch.port }}</td>
<td>{{ fetch.username }}</td> <td>{{ fetch.username }}</td>
<td>{% if fetch.keep %}{% trans %}yes{% endtrans %}{% else %}{% trans %}no{% endtrans %}{% endif %}</td> <td data-sort="{{ fetch.keep }}">{% if fetch.keep %}{% trans %}yes{% endtrans %}{% else %}{% trans %}no{% endtrans %}{% endif %}</td>
<td>{{ fetch.last_check | format_datetime or '-' }}</td> <td>{{ fetch.last_check | format_datetime or '-' }}</td>
<td>{{ fetch.error or '-' }}</td> <td>{{ fetch.error or '-' }}</td>
<td>{{ fetch.created_at | format_date }}</td> <td data-sort="{{ fetch.created_at or '0000-00-00' }}">{{ fetch.created_at | format_date }}</td>
<td>{{ fetch.updated_at | format_date }}</td> <td data-sort="{{ fetch.updated_at or '0000-00-00' }}">{{ fetch.updated_at | format_date }}</td>
</tr> </tr>
{%- endfor %} {%- endfor %}
</tbody> </tbody>

@ -86,7 +86,7 @@
</div> </div>
{%- endmacro %} {%- endmacro %}
{%- macro table(title=None, theme="primary", datatable=True) %} {%- macro table(title=None, theme="primary", datatable=True, order=None) %}
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
<div class="card card-outline card-{{ theme }}"> <div class="card card-outline card-{{ theme }}">
@ -96,7 +96,7 @@
</div> </div>
{%- endif %} {%- endif %}
<div class="card-body"> <div class="card-body">
<table class="table table-bordered{% if datatable %} dataTable{% endif %}"> <table class="table table-bordered{% if datatable %} dataTable{% endif %}" data-order="{{ order or '[]' | e }}">
{{- caller() }} {{- caller() }}
</table> </table>
</div> </div>

@ -13,10 +13,10 @@
{%- endblock %} {%- endblock %}
{%- block content %} {%- block content %}
{%- call macros.table() %} {%- call macros.table(order='[[2,"asc"]]') %}
<thead> <thead>
<tr> <tr>
<th>{% trans %}Actions{% endtrans %}</th> <th data-orderable="false">{% trans %}Actions{% endtrans %}</th>
<th>{% trans %}Email{% endtrans %}</th> <th>{% trans %}Email{% endtrans %}</th>
</tr> </tr>
</thead> </thead>

@ -11,10 +11,10 @@
{%- endblock %} {%- endblock %}
{%- block content %} {%- block content %}
{%- call macros.table() %} {%- call macros.table(order='[[1,"asc"]]') %}
<thead> <thead>
<tr> <tr>
<th>{% trans %}Actions{% endtrans %}</th> <th data-orderable="false">{% trans %}Actions{% endtrans %}</th>
<th>{% trans %}Domain name{% endtrans %}</th> <th>{% trans %}Domain name{% endtrans %}</th>
<th>{% trans %}Remote host{% endtrans %}</th> <th>{% trans %}Remote host{% endtrans %}</th>
<th>{% trans %}Comment{% endtrans %}</th> <th>{% trans %}Comment{% endtrans %}</th>
@ -32,8 +32,8 @@
<td>{{ relay.name }}</td> <td>{{ relay.name }}</td>
<td>{{ relay.smtp or '-' }}</td> <td>{{ relay.smtp or '-' }}</td>
<td>{{ relay.comment or '' }}</td> <td>{{ relay.comment or '' }}</td>
<td>{{ relay.created_at | format_date }}</td> <td data-sort="{{ relay.created_at or '0000-00-00' }}">{{ relay.created_at | format_date }}</td>
<td>{{ relay.updated_at | format_date }}</td> <td data-sort="{{ relay.updated_at or '0000-00-00' }}">{{ relay.updated_at | format_date }}</td>
</tr> </tr>
{%- endfor %} {%- endfor %}
</tbody> </tbody>

@ -16,7 +16,7 @@
{%- call macros.table() %} {%- call macros.table() %}
<thead> <thead>
<tr> <tr>
<th>{% trans %}Actions{% endtrans %}</th> <th data-orderable="false">{% trans %}Actions{% endtrans %}</th>
<th>{% trans %}Comment{% endtrans %}</th> <th>{% trans %}Comment{% endtrans %}</th>
<th>{% trans %}Authorized IP{% endtrans %}</th> <th>{% trans %}Authorized IP{% endtrans %}</th>
<th>{% trans %}Created{% endtrans %}</th> <th>{% trans %}Created{% endtrans %}</th>
@ -31,8 +31,8 @@
</td> </td>
<td>{{ token.comment }}</td> <td>{{ token.comment }}</td>
<td>{{ token.ip or "any" }}</td> <td>{{ token.ip or "any" }}</td>
<td>{{ token.created_at | format_date }}</td> <td data-sort="{{ token.created_at or '0000-00-00' }}">{{ token.created_at | format_date }}</td>
<td>{{ token.updated_at | format_date }}</td> <td data-sort="{{ token.updated_at or '0000-00-00' }}">{{ token.updated_at | format_date }}</td>
</tr> </tr>
{%- endfor %} {%- endfor %}
</tbody> </tbody>

@ -16,8 +16,8 @@
{%- call macros.table() %} {%- call macros.table() %}
<thead> <thead>
<tr> <tr>
<th>{% trans %}Actions{% endtrans %}</th> <th data-orderable="false">{% trans %}Actions{% endtrans %}</th>
<th>{% trans %}User settings{% endtrans %}</th> <th data-orderable="false">{% trans %}User settings{% endtrans %}</th>
<th>{% trans %}Email{% endtrans %}</th> <th>{% trans %}Email{% endtrans %}</th>
<th>{% trans %}Features{% endtrans %}</th> <th>{% trans %}Features{% endtrans %}</th>
<th>{% trans %}Quota{% endtrans %}</th> <th>{% trans %}Quota{% endtrans %}</th>
@ -39,14 +39,14 @@
<a href="{{ url_for('.fetch_list', user_email=user.email) }}" title="{% trans %}Fetched accounts{% endtrans %}"><i class="fa fa-download"></i></a>&nbsp; <a href="{{ url_for('.fetch_list', user_email=user.email) }}" title="{% trans %}Fetched accounts{% endtrans %}"><i class="fa fa-download"></i></a>&nbsp;
</td> </td>
<td>{{ user }}</td> <td>{{ user }}</td>
<td> <td data-sort="{{ user.enable_imap*2 + user.enable_pop }}">
{% if user.enable_imap %}<span class="badge bg-info">imap</span>{% endif %} {% if user.enable_imap %}<span class="badge bg-info">imap</span>{% endif %}
{% if user.enable_pop %}<span class="badge bg-info">pop3</span>{% endif %} {% if user.enable_pop %}<span class="badge bg-info">pop3</span>{% endif %}
</td> </td>
<td>{{ user.quota_bytes_used | filesizeformat }} / {{ (user.quota_bytes | filesizeformat) if user.quota_bytes else '∞' }}</td> <td data-sort="{{ user.quota_bytes_used }}">{{ user.quota_bytes_used | filesizeformat }} / {{ (user.quota_bytes | filesizeformat) if user.quota_bytes else '∞' }}</td>
<td>{{ user.comment or '-' }}</td> <td>{{ user.comment or '-' }}</td>
<td>{{ user.created_at | format_date }}</td> <td data-sort="{{ user.created_at or '0000-00-00' }}">{{ user.created_at | format_date }}</td>
<td>{{ user.updated_at | format_date }}</td> <td data-sort="{{ user.updated_at or '0000-00-00' }}">{{ user.updated_at | format_date }}</td>
</tr> </tr>
{%- endfor %} {%- endfor %}
</tbody> </tbody>

@ -9,18 +9,22 @@
{%- endblock %} {%- endblock %}
{%- block content %} {%- block content %}
{%- call macros.table() %} {%- call macros.table(order='[[1,"asc"]]') %}
<tr> <thead>
<th>{% trans %}Domain{% endtrans %}</th> <tr>
<th>{% trans %}Available slots{% endtrans %}</th> <th>{% trans %}Domain{% endtrans %}</th>
<th>{% trans %}Quota{% endtrans %}</th> <th>{% trans %}Available slots{% endtrans %}</th>
</tr> <th>{% trans %}Quota{% endtrans %}</th>
</tr>
</thead>
<tbody>
{%- for domain_name, domain in available_domains.items() %} {%- for domain_name, domain in available_domains.items() %}
<tr> <tr>
<td><a href="{{ url_for('.user_signup', domain_name=domain_name) }}">{{ domain_name }}</a></td> <td><a href="{{ url_for('.user_signup', domain_name=domain_name) }}">{{ domain_name }}</a></td>
<td>{{ '∞' if domain.max_users == -1 else domain.max_users - (domain.users | count)}}</td> <td data-sort="{{ -1 if domain.max_users == -1 else domain.max_users - (domain.users | count)}}">{{ '∞' if domain.max_users == -1 else domain.max_users - (domain.users | count)}}</td>
<td>{{ domain.max_quota_bytes or config['DEFAULT_QUOTA'] | filesizeformat }}</td> <td data-sort="{{ domain.max_quota_bytes or config['DEFAULT_QUOTA'] }}">{{ domain.max_quota_bytes or config['DEFAULT_QUOTA'] | filesizeformat }}</td>
</tr> </tr>
{%- endfor %} {%- endfor %}
</tbody>
{%- endcall %} {%- endcall %}
{%- endblock %} {%- endblock %}

Loading…
Cancel
Save