2
0
Эх сурвалжийг харах

[BS5] Replace FooTable with jquery Datatables

FreddleSpl0it 3 жил өмнө
parent
commit
160dceff3e

+ 291 - 222
data/web/js/site/admin.js

@@ -63,13 +63,6 @@ jQuery(function($){
     draw_table = $(this).data('draw');
     eval(draw_table + '()');
   });
-  function table_admin_ready(ft, name) {
-    heading = ft.$el.parents('.card').find('.card-header')
-    var ft_paging = ft.use(FooTable.Paging)
-    $(heading).children('.table-lines').text(function(){
-      return ft_paging.totalRows;
-    })
-  }
   function draw_domain_admins() {
     $('#domainadminstable').DataTable({
       processing: true,
@@ -78,12 +71,23 @@ jQuery(function($){
       ajax: {
         type: "GET",
         url: "/api/v1/get/domain-admin/all",
-        dataSrc: function(json){
-          console.log(json);
-          return json;
+        dataSrc: function(data){
+          return process_table_data(data, 'domainadminstable');
         }
       },
       columns: [
+          {
+            // placeholder, so checkbox will not block child row toggle
+            title: '',
+            data: null,
+            searchable: false,
+            orderable: false,
+            defaultContent: ''
+          },
+          {
+            title: '',
+            data: 'chkbox'
+          },
           {
             title: lang.username,
             data: 'username',
@@ -113,74 +117,57 @@ jQuery(function($){
           },
           {
             title: lang.action,
-            data: null,
-            render: function (data, type) {
-              return `<div class="btn-group">
-                <a href="/edit/admin/admin" class="btn btn-xs btn-xs-half btn-secondary">
-                  <i class="bi bi-pencil-fill"></i> Bearbeiten
-                </a>
-                <a href="#" data-action="delete_selected" data-id="single-admin" data-api-url="delete/admin" data-item="admin" class="btn btn-xs btn-xs-half btn-danger">
-                  <i class="bi bi-trash"></i> Entfernen
-                </a>
-              </div>`;
-            }
+            data: 'action'
           },
       ]
     });
-
-    // ft_domainadmins = FooTable.init('#domainadminstable', {
-    //   "columns": [
-    //     {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
-    //     {"sorted": true,"name":"username","title":lang.username,"style":{"width":"250px"}},
-    //     {"name":"selected_domains","title":lang.admin_domains,"breakpoints":"xs sm"},
-    //     {"name":"tfa_active","title":"TFA", "filterable": false,"style":{"maxWidth":"80px","width":"80px"},"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
-    //     {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
-    //     {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
-    //   ],
-    //   "rows": $.ajax({
-    //     dataType: 'json',
-    //     url: '/api/v1/get/domain-admin/all',
-    //     jsonp: false,
-    //     error: function () {
-    //       console.log('Cannot draw domain admin table');
-    //     },
-    //     success: function (data) {
-    //       return process_table_data(data, 'domainadminstable');
-    //     }
-    //   }),
-    //   "empty": lang.empty,
-    //   "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
-    //   "state": {"enabled": true},
-    //   "filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table},
-    //   "sorting": {"enabled": true},
-    //   "toggleSelector": "table tbody span.footable-toggle"
-    // });
   }
   function draw_oauth2_clients() {
-    ft_oauth2clientstable = FooTable.init('#oauth2clientstable', {
-      "columns": [
-        {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
-        {"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
-        {"name":"client_id","type":"text","title":lang.oauth2_client_id,"style":{"width":"200px"}},
-        {"name":"client_secret","title":lang.oauth2_client_secret,"breakpoints":"xs sm md","style":{"width":"200px"}},
-        {"name":"redirect_uri","title":lang.oauth2_redirect_uri, "type": "text"},
-        {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
-      ],
-      "rows": $.ajax({
-        dataType: 'json',
-        url: '/api/v1/get/oauth2-client/all',
-        jsonp: false,
-        error: function () {
-          console.log('Cannot draw oauth2 clients table');
-        },
-        success: function (data) {
+    $('#oauth2clientstable').DataTable({
+      processing: true,
+      serverSide: false,
+      language: lang_datatables,
+      ajax: {
+        type: "GET",
+        url: "/api/v1/get/oauth2-client/all",
+        dataSrc: function(data){
           return process_table_data(data, 'oauth2clientstable');
         }
-      }),
-      "empty": lang.empty,
-      "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
-      "sorting": {"enabled": true},
-      "toggleSelector": "table tbody span.footable-toggle"
+      },
+      columns: [
+          {
+            // placeholder, so checkbox will not block child row toggle
+            title: '',
+            data: null,
+            searchable: false,
+            orderable: false,
+            defaultContent: ''
+          },
+          {
+            title: '',
+            data: 'chkbox'
+          },
+          {
+            title: 'ID',
+            data: 'id',
+          },
+          {
+            title: lang.oauth2_client_id,
+            data: 'client_id'
+          },
+          {
+            title: lang.oauth2_client_secret,
+            data: 'client_secret'
+          },
+          {
+            title: lang.oauth2_redirect_uri,
+            data: 'redirect_uri'
+          },
+          {
+            title: lang.action,
+            data: 'action'
+          },
+      ]
     });
   }
   function draw_admins() {
@@ -191,11 +178,23 @@ jQuery(function($){
       ajax: {
         type: "GET",
         url: "/api/v1/get/admin/all",
-        dataSrc: function(json){
-          return json;
+        dataSrc: function(data){
+          return process_table_data(data, 'adminstable');
         }
       },
       columns: [
+          {
+            // placeholder, so checkbox will not block child row toggle
+            title: '',
+            data: null,
+            searchable: false,
+            orderable: false,
+            defaultContent: ''
+          },
+          {
+            title: '',
+            data: 'chkbox'
+          },
           {
             title: lang.username,
             data: 'username',
@@ -218,169 +217,220 @@ jQuery(function($){
           },
           {
             title: lang.action,
-            data: null,
-            render: function (data, type) {
-              return `<div class="btn-group">
-                <a href="/edit/admin/admin" class="btn btn-xs btn-xs-half btn-secondary">
-                  <i class="bi bi-pencil-fill"></i> Bearbeiten
-                </a>
-                <a href="#" data-action="delete_selected" data-id="single-admin" data-api-url="delete/admin" data-item="admin" class="btn btn-xs btn-xs-half btn-danger">
-                  <i class="bi bi-trash"></i> Entfernen
-                </a>
-              </div>`;
-            }
+            data: 'action'
           },
       ]
     });
-
-    // ft_admins = FooTable.init('#adminstable', {
-    //   "columns": [
-    //     {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
-    //     {"sorted": true,"name":"usr","title":lang.username,"style":{"width":"250px"}},
-    //     {"name":"tfa_active","title":"TFA", "filterable": false,"style":{"maxWidth":"80px","width":"80px"},"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
-    //     {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
-    //     {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
-    //   ],
-    //   "rows": $.ajax({
-    //     dataType: 'json',
-    //     url: '/api/v1/get/admin/all',
-    //     jsonp: false,
-    //     error: function () {
-    //       console.log('Cannot draw admin table');
-    //     },
-    //     success: function (data) {
-    //       return process_table_data(data, 'adminstable');
-    //     }
-    //   }),
-    //   "empty": lang.empty,
-    //   "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
-    //   "filtering": {"enabled": false},
-    //   "state": {"enabled": true},
-    //   "sorting": {"enabled": true},
-    //   "toggleSelector": "table tbody span.footable-toggle"
-    // });
   }
   function draw_fwd_hosts() {
-    ft_forwardinghoststable = FooTable.init('#forwardinghoststable', {
-      "columns": [
-        {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
-        {"name":"host","type":"text","title":lang.host,"style":{"width":"250px"}},
-        {"name":"source","title":lang.source,"breakpoints":"xs sm"},
-        {"name":"keep_spam","title":lang.spamfilter, "type": "text","style":{"maxWidth":"80px","width":"80px"},"formatter": function(value){return 'yes'==value?'<i class="bi bi-x-lg"></i>':'no'==value&&'<i class="bi bi-check-lg"></i>';}},
-        {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
-      ],
-      "rows": $.ajax({
-        dataType: 'json',
-        url: '/api/v1/get/fwdhost/all',
-        jsonp: false,
-        error: function () {
-          console.log('Cannot draw forwarding hosts table');
-        },
-        success: function (data) {
+    $('#forwardinghoststable').DataTable({
+      processing: true,
+      serverSide: false,
+      language: lang_datatables,
+      ajax: {
+        type: "GET",
+        url: "/api/v1/get/fwdhost/all",
+        dataSrc: function(data){
           return process_table_data(data, 'forwardinghoststable');
         }
-      }),
-      "empty": lang.empty,
-      "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
-      "sorting": {"enabled": true},
-      "toggleSelector": "table tbody span.footable-toggle"
+      },
+      columns: [
+          {
+            // placeholder, so checkbox will not block child row toggle
+            title: '',
+            data: null,
+            searchable: false,
+            orderable: false,
+            defaultContent: ''
+          },
+          {
+            title: '',
+            data: 'chkbox'
+          },
+          {
+            title: lang.host,
+            data: 'host',
+          },
+          {
+            title: lang.source,
+            data: 'source'
+          },
+          {
+            title: lang.spamfilter,
+            data: 'keep_spam'
+          },
+          {
+            title: lang.action,
+            data: 'action'
+          },
+      ]
     });
   }
   function draw_relayhosts() {
-    ft_relayhoststable = FooTable.init('#relayhoststable', {
-      "columns": [
-        {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
-        {"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
-        {"name":"hostname","type":"text","title":lang.host,"style":{"width":"250px"}},
-        {"name":"username","title":lang.username,"breakpoints":"xs sm"},
-        {"name":"in_use_by","title":lang.in_use_by,"style":{"min-width":"200px","width":"200px"}, "type": "text","breakpoints":"xs sm"},
-        {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
-        {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
-      ],
-      "rows": $.ajax({
-        dataType: 'json',
-        url: '/api/v1/get/relayhost/all',
-        jsonp: false,
-        error: function () {
-          console.log('Cannot draw forwarding hosts table');
-        },
-        success: function (data) {
+    $('#relayhoststable').DataTable({
+      processing: true,
+      serverSide: false,
+      language: lang_datatables,
+      ajax: {
+        type: "GET",
+        url: "/api/v1/get/relayhost/all",
+        dataSrc: function(data){
           return process_table_data(data, 'relayhoststable');
         }
-      }),
-      "empty": lang.empty,
-      "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
-      "sorting": {"enabled": true},
-      "toggleSelector": "table tbody span.footable-toggle"
+      },
+      columns: [
+          {
+            // placeholder, so checkbox will not block child row toggle
+            title: '',
+            data: null,
+            searchable: false,
+            orderable: false,
+            defaultContent: ''
+          },
+          {
+            title: '',
+            data: 'chkbox'
+          },
+          {
+            title: 'ID',
+            data: 'id',
+          },
+          {
+            title: lang.host,
+            data: 'hostname'
+          },
+          {
+            title: lang.username,
+            data: 'username'
+          },
+          {
+            title: lang.in_use_by,
+            data: 'in_use_by'
+          },
+          {
+            title: lang.active,
+            data: 'active'
+          },
+          {
+            title: lang.action,
+            data: 'action'
+          },
+      ]
     });
   }
   function draw_transport_maps() {
-    ft_transportstable = FooTable.init('#transportstable', {
-      "columns": [
-        {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
-        {"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
-        {"name":"destination","type":"text","title":lang.destination,"style":{"min-width":"300px","width":"300px"}},
-        {"name":"nexthop","type":"text","title":lang.nexthop,"style":{"min-width":"200px","width":"200px"}},
-        {"name":"username","title":lang.username,"breakpoints":"xs sm"},
-        {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
-        {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
-      ],
-      "rows": $.ajax({
-        dataType: 'json',
-        url: '/api/v1/get/transport/all',
-        jsonp: false,
-        error: function () {
-          console.log('Cannot draw transports table');
-        },
-        success: function (data) {
+    $('#transportstable').DataTable({
+      processing: true,
+      serverSide: false,
+      language: lang_datatables,
+      ajax: {
+        type: "GET",
+        url: "/api/v1/get/transport/all",
+        dataSrc: function(data){
           return process_table_data(data, 'transportstable');
         }
-      }),
-      "empty": lang.empty,
-      "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
-      "sorting": {"enabled": true},
-      "toggleSelector": "table tbody span.footable-toggle",
-      "on": {
-        "ready.ft.table": function(e, ft){
-          $('.mx-info').tooltip();
-        }
-      }
+      },
+      columns: [
+          {
+            // placeholder, so checkbox will not block child row toggle
+            title: '',
+            data: null,
+            searchable: false,
+            orderable: false,
+            defaultContent: ''
+          },
+          {
+            title: '',
+            data: 'chkbox'
+          },
+          {
+            title: 'ID',
+            data: 'id',
+          },
+          {
+            title: lang.destination,
+            data: 'destination'
+          },
+          {
+            title: lang.nexthop,
+            data: 'nexthop'
+          },
+          {
+            title: lang.username,
+            data: 'username'
+          },
+          {
+            title: lang.active,
+            data: 'active'
+          },
+          {
+            title: lang.action,
+            data: 'action'
+          },
+      ]
     });
   }
   function draw_queue() {
-    ft_queuetable = FooTable.init('#queuetable', {
-      "columns": [
-        {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
-        {"name":"queue_id","type":"text","title":"QID","style":{"width":"50px"}},
-        {"name":"queue_name","type":"text","title":"Queue","style":{"width":"120px"}},
-        {"name":"arrival_time","sorted": true,"direction": "DESC","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.arrival_time,"style":{"width":"170px"}},
-        {"name":"message_size","style":{"whiteSpace":"nowrap"},"title":lang.message_size,"formatter": function(value){
-          return humanFileSize(value);
-        }},
-        {"name":"sender","title":lang.sender, "type": "text","breakpoints":"xs sm"},
-        {"name":"recipients","title":lang.recipients, "type": "text","style":{"word-break":"break-all","min-width":"300px"},"breakpoints":"xs sm md"},
-        {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"220px","width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
-      ],
-      "rows": $.ajax({
-        dataType: 'json',
-        url: '/api/v1/get/mailq/all',
-        jsonp: false,
-        error: function () {
-          console.log('Cannot draw forwarding hosts table');
-        },
-        success: function (data) {
+    $('#queuetable').DataTable({
+      processing: true,
+      serverSide: false,
+      language: lang_datatables,
+      ajax: {
+        type: "GET",
+        url: "/api/v1/get/mailq/all",
+        dataSrc: function(data){
           return process_table_data(data, 'queuetable');
         }
-      }),
-      "empty": lang.empty,
-      "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
-      "sorting": {"enabled": true},
-      "toggleSelector": "table tbody span.footable-toggle",
-      "on": {
-        "ready.ft.table": function(e, ft){
-          table_admin_ready(ft, 'queuetable');
-        }
-      }
+      },
+      columns: [
+          {
+            // placeholder, so checkbox will not block child row toggle
+            title: '',
+            data: null,
+            searchable: false,
+            orderable: false,
+            defaultContent: ''
+          },
+          {
+            title: '',
+            data: 'chkbox'
+          },
+          {
+            title: 'QID',
+            data: 'queue_id',
+          },
+          {
+            title: 'Queue',
+            data: 'queue_name'
+          },
+          {
+            title: lang.arrival_time,
+            data: 'arrival_time',
+            render: function (data, type){
+              var date = new Date(data ? data * 1000 : 0); 
+              return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
+            }
+          },
+          {
+            title: lang.message_size,
+            data: 'message_size',
+            render: function (data, type){
+              return humanFileSize(data);
+            }
+          },
+          {
+            title: lang.sender,
+            data: 'sender'
+          },
+          {
+            title: lang.recipients,
+            data: 'recipients'
+          },
+          {
+            title: lang.action,
+            data: 'action'
+          },
+      ]
     });
   }
 
@@ -467,14 +517,33 @@ jQuery(function($){
     }
     return data
   };
-  // // Initial table drawings
-  draw_domain_admins();
-  draw_admins();
-  // draw_fwd_hosts();
-  // draw_relayhosts();
-  // draw_oauth2_clients();
-  // draw_transport_maps();
-  // draw_queue();
+
+  // detect element visibility changes
+  function onVisible(element, callback) {
+    $(element).ready(function() {
+      element_object = document.querySelector(element)
+      new IntersectionObserver((entries, observer) => {
+        entries.forEach(entry => {
+          if(entry.intersectionRatio > 0) {
+            callback(element_object);
+            observer.disconnect();
+          }
+        });
+      }).observe(element_object);
+    });
+  }
+  // Draw Table if tab is active
+  onVisible("[id^=tab-config-admins]", () => {
+    draw_admins();
+    draw_domain_admins();
+  });
+  onVisible("[id^=tab-config-oauth2]", () => draw_oauth2_clients());
+  onVisible("[id^=tab-config-fwdhosts]", () => draw_fwd_hosts());
+  onVisible("[id^=tab-routing]", () => {
+    draw_relayhosts();
+    draw_transport_maps();
+  });
+  onVisible("[id^=tab-mailq]", () => draw_queue());
 
 
   $('body').on('click', 'span.footable-toggle', function () {

+ 73 - 73
data/web/js/site/quarantine.js

@@ -7,67 +7,20 @@ jQuery(function($){
   var entityMap={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};
   function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
   function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
-  // Set paging
-  $('[data-page-size]').on('click', function(e){
-    e.preventDefault();
-    var new_size = $(this).data('page-size');
-    var parent_ul = $(this).closest('ul');
-    var table_id = $(parent_ul).data('table-id');
-    FooTable.get('#' + table_id).pageSize(new_size);
-    //$(this).parent().addClass('active').siblings().removeClass('active')
-    heading = $(this).parents('.card').find('.card-header')
-    var n_results = $(heading).children('.table-lines').text().split(' / ')[1];
-    $(heading).children('.table-lines').text(function(){
-      if (new_size > n_results) {
-        new_size = n_results;
-      }
-      return new_size + ' / ' + n_results;
-    })
-  });
   $(".refresh_table").on('click', function(e) {
     e.preventDefault();
     var table_name = $(this).data('table');
-    $('#' + table_name).find("tr.footable-empty").remove();
-    draw_table = $(this).data('draw');
-    eval(draw_table + '()');
+    $('#' + table_name).DataTable().ajax.reload();
   });
-  function table_quarantine_ready(ft, name) {
-    $('.refresh_table').prop("disabled", false);
-    heading = ft.$el.parents('.card').find('.card-header')
-    var ft_paging = ft.use(FooTable.Paging)
-    $(heading).children('.table-lines').text(function(){
-      var total_rows = ft_paging.totalRows;
-      var size = ft_paging.size;
-      if (size > total_rows) {
-        size = total_rows;
-      }
-      return size + ' / ' + total_rows;
-    })
-  }
   function draw_quarantine_table() {
-    ft_quarantinetable = FooTable.init('#quarantinetable', {
-      "columns": [
-        {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
-        {"name":"id","type":"ID","filterable": false,"sorted": true,"direction":"DESC","title":"ID","style":{"width":"50px"}},
-        {"name":"qid","breakpoints":"all","type":"text","title":lang.qid,"style":{"width":"125px"}},
-        {"name":"sender","title":lang.sender},
-        {"name":"subject","title":lang.subj, "type": "text"},
-        {"name":"rspamdaction","title":lang.rspamd_result, "type": "html"},
-        {"name":"rcpt","title":lang.rcpt, "type": "text"},
-        {"name":"virus","title":lang.danger, "type": "text"},
-        {"name":"score","title": lang.spam_score, "type": "text"},
-        {"name":"notified","title":lang.notified, "type": "text"},
-        {"name":"created","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.received,"style":{"width":"170px"}},
-        {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right"},"style":{"min-width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
-      ],
-      "rows": $.ajax({
-        dataType: 'json',
-        url: '/api/v1/get/quarantine/all',
-        jsonp: false,
-        error: function () {
-          console.log('Cannot draw quarantine table');
-        },
-        success: function (data) {
+    $('#quarantinetable').DataTable({
+      processing: true,
+      serverSide: false,
+      language: lang_datatables,
+      ajax: {
+        type: "GET",
+        url: "/api/v1/get/quarantine/all",
+        dataSrc: function(data){
           $.each(data, function (i, item) {
             if (item.subject === null) {
               item.subject = '';
@@ -107,25 +60,72 @@ jQuery(function($){
             }
             item.chkbox = '<input type="checkbox" data-id="qitems" name="multi_select" value="' + item.id + '" />';
           });
-        }
-      }),
-      "empty": lang.empty,
-      "paging": {"enabled": true,"limit": 5,"size": pagination_size},
-      "state": {"enabled": true},
-      "sorting": {"enabled": true},
-      "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
-      "toggleSelector": "table tbody span.footable-toggle",
-      "on": {
-        "destroy.ft.table": function(e, ft){
-          $('.refresh_table').attr('disabled', 'true');
-        },
-        "ready.ft.table": function(e, ft){
-          table_quarantine_ready(ft, 'quarantinetable');
-        },
-        "after.ft.filtering": function(e, ft){
-          table_quarantine_ready(ft, 'quarantinetable');
+
+          return data;
         }
       },
+      columns: [
+          {
+            // placeholder, so checkbox will not block child row toggle
+            title: '',
+            data: null,
+            searchable: false,
+            orderable: false,
+            defaultContent: ''
+          },
+          {
+            title: '',
+            data: 'chkbox'
+          },
+          {
+            title: 'ID',
+            data: 'id',
+          },
+          {
+            title: lang.qid,
+            data: 'qid'
+          },
+          {
+            title: lang.sender,
+            data: 'sender'
+          },
+          {
+            title: lang.subj,
+            data: 'sender'
+          },
+          {
+            title: lang.rspamd_result,
+            data: 'rspamdaction'
+          },
+          {
+            title: lang.rcpt,
+            data: 'rcpt'
+          },
+          {
+            title: lang.danger,
+            data: 'virus'
+          },
+          {
+            title: lang.spam_score,
+            data: 'score'
+          },
+          {
+            title: lang.notified,
+            data: 'notified'
+          },
+          {
+            title: lang.received,
+            data: 'created',
+            render: function (data,type) {
+              var date = new Date(data ? data * 1000 : 0); 
+              return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
+            }
+          },
+          {
+            title: lang.action,
+            data: 'action'
+          },
+      ]
     });
   }
 

+ 1 - 0
data/web/quarantine.php

@@ -21,6 +21,7 @@ $template_data = [
   'role' => $role,
   'quarantine_settings' => $quarantine_settings,
   'lang_quarantine' => json_encode($lang['quarantine']),
+  'lang_datatables' => json_encode($lang['datatables']),
 ];
 
 require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';

+ 2 - 2
data/web/templates/admin/tab-config-admins.twig

@@ -1,8 +1,8 @@
 <div role="tabpanel" class="tab-pane fade show active" id="tab-config-admins" role="tabpanel" aria-labelledby="tab-config-admins">
     <div class="card mb-4">
       <div class="card-header bg-danger text-white">{{ lang.admin.admin_details }}</div>
-      <table id="adminstable" class="table table-striped dt-responsive nowrap w-100"></table>
       <div class="card-body">
+        <table id="adminstable" class="table table-striped dt-responsive nowrap w-100"></table>
         <div class="mass-actions-admin">
           <div class="btn-group">
             <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="admins" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
@@ -223,8 +223,8 @@
 
   <div class="card mb-4">
     <div class="card-header">{{ lang.admin.domain_admins }}</div>
-    <table id="domainadminstable" class="table table-striped dt-responsive nowrap w-100"></table>
     <div class="card-body">
+      <table id="domainadminstable" class="table table-striped dt-responsive nowrap w-100"></table>
       <div class="mass-actions-admin">
         <div class="btn-group">
           <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="domain_admins" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>

+ 1 - 3
data/web/templates/admin/tab-config-fwdhosts.twig

@@ -3,9 +3,7 @@
     <div class="card-header">{{ lang.admin.forwarding_hosts }}</div>
     <div class="card-body">
       <p style="margin-bottom:40px">{{ lang.admin.forwarding_hosts_hint }}</p>
-      <div class="table-responsive">
-        <table class="table table-striped table-condensed" id="forwardinghoststable"></table>
-      </div>
+      <table class="table table-striped table-condensed" id="forwardinghoststable"></table>
       <div class="mass-actions-admin">
         <div class="btn-group btn-group-sm">
           <button type="button" id="toggle_multi_select_all" data-id="fwdhosts" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary">{{ lang.mailbox.toggle_all }}</button>

+ 1 - 3
data/web/templates/admin/tab-config-oauth2.twig

@@ -3,9 +3,7 @@
     <div class="card-header">{{ lang.admin.oauth2_apps }}</div>
     <div class="card-body">
       <p>{{ lang.admin.oauth2_info|raw }}</p>
-      <div class="table-responsive">
-        <table class="table table-striped" id="oauth2clientstable"></table>
-      </div>
+      <table class="table table-striped" id="oauth2clientstable"></table>
       <div class="mass-actions-admin">
         <div class="btn-group">
           <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="oauth2_clients" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>

+ 1 - 3
data/web/templates/admin/tab-mailq.twig

@@ -7,9 +7,7 @@
       </div>
     </div>
     <div class="card-body">
-      <div class="table-responsive">
-        <table class="table table-striped table-condensed" id="queuetable"></table>
-      </div>
+      <table class="table table-striped table-condensed" id="queuetable"></table>
       <div class="mass-actions-admin">
         <div class="btn-group">
           <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="mailqitems" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>

+ 2 - 6
data/web/templates/admin/tab-routing.twig

@@ -3,9 +3,7 @@
     <div class="card-header">{{ lang.admin.relayhosts }}</div>
     <div class="card-body">
       <p style="margin-bottom:40px">{{ lang.admin.relayhosts_hint|raw }}</p>
-      <div class="table-responsive">
-        <table class="table table-striped table-condensed" id="relayhoststable"></table>
-      </div>
+      <table class="table table-striped table-condensed" id="relayhoststable"></table>
       <div class="mass-actions-admin">
         <div class="btn-group btn-group-sm">
           <button type="button" id="toggle_multi_select_all" data-id="rlyhosts" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary">{{ lang.mailbox.toggle_all }}</button>
@@ -46,9 +44,7 @@
     <div class="card-header">{{ lang.admin.transport_maps }}</div>
     <div class="card-body">
       <p style="margin-bottom:40px">{{ lang.admin.transports_hint|raw }}</p>
-      <div class="table-responsive">
-        <table class="table table-striped table-condensed" id="transportstable"></table>
-      </div>
+      <table class="table table-striped table-condensed" id="transportstable"></table>
       <div class="mass-actions-admin">
         <div class="btn-group btn-group-sm">
           <button type="button" id="toggle_multi_select_all" data-id="transports" class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary">{{ lang.mailbox.toggle_all }}</button>

+ 34 - 32
data/web/templates/mailbox/tab-bcc.twig

@@ -7,23 +7,25 @@
         <button class="btn btn-xs btn-secondary refresh_table" data-draw="draw_bcc_table" data-table="bcc_table">{{ lang.admin.refresh }}</button>
       </div>
     </div>
-    <p style="margin:10px" class="text-muted">{{ lang.mailbox.bcc_info|raw }}</p>
-{#    <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
-    <table id="bcc_table" class="table table-striped dt-responsive nowrap w-100"></table>
-    <div class="mass-actions-mailbox">
-      <div class="btn-group" data-acl="{{ acl.bcc_maps }}">
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="bcc" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
-        <ul class="dropdown-menu">
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"sender"}' href="#">{{ lang.mailbox.bcc_to_sender }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"rcpt"}' href="#">{{ lang.mailbox.bcc_to_rcpt }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="delete_selected" data-id="bcc" data-api-url='delete/bcc' href="#">{{ lang.mailbox.remove }}</a></li>
-        </ul>
-        <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addBCCModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_bcc_entry }}</a>
+    <div class="card-body">
+      <p class="text-muted">{{ lang.mailbox.bcc_info|raw }}</p>
+      {#<div class="mass-actions-mailbox" data-actions-header="true"></div>#}
+      <table id="bcc_table" class="table table-striped dt-responsive nowrap w-100"></table>
+      <div class="mass-actions-mailbox">
+        <div class="btn-group" data-acl="{{ acl.bcc_maps }}">
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="bcc" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
+          <ul class="dropdown-menu">
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"sender"}' href="#">{{ lang.mailbox.bcc_to_sender }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"rcpt"}' href="#">{{ lang.mailbox.bcc_to_rcpt }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="delete_selected" data-id="bcc" data-api-url='delete/bcc' href="#">{{ lang.mailbox.remove }}</a></li>
+          </ul>
+          <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addBCCModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_bcc_entry }}</a>
+        </div>
       </div>
     </div>
   </div>
@@ -35,22 +37,22 @@
         <button class="btn btn-xs btn-secondary refresh_table" data-draw="draw_recipient_map_table" data-table="recipient_map_table">{{ lang.admin.refresh }}</button>
       </div>
     </div>
-    <p style="margin:10px" class="text-muted">{{ lang.mailbox.recipient_map_info }}</p>
-  {#  <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
-    <div class="table-responsive">
+    <div class="card-body">
+      <p class="text-muted">{{ lang.mailbox.recipient_map_info }}</p>
+      {#<div class="mass-actions-mailbox" data-actions-header="true"></div>#}
       <table class="table table-striped" id="recipient_map_table"></table>
-    </div>
-    <div class="mass-actions-mailbox">
-      <div class="btn-group">
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="recipient_map" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
-        <ul class="dropdown-menu">
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="recipient_map" data-api-url='edit/recipient_map' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="recipient_map" data-api-url='edit/recipient_map' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="delete_selected" data-id="recipient_map" data-api-url='delete/recipient_map' href="#">{{ lang.mailbox.remove }}</a></li>
-        </ul>
-        <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addRecipientMapModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_recipient_map_entry }}</a>
+      <div class="mass-actions-mailbox">
+        <div class="btn-group">
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="recipient_map" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
+          <ul class="dropdown-menu">
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="recipient_map" data-api-url='edit/recipient_map' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="recipient_map" data-api-url='edit/recipient_map' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="delete_selected" data-id="recipient_map" data-api-url='delete/recipient_map' href="#">{{ lang.mailbox.remove }}</a></li>
+          </ul>
+          <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addRecipientMapModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_recipient_map_entry }}</a>
+        </div>
       </div>
     </div>
   </div>

+ 15 - 13
data/web/templates/mailbox/tab-domain-aliases.twig

@@ -7,19 +7,21 @@
         <button class="btn btn-xs btn-secondary refresh_table" data-draw="draw_aliasdomain_table" data-table="aliasdomain_table">{{ lang.admin.refresh }}</button>
       </div>
     </div>
-{#    <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
-    <table id="aliasdomain_table" class="table table-striped dt-responsive nowrap w-100"></table>
-    <div class="mass-actions-mailbox">
-      <div class="btn-group">
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="alias-domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
-        <ul class="dropdown-menu">
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="alias-domain" data-api-url='edit/alias-domain' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="alias-domain" data-api-url='edit/alias-domain' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="delete_selected" data-id="alias-domain" data-api-url='delete/alias-domain' href="#">{{ lang.mailbox.remove }}</a></li>
-        </ul>
-        <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-acl="{{ acl.alias_domains }}" data-bs-toggle="modal" data-bs-target="#addAliasDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain_alias }}</a>
+    <div class="card-body">
+      {#<div class="mass-actions-mailbox" data-actions-header="true"></div>#}
+      <table id="aliasdomain_table" class="table table-striped dt-responsive nowrap w-100"></table>
+      <div class="mass-actions-mailbox">
+        <div class="btn-group">
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="alias-domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
+          <ul class="dropdown-menu">
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="alias-domain" data-api-url='edit/alias-domain' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="alias-domain" data-api-url='edit/alias-domain' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="delete_selected" data-id="alias-domain" data-api-url='delete/alias-domain' href="#">{{ lang.mailbox.remove }}</a></li>
+          </ul>
+          <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-acl="{{ acl.alias_domains }}" data-bs-toggle="modal" data-bs-target="#addAliasDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain_alias }}</a>
+        </div>
       </div>
     </div>
   </div>

+ 17 - 15
data/web/templates/mailbox/tab-domains.twig

@@ -9,23 +9,25 @@
         <button class="btn btn-xs btn-secondary refresh_table" data-draw="draw_domain_table" data-table="domain_table">{{ lang.admin.refresh }}</button>
       </div>
     </div>
-{#    <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
-    <table id="domain_table" class="table table-striped dt-responsive nowrap w-100"></table>
-    <div class="mass-actions-mailbox">
-      <div class="btn-group">
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
-        <ul class="dropdown-menu">
+    <div class="card-body">
+      {#<div class="mass-actions-mailbox" data-actions-header="true"></div>#}
+      <table id="domain_table" class="table table-striped dt-responsive nowrap w-100"></table>
+      <div class="mass-actions-mailbox">
+        <div class="btn-group">
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
+          <ul class="dropdown-menu">
+            {% if mailcow_cc_role == 'admin' %}
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="domain" data-api-url='edit/domain' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="domain" data-api-url='edit/domain' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="delete_selected" data-id="domain" data-api-url='delete/domain' href="#">{{ lang.mailbox.remove }}</a></li>
+            {% endif %}
+          </ul>
           {% if mailcow_cc_role == 'admin' %}
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="domain" data-api-url='edit/domain' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="domain" data-api-url='edit/domain' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="delete_selected" data-id="domain" data-api-url='delete/domain' href="#">{{ lang.mailbox.remove }}</a></li>
+          <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain }}</a>
           {% endif %}
-        </ul>
-        {% if mailcow_cc_role == 'admin' %}
-        <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain }}</a>
-        {% endif %}
+        </div>
       </div>
     </div>
   </div>

+ 52 - 52
data/web/templates/mailbox/tab-filters.twig

@@ -9,64 +9,64 @@
     </div>
     <div class="card-body">
       <p class="text-muted">{{ lang.mailbox.sieve_info|raw }}</p><br>
-    </div>
-{#    <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
-    <table id="filter_table" class="table table-striped dt-responsive nowrap w-100"></table>
-    <div class="mass-actions-mailbox">
-      <div class="btn-group" data-acl="{{ acl.filters }}">
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="filter_item" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
-        <ul class="dropdown-menu">
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"filter_type":"prefilter"}' href="#">{{ lang.mailbox.set_prefilter }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"filter_type":"postfilter"}' href="#">{{ lang.mailbox.set_postfilter }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="delete_selected" data-text="{{ lang.user.eas_reset }}?" data-id="filter_item" data-api-url='delete/filter' href="#">{{ lang.mailbox.remove }}</a></li>
-        </ul>
-        <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addFilterModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_filter }}</a>
+      {#<div class="mass-actions-mailbox" data-actions-header="true"></div>#}
+      <table id="filter_table" class="table table-striped dt-responsive nowrap w-100"></table>
+      <div class="mass-actions-mailbox">
+        <div class="btn-group" data-acl="{{ acl.filters }}">
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="filter_item" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
+          <ul class="dropdown-menu">
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"filter_type":"prefilter"}' href="#">{{ lang.mailbox.set_prefilter }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"filter_type":"postfilter"}' href="#">{{ lang.mailbox.set_postfilter }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="delete_selected" data-text="{{ lang.user.eas_reset }}?" data-id="filter_item" data-api-url='delete/filter' href="#">{{ lang.mailbox.remove }}</a></li>
+          </ul>
+          <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addFilterModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_filter }}</a>
+        </div>
       </div>
-    </div>
-    <div class="card-body{% if mailcow_cc_role != 'admin' %} hidden{% endif %}">
-    <div class="row">
-      <div class="col-lg-6">
-        <h5>Global Prefilter</h5>
-        <form class="form-horizontal" data-cached-form="false" role="form" data-id="add_prefilter">
-          <div class="row">
-            <div class="col-sm-12">
-              <textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code script_data" rows="10" name="script_data" required>{{ global_filters.prefilter }}</textarea>
-            </div>
-          </div>
-          <div class="row">
-            <div class="col-sm-10 add_filter_btns">
-              <div class="btn-group">
-                <button class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary validate_sieve" href="#">{{ lang.add.validate }}</button>
-                <button class="btn btn-sm btn-xs-half d-block d-sm-inline btn-success add_sieve_script" data-action="add_item" data-id="add_prefilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"prefilter"}' href="#" disabled><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
+      <div class="{% if mailcow_cc_role != 'admin' %}hidden{% endif %}">
+        <div class="row">
+          <div class="col-lg-6">
+            <h5>Global Prefilter</h5>
+            <form class="form-horizontal" data-cached-form="false" role="form" data-id="add_prefilter">
+              <div class="row">
+                <div class="col-sm-12">
+                  <textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code script_data" rows="10" name="script_data" required>{{ global_filters.prefilter }}</textarea>
+                </div>
               </div>
-            </div>
-          </div>
-        </form>
-      </div>
-      <div class="col-lg-6">
-        <h5>Global Postfilter</h5>
-        <form class="form-horizontal" data-cached-form="false" role="form" data-id="add_postfilter">
-          <div class="row">
-            <div class="col-sm-12">
-              <textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code script_data" rows="10" name="script_data" required>{{ global_filters.postfilter }}</textarea>
-            </div>
+              <div class="row">
+                <div class="col-sm-10 add_filter_btns">
+                  <div class="btn-group">
+                    <button class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary validate_sieve" href="#">{{ lang.add.validate }}</button>
+                    <button class="btn btn-sm btn-xs-half d-block d-sm-inline btn-success add_sieve_script" data-action="add_item" data-id="add_prefilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"prefilter"}' href="#" disabled><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
+                  </div>
+                </div>
+              </div>
+            </form>
           </div>
-          <div class="row">
-            <div class="col-sm-10 add_filter_btns">
-              <div class="btn-group">
-                <button class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary validate_sieve" href="#">{{ lang.add.validate }}</button>
-                <button class="btn btn-sm btn-xs-half d-block d-sm-inline btn-success add_sieve_script" data-action="add_item" data-id="add_postfilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"postfilter"}' href="#" disabled><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
+          <div class="col-lg-6">
+            <h5>Global Postfilter</h5>
+            <form class="form-horizontal" data-cached-form="false" role="form" data-id="add_postfilter">
+              <div class="row">
+                <div class="col-sm-12">
+                  <textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code script_data" rows="10" name="script_data" required>{{ global_filters.postfilter }}</textarea>
+                </div>
               </div>
-            </div>
+              <div class="row">
+                <div class="col-sm-10 add_filter_btns">
+                  <div class="btn-group">
+                    <button class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary validate_sieve" href="#">{{ lang.add.validate }}</button>
+                    <button class="btn btn-sm btn-xs-half d-block d-sm-inline btn-success add_sieve_script" data-action="add_item" data-id="add_postfilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"postfilter"}' href="#" disabled><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
+                  </div>
+                </div>
+              </div>
+            </form>
           </div>
-        </form>
+        </div>
       </div>
     </div>
   </div>
-  </div>
 </div>

+ 76 - 74
data/web/templates/mailbox/tab-mailboxes.twig

@@ -7,66 +7,19 @@
         <button class="btn btn-xs btn-secondary refresh_table" data-draw="draw_mailbox_table" data-table="mailbox_table">{{ lang.admin.refresh }}</button>
       </div>
     </div>
-    <div class="mass-actions-mailbox d-none d-sm-flex" data-actions-header="true"></div>
-    <table id="mailbox_table" class="table table-striped dt-responsive nowrap w-100"></table>
-    <div class="mass-actions-mailbox">
-      <div class="btn-group d-block d-md-none">
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
-        <ul class="dropdown-menu">
-          <li class="dropdown-header">{{ lang.mailbox.mailbox }}</li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><a class="dropdown-item" data-action="delete_selected" data-id="mailbox" data-api-url='delete/mailbox' href="#">{{ lang.mailbox.remove }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li class="dropdown-header">{{ lang.mailbox.tls_enforce_in }}</li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_in":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_in":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li class="dropdown-header">{{ lang.mailbox.tls_enforce_out }}</li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_out":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_out":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li class="dropdown-header">{{ lang.mailbox.quarantine_notification }}</li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"hourly"}' href="#">{{ lang.user.hourly }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"daily"}' href="#">{{ lang.user.daily }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"weekly"}' href="#">{{ lang.user.weekly }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"never"}' href="#">{{ lang.user.never }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"reject"}' href="#">{{ lang.user.q_reject }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"add_header"}' href="#">{{ lang.user.q_add_header }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"all"}' href="#">{{ lang.user.q_all }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li class="dropdown-header">{{ lang.mailbox.allowed_protocols }}</li>
-          <li class="dropdown-header">IMAP</li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"imap_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"imap_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li class="dropdown-header">POP3</li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"pop3_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"pop3_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li class="dropdown-header">SMTP</li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-        </ul>
-        <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addMailboxModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_mailbox }}</a>
-      </div>
-      <div class="btn-group d-none d-md-flex">
-        <a class="btn btn-sm btn-secondary" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
-        <div class="btn-group">
-          <a class="btn btn-sm btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.mailbox }}</a>
+    <div class="card-body">
+      <div class="mass-actions-mailbox d-none d-sm-flex" data-actions-header="true"></div>
+      <table id="mailbox_table" class="table table-striped dt-responsive nowrap w-100"></table>
+      <div class="mass-actions-mailbox">
+        <div class="btn-group d-block d-md-none">
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
           <ul class="dropdown-menu">
+            <li class="dropdown-header">{{ lang.mailbox.mailbox }}</li>
             <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
-            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"2"}' href="#">{{ lang.mailbox.disable_login }}</a></li>
             <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-            <li><hr class="dropdown-divider"></li>
             <li><a class="dropdown-item" data-action="delete_selected" data-id="mailbox" data-api-url='delete/mailbox' href="#">{{ lang.mailbox.remove }}</a></li>
-          </ul>
-        </div>
-        <div class="btn-group">
-          <a class="btn btn-sm btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">TLS</a>
-          <ul class="dropdown-menu">
+            <li><hr class="dropdown-divider"></li>
             <li class="dropdown-header">{{ lang.mailbox.tls_enforce_in }}</li>
             <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_in":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
             <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_in":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
@@ -74,11 +27,18 @@
             <li class="dropdown-header">{{ lang.mailbox.tls_enforce_out }}</li>
             <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_out":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
             <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_out":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          </ul>
-        </div>
-        <div class="btn-group">
-          <a class="btn btn-sm btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.allowed_protocols }}</a>
-          <ul class="dropdown-menu">
+            <li><hr class="dropdown-divider"></li>
+            <li class="dropdown-header">{{ lang.mailbox.quarantine_notification }}</li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"hourly"}' href="#">{{ lang.user.hourly }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"daily"}' href="#">{{ lang.user.daily }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"weekly"}' href="#">{{ lang.user.weekly }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"never"}' href="#">{{ lang.user.never }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"reject"}' href="#">{{ lang.user.q_reject }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"add_header"}' href="#">{{ lang.user.q_add_header }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"all"}' href="#">{{ lang.user.q_all }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li class="dropdown-header">{{ lang.mailbox.allowed_protocols }}</li>
             <li class="dropdown-header">IMAP</li>
             <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"imap_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
             <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"imap_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
@@ -91,21 +51,63 @@
             <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
             <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
           </ul>
+          <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addMailboxModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_mailbox }}</a>
         </div>
-        <div class="btn-group">
-          <a class="btn btn-sm btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quarantine_notification }}</a>
-          <ul class="dropdown-menu">
-            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"hourly"}' href="#">{{ lang.user.hourly }}</a></li>
-            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"daily"}' href="#">{{ lang.user.daily }}</a></li>
-            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"weekly"}' href="#">{{ lang.user.weekly }}</a></li>
-            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"never"}' href="#">{{ lang.user.never }}</a></li>
-            <li><hr class="dropdown-divider"></li>
-            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"reject"}' href="#">{{ lang.user.q_reject }}</a></li>
-            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"add_header"}' href="#">{{ lang.user.q_add_header }}</a></li>
-            <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"all"}' href="#">{{ lang.user.q_all }}</a></li>
-          </ul>
+        <div class="btn-group d-none d-md-flex">
+          <a class="btn btn-sm btn-secondary" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
+          <div class="btn-group">
+            <a class="btn btn-sm btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.mailbox }}</a>
+            <ul class="dropdown-menu">
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"2"}' href="#">{{ lang.mailbox.disable_login }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+              <li><hr class="dropdown-divider"></li>
+              <li><a class="dropdown-item" data-action="delete_selected" data-id="mailbox" data-api-url='delete/mailbox' href="#">{{ lang.mailbox.remove }}</a></li>
+            </ul>
+          </div>
+          <div class="btn-group">
+            <a class="btn btn-sm btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">TLS</a>
+            <ul class="dropdown-menu">
+              <li class="dropdown-header">{{ lang.mailbox.tls_enforce_in }}</li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_in":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_in":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+              <li><hr class="dropdown-divider"></li>
+              <li class="dropdown-header">{{ lang.mailbox.tls_enforce_out }}</li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_out":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_out":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+            </ul>
+          </div>
+          <div class="btn-group">
+            <a class="btn btn-sm btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.allowed_protocols }}</a>
+            <ul class="dropdown-menu">
+              <li class="dropdown-header">IMAP</li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"imap_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"imap_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+              <li><hr class="dropdown-divider"></li>
+              <li class="dropdown-header">POP3</li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"pop3_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"pop3_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+              <li><hr class="dropdown-divider"></li>
+              <li class="dropdown-header">SMTP</li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+            </ul>
+          </div>
+          <div class="btn-group">
+            <a class="btn btn-sm btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quarantine_notification }}</a>
+            <ul class="dropdown-menu">
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"hourly"}' href="#">{{ lang.user.hourly }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"daily"}' href="#">{{ lang.user.daily }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"weekly"}' href="#">{{ lang.user.weekly }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"never"}' href="#">{{ lang.user.never }}</a></li>
+              <li><hr class="dropdown-divider"></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"reject"}' href="#">{{ lang.user.q_reject }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"add_header"}' href="#">{{ lang.user.q_add_header }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"all"}' href="#">{{ lang.user.q_all }}</a></li>
+            </ul>
+          </div>
+          <a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addMailboxModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_mailbox }}</a>
         </div>
-        <a class="btn btn-sm btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addMailboxModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_mailbox }}</a>
       </div>
     </div>
   </div>

+ 22 - 22
data/web/templates/mailbox/tab-mbox-aliases.twig

@@ -7,28 +7,28 @@
         <button class="btn btn-xs btn-secondary refresh_table" data-draw="draw_alias_table" data-table="alias_table">{{ lang.admin.refresh }}</button>
       </div>
     </div>
-    <div class="card-body text-muted">
-      {{ lang.mailbox.alias_domain_alias_hint|raw }}
-    </div>
-    <!-- <div class="mass-actions-mailbox" data-actions-header="true"></div> -->
-    <table id="alias_table" class="table table-striped dt-responsive nowrap w-100"></table>
-    <div class="mass-actions-mailbox">
-      <div class="btn-group">
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="alias" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
-        <ul class="dropdown-menu top33">
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="delete_selected" data-id="alias" data-api-url='delete/alias' href="#">{{ lang.mailbox.remove }}</a></li>
-          {% if not skip_sogo %}
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"sogo_visible":"1"}' href="#">{{ lang.mailbox.sogo_visible_y }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"sogo_visible":"0"}' href="#">{{ lang.mailbox.sogo_visible_n }}</a></li>
-          {% endif %}
-        </ul>
-        <a class="btn btn-sm d-block d-sm-inline btn-secondary" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"expand_alias":true}' ><i class="bi bi-arrows-angle-expand"></i> {{ lang.mailbox.add_alias_expand }}</a>
-        <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addAliasModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_alias }}</a>
+    <div class="card-body">
+      <p class="text-muted">{{ lang.mailbox.alias_domain_alias_hint|raw }}</p>
+      <!-- <div class="mass-actions-mailbox" data-actions-header="true"></div> -->
+      <table id="alias_table" class="table table-striped dt-responsive nowrap w-100"></table>
+      <div class="mass-actions-mailbox">
+        <div class="btn-group">
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="alias" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
+          <ul class="dropdown-menu top33">
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="delete_selected" data-id="alias" data-api-url='delete/alias' href="#">{{ lang.mailbox.remove }}</a></li>
+            {% if not skip_sogo %}
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"sogo_visible":"1"}' href="#">{{ lang.mailbox.sogo_visible_y }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"sogo_visible":"0"}' href="#">{{ lang.mailbox.sogo_visible_n }}</a></li>
+            {% endif %}
+          </ul>
+          <a class="btn btn-sm d-block d-sm-inline btn-secondary" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"expand_alias":true}' ><i class="bi bi-arrows-angle-expand"></i> {{ lang.mailbox.add_alias_expand }}</a>
+          <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addAliasModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_alias }}</a>
+        </div>
       </div>
     </div>
   </div>

+ 18 - 18
data/web/templates/mailbox/tab-resources.twig

@@ -7,24 +7,24 @@
         <button class="btn btn-xs btn-secondary refresh_table" data-draw="draw_resource_table" data-table="resource_table">{{ lang.admin.refresh }}</button>
       </div>
     </div>
-    <div class="card-body text-muted">
-      <p><span class="badge fs-5 bg-success">{{ lang.mailbox.booking_0_short }}</span> - {{ lang.mailbox.booking_null }}</p>
-      <p><span class="badge fs-5 bg-warning">{{ lang.mailbox.booking_lt0_short }}</span> - {{ lang.mailbox.booking_ltnull }}</p>
-      <p><span class="badge fs-5 bg-danger">{{ lang.mailbox.booking_custom_short }}</span> - {{ lang.mailbox.booking_custom }}</p>
-    </div>
-{#    <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
-    <table id="resource_table" class="table table-striped dt-responsive nowrap w-100"></table>
-    <div class="mass-actions-mailbox">
-      <div class="btn-group">
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="resource" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
-        <ul class="dropdown-menu">
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="resource" data-api-url='edit/resource' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="resource" data-api-url='edit/resource' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="delete_selected" data-id="resource" data-api-url='delete/resource' href="#">{{ lang.mailbox.remove }}</a></li>
-        </ul>
-        <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addResourceModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_resource }}</a>
+    <div class="card-body">
+      <p><span class="badge fs-5 bg-success text-muted">{{ lang.mailbox.booking_0_short }}</span> - {{ lang.mailbox.booking_null }}</p>
+      <p><span class="badge fs-5 bg-warning text-muted">{{ lang.mailbox.booking_lt0_short }}</span> - {{ lang.mailbox.booking_ltnull }}</p>
+      <p><span class="badge fs-5 bg-danger text-muted">{{ lang.mailbox.booking_custom_short }}</span> - {{ lang.mailbox.booking_custom }}</p>
+      {#<div class="mass-actions-mailbox" data-actions-header="true"></div>#}
+      <table id="resource_table" class="table table-striped dt-responsive nowrap w-100"></table>
+      <div class="mass-actions-mailbox">
+        <div class="btn-group">
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="resource" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
+          <ul class="dropdown-menu">
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="resource" data-api-url='edit/resource' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="resource" data-api-url='edit/resource' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="delete_selected" data-id="resource" data-api-url='delete/resource' href="#">{{ lang.mailbox.remove }}</a></li>
+          </ul>
+          <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addResourceModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_resource }}</a>
+        </div>
       </div>
     </div>
   </div>

+ 17 - 15
data/web/templates/mailbox/tab-syncjobs.twig

@@ -7,21 +7,23 @@
         <button class="btn btn-xs btn-secondary refresh_table" data-draw="draw_sync_job_table" data-table="sync_job_table">{{ lang.admin.refresh }}</button>
       </div>
     </div>
-    <!-- <div class="mass-actions-mailbox" data-actions-header="true"></div> -->
-    <table id="sync_job_table" class="table table-striped dt-responsive nowrap w-100"></table>
-    <div class="mass-actions-mailbox">
-      <div class="btn-group" data-acl="{{ acl.syncjobs }}">
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="syncjob" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
-        <ul class="dropdown-menu">
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"last_run":"","success":""}' href="#">{{ lang.mailbox.last_run_reset }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="delete_selected" data-id="syncjob" data-api-url='delete/syncjob' href="#">{{ lang.mailbox.remove }}</a></li>
-        </ul>
-        <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addSyncJobModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.user.create_syncjob }}</a>
+    <div class="card-body">
+      <!-- <div class="mass-actions-mailbox" data-actions-header="true"></div> -->
+      <table id="sync_job_table" class="table table-striped dt-responsive nowrap w-100"></table>
+      <div class="mass-actions-mailbox">
+        <div class="btn-group" data-acl="{{ acl.syncjobs }}">
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="syncjob" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
+          <ul class="dropdown-menu">
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"last_run":"","success":""}' href="#">{{ lang.mailbox.last_run_reset }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="delete_selected" data-id="syncjob" data-api-url='delete/syncjob' href="#">{{ lang.mailbox.remove }}</a></li>
+          </ul>
+          <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addSyncJobModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.user.create_syncjob }}</a>
+        </div>
       </div>
     </div>
   </div>

+ 16 - 14
data/web/templates/mailbox/tab-tls-policy.twig

@@ -7,20 +7,22 @@
         <button class="btn btn-xs btn-secondary refresh_table" data-draw="draw_tls_policy_table" data-table="tls_policy_table">{{ lang.admin.refresh }}</button>
       </div>
     </div>
-    <p style="margin:10px" class="text-muted">{{ lang.mailbox.tls_policy_maps_info|raw }}</p>
-{#    <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
-    <table id="tls_policy_table" class="table table-striped dt-responsive nowrap w-100"></table>
-    <div class="mass-actions-mailbox">
-      <div class="btn-group">
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="tls-policy-map" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
-        <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
-        <ul class="dropdown-menu">
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
-          <li><a class="dropdown-item" data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
-          <li><hr class="dropdown-divider"></li>
-          <li><a class="dropdown-item" data-action="delete_selected" data-id="tls-policy-map" data-api-url='delete/tls-policy-map' href="#">{{ lang.mailbox.remove }}</a></li>
-        </ul>
-        <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addTLSPolicyMapAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_tls_policy_map }}</a>
+    <div class="card-body">
+      <p class="text-muted">{{ lang.mailbox.tls_policy_maps_info|raw }}</p>
+      {#<div class="mass-actions-mailbox" data-actions-header="true"></div>#}
+      <table id="tls_policy_table" class="table table-striped dt-responsive nowrap w-100"></table>
+      <div class="mass-actions-mailbox">
+        <div class="btn-group">
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="tls-policy-map" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
+          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
+          <ul class="dropdown-menu">
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
+            <li><a class="dropdown-item" data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
+            <li><hr class="dropdown-divider"></li>
+            <li><a class="dropdown-item" data-action="delete_selected" data-id="tls-policy-map" data-api-url='delete/tls-policy-map' href="#">{{ lang.mailbox.remove }}</a></li>
+          </ul>
+          <a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addTLSPolicyMapAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_tls_policy_map }}</a>
+        </div>
       </div>
     </div>
   </div>

+ 23 - 31
data/web/templates/quarantine.twig

@@ -8,41 +8,32 @@
         {{ lang.quarantine.quarantine }} <span class="badge bg-info table-lines"></span>
         <div class="btn-group ms-auto">
           <button class="btn btn-xs btn-xs-lg btn-secondary refresh_table" data-draw="draw_quarantine_table" data-table="quarantinetable">{{ lang.quarantine.refresh }}</button>
-          <button type="button" class="btn btn-xs btn-xs-lg btn-secondary dropdown-toggle" data-bs-toggle="dropdown">{{ lang.quarantine.table_size }}</button>
-          <ul class="dropdown-menu" data-table-id="quarantinetable" role="menu">
-            <li><a class="dropdown-item" href="#" data-page-size="10">{{ lang.quarantine.table_size_show_n|format(10) }}</a></li>
-            <li><a class="dropdown-item" href="#" data-page-size="20">{{ lang.quarantine.table_size_show_n|format(20) }}</a></li>
-            <li><a class="dropdown-item" href="#" data-page-size="50">{{ lang.quarantine.table_size_show_n|format(50) }}</a></li>
-            <li><a class="dropdown-item" href="#" data-page-size="100">{{ lang.quarantine.table_size_show_n|format(100) }}</a></li>
-            <li><a class="dropdown-item" href="#" data-page-size="200">{{ lang.quarantine.table_size_show_n|format(200) }}</a></li>
-            <li><a class="dropdown-item" href="#" data-page-size="500">{{ lang.quarantine.table_size_show_n|format(500) }}</a></li>
-          </ul>
         </div>
       </div>
-      <p style="margin:10px" class="text-muted">{{ lang.quarantine.qinfo|raw }}</p>
-      <p style="margin:10px">
-        {% if not quarantine_settings.retention_size or not quarantine_settings.max_size %}
-        <div class="card-body"><div class="alert alert-info">{{ lang.quarantine.disabled_by_config }}</div></div>
-        {% else %}
-        <p style="margin:10px" class="text-muted">
-          {{ lang.quarantine.settings_info|format(quarantine_settings.retention_size, quarantine_settings.max_size)|raw }}
+      <div class="card-body">
+        <p class="text-muted">{{ lang.quarantine.qinfo|raw }}</p>
+        <p>
+          {% if not quarantine_settings.retention_size or not quarantine_settings.max_size %}
+          <div class="alert alert-info">{{ lang.quarantine.disabled_by_config }}</div>
+          {% else %}
+          <p style="margin:10px" class="text-muted">
+            {{ lang.quarantine.settings_info|format(quarantine_settings.retention_size, quarantine_settings.max_size)|raw }}
+          </p>
+          {% endif %}
         </p>
-        {% endif %}
-      </p>
-      <div class="table-responsive">
         <table id="quarantinetable" class="table table-striped"></table>
-      </div>
-      <div class="mass-actions-quarantine">
-        <div class="btn-group" data-acl="{{ acl.quarantine }}">
-          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="qitems" href="#"><i class="bi bi-check-all"></i> {{ lang.quarantine.toggle_all }}</a>
-          <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.quarantine.quick_actions }}</a>
-          <ul class="dropdown-menu">
-            <li><a class="dropdown-item" data-action="edit_selected" data-id="qitems" data-api-url='edit/qitem' data-api-attr='{"action":"release"}' href="#">{{ lang.quarantine.deliver_inbox }}</a></li>
-            <li><hr class="dropdown-divider"></li>
-            <li><a class="dropdown-item" data-action="edit_selected" data-id="qitems" data-api-url='edit/qitem' data-api-attr='{"action":"learnspam"}' href="#">{{ lang.quarantine.learn_spam_delete }}</a></li>
-            <li><hr class="dropdown-divider"></li>
-            <li><a class="dropdown-item" data-action="delete_selected" data-id="qitems" data-api-url='delete/qitem' href="#">{{ lang.quarantine.remove }}</a></li>
-          </ul>
+        <div class="mass-actions-quarantine">
+          <div class="btn-group" data-acl="{{ acl.quarantine }}">
+            <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="qitems" href="#"><i class="bi bi-check-all"></i> {{ lang.quarantine.toggle_all }}</a>
+            <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.quarantine.quick_actions }}</a>
+            <ul class="dropdown-menu">
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="qitems" data-api-url='edit/qitem' data-api-attr='{"action":"release"}' href="#">{{ lang.quarantine.deliver_inbox }}</a></li>
+              <li><hr class="dropdown-divider"></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="qitems" data-api-url='edit/qitem' data-api-attr='{"action":"learnspam"}' href="#">{{ lang.quarantine.learn_spam_delete }}</a></li>
+              <li><hr class="dropdown-divider"></li>
+              <li><a class="dropdown-item" data-action="delete_selected" data-id="qitems" data-api-url='delete/qitem' href="#">{{ lang.quarantine.remove }}</a></li>
+            </ul>
+          </div>
         </div>
       </div>
     </div>
@@ -54,6 +45,7 @@
 <script type='text/javascript'>
 var acl = '{{ acl_json|raw }}';
 var lang = {{ lang_quarantine|raw }};
+var lang_datatables = {{ lang_datatables|raw }};
 var csrf_token = '{{ csrf_token }}';
 var pagination_size = '{{ pagination_size }}';
 var role = '{{ role }}';