git subrepo commit mailcow/src/mailcow-dockerized
subrepo: subdir: "mailcow/src/mailcow-dockerized"
merged: "308860af"
upstream: origin: "https://github.com/mailcow/mailcow-dockerized.git"
branch: "master"
commit: "3f1a5af8"
git-subrepo: version: "0.4.5"
origin: "???"
commit: "???"
Change-Id: I5d51c14b45db54fe706be40a591ddbfcea50d4b0
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/site/user.js b/mailcow/src/mailcow-dockerized/data/web/js/site/user.js
index 8fd7b47..36bcfa6 100644
--- a/mailcow/src/mailcow-dockerized/data/web/js/site/user.js
+++ b/mailcow/src/mailcow-dockerized/data/web/js/site/user.js
@@ -101,7 +101,7 @@
$.each(data.sasl, function (i, item) {
var datetime = new Date(item.datetime.replace(/-/g, "/"));
var local_datetime = datetime.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
- var service = '<div class="label label-default">' + item.service.toUpperCase() + '</div>';
+ var service = '<div class="badge fs-6 bg-secondary">' + item.service.toUpperCase() + '</div>';
var app_password = item.app_password ? ' <a href="/edit/app-passwd/' + item.app_password + '"><i class="bi bi-app-indicator"></i> ' + escapeHtml(item.app_password_name || "App") + '</a>' : '';
var real_rip = item.real_rip.startsWith("Web") ? item.real_rip : '<a href="https://bgp.he.net/ip/' + item.real_rip + '" target="_blank">' + item.real_rip + "</a>";
var ip_location = item.location ? ' <span class="flag-icon flag-icon-' + item.location.toLowerCase() + '"></span>' : '';
@@ -128,26 +128,24 @@
}
function draw_tla_table() {
- ft_tla_table = FooTable.init('#tla_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"address","title":lang.alias},
- {"name":"validity","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.alias_valid_until,"style":{"width":"170px"}},
- {"sorted": true,"sortValue": function(value){res = new Date(value);return res.getTime();},"direction":"DESC","name":"created","formatter":function date_format(datetime) { var date = new Date(datetime.replace(/-/g, "/")); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.created_on,"style":{"width":"170px"}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"220px","width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/time_limited_aliases',
- jsonp: false,
- error: function () {
- console.log('Cannot draw tla table');
- },
- success: function (data) {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#tla_table') ) {
+ $('#tla_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#tla_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/time_limited_aliases",
+ dataSrc: function(data){
+ console.log(data);
$.each(data, function (i, item) {
if (acl_data.spam_alias === 1) {
- item.action = '<div class="btn-group footable-actions">' +
+ item.action = '<div class="btn-group">' +
'<a href="#" data-action="delete_selected" data-id="single-tla" data-api-url="delete/time_limited_alias" data-item="' + encodeURIComponent(item.address) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />';
@@ -158,49 +156,77 @@
item.action = '<span>-</span>';
}
});
+
+ return data;
}
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
},
- "state": {"enabled": true},
- "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',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: lang.alias,
+ data: 'address',
+ defaultContent: ''
+ },
+ {
+ title: lang.alias_valid_until,
+ data: 'validity',
+ defaultContent: '',
+ 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.created_on,
+ data: 'created',
+ defaultContent: '',
+ render: function (data, type) {
+ var date = new Date(data.replace(/-/g, "/"));
+ 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',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right',
+ defaultContent: ''
+ }
+ ]
});
}
function draw_sync_job_table() {
- ft_syncjob_table = FooTable.init('#sync_job_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
- {"name":"server_w_port","title":"Server","breakpoints":"xs sm md","style":{"word-break":"break-all"}},
- {"name":"enc1","title":lang.encryption,"breakpoints":"all"},
- {"name":"user1","title":lang.username},
- {"name":"exclude","title":lang.excludes,"breakpoints":"all"},
- {"name":"mins_interval","title":lang.interval + " (min)","breakpoints":"all"},
- {"name":"last_run","title":lang.last_run,"breakpoints":"xs sm md"},
- {"name":"exit_status","filterable": false,"title":lang.syncjob_last_run_result},
- {"name":"log","title":"Log"},
- {"name":"active","filterable": false,"style":{"maxWidth":"70px","width":"70px"},"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":"is_running","filterable": false,"style":{"maxWidth":"120px","width":"100px"},"title":lang.status},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"260px","width":"260px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#sync_job_table') ) {
+ $('#sync_job_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#sync_job_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
url: '/api/v1/get/syncjobs/' + encodeURIComponent(mailcow_cc_username) + '/no_log',
- jsonp: false,
- error: function () {
- console.log('Cannot draw sync job table');
- },
- success: function (data) {
+ dataSrc: function(data){
+ console.log(data);
$.each(data, function (i, item) {
item.user1 = escapeHtml(item.user1);
- item.log = '<a href="#syncjobLogModal" data-toggle="modal" data-syncjob-id="' + item.id + '">' + lang.open_logs + '</a>'
+ item.log = '<a href="#syncjobLogModal" data-bs-toggle="modal" data-syncjob-id="' + item.id + '">' + lang.open_logs + '</a>'
if (!item.exclude > 0) {
item.exclude = '-';
} else {
@@ -208,8 +234,8 @@
}
item.server_w_port = escapeHtml(item.user1 + '@' + item.host1 + ':' + item.port1);
if (acl_data.syncjobs === 1) {
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
@@ -219,9 +245,9 @@
item.chkbox = '<input type="checkbox" disabled />';
}
if (item.is_running == 1) {
- item.is_running = '<span id="active-script" class="label label-success">' + lang.running + '</span>';
+ item.is_running = '<span id="active-script" class="badge fs-6 bg-success">' + lang.running + '</span>';
} else {
- item.is_running = '<span id="inactive-script" class="label label-warning">' + lang.waiting + '</span>';
+ item.is_running = '<span id="inactive-script" class="badge fs-6 bg-warning">' + lang.waiting + '</span>';
}
if (!item.last_run > 0) {
item.last_run = lang.waiting;
@@ -239,39 +265,115 @@
}
item.exit_status = item.success + ' ' + item.exit_status;
});
+
+ return data;
}
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
},
- "state": {"enabled": true},
- "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: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 2
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ defaultContent: '',
+ responsivePriority: 3
+ },
+ {
+ title: 'Server',
+ data: 'server_w_port',
+ defaultContent: ''
+ },
+ {
+ title: lang.username,
+ data: 'user1',
+ defaultContent: '',
+ responsivePriority: 3
+ },
+ {
+ title: lang.last_run,
+ data: 'last_run',
+ defaultContent: ''
+ },
+ {
+ title: lang.syncjob_last_run_result,
+ data: 'exit_status',
+ defaultContent: ''
+ },
+ {
+ title: 'Log',
+ data: 'log',
+ defaultContent: ''
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'
+ }
+ },
+ {
+ title: lang.status,
+ data: 'is_running',
+ defaultContent: '',
+ responsivePriority: 5
+ },
+ {
+ title: lang.encryption,
+ data: 'enc1',
+ defaultContent: ''
+ },
+ {
+ title: lang.excludes,
+ data: 'exclude',
+ defaultContent: ''
+ },
+ {
+ title: lang.interval + " (min)",
+ data: 'mins_interval',
+ defaultContent: ''
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right',
+ defaultContent: '',
+ responsivePriority: 5
+ }
+ ]
});
}
function draw_app_passwd_table() {
- ft_apppasswd_table = FooTable.init('#app_passwd_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
- {"name":"name","title":lang.app_name},
- {"name":"protocols","title":lang.allowed_protocols},
- {"name":"active","filterable": false,"style":{"maxWidth":"70px","width":"70px"},"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":"220px","width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#app_passwd_table') ) {
+ $('#app_passwd_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#app_passwd_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
url: '/api/v1/get/app-passwd/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw app passwd table');
- },
- success: function (data) {
+ dataSrc: function(data){
+ console.log(data);
$.each(data, function (i, item) {
item.name = escapeHtml(item.name)
item.protocols = []
@@ -283,8 +385,8 @@
if (item.sieve_access == 1) { item.protocols.push("<code>Sieve</code>"); }
item.protocols = item.protocols.join(" ")
if (acl_data.app_passwds === 1) {
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/app-passwd/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/app-passwd/' + item.id + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-apppasswd" data-api-url="delete/app-passwd" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="apppasswd" name="multi_select" value="' + item.id + '" />';
@@ -294,37 +396,74 @@
item.chkbox = '<input type="checkbox" disabled />';
}
});
+
+ return data;
}
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
},
- "state": {"enabled": true},
- "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',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ defaultContent: ''
+ },
+ {
+ title: lang.app_name,
+ data: 'name',
+ defaultContent: ''
+ },
+ {
+ title: lang.allowed_protocols,
+ data: 'protocols',
+ defaultContent: ''
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right',
+ defaultContent: ''
+ }
+ ]
});
}
function draw_wl_policy_mailbox_table() {
- ft_wl_policy_mailbox_table = FooTable.init('#wl_policy_mailbox_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
- {"sorted": true,"name":"value","title":lang.spamfilter_table_rule},
- {"name":"object","title":"Scope"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#wl_policy_mailbox_table') ) {
+ $('#wl_policy_mailbox_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#wl_policy_mailbox_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
url: '/api/v1/get/policy_wl_mailbox',
- jsonp: false,
- error: function () {
- console.log('Cannot draw mailbox policy wl table');
- },
- success: function (data) {
+ dataSrc: function(data){
+ console.log(data);
$.each(data, function (i, item) {
if (validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_wl_mailbox" name="multi_select" value="' + item.prefid + '" />';
@@ -336,36 +475,60 @@
item.chkbox = '<input type="checkbox" disabled />';
}
});
+
+ return data;
}
- }),
- "state": {"enabled": true},
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
},
- "sorting": {
- "enabled": true
- }
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: 'ID',
+ data: 'prefid',
+ defaultContent: ''
+ },
+ {
+ title: lang.spamfilter_table_rule,
+ data: 'value',
+ defaultContent: ''
+ },
+ {
+ title:'Scope',
+ data: 'object',
+ defaultContent: ''
+ }
+ ]
});
}
function draw_bl_policy_mailbox_table() {
- ft_bl_policy_mailbox_table = FooTable.init('#bl_policy_mailbox_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
- {"sorted": true,"name":"value","title":lang.spamfilter_table_rule},
- {"name":"object","title":"Scope"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#bl_policy_mailbox_table') ) {
+ $('#bl_policy_mailbox_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#bl_policy_mailbox_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
url: '/api/v1/get/policy_bl_mailbox',
- jsonp: false,
- error: function () {
- console.log('Cannot draw mailbox policy bl table');
- },
- success: function (data) {
+ dataSrc: function(data){
+ console.log(data);
$.each(data, function (i, item) {
if (validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_bl_mailbox" name="multi_select" value="' + item.prefid + '" />';
@@ -377,31 +540,45 @@
item.chkbox = '<input type="checkbox" disabled />';
}
});
+
+ return data;
}
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
},
- "state": {"enabled": true},
- "sorting": {
- "enabled": true
- }
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: 'ID',
+ data: 'prefid',
+ defaultContent: ''
+ },
+ {
+ title: lang.spamfilter_table_rule,
+ data: 'value',
+ defaultContent: ''
+ },
+ {
+ title:'Scope',
+ data: 'object',
+ defaultContent: ''
+ }
+ ]
});
}
- $('body').on('click', 'span.footable-toggle', function () {
- event.stopPropagation();
- })
-
- draw_sync_job_table();
- draw_app_passwd_table();
- draw_tla_table();
- draw_wl_policy_mailbox_table();
- draw_bl_policy_mailbox_table();
- last_logins('get');
-
// FIDO2 friendly name modal
$('#fido2ChangeFn').on('show.bs.modal', function (e) {
rename_link = $(e.relatedTarget)
@@ -433,4 +610,28 @@
$('#userFilterModal').on('hidden.bs.modal', function () {
$('#user_sieve_filter').text(lang.loading);
});
+
+ // detect element visibility changes
+ function onVisible(element, callback) {
+ $(document).ready(function() {
+ element_object = document.querySelector(element);
+ if (element_object === null) return;
+
+ new IntersectionObserver((entries, observer) => {
+ entries.forEach(entry => {
+ if(entry.intersectionRatio > 0) {
+ callback(element_object);
+ }
+ });
+ }).observe(element_object);
+ });
+ }
+
+ // Load only if the tab is visible
+ onVisible("[id^=tla_table]", () => draw_tla_table());
+ onVisible("[id^=bl_policy_mailbox_table]", () => draw_bl_policy_mailbox_table());
+ onVisible("[id^=wl_policy_mailbox_table]", () => draw_wl_policy_mailbox_table());
+ onVisible("[id^=sync_job_table]", () => draw_sync_job_table());
+ onVisible("[id^=app_passwd_table]", () => draw_app_passwd_table());
+ last_logins('get');
});