Made a few tweaks about fonts and added more options for filtering for datatables in web UI

This commit is contained in:
Théophile Diot 2024-10-07 11:13:29 +02:00
parent 4d3d3dc0c1
commit 4dc9c4a6cd
No known key found for this signature in database
GPG key ID: FA995104A0BA376A
25 changed files with 409 additions and 46 deletions

View file

@ -5,7 +5,7 @@ from flask_login import login_required
from magic import Magic
from werkzeug.utils import secure_filename
from app.dependencies import DB
from app.dependencies import BW_CONFIG, DB
cache = Blueprint("cache", __name__)
@ -16,7 +16,17 @@ SHOWN_FILE_TYPES = ("text/plain", "text/html", "text/css", "text/javascript", "a
@cache.route("/cache", methods=["GET"])
@login_required
def cache_page():
return render_template("cache.html", caches=DB.get_jobs_cache_files(with_data=False))
service = request.args.get("service", "")
cache_plugin = request.args.get("plugin", "")
cache_job_name = request.args.get("job_name", "")
return render_template(
"cache.html",
caches=DB.get_jobs_cache_files(with_data=False),
services=BW_CONFIG.get_config(global_only=True, methods=False, with_drafts=True, filtered_settings=("SERVER_NAME"))["SERVER_NAME"],
cache_service=service,
cache_plugin=cache_plugin,
cache_job_name=cache_job_name,
)
@cache.route("/cache/<string:service>/<string:plugin_id>/<string:job_name>/<string:file_name>", methods=["GET"])

View file

@ -38,7 +38,16 @@ CONFIG_TYPES = {
@configs.route("/configs", methods=["GET"])
@login_required
def configs_page():
return render_template("configs.html", configs=DB.get_custom_configs(with_drafts=True, with_data=False))
service = request.args.get("service", "")
config_type = request.args.get("type", "")
return render_template(
"configs.html",
configs=DB.get_custom_configs(with_drafts=True, with_data=False),
services=BW_CONFIG.get_config(global_only=True, methods=False, with_drafts=True, filtered_settings=("SERVER_NAME"))["SERVER_NAME"],
db_templates=" ".join([template for template in DB.get_templates() if template != "ui"]),
config_service=service,
config_type=config_type,
)
@configs.route("/configs/delete", methods=["POST"])
@ -239,7 +248,7 @@ def configs_new():
)
@configs.route("/configs/<string:service>/<string:config_type>/<string:name>", methods=["GET", "POST"]) # TODO: finish saving
@configs.route("/configs/<string:service>/<string:config_type>/<string:name>", methods=["GET", "POST"])
@login_required
def configs_edit(service: str, config_type: str, name: str):
if service == "global":

View file

@ -149,6 +149,13 @@ $(document).ready(function () {
const layout = {
topStart: {},
bottomEnd: {},
bottom1: {
searchPanes: {
viewTotal: true,
cascadePanes: true,
columns: [1, 4],
},
},
};
if (banNumber > 10) {
@ -320,10 +327,95 @@ $(document).ready(function () {
render: DataTable.render.select(),
targets: 0,
},
{ type: "ip-address", targets: 1 },
{
orderable: false,
targets: -1,
},
{
searchPanes: {
show: true,
options: [
{
label: "Last 24 hours",
value: function (rowData, rowIdx) {
const date = new Date(rowData[1]);
const now = new Date();
return now - date < 24 * 60 * 60 * 1000;
},
},
{
label: "Last 7 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[1]);
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[1]);
const now = new Date();
return now - date < 30 * 24 * 60 * 60 * 1000;
},
},
{
label: "More than 30 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[1]);
const now = new Date();
return now - date >= 30 * 24 * 60 * 60 * 1000;
},
},
],
combiner: "or",
orderable: false,
},
targets: 1,
},
{
searchPanes: {
show: true,
options: [
{
label: "Next 24 hours",
value: function (rowData, rowIdx) {
const date = new Date(rowData[4]);
const now = new Date();
return date - now < 24 * 60 * 60 * 1000;
},
},
{
label: "Next 7 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[4]);
const now = new Date();
return date - now < 7 * 24 * 60 * 60 * 1000;
},
},
{
label: "Next 30 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[4]);
const now = new Date();
return date - now < 30 * 24 * 60 * 60 * 1000;
},
},
{
label: "More than 30 days",
value: function (rowData, rowIdx) {
const date = new Date(rowData[4]);
const now = new Date();
return date - now >= 30 * 24 * 60 * 60 * 1000;
},
},
],
combiner: "or",
orderable: false,
},
targets: 4,
},
{
targets: "_all", // Target all columns
createdCell: function (td, cellData, rowData, row, col) {

View file

@ -1,5 +1,27 @@
$(document).ready(function () {
const cacheNumber = parseInt($("#cache_number").val());
const services = $("#services").val().trim().split(" ");
const cacheServiceSelection = $("#cache_service_selection").val().trim();
const cachePluginSelection = $("#cache_plugin_selection").val().trim();
const cacheJobNameSelection = $("#cache_job_name_selection").val().trim();
const servicesSearchPanesOptions = [
{
label: "global",
value: function (rowData) {
return $(rowData[3]).text().trim() === "global";
},
},
];
services.forEach((service) => {
servicesSearchPanesOptions.push({
label: service,
value: function (rowData) {
return $(rowData[3]).text().trim() === service;
},
});
});
const layout = {
topStart: {},
@ -8,7 +30,7 @@ $(document).ready(function () {
searchPanes: {
viewTotal: true,
cascadePanes: true,
columns: [2, 3, 4],
columns: [1, 2, 3, 4],
},
},
};
@ -116,7 +138,15 @@ $(document).ready(function () {
show: true,
combiner: "or",
},
targets: [2, 3],
targets: [1, 2],
},
{
searchPanes: {
show: true,
combiner: "or",
options: servicesSearchPanesOptions,
},
targets: 3,
},
{
searchPanes: {
@ -176,6 +206,18 @@ $(document).ready(function () {
},
});
$(`#DataTables_Table_0 span[title='${cacheJobNameSelection}']`).trigger(
"click"
);
$(`#DataTables_Table_1 span[title='${cachePluginSelection}']`).trigger(
"click"
);
$(`#DataTables_Table_2 span[title='${cacheServiceSelection}']`).trigger(
"click"
);
$("#cache").removeClass("d-none");
$("#cache-waiting").addClass("visually-hidden");

View file

@ -1,8 +1,49 @@
$(document).ready(function () {
var actionLock = false;
const configNumber = parseInt($("#configs_number").val());
const services = $("#services").val().trim().split(" ");
const templates = $("#templates").val().trim().split(" ");
const configServiceSelection = $("#configs_service_selection").val().trim();
const configTypeSelection = $("#configs_type_selection")
.val()
.trim()
.toUpperCase();
const isReadOnly = $("#is-read-only").val().trim() === "True";
const servicesSearchPanesOptions = [
{
label: "global",
value: function (rowData) {
return $(rowData[4]).text().trim() === "global";
},
},
];
const templatesSearchPanesOptions = [
{
label: "no template",
value: function (rowData) {
return $(rowData[5]).text().trim() === "no template";
},
},
];
services.forEach((service) => {
servicesSearchPanesOptions.push({
label: service,
value: function (rowData) {
return $(rowData[4]).text().trim() === service;
},
});
});
templates.forEach((template) => {
templatesSearchPanesOptions.push({
label: template,
value: function (rowData) {
return $(rowData[5]).text().trim() === template;
},
});
});
const setupDeletionModal = (configs) => {
const delete_modal = $("#modal-delete-configs");
const list = $(
@ -324,13 +365,29 @@ $(document).ready(function () {
},
targets: 2,
},
{
searchPanes: {
show: true,
combiner: "or",
options: servicesSearchPanesOptions,
},
targets: 4,
},
{
searchPanes: {
show: true,
combiner: "or",
orderable: false,
},
targets: [3, 4, 5],
targets: 3,
},
{
searchPanes: {
show: true,
combiner: "or",
options: templatesSearchPanesOptions,
},
targets: 5,
},
{
targets: "_all", // Target all columns
@ -376,6 +433,14 @@ $(document).ready(function () {
},
});
$(`#DataTables_Table_0 span[title='${configTypeSelection}']`).trigger(
"click"
);
$(`#DataTables_Table_2 span[title='${configServiceSelection}']`).trigger(
"click"
);
$("#configs").removeClass("d-none");
$("#configs-waiting").addClass("visually-hidden");

View file

@ -398,7 +398,7 @@ $(document).ready(function () {
combiner: "or",
orderable: false,
},
targets: 3,
targets: [3],
},
{
searchPanes: {

View file

@ -6,6 +6,13 @@ $(document).ready(function () {
const layout = {
topStart: {},
bottomEnd: {},
bottom1: {
searchPanes: {
viewTotal: true,
cascadePanes: true,
columns: [2, 3, 4, 5],
},
},
};
if (jobNumber > 10) {
@ -114,14 +121,14 @@ $(document).ready(function () {
type: "hidden",
name: "csrf_token",
value: $("#csrf_token").val(),
}),
})
);
form.append(
$("<input>", {
type: "hidden",
name: "jobs",
value: JSON.stringify(jobs),
}),
})
);
// Append the form to the body and submit it
@ -184,6 +191,95 @@ $(document).ready(function () {
orderable: false,
targets: -1,
},
{
searchPanes: {
show: true,
combiner: "or",
},
targets: [2],
},
{
searchPanes: {
show: true,
header: "Interval",
options: [
{
label: "Every day",
value: function (rowData, rowIdx) {
return rowData[3].includes("day");
},
},
{
label: "Every hour",
value: function (rowData, rowIdx) {
return rowData[3].includes("hour");
},
},
{
label: "Every week",
value: function (rowData, rowIdx) {
return rowData[3].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-sm bx-x text-danger"></i>&nbsp;No',
value: function (rowData, rowIdx) {
return rowData[4].includes("bx-x");
},
},
{
label: '<i class="bx bx-sm bx-check text-success"></i>&nbsp;Yes',
value: function (rowData, rowIdx) {
return rowData[4].includes("bx-check");
},
},
],
combiner: "or",
orderable: false,
},
targets: 4,
},
{
searchPanes: {
show: true,
header: "Last run state",
options: [
{
label: '<i class="bx bx-sm bx-x text-danger"></i>&nbsp;Failed',
value: function (rowData, rowIdx) {
return rowData[5].includes("bx-x");
},
},
{
label:
'<i class="bx bx-sm bx-check text-success"></i>&nbsp;Success',
value: function (rowData, rowIdx) {
return rowData[5].includes("bx-check");
},
},
],
combiner: "or",
orderable: false,
},
targets: 5,
},
{
targets: "_all", // Target all columns
createdCell: function (td, cellData, rowData, row, col) {
@ -273,7 +369,7 @@ $(document).ready(function () {
.html(
`Last${historyCount > 1 ? " " + historyCount : ""} execution${
historyCount > 1 ? "s" : ""
} of Job <span class="fw-bold fst-italic">${job}</span> from plugin <span class="fw-bold fst-italic">${plugin}</span>`,
} of Job <span class="fw-bold fst-italic">${job}</span> from plugin <span class="fw-bold fst-italic">${plugin}</span>`
);
history.removeClass("visually-hidden");
historyModal.find(".modal-body").html(history);

View file

@ -283,7 +283,7 @@ $(function () {
if (country) {
$(`[data-bs-original-title="${countryCode}"]`).attr(
"data-bs-original-title",
country,
country
);
}
});
@ -377,6 +377,7 @@ $(function () {
{
searchPanes: {
show: true,
combiner: "or",
options: countriesSearchPanesOptions,
},
targets: 2,

View file

@ -149,15 +149,21 @@ class News {
})
);
const cardText = $("<small>", { class: "card-text lh-1", text: excerpt });
const cardText = $("<small>", {
class: "card-text lh-1 courier-prime",
text: excerpt,
});
const cardFooter = $("<div>", {
class:
"card-footer p-0 mt-2 d-flex justify-content-between align-items-center",
"card-footer p-0 mt-3 d-flex justify-content-between align-items-center",
});
$("<p>", { class: "card-text mb-0" })
.append(
$("<small>", { class: "text-muted", text: `Posted on: ${date}` })
$("<small>", {
class: "text-muted courier-prime",
text: `Posted on: ${date}`,
})
)
.appendTo(cardFooter);
@ -207,7 +213,10 @@ class News {
text: title,
})
);
const cardText = $("<p>", { class: "card-text", text: excerpt });
const cardText = $("<p>", {
class: "card-text courier-prime",
text: excerpt,
});
const tagsContainer = $("<p>", { class: "d-flex flex-wrap" });
tags.forEach((tag) => {
@ -229,7 +238,10 @@ class News {
});
const dateText = $("<p>", { class: "card-text" }).append(
$("<small>", { class: "text-muted", text: `Posted on: ${date}` })
$("<small>", {
class: "text-muted courier-prime",
text: `Posted on: ${date}`,
})
);
cardBody.append(cardTitle, cardText, tagsContainer, dateText);
@ -261,6 +273,7 @@ $(document).ready(() => {
let currentIndex = 0;
const intervalTime = 7000;
let interval;
const $bannerText = $("#banner-text");
function loadData() {
const nowStamp = Math.round(Date.now() / 1000);
@ -300,8 +313,6 @@ $(document).ready(() => {
// Function to update the banner text with animation
function updateBannerText(nextIndex) {
const $bannerText = $("#banner-text");
// Remove any existing slide-in class to reset
$bannerText.removeClass("slide-in").addClass("slide-out");
@ -342,6 +353,8 @@ $(document).ready(() => {
resetInterval();
});
loadData();
$("#next-news").trigger("click");
if ($bannerText.length) {
loadData();
$("#next-news").trigger("click");
}
});

View file

@ -57,7 +57,7 @@
href="{{ url_for('static', filename='libs/datatables/datatables.min.css') }}"
nonce="{{ style_nonce }}" />
{% endif %}
{% if current_endpoint in ("bans") %}
{% if current_endpoint == "bans" or current_endpoint != "plugins" and "plugins" in request.path %}
<!-- Flatpickr -->
<link rel="stylesheet"
href="{{ url_for('static', filename='libs/flatpickr/flatpickr.min.css') }}"
@ -83,7 +83,7 @@
<link rel="stylesheet"
href="{{ url_for('static', filename='libs/perfect-scrollbar/perfect-scrollbar.css') }}"
nonce="{{ style_nonce }}" />
{% if current_endpoint == "home" %}
{% if current_endpoint == "home" or current_endpoint != "plugins" and "plugins" in request.path %}
<link rel="stylesheet"
href="{{ url_for('static', filename='libs/apexcharts/apexcharts.css') }}"
nonce="{{ style_nonce }}" />
@ -141,23 +141,23 @@
<script src="{{ url_for('static', filename='libs/datatables/plugins/ip-address.js') }}"
nonce="{{ script_nonce }}"></script>
{% endif %}
{% if current_endpoint == "home" %}
{% if current_endpoint == "home" or current_endpoint != "plugins" and "plugins" in request.path %}
<script src="{{ url_for('static', filename='libs/apexcharts/apexcharts.min.js') }}"
nonce="{{ script_nonce }}"></script>
<script src="{{ url_for('static', filename='libs/leaflet/leaflet.min.js') }}"
nonce="{{ script_nonce }}"></script>
{% endif %}
{% if current_endpoint in ("bans") %}
{% if current_endpoint == "bans" or current_endpoint != "plugins" and "plugins" in request.path %}
<script src="{{ url_for('static', filename='libs/flatpickr/flatpickr.min.js') }}"
nonce="{{ script_nonce }}"></script>
<script src="{{ url_for('static', filename='libs/flatpickr/plugins/minMaxTimePlugin.js') }}"
nonce="{{ script_nonce }}"></script>
{% endif %}
{% if current_endpoint not in ("services", "configs", "cache") and ("services" in request.path or "configs" in request.path or "cache" in request.path or current_endpoint == "logs") %}
{% if current_endpoint not in ("services", "configs", "cache", "plugins") and ("services" in request.path or "configs" in request.path or "cache" in request.path or current_endpoint == "logs" or "plugins" in request.path) %}
<script src="{{ url_for('static', filename='libs/ace/src-min/ace.js') }}"
nonce="{{ script_nonce }}"></script>
{% endif %}
{% if current_endpoint in ("loading", "instances") %}
{% if current_endpoint in ("loading", "instances") or current_endpoint != "plugins" and "plugins" in request.path %}
<script src="{{ url_for('static', filename='libs/lottie-player/lottie-player.min.js') }}"
nonce="{{ script_nonce }}"></script>
{% endif %}

View file

@ -2,14 +2,37 @@
<ol class="breadcrumb mb-0">
<!-- prettier-ignore -->
{% with breadcrumbs = request.path.split("/") %}
{% set breadcrumbs_ns = namespace(working_url="") %}
{% for breadcrumb in breadcrumbs %}
{% set breadcrumb_prefix = "" %}
{% set breadcrumb_url = url_for(breadcrumb.replace('_', '-')) %}
{% if breadcrumb == current_endpoint %}
{% set breadcrumb_url = breadcrumbs_url %}
{% endif %}
{% if breadcrumb_url == "#" %}
{% set breadcrumb_url = breadcrumbs_ns.working_url %}
{% else %}
{% set breadcrumbs_ns.working_url = breadcrumb_url %}
{% endif %}
{% if current_endpoint != "configs" and "configs" in request.path %}
{% if loop.index == 3 %}
{% set breadcrumb_prefix = "?service=" + breadcrumb %}
{% elif loop.index == 4 %}
{% set breadcrumb_prefix = "?type=" + breadcrumb %}
{% endif %}
{% endif %}
{% if current_endpoint != "cache" and "cache" in request.path %}
{% if loop.index == 3 %}
{% set breadcrumb_prefix = "?service=" + breadcrumb %}
{% elif loop.index == 4 %}
{% set breadcrumb_prefix = "?plugin=" + breadcrumb %}
{% elif loop.index == 5 %}
{% set breadcrumb_prefix = "?job_name=" + breadcrumb %}
{% endif %}
{% endif %}
<li class="breadcrumb-item{% if breadcrumb == current_endpoint %} active{% endif %}"
{% if breadcrumb == current_endpoint %}aria-current="page"{% endif %}>
<a href="{{ breadcrumb_url }}">{{ breadcrumb }}</a>
<a href="{{ breadcrumb_url }}{{ breadcrumb_prefix }}">{{ breadcrumb }}</a>
</li>
{% endfor %}
{% endwith %}

View file

@ -3,6 +3,12 @@
<!-- Content -->
<div class="card table-responsive text-nowrap p-4 pb-8 min-vh-70">
<input type="hidden" id="cache_number" value="{{ caches|length }}" />
<input type="hidden"
id="services"
value="{{ services }}" />
<input type="hidden" id="cache_service_selection" value="{{ cache_service }}" />
<input type="hidden" id="cache_plugin_selection" value="{{ cache_plugin }}" />
<input type="hidden" id="cache_job_name_selection" value="{{ cache_job_name }}" />
<input type="hidden"
id="csrf_token"
name="csrf_token"

View file

@ -20,7 +20,7 @@
<p id="cache-waiting"
class="text-center relative w-full p-2 text-primary rounded-lg fw-bold">Loading cache file...</p>
<div id="cache-value"
class="visually-hidden ace-editor border rounded position-absolute top-0 start-0 end-0 bottom-0">
class="visually-hidden ace-editor border rounded position-absolute top-0 start-0 end-0 bottom-0 courier-prime">
{{ cache_file }}
</div>
</div>

View file

@ -146,7 +146,7 @@
data-language="{% if type and type.startswith(('CRS', 'MODSEC')) %}ModSecurity{% else %}NGINX{% endif %}"
data-method="{{ config_method or 'ui' }}"
data-template="{{ config_template }}"
class="visually-hidden ace-editor border rounded position-absolute top-0 start-0 end-0 bottom-0">
class="visually-hidden ace-editor border rounded position-absolute top-0 start-0 end-0 bottom-0 courier-prime">
{{ config_value }}
</div>
</div>

View file

@ -3,6 +3,14 @@
<!-- Content -->
<div class="card table-responsive text-nowrap p-4 min-vh-70">
<input type="hidden" id="configs_number" value="{{ configs|length }}" />
<input type="hidden"
id="services"
value="{{ services }}" />
<input type="hidden"
id="templates"
value="{{ db_templates }}" />
<input type="hidden" id="configs_service_selection" value="{{ config_service }}" />
<input type="hidden" id="configs_type_selection" value="{{ config_type }}" />
<input type="hidden"
id="csrf_token"
name="csrf_token"

View file

@ -172,9 +172,7 @@
<a class="btn btn-responsive btn-buy-now"
role="button"
aria-pressed="true"
href="https://panel.bunkerweb.io/order/bunkerweb-pro/?utm_campaign=self&utm_source=ui"
target="_blank"
rel="noopener">
href="{{ url_for('pro') }}">
<span class="me-1 me-md-2 d-flex h-100 justify-content-center align-items-center">
<img src="{{ pro_diamond_url }}"
alt="Pro plugin"

View file

@ -103,12 +103,12 @@
<div class="card p-4 position-relative shadow-sm rounded-3 h-100">
<div class="card-header p-2">
<div class="card-title mb-0">
<h5 class="mb-1 me-2 don-jose">Blocked Requests countries</h5>
<h5 class="me-2 don-jose mb-0">Blocked Requests countries</h5>
</div>
</div>
<div class="card-body p-0">
<div id="requests-map-data" class="visually-hidden">{{ request_countries|tojson }}</div>
<div id="requests-map" class="h-100"></div>
<div id="requests-map" class="rounded h-100"></div>
</div>
</div>
</div>
@ -116,9 +116,9 @@
<div class="card p-4 position-relative shadow-sm rounded-3">
<div class="card-header p-2">
<div class="card-title mb-0 d-flex justify-content-between">
<h5 class="don-jose">News</h5>
<h5 class="don-jose mb-0">News</h5>
<a class="text-decoration-underline link-underline-primary"
href="https://www.bunkerweb.io/blog?utm_campaign=self&amp;utm_source=ui"
href="https://www.bunkerweb.io/blog?utm_campaign=self&utm_source=ui"
target="_blank"
rel="noopener">See more</a>
</div>

View file

@ -79,7 +79,7 @@
<li class="menu-item{% if current_endpoint == plugin %} active{% endif %}"{% if not_pro_pro_plugin %}data-bs-toggle="tooltip" data-bs-placement="top" data-bs-html="true" data-bs-original-title="<i class='bx bx-diamond bx-xs'></i><span>Pro feature</span>"
{% endif %}
>
<a href="{% if not_pro_pro_plugin %}https://panel.bunkerweb.io/?utm_campaign=self&utm_source=ui#pro{% else %}{{ url_for("plugins") }}/{{ plugin }}{% endif %}"
<a href="{% if not_pro_pro_plugin %}{{ url_for("pro") }}{% else %}{{ url_for("plugins") }}/{{ plugin }}{% endif %}"
class="menu-link"
{% if not_pro_pro_plugin %}target="_blank" rel="noopener"{% endif %}>
<i class="menu-icon tf-icons bx bx-puzzle"></i>

View file

@ -113,7 +113,7 @@
width="18px"
height="15.5px">') |safe }}
</h5>
<p class="card-subtitle text-muted text-truncate mt-3">{{ plugin_data["description"] }}</p>
<p class="card-subtitle text-muted text-truncate mt-3 courier-prime">{{ plugin_data["description"] }}</p>
</div>
<div class="d-flex flex-grow-0 flex-shrink-0 justify-content-end align-items-center">
<a href="https://docs.bunkerweb.io/latest/quickstart-guide/#protect-udptcp-applications"

View file

@ -82,7 +82,7 @@
width="18px"
height="15.5px">') |safe }}
</h5>
<p class="card-subtitle text-muted text-truncate mt-3">{{ template_data["name"] }}</p>
<p class="card-subtitle text-muted text-truncate mt-3 courier-prime">{{ template_data["name"] }}</p>
</div>
</div>
<div class="card-body">

View file

@ -61,7 +61,7 @@
name="raw-config"
value="{{ default_settings | join('\r\n') }}">
<div class="form-floating">
<textarea class="form-control w-100 h-100 text-white"
<textarea class="form-control w-100 h-100 text-white courier-prime"
rows="35"
id="raw-config"
aria-label="Raw configuration"

View file

@ -71,7 +71,7 @@
{% endif %}
>
{% if plugin_data["type"] == "pro" %}
<a href="https://panel.bunkerweb.io/?utm_campaign=self&utm_source=ui#pro" target="_blank" rel="noopener" {% else %}
<a href="{{ url_for("pro") }}" target="_blank" rel="noopener" {% else %}
<div {% endif %}
class="{{ plugin_types[plugin_data['type']].get('text-class', '') }}">
{{ plugin_types[plugin_data["type"]].get('icon', '<img src="' + pro_diamond_url + '"

View file

@ -609,7 +609,7 @@
<div class="collapse show mt-2" id="newsletter-floating">
<div class="card card-body bg-white border-0 shadow-sm">
<h5 class="mb-3 text-dark">Join the Newsletter</h5>
<form action="https://bunkerity.us1.list-manage.com/subscribe/post?u=ec5b1577cf427972b9bd491a6&amp;id=37076d9d67"
<form action="https://bunkerity.us1.list-manage.com/subscribe/post?u=ec5b1577cf427972b9bd491a6&id=37076d9d67"
method="POST"
target="_blank"
rel="noopener">

View file

@ -46,7 +46,7 @@
<p class="text-center relative w-full p-2 text-primary rounded-lg fw-bold">Impossible to connect to blog news.</p>
</div>
<div class="text-center relative w-full p-2 text-primary rounded-lg fw-bold mt-4">
<a href="https://www.bunkerweb.io/blog?utm_campaign=self&amp;utm_source=ui"
<a href="https://www.bunkerweb.io/blog?utm_campaign=self&utm_source=ui"
class="text-decoration-underline link-underline-primary position-relative pe-4"
target="_blank"
rel="noopener">More news <i class="bx bx-xs bx-right-arrow-alt position-absolute end-0 top-0 mt-0_5"></i></a>
@ -55,7 +55,7 @@
<!-- Newsletter Signup Section -->
<div class="newsletter-signup position-sticky bottom-0 start-0 w-100 p-4 bg-white border-top">
<h5 class="mb-3 text-dark">Join the Newsletter</h5>
<form action="https://bunkerity.us1.list-manage.com/subscribe/post?u=ec5b1577cf427972b9bd491a6&amp;id=37076d9d67"
<form action="https://bunkerity.us1.list-manage.com/subscribe/post?u=ec5b1577cf427972b9bd491a6&id=37076d9d67"
method="POST">
<div class="mb-3">
<input type="email"

View file

@ -76,7 +76,7 @@
<!-- Newsletter Signup Section -->
<div class="newsletter-signup position-sticky bottom-0 start-0 w-100 p-4 bg-white border-top">
<h5 class="mb-3 text-dark">Join the Newsletter</h5>
<form action="https://bunkerity.us1.list-manage.com/subscribe/post?u=ec5b1577cf427972b9bd491a6&amp;id=37076d9d67"
<form action="https://bunkerity.us1.list-manage.com/subscribe/post?u=ec5b1577cf427972b9bd491a6&id=37076d9d67"
method="POST">
<div class="mb-3">
<input type="email"