Compare commits

..

20 Commits

Author SHA1 Message Date
Niklas Meyer
3f1a5af88b Merge pull request #4927 from mailcow/staging
2022-12b
2022-12-27 13:02:44 +01:00
Niklas Meyer
850fd85d4d Merge pull request #4925 from tomudding/fix/datatables-crashing-with-non-english-locale
[WEB] Update DataTables to v1.13.1 and fix crash for non-English locales
2022-12-27 13:01:17 +01:00
milkmaker
24acd42589 Translations update from Weblate (#4926)
* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.fr-fr.json

[Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: Clément Hampaï <clement.hampai@cypressxt.net>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Language file updated by 'Cleanup translation files' addon

Co-authored-by: milkmaker <milkmaker@mailcow.de>

Co-authored-by: Clément Hampaï <clement.hampai@cypressxt.net>
2022-12-26 20:06:49 +01:00
Tom Udding
eaa0dea63b [WEB] Update DataTables to v1.13.1 and fix crash for non-English locales
This newer version of DataTables includes a fix for improper access
to localisation information from `Intl.NumberFormat`. This improper access
lead to datatables not being created.
2022-12-26 17:35:49 +01:00
DerLinkman
dd50bbca9b Merge branch 'staging' 2022-12-26 16:01:31 +01:00
DerLinkman
f3f5471ef7 [Web] Removed double Sender Entry in RSPAMD Logs 2022-12-26 15:56:23 +01:00
Niklas Meyer
516c8ea66c Merge pull request #4923 from mailcow/staging
2022-12a
2022-12-26 14:35:37 +01:00
DerLinkman
48310034e5 [Compose Updater] Corrected syntax errors 2022-12-26 14:33:15 +01:00
Niklas Meyer
be35a88f8c Merge pull request #4916 from tomy0000000/patch-1
[web] 🛠 fix: Locale decision algorithm
2022-12-26 14:15:43 +01:00
Niklas Meyer
e67b512499 Merge pull request #4914 from tomudding/fix/datatables-not-ordering-datetimes-correctly
Fix sorting dates and missing Rspamd attributes in datatables
2022-12-26 14:07:14 +01:00
FreddleSpl0it
0cf59159cd [Web] fix SAL display 2022-12-26 12:03:51 +01:00
FreddleSpl0it
e7a929a947 [Web] add missing </code> tag in edit/mailbox.twig 2022-12-26 11:35:18 +01:00
DerLinkman
dabf4d4383 [UI] Show Restart SOGo only when permission = admin 2022-12-25 14:44:00 +01:00
Tomy Hsieh
13bdd4ad0b 🛠 fix: Locale decision algorithm 2022-12-25 16:56:43 +08:00
DerLinkman
3281b97ea9 [UI] Removed solr informations if container is disabled 2022-12-24 23:25:52 +01:00
DerLinkman
8070db96e9 [UI] Fixed Wrong Table content in Qurantine (sender instead of subject) 2022-12-24 22:25:42 +01:00
Tom Udding
82c80a9682 Make default ordering of Rspamd table consistent 2022-12-24 18:29:46 +01:00
Tom Udding
136cc2e3ff Fix missing score and scan time Rspamd logs 2022-12-24 18:18:28 +01:00
Tom Udding
eefce62f01 Fix incorrect datetime for Rspamd logs 2022-12-24 18:10:57 +01:00
Tom Udding
240b2c63f6 Fix timestamps not sorting in datatables
Timestamps retrieved from the API were always converted to a browser
local format. The format specified for moment.js added in
5160eff294 did not work because of this.

Additionally, the format specified used `dd` which looks for two letter
days, such as "Mo", "Tu", "We", etc. Furthermore, `mm` is used for
minutes, not months.

Because the locale formatted datetime can vary a lot, it is not easy to
get this into moment.js to enable the sorting of datetimes in the
datatables. In other words, there is no conversion from an
`Intl.DateTimeFormat` specifier string to moment.js. Adding many
`$.fn.dataTable.moment(format);` with different `format`s is not useful.

I have fixed this rewriting how the timestamps from the API are added
to the tables. It still uses the locale of the browser, because not
everyone wants to use ISO 8601, but no longer requires moment.js (which
has been removed).

Two data attributes are added to the `td`s of the timestamps:
- `data-order`
- `data-sort`

The values of these are the timestamps as returned by the server, which
are very easily sorted (as they are just UNIX timestamps). Then, when
creating the cell in the table, it will be converted to what the locale
of the browser specified (this has not changed).
2022-12-24 17:35:31 +01:00
43 changed files with 2195 additions and 2193 deletions

View File

@@ -10,9 +10,6 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/header.inc.php';
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
$tfa_data = get_tfa();
$fido2_data = fido2(array("action" => "get_friendly_names"));
if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CACHE')) {
$_SESSION['gal'] = json_decode($license_cache, true);
}
$js_minifier->add('/web/js/site/admin.js');
$js_minifier->add('/web/js/presets/rspamd.js');
@@ -89,7 +86,6 @@ $template_data = [
'tfa_id' => @$_SESSION['tfa_id'],
'fido2_cid' => @$_SESSION['fido2_cid'],
'fido2_data' => $fido2_data,
'gal' => @$_SESSION['gal'],
'api' => [
'ro' => admin_api('ro', 'get'),
'rw' => admin_api('rw', 'get'),

View File

@@ -4,10 +4,10 @@
*
* To rebuild or modify this file with the latest versions of the included
* software please visit:
* https://datatables.net/download/#bs5/dt-1.12.0/r-2.3.0/sl-1.4.0
* https://datatables.net/download/#bs5/dt-1.13.1/r-2.4.0/sl-1.5.0
*
* Included libraries:
* DataTables 1.12.0, Responsive 2.3.0, Select 1.4.0
* DataTables 1.13.1, Responsive 2.4.0, Select 1.5.0
*/
@charset "UTF-8";
@@ -63,7 +63,7 @@ table.dataTable thead > tr > td.sorting_desc_disabled:after {
opacity: 0.125;
right: 10px;
line-height: 9px;
font-size: 0.9em;
font-size: 0.8em;
}
table.dataTable thead > tr > th.sorting:before, table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_desc:before, table.dataTable thead > tr > th.sorting_asc_disabled:before, table.dataTable thead > tr > th.sorting_desc_disabled:before,
table.dataTable thead > tr > td.sorting:before,
@@ -72,7 +72,7 @@ table.dataTable thead > tr > td.sorting_desc:before,
table.dataTable thead > tr > td.sorting_asc_disabled:before,
table.dataTable thead > tr > td.sorting_desc_disabled:before {
bottom: 50%;
content: "";
content: "";
}
table.dataTable thead > tr > th.sorting:after, table.dataTable thead > tr > th.sorting_asc:after, table.dataTable thead > tr > th.sorting_desc:after, table.dataTable thead > tr > th.sorting_asc_disabled:after, table.dataTable thead > tr > th.sorting_desc_disabled:after,
table.dataTable thead > tr > td.sorting:after,
@@ -81,7 +81,7 @@ table.dataTable thead > tr > td.sorting_desc:after,
table.dataTable thead > tr > td.sorting_asc_disabled:after,
table.dataTable thead > tr > td.sorting_desc_disabled:after {
top: 50%;
content: "";
content: "";
}
table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_desc:after,
table.dataTable thead > tr > td.sorting_asc:before,
@@ -287,6 +287,9 @@ table.dataTable > tbody > tr.selected > * {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.9);
color: white;
}
table.dataTable > tbody > tr.selected a {
color: #090a0b;
}
table.dataTable.table-striped > tbody > tr.odd > * {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.05);
}
@@ -335,6 +338,9 @@ div.dataTables_wrapper div.dataTables_paginate ul.pagination {
white-space: nowrap;
justify-content: flex-end;
}
div.dataTables_wrapper div.dt-row {
position: relative;
}
div.dataTables_scrollHead table.dataTable {
margin-bottom: 0 !important;
@@ -380,17 +386,6 @@ div.dataTables_wrapper div.dataTables_paginate {
table.dataTable.table-sm > thead > tr > th:not(.sorting_disabled) {
padding-right: 20px;
}
table.dataTable.table-sm .sorting:before,
table.dataTable.table-sm .sorting_asc:before,
table.dataTable.table-sm .sorting_desc:before {
top: 5px;
right: 0.85em;
}
table.dataTable.table-sm .sorting:after,
table.dataTable.table-sm .sorting_asc:after,
table.dataTable.table-sm .sorting_desc:after {
top: 5px;
}
table.table-bordered.dataTable {
border-right-width: 0;
@@ -629,13 +624,13 @@ table.dataTable > tbody > tr > .selected {
background-color: rgba(13, 110, 253, 0.9);
color: white;
}
table.dataTable tbody td.select-checkbox,
table.dataTable tbody th.select-checkbox {
table.dataTable > tbody > tr > td.select-checkbox,
table.dataTable > tbody > tr > th.select-checkbox {
position: relative;
}
table.dataTable tbody td.select-checkbox:before, table.dataTable tbody td.select-checkbox:after,
table.dataTable tbody th.select-checkbox:before,
table.dataTable tbody th.select-checkbox:after {
table.dataTable > tbody > tr > td.select-checkbox:before, table.dataTable > tbody > tr > td.select-checkbox:after,
table.dataTable > tbody > tr > th.select-checkbox:before,
table.dataTable > tbody > tr > th.select-checkbox:after {
display: block;
position: absolute;
top: 1.2em;
@@ -644,20 +639,20 @@ table.dataTable tbody th.select-checkbox:after {
height: 12px;
box-sizing: border-box;
}
table.dataTable tbody td.select-checkbox:before,
table.dataTable tbody th.select-checkbox:before {
table.dataTable > tbody > tr > td.select-checkbox:before,
table.dataTable > tbody > tr > th.select-checkbox:before {
content: " ";
margin-top: -5px;
margin-left: -6px;
border: 1px solid black;
border-radius: 3px;
}
table.dataTable tr.selected td.select-checkbox:before,
table.dataTable tr.selected th.select-checkbox:before {
table.dataTable > tbody > tr.selected > td.select-checkbox:before,
table.dataTable > tbody > tr.selected > th.select-checkbox:before {
border: 1px solid white;
}
table.dataTable tr.selected td.select-checkbox:after,
table.dataTable tr.selected th.select-checkbox:after {
table.dataTable > tbody > tr.selected > td.select-checkbox:after,
table.dataTable > tbody > tr.selected > th.select-checkbox:after {
content: "✓";
font-size: 20px;
margin-top: -19px;
@@ -665,12 +660,12 @@ table.dataTable tr.selected th.select-checkbox:after {
text-align: center;
text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;
}
table.dataTable.compact tbody td.select-checkbox:before,
table.dataTable.compact tbody th.select-checkbox:before {
table.dataTable.compact > tbody > tr > td.select-checkbox:before,
table.dataTable.compact > tbody > tr > th.select-checkbox:before {
margin-top: -12px;
}
table.dataTable.compact tr.selected td.select-checkbox:after,
table.dataTable.compact tr.selected th.select-checkbox:after {
table.dataTable.compact > tbody > tr.selected > td.select-checkbox:after,
table.dataTable.compact > tbody > tr.selected > th.select-checkbox:after {
margin-top: -16px;
}
@@ -690,4 +685,3 @@ table.dataTable.table-sm tbody td.select-checkbox::before {
margin-top: -9px;
}

View File

@@ -11,6 +11,11 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
$solr_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_SOLR"])) ? false : solr_status();
$clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ? false : true;
if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CACHE')) {
$_SESSION['gal'] = json_decode($license_cache, true);
}
$js_minifier->add('/web/js/site/debug.js');
// vmail df
@@ -54,6 +59,7 @@ $template_data = [
'vmail_df' => $vmail_df,
'hostname' => $hostname,
'timezone' => $timezone,
'gal' => @$_SESSION['gal'],
'license_guid' => license('guid'),
'solr_status' => $solr_status,
'solr_uptime' => round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60),

View File

@@ -234,7 +234,7 @@ if (!isset($_SESSION['mailcow_locale']) && !isset($_COOKIE['mailcow_locale'])) {
// Try suggest match
// e.g. suggest en-gb when only en-us is provided
if (!isset($_COOKIE['mailcow_locale'])) {
if (!isset($_SESSION['mailcow_locale'])) {
foreach ($lang2pref as $lang => $q) {
if (array_key_exists(substr($lang, 0, 2), $AVAILABLE_BASE_LANGUAGES)) {
$_SESSION['mailcow_locale'] = $AVAILABLE_BASE_LANGUAGES[substr($lang, 0, 2)];

View File

@@ -4,20 +4,20 @@
*
* To rebuild or modify this file with the latest versions of the included
* software please visit:
* https://datatables.net/download/#bs5/dt-1.12.0/r-2.3.0/sl-1.4.0
* https://datatables.net/download/#bs5/dt-1.13.1/r-2.4.0/sl-1.5.0
*
* Included libraries:
* DataTables 1.12.0, Responsive 2.3.0, Select 1.4.0
* DataTables 1.13.1, Responsive 2.4.0, Select 1.5.0
*/
/*! DataTables 1.12.0
/*! DataTables 1.13.1
* ©2008-2022 SpryMedia Ltd - datatables.net/license
*/
/**
* @summary DataTables
* @description Paginate, search and order HTML tables
* @version 1.12.0
* @version 1.13.1
* @author SpryMedia Ltd
* @contact www.datatables.net
* @copyright SpryMedia Ltd.
@@ -1162,6 +1162,10 @@
$( rowOne[0] ).children('th, td').each( function (i, cell) {
var col = oSettings.aoColumns[i];
if (! col) {
_fnLog( oSettings, 0, 'Incorrect column count', 18 );
}
if ( col.mData === i ) {
var sort = a( cell, 'sort' ) || a( cell, 'order' );
var filter = a( cell, 'filter' ) || a( cell, 'search' );
@@ -3166,6 +3170,11 @@
create = nTrIn ? false : true;
nTd = create ? document.createElement( oCol.sCellType ) : anTds[i];
if (! nTd) {
_fnLog( oSettings, 0, 'Incorrect column count', 18 );
}
nTd._DT_CellIndex = {
row: iRow,
column: i
@@ -3316,12 +3325,18 @@
for ( i=0, ien=cells.length ; i<ien ; i++ ) {
column = columns[i];
if (column) {
column.nTf = cells[i].cell;
if ( column.sClass ) {
$(column.nTf).addClass( column.sClass );
}
}
else {
_fnLog( oSettings, 0, 'Incorrect column count', 18 );
}
}
}
}
@@ -5079,6 +5094,10 @@
_fnDraw( settings );
}
}
else {
// No change event - paging was called, but no change
_fnCallbackFire( settings, null, 'page-nc', [settings] );
}
return changed;
}
@@ -5348,6 +5367,7 @@
footerCopy = footer.clone().prependTo( table );
footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
footerSrcEls = footerCopy.find('tr');
footerCopy.find('[id]').removeAttr('id');
}
// Clone the current header and footer elements and then place it into the inner table
@@ -5355,6 +5375,7 @@
headerTrgEls = header.find('tr'); // original header is in its own table
headerSrcEls = headerCopy.find('tr');
headerCopy.find('th, td').removeAttr('tabindex');
headerCopy.find('[id]').removeAttr('id');
/*
@@ -8333,7 +8354,11 @@
$(document).on('plugin-init.dt', function (e, context) {
var api = new _Api( context );
api.on( 'stateSaveParams', function ( e, settings, d ) {
const namespace = 'on-plugin-init';
const stateSaveParamsEvent = `stateSaveParams.${namespace}`;
const destroyEvent = `destroy.${namespace}`;
api.on( stateSaveParamsEvent, function ( e, settings, d ) {
// This could be more compact with the API, but it is a lot faster as a simple
// internal loop
var idFn = settings.rowIdFn;
@@ -8347,7 +8372,11 @@
}
d.childRows = ids;
})
});
api.on( destroyEvent, function () {
api.off(`${stateSaveParamsEvent} ${destroyEvent}`);
});
var loaded = api.state.loaded();
@@ -9668,7 +9697,7 @@
* @type string
* @default Version number
*/
DataTable.version = "1.12.0";
DataTable.version = "1.13.1";
/**
* Private data store, containing all of the settings objects that are
@@ -14092,7 +14121,7 @@
*
* @type string
*/
build:"bs5/dt-1.12.0/r-2.3.0/sl-1.4.0",
build:"bs5/dt-1.13.1/r-2.4.0/sl-1.5.0",
/**
@@ -14730,7 +14759,7 @@
var classes = settings.oClasses;
var lang = settings.oLanguage.oPaginate;
var aria = settings.oLanguage.oAria.paginate || {};
var btnDisplay, btnClass, counter=0;
var btnDisplay, btnClass;
var attach = function( container, buttons ) {
var i, ien, node, button, tabIndex;
@@ -14805,7 +14834,7 @@
'class': classes.sPageButton+' '+btnClass,
'aria-controls': settings.sTableId,
'aria-label': aria[ button ],
'data-dt-idx': counter,
'data-dt-idx': button,
'tabindex': tabIndex,
'id': idx === 0 && typeof button === 'string' ?
settings.sTableId +'_'+ button :
@@ -14817,8 +14846,6 @@
_fnBindAction(
node, {action: button}, clickHandler
);
counter++;
}
}
}
@@ -15163,7 +15190,7 @@
}
}
else if (window.luxon) {
dt = format
dt = format && typeof d === 'string'
? window.luxon.DateTime.fromFormat( d, format )
: window.luxon.DateTime.fromISO( d );
@@ -15303,14 +15330,26 @@
}
// Based on locale, determine standard number formatting
var __thousands = '';
var __decimal = '';
// Fallback for legacy browsers is US English
var __thousands = ',';
var __decimal = '.';
if (Intl) {
var num = new Intl.NumberFormat().formatToParts(1000.1);
try {
var num = new Intl.NumberFormat().formatToParts(100000.1);
__thousands = num[1].value;
__decimal = num[3].value;
for (var i=0 ; i<num.length ; i++) {
if (num[i].type === 'group') {
__thousands = num[i].value;
}
else if (num[i].type === 'decimal') {
__decimal = num[i].value;
}
}
}
catch (e) {
// noop
}
}
// Formatted date time detection - use by declaring the formats you are going to use
@@ -15379,6 +15418,10 @@
return d;
}
if (d === '' || d === null) {
return d;
}
var negative = d < 0 ? '-' : '';
var flo = parseFloat( d );
@@ -15578,14 +15621,6 @@
* 2020 SpryMedia Ltd - datatables.net/license
*/
/**
* DataTables integration for Bootstrap 4. This requires Bootstrap 5 and
* DataTables 1.10 or newer.
*
* This file sets the defaults and adds options to DataTables to style its
* controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap
* for further information.
*/
(function( factory ){
if ( typeof define === 'function' && define.amd ) {
// AMD
@@ -15597,16 +15632,22 @@
// CommonJS
module.exports = function (root, $) {
if ( ! root ) {
// CommonJS environments without a window global must pass a
// root. This will give an error otherwise
root = window;
}
if ( ! $ || ! $.fn.dataTable ) {
// Require DataTables, which attaches to jQuery, including
// jQuery if needed and have a $ property so we can access the
// jQuery object that is used
$ = require('datatables.net')(root, $).$;
if ( ! $ ) {
$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
require('jquery') :
require('jquery')( root );
}
if ( ! $.fn.dataTable ) {
require('datatables.net')(root, $);
}
return factory( $, root, root.document );
};
}
@@ -15619,11 +15660,21 @@
var DataTable = $.fn.dataTable;
/**
* DataTables integration for Bootstrap 5. This requires Bootstrap 5 and
* DataTables 1.10 or newer.
*
* This file sets the defaults and adds options to DataTables to style its
* controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap
* for further information.
*/
/* Set the defaults for DataTables initialisation */
$.extend( true, DataTable.defaults, {
dom:
"<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>>" +
"<'row'<'col-sm-12'tr>>" +
"<'row dt-row'<'col-sm-12'tr>>" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
renderer: 'bootstrap'
} );
@@ -15645,7 +15696,7 @@ DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, bu
var classes = settings.oClasses;
var lang = settings.oLanguage.oPaginate;
var aria = settings.oLanguage.oAria.paginate || {};
var btnDisplay, btnClass, counter=0;
var btnDisplay, btnClass;
var attach = function( container, buttons ) {
var i, ien, node, button;
@@ -15714,7 +15765,7 @@ DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, bu
'href': '#',
'aria-controls': settings.sTableId,
'aria-label': aria[ button ],
'data-dt-idx': counter,
'data-dt-idx': button,
'tabindex': settings.iTabIndex,
'class': 'page-link'
} )
@@ -15725,13 +15776,12 @@ DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, bu
settings.oApi._fnBindAction(
node, {action: button}, clickHandler
);
counter++;
}
}
}
};
var hostEl = $(host);
// IE9 throws an 'unknown error' if document.activeElement is used
// inside an iframe or frame.
var activeEl;
@@ -15741,17 +15791,26 @@ DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, bu
// elements, focus is lost on the select button which is bad for
// accessibility. So we want to restore focus once the draw has
// completed
activeEl = $(host).find(document.activeElement).data('dt-idx');
activeEl = hostEl.find(document.activeElement).data('dt-idx');
}
catch (e) {}
var paginationEl = hostEl.children('ul.pagination');
if (paginationEl.length) {
paginationEl.empty();
}
else {
paginationEl = hostEl.html('<ul/>').children('ul').addClass('pagination');
}
attach(
$(host).empty().html('<ul class="pagination"/>').children('ul'),
paginationEl,
buttons
);
if ( activeEl !== undefined ) {
$(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
hostEl.find('[data-dt-idx='+activeEl+']').trigger('focus');
}
};
@@ -15760,14 +15819,54 @@ return DataTable;
}));
/*! Responsive 2.3.0
/*! Responsive 2.4.0
* 2014-2022 SpryMedia Ltd - datatables.net/license
*/
(function( factory ){
if ( typeof define === 'function' && define.amd ) {
// AMD
define( ['jquery', 'datatables.net'], function ( $ ) {
return factory( $, window, document );
} );
}
else if ( typeof exports === 'object' ) {
// CommonJS
module.exports = function (root, $) {
if ( ! root ) {
// CommonJS environments without a window global must pass a
// root. This will give an error otherwise
root = window;
}
if ( ! $ ) {
$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
require('jquery') :
require('jquery')( root );
}
if ( ! $.fn.dataTable ) {
require('datatables.net')(root, $);
}
return factory( $, root, root.document );
};
}
else {
// Browser
factory( jQuery, window, document );
}
}(function( $, window, document, undefined ) {
'use strict';
var DataTable = $.fn.dataTable;
/**
* @summary Responsive
* @description Responsive tables plug-in for DataTables
* @version 2.3.0
* @version 2.4.0
* @author SpryMedia Ltd (www.sprymedia.co.uk)
* @contact www.sprymedia.co.uk/contact
* @copyright SpryMedia Ltd.
@@ -15781,35 +15880,6 @@ return DataTable;
*
* For details please refer to: http://www.datatables.net
*/
(function( factory ){
if ( typeof define === 'function' && define.amd ) {
// AMD
define( ['jquery', 'datatables.net'], function ( $ ) {
return factory( $, window, document );
} );
}
else if ( typeof exports === 'object' ) {
// CommonJS
module.exports = function (root, $) {
if ( ! root ) {
root = window;
}
if ( ! $ || ! $.fn.dataTable ) {
$ = require('datatables.net')(root, $).$;
}
return factory( $, root, root.document );
};
}
else {
// Browser
factory( jQuery, window, document );
}
}(function( $, window, document, undefined ) {
'use strict';
var DataTable = $.fn.dataTable;
/**
* Responsive is a plug-in for the DataTables library that makes use of
@@ -15863,9 +15933,10 @@ var Responsive = function ( settings, opts ) {
}
this.s = {
dt: new DataTable.Api( settings ),
childNodeStore: {},
columns: [],
current: []
current: [],
dt: new DataTable.Api( settings )
};
// Check if responsive has already been initialised on this table
@@ -16070,6 +16141,63 @@ $.extend( Responsive.prototype, {
* Private methods
*/
/**
* Get and store nodes from a cell - use for node moving renderers
*
* @param {*} dt DT instance
* @param {*} row Row index
* @param {*} col Column index
*/
_childNodes: function( dt, row, col ) {
var name = row+'-'+col;
if ( this.s.childNodeStore[ name ] ) {
return this.s.childNodeStore[ name ];
}
// https://jsperf.com/childnodes-array-slice-vs-loop
var nodes = [];
var children = dt.cell( row, col ).node().childNodes;
for ( var i=0, ien=children.length ; i<ien ; i++ ) {
nodes.push( children[i] );
}
this.s.childNodeStore[ name ] = nodes;
return nodes;
},
/**
* Restore nodes from the cache to a table cell
*
* @param {*} dt DT instance
* @param {*} row Row index
* @param {*} col Column index
*/
_childNodesRestore: function( dt, row, col ) {
var name = row+'-'+col;
if ( ! this.s.childNodeStore[ name ] ) {
return;
}
var node = dt.cell( row, col ).node();
var store = this.s.childNodeStore[ name ];
var parent = store[0].parentNode;
var parentChildren = parent.childNodes;
var a = [];
for ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) {
a.push( parentChildren[i] );
}
for ( var j=0, jen=a.length ; j<jen ; j++ ) {
node.appendChild( a[j] );
}
this.s.childNodeStore[ name ] = undefined;
},
/**
* Calculate the visibility for the columns in a table for a given
* breakpoint. The result is pre-determined based on the class logic if
@@ -16399,8 +16527,8 @@ $.extend( Responsive.prototype, {
: details.renderer;
var res = details.display( row, update, function () {
return renderer(
dt, row[0], that._detailsObj(row[0])
return renderer.call(
that, dt, row[0], that._detailsObj(row[0])
);
} );
@@ -16622,9 +16750,11 @@ $.extend( Responsive.prototype, {
}
} );
if ( changed ) {
// Always need to update the display, regardless of if it has changed or not, so nodes
// can be re-inserted for listHiddenNodes
this._redrawChildren();
if ( changed ) {
// Inform listeners of the change
$(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] );
@@ -16650,6 +16780,7 @@ $.extend( Responsive.prototype, {
{
var dt = this.s.dt;
var columns = this.s.columns;
var that = this;
// Are we allowed to do auto sizing?
if ( ! this.c.auto ) {
@@ -16663,11 +16794,11 @@ $.extend( Responsive.prototype, {
}
// Need to restore all children. They will be reinstated by a re-render
if ( ! $.isEmptyObject( _childNodeStore ) ) {
$.each( _childNodeStore, function ( key ) {
if ( ! $.isEmptyObject( this.s.childNodeStore ) ) {
$.each( this.s.childNodeStore, function ( key ) {
var idx = key.split('-');
_childNodesRestore( dt, idx[0]*1, idx[1]*1 );
that._childNodesRestore( dt, idx[0]*1, idx[1]*1 );
} );
}
@@ -16787,6 +16918,7 @@ $.extend( Responsive.prototype, {
*/
_setColumnVis: function ( col, showHide )
{
var that = this;
var dt = this.s.dt;
var display = showHide ? '' : 'none'; // empty string will remove the attr
@@ -16803,9 +16935,9 @@ $.extend( Responsive.prototype, {
.toggleClass('dtr-hidden', !showHide);
// If the are child nodes stored, we might need to reinsert them
if ( ! $.isEmptyObject( _childNodeStore ) ) {
if ( ! $.isEmptyObject( this.s.childNodeStore ) ) {
dt.cells( null, col ).indexes().each( function (idx) {
_childNodesRestore( dt, idx.row, idx.column );
that._childNodesRestore( dt, idx.row, idx.column );
} );
}
},
@@ -16972,52 +17104,6 @@ Responsive.display = {
};
var _childNodeStore = {};
function _childNodes( dt, row, col ) {
var name = row+'-'+col;
if ( _childNodeStore[ name ] ) {
return _childNodeStore[ name ];
}
// https://jsperf.com/childnodes-array-slice-vs-loop
var nodes = [];
var children = dt.cell( row, col ).node().childNodes;
for ( var i=0, ien=children.length ; i<ien ; i++ ) {
nodes.push( children[i] );
}
_childNodeStore[ name ] = nodes;
return nodes;
}
function _childNodesRestore( dt, row, col ) {
var name = row+'-'+col;
if ( ! _childNodeStore[ name ] ) {
return;
}
var node = dt.cell( row, col ).node();
var store = _childNodeStore[ name ];
var parent = store[0].parentNode;
var parentChildren = parent.childNodes;
var a = [];
for ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) {
a.push( parentChildren[i] );
}
for ( var j=0, jen=a.length ; j<jen ; j++ ) {
node.appendChild( a[j] );
}
_childNodeStore[ name ] = undefined;
}
/**
* Display methods - functions which define how the hidden data should be shown
* in the table.
@@ -17029,6 +17115,7 @@ function _childNodesRestore( dt, row, col ) {
Responsive.renderer = {
listHiddenNodes: function () {
return function ( api, rowIdx, columns ) {
var that = this;
var ul = $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>');
var found = false;
@@ -17045,7 +17132,7 @@ Responsive.renderer = {
'</span> '+
'</li>'
)
.append( $('<span class="dtr-data"/>').append( _childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) )
.append( $('<span class="dtr-data"/>').append( that._childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) )
.appendTo( ul );
found = true;
@@ -17229,7 +17316,7 @@ Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()
* @name Responsive.version
* @static
*/
Responsive.version = '2.3.0';
Responsive.version = '2.4.0';
$.fn.dataTable.Responsive = Responsive;
@@ -17256,12 +17343,12 @@ $(document).on( 'preInit.dt.dtr', function (e, settings, json) {
} );
return Responsive;
return DataTable;
}));
/*! Bootstrap 5 integration for DataTables' Responsive
* ©2021 SpryMedia Ltd - datatables.net/license
* © SpryMedia Ltd - datatables.net/license
*/
(function( factory ){
@@ -17275,17 +17362,26 @@ return Responsive;
// CommonJS
module.exports = function (root, $) {
if ( ! root ) {
// CommonJS environments without a window global must pass a
// root. This will give an error otherwise
root = window;
}
if ( ! $ || ! $.fn.dataTable ) {
$ = require('datatables.net-bs5')(root, $).$;
if ( ! $ ) {
$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
require('jquery') :
require('jquery')( root );
}
if ( ! $.fn.dataTable.Responsive ) {
if ( ! $.fn.dataTable ) {
require('datatables.net-bs5')(root, $);
}
if ( ! $.fn.dataTable ) {
require('datatables.net-responsive')(root, $);
}
return factory( $, root, root.document );
};
}
@@ -17298,6 +17394,7 @@ return Responsive;
var DataTable = $.fn.dataTable;
var _display = DataTable.Responsive.display;
var _original = _display.modal;
var _modal = $(
@@ -17359,33 +17456,14 @@ _display.modal = function ( options ) {
};
return DataTable.Responsive;
return DataTable;
}));
/*! Select for DataTables 1.4.0
/*! Select for DataTables 1.5.0
* 2015-2021 SpryMedia Ltd - datatables.net/license/mit
*/
/**
* @summary Select for DataTables
* @description A collection of API methods, events and buttons for DataTables
* that provides selection options of the items in a DataTable
* @version 1.4.0
* @file dataTables.select.js
* @author SpryMedia Ltd (www.sprymedia.co.uk)
* @contact datatables.net/forums
* @copyright Copyright 2015-2021 SpryMedia Ltd.
*
* This source file is free software, available under the following license:
* MIT license - http://datatables.net/license/mit
*
* This source file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
*
* For details please refer to: http://www.datatables.net/extensions/select
*/
(function( factory ){
if ( typeof define === 'function' && define.amd ) {
// AMD
@@ -17397,13 +17475,22 @@ return DataTable.Responsive;
// CommonJS
module.exports = function (root, $) {
if ( ! root ) {
// CommonJS environments without a window global must pass a
// root. This will give an error otherwise
root = window;
}
if ( ! $ || ! $.fn.dataTable ) {
$ = require('datatables.net')(root, $).$;
if ( ! $ ) {
$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
require('jquery') :
require('jquery')( root );
}
if ( ! $.fn.dataTable ) {
require('datatables.net')(root, $);
}
return factory( $, root, root.document );
};
}
@@ -17416,10 +17503,11 @@ return DataTable.Responsive;
var DataTable = $.fn.dataTable;
// Version information for debugger
DataTable.select = {};
DataTable.select.version = '1.4.0';
DataTable.select.version = '1.5.0';
DataTable.select.init = function ( dt ) {
var ctx = dt.settings()[0];
@@ -18688,7 +18776,6 @@ $(document).on( 'preInit.dt.dtSelect', function (e, ctx) {
} );
return DataTable.select;
return DataTable;
}));

File diff suppressed because one or more lines are too long

View File

@@ -1,70 +0,0 @@
/**
* This plug-in for DataTables represents the ultimate option in extensibility
* for sorting date / time strings correctly. It uses
* [Moment.js](http://momentjs.com) to create automatic type detection and
* sorting plug-ins for DataTables based on a given format. This way, DataTables
* will automatically detect your temporal information and sort it correctly.
*
* For usage instructions, please see the DataTables blog
* post that [introduces it](//datatables.net/blog/2014-12-18).
*
* @name Ultimate Date / Time sorting
* @summary Sort date and time in any format using Moment.js
* @author [Allan Jardine](//datatables.net)
* @depends DataTables 1.10+, Moment.js 1.7+
*
* @example
* $.fn.dataTable.moment( 'HH:mm MMM D, YY' );
* $.fn.dataTable.moment( 'dddd, MMMM Do, YYYY' );
*
* $('#example').DataTable();
*/
(function (factory) {
if (typeof define === "function" && define.amd) {
define(["jquery", "moment", "datatables.net"], factory);
} else {
factory(jQuery, moment);
}
}(function ($, moment) {
function strip (d) {
if ( typeof d === 'string' ) {
// Strip HTML tags and newline characters if possible
d = d.replace(/(<.*?>)|(\r?\n|\r)/g, '');
// Strip out surrounding white space
d = d.trim();
}
return d;
}
$.fn.dataTable.moment = function ( format, locale, reverseEmpties ) {
var types = $.fn.dataTable.ext.type;
// Add type detection
types.detect.unshift( function ( d ) {
d = strip(d);
// Null and empty values are acceptable
if ( d === '' || d === null ) {
return 'moment-'+format;
}
return moment( d, format, locale, true ).isValid() ?
'moment-'+format :
null;
} );
// Add sorting method - use an integer for the sorting
types.order[ 'moment-'+format+'-pre' ] = function ( d ) {
d = strip(d);
return !moment(d, format, locale, true).isValid() ?
(reverseEmpties ? -Infinity : Infinity) :
parseInt( moment( d, format, locale, true ).format( 'x' ), 10 );
};
};
}));

View File

@@ -274,11 +274,10 @@ $(document).ready(function() {
});
})
// Jquery Datatables, enable responsive plugin and date sort plugin
// Jquery Datatables, enable responsive plugin
$.extend($.fn.dataTable.defaults, {
responsive: true
});
$.fn.dataTable.moment('dd:mm:YYYY');
// tag boxes
$('.tag-box .tag-add').click(function(){

View File

@@ -1,3 +1,13 @@
const LOCALE = undefined;
const DATETIME_FORMAT = {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
};
$(document).ready(function() {
// Parse seconds ago to date
// Get "now" timestamp
@@ -7,14 +17,7 @@ $(document).ready(function() {
if (typeof started_s_ago != 'NaN') {
var started_date = new Date((ts_now - started_s_ago) * 1000);
if (started_date instanceof Date && !isNaN(started_date)) {
var started_local_date = started_date.toLocaleDateString(undefined, {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
});
var started_local_date = started_date.toLocaleDateString(LOCALE, DATETIME_FORMAT);
$(this).text(started_local_date);
} else {
$(this).text('-');
@@ -25,14 +28,7 @@ $(document).ready(function() {
$('.parse_date').each(function(i, parse_date) {
var started_date = new Date(Date.parse($(this).text()));
if (typeof started_date != 'NaN') {
var started_local_date = started_date.toLocaleDateString(undefined, {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
});
var started_local_date = started_date.toLocaleDateString(LOCALE, DATETIME_FORMAT);
$(this).text(started_local_date);
}
});
@@ -75,6 +71,13 @@ jQuery(function($){
var table_name = $(this).data('table');
$('#' + table_name).DataTable().ajax.reload();
});
function createSortableDate(td, cellData) {
$(td).attr({
"data-order": cellData,
"data-sort": cellData
});
$(td).html(convertTimestampToLocalFormat(cellData));
}
function draw_autodiscover_logs() {
// just recalc width if instance already exists
if ($.fn.DataTable.isDataTable('#autodiscover_log') ) {
@@ -100,9 +103,8 @@ jQuery(function($){
data: 'time',
defaultContent: '',
responsivePriority: 1,
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"});
createdCell: function(td, cellData) {
createSortableDate(td, cellData)
}
},
{
@@ -157,9 +159,8 @@ jQuery(function($){
title: lang.time,
data: 'time',
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"});
createdCell: function(td, cellData) {
createSortableDate(td, cellData)
}
},
{
@@ -200,9 +201,8 @@ jQuery(function($){
title: lang.time,
data: 'time',
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"});
createdCell: function(td, cellData) {
createSortableDate(td, cellData)
}
},
{
@@ -247,9 +247,8 @@ jQuery(function($){
title: lang.time,
data: 'time',
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"});
createdCell: function(td, cellData) {
createSortableDate(td, cellData)
}
},
{
@@ -306,9 +305,8 @@ jQuery(function($){
title: lang.time,
data: 'time',
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"});
createdCell: function(td, cellData) {
createSortableDate(td, cellData)
}
},
{
@@ -393,9 +391,8 @@ jQuery(function($){
title: lang.time,
data: 'time',
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"});
createdCell: function(td, cellData) {
createSortableDate(td, cellData)
}
},
{
@@ -481,9 +478,9 @@ jQuery(function($){
title: lang.login_time,
data: 'datetime',
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"});
createdCell: function(td, cellData) {
cellData = Math.floor((new Date(data.replace(/-/g, "/"))).getTime() / 1000);
createSortableDate(td, cellData)
}
}
]
@@ -513,9 +510,8 @@ jQuery(function($){
title: lang.time,
data: 'time',
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"});
createdCell: function(td, cellData) {
createSortableDate(td, cellData)
}
},
{
@@ -551,9 +547,8 @@ jQuery(function($){
title: lang.time,
data: 'time',
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"});
createdCell: function(td, cellData) {
createSortableDate(td, cellData)
}
},
{
@@ -594,9 +589,8 @@ jQuery(function($){
title: lang.time,
data: 'time',
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"});
createdCell: function(td, cellData) {
createSortableDate(td, cellData)
}
},
{
@@ -637,9 +631,8 @@ jQuery(function($){
title: lang.time,
data: 'time',
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"});
createdCell: function(td, cellData) {
createSortableDate(td, cellData)
}
},
{
@@ -728,6 +721,7 @@ jQuery(function($){
processing: true,
serverSide: false,
language: lang_datatables,
order: [[0, 'desc']],
ajax: {
type: "GET",
url: "/api/v1/get/logs/rspamd-history",
@@ -738,11 +732,10 @@ jQuery(function($){
columns: [
{
title: lang.time,
data: 'time',
data: 'unix_time',
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"});
createdCell: function(td, cellData) {
createSortableDate(td, cellData)
}
},
{
@@ -773,12 +766,14 @@ jQuery(function($){
{
title: 'Score',
data: 'score',
defaultContent: ''
},
{
title: 'Subject',
data: 'header_subject',
defaultContent: ''
defaultContent: '',
createdCell: function(td, cellData) {
$(td).attr({
"data-order": cellData.sortBy,
"data-sort": cellData.sortBy
});
$(td).html(cellData.value);
}
},
{
title: 'Symbols',
@@ -794,7 +789,14 @@ jQuery(function($){
{
title: 'Scan Time',
data: 'scan_time',
defaultContent: ''
defaultContent: '',
createdCell: function(td, cellData) {
$(td).attr({
"data-order": cellData.sortBy,
"data-sort": cellData.sortBy
});
$(td).html(cellData.value);
}
},
{
title: 'ID',
@@ -851,9 +853,7 @@ jQuery(function($){
scan_time += ' / ' + item.time_virtual.toFixed(3);
}
item.scan_time = {
"options": {
"sortValue": item.time_real
},
"sortBy": item.time_real,
"value": scan_time
};
if (item.action === 'clean' || item.action === 'no action') {
@@ -872,9 +872,7 @@ jQuery(function($){
score_content = "[ <span class='text-danger'>" + item.score.toFixed(2) + " / " + item.required_score + "</span> ]";
}
item.score = {
"options": {
"sortValue": item.score
},
"sortBy": item.score,
"value": score_content
};
if (item.user == null) {
@@ -1531,3 +1529,8 @@ function parseGithubMarkdownLinks(inputText) {
return replacedText;
}
function convertTimestampToLocalFormat(timestamp) {
var date = new Date(timestamp ? timestamp * 1000 : 0);
return date.toLocaleDateString(LOCALE, DATETIME_FORMAT);
}

View File

@@ -97,7 +97,7 @@ jQuery(function($){
},
{
title: lang.subj,
data: 'sender',
data: 'subject',
defaultContent: ''
},
{

View File

@@ -393,7 +393,6 @@
"toggle_all": "Marcar tots"
},
"queue": {
"queue_command_success": "Queue command completed successfully",
"queue_manager": "Queue Manager"
},
"start": {

View File

@@ -889,7 +889,6 @@
"type": "Typ"
},
"queue": {
"queue_deliver_mail": "Doručit",
"queue_manager": "Správce fronty"
},
"ratelimit": {

View File

@@ -803,7 +803,6 @@
"toggle_all": "Skift alt"
},
"queue": {
"queue_deliver_mail": "Aflevere",
"queue_manager": "Køadministrator"
},
"start": {

View File

@@ -488,6 +488,7 @@
"chart_this_server": "Chart (dieser Server)",
"containers_info": "Container-Information",
"container_running": "Läuft",
"container_disabled": "Container gestoppt oder deaktiviert",
"container_stopped": "Angehalten",
"cores": "Kerne",
"current_time": "Systemzeit",

View File

@@ -491,6 +491,7 @@
"chart_this_server": "Chart (this server)",
"containers_info": "Container information",
"container_running": "Running",
"container_disabled": "Container stopped or disabled",
"container_stopped": "Stopped",
"cores": "Cores",
"current_time": "System Time",

View File

@@ -602,7 +602,6 @@
"toggle_all": "Seleccionar todos"
},
"queue": {
"queue_deliver_mail": "Entregar",
"queue_manager": "Administrador de cola"
},
"start": {

View File

@@ -686,7 +686,6 @@
"toggle_all": "Valitse kaikki"
},
"queue": {
"queue_deliver_mail": "Toimittaa",
"queue_manager": "Jonon hallinta"
},
"start": {

View File

@@ -26,7 +26,9 @@
"syncjobs": "Tâches de synchronisation",
"tls_policy": "Police TLS",
"unlimited_quota": "Quota illimité pour les boites de courriel",
"domain_desc": "Modifier la description du domaine"
"domain_desc": "Modifier la description du domaine",
"domain_relayhost": "Changer le relais pour un domaine",
"mailbox_relayhost": "Changer le relais dune boîte de réception"
},
"add": {
"activate_filter_warn": "Tous les autres filtres seront désactivés, quand activé est coché.",
@@ -827,7 +829,6 @@
"toggle_all": "Tout basculer"
},
"queue": {
"queue_deliver_mail": "Délivrer",
"queue_manager": "Gestion de la file d'attente"
},
"start": {

View File

@@ -216,7 +216,6 @@
"toggle_all": "Összes átkapcsolása"
},
"queue": {
"queue_command_success": "Queue command completed successfully",
"queue_manager": "Queue Manager"
},
"start": {

View File

@@ -893,7 +893,6 @@
"type": "Tipologia"
},
"queue": {
"queue_deliver_mail": "Consegna",
"queue_manager": "Gestore code"
},
"start": {

View File

@@ -777,7 +777,6 @@
"toggle_all": "선택 반전"
},
"queue": {
"queue_deliver_mail": "Deliver",
"queue_manager": "대기열 관리자"
},
"start": {

View File

@@ -400,7 +400,6 @@
"toggle_all": "Pārslēgt visu"
},
"queue": {
"queue_command_success": "Queue command completed successfully",
"queue_manager": "Queue Manager"
},
"start": {

View File

@@ -815,7 +815,6 @@
"toggle_all": "Selecteer alles"
},
"queue": {
"queue_deliver_mail": "Lever af",
"queue_manager": "Queue manager"
},
"start": {

View File

@@ -285,7 +285,6 @@
"toggle_all": "Zaznacz wszystkie"
},
"queue": {
"queue_command_success": "Queue command completed successfully",
"queue_manager": "Queue Manager"
},
"start": {

View File

@@ -193,7 +193,6 @@
"remove": "Remover"
},
"queue": {
"queue_command_success": "Queue command completed successfully",
"queue_manager": "Queue Manager"
},
"start": {

View File

@@ -895,7 +895,6 @@
"toggle_all": "Comută toate"
},
"queue": {
"queue_deliver_mail": "Livrează",
"queue_manager": "Manager de coadă"
},
"ratelimit": {

View File

@@ -893,7 +893,6 @@
"type": "Тип"
},
"queue": {
"queue_deliver_mail": "Доставить",
"queue_manager": "Очередь на отправку"
},
"ratelimit": {

View File

@@ -895,7 +895,6 @@
"type": "Typ"
},
"queue": {
"queue_deliver_mail": "Doručiť",
"queue_manager": "Správca fronty"
},
"ratelimit": {

View File

@@ -896,7 +896,6 @@
"table_size_show_n": "Відображати %s полів"
},
"queue": {
"queue_hold_mail": "Поставити на утримання",
"queue_manager": "Черга на відправлення"
},
"ratelimit": {

View File

@@ -257,7 +257,6 @@
"quarantine_release_format_att": "附件",
"quarantine_release_format_raw": "原件 (未修改)",
"quarantine_retention_size": "每个邮箱保留隔离项目数:<br><small>0 表示 <b>禁用</b>。</small>",
"queue_manager": "队列管理",
"quota_notification_html": "通知邮件模板:<br><small>留空则恢复默认模板。</small>",
"quota_notification_sender": "通知邮件发件人",
"quota_notification_subject": "通知邮件主题",
@@ -886,7 +885,6 @@
"type": "类型"
},
"queue": {
"queue_deliver_mail": "递送",
"queue_manager": "队列管理器"
},
"ratelimit": {

View File

@@ -257,7 +257,6 @@
"quarantine_release_format_att": "如附件",
"quarantine_release_format_raw": "未修改的原始信件",
"quarantine_retention_size": "每個信箱的隔離保留上限:<br><small>0 表示 <b>停用</b>。</small>",
"queue_manager": "佇列管理",
"quota_notification_html": "通知信模版:<br><small>留空來重設為預設模版。</small>",
"quota_notification_sender": "通知信寄件人",
"quota_notification_subject": "通知信主旨",

View File

@@ -80,7 +80,9 @@
{% if mailcow_cc_role == 'admin' %}
<li><a href="/queue" class="dropdown-item {% if is_uri('queue') %}active{% endif %}">{{ lang.queue.queue_manager }}</a></li>
{% endif %}
{% if mailcow_cc_role == 'admin' %}
<li><a href="#" class="dropdown-item" data-bs-toggle="modal" data-container="sogo-mailcow" data-bs-target="#RestartContainer">{{ lang.header.restart_sogo }}</a></li>
{% endif %}
</ul>
</li>
{% endif %}

View File

@@ -160,8 +160,14 @@
<div class="d-flex p-2 list-group-header">
<div>
<span class="fw-bold">solr-mailcow</span>
{% if containers["solr-mailcow"].State.Running == 1 %}
<span class="d-block d-md-inline">({{ containers["solr-mailcow"].Config.Image }})</span>
{% endif %}
{% if containers["solr-mailcow"].State.Running == 1 %}
<small class="d-block">({{ lang.debug.started_on }} <span class="parse_date">{{ containers["solr-mailcow"].State.StartedAtHR }}</span>)</small>
{% elseif containers["solr-mailcow"].State.Running != 1 %}
<small class="d-block">{{ lang.debug.container_disabled }}</small>
{% endif %}
{% if containers["solr-mailcow"].State.Running == 1 %}
<span class="badge fs-7 bg-success loader" style="min-width:100px">
{{ lang.debug.container_running }}
@@ -169,19 +175,22 @@
<span class="loader-dot">.</span>
<span class="loader-dot">.</span>
</span>
{% elseif containers["solr-mailcow"].State %}
{% elseif containers["solr-mailcow"].State.Running != 1 %}
<span class="badge fs-7 bg-danger" style="min-width:100px">
{{ lang.debug.container_stopped }}
<i class="bi-x ms-1"></i>
</span>
{% endif %}
</div>
{% if containers["solr-mailcow"].State.Running == 1 %}
<div class="mt-auto ms-auto">
<button class="btn btn-light" type="button" data-bs-toggle="collapse" data-bs-target="#solr-mailcowCollapse" aria-expanded="false" aria-controls="solr-mailcowCollapse">
<i class="bi bi-caret-down-fill caret"></i>
</button>
</div>
{% endif %}
</div>
{% if containers["solr-mailcow"].State.Running == 1 %}
<div class="collapse p-0 list-group-details container-details-collapse" id="solr-mailcowCollapse" data-id="{{ containers["solr-mailcow"].Id }}">
<div class="row p-2 pt-4">
<div class="col-sm-3">
@@ -238,6 +247,7 @@
</div>
</div>
</div>
{% endif %}
</div>
</div>

View File

@@ -274,7 +274,7 @@
</div>
<div class="col-sm-10">
<p class="text-muted">{{ lang.user.pushover_info|format(mailbox)|raw }}</p>
<p class="text-muted">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code>, <code>{TO_NAME}</code>, <code>{TO_ADDRESS}, <code>{MSG_ID}</code></p>
<p class="text-muted">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code>, <code>{TO_NAME}</code>, <code>{TO_ADDRESS}</code>, <code>{MSG_ID}</code></p>
<div class="row">
<div class="col-sm-6 mb-2">
<label for="token">API Token/Key (Application)</label>

View File

@@ -42,8 +42,6 @@ echo -e "\e[32mTrying to determine GLIBC version...\e[0m"
elif [[ $(curl -sL -w "%{http_code}" https://github.com/docker/compose/releases/latest -o /dev/null) == "200" ]]; then
LATEST_COMPOSE=$(curl -Ls -w %{url_effective} -o /dev/null https://github.com/docker/compose/releases/latest) # redirect to latest release
LATEST_COMPOSE=${LATEST_COMPOSE##*/} #get the latest version from the redirect, inlcuding the "v" prefix
if [ $DC_DL_SUFFIX]; then
LATEST_COMPOSE=1.27.4 # force 1.27.4 for legacy systems, tag is not prefixed by "v"
COMPOSE_VERSION=$(docker-compose version --short)
if [[ "$LATEST_COMPOSE" != "$COMPOSE_VERSION" ]]; then
COMPOSE_PATH=$(command -v docker-compose)