ui: enhance table responsiveness and add tooltips for better accessibility

This commit is contained in:
Théophile Diot 2024-11-18 14:30:47 +01:00
parent 53e1e4189b
commit ee635c36a6
No known key found for this signature in database
GPG key ID: FA995104A0BA376A
24 changed files with 839 additions and 792 deletions

View file

@ -715,6 +715,14 @@ table.table.dataTable > tbody > tr.selected a.btn-outline-primary {
color: var(--bs-primary) !important;
}
table.table.dataTable > tbody > tr.selected a.btn-outline-secondary:hover {
color: #fff !important;
}
table.table.dataTable > tbody > tr.selected a.btn-outline-primary:hover {
color: #fff !important;
}
table.table.dataTable > tbody > tr.selected a.btn-primary {
color: #fff !important;
}
@ -904,6 +912,29 @@ table.table.dataTable > tbody > tr.selected > * {
box-shadow: inset 0 0 0 9999px rgb(var(--bs-primary-rgb), 0.1) !important;
}
@media (min-width: 992px) {
.w-lg-70 {
width: 70% !important;
}
}
/* Align and style the modal content */
.modal-dialog {
max-width: 600px; /* Restrict modal width */
}
@media (max-width: 768px) {
.modal-dialog {
max-width: 90%; /* Adjust modal width on smaller screens */
}
}
#floating-settings-button {
bottom: 2.1rem !important;
right: 1.5rem !important;
z-index: 1080;
}
/*
* Dark mode overrides
******************************************************************************/
@ -1272,6 +1303,11 @@ html:not(.layout-menu-collapsed).dark-style
background-color: #0b394e;
}
html.dark-style div.dts div.dt-scroll-body table,
html.dark-style div.dts div.dataTables_scrollBody table {
background-color: #0c283a;
}
.dark-style table.table.dataTable > tbody > tr.selected > * {
color: #fff !important;
}

View file

@ -150,7 +150,7 @@ $(document).ready(function () {
viewTotal: true,
cascadePanes: true,
collapse: false,
columns: [1, 4, 5],
columns: [2, 5, 6],
},
},
topStart: {},
@ -196,8 +196,8 @@ $(document).ready(function () {
},
{
extend: "colvis",
columns: "th:not(:first-child):not(:nth-child(2)):not(:last-child)",
text: '<span class="tf-icons bx bx-columns bx-18px me-2"></span>Columns',
columns: "th:not(:nth-child(-n+3))",
text: '<span class="tf-icons bx bx-columns bx-18px me-md-2"></span><span class="d-none d-md-inline">Columns</span>',
className: "btn btn-sm btn-outline-primary rounded-start",
columnText: function (dt, idx, title) {
return idx + 1 + ". " + title;
@ -205,19 +205,19 @@ $(document).ready(function () {
},
{
extend: "colvisRestore",
text: '<span class="tf-icons bx bx-reset bx-18px me-2"></span>Reset<span class="d-none d-md-inline"> columns</span>',
className: "btn btn-sm btn-outline-primary",
text: '<span class="tf-icons bx bx-reset bx-18px me-2"></span>Reset columns',
className: "btn btn-sm btn-outline-primary d-none d-md-inline",
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-export bx-18px me-2"></span>Export',
text: '<span class="tf-icons bx bx-export bx-18px me-md-2"></span><span class="d-none d-md-inline">Export</span>',
className: "btn btn-sm btn-outline-primary",
buttons: [
{
extend: "copy",
text: '<span class="tf-icons bx bx-copy bx-18px me-2"></span>Copy visible',
exportOptions: {
columns: ":visible:not(:first-child):not(:last-child)",
columns: ":visible:not(:nth-child(-n+2)):not(:last-child)",
},
},
{
@ -229,7 +229,7 @@ $(document).ready(function () {
modifier: {
search: "none",
},
columns: ":not(:first-child):not(:last-child)",
columns: ":not(:nth-child(-n+2)):not(:last-child)",
},
},
{
@ -240,14 +240,14 @@ $(document).ready(function () {
modifier: {
search: "none",
},
columns: ":not(:first-child):not(:last-child)",
columns: ":not(:nth-child(-n+2)):not(:last-child)",
},
},
],
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-play bx-18px me-2"></span>Actions',
text: '<span class="tf-icons bx bx-play bx-18px me-md-2"></span><span class="d-none d-md-inline">Actions</span>',
className: "btn btn-sm btn-outline-primary action-button disabled",
buttons: [
{
@ -266,15 +266,15 @@ $(document).ready(function () {
const getSelectedBans = () => {
const bans = [];
$("tr.selected").each(function () {
const ip = $(this).find("td:eq(2)").text().trim();
const time_remaining = $(this).find("td:eq(5)").text().trim();
const ip = $(this).find("td:eq(3)").text().trim();
const time_remaining = $(this).find("td:eq(6)").text().trim();
bans.push({ ip: ip, time_remaining: time_remaining });
});
return bans;
};
$.fn.dataTable.ext.buttons.add_ban = {
text: '<span class="tf-icons bx bx-plus"></span>&nbsp;Add<span class="d-none d-md-inline"> ban(s)</span>',
text: '<span class="tf-icons bx bx-plus"></span><span class="d-none d-md-inline">&nbsp;Add ban(s)</span>',
className: `btn btn-sm rounded me-4 btn-bw-green${
isReadOnly ? " disabled" : ""
}`,
@ -327,16 +327,21 @@ $(document).ready(function () {
columnDefs: [
{
orderable: false,
render: DataTable.render.select(),
className: "dtr-control",
targets: 0,
},
{ type: "ip-address", targets: 1 },
{
orderable: false,
render: DataTable.render.select(),
targets: 1,
},
{ type: "ip-address", targets: 2 },
{
orderable: false,
targets: -1,
},
{
targets: [1, 5],
targets: [2, 6],
render: function (data, type, row) {
if (type === "display" || type === "filter") {
const date = new Date(data);
@ -354,7 +359,7 @@ $(document).ready(function () {
{
label: "Last 24 hours",
value: function (rowData, rowIdx) {
const date = new Date(rowData[1]);
const date = new Date(rowData[2]);
const now = new Date();
return now - date < 24 * 60 * 60 * 1000;
},
@ -362,7 +367,7 @@ $(document).ready(function () {
{
label: "Last 7 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[1]);
const date = new Date(rowData[2]);
const now = new Date();
return now - date < 7 * 24 * 60 * 60 * 1000;
},
@ -370,7 +375,7 @@ $(document).ready(function () {
{
label: "Last 30 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[1]);
const date = new Date(rowData[2]);
const now = new Date();
return now - date < 30 * 24 * 60 * 60 * 1000;
},
@ -378,7 +383,7 @@ $(document).ready(function () {
{
label: "More than 30 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[1]);
const date = new Date(rowData[2]);
const now = new Date();
return now - date >= 30 * 24 * 60 * 60 * 1000;
},
@ -387,7 +392,7 @@ $(document).ready(function () {
combiner: "or",
orderable: false,
},
targets: 1,
targets: 2,
},
{
searchPanes: {
@ -396,7 +401,7 @@ $(document).ready(function () {
{
label: "Next 24 hours",
value: function (rowData, rowIdx) {
const date = new Date(rowData[5]);
const date = new Date(rowData[6]);
const now = new Date();
return date - now < 24 * 60 * 60 * 1000;
},
@ -404,7 +409,7 @@ $(document).ready(function () {
{
label: "Next 7 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[5]);
const date = new Date(rowData[6]);
const now = new Date();
return date - now < 7 * 24 * 60 * 60 * 1000;
},
@ -412,7 +417,7 @@ $(document).ready(function () {
{
label: "Next 30 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[5]);
const date = new Date(rowData[6]);
const now = new Date();
return date - now < 30 * 24 * 60 * 60 * 1000;
},
@ -420,7 +425,7 @@ $(document).ready(function () {
{
label: "More than 30 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[5]);
const date = new Date(rowData[6]);
const now = new Date();
return date - now >= 30 * 24 * 60 * 60 * 1000;
},
@ -429,20 +434,20 @@ $(document).ready(function () {
combiner: "or",
orderable: false,
},
targets: 5,
targets: 6,
},
{
searchPanes: { show: true },
targets: 4,
targets: 5,
},
],
order: [[5, "asc"]],
order: [[6, "asc"]],
autoFill: false,
responsive: true,
select: {
style: "multi+shift",
selector: "td:first-child",
headerCheckbox: false,
selector: "td:nth-child(2)",
headerCheckbox: true,
},
layout: layout,
language: {
@ -486,6 +491,8 @@ $(document).ready(function () {
$("#bans").removeClass("d-none");
$("#bans-waiting").addClass("visually-hidden");
bans_table.responsive.recalc();
bans_table.on("mouseenter", "td", function () {
if (bans_table.cell(this).index() === undefined) return;
const rowIdx = bans_table.cell(this).index().row;
@ -535,20 +542,6 @@ $(document).ready(function () {
)
.attr("data-bs-placement", "top")
.tooltip();
$("#select-all-rows").prop("checked", false);
}
});
// Event listener for the select-all checkbox
$("#select-all-rows").on("change", function () {
const isChecked = $(this).prop("checked");
if (isChecked) {
// Select all rows on the current page
bans_table.rows({ page: "current" }).select();
} else {
// Deselect all rows on the current page
bans_table.rows({ page: "current" }).deselect();
}
});

View file

@ -9,7 +9,7 @@ $(document).ready(function () {
{
label: "global",
value: function (rowData) {
return $(rowData[3]).text().trim() === "global";
return $(rowData[4]).text().trim() === "global";
},
},
];
@ -18,7 +18,7 @@ $(document).ready(function () {
servicesSearchPanesOptions.push({
label: service,
value: function (rowData) {
return $(rowData[3]).text().trim() === service;
return $(rowData[4]).text().trim() === service;
},
});
});
@ -29,7 +29,7 @@ $(document).ready(function () {
viewTotal: true,
cascadePanes: true,
collapse: false,
columns: [1, 2, 3, 4],
columns: [2, 3, 4, 5],
},
},
topStart: {},
@ -72,7 +72,7 @@ $(document).ready(function () {
layout.topStart.buttons = [
{
extend: "colvis",
columns: "th:not(:first-child):not(:last-child)",
columns: "th:not(:nth-child(-n+3))",
text: '<span class="tf-icons bx bx-columns bx-18px me-2"></span>Columns',
className: "btn btn-sm btn-outline-primary",
columnText: function (dt, idx, title) {
@ -81,12 +81,12 @@ $(document).ready(function () {
},
{
extend: "colvisRestore",
text: '<span class="tf-icons bx bx-reset bx-18px me-2"></span>Reset<span class="d-none d-md-inline"> columns</span>',
text: '<span class="tf-icons bx bx-reset bx-18px me-md-2"></span><span class="d-none d-md-inline">Reset columns</span>',
className: "btn btn-sm btn-outline-primary",
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-export bx-18px me-2"></span>Export',
text: '<span class="tf-icons bx bx-export bx-18px me-md-2"></span><span class="d-none d-md-inline">Export</span>',
className: "btn btn-sm btn-outline-primary",
buttons: [
{
@ -105,7 +105,7 @@ $(document).ready(function () {
modifier: {
search: "none",
},
columns: ":not(:last-child)",
columns: ":not(:first-child):not(:last-child)",
},
},
{
@ -116,7 +116,7 @@ $(document).ready(function () {
modifier: {
search: "none",
},
columns: ":not(:last-child)",
columns: ":not(:first-child):not(:last-child)",
},
},
],
@ -142,16 +142,21 @@ $(document).ready(function () {
const cache_table = new DataTable("#cache", {
columnDefs: [
{
orderable: false,
className: "dtr-control",
targets: 0,
},
{
orderable: false,
targets: -1,
},
{
visible: false,
targets: 5,
targets: 6,
},
{
targets: 4,
targets: 5,
render: function (data, type, row) {
if (type === "display" || type === "filter") {
const date = new Date(data);
@ -167,7 +172,7 @@ $(document).ready(function () {
show: true,
combiner: "or",
},
targets: [1, 2],
targets: [2, 3],
},
{
searchPanes: {
@ -175,7 +180,7 @@ $(document).ready(function () {
combiner: "or",
options: servicesSearchPanesOptions,
},
targets: 3,
targets: 4,
},
{
searchPanes: {
@ -184,7 +189,7 @@ $(document).ready(function () {
{
label: "Last 24 hours",
value: function (rowData, rowIdx) {
const date = new Date(rowData[4]);
const date = new Date(rowData[5]);
const now = new Date();
return now - date < 24 * 60 * 60 * 1000;
},
@ -192,7 +197,7 @@ $(document).ready(function () {
{
label: "Last 7 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[4]);
const date = new Date(rowData[5]);
const now = new Date();
return now - date < 7 * 24 * 60 * 60 * 1000;
},
@ -200,7 +205,7 @@ $(document).ready(function () {
{
label: "Last 30 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[4]);
const date = new Date(rowData[5]);
const now = new Date();
return now - date < 30 * 24 * 60 * 60 * 1000;
},
@ -209,10 +214,10 @@ $(document).ready(function () {
combiner: "or",
orderable: false,
},
targets: 4,
targets: 5,
},
],
order: [[2, "asc"]],
order: [[3, "asc"]],
autoFill: false,
responsive: true,
layout: layout,
@ -246,6 +251,8 @@ $(document).ready(function () {
$("#cache").removeClass("d-none");
$("#cache-waiting").addClass("visually-hidden");
cache_table.responsive.recalc();
cache_table.on("mouseenter", "td", function () {
if (cache_table.cell(this).index() === undefined) return;
const rowIdx = cache_table.cell(this).index().row;

View file

@ -14,7 +14,7 @@ $(document).ready(function () {
{
label: "global",
value: function (rowData) {
return $(rowData[4]).text().trim() === "global";
return $(rowData[5]).text().trim() === "global";
},
},
];
@ -22,7 +22,7 @@ $(document).ready(function () {
{
label: "no template",
value: function (rowData) {
return $(rowData[5]).text().trim() === "no template";
return $(rowData[6]).text().trim() === "no template";
},
},
];
@ -31,7 +31,7 @@ $(document).ready(function () {
servicesSearchPanesOptions.push({
label: service,
value: function (rowData) {
return $(rowData[4]).text().trim() === service;
return $(rowData[5]).text().trim() === service;
},
});
});
@ -39,7 +39,7 @@ $(document).ready(function () {
templatesSearchPanesOptions.push({
label: template,
value: function (rowData) {
return $(rowData[5]).text().trim() === template;
return $(rowData[6]).text().trim() === template;
},
});
});
@ -125,7 +125,7 @@ $(document).ready(function () {
viewTotal: true,
cascadePanes: true,
collapse: false,
columns: [2, 3, 4, 5],
columns: [3, 4, 5, 6],
},
},
topStart: {},
@ -171,8 +171,8 @@ $(document).ready(function () {
},
{
extend: "colvis",
columns: "th:not(:first-child):not(:nth-child(2)):not(:last-child)",
text: '<span class="tf-icons bx bx-columns bx-18px me-2"></span>Columns',
columns: "th:not(:nth-child(-n+3))",
text: '<span class="tf-icons bx bx-columns bx-18px me-md-2"></span><span class="d-none d-md-inline">Columns</span>',
className: "btn btn-sm btn-outline-primary rounded-start",
columnText: function (dt, idx, title) {
return idx + 1 + ". " + title;
@ -180,19 +180,19 @@ $(document).ready(function () {
},
{
extend: "colvisRestore",
text: '<span class="tf-icons bx bx-reset bx-18px me-2"></span>Reset<span class="d-none d-md-inline"> columns</span>',
className: "btn btn-sm btn-outline-primary",
text: '<span class="tf-icons bx bx-reset bx-18px me-2"></span>Reset columns',
className: "btn btn-sm btn-outline-primary d-none d-md-inline",
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-export bx-18px me-2"></span>Export',
text: '<span class="tf-icons bx bx-export bx-18px me-md-2"></span><span class="d-none d-md-inline">Export</span>',
className: "btn btn-sm btn-outline-primary",
buttons: [
{
extend: "copy",
text: '<span class="tf-icons bx bx-copy bx-18px me-2"></span>Copy visible',
exportOptions: {
columns: ":visible:not(:first-child):not(:last-child)",
columns: ":visible:not(:nth-child(-n+2)):not(:last-child)",
},
},
{
@ -204,7 +204,7 @@ $(document).ready(function () {
modifier: {
search: "none",
},
columns: ":not(:first-child):not(:last-child)",
columns: ":not(:nth-child(-n+2)):not(:last-child)",
},
},
{
@ -215,14 +215,14 @@ $(document).ready(function () {
modifier: {
search: "none",
},
columns: ":not(:first-child):not(:last-child)",
columns: ":not(:nth-child(-n+2)):not(:last-child)",
},
},
],
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-play bx-18px me-2"></span>Actions',
text: '<span class="tf-icons bx bx-play bx-18px me-md-2"></span><span class="d-none d-md-inline">Actions</span>',
className: "btn btn-sm btn-outline-primary action-button disabled",
buttons: [
{
@ -250,9 +250,9 @@ $(document).ready(function () {
const configs = [];
$("tr.selected").each(function () {
const $this = $(this);
const name = $this.find("td:eq(1)").find("a").text().trim();
const type = $this.find("td:eq(2)").text().trim();
let service = $this.find("td:eq(4)");
const name = $this.find("td:eq(2)").find("a").text().trim();
const type = $this.find("td:eq(3)").text().trim();
let service = $this.find("td:eq(5)");
if (service.find("a").length > 0) {
service = service.find("a").text().trim();
} else {
@ -277,7 +277,7 @@ $(document).ready(function () {
};
$.fn.dataTable.ext.buttons.create_config = {
text: '<span class="tf-icons bx bx-plus"></span>&nbsp;Create<span class="d-none d-md-inline"> new custom config</span>',
text: '<span class="tf-icons bx bx-plus"></span><span class="d-none d-md-inline">&nbsp;Create new custom config</span>',
className: `btn btn-sm rounded me-4 btn-bw-green${
isReadOnly ? " disabled" : ""
}`,
@ -319,16 +319,21 @@ $(document).ready(function () {
columnDefs: [
{
orderable: false,
render: DataTable.render.select(),
className: "dtr-control",
targets: 0,
},
{
orderable: false,
render: DataTable.render.select(),
targets: 1,
},
{
orderable: false,
targets: -1,
},
{
visible: false,
targets: 6,
targets: 7,
},
{
searchPanes: {
@ -337,95 +342,95 @@ $(document).ready(function () {
{
label: '<i class="bx bx-xs bx-window-alt"></i>HTTP',
value: function (rowData, rowIdx) {
$(rowData[2]).text().trim() === "HTTP";
$(rowData[3]).text().trim() === "HTTP";
},
},
{
label: '<i class="bx bx-xs bx-window-alt"></i>SERVER_HTTP',
value: function (rowData, rowIdx) {
return $(rowData[2]).text().trim() === "SERVER_HTTP";
return $(rowData[3]).text().trim() === "SERVER_HTTP";
},
},
{
label:
'<i class="bx bx-xs bx-window-alt"></i>DEFAULT_SERVER_HTTP',
value: function (rowData, rowIdx) {
return $(rowData[2]).text().trim() === "DEFAULT_SERVER_HTTP";
return $(rowData[3]).text().trim() === "DEFAULT_SERVER_HTTP";
},
},
{
label: '<i class="bx bx-xs bx-shield-quarter"></i>MODSEC_CRS',
value: function (rowData, rowIdx) {
return $(rowData[2]).text().trim() === "MODSEC_CRS";
return $(rowData[3]).text().trim() === "MODSEC_CRS";
},
},
{
label: '<i class="bx bx-xs bx-shield-alt-2"></i>MODSEC',
value: function (rowData, rowIdx) {
return $(rowData[2]).text().trim() === "MODSEC";
return $(rowData[3]).text().trim() === "MODSEC";
},
},
{
label: '<i class="bx bx-xs bx-network-chart"></i>STREAM',
value: function (rowData, rowIdx) {
return $(rowData[2]).text().trim() === "STREAM";
return $(rowData[3]).text().trim() === "STREAM";
},
},
{
label: '<i class="bx bx-xs bx-network-chart"></i>SERVER_STREAM',
value: function (rowData, rowIdx) {
return $(rowData[2]).text().trim() === "SERVER_STREAM";
return $(rowData[3]).text().trim() === "SERVER_STREAM";
},
},
{
label: '<i class="bx bx-xs bx-shield-alt"></i>CRS_PLUGINS_BEFORE',
value: function (rowData, rowIdx) {
return $(rowData[2]).text().trim() === "CRS_PLUGINS_BEFORE";
return $(rowData[3]).text().trim() === "CRS_PLUGINS_BEFORE";
},
},
{
label: '<i class="bx bx-xs bx-shield-alt"></i>CRS_PLUGINS_AFTER',
value: function (rowData, rowIdx) {
return $(rowData[2]).text().trim() === "CRS_PLUGINS_AFTER";
return $(rowData[3]).text().trim() === "CRS_PLUGINS_AFTER";
},
},
],
combiner: "or",
},
targets: 2,
},
{
searchPanes: {
show: true,
combiner: "or",
options: servicesSearchPanesOptions,
},
targets: 4,
},
{
searchPanes: {
show: true,
combiner: "or",
orderable: false,
},
targets: 3,
},
{
searchPanes: {
show: true,
combiner: "or",
options: templatesSearchPanesOptions,
orderable: false,
},
targets: 4,
},
{
searchPanes: {
show: true,
combiner: "or",
options: servicesSearchPanesOptions,
},
targets: 5,
},
{
searchPanes: {
show: true,
combiner: "or",
options: templatesSearchPanesOptions,
},
targets: 6,
},
],
order: [[1, "asc"]],
order: [[2, "asc"]],
autoFill: false,
responsive: true,
select: {
style: "multi+shift",
selector: "td:first-child",
headerCheckbox: false,
selector: "td:nth-child(2)",
headerCheckbox: true,
},
layout: layout,
language: {
@ -478,6 +483,8 @@ $(document).ready(function () {
$("#configs").removeClass("d-none");
$("#configs-waiting").addClass("visually-hidden");
configs_table.responsive.recalc();
configs_table.on("mouseenter", "td", function () {
if (configs_table.cell(this).index() === undefined) return;
const rowIdx = configs_table.cell(this).index().row;
@ -527,20 +534,6 @@ $(document).ready(function () {
)
.attr("data-bs-placement", "top")
.tooltip();
$("#select-all-rows").prop("checked", false);
}
});
// Event listener for the select-all checkbox
$("#select-all-rows").on("change", function () {
const isChecked = $(this).prop("checked");
if (isChecked) {
// Select all rows on the current page
configs_table.rows({ page: "current" }).select();
} else {
// Deselect all rows on the current page
configs_table.rows({ page: "current" }).deselect();
}
});

View file

@ -144,7 +144,7 @@ $(document).ready(function () {
viewTotal: true,
cascadePanes: true,
collapse: false,
columns: [3, 4, 5, 6, 7],
columns: [4, 5, 6, 7, 8],
},
},
topStart: {},
@ -190,8 +190,8 @@ $(document).ready(function () {
},
{
extend: "colvis",
columns: "th:not(:first-child):not(:nth-child(2))",
text: '<span class="tf-icons bx bx-columns bx-18px me-2"></span>Columns',
columns: "th:not(:nth-child(-n+3))",
text: '<span class="tf-icons bx bx-columns bx-18px me-md-2"></span><span class="d-none d-md-inline">Columns</span>',
className: "btn btn-sm btn-outline-primary rounded-start",
columnText: function (dt, idx, title) {
return idx + 1 + ". " + title;
@ -199,19 +199,19 @@ $(document).ready(function () {
},
{
extend: "colvisRestore",
text: '<span class="tf-icons bx bx-reset bx-18px me-2"></span>Reset<span class="d-none d-md-inline"> columns</span>',
className: "btn btn-sm btn-outline-primary",
text: '<span class="tf-icons bx bx-reset bx-18px me-2"></span>Reset columns',
className: "btn btn-sm btn-outline-primary d-none d-md-inline",
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-export bx-18px me-2"></span>Export',
text: '<span class="tf-icons bx bx-export bx-18px me-md-2"></span><span class="d-none d-md-inline">Export</span>',
className: "btn btn-sm btn-outline-primary",
buttons: [
{
extend: "copy",
text: '<span class="tf-icons bx bx-copy bx-18px me-2"></span>Copy visible',
exportOptions: {
columns: ":visible:not(:first-child):not(:last-child)",
columns: ":visible:not(:nth-child(-n+2)):not(:last-child)",
},
},
{
@ -223,7 +223,7 @@ $(document).ready(function () {
modifier: {
search: "none",
},
columns: ":not(:first-child):not(:last-child)",
columns: ":not(:nth-child(-n+2)):not(:last-child)",
},
},
{
@ -234,14 +234,14 @@ $(document).ready(function () {
modifier: {
search: "none",
},
columns: ":not(:first-child):not(:last-child)",
columns: ":not(:nth-child(-n+2)):not(:last-child)",
},
},
],
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-play bx-18px me-2"></span>Actions',
text: '<span class="tf-icons bx bx-play bx-18px me-md-2"></span><span class="d-none d-md-inline">Actions</span>',
className: "btn btn-sm btn-outline-primary action-button disabled",
buttons: [
{
@ -279,13 +279,13 @@ $(document).ready(function () {
const getSelectedInstances = () => {
const instances = [];
$("tr.selected").each(function () {
instances.push($(this).find("td:eq(1)").text());
instances.push($(this).find("td:eq(2)").text());
});
return instances;
};
$.fn.dataTable.ext.buttons.create_instance = {
text: '<span class="tf-icons bx bx-plus"></span>&nbsp;Create<span class="d-none d-md-inline"> new instance</span>',
text: '<span class="tf-icons bx bx-plus"></span><span class="d-none d-md-inline">&nbsp;Create new instance</span>',
className: `btn btn-sm rounded me-4 btn-bw-green${
isReadOnly ? " disabled" : ""
}`,
@ -386,19 +386,24 @@ $(document).ready(function () {
columnDefs: [
{
orderable: false,
render: DataTable.render.select(),
className: "dtr-control",
targets: 0,
},
{
orderable: false,
render: DataTable.render.select(),
targets: 1,
},
{
orderable: false,
targets: -1,
},
{
visible: false,
targets: [2, 3],
targets: [3, 4],
},
{
targets: [6, 7],
targets: [7, 8],
render: function (data, type, row) {
if (type === "display" || type === "filter") {
const date = new Date(data);
@ -415,7 +420,7 @@ $(document).ready(function () {
combiner: "or",
orderable: false,
},
targets: [3],
targets: [4],
},
{
searchPanes: {
@ -425,49 +430,21 @@ $(document).ready(function () {
label:
'<i class="bx bx-xs bx-up-arrow-alt text-success"></i>&nbsp;Up',
value: function (rowData, rowIdx) {
return rowData[4].includes("Up");
return rowData[5].includes("Up");
},
},
{
label:
'<i class="bx bx-xs bx-down-arrow-alt text-danger"></i>&nbsp;Down',
value: function (rowData, rowIdx) {
return rowData[4].includes("Down");
return rowData[5].includes("Down");
},
},
{
label:
'<i class="bx bx-xs bxs-hourglass text-warning"></i>&nbsp;Loading',
value: function (rowData, rowIdx) {
return rowData[4].includes("Loading");
},
},
],
combiner: "or",
orderable: false,
},
targets: 4,
},
{
searchPanes: {
show: true,
options: [
{
label: '<i class="bx bx-xs bx-microchip"></i>&nbsp;Static',
value: function (rowData, rowIdx) {
return rowData[5].includes("Static");
},
},
{
label: '<i class="bx bx-xs bxl-docker"></i>&nbsp;Container',
value: function (rowData, rowIdx) {
return rowData[5].includes("Container");
},
},
{
label: '<i class="bx bx-xs bxl-kubernetes"></i>&nbsp;Pod',
value: function (rowData, rowIdx) {
return rowData[5].includes("Pod");
return rowData[5].includes("Loading");
},
},
],
@ -481,27 +458,21 @@ $(document).ready(function () {
show: true,
options: [
{
label: "Last 24 hours",
label: '<i class="bx bx-xs bx-microchip"></i>&nbsp;Static',
value: function (rowData, rowIdx) {
const date = new Date(rowData[6]);
const now = new Date();
return now - date < 24 * 60 * 60 * 1000;
return rowData[6].includes("Static");
},
},
{
label: "Last 7 days",
label: '<i class="bx bx-xs bxl-docker"></i>&nbsp;Container',
value: function (rowData, rowIdx) {
const date = new Date(rowData[6]);
const now = new Date();
return now - date < 7 * 24 * 60 * 60 * 1000;
return rowData[6].includes("Container");
},
},
{
label: "Last 30 days",
label: '<i class="bx bx-xs bxl-kubernetes"></i>&nbsp;Pod',
value: function (rowData, rowIdx) {
const date = new Date(rowData[6]);
const now = new Date();
return now - date < 30 * 24 * 60 * 60 * 1000;
return rowData[6].includes("Pod");
},
},
],
@ -544,14 +515,48 @@ $(document).ready(function () {
},
targets: 7,
},
{
searchPanes: {
show: true,
options: [
{
label: "Last 24 hours",
value: function (rowData, rowIdx) {
const date = new Date(rowData[8]);
const now = new Date();
return now - date < 24 * 60 * 60 * 1000;
},
},
{
label: "Last 7 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[8]);
const now = new Date();
return now - date < 7 * 24 * 60 * 60 * 1000;
},
},
{
label: "Last 30 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[8]);
const now = new Date();
return now - date < 30 * 24 * 60 * 60 * 1000;
},
},
],
combiner: "or",
orderable: false,
},
targets: 8,
},
],
order: [[7, "desc"]],
order: [[8, "desc"]],
autoFill: false,
responsive: true,
select: {
style: "multi+shift",
selector: "td:first-child",
headerCheckbox: false,
selector: "td:nth-child(2)",
headerCheckbox: true,
},
layout: layout,
language: {
@ -595,6 +600,8 @@ $(document).ready(function () {
$("#instances").removeClass("d-none");
$("#instances-waiting").addClass("visually-hidden");
instances_table.responsive.recalc();
instances_table.on("mouseenter", "td", function () {
if (instances_table.cell(this).index() === undefined) return;
const rowIdx = instances_table.cell(this).index().row;
@ -644,20 +651,6 @@ $(document).ready(function () {
)
.attr("data-bs-placement", "top")
.tooltip();
$("#select-all-rows").prop("checked", false);
}
});
// Event listener for the select-all checkbox
$("#select-all-rows").on("change", function () {
const isChecked = $(this).prop("checked");
if (isChecked) {
// Select all rows on the current page
instances_table.rows({ page: "current" }).select();
} else {
// Deselect all rows on the current page
instances_table.rows({ page: "current" }).deselect();
}
});

View file

@ -9,7 +9,7 @@ $(document).ready(function () {
viewTotal: true,
cascadePanes: true,
collapse: false,
columns: [2, 3, 4, 5, 6],
columns: [3, 4, 5, 6, 7],
},
},
topStart: {},
@ -50,13 +50,9 @@ $(document).ready(function () {
}
layout.topStart.buttons = [
{
extend: "toggle_filters",
className: "btn btn-sm btn-outline-primary toggle-filters",
},
{
extend: "colvis",
columns: "th:not(:first-child)",
columns: "th:not(:nth-child(-n+3))",
text: '<span class="tf-icons bx bx-columns bx-18px me-2"></span>Columns',
className: "btn btn-sm btn-outline-primary",
columnText: function (dt, idx, title) {
@ -65,19 +61,19 @@ $(document).ready(function () {
},
{
extend: "colvisRestore",
text: '<span class="tf-icons bx bx-reset bx-18px me-2"></span>Reset<span class="d-none d-md-inline"> columns</span>',
text: '<span class="tf-icons bx bx-reset bx-18px me-md-2"></span><span class="d-none d-md-inline">Reset columns</span>',
className: "btn btn-sm btn-outline-primary",
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-export bx-18px me-2"></span>Export',
text: '<span class="tf-icons bx bx-export bx-18px me-md-2"></span><span class="d-none d-md-inline">Export</span>',
className: "btn btn-sm btn-outline-primary",
buttons: [
{
extend: "copy",
text: '<span class="tf-icons bx bx-copy bx-18px me-2"></span>Copy visible',
exportOptions: {
columns: ":visible:not(:first-child):not(:last-child)",
columns: ":visible:not(:nth-child(-n+2)):not(:last-child)",
},
},
{
@ -89,7 +85,7 @@ $(document).ready(function () {
modifier: {
search: "none",
},
columns: ":not(:first-child):not(:last-child)",
columns: ":not(:nth-child(-n+2)):not(:last-child)",
},
},
{
@ -100,14 +96,14 @@ $(document).ready(function () {
modifier: {
search: "none",
},
columns: ":not(:first-child):not(:last-child)",
columns: ":not(:nth-child(-n+2)):not(:last-child)",
},
},
],
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-play bx-18px me-2"></span>Actions',
text: '<span class="tf-icons bx bx-play bx-18px me-md-2"></span><span class="d-none d-md-inline">Actions</span>',
className: "btn btn-sm btn-outline-primary action-button disabled",
buttons: [
{
@ -213,9 +209,14 @@ $(document).ready(function () {
columnDefs: [
{
orderable: false,
render: DataTable.render.select(),
className: "dtr-control",
targets: 0,
},
{
orderable: false,
render: DataTable.render.select(),
targets: 1,
},
{
orderable: false,
targets: -1,
@ -225,7 +226,7 @@ $(document).ready(function () {
show: true,
combiner: "or",
},
targets: [2],
targets: 3,
},
{
searchPanes: {
@ -235,48 +236,25 @@ $(document).ready(function () {
{
label: "Every day",
value: function (rowData, rowIdx) {
return rowData[3].includes("day");
return rowData[4].includes("day");
},
},
{
label: "Every hour",
value: function (rowData, rowIdx) {
return rowData[3].includes("hour");
return rowData[4].includes("hour");
},
},
{
label: "Every week",
value: function (rowData, rowIdx) {
return rowData[3].includes("week");
return rowData[4].includes("week");
},
},
{
label: "Once",
value: function (rowData, rowIdx) {
return rowData[3].includes("once");
},
},
],
combiner: "or",
orderable: false,
},
targets: 3,
},
{
searchPanes: {
show: true,
header: "Reload",
options: [
{
label: '<i class="bx bx-xs bx-x text-danger"></i>&nbsp;No',
value: function (rowData, rowIdx) {
return rowData[4].includes("bx-x");
},
},
{
label: '<i class="bx bx-xs bx-check text-success"></i>&nbsp;Yes',
value: function (rowData, rowIdx) {
return rowData[4].includes("bx-check");
return rowData[4].includes("once");
},
},
],
@ -288,7 +266,7 @@ $(document).ready(function () {
{
searchPanes: {
show: true,
header: "Async",
header: "Reload",
options: [
{
label: '<i class="bx bx-xs bx-x text-danger"></i>&nbsp;No',
@ -311,17 +289,16 @@ $(document).ready(function () {
{
searchPanes: {
show: true,
header: "Last run state",
header: "Async",
options: [
{
label: '<i class="bx bx-xs bx-x text-danger"></i>&nbsp;Failed',
label: '<i class="bx bx-xs bx-x text-danger"></i>&nbsp;No',
value: function (rowData, rowIdx) {
return rowData[6].includes("bx-x");
},
},
{
label:
'<i class="bx bx-xs bx-check text-success"></i>&nbsp;Success',
label: '<i class="bx bx-xs bx-check text-success"></i>&nbsp;Yes',
value: function (rowData, rowIdx) {
return rowData[6].includes("bx-check");
},
@ -332,14 +309,38 @@ $(document).ready(function () {
},
targets: 6,
},
{
searchPanes: {
show: true,
header: "Last run state",
options: [
{
label: '<i class="bx bx-xs bx-x text-danger"></i>&nbsp;Failed',
value: function (rowData, rowIdx) {
return rowData[7].includes("bx-x");
},
},
{
label:
'<i class="bx bx-xs bx-check text-success"></i>&nbsp;Success',
value: function (rowData, rowIdx) {
return rowData[7].includes("bx-check");
},
},
],
combiner: "or",
orderable: false,
},
targets: 7,
},
],
order: [[2, "asc"]],
order: [[3, "asc"]],
autoFill: false,
responsive: true,
select: {
style: "multi+shift",
selector: "td:first-child",
headerCheckbox: false,
selector: "td:nth-child(2)",
headerCheckbox: true,
},
layout: layout,
language: {
@ -375,6 +376,8 @@ $(document).ready(function () {
$("#jobs").removeClass("d-none");
$("#jobs-waiting").addClass("visually-hidden");
jobs_table.responsive.recalc();
jobs_table.on("mouseenter", "td", function () {
if (jobs_table.cell(this).index() === undefined) return;
const rowIdx = jobs_table.cell(this).index().row;
@ -424,20 +427,6 @@ $(document).ready(function () {
)
.attr("data-bs-placement", "top")
.tooltip();
$("#select-all-rows").prop("checked", false);
}
});
// Event listener for the select-all checkbox
$("#select-all-rows").on("change", function () {
const isChecked = $(this).prop("checked");
if (isChecked) {
// Select all rows on the current page
jobs_table.rows({ page: "current" }).select();
} else {
// Deselect all rows on the current page
jobs_table.rows({ page: "current" }).deselect();
}
});

View file

@ -24,23 +24,27 @@ $(document).ready(() => {
// Function to apply the theme
function applyTheme(theme) {
if (theme === "dark") {
$("html").removeClass("light-style").addClass("dark-style");
$("html")
.removeClass("light-style")
.addClass("dark-style dark")
.attr("data-bs-theme", "dark");
$(".bs-toast.bg-white").addClass("bg-dark").removeClass("bg-white");
$(".bg-light-subtle")
.addClass("bg-dark-subtle")
.removeClass("bg-light-subtle");
$("#dark-mode-toggle").prop("checked", true);
$("html").attr("data-bs-theme", "dark");
$("[alt='BunkerWeb logo']").attr("src", $("#bw-logo-white").val());
$("[alt='User Avatar']").attr("src", $("#avatar-url-white").val());
} else {
$("html").removeClass("dark-style").addClass("light-style");
$("html")
.removeClass("dark-style dark")
.addClass("light-style")
.attr("data-bs-theme", null);
$(".bs-toast.bg-dark").addClass("bg-white").removeClass("bg-dark");
$(".bg-dark-subtle")
.addClass("bg-light-subtle")
.removeClass("bg-dark-subtle");
$("#dark-mode-toggle").prop("checked", false);
$("html").attr("data-bs-theme", null);
$("[alt='BunkerWeb logo']").attr("src", $("#bw-logo").val());
$("[alt='User Avatar']").attr("src", $("#avatar-url").val());
}

View file

@ -156,7 +156,7 @@ $(document).ready(function () {
viewTotal: true,
cascadePanes: true,
collapse: false,
columns: [5, 6, 7],
columns: [6, 7, 8],
},
},
topStart: {},
@ -202,8 +202,8 @@ $(document).ready(function () {
},
{
extend: "colvis",
columns: "th:not(:first-child):not(:nth-child(2)):not(:last-child)",
text: '<span class="tf-icons bx bx-columns bx-18px me-2"></span>Columns',
columns: "th:not(:nth-child(-n+3))",
text: '<span class="tf-icons bx bx-columns bx-18px me-md-2"></span><span class="d-none d-md-inline">Columns</span>',
className: "btn btn-sm btn-outline-primary rounded-start",
columnText: function (dt, idx, title) {
return idx + 1 + ". " + title;
@ -211,19 +211,19 @@ $(document).ready(function () {
},
{
extend: "colvisRestore",
text: '<span class="tf-icons bx bx-reset bx-18px me-2"></span>Reset<span class="d-none d-md-inline"> columns</span>',
className: "btn btn-sm btn-outline-primary",
text: '<span class="tf-icons bx bx-reset bx-18px me-2"></span>Reset columns',
className: "btn btn-sm btn-outline-primary d-none d-md-inline",
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-export bx-18px me-2"></span>Export',
text: '<span class="tf-icons bx bx-export bx-18px me-md-2"></span><span class="d-none d-md-inline">Export</span>',
className: "btn btn-sm btn-outline-primary",
buttons: [
{
extend: "copy",
text: '<span class="tf-icons bx bx-copy bx-18px me-2"></span>Copy visible',
exportOptions: {
columns: ":visible:not(:first-child):not(:last-child)",
columns: ":visible:not(:nth-child(-n+2)):not(:last-child)",
},
},
{
@ -235,7 +235,7 @@ $(document).ready(function () {
modifier: {
search: "none",
},
columns: ":not(:first-child):not(:last-child)",
columns: ":not(:nth-child(-n+2)):not(:last-child)",
},
},
{
@ -246,14 +246,14 @@ $(document).ready(function () {
modifier: {
search: "none",
},
columns: ":not(:first-child):not(:last-child)",
columns: ":not(:nth-child(-n+2)):not(:last-child)",
},
},
],
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-play bx-18px me-2"></span>Actions',
text: '<span class="tf-icons bx bx-play bx-18px me-md-2"></span><span class="d-none d-md-inline">Actions</span>',
className: "btn btn-sm btn-outline-primary action-button disabled",
buttons: [
{
@ -272,7 +272,7 @@ $(document).ready(function () {
const getSelectedPlugins = () => {
const plugins = [];
$("tr.selected").each(function () {
const plugin = $(this).find("td:eq(1)").data("id");
const plugin = $(this).find("td:eq(2)").data("id");
if (plugin) {
plugins.push(plugin);
}
@ -290,7 +290,7 @@ $(document).ready(function () {
};
$.fn.dataTable.ext.buttons.add_plugin = {
text: '<span class="tf-icons bx bx-plus"></span>&nbsp;Add<span class="d-none d-md-inline"> plugin(s)</span>',
text: '<span class="tf-icons bx bx-plus"></span><span class="d-none d-md-inline">&nbsp;Add plugin(s)</span>',
className: `btn btn-sm rounded me-4 btn-bw-green${
isReadOnly ? " disabled" : ""
}`,
@ -334,16 +334,21 @@ $(document).ready(function () {
columnDefs: [
{
orderable: false,
render: DataTable.render.select(),
className: "dtr-control",
targets: 0,
},
{
orderable: false,
render: DataTable.render.select(),
targets: 1,
},
{
orderable: false,
targets: -1,
},
{
visible: false,
targets: [1, 3],
targets: [2, 4],
},
{
searchPanes: {
@ -353,56 +358,20 @@ $(document).ready(function () {
{
label: '<i class="bx bx-xs bx-x text-danger"></i>&nbsp;No',
value: function (rowData, rowIdx) {
return rowData[5].includes("bx-x");
return rowData[6].includes("bx-x");
},
},
{
label: '<i class="bx bx-xs bx-check text-success"></i>&nbsp;Yes',
value: function (rowData, rowIdx) {
return rowData[5].includes("bx-check");
return rowData[6].includes("bx-check");
},
},
{
label:
'<i class="bx bx-xs bx-minus text-warning"></i>&nbsp;Partial',
value: function (rowData, rowIdx) {
return rowData[5].includes("bx-minus");
},
},
],
combiner: "or",
orderable: false,
},
targets: 5,
},
{
searchPanes: {
show: true,
options: [
{
label: `<img src="${$("#pro_diamond_url")
.val()
.trim()}" alt="Pro plugin" width="16px" height="12.9125px" class="mb-1">&nbsp;PRO`,
value: function (rowData, rowIdx) {
return rowData[6].includes("PRO");
},
},
{
label: '<i class="bx bx-plug bx-xs"></i>&nbsp;External',
value: function (rowData, rowIdx) {
return rowData[6].includes("EXTERNAL");
},
},
{
label: '<i class="bx bx-cloud-upload bx-xs"></i>&nbsp;UI',
value: function (rowData, rowIdx) {
return rowData[6].includes("UI");
},
},
{
label: '<i class="bx bx-shield bx-xs"></i>&nbsp;Core',
value: function (rowData, rowIdx) {
return rowData[6].includes("CORE");
return rowData[6].includes("bx-minus");
},
},
],
@ -414,19 +383,55 @@ $(document).ready(function () {
{
searchPanes: {
show: true,
options: [
{
label: `<img src="${$("#pro_diamond_url")
.val()
.trim()}" alt="Pro plugin" width="16px" height="12.9125px" class="mb-1">&nbsp;PRO`,
value: function (rowData, rowIdx) {
return rowData[7].includes("PRO");
},
},
{
label: '<i class="bx bx-plug bx-xs"></i>&nbsp;External',
value: function (rowData, rowIdx) {
return rowData[7].includes("EXTERNAL");
},
},
{
label: '<i class="bx bx-cloud-upload bx-xs"></i>&nbsp;UI',
value: function (rowData, rowIdx) {
return rowData[7].includes("UI");
},
},
{
label: '<i class="bx bx-shield bx-xs"></i>&nbsp;Core',
value: function (rowData, rowIdx) {
return rowData[7].includes("CORE");
},
},
],
combiner: "or",
orderable: false,
},
targets: 7,
},
{
searchPanes: {
show: true,
combiner: "or",
orderable: false,
},
targets: 8,
},
],
order: [[2, "asc"]],
order: [[3, "asc"]],
autoFill: false,
responsive: true,
select: {
style: "multi+shift",
selector: "td:first-child",
headerCheckbox: false,
selector: "td:nth-child(2)",
headerCheckbox: true,
},
layout: layout,
language: {
@ -470,6 +475,8 @@ $(document).ready(function () {
$("#plugins").removeClass("d-none");
$("#plugins-waiting").addClass("visually-hidden");
plugins_table.responsive.recalc();
plugins_table.on("mouseenter", "td", function () {
if (plugins_table.cell(this).index() === undefined) return;
const rowIdx = plugins_table.cell(this).index().row;
@ -519,20 +526,6 @@ $(document).ready(function () {
)
.attr("data-bs-placement", "top")
.tooltip();
$("#select-all-rows").prop("checked", false);
}
});
// Event listener for the select-all checkbox
$("#select-all-rows").on("change", function () {
const isChecked = $(this).prop("checked");
if (isChecked) {
// Select all rows on the current page
plugins_table.rows({ page: "current" }).select();
} else {
// Deselect all rows on the current page
plugins_table.rows({ page: "current" }).deselect();
}
});

View file

@ -6,279 +6,278 @@ $(function () {
const baseFlagsUrl = $("#base_flags_url").val().trim();
const countriesDataNames = {
AD: "Andorra",
AE: "United Arab Emirates",
AF: "Afghanistan",
AG: "Antigua and Barbuda",
AI: "Anguilla",
AL: "Albania",
AM: "Armenia",
AO: "Angola",
AQ: "Antarctica",
AR: "Argentina",
AS: "American Samoa",
AT: "Austria",
AU: "Australia",
AW: "Aruba",
AX: "Åland Islands",
AZ: "Azerbaijan",
BA: "Bosnia and Herzegovina",
BB: "Barbados",
BD: "Bangladesh",
BE: "Belgium",
BF: "Burkina Faso",
BG: "Bulgaria",
BH: "Bahrain",
BI: "Burundi",
BJ: "Benin",
BL: "Saint Barthélemy",
BM: "Bermuda",
BN: "Brunei Darussalam",
BO: "Bolivia, Plurinational State of",
BQ: "Caribbean Netherlands",
BR: "Brazil",
BS: "Bahamas",
BT: "Bhutan",
BV: "Bouvet Island",
BW: "Botswana",
BY: "Belarus",
BZ: "Belize",
CA: "Canada",
CC: "Cocos (Keeling) Islands",
CD: "Congo, the Democratic Republic of the",
CF: "Central African Republic",
CG: "Republic of the Congo",
CH: "Switzerland",
CI: "Côte d'Ivoire",
CK: "Cook Islands",
CL: "Chile",
CM: "Cameroon",
CN: "China (People's Republic of China)",
CO: "Colombia",
CR: "Costa Rica",
CU: "Cuba",
CV: "Cape Verde",
CW: "Curaçao",
CX: "Christmas Island",
CY: "Cyprus",
CZ: "Czech Republic",
DE: "Germany",
DJ: "Djibouti",
DK: "Denmark",
DM: "Dominica",
DO: "Dominican Republic",
DZ: "Algeria",
EC: "Ecuador",
EE: "Estonia",
EG: "Egypt",
EH: "Western Sahara",
ER: "Eritrea",
ES: "Spain",
ET: "Ethiopia",
EU: "Europe",
FI: "Finland",
FJ: "Fiji",
FK: "Falkland Islands (Malvinas)",
FM: "Micronesia, Federated States of",
FO: "Faroe Islands",
FR: "France",
GA: "Gabon",
GB: "United Kingdom",
GD: "Grenada",
GE: "Georgia",
GF: "French Guiana",
GG: "Guernsey",
GH: "Ghana",
GI: "Gibraltar",
GL: "Greenland",
GM: "Gambia",
GN: "Guinea",
GP: "Guadeloupe",
GQ: "Equatorial Guinea",
GR: "Greece",
GS: "South Georgia and the South Sandwich Islands",
GT: "Guatemala",
GU: "Guam",
GW: "Guinea-Bissau",
GY: "Guyana",
HK: "Hong Kong",
HM: "Heard Island and McDonald Islands",
HN: "Honduras",
HR: "Croatia",
HT: "Haiti",
HU: "Hungary",
ID: "Indonesia",
IE: "Ireland",
IL: "Israel",
IM: "Isle of Man",
IN: "India",
IO: "British Indian Ocean Territory",
IQ: "Iraq",
IR: "Iran, Islamic Republic of",
IS: "Iceland",
IT: "Italy",
JE: "Jersey",
JM: "Jamaica",
JO: "Jordan",
JP: "Japan",
KE: "Kenya",
KG: "Kyrgyzstan",
KH: "Cambodia",
KI: "Kiribati",
KM: "Comoros",
KN: "Saint Kitts and Nevis",
KP: "Korea, Democratic People's Republic of",
KR: "Korea, Republic of",
KW: "Kuwait",
KY: "Cayman Islands",
KZ: "Kazakhstan",
LA: "Laos (Lao People's Democratic Republic)",
LB: "Lebanon",
LC: "Saint Lucia",
LI: "Liechtenstein",
LK: "Sri Lanka",
LR: "Liberia",
LS: "Lesotho",
LT: "Lithuania",
LU: "Luxembourg",
LV: "Latvia",
LY: "Libya",
MA: "Morocco",
MC: "Monaco",
MD: "Moldova, Republic of",
ME: "Montenegro",
MF: "Saint Martin",
MG: "Madagascar",
MH: "Marshall Islands",
MK: "North Macedonia",
ML: "Mali",
MM: "Myanmar",
MN: "Mongolia",
MO: "Macao",
MP: "Northern Mariana Islands",
MQ: "Martinique",
MR: "Mauritania",
MS: "Montserrat",
MT: "Malta",
MU: "Mauritius",
MV: "Maldives",
MW: "Malawi",
MX: "Mexico",
MY: "Malaysia",
MZ: "Mozambique",
NA: "Namibia",
NC: "New Caledonia",
NE: "Niger",
NF: "Norfolk Island",
NG: "Nigeria",
NI: "Nicaragua",
NL: "Netherlands",
NO: "Norway",
NP: "Nepal",
NR: "Nauru",
NU: "Niue",
NZ: "New Zealand",
OM: "Oman",
PA: "Panama",
PE: "Peru",
PF: "French Polynesia",
PG: "Papua New Guinea",
PH: "Philippines",
PK: "Pakistan",
PL: "Poland",
PM: "Saint Pierre and Miquelon",
PN: "Pitcairn",
PR: "Puerto Rico",
PS: "Palestine",
PT: "Portugal",
PW: "Palau",
PY: "Paraguay",
QA: "Qatar",
RE: "Réunion",
RO: "Romania",
RS: "Serbia",
RU: "Russian Federation",
RW: "Rwanda",
SA: "Saudi Arabia",
SB: "Solomon Islands",
SC: "Seychelles",
SD: "Sudan",
SE: "Sweden",
SG: "Singapore",
SH: "Saint Helena, Ascension and Tristan da Cunha",
SI: "Slovenia",
SJ: "Svalbard and Jan Mayen Islands",
SK: "Slovakia",
SL: "Sierra Leone",
SM: "San Marino",
SN: "Senegal",
SO: "Somalia",
SR: "Suriname",
SS: "South Sudan",
ST: "Sao Tome and Principe",
SV: "El Salvador",
SX: "Sint Maarten (Dutch part)",
SY: "Syrian Arab Republic",
SZ: "Swaziland",
TC: "Turks and Caicos Islands",
TD: "Chad",
TF: "French Southern Territories",
TG: "Togo",
TH: "Thailand",
TJ: "Tajikistan",
TK: "Tokelau",
TL: "Timor-Leste",
TM: "Turkmenistan",
TN: "Tunisia",
TO: "Tonga",
TR: "Turkey",
TT: "Trinidad and Tobago",
TV: "Tuvalu",
TW: "Taiwan (Republic of China)",
TZ: "Tanzania, United Republic of",
UA: "Ukraine",
UG: "Uganda",
UM: "US Minor Outlying Islands",
US: "United States",
UY: "Uruguay",
UZ: "Uzbekistan",
VA: "Holy See (Vatican City State)",
VC: "Saint Vincent and the Grenadines",
VE: "Venezuela, Bolivarian Republic of",
VG: "Virgin Islands, British",
VI: "Virgin Islands, U.S.",
VN: "Vietnam",
VU: "Vanuatu",
WF: "Wallis and Futuna Islands",
WS: "Samoa",
XK: "Kosovo",
YE: "Yemen",
YT: "Mayotte",
ZA: "South Africa",
ZM: "Zambia",
ZW: "Zimbabwe",
ad: "Andorra",
ae: "United Arab Emirates",
af: "Afghanistan",
ag: "Antigua and Barbuda",
ai: "Anguilla",
al: "Albania",
am: "Armenia",
ao: "Angola",
aq: "Antarctica",
ar: "Argentina",
as: "American Samoa",
at: "Austria",
au: "Australia",
aw: "Aruba",
ax: "Åland Islands",
az: "Azerbaijan",
ba: "Bosnia and Herzegovina",
bb: "Barbados",
bd: "Bangladesh",
be: "Belgium",
bf: "Burkina Faso",
bg: "Bulgaria",
bh: "Bahrain",
bi: "Burundi",
bj: "Benin",
bl: "Saint Barthélemy",
bm: "Bermuda",
bn: "Brunei Darussalam",
bo: "Bolivia, Plurinational State of",
bq: "Caribbean Netherlands",
br: "Brazil",
bs: "Bahamas",
bt: "Bhutan",
bv: "Bouvet Island",
bw: "Botswana",
by: "Belarus",
bz: "Belize",
ca: "Canada",
cc: "Cocos (Keeling) Islands",
cd: "Congo, the Democratic Republic of the",
cf: "Central African Republic",
cg: "Republic of the Congo",
ch: "Switzerland",
ci: "Côte d'Ivoire",
ck: "Cook Islands",
cl: "Chile",
cm: "Cameroon",
cn: "China (People's Republic of China)",
co: "Colombia",
cr: "Costa Rica",
cu: "Cuba",
cv: "Cape Verde",
cw: "Curaçao",
cx: "Christmas Island",
cy: "Cyprus",
cz: "Czech Republic",
de: "Germany",
dj: "Djibouti",
dk: "Denmark",
dm: "Dominica",
do: "Dominican Republic",
dz: "Algeria",
ec: "Ecuador",
ee: "Estonia",
eg: "Egypt",
eh: "Western Sahara",
er: "Eritrea",
es: "Spain",
et: "Ethiopia",
eu: "Europe",
fi: "Finland",
fj: "Fiji",
fk: "Falkland Islands (Malvinas)",
fm: "Micronesia, Federated States of",
fo: "Faroe Islands",
fr: "France",
ga: "Gabon",
gb: "United Kingdom",
gd: "Grenada",
ge: "Georgia",
gf: "French Guiana",
gg: "Guernsey",
gh: "Ghana",
gi: "Gibraltar",
gl: "Greenland",
gm: "Gambia",
gn: "Guinea",
gp: "Guadeloupe",
gq: "Equatorial Guinea",
gr: "Greece",
gs: "South Georgia and the South Sandwich Islands",
gt: "Guatemala",
gu: "Guam",
gw: "Guinea-Bissau",
gy: "Guyana",
hk: "Hong Kong",
hm: "Heard Island and McDonald Islands",
hn: "Honduras",
hr: "Croatia",
ht: "Haiti",
hu: "Hungary",
id: "Indonesia",
ie: "Ireland",
il: "Israel",
im: "Isle of Man",
in: "India",
io: "British Indian Ocean Territory",
iq: "Iraq",
ir: "Iran, Islamic Republic of",
is: "Iceland",
it: "Italy",
je: "Jersey",
jm: "Jamaica",
jo: "Jordan",
jp: "Japan",
ke: "Kenya",
kg: "Kyrgyzstan",
kh: "Cambodia",
ki: "Kiribati",
km: "Comoros",
kn: "Saint Kitts and Nevis",
kp: "Korea, Democratic People's Republic of",
kr: "Korea, Republic of",
kw: "Kuwait",
ky: "Cayman Islands",
kz: "Kazakhstan",
la: "Laos (Lao People's Democratic Republic)",
lb: "Lebanon",
lc: "Saint Lucia",
li: "Liechtenstein",
lk: "Sri Lanka",
lr: "Liberia",
ls: "Lesotho",
lt: "Lithuania",
lu: "Luxembourg",
lv: "Latvia",
ly: "Libya",
ma: "Morocco",
mc: "Monaco",
md: "Moldova, Republic of",
me: "Montenegro",
mf: "Saint Martin",
mg: "Madagascar",
mh: "Marshall Islands",
mk: "North Macedonia",
ml: "Mali",
mm: "Myanmar",
mn: "Mongolia",
mo: "Macao",
mp: "Northern Mariana Islands",
mq: "Martinique",
mr: "Mauritania",
ms: "Montserrat",
mt: "Malta",
mu: "Mauritius",
mv: "Maldives",
mw: "Malawi",
mx: "Mexico",
my: "Malaysia",
mz: "Mozambique",
na: "Namibia",
nc: "New Caledonia",
ne: "Niger",
nf: "Norfolk Island",
ng: "Nigeria",
ni: "Nicaragua",
nl: "Netherlands",
no: "Norway",
np: "Nepal",
nr: "Nauru",
nu: "Niue",
nz: "New Zealand",
om: "Oman",
pa: "Panama",
pe: "Peru",
pf: "French Polynesia",
pg: "Papua New Guinea",
ph: "Philippines",
pk: "Pakistan",
pl: "Poland",
pm: "Saint Pierre and Miquelon",
pn: "Pitcairn",
pr: "Puerto Rico",
ps: "Palestine",
pt: "Portugal",
pw: "Palau",
py: "Paraguay",
qa: "Qatar",
re: "Réunion",
ro: "Romania",
rs: "Serbia",
ru: "Russian Federation",
rw: "Rwanda",
sa: "Saudi Arabia",
sb: "Solomon Islands",
sc: "Seychelles",
sd: "Sudan",
se: "Sweden",
sg: "Singapore",
sh: "Saint Helena, Ascension and Tristan da Cunha",
si: "Slovenia",
sj: "Svalbard and Jan Mayen Islands",
sk: "Slovakia",
sl: "Sierra Leone",
sm: "San Marino",
sn: "Senegal",
so: "Somalia",
sr: "Suriname",
ss: "South Sudan",
st: "Sao Tome and Principe",
sv: "El Salvador",
sx: "Sint Maarten (Dutch part)",
sy: "Syrian Arab Republic",
sz: "Swaziland",
tc: "Turks and Caicos Islands",
td: "Chad",
tf: "French Southern Territories",
tg: "Togo",
th: "Thailand",
tj: "Tajikistan",
tk: "Tokelau",
tl: "Timor-Leste",
tm: "Turkmenistan",
tn: "Tunisia",
to: "Tonga",
tr: "Turkey",
tt: "Trinidad and Tobago",
tv: "Tuvalu",
tw: "Taiwan (Republic of China)",
tz: "Tanzania, United Republic of",
ua: "Ukraine",
ug: "Uganda",
um: "US Minor Outlying Islands",
us: "United States",
uy: "Uruguay",
uz: "Uzbekistan",
va: "Holy See (Vatican City State)",
vc: "Saint Vincent and the Grenadines",
ve: "Venezuela, Bolivarian Republic of",
vg: "Virgin Islands, British",
vi: "Virgin Islands, U.S.",
vn: "Vietnam",
vu: "Vanuatu",
wf: "Wallis and Futuna Islands",
ws: "Samoa",
xk: "Kosovo",
ye: "Yemen",
yt: "Mayotte",
za: "South Africa",
zm: "Zambia",
zw: "Zimbabwe",
};
// Filter countriesDataNames to include only necessary countries
const filteredCountriesDataNames = dataCountries.reduce((obj, code) => {
// Precompute filtered options using jQuery's map for efficiency
const countriesSearchPanesOptions = $.map(dataCountries, function (code) {
if (countriesDataNames[code]) {
obj[code] = countriesDataNames[code];
return {
label: `<img src="${baseFlagsUrl}/${code}.svg" class="border border-1 p-0 me-1" height="17" />&nbsp;&nbsp;${countriesDataNames[code]}`,
value: function (rowData) {
return rowData[3].indexOf(`${code}.svg`) !== -1;
},
};
}
return obj;
}, {});
});
// Assuming baseFlagsUrl, dataCountries, and countriesDataNames are defined
const countriesSearchPanesOptions = [
{
label: `<img src="${baseFlagsUrl}/zz.svg" class="border border-1 p-0 me-1" height="17" />&nbsp;&nbsp;N/A`,
value: (rowData) => rowData[2].includes("N/A"),
// Append the "N/A" option first
countriesSearchPanesOptions.unshift({
label: `<img src="${baseFlagsUrl}/zz.svg" class="border border-1 p-0 me-1" height="17" />&nbsp;&nbsp;N/A`,
value: function (rowData) {
return rowData[3].indexOf("N/A") !== -1;
},
...Object.entries(filteredCountriesDataNames).map(([code, name]) => ({
label: `<img src="${baseFlagsUrl}/${code.toLowerCase()}.svg" class="border border-1 p-0 me-1" height="17" />&nbsp;&nbsp;${name}`,
value: (rowData) =>
rowData[2].includes(`data-bs-original-title="${code}"`),
})),
];
});
// Batch update tooltips
const updateCountryTooltips = () => {
@ -301,7 +300,7 @@ $(function () {
viewTotal: true,
cascadePanes: true,
collapse: false,
columns: [1, 2, 3, 4, 5, 7, 8, 10],
columns: [2, 3, 4, 5, 6, 8, 9, 11],
},
},
topStart: {},
@ -344,26 +343,28 @@ $(function () {
layout.topStart.buttons = [
{
extend: "colvis",
columns: "th:not(:first-child):not(:last-child)",
columns: "th:not(:nth-child(-n+3))",
text: '<span class="tf-icons bx bx-columns bx-18px me-2"></span>Columns',
className: "btn btn-sm btn-outline-primary",
columnText: (dt, idx, title) => `${idx + 1}. ${title}`,
columnText: function (dt, idx, title) {
return idx + 1 + ". " + title;
},
},
{
extend: "colvisRestore",
text: '<span class="tf-icons bx bx-reset bx-18px me-2"></span>Reset<span class="d-none d-md-inline"> columns</span>',
text: '<span class="tf-icons bx bx-reset bx-18px me-md-2"></span><span class="d-none d-md-inline">Reset columns</span>',
className: "btn btn-sm btn-outline-primary",
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-export bx-18px me-2"></span>Export',
text: '<span class="tf-icons bx bx-export bx-18px me-md-2"></span><span class="d-none d-md-inline">Export</span>',
className: "btn btn-sm btn-outline-primary",
buttons: [
{
extend: "copy",
text: '<span class="tf-icons bx bx-copy bx-18px me-2"></span>Copy visible',
exportOptions: {
columns: ":visible:not(:first-child):not(:last-child)",
columns: ":visible:not(:first-child)",
},
},
{
@ -373,6 +374,7 @@ $(function () {
filename: "bw_report",
exportOptions: {
modifier: { search: "none" },
columns: ":not(:first-child)",
},
},
{
@ -381,6 +383,7 @@ $(function () {
filename: "bw_report",
exportOptions: {
modifier: { search: "none" },
columns: ":not(:first-child)",
},
},
],
@ -435,11 +438,15 @@ $(function () {
// Initialize DataTable
const reports_table = new DataTable("#reports", {
columnDefs: [
{ orderable: false, targets: -1 },
{ visible: false, targets: [3, 4, 5, 6, 9] },
{ type: "ip-address", targets: 1 },
{
orderable: false,
className: "dtr-control",
targets: 0,
},
{ orderable: false, targets: -1 },
{ visible: false, targets: [4, 5, 6, 7, 10] },
{ type: "ip-address", targets: 2 },
{
render: function (data, type, row) {
if (type === "display" || type === "filter") {
const date = new Date(data);
@ -449,6 +456,7 @@ $(function () {
}
return data;
},
targets: 1,
},
{
searchPanes: {
@ -456,14 +464,14 @@ $(function () {
combiner: "or",
options: countriesSearchPanesOptions,
},
targets: 2,
targets: 3,
},
{
searchPanes: { show: true },
targets: [1, 2, 3, 4, 5, 7, 8, 10],
targets: [2, 4, 5, 6, 8, 9, 11],
},
],
order: [[0, "desc"]],
order: [[1, "desc"]],
autoFill: false,
responsive: true,
layout: layout,
@ -473,13 +481,6 @@ $(function () {
infoFiltered: "(filtered from _MAX_ total reports)",
lengthMenu: "Display _MENU_ reports",
zeroRecords: "No matching reports found",
select: {
rows: {
_: "Selected %d reports",
0: "No reports selected",
1: "Selected 1 report",
},
},
},
initComplete: () => {
$("#reports_wrapper").find(".btn-secondary").removeClass("btn-secondary");
@ -500,6 +501,8 @@ $(function () {
$("#reports").removeClass("d-none");
$("#reports-waiting").addClass("visually-hidden");
reports_table.responsive.recalc();
// Update tooltips after table draw
reports_table.on("draw.dt", updateCountryTooltips);

View file

@ -90,7 +90,7 @@ $(function () {
viewTotal: true,
cascadePanes: true,
collapse: false,
columns: [2, 3, 4, 5],
columns: [3, 4, 5, 6],
},
},
topStart: {},
@ -130,26 +130,26 @@ $(function () {
},
{
extend: "colvis",
columns: "th:not(:first-child):not(:nth-child(2)):not(:last-child)",
text: '<span class="tf-icons bx bx-columns bx-18px me-2"></span>Columns',
columns: "th:not(:nth-child(-n+3))",
text: '<span class="tf-icons bx bx-columns bx-18px me-md-2"></span><span class="d-none d-md-inline">Columns</span>',
className: "btn btn-sm btn-outline-primary rounded-start",
columnText: (dt, idx, title) => `${idx + 1}. ${title}`,
},
{
extend: "colvisRestore",
text: '<span class="tf-icons bx bx-reset bx-18px me-2"></span>Reset<span class="d-none d-md-inline"> columns</span>',
className: "btn btn-sm btn-outline-primary",
text: '<span class="tf-icons bx bx-reset bx-18px me-2"></span>Reset columns',
className: "btn btn-sm btn-outline-primary d-none d-md-inline",
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-export bx-18px me-2"></span>Export',
text: '<span class="tf-icons bx bx-export bx-18px me-md-2"></span><span class="d-none d-md-inline">Export</span>',
className: "btn btn-sm btn-outline-primary",
buttons: [
{
extend: "copy",
text: '<span class="tf-icons bx bx-copy bx-18px me-2"></span>Copy visible',
exportOptions: {
columns: ":visible:not(:first-child):not(:last-child)",
columns: ":visible:not(:nth-child(-n+2)):not(:last-child)",
},
},
{
@ -159,7 +159,7 @@ $(function () {
filename: "bw_services",
exportOptions: {
modifier: { search: "none" },
columns: ":not(:first-child):not(:last-child)",
columns: ":not(:nth-child(-n+2)):not(:last-child)",
},
},
{
@ -168,14 +168,14 @@ $(function () {
filename: "bw_services",
exportOptions: {
modifier: { search: "none" },
columns: ":not(:first-child):not(:last-child)",
columns: ":not(:nth-child(-n+2)):not(:last-child)",
},
},
],
},
{
extend: "collection",
text: '<span class="tf-icons bx bx-play bx-18px me-2"></span>Actions',
text: '<span class="tf-icons bx bx-play bx-18px me-md-2"></span><span class="d-none d-md-inline">Actions</span>',
className: "btn btn-sm btn-outline-primary action-button disabled",
buttons: [
{
@ -223,7 +223,7 @@ $(function () {
const getSelectedServices = () =>
$("tr.selected")
.map(function () {
return $(this).find("td:eq(1) a").text().trim();
return $(this).find("td:eq(2) a").text().trim();
})
.get();
@ -237,7 +237,7 @@ $(function () {
};
$.fn.dataTable.ext.buttons.create_service = {
text: '<span class="tf-icons bx bx-plus"></span>&nbsp;Create<span class="d-none d-md-inline"> new service</span>',
text: '<span class="tf-icons bx bx-plus"></span><span class="d-none d-md-inline">&nbsp;Create new service</span>',
className: `btn btn-sm rounded me-4 btn-bw-green${
isReadOnly ? " disabled" : ""
}`,
@ -336,10 +336,19 @@ $(function () {
const services_table = new DataTable("#services", {
columnDefs: [
{ orderable: false, render: DataTable.render.select(), targets: 0 },
{
orderable: false,
className: "dtr-control",
targets: 0,
},
{
orderable: false,
render: DataTable.render.select(),
targets: 1,
},
{ orderable: false, targets: -1 },
{
targets: [4, 5],
targets: [5, 6],
render: function (data, type, row) {
if (type === "display" || type === "filter") {
const date = new Date(data);
@ -356,44 +365,21 @@ $(function () {
options: [
{
label: '<i class="bx bx-xs bx-globe"></i>&nbsp;Online',
value: (rowData) => rowData[2].includes("Online"),
value: (rowData) => rowData[3].includes("Online"),
},
{
label: '<i class="bx bx-xs bx-file-blank"></i>&nbsp;Draft',
value: (rowData) => rowData[2].includes("Draft"),
value: (rowData) => rowData[3].includes("Draft"),
},
],
combiner: "or",
orderable: false,
},
targets: 2,
},
{
searchPanes: {
show: true,
combiner: "or",
orderable: false,
},
targets: 3,
},
{
searchPanes: {
show: true,
options: [
{
label: "Last 24 hours",
value: (rowData) => new Date() - new Date(rowData[4]) < 86400000,
},
{
label: "Last 7 days",
value: (rowData) => new Date() - new Date(rowData[4]) < 604800000,
},
{
label: "Last 30 days",
value: (rowData) =>
new Date() - new Date(rowData[4]) < 2592000000,
},
],
combiner: "or",
orderable: false,
},
@ -422,14 +408,37 @@ $(function () {
},
targets: 5,
},
{
searchPanes: {
show: true,
options: [
{
label: "Last 24 hours",
value: (rowData) => new Date() - new Date(rowData[6]) < 86400000,
},
{
label: "Last 7 days",
value: (rowData) => new Date() - new Date(rowData[6]) < 604800000,
},
{
label: "Last 30 days",
value: (rowData) =>
new Date() - new Date(rowData[6]) < 2592000000,
},
],
combiner: "or",
orderable: false,
},
targets: 6,
},
],
order: [[1, "asc"]],
order: [[2, "asc"]],
autoFill: false,
responsive: true,
select: {
style: "multi+shift",
selector: "td:first-child",
headerCheckbox: false,
selector: "td:nth-child(2)",
headerCheckbox: true,
},
layout: layout,
language: {
@ -482,6 +491,8 @@ $(function () {
$("#services").removeClass("d-none");
$("#services-waiting").addClass("visually-hidden");
services_table.responsive.recalc();
services_table.on("mouseenter", "td", function () {
if (services_table.cell(this).index() === undefined) return;
const rowIdx = services_table.cell(this).index().row;
@ -531,27 +542,9 @@ $(function () {
)
.attr("data-bs-placement", "top")
.tooltip();
$("#select-all-rows").prop("checked", false);
}
});
// Event listener for the select-all checkbox
$("#select-all-rows").on("change", function () {
const isChecked = $(this).prop("checked");
const rows = services_table.rows({ page: "current" });
isChecked ? rows.select() : rows.deselect();
});
$(document).on("click", ".convert-service", function () {
if (isReadOnly) {
alert("This action is not allowed in read-only mode.");
return;
}
const service = $(this).data("service-id");
const conversionType = $(this).data("value");
setupConversionModal([service], conversionType);
});
$(document).on("click", ".delete-service", function () {
if (isReadOnly) {
alert("This action is not allowed in read-only mode.");

View file

@ -429,7 +429,10 @@ $(document).ready(() => {
const darkMode = $(this).prop("checked");
if (darkMode) {
$("html").removeClass("light-style").addClass("dark-style");
$("html")
.removeClass("light-style")
.addClass("dark-style dark")
.attr("data-bs-theme", "dark");
$(".btn-outline-dark")
.addClass("btn-outline-light")
.removeClass("btn-outline-dark");
@ -438,12 +441,14 @@ $(document).ready(() => {
$(".bg-light-subtle")
.addClass("bg-dark-subtle")
.removeClass("bg-light-subtle");
$("html").attr("data-bs-theme", "dark");
$(".dark-mode-toggle-icon").removeClass("bx-sun").addClass("bx-moon");
$("[alt='BunkerWeb logo']").attr("src", $("#bw-logo-white").val());
$("[alt='User Avatar']").attr("src", $("#avatar-url-white").val());
} else {
$("html").removeClass("dark-style").addClass("light-style");
$("html")
.removeClass("dark-style dark")
.addClass("light-style")
.attr("data-bs-theme", null);
$(".btn-outline-light")
.addClass("btn-outline-dark")
.removeClass("btn-outline-light");
@ -452,7 +457,6 @@ $(document).ready(() => {
$(".bg-dark-subtle")
.addClass("bg-light-subtle")
.removeClass("bg-dark-subtle");
$("html").attr("data-bs-theme", null);
$(".dark-mode-toggle-icon").removeClass("bx-moon").addClass("bx-sun");
$("[alt='BunkerWeb logo']").attr("src", $("#bw-logo").val());
$("[alt='User Avatar']").attr("src", $("#avatar-url").val());

View file

@ -9,16 +9,16 @@
value="{{ csrf_token() }}" />
<p id="bans-waiting"
class="text-center relative w-full p-2 text-primary rounded-lg fw-bold">Loading bans...</p>
<table id="bans" class="table position-relative w-100 d-none">
<table id="bans"
class="table responsive nowrap position-relative w-100 d-none">
<thead>
<tr>
<th>
<input id="select-all-rows"
aria-label="Select all rows"
class="dt-select-checkbox mb-1"
type="checkbox">
Select All
</th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Show the Bans' details"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Select all Bans"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="The date and time when the Ban was created">Date</th>
@ -45,6 +45,7 @@
<tbody>
{% for ban in bans %}
<tr>
<td></td>
<td></td>
<td class="ban-start-date">{{ ban["start_date"] }}</td>
<td>{{ ban["ip"] }}</td>
@ -81,7 +82,7 @@
tabindex="-1"
aria-hidden="true"
role="dialog">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-dialog modal-dialog-scrollable modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add Ban(s)</h5>
@ -106,36 +107,36 @@
<ul id="bans-container" class="list-group rounded-top w-100">
<li id="bans-header" class="list-group-item bg-secondary text-white">
<div class="row">
<div class="col-3 text-center fw-bold">IP Address</div>
<div class="col-5 border-start text-center fw-bold">End Date</div>
<div class="col-3 border-start text-center fw-bold">Reason</div>
<div class="col-1 border-start text-center fw-bold">Delete</div>
<div class="col-12 col-md-3 text-center fw-bold">IP Address</div>
<div class="col-12 col-md-5 border-start text-center fw-bold">End Date</div>
<div class="col-12 col-md-3 border-start text-center fw-bold">Reason</div>
<div class="col-12 col-md-1 border-start text-center fw-bold">Delete</div>
</div>
</li>
<li id="ban-1" class="list-group-item rounded-0">
<div class="row align-items-center d-flex">
<div class="col-3">
<div class="row align-items-center">
<div class="col-12 col-md-3 mb-2 mb-md-0">
<input type="text"
name="ip"
class="form-control"
placeholder="127.0.0.1"
required />
</div>
<div class="col-5 border-start">
<div class="col-12 col-md-5 mb-2 mb-md-0 border-start">
<input type="flatpickr-datetime"
name="datetime"
class="form-control"
required />
</div>
<div class="col-3 border-start">
<div class="col-12 col-md-3 mb-2 mb-md-0 border-start">
<input type="text" name="reason" class="form-control" value="ui" required />
</div>
<div class="col-1 border-start align-items-center d-flex"
data-bs-toggle="tooltip"
data-bs-placement="right"
data-bs-original-title="Can't delete the original Ban">
<div class="col-12 col-md-1 border-start text-center">
<button type="button"
class="btn btn-outline-danger btn-sm me-1 delete-ban disabled">
class="btn btn-outline-danger btn-sm disabled"
data-bs-toggle="tooltip"
data-bs-placement="right"
title="Can't delete the original Ban">
<i class="bx bx-trash bx-xs"></i>
</button>
</div>
@ -143,8 +144,8 @@
</li>
</ul>
</div>
<div class="modal-footer justify-content-center">
<button type="submit" class="btn btn-danger me-2">Ban</button>
<div class="modal-footer justify-content-center flex-wrap gap-2">
<button type="submit" class="btn btn-danger">Ban</button>
<button type="reset"
class="btn btn-outline-secondary"
data-bs-dismiss="modal">Cancel</button>

View file

@ -24,7 +24,7 @@
} %}
<!DOCTYPE html>
<html lang="en"
class="{{ theme }}-style layout-navbar-fixed layout-menu-fixed"
class="{{ theme }}-style layout-navbar-fixed layout-menu-fixed{% if theme == 'dark' %} dark{% endif %}"
data-theme="theme-default"
{% if theme == 'dark' %}data-bs-theme="dark"{% endif %}>
<head>

View file

@ -17,9 +17,12 @@
value="{{ csrf_token() }}" />
<p id="cache-waiting"
class="text-center relative w-full p-2 text-primary rounded-lg fw-bold">Loading cache files...</p>
<table id="cache" class="table position-relative w-100 d-none">
<table id="cache" class="table responsive nowrap position-relative w-100 d-none">
<thead>
<tr>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Show the Cache files' details"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="The Cache file's name">File name</th>
@ -49,6 +52,7 @@
{% for cache in caches %}
{% set service_id = cache['service_id'] if cache['service_id'] else 'global' %}
<tr>
<td></td>
<td>
<a href="{{ url_for("cache") }}/{{ service_id }}/{{ cache['plugin_id'] }}/{{ cache['job_name'] }}/{{ cache['file_name'].replace('/', '_') if cache['file_name'].startswith('folder:') else cache['file_name'] }}"
class="d-flex align-items-center"

View file

@ -15,16 +15,15 @@
value="{{ csrf_token() }}" />
<p id="configs-waiting"
class="text-center relative w-full p-2 text-primary rounded-lg fw-bold">Loading custom configurations...</p>
<table id="configs" class="table w-100 d-none">
<table id="configs" class="table responsive nowrap w-100 d-none">
<thead>
<tr>
<th>
<input id="select-all-rows"
aria-label="Select all rows"
class="dt-select-checkbox mb-1"
type="checkbox">
Select All
</th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Show the Custom configs' details"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Select all Custom configs"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="The user defined Custom config's name">Name</th>
@ -72,6 +71,7 @@
{% set config_icon = "window-alt" %}
{% endif %}
<tr>
<td></td>
<td></td>
<td>
<a href="{{ url_for("configs") }}/{{ service_id }}/{{ config['type'] }}/{{ config['name'] }}"

View file

@ -25,16 +25,16 @@
value="{{ csrf_token() }}" />
<p id="instances-waiting"
class="text-center relative w-full p-2 text-primary rounded-lg fw-bold">Loading instances...</p>
<table id="instances" class="table position-relative w-100 d-none">
<table id="instances"
class="table responsive nowrap position-relative w-100 d-none">
<thead>
<tr>
<th>
<input id="select-all-rows"
aria-label="Select all rows"
class="dt-select-checkbox mb-1"
type="checkbox">
Select All
</th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Show the instances' details"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Select all instances"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="The hostname of the Instance">Hostname</th>
@ -64,6 +64,7 @@
<tbody>
{% for instance in instances %}
<tr>
<td></td>
<td></td>
<td>{{ instance.hostname }}</td>
<td>{{ instance.name }}</td>

View file

@ -9,16 +9,15 @@
value="{{ csrf_token() }}" />
<p id="jobs-waiting"
class="text-center relative w-full p-2 text-primary rounded-lg fw-bold">Loading jobs...</p>
<table id="jobs" class="table w-100 d-none">
<table id="jobs" class="table responsive nowrap w-100 d-none">
<thead>
<tr>
<th>
<input id="select-all-rows"
aria-label="Select all rows"
class="dt-select-checkbox mb-1"
type="checkbox">
Select All
</th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Show the Jobs' details"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Select all Jobs"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="The Job's name">Name</th>
@ -45,6 +44,7 @@
<tbody>
{% for job, job_data in jobs.items() %}
<tr>
<td></td>
<td></td>
<td>{{ job }}</td>
<td>{{ job_data["plugin_id"] }}</td>

View file

@ -1,26 +1,26 @@
{% extends "base.html" %}
{% block page %}
<div class="bg-{% if theme == 'light' %}light{% else %}dark{% endif %}-subtle">
<div class="login-background">
<div class="container-xxl">
<div class="authentication-wrapper authentication-basic container-p-y">
<div class="position-absolute top-0 p-4 pe-6 ps-6 w-70">
<div class="bg-bw-green position-relative w-100 p-2 text-white rounded fw-bold overflow-hidden">
<div class="d-flex justify-content-between align-items-center">
<div class="flex-grow-1 overflow-hidden me-2">
<div id="banner-container">
<p id="banner-text" class="mb-0 slide-in">
Get the most of BunkerWeb by upgrading to the PRO version. More info and free trial <a class="light-href text-white-80"
target="_blank"
rel="noopener"
href="https://panel.bunkerweb.io/?utm_campaign=self&utm_source=banner#pro">here</a>.
</p>
</div>
</div>
<i id="next-news" role="button" class='bx bx-sm bx-chevron-right'></i>
<div class="login-background d-flex justify-content-center">
<div class="position-absolute top-0 p-3 w-100 w-lg-70">
<div class="bg-bw-green position-relative w-100 p-2 text-white rounded fw-bold overflow-hidden">
<div class="d-flex justify-content-between align-items-center">
<div class="flex-grow-1 overflow-hidden me-2">
<div id="banner-container">
<p id="banner-text" class="mb-0 slide-in">
Get the most of BunkerWeb by upgrading to the PRO version. More info and free trial <a class="light-href text-white-80"
target="_blank"
rel="noopener"
href="https://panel.bunkerweb.io/?utm_campaign=self&utm_source=banner#pro">here</a>.
</p>
</div>
</div>
<i id="next-news" role="button" class='bx bx-sm bx-chevron-right'></i>
</div>
</div>
</div>
<div class="container-xxl">
<div class="authentication-wrapper authentication-basic container-p-y">
<div class="container-xxl d-flex justify-content-center align-items-center">
<div class="authentication-inner">
<div class="layout-main-wrapper mt-0 mb-0">

View file

@ -63,7 +63,7 @@
<label for="plugin-type-select">Type</label>
</div>
</div>
<div class="d-flex justify-content-center">
<div class="justify-content-center d-none d-sm-flex">
{% if current_endpoint != "global-config" %}
<div {% if current_endpoint != 'new' and service_method != 'ui' %}data-bs-toggle="tooltip" data-bs-placement="top" data-bs-original-title="The draft mode can only be toggled on UI created services"{% endif %}>
<button type="button"
@ -96,6 +96,37 @@
</div>
</div>
</div>
<div class="d-flex justify-content-center position-fixed m-3 d-sm-none"
id="floating-settings-button">
{% if current_endpoint != "global-config" %}
<div {% if current_endpoint != 'new' and service_method != 'ui' %}data-bs-toggle="tooltip" data-bs-placement="top" data-bs-original-title="The draft mode can only be toggled on UI created services"{% endif %}>
<button type="button"
class="btn btn-sm btn-outline-secondary toggle-draft p-1_5 me-1 {% if current_endpoint != 'new' and service_method != 'ui' %}disabled{% endif %}">
<i class="bx bx-xs bx-{% if is_draft == 'yes' %}file-blank{% else %}globe{% endif %}"></i>
&nbsp;
{% if is_draft == 'yes' %}
Draft
{% else %}
Online
{% endif %}
</button>
</div>
{% endif %}
<div {% if service_method == "autoconf" or is_readonly %}data-bs-toggle="tooltip" data-bs-placement="top" data-bs-original-title="{% if is_readonly %}The database is in readonly{% else %}The service was created using the autoconf method{% endif %}
therefore
the
configuration
is
locked
"
{% endif %}>
<button type="button"
class="btn btn-sm btn-bw-green save-settings p-1_5 {% if service_method == "autoconf" or is_readonly %}disabled{% endif %}">
<i class="bx bx-save bx-xs"></i>
&nbsp;Save
</button>
</div>
</div>
<div class="card tab-content p-2 position-relative">
{% for plugin, plugin_data in plugins.items() %}
{% set filtered_settings = get_filtered_settings(plugin_data["settings"], current_endpoint == "global-config") %}
@ -123,18 +154,18 @@
data-bs-toggle="tooltip"
data-bs-placement="top"
data-bs-original-title="{% if plugin_data['stream'] != 'no' %}Supports{% else %}Doesn't support{% endif %} STREAM mode{% if plugin_data['stream'] == 'partial' %} partially{% endif %}">
<i class="bx bx-{% if plugin_data['stream'] == 'yes' %}badge-check{% elif plugin_data['stream'] == 'partial' %}message-square-detail{% else %}no-entry{% endif %}"></i>&nbsp;STREAM
<i class="bx bx-{% if plugin_data['stream'] == 'yes' %}badge-check{% elif plugin_data['stream'] == 'partial' %}message-square-detail{% else %}no-entry{% endif %}"></i><span class="d-none d-md-inline">&nbsp;STREAM</span>
</a>
<a href="{% if plugin_data['type'] == 'core' %}https://docs.bunkerweb.io/latest/settings/?utm_campaign=self&utm_source=ui#{% if plugin == 'general' %}global-settings{% else %}{{ plugin }}{% endif %}{% else %}https://docs.bunkerweb.io/latest/plugins/?utm_campaign=self&utm_source=ui{% endif %}"
class="btn btn-sm btn-primary rounded-pill ms-2"
target="_blank"
rel="noopener">
<i class="bx bx-link"></i>&nbsp;More info
<i class="bx bx-link"></i><span class="d-none d-md-inline">&nbsp;More info</span>
</a>
{% if plugin_data["page"] %}
<a href="{{ url_for("plugins") }}/{{ plugin }}"
class="btn btn-sm btn-primary rounded-pill ms-2">
<i class="bx bxs-file-html"></i>&nbsp;Plugin page
<i class="bx bxs-file-html"></i><span class="d-none d-md-inline">&nbsp;Plugin page</span>
</a>
{% endif %}
</div>

View file

@ -17,7 +17,7 @@
class="btn btn-sm btn-primary rounded-pill ms-2"
target="_blank"
rel="noopener">
<i class="bx bx-link"></i>&nbsp;More info
<i class="bx bx-link"></i><span class="d-none d-md-inline">&nbsp;More info</span>
</a>
</div>
</div>

View file

@ -10,16 +10,15 @@
value="{{ csrf_token() }}" />
<p id="plugins-waiting"
class="text-center relative w-full p-2 text-primary rounded-lg fw-bold">Loading plugins...</p>
<table id="plugins" class="table w-100 d-none">
<table id="plugins" class="table responsive nowrap w-100 d-none">
<thead>
<tr>
<th>
<input id="select-all-rows"
aria-label="Select all rows"
class="dt-select-checkbox mb-1"
type="checkbox">
Select All
</th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Show the Plugins' details"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Select all Plugins"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="The Plugin's ID">ID</th>
@ -49,6 +48,7 @@
<tbody>
{% for plugin, plugin_data in plugins.items() %}
<tr>
<td></td>
<td></td>
<td>
<div class="{{ plugin_types[plugin_data['type']].get('text-class', '') }}">{{ plugin }}</div>

View file

@ -7,9 +7,13 @@
<input type="hidden" id="base_flags_url" value="{{ base_flags_url }}" />
<p id="reports-waiting"
class="text-center relative w-full p-2 text-primary rounded-lg fw-bold">Loading reports...</p>
<table id="reports" class="table position-relative w-100 d-none">
<table id="reports"
class="table responsive nowrap position-relative w-100 d-none">
<thead>
<tr>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Show the Reports' details"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="The date and time when the Report was created">Date</th>
@ -49,26 +53,24 @@
{% set ns = namespace(countries=[]) %}
{% for report in reports %}
{% if report["country"] not in ns.countries %}
{% set ns.countries = ns.countries + [report["country"]] %}
{% set ns.countries = ns.countries + [report["country"].lower()] %}
{% endif %}
<tr>
<td></td>
<td class="report-date">{{ report["date"] }}</td>
<td>{{ report["ip"] }}</td>
<td>
<div class="d-flex align-items-center">
<img src="{{ base_flags_url }}/{% if report['country'] == "local" %}zz{% else %}{{ report['country']|lower }}{% endif %}.svg"
class="border border-1 p-0 me-1"
data-bs-toggle="tooltip"
data-bs-placement="top"
data-bs-original-title="{% if report['country'] == "local" %}N/A{% else %}{{ report["country"] }}{% endif %}"
height="17" />
&nbsp;&nbsp;
{% if report['country'] == "local" %}
N/A
{% else %}
{{ report["country"] }}
{% endif %}
</div>
<td data-bs-toggle="tooltip"
data-bs-placement="top"
data-bs-original-title="{% if report['country'] == "local" %}N/A{% else %}{{ report["country"]|lower }}{% endif %}">
<img src="{{ base_flags_url }}/{% if report['country'] == "local" %}zz{% else %}{{ report['country']|lower }}{% endif %}.svg"
class="border border-1 p-0 me-1"
height="17" />
&nbsp;&nbsp;
{% if report['country'] == "local" %}
N/A
{% else %}
{{ report["country"] }}
{% endif %}
</td>
<td>{{ report["method"] }}</td>
<td>{{ report["url"] }}</td>

View file

@ -9,16 +9,15 @@
value="{{ csrf_token() }}" />
<p id="services-waiting"
class="text-center relative w-full p-2 text-primary rounded-lg fw-bold">Loading services...</p>
<table id="services" class="table position-relative w-100 d-none">
<table id="services" class="table responsive nowrap position-relative w-100 d-none">
<thead>
<tr>
<th>
<input id="select-all-rows"
aria-label="Select all rows"
class="dt-select-checkbox mb-1"
type="checkbox">
Select All
</th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Show the services' details"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="Select all services"></th>
<th data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="The name of the service">Service name</th>
@ -42,6 +41,7 @@
<tbody>
{% for service in services %}
<tr>
<td></td>
<td></td>
<td>
<a href="{{ url_for("services") }}/{{ service['id'] }}"