mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
Made a lot of optimizations and tweaks in web UI + Made advancements on Global Config and Services pages
This commit is contained in:
parent
69d0358f58
commit
974cfcaeb3
29 changed files with 1144 additions and 564 deletions
|
|
@ -79,6 +79,8 @@ def global_config_page():
|
|||
)
|
||||
)
|
||||
|
||||
global_config = BW_CONFIG.get_config(global_only=True, methods=True)
|
||||
keywords = request.args.get("keywords", "")
|
||||
search_type = request.args.get("type", "all")
|
||||
global_config = DB.get_config(global_only=True, methods=True)
|
||||
plugins = BW_CONFIG.get_plugins()
|
||||
return render_template("plugins_settings.html", config=global_config, plugins=plugins)
|
||||
return render_template("global_config.html", config=global_config, plugins=plugins, keywords=keywords, type=search_type)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from flask import Blueprint, redirect, render_template, request, url_for
|
||||
from flask import Blueprint, Response, redirect, render_template, request, url_for
|
||||
from flask_login import login_required
|
||||
|
||||
from app.dependencies import DB
|
||||
from app.dependencies import BW_CONFIG, DB
|
||||
|
||||
from app.routes.utils import get_service_data, handle_error, update_service
|
||||
|
||||
|
|
@ -21,39 +21,18 @@ def services_page():
|
|||
|
||||
return redirect(url_for("loading", next=url_for("services.services_page"), message=message))
|
||||
|
||||
# Display services
|
||||
services = []
|
||||
tmp_config = DB.get_config(methods=True, with_drafts=True).copy()
|
||||
service_names = tmp_config["SERVER_NAME"]["value"].split(" ")
|
||||
return render_template("services.html") # TODO
|
||||
|
||||
table_settings = (
|
||||
"USE_REVERSE_PROXY",
|
||||
"IS_DRAFT",
|
||||
"SERVE_FILES",
|
||||
"REMOTE_PHP",
|
||||
"AUTO_LETS_ENCRYPT",
|
||||
"USE_CUSTOM_SSL",
|
||||
"USE_MODSECURITY",
|
||||
"USE_BAD_BEHAVIOR",
|
||||
"USE_LIMIT_REQ",
|
||||
"USE_DNSBL",
|
||||
"SERVER_NAME",
|
||||
)
|
||||
|
||||
for service in service_names:
|
||||
service_settings = {}
|
||||
|
||||
# For each needed setting, get the service value if one, else the global (value), else default value
|
||||
for setting in table_settings:
|
||||
value = tmp_config.get(f"{service}_{setting}", tmp_config.get(setting, {"value": None}))["value"]
|
||||
method = tmp_config.get(f"{service}_{setting}", tmp_config.get(setting, {"method": None}))["method"]
|
||||
is_global = tmp_config.get(f"{service}_{setting}", tmp_config.get(setting, {"global": None}))["global"]
|
||||
service_settings[setting] = {"value": value, "method": method, "global": is_global}
|
||||
|
||||
services.append(service_settings)
|
||||
|
||||
services.sort(key=lambda x: x["SERVER_NAME"]["value"])
|
||||
|
||||
# builder = services_builder(services)
|
||||
# return render_template("services.html", data_server_builder=b64encode(dumps(builder).encode("utf-8")).decode("ascii"))
|
||||
return render_template("services.html")
|
||||
@services.route("/services/<string:service>", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def services_service_page(service: str):
|
||||
services = BW_CONFIG.get_config(global_only=True, methods=False, filtered_settings=("SERVER_NAME"))["SERVER_NAME"].split(" ")
|
||||
if service not in services:
|
||||
return Response("Service not found", status=404)
|
||||
mode = request.args.get("mode", "easy")
|
||||
keywords = request.args.get("keywords", "")
|
||||
search_type = request.args.get("type", "all")
|
||||
db_config = DB.get_config(methods=True, with_drafts=True, service=service)
|
||||
plugins = BW_CONFIG.get_plugins()
|
||||
return render_template("service_settings.html", config=db_config, plugins=plugins, mode=mode, keywords=keywords, type=search_type)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
:root,
|
||||
[data-bs-theme="light"] {
|
||||
--bs-bw-green: #2eac68;
|
||||
--bs-bw-blue: #0b5577;
|
||||
--bs-blue: #007bff;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #696cff;
|
||||
|
|
@ -24,8 +25,8 @@
|
|||
--bs-gray-25: rgba(34, 48, 62, 0.025);
|
||||
--bs-gray-60: rgba(34, 48, 62, 0.06);
|
||||
--bs-gray-80: rgba(34, 48, 62, 0.08);
|
||||
--bs-primary: #0b5577;
|
||||
--bs-secondary: #8592a3;
|
||||
--bs-primary: #0b354a;
|
||||
--bs-secondary: #35728e;
|
||||
--bs-success: #71dd37;
|
||||
--bs-info: #03c3ec;
|
||||
--bs-warning: #ffab00;
|
||||
|
|
@ -33,8 +34,8 @@
|
|||
--bs-light: #dbdee0;
|
||||
--bs-dark: #2b2c40;
|
||||
--bs-gray: rgba(34, 48, 62, 0.5);
|
||||
--bs-primary-rgb: 11, 85, 119;
|
||||
--bs-secondary-rgb: 133, 146, 163;
|
||||
--bs-primary-rgb: 11, 53, 74;
|
||||
--bs-secondary-rgb: 53, 114, 142;
|
||||
--bs-success-rgb: 113, 221, 55;
|
||||
--bs-info-rgb: 3, 195, 236;
|
||||
--bs-warning-rgb: 255, 171, 0;
|
||||
|
|
@ -42,8 +43,8 @@
|
|||
--bs-light-rgb: 219, 222, 224;
|
||||
--bs-dark-rgb: 43, 44, 64;
|
||||
--bs-gray-rgb: 34, 48, 62;
|
||||
--bs-primary-text-emphasis: #2a2b66;
|
||||
--bs-secondary-text-emphasis: #353a41;
|
||||
--bs-primary-text-emphasis: #07354a;
|
||||
--bs-secondary-text-emphasis: #395d6e;
|
||||
--bs-success-text-emphasis: #2d5816;
|
||||
--bs-info-text-emphasis: #014e5e;
|
||||
--bs-warning-text-emphasis: #664400;
|
||||
|
|
@ -98,10 +99,10 @@
|
|||
--bs-tertiary-bg: rgba(34, 48, 62, 0.1);
|
||||
--bs-tertiary-bg-rgb: 34, 48, 62;
|
||||
--bs-heading-color: #384551;
|
||||
--bs-link-color: #0b5577;
|
||||
--bs-link-color: #0b354a;
|
||||
--bs-link-color-rgb: 105, 108, 255;
|
||||
--bs-link-decoration: none;
|
||||
--bs-link-hover-color: #0b5577;
|
||||
--bs-link-hover-color: #0b354a;
|
||||
--bs-link-hover-color-rgb: 95, 97, 230;
|
||||
--bs-code-color: #e83e8c;
|
||||
--bs-highlight-color: #646e78;
|
||||
|
|
@ -7556,7 +7557,7 @@ h6,
|
|||
|
||||
.bg-label-secondary {
|
||||
background-color: #ebeef0 !important;
|
||||
color: #8592a3 !important;
|
||||
color: var(--bs-secondary) !important;
|
||||
}
|
||||
|
||||
.border-label-secondary {
|
||||
|
|
@ -8095,21 +8096,21 @@ label.btn {
|
|||
|
||||
.btn-secondary {
|
||||
color: #fff;
|
||||
background-color: #8592a3;
|
||||
border-color: #8592a3;
|
||||
background-color: var(--bs-secondary);
|
||||
border-color: var(--bs-secondary);
|
||||
box-shadow: 0 0.125rem 0.25rem 0 rgba(133, 146, 163, 0.4);
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
color: #fff !important;
|
||||
background-color: #788393 !important;
|
||||
border-color: #788393 !important;
|
||||
background-color: var(--bs-secondary) !important;
|
||||
border-color: var(--bs-secondary) !important;
|
||||
}
|
||||
.btn-check:focus + .btn-secondary,
|
||||
.btn-secondary:focus,
|
||||
.btn-secondary.focus {
|
||||
color: #fff;
|
||||
background-color: #788393;
|
||||
border-color: #788393;
|
||||
background-color: var(--bs-secondary);
|
||||
border-color: var(--bs-secondary);
|
||||
}
|
||||
.btn-check:checked + .btn-secondary,
|
||||
.btn-check:active + .btn-secondary,
|
||||
|
|
@ -8118,43 +8119,43 @@ label.btn {
|
|||
.btn-secondary.show.dropdown-toggle,
|
||||
.show > .btn-secondary.dropdown-toggle {
|
||||
color: #fff !important;
|
||||
background-color: #788393 !important;
|
||||
border-color: #788393 !important;
|
||||
background-color: var(--bs-secondary) !important;
|
||||
border-color: var(--bs-secondary) !important;
|
||||
}
|
||||
.btn-secondary.disabled,
|
||||
.btn-secondary:disabled {
|
||||
color: #fff !important;
|
||||
background-color: #8592a3 !important;
|
||||
border-color: #8592a3 !important;
|
||||
background-color: var(--bs-secondary) !important;
|
||||
border-color: var(--bs-secondary) !important;
|
||||
}
|
||||
|
||||
.btn-group .btn-secondary,
|
||||
.input-group .btn-secondary {
|
||||
border-right: var(--bs-border-width) solid #788393;
|
||||
border-left: var(--bs-border-width) solid #788393;
|
||||
border-right: var(--bs-border-width) solid var(--bs-secondary);
|
||||
border-left: var(--bs-border-width) solid var(--bs-secondary);
|
||||
}
|
||||
|
||||
.btn-group-vertical .btn-secondary {
|
||||
border-top-color: #788393;
|
||||
border-bottom-color: #788393;
|
||||
border-top-color: var(--bs-secondary);
|
||||
border-bottom-color: var(--bs-secondary);
|
||||
}
|
||||
|
||||
.btn-outline-secondary {
|
||||
color: #8592a3;
|
||||
border-color: #8592a3;
|
||||
color: var(--bs-secondary);
|
||||
border-color: var(--bs-secondary);
|
||||
background: transparent;
|
||||
}
|
||||
.btn-outline-secondary:hover {
|
||||
color: #fff !important;
|
||||
background-color: #788393 !important;
|
||||
border-color: #788393 !important;
|
||||
background-color: var(--bs-secondary) !important;
|
||||
border-color: var(--bs-secondary) !important;
|
||||
box-shadow: 0 0.125rem 0.25rem 0 rgba(133, 146, 163, 0.4) !important;
|
||||
}
|
||||
.btn-check:focus + .btn-outline-secondary,
|
||||
.btn-outline-secondary:focus {
|
||||
color: #fff;
|
||||
background-color: #788393;
|
||||
border-color: #788393;
|
||||
background-color: var(--bs-secondary);
|
||||
border-color: var(--bs-secondary);
|
||||
}
|
||||
.btn-check:checked + .btn-outline-secondary,
|
||||
.btn-check:active + .btn-outline-secondary,
|
||||
|
|
@ -8162,18 +8163,18 @@ label.btn {
|
|||
.btn-outline-secondary.active,
|
||||
.btn-outline-secondary.dropdown-toggle.show {
|
||||
color: #fff !important;
|
||||
background-color: #788393 !important;
|
||||
border-color: #788393 !important;
|
||||
background-color: var(--bs-secondary) !important;
|
||||
border-color: var(--bs-secondary) !important;
|
||||
}
|
||||
.btn-outline-secondary.disabled,
|
||||
.btn-outline-secondary:disabled {
|
||||
color: #8592a3 !important;
|
||||
border-color: #8592a3 !important;
|
||||
color: var(--bs-secondary) !important;
|
||||
border-color: var(--bs-secondary) !important;
|
||||
}
|
||||
|
||||
.btn-outline-secondary .badge {
|
||||
background: #8592a3;
|
||||
border-color: #8592a3;
|
||||
background: var(--bs-secondary);
|
||||
border-color: var(--bs-secondary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
|
@ -8184,7 +8185,7 @@ label.btn {
|
|||
.show > .btn-outline-secondary.dropdown-toggle .badge {
|
||||
background: #fff;
|
||||
border-color: #fff;
|
||||
color: #8592a3;
|
||||
color: var(--bs-secondary);
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
|
|
@ -9537,20 +9538,20 @@ li:not(:first-child) .dropdown-item,
|
|||
.alert-secondary {
|
||||
background-color: #ebeef0;
|
||||
border-color: #ebeef0;
|
||||
color: #8592a3;
|
||||
color: var(--bs-secondary);
|
||||
}
|
||||
.alert-secondary .btn-close {
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='150px' height='151px' viewBox='0 0 150 151' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cdefs%3E%3Cpolygon id='path-1' points='131.251657 0 74.9933705 56.25 18.7483426 0 0 18.75 56.2450278 75 0 131.25 18.7483426 150 74.9933705 93.75 131.251657 150 150 131.25 93.7549722 75 150 18.75'%3E%3C/polygon%3E%3C/defs%3E%3Cg id='🎨-%5BSetup%5D:-Colors-&-Shadows' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E%3Cg id='Artboard' transform='translate(-225.000000, -250.000000)'%3E%3Cg id='Icon-Color' transform='translate(225.000000, 250.500000)'%3E%3Cuse fill='%238592a3' xlink:href='%23path-1'%3E%3C/use%3E%3Cuse fill-opacity='0.5' fill='%238592a3' xlink:href='%23path-1'%3E%3C/use%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='150px' height='151px' viewBox='0 0 150 151' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cdefs%3E%3Cpolygon id='path-1' points='131.251657 0 74.9933705 56.25 18.7483426 0 0 18.75 56.2450278 75 0 131.25 18.7483426 150 74.9933705 93.75 131.251657 150 150 131.25 93.7549722 75 150 18.75'%3E%3C/polygon%3E%3C/defs%3E%3Cg id='🎨-%5BSetup%5D:-Colors-&-Shadows' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E%3Cg id='Artboard' transform='translate(-225.000000, -250.000000)'%3E%3Cg id='Icon-Color' transform='translate(225.000000, 250.500000)'%3E%3Cuse fill='%2335728e' xlink:href='%23path-1'%3E%3C/use%3E%3Cuse fill-opacity='0.5' fill='%2335728e' xlink:href='%23path-1'%3E%3C/use%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
.alert-secondary .alert-link {
|
||||
color: #8592a3;
|
||||
color: var(--bs-secondary);
|
||||
}
|
||||
|
||||
.alert-secondary hr {
|
||||
color: #8592a3 !important;
|
||||
color: var(--bs-secondary) !important;
|
||||
}
|
||||
.alert-secondary .alert-icon {
|
||||
background-color: #8592a3;
|
||||
background-color: var(--bs-secondary);
|
||||
box-shadow: 0 0 0 0.125rem rgba(133, 146, 163, 0.16);
|
||||
}
|
||||
|
||||
|
|
@ -10465,27 +10466,27 @@ form select.selectpicker.is-invalid ~ .btn {
|
|||
}
|
||||
|
||||
.list-group-item-secondary {
|
||||
border-color: #8592a3;
|
||||
border-color: var(--bs-secondary);
|
||||
background-color: #ebeef0;
|
||||
color: #8592a3 !important;
|
||||
color: var(--bs-secondary) !important;
|
||||
}
|
||||
|
||||
a.list-group-item-secondary,
|
||||
button.list-group-item-secondary {
|
||||
color: #8592a3;
|
||||
color: var(--bs-secondary);
|
||||
}
|
||||
a.list-group-item-secondary:hover,
|
||||
a.list-group-item-secondary:focus,
|
||||
button.list-group-item-secondary:hover,
|
||||
button.list-group-item-secondary:focus {
|
||||
border-color: #8592a3;
|
||||
border-color: var(--bs-secondary);
|
||||
background-color: #dde0e2;
|
||||
color: #8592a3;
|
||||
color: var(--bs-secondary);
|
||||
}
|
||||
a.list-group-item-secondary.active,
|
||||
button.list-group-item-secondary.active {
|
||||
border-color: #8592a3 !important;
|
||||
background-color: #8592a3 !important;
|
||||
border-color: var(--bs-secondary) !important;
|
||||
background-color: var(--bs-secondary) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
|
|
@ -11018,7 +11019,7 @@ button.list-group-item-gray.active {
|
|||
}
|
||||
.bg-secondary.toast .toast-header .btn-close,
|
||||
.bg-secondary.bs-toast .toast-header .btn-close {
|
||||
background-color: #8592a3 !important;
|
||||
background-color: var(--bs-secondary) !important;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='150px' height='151px' viewBox='0 0 150 151' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cdefs%3E%3Cpolygon id='path-1' points='131.251657 0 74.9933705 56.25 18.7483426 0 0 18.75 56.2450278 75 0 131.25 18.7483426 150 74.9933705 93.75 131.251657 150 150 131.25 93.7549722 75 150 18.75'%3E%3C/polygon%3E%3C/defs%3E%3Cg id='🎨-%5BSetup%5D:-Colors-&-Shadows' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E%3Cg id='Artboard' transform='translate(-225.000000, -250.000000)'%3E%3Cg id='Icon-Color' transform='translate(225.000000, 250.500000)'%3E%3Cuse fill='%23fff' xlink:href='%23path-1'%3E%3C/use%3E%3Cuse fill-opacity='1' fill='%23fff' xlink:href='%23path-1'%3E%3C/use%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
|
||||
box-shadow: 0 0.1875rem 0.375rem 0 rgba(133, 146, 163, 0.4) !important;
|
||||
}
|
||||
|
|
@ -11508,7 +11509,7 @@ button.list-group-item-gray.active {
|
|||
}
|
||||
|
||||
.border-secondary {
|
||||
border-color: #8592a3 !important;
|
||||
border-color: var(--bs-secondary) !important;
|
||||
}
|
||||
|
||||
.border-success {
|
||||
|
|
@ -22564,19 +22565,13 @@ body {
|
|||
|
||||
@keyframes colorPhase {
|
||||
0% {
|
||||
background-color: var(--bs-primary); /* Start with primary color */
|
||||
box-shadow: 0 1px 20px 1px var(--bs-primary); /* Primary shadow */
|
||||
border-color: var(--bs-primary); /* Primary border color */
|
||||
}
|
||||
50% {
|
||||
background-color: var(--bs-bw-green); /* Transition to secondary color */
|
||||
box-shadow: 0 1px 20px 1px var(--bs-bw-green); /* Secondary shadow */
|
||||
border-color: var(--bs-bw-green); /* Secondary border color */
|
||||
}
|
||||
100% {
|
||||
background-color: var(--bs-primary); /* Back to primary color */
|
||||
box-shadow: 0 1px 20px 1px var(--bs-primary); /* Primary shadow */
|
||||
border-color: var(--bs-primary); /* Primary border color */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -22586,7 +22581,7 @@ body {
|
|||
right: 1.625rem;
|
||||
z-index: 1080;
|
||||
box-shadow: 0 1px 20px 1px var(--bs-primary); /* Initial shadow */
|
||||
background-color: var(--bs-primary); /* Initial background color */
|
||||
background-color: var(--bs-bw-green); /* Initial background color */
|
||||
color: #fff;
|
||||
animation: colorPhase 3s infinite; /* Apply the color phasing animation */
|
||||
transition:
|
||||
|
|
@ -22599,9 +22594,6 @@ body {
|
|||
background-color: var(
|
||||
--bs-bw-green
|
||||
) !important; /* Keep the primary color on hover */
|
||||
border-color: var(
|
||||
--bs-bw-green
|
||||
) !important; /* Keep the primary color on hover */
|
||||
}
|
||||
|
||||
.ui-square,
|
||||
|
|
@ -23930,7 +23922,7 @@ html:not(.layout-footer-fixed) .content-wrapper {
|
|||
background-color: #71dd37;
|
||||
}
|
||||
.avatar.avatar-offline:after {
|
||||
background-color: #8592a3;
|
||||
background-color: var(--bs-secondary);
|
||||
}
|
||||
.avatar.avatar-away:after {
|
||||
background-color: #ffab00;
|
||||
|
|
@ -24124,7 +24116,7 @@ html:not(.layout-footer-fixed) .content-wrapper {
|
|||
|
||||
.divider.divider.divider-secondary .divider-text:before,
|
||||
.divider.divider.divider-secondary .divider-text:after {
|
||||
border-color: #8592a3;
|
||||
border-color: var(--bs-secondary);
|
||||
}
|
||||
|
||||
.divider.divider.divider-success .divider-text:before,
|
||||
|
|
@ -24211,7 +24203,7 @@ html:not(.layout-footer-fixed) .content-wrapper {
|
|||
}
|
||||
.navbar.bg-secondary .search-input-wrapper .search-input,
|
||||
.navbar.bg-secondary .search-input-wrapper .search-toggler {
|
||||
background-color: #8592a3 !important;
|
||||
background-color: var(--bs-secondary) !important;
|
||||
color: #eaecef;
|
||||
}
|
||||
.navbar.bg-secondary .navbar-nav > .nav-link,
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@
|
|||
background-color: var(--bs-bw-green);
|
||||
}
|
||||
|
||||
.pro-icon {
|
||||
/* .pro-icon {
|
||||
position: relative;
|
||||
width: 18px;
|
||||
height: 15.5px;
|
||||
|
|
@ -223,7 +223,7 @@
|
|||
background-image: url("../img/diamond-blue.svg");
|
||||
opacity: 0;
|
||||
animation: fadeIn 1.5s infinite alternate;
|
||||
}
|
||||
} */
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.btn-responsive {
|
||||
|
|
@ -232,10 +232,10 @@
|
|||
line-height: 1;
|
||||
}
|
||||
|
||||
.pro-icon {
|
||||
/* .pro-icon {
|
||||
width: 9px;
|
||||
height: 7.75px;
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
@media (min-width: 769px) and (max-width: 992px) {
|
||||
|
|
@ -287,7 +287,7 @@ td.highlight {
|
|||
|
||||
.btn-outline-bw-green:hover {
|
||||
color: #fff;
|
||||
background-color: var(--bs-primary);
|
||||
background-color: var(--bs-bw-green);
|
||||
}
|
||||
|
||||
.col.form-floating > .form-control-sm,
|
||||
|
|
@ -320,3 +320,81 @@ td.highlight {
|
|||
.form-floating > .form-control.form-control-sm:focus {
|
||||
padding-top: 1.1rem !important;
|
||||
}
|
||||
|
||||
.shine {
|
||||
background-image: linear-gradient(
|
||||
120deg,
|
||||
rgba(46, 172, 104, 0) 0%,
|
||||
rgba(46, 172, 104, 0.8) 50%,
|
||||
rgba(46, 172, 104, 0) 100%
|
||||
);
|
||||
background-size: 40%;
|
||||
background-position: -100% center;
|
||||
background-repeat: no-repeat;
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
color: transparent;
|
||||
animation: shine 8s linear infinite;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
.shine-sm {
|
||||
animation: shineSm 5s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes shine {
|
||||
0% {
|
||||
background-position: -200% center;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% center;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shineSm {
|
||||
0% {
|
||||
background-position: -200% center;
|
||||
}
|
||||
60% {
|
||||
background-position: 200% center;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% center;
|
||||
}
|
||||
}
|
||||
|
||||
.text-primary.shine {
|
||||
color: rgba(var(--bs-primary-rgb), 0.1) !important;
|
||||
background-color: var(--bs-primary) !important;
|
||||
}
|
||||
|
||||
.form-floating > :disabled ~ label::after,
|
||||
.form-floating > .form-control:disabled ~ label::after {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.chevron-icon {
|
||||
padding-bottom: 0.125rem !important;
|
||||
}
|
||||
|
||||
.chevron-rotate {
|
||||
transform: rotate(90deg);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.chevron-rotate-back {
|
||||
transform: rotate(0deg);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.multiple-container:not(:first-child) {
|
||||
border-top: 1px solid var(--bs-primary);
|
||||
}
|
||||
|
||||
a.badge:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.setting-checkbox-label {
|
||||
font-size: calc(var(--bs-body-font-size) * 0.85);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@
|
|||
}
|
||||
|
||||
.text-primary {
|
||||
color: #0b5577 !important;
|
||||
color: #0b354a !important;
|
||||
}
|
||||
|
||||
.text-body[href]:hover,
|
||||
|
|
@ -135,23 +135,23 @@
|
|||
}
|
||||
|
||||
.bg-primary {
|
||||
background-color: #0b5577 !important;
|
||||
background-color: #0b354a !important;
|
||||
}
|
||||
|
||||
a.bg-primary:hover,
|
||||
a.bg-primary:focus {
|
||||
background-color: #0b5577 !important;
|
||||
background-color: #0b354a !important;
|
||||
}
|
||||
|
||||
.dropdown-notifications-item:not(.mark-as-read)
|
||||
.dropdown-notifications-read
|
||||
span {
|
||||
background-color: #0b5577;
|
||||
background-color: #0b354a;
|
||||
}
|
||||
|
||||
.bg-label-primary {
|
||||
background-color: #e7e7ff !important;
|
||||
color: #0b5577 !important;
|
||||
color: #0b354a !important;
|
||||
}
|
||||
|
||||
.border-label-primary {
|
||||
|
|
@ -168,40 +168,40 @@ a.bg-primary:focus {
|
|||
.pagination li.active > a:not(.page-link),
|
||||
.pagination li.active > a:not(.page-link):hover,
|
||||
.pagination li.active > a:not(.page-link):focus {
|
||||
border-color: #0b5577;
|
||||
background-color: #0b5577;
|
||||
border-color: #0b354a;
|
||||
background-color: #0b354a;
|
||||
color: #fff;
|
||||
box-shadow: 0 0.125rem 0.25rem rgba(11, 85, 119, 0.4);
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
background-color: #0b5577;
|
||||
background-color: #0b354a;
|
||||
color: #fff;
|
||||
box-shadow: 0 2px 4px 0 rgba(11, 85, 119, 0.4);
|
||||
}
|
||||
|
||||
.list-group-item-primary {
|
||||
border-color: #0b5577;
|
||||
border-color: #0b354a;
|
||||
background-color: #e7e7ff;
|
||||
color: #0b5577 !important;
|
||||
color: #0b354a !important;
|
||||
}
|
||||
|
||||
a.list-group-item-primary,
|
||||
button.list-group-item-primary {
|
||||
color: #0b5577;
|
||||
color: #0b354a;
|
||||
}
|
||||
a.list-group-item-primary:hover,
|
||||
a.list-group-item-primary:focus,
|
||||
button.list-group-item-primary:hover,
|
||||
button.list-group-item-primary:focus {
|
||||
border-color: #0b5577;
|
||||
border-color: #0b354a;
|
||||
background-color: #d9d9f0;
|
||||
color: #0b5577;
|
||||
color: #0b354a;
|
||||
}
|
||||
a.list-group-item-primary.active,
|
||||
button.list-group-item-primary.active {
|
||||
border-color: #0b5577 !important;
|
||||
background-color: #0b5577 !important;
|
||||
border-color: #0b354a !important;
|
||||
background-color: #0b354a !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
|
|
@ -209,26 +209,26 @@ button.list-group-item-primary.active {
|
|||
.list-group-item.active:hover,
|
||||
.list-group-item.active:focus {
|
||||
background-color: #e7e7ff;
|
||||
color: #0b5577;
|
||||
color: #0b354a;
|
||||
}
|
||||
|
||||
.alert-primary {
|
||||
background-color: #e7e7ff;
|
||||
border-color: #e7e7ff;
|
||||
color: #0b5577;
|
||||
color: #0b354a;
|
||||
}
|
||||
.alert-primary .btn-close {
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='150px' height='151px' viewBox='0 0 150 151' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cdefs%3E%3Cpolygon id='path-1' points='131.251657 0 74.9933705 56.25 18.7483426 0 0 18.75 56.2450278 75 0 131.25 18.7483426 150 74.9933705 93.75 131.251657 150 150 131.25 93.7549722 75 150 18.75'%3E%3C/polygon%3E%3C/defs%3E%3Cg id='🎨-%5BSetup%5D:-Colors-&-Shadows' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E%3Cg id='Artboard' transform='translate(-225.000000, -250.000000)'%3E%3Cg id='Icon-Color' transform='translate(225.000000, 250.500000)'%3E%3Cuse fill='%230b5577' xlink:href='%23path-1'%3E%3C/use%3E%3Cuse fill-opacity='0.5' fill='%230b5577' xlink:href='%23path-1'%3E%3C/use%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='150px' height='151px' viewBox='0 0 150 151' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cdefs%3E%3Cpolygon id='path-1' points='131.251657 0 74.9933705 56.25 18.7483426 0 0 18.75 56.2450278 75 0 131.25 18.7483426 150 74.9933705 93.75 131.251657 150 150 131.25 93.7549722 75 150 18.75'%3E%3C/polygon%3E%3C/defs%3E%3Cg id='🎨-%5BSetup%5D:-Colors-&-Shadows' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E%3Cg id='Artboard' transform='translate(-225.000000, -250.000000)'%3E%3Cg id='Icon-Color' transform='translate(225.000000, 250.500000)'%3E%3Cuse fill='%230B354A' xlink:href='%23path-1'%3E%3C/use%3E%3Cuse fill-opacity='0.5' fill='%230B354A' xlink:href='%23path-1'%3E%3C/use%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
.alert-primary .alert-link {
|
||||
color: #0b5577;
|
||||
color: #0b354a;
|
||||
}
|
||||
|
||||
.alert-primary hr {
|
||||
color: #0b5577 !important;
|
||||
color: #0b354a !important;
|
||||
}
|
||||
.alert-primary .alert-icon {
|
||||
background-color: #0b5577;
|
||||
background-color: #0b354a;
|
||||
box-shadow: 0 0 0 0.125rem rgba(11, 85, 119, 0.16);
|
||||
}
|
||||
|
||||
|
|
@ -250,8 +250,8 @@ button.list-group-item-primary.active {
|
|||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #0b5577;
|
||||
border-color: #0b5577;
|
||||
background-color: #0b354a;
|
||||
border-color: #0b354a;
|
||||
box-shadow: 0 0.125rem 0.25rem 0 rgba(11, 85, 119, 0.4);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
|
|
@ -279,8 +279,8 @@ button.list-group-item-primary.active {
|
|||
.btn-primary.disabled,
|
||||
.btn-primary:disabled {
|
||||
color: #fff !important;
|
||||
background-color: #0b5577 !important;
|
||||
border-color: #0b5577 !important;
|
||||
background-color: #0b354a !important;
|
||||
border-color: #0b354a !important;
|
||||
}
|
||||
|
||||
.btn-group .btn-primary,
|
||||
|
|
@ -295,21 +295,21 @@ button.list-group-item-primary.active {
|
|||
}
|
||||
|
||||
.btn-outline-primary {
|
||||
color: #0b5577;
|
||||
border-color: #0b5577;
|
||||
color: #0b354a;
|
||||
border-color: #0b354a;
|
||||
background: transparent;
|
||||
}
|
||||
.btn-outline-primary:hover {
|
||||
color: #fff !important;
|
||||
background-color: #2eac68 !important;
|
||||
border-color: #2eac68 !important;
|
||||
background-color: #0b354a !important;
|
||||
border-color: #0b354a !important;
|
||||
box-shadow: 0 0.125rem 0.25rem 0 rgba(11, 85, 119, 0.4) !important;
|
||||
}
|
||||
.btn-check:focus + .btn-outline-primary,
|
||||
.btn-outline-primary:focus {
|
||||
color: #fff;
|
||||
background-color: #2eac68;
|
||||
border-color: #2eac68;
|
||||
background-color: #0b354a;
|
||||
border-color: #0b354a;
|
||||
}
|
||||
.btn-check:checked + .btn-outline-primary,
|
||||
.btn-check:active + .btn-outline-primary,
|
||||
|
|
@ -317,18 +317,18 @@ button.list-group-item-primary.active {
|
|||
.btn-outline-primary.active,
|
||||
.btn-outline-primary.dropdown-toggle.show {
|
||||
color: #fff !important;
|
||||
background-color: #2eac68 !important;
|
||||
border-color: #2eac68 !important;
|
||||
background-color: #0b354a !important;
|
||||
border-color: #0b354a !important;
|
||||
}
|
||||
.btn-outline-primary.disabled,
|
||||
.btn-outline-primary:disabled {
|
||||
color: #0b5577 !important;
|
||||
border-color: #0b5577 !important;
|
||||
color: #0b354a !important;
|
||||
border-color: #0b354a !important;
|
||||
}
|
||||
|
||||
.btn-outline-primary .badge {
|
||||
background: #0b5577;
|
||||
border-color: #0b5577;
|
||||
background: #0b354a;
|
||||
border-color: #0b354a;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
|
@ -339,19 +339,19 @@ button.list-group-item-primary.active {
|
|||
.show > .btn-outline-primary.dropdown-toggle .badge {
|
||||
background: #fff;
|
||||
border-color: #fff;
|
||||
color: #0b5577;
|
||||
color: #0b354a;
|
||||
}
|
||||
|
||||
.dropdown-item:not(.disabled).active,
|
||||
.dropdown-item:not(.disabled):active {
|
||||
background-color: rgba(11, 85, 119, 0.16);
|
||||
color: #0b5577 !important;
|
||||
color: #0b354a !important;
|
||||
}
|
||||
|
||||
.dropdown-menu > li:not(.disabled) > a:not(.dropdown-item):active,
|
||||
.dropdown-menu > li.active:not(.disabled) > a:not(.dropdown-item) {
|
||||
background-color: rgba(11, 85, 119, 0.16);
|
||||
color: #0b5577 !important;
|
||||
color: #0b354a !important;
|
||||
}
|
||||
|
||||
.dt-button-collection .dropdown-item:not(.disabled):active {
|
||||
|
|
@ -364,7 +364,7 @@ button.list-group-item-primary.active {
|
|||
.nav-pills .nav-link.active,
|
||||
.nav-pills .nav-link.active:hover,
|
||||
.nav-pills .nav-link.active:focus {
|
||||
background-color: #0b5577;
|
||||
background-color: #0b354a;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
|
@ -374,7 +374,7 @@ button.list-group-item-primary.active {
|
|||
.nav-tabs .nav-link.active,
|
||||
.nav-tabs .nav-link.active:hover,
|
||||
.nav-tabs .nav-link.active:focus {
|
||||
box-shadow: 0 -2px 0 #0b5577 inset;
|
||||
box-shadow: 0 -2px 0 #0b354a inset;
|
||||
}
|
||||
|
||||
.nav-align-bottom .nav-tabs .nav-link.active,
|
||||
|
|
@ -383,7 +383,7 @@ button.list-group-item-primary.active {
|
|||
.nav-align-bottom .nav-tabs .nav-link.active,
|
||||
.nav-align-bottom .nav-tabs .nav-link.active:hover,
|
||||
.nav-align-bottom .nav-tabs .nav-link.active:focus {
|
||||
box-shadow: 0 2px 0 #0b5577 inset;
|
||||
box-shadow: 0 2px 0 #0b354a inset;
|
||||
}
|
||||
|
||||
.nav-align-left .nav-tabs .nav-link.active,
|
||||
|
|
@ -392,7 +392,7 @@ button.list-group-item-primary.active {
|
|||
.nav-align-left .nav-tabs .nav-link.active,
|
||||
.nav-align-left .nav-tabs .nav-link.active:hover,
|
||||
.nav-align-left .nav-tabs .nav-link.active:focus {
|
||||
box-shadow: -2px 0px 0 #0b5577 inset;
|
||||
box-shadow: -2px 0px 0 #0b354a inset;
|
||||
}
|
||||
|
||||
.nav-align-right .nav-tabs .nav-link.active,
|
||||
|
|
@ -401,32 +401,32 @@ button.list-group-item-primary.active {
|
|||
.nav-align-right .nav-tabs .nav-link.active,
|
||||
.nav-align-right .nav-tabs .nav-link.active:hover,
|
||||
.nav-align-right .nav-tabs .nav-link.active:focus {
|
||||
box-shadow: 2px 0px 0 #0b5577 inset;
|
||||
box-shadow: 2px 0px 0 #0b354a inset;
|
||||
}
|
||||
|
||||
.form-control:focus,
|
||||
.form-select:focus {
|
||||
border-color: #0b5577 !important;
|
||||
border-color: #0b354a !important;
|
||||
}
|
||||
|
||||
.input-group:focus-within .form-control,
|
||||
.input-group:focus-within .input-group-text {
|
||||
border-color: #0b5577 !important;
|
||||
border-color: #0b354a !important;
|
||||
}
|
||||
|
||||
.form-check-input:checked {
|
||||
background-color: #0b5577;
|
||||
border-color: #0b5577;
|
||||
background-color: #0b354a;
|
||||
border-color: #0b354a;
|
||||
box-shadow: 0 0.125rem 0.25rem 0 rgba(11, 85, 119, 0.4);
|
||||
}
|
||||
.form-check-input[type="checkbox"]:indeterminate {
|
||||
background-color: #0b5577;
|
||||
border-color: #0b5577;
|
||||
background-color: #0b354a;
|
||||
border-color: #0b354a;
|
||||
box-shadow: 0 0.125rem 0.25rem 0 rgba(11, 85, 119, 0.4);
|
||||
}
|
||||
|
||||
.custom-option.checked {
|
||||
border: 1px solid #0b5577;
|
||||
border: 1px solid #0b354a;
|
||||
}
|
||||
|
||||
.form-switch .form-check-input:focus {
|
||||
|
|
@ -437,7 +437,7 @@ button.list-group-item-primary.active {
|
|||
}
|
||||
|
||||
.form-control:focus ~ .form-label {
|
||||
border-color: #0b5577;
|
||||
border-color: #0b354a;
|
||||
}
|
||||
.form-control:focus ~ .form-label::after {
|
||||
border-color: inherit;
|
||||
|
|
@ -445,7 +445,7 @@ button.list-group-item-primary.active {
|
|||
|
||||
.divider.divider-primary .divider-text:before,
|
||||
.divider.divider-primary .divider-text:after {
|
||||
border-color: #0b5577;
|
||||
border-color: #0b354a;
|
||||
}
|
||||
|
||||
.navbar.bg-primary {
|
||||
|
|
@ -468,7 +468,7 @@ button.list-group-item-primary.active {
|
|||
}
|
||||
.navbar.bg-primary .search-input-wrapper .search-input,
|
||||
.navbar.bg-primary .search-input-wrapper .search-toggler {
|
||||
background-color: #0b5577 !important;
|
||||
background-color: #0b354a !important;
|
||||
color: #e0e1ff;
|
||||
}
|
||||
.navbar.bg-primary .navbar-nav > .nav-link,
|
||||
|
|
@ -517,7 +517,7 @@ button.list-group-item-primary.active {
|
|||
}
|
||||
|
||||
.menu.bg-primary {
|
||||
background-color: #0b5577 !important;
|
||||
background-color: #0b354a !important;
|
||||
color: #e0e1ff;
|
||||
}
|
||||
.menu.bg-primary .menu-link,
|
||||
|
|
@ -578,7 +578,7 @@ button.list-group-item-primary.active {
|
|||
}
|
||||
.menu.bg-primary .menu-inner-shadow {
|
||||
background: linear-gradient(
|
||||
#0b5577 41%,
|
||||
#0b354a 41%,
|
||||
rgba(11, 85, 119, 0.11) 95%,
|
||||
rgba(11, 85, 119, 0)
|
||||
);
|
||||
|
|
@ -630,7 +630,7 @@ button.list-group-item-primary.active {
|
|||
|
||||
@media (max-width: 1199.98px) {
|
||||
.app-brand .layout-menu-toggle {
|
||||
border: 7px solid #0b5577 !important;
|
||||
border: 7px solid #0b354a !important;
|
||||
}
|
||||
}
|
||||
.footer.bg-primary {
|
||||
|
|
@ -671,7 +671,7 @@ button.list-group-item-primary.active {
|
|||
}
|
||||
.bg-primary.toast .toast-header .btn-close,
|
||||
.bg-primary.bs-toast .toast-header .btn-close {
|
||||
background-color: #0b5577 !important;
|
||||
background-color: #0b354a !important;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='150px' height='151px' viewBox='0 0 150 151' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cdefs%3E%3Cpolygon id='path-1' points='131.251657 0 74.9933705 56.25 18.7483426 0 0 18.75 56.2450278 75 0 131.25 18.7483426 150 74.9933705 93.75 131.251657 150 150 131.25 93.7549722 75 150 18.75'%3E%3C/polygon%3E%3C/defs%3E%3Cg id='🎨-%5BSetup%5D:-Colors-&-Shadows' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E%3Cg id='Artboard' transform='translate(-225.000000, -250.000000)'%3E%3Cg id='Icon-Color' transform='translate(225.000000, 250.500000)'%3E%3Cuse fill='%23fff' xlink:href='%23path-1'%3E%3C/use%3E%3Cuse fill-opacity='1' fill='%23fff' xlink:href='%23path-1'%3E%3C/use%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
|
||||
box-shadow: 0 0.1875rem 0.375rem 0 rgba(11, 85, 119, 0.4) !important;
|
||||
}
|
||||
|
|
@ -680,27 +680,27 @@ button.list-group-item-primary.active {
|
|||
.form-floating > .form-control:focus:not(:placeholder-shown) ~ label,
|
||||
.form-floating > .form-select:focus ~ label,
|
||||
.form-floating > .form-select:focus:not(:placeholder-shown) ~ label {
|
||||
color: #0b5577;
|
||||
color: #0b354a;
|
||||
}
|
||||
|
||||
.svg-illustration svg {
|
||||
fill: #0b5577;
|
||||
fill: #0b354a;
|
||||
}
|
||||
|
||||
html:not([dir="rtl"]) .border-primary,
|
||||
html[dir="rtl"] .border-primary {
|
||||
border-color: #0b5577 !important;
|
||||
border-color: #0b354a !important;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0b5577;
|
||||
color: #0b354a;
|
||||
}
|
||||
a:hover {
|
||||
color: #2eac68;
|
||||
}
|
||||
|
||||
.fill-primary {
|
||||
fill: #0b5577;
|
||||
fill: #0b354a;
|
||||
}
|
||||
|
||||
.bg-navbar-theme {
|
||||
|
|
@ -945,14 +945,14 @@ html:not(.layout-menu-collapsed)
|
|||
.menu-sub
|
||||
> .menu-item.active:not(:has(.menu-sub))
|
||||
.menu-icon {
|
||||
color: #0b5577;
|
||||
color: #0b354a;
|
||||
}
|
||||
.bg-menu-theme .menu-inner > .menu-item.active > .menu-link {
|
||||
color: #0b5577;
|
||||
color: #0b354a;
|
||||
background-color: rgba(11, 85, 119, 0.16) !important;
|
||||
}
|
||||
.bg-menu-theme .menu-inner > .menu-item.active:before {
|
||||
background: #0b5577;
|
||||
background: #0b354a;
|
||||
}
|
||||
.bg-menu-theme .menu-sub > .menu-item > .menu-link:before {
|
||||
background-color: #a7acb2 !important;
|
||||
|
|
@ -961,12 +961,12 @@ html:not(.layout-menu-collapsed)
|
|||
.menu-sub
|
||||
> .menu-item.active
|
||||
> .menu-link:not(.menu-toggle):before {
|
||||
background-color: #0b5577 !important;
|
||||
background-color: #0b354a !important;
|
||||
border: 3px solid #e7e7ff !important;
|
||||
}
|
||||
|
||||
.app-brand .layout-menu-toggle {
|
||||
background-color: #0b5577;
|
||||
background-color: #0b354a;
|
||||
border: 7px solid #f5f5f9;
|
||||
}
|
||||
.app-brand .layout-menu-toggle i {
|
||||
|
|
@ -980,11 +980,11 @@ html:not(.layout-menu-collapsed)
|
|||
color: #646e78;
|
||||
}
|
||||
.bg-footer-theme .footer-link {
|
||||
color: #0b5577;
|
||||
color: #0b354a;
|
||||
}
|
||||
.bg-footer-theme .footer-link:hover,
|
||||
.bg-footer-theme .footer-link:focus {
|
||||
color: #0b5577;
|
||||
color: #0b354a;
|
||||
}
|
||||
.bg-footer-theme .footer-link.disabled {
|
||||
color: #a2a8ae !important;
|
||||
|
|
@ -996,7 +996,7 @@ html:not(.layout-menu-collapsed)
|
|||
.bg-footer-theme .active > .footer-link,
|
||||
.bg-footer-theme .footer-link.show,
|
||||
.bg-footer-theme .footer-link.active {
|
||||
color: #0b5577;
|
||||
color: #0b354a;
|
||||
}
|
||||
.bg-footer-theme hr {
|
||||
border-color: rgba(11, 85, 119, 0.075);
|
||||
|
|
|
|||
|
|
@ -154,47 +154,15 @@ $(document).ready(function () {
|
|||
});
|
||||
});
|
||||
|
||||
$("#select-plugin").on("click", function () {
|
||||
$("#plugin-search").focus();
|
||||
$("#pluginsCollapse").on("shown.bs.collapse", () => {
|
||||
$(".chevron-icon")
|
||||
.addClass("chevron-rotate")
|
||||
.removeClass("chevron-rotate-back");
|
||||
});
|
||||
|
||||
$("#plugin-search").on("input", function () {
|
||||
const inputValue = $(this).val().toLowerCase();
|
||||
const dropdownItems = $("#plugins-dropdown-menu li.nav-item");
|
||||
|
||||
dropdownItems.each(function () {
|
||||
const item = $(this);
|
||||
const text = item.text().toLowerCase();
|
||||
console.log(item);
|
||||
const pluginId = item
|
||||
.find("button")
|
||||
.data("bs-target")
|
||||
.replace("#navs-plugins-", "");
|
||||
|
||||
if (text.includes(inputValue) || pluginId.includes(inputValue)) {
|
||||
item.show();
|
||||
} else {
|
||||
item.hide();
|
||||
}
|
||||
});
|
||||
|
||||
// Show "No Item" message if no items match
|
||||
if (dropdownItems.filter(":visible").length === 0) {
|
||||
if ($(".no-items").length === 0) {
|
||||
$("#plugins-dropdown-menu").append(
|
||||
'<li class="no-items dropdown-item text-muted">No Item</li>',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$(".no-items").remove();
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("click", function (event) {
|
||||
if (!$(event.target).closest(".card").length) {
|
||||
$("#plugins-dropdown-menu").removeClass("show");
|
||||
$("#plugin-search").val("");
|
||||
$("#plugin-search").trigger("input");
|
||||
}
|
||||
$("#pluginsCollapse").on("hidden.bs.collapse", () => {
|
||||
$(".chevron-icon")
|
||||
.removeClass("chevron-rotate")
|
||||
.addClass("chevron-rotate-back");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,26 +5,7 @@ $(document).ready(function () {
|
|||
|
||||
const layout = {
|
||||
topStart: {},
|
||||
bottomEnd: {
|
||||
buttons: [
|
||||
{
|
||||
extend: "ping_instances",
|
||||
},
|
||||
{
|
||||
extend: "exec_form",
|
||||
text: '<span class="tf-icons bx bx-refresh bx-18px me-2"></span>Reload',
|
||||
className: "btn btn-sm btn-outline-primary",
|
||||
},
|
||||
{
|
||||
extend: "exec_form",
|
||||
text: '<span class="tf-icons bx bx-stop bx-18px me-2"></span>Stop',
|
||||
className: "btn btn-sm btn-outline-primary",
|
||||
},
|
||||
{
|
||||
extend: "delete_instances",
|
||||
},
|
||||
],
|
||||
},
|
||||
bottomEnd: {},
|
||||
};
|
||||
|
||||
if (instanceNumber > 10) {
|
||||
|
|
@ -37,7 +18,7 @@ $(document).ready(function () {
|
|||
layout.topStart.buttons = [
|
||||
{
|
||||
extend: "colvis",
|
||||
columns: "th:not(:first-child)",
|
||||
columns: "th:not(:first-child):not(:nth-child(2))",
|
||||
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) {
|
||||
|
|
@ -86,6 +67,28 @@ $(document).ready(function () {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
extend: "collection",
|
||||
text: '<span class="tf-icons bx bx-play bx-18px me-2"></span>Actions',
|
||||
className: "btn btn-sm btn-outline-primary",
|
||||
buttons: [
|
||||
{
|
||||
extend: "ping_instances",
|
||||
},
|
||||
{
|
||||
extend: "exec_form",
|
||||
text: '<span class="tf-icons bx bx-refresh bx-18px me-2"></span>Reload',
|
||||
},
|
||||
{
|
||||
extend: "exec_form",
|
||||
text: '<span class="tf-icons bx bx-stop bx-18px me-2"></span>Stop',
|
||||
},
|
||||
{
|
||||
extend: "delete_instances",
|
||||
className: "text-danger",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
extend: "create_instance",
|
||||
},
|
||||
|
|
@ -107,14 +110,14 @@ $(document).ready(function () {
|
|||
const getSelectedInstances = () => {
|
||||
const instances = [];
|
||||
$("tr.selected").each(function () {
|
||||
instances.push($(this).find("td:first").text());
|
||||
instances.push($(this).find("td:eq(1)").text());
|
||||
});
|
||||
return instances;
|
||||
};
|
||||
|
||||
$.fn.dataTable.ext.buttons.create_instance = {
|
||||
text: '<span class="tf-icons bx bx-plus-circle bx-18px me-2"></span>Create<span class="d-none d-md-inline"> new instance</span>',
|
||||
className: "btn btn-sm btn-outline-primary",
|
||||
className: "btn btn-sm btn-outline-bw-green",
|
||||
action: function (e, dt, node, config) {
|
||||
const modal = new bootstrap.Modal($("#modal-create-instance"));
|
||||
modal.show();
|
||||
|
|
@ -127,7 +130,6 @@ $(document).ready(function () {
|
|||
|
||||
$.fn.dataTable.ext.buttons.ping_instances = {
|
||||
text: '<span class="tf-icons bx bx-bell bx-18px me-2"></span>Ping',
|
||||
className: "btn btn-sm btn-outline-primary",
|
||||
action: function (e, dt, node, config) {
|
||||
if (actionLock) {
|
||||
return;
|
||||
|
|
@ -142,6 +144,7 @@ $(document).ready(function () {
|
|||
|
||||
setTimeout(() => {
|
||||
if (actionLock) {
|
||||
$(".dt-button-background").click();
|
||||
$("#loadingModal").modal("show");
|
||||
setTimeout(() => {
|
||||
$("#loadingModal").modal("hide");
|
||||
|
|
@ -250,7 +253,6 @@ $(document).ready(function () {
|
|||
|
||||
$.fn.dataTable.ext.buttons.delete_instances = {
|
||||
text: '<span class="tf-icons bx bx-trash bx-18px me-2"></span>Delete',
|
||||
className: "btn btn-sm btn-outline-danger",
|
||||
action: function (e, dt, node, config) {
|
||||
if (actionLock) {
|
||||
return;
|
||||
|
|
@ -292,6 +294,11 @@ $(document).ready(function () {
|
|||
|
||||
const instances_table = new DataTable("#instances", {
|
||||
columnDefs: [
|
||||
{
|
||||
orderable: false,
|
||||
render: DataTable.render.select(),
|
||||
targets: 0,
|
||||
},
|
||||
{
|
||||
targets: "_all", // Target all columns
|
||||
createdCell: function (td, cellData, rowData, row, col) {
|
||||
|
|
@ -299,18 +306,37 @@ $(document).ready(function () {
|
|||
},
|
||||
},
|
||||
],
|
||||
order: [[6, "desc"]],
|
||||
order: [[7, "desc"]],
|
||||
autoFill: false,
|
||||
colReorder: true,
|
||||
responsive: true,
|
||||
select: {
|
||||
style: "multi+shift",
|
||||
selector: "td:first-child",
|
||||
headerCheckbox: false,
|
||||
},
|
||||
layout: layout,
|
||||
language: {
|
||||
info: "Showing _START_ to _END_ of _TOTAL_ instances",
|
||||
infoEmpty: "No instances available",
|
||||
infoFiltered: "(filtered from _MAX_ total instances)",
|
||||
lengthMenu: "Display _MENU_ instances",
|
||||
zeroRecords: "No matching instances found",
|
||||
select: {
|
||||
rows: {
|
||||
_: "Selected %d instances",
|
||||
0: "No instances selected",
|
||||
1: "Selected 1 instance",
|
||||
},
|
||||
},
|
||||
},
|
||||
initComplete: function (settings, json) {
|
||||
$("#instances_wrapper .btn-secondary").removeClass("btn-secondary");
|
||||
},
|
||||
});
|
||||
|
||||
instances_table.on("mouseenter", "td", function () {
|
||||
const colIdx = instances_table.cell(this).index().column;
|
||||
const rowIdx = instances_table.cell(this).index().row;
|
||||
|
||||
instances_table
|
||||
.cells()
|
||||
|
|
@ -318,8 +344,31 @@ $(document).ready(function () {
|
|||
.each((el) => el.classList.remove("highlight"));
|
||||
|
||||
instances_table
|
||||
.column(colIdx)
|
||||
.cells()
|
||||
.nodes()
|
||||
.each((el) => el.classList.add("highlight"));
|
||||
.each(function (el) {
|
||||
if (instances_table.cell(el).index().row === rowIdx)
|
||||
el.classList.add("highlight");
|
||||
});
|
||||
});
|
||||
|
||||
instances_table.on("mouseleave", "td", function () {
|
||||
instances_table
|
||||
.cells()
|
||||
.nodes()
|
||||
.each((el) => el.classList.remove("highlight"));
|
||||
});
|
||||
|
||||
// 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();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -152,7 +152,9 @@ $(document).ready(function () {
|
|||
|
||||
setTimeout(() => {
|
||||
fadeInPlaceholders();
|
||||
loadSessionData(page);
|
||||
setTimeout(() => {
|
||||
loadSessionData(page);
|
||||
}, 200);
|
||||
}, 50);
|
||||
});
|
||||
|
||||
|
|
|
|||
186
src/ui/app/static/js/plugins-settings.js
Normal file
186
src/ui/app/static/js/plugins-settings.js
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
$(document).ready(() => {
|
||||
let currentPlugin = "general";
|
||||
let currentMode = "easy";
|
||||
let currentType = "all";
|
||||
let currentKeywords = "";
|
||||
const pluginDropdownItems = $("#plugins-dropdown-menu li.nav-item");
|
||||
|
||||
const updateUrlParams = (params) => {
|
||||
// Create a new URL based on the current location (this keeps both the search params and the hash)
|
||||
const newUrl = new URL(window.location.href);
|
||||
|
||||
// Merge existing search parameters with new parameters
|
||||
const searchParams = new URLSearchParams(newUrl.search);
|
||||
|
||||
// Add or update the parameters with the new values passed in the `params` object
|
||||
Object.keys(params).forEach((key) => {
|
||||
searchParams.set(key, params[key]);
|
||||
});
|
||||
|
||||
// Update the search params of the URL
|
||||
newUrl.search = searchParams.toString();
|
||||
|
||||
// Push the updated URL (this keeps the hash and the merged search params)
|
||||
history.pushState(params, document.title, newUrl.toString());
|
||||
};
|
||||
|
||||
$("#select-plugin").on("click", () => $("#plugin-search").focus());
|
||||
|
||||
// Debounce for search input to avoid triggering the search on every keystroke
|
||||
let debounceTimer;
|
||||
$("#plugin-search").on("input", (e) => {
|
||||
clearTimeout(debounceTimer);
|
||||
debounceTimer = setTimeout(() => {
|
||||
const inputValue = e.target.value.toLowerCase();
|
||||
|
||||
pluginDropdownItems.each(function () {
|
||||
const item = $(this);
|
||||
if (currentType !== "all" && item.data("type") !== currentType) return;
|
||||
|
||||
const text = item.text().toLowerCase();
|
||||
const pluginId = item
|
||||
.find("button")
|
||||
.data("bs-target")
|
||||
.replace("#navs-plugins-", "");
|
||||
|
||||
text.includes(inputValue) || pluginId.includes(inputValue)
|
||||
? item.show()
|
||||
: item.hide();
|
||||
});
|
||||
|
||||
// Show "No Item" message if no items match
|
||||
const noVisibleItems =
|
||||
pluginDropdownItems.filter(":visible").length === 0;
|
||||
if (noVisibleItems && $(".no-items").length === 0) {
|
||||
$("#plugins-dropdown-menu").append(
|
||||
'<li class="no-items dropdown-item text-muted">No Item</li>',
|
||||
);
|
||||
} else {
|
||||
$(".no-items").remove();
|
||||
}
|
||||
}, 300); // 300ms delay for debounce
|
||||
});
|
||||
|
||||
$("#select-plugin").on("hidden.bs.dropdown", () => {
|
||||
$("#plugin-search").val("").trigger("input");
|
||||
$(".no-items").remove();
|
||||
});
|
||||
|
||||
const handleModeChange = (targetClass) => {
|
||||
currentMode = targetClass.substring(1).replace("navs-modes-", "");
|
||||
if (currentMode === "easy") {
|
||||
updateUrlParams(currentType !== "all" ? { type: currentType } : {});
|
||||
} else {
|
||||
updateUrlParams({ mode: currentMode });
|
||||
}
|
||||
};
|
||||
|
||||
$('#service-modes-menu button[data-bs-toggle="tab"]').on(
|
||||
"shown.bs.tab",
|
||||
(e) => {
|
||||
handleModeChange($(e.target).data("bs-target"));
|
||||
},
|
||||
);
|
||||
|
||||
const handleTabChange = (targetClass) => {
|
||||
currentPlugin = targetClass.substring(1).replace("navs-plugins-", "");
|
||||
if (currentPlugin === "general" && window.location.hash) {
|
||||
const params = {};
|
||||
if (currentType !== "all") params.type = currentType;
|
||||
if (currentMode !== "easy") params.mode = currentMode;
|
||||
updateUrlParams(params);
|
||||
} else {
|
||||
window.location.hash = currentPlugin;
|
||||
}
|
||||
};
|
||||
|
||||
$('#plugins-dropdown-menu button[data-bs-toggle="tab"]').on(
|
||||
"shown.bs.tab",
|
||||
(e) => {
|
||||
handleTabChange($(e.target).data("bs-target"));
|
||||
},
|
||||
);
|
||||
|
||||
$(".plugin-setting").on("input", function () {
|
||||
const isValid = $(this).data("pattern")
|
||||
? new RegExp($(this).data("pattern")).test($(this).val())
|
||||
: true;
|
||||
$(this)
|
||||
.toggleClass("is-valid", isValid)
|
||||
.toggleClass("is-invalid", !isValid);
|
||||
});
|
||||
|
||||
$(".plugin-setting").on("focusout", function () {
|
||||
$(this).removeClass("is-valid");
|
||||
});
|
||||
|
||||
$(".show-multiple").on("click", function () {
|
||||
const toggleText = $(this).text().trim() === "SHOW" ? "HIDE" : "SHOW";
|
||||
$(this).html(
|
||||
`<i class="bx bx-${
|
||||
toggleText === "SHOW" ? "hide" : "show-alt"
|
||||
} bx-sm"></i> ${toggleText}`,
|
||||
);
|
||||
});
|
||||
|
||||
$(".add-multiple").on("click", function () {
|
||||
const showButtonId = $(this).attr("id").replace("add", "show");
|
||||
if ($(`#${showButtonId}`).text().trim() === "SHOW") {
|
||||
$(`#${showButtonId}`).trigger("click");
|
||||
}
|
||||
});
|
||||
|
||||
$('div[id^="multiple-"]')
|
||||
.filter(function () {
|
||||
return !/^multiple-.*-\d+$/.test($(this).attr("id"));
|
||||
})
|
||||
.each(function () {
|
||||
let defaultValues = true;
|
||||
$(this)
|
||||
.find("input, select")
|
||||
.each(function () {
|
||||
const type = $(this).attr("type");
|
||||
const defaultVal = $(this).data("default");
|
||||
const isChecked =
|
||||
type === "checkbox" &&
|
||||
$(this).prop("checked") === (defaultVal === "yes");
|
||||
const isMatchingValue =
|
||||
type !== "checkbox" && $(this).val() === defaultVal;
|
||||
|
||||
if (!isChecked && !isMatchingValue) defaultValues = false;
|
||||
});
|
||||
|
||||
if (defaultValues) $(`#show-${$(this).attr("id")}`).trigger("click");
|
||||
});
|
||||
|
||||
$("#plugin-type-select").on("change", function () {
|
||||
currentType = $(this).val();
|
||||
const params = currentType === "all" ? {} : { type: currentType };
|
||||
|
||||
updateUrlParams(params);
|
||||
|
||||
pluginDropdownItems.each(function () {
|
||||
$(this).toggle(
|
||||
currentType === "all" || $(this).data("type") === currentType,
|
||||
);
|
||||
});
|
||||
|
||||
const currentPane = $('div[id^="navs-plugins-"].active').first();
|
||||
if (currentPane.data("type") !== currentType) {
|
||||
$(`#plugins-dropdown-menu li.nav-item[data-type="${currentType}"]`)
|
||||
.first()
|
||||
.find("button")
|
||||
.tab("show");
|
||||
}
|
||||
});
|
||||
|
||||
const hash = window.location.hash;
|
||||
if (hash) {
|
||||
const targetTab = $(
|
||||
`button[data-bs-target="#navs-plugins-${hash.substring(1)}"]`,
|
||||
);
|
||||
if (targetTab.length) targetTab.tab("show");
|
||||
}
|
||||
|
||||
$("#plugin-type-select").trigger("change");
|
||||
});
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
{% set current_endpoint = url_for(request.endpoint).split("/")[-1] %}
|
||||
{% set current_endpoint = request.path.split("/")[-1] %}
|
||||
{% set pro_diamond_url = url_for('static', filename='img/diamond.svg') %}
|
||||
{% set avatar_url = url_for('static', filename='img/avatar_profil_BW.png') %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"
|
||||
class="light-style layout-navbar-fixed layout-menu-fixed"
|
||||
|
|
@ -12,54 +14,64 @@
|
|||
<meta name="author" content="Bunkerity" />
|
||||
<title>BunkerWeb UI</title>
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/x-icon" href="img/favicon.ico" />
|
||||
<link rel="icon"
|
||||
type="image/x-icon"
|
||||
href="{{ url_for('static', filename='img/favicon.ico') }}" />
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet"
|
||||
href="fonts/Public_sans.css"
|
||||
href="{{ url_for('static', filename='fonts/Public_sans.css') }}"
|
||||
nonce="{{ style_nonce }}" />
|
||||
<!-- Icons -->
|
||||
<link rel="stylesheet"
|
||||
href="fonts/boxicons.min.css"
|
||||
href="{{ url_for('static', filename='fonts/boxicons.min.css') }}"
|
||||
nonce="{{ style_nonce }}" />
|
||||
<!-- Core CSS -->
|
||||
<link rel="stylesheet" href="css/core.css" nonce="{{ style_nonce }}" />
|
||||
<link rel="stylesheet"
|
||||
href="css/theme-default.css"
|
||||
href="{{ url_for('static', filename='css/core.css') }}"
|
||||
nonce="{{ style_nonce }}" />
|
||||
<link rel="stylesheet"
|
||||
href="{{ url_for('static', filename='css/theme-default.css') }}"
|
||||
nonce="{{ style_nonce }}" />
|
||||
<link rel="stylesheet"
|
||||
href="{{ url_for('static', filename='css/main.css') }}"
|
||||
nonce="{{ style_nonce }}" />
|
||||
<link rel="stylesheet" href="css/main.css" nonce="{{ style_nonce }}" />
|
||||
<!-- Vendors CSS -->
|
||||
<link rel="stylesheet"
|
||||
href="libs/perfect-scrollbar/perfect-scrollbar.css"
|
||||
href="{{ url_for('static', filename='libs/perfect-scrollbar/perfect-scrollbar.css') }}"
|
||||
nonce="{{ style_nonce }}" />
|
||||
{% if current_endpoint == "home" %}
|
||||
<link rel="stylesheet"
|
||||
href="libs/apexcharts/apexcharts.css"
|
||||
href="{{ url_for('static', filename='libs/apexcharts/apexcharts.css') }}"
|
||||
nonce="{{ style_nonce }}" />
|
||||
{% elif current_endpoint == "instances" %}
|
||||
<link rel="stylesheet"
|
||||
href="libs/datatables/datatables.min.css"
|
||||
href="{{ url_for('static', filename='libs/datatables/datatables.min.css') }}"
|
||||
nonce="{{ style_nonce }}" />
|
||||
<link rel="stylesheet"
|
||||
href="css/pages/instances.css"
|
||||
href="{{ url_for('static', filename='css/pages/instances.css') }}"
|
||||
nonce="{{ style_nonce }}" />
|
||||
{% endif %}
|
||||
<!-- Page CSS -->
|
||||
<!-- Page -->
|
||||
{% if current_endpoint == "login" or current_endpoint == "totp" %}
|
||||
<link rel="stylesheet" href="css/pages/login.css" nonce="{{ style_nonce }}" />
|
||||
<link rel="stylesheet"
|
||||
href="{{ url_for('static', filename='css/pages/login.css') }}"
|
||||
nonce="{{ style_nonce }}" />
|
||||
{% elif current_endpoint == "loading" %}
|
||||
<link rel="stylesheet"
|
||||
href="css/pages/loading.css"
|
||||
href="{{ url_for('static', filename='css/pages/loading.css') }}"
|
||||
nonce="{{ style_nonce }}" />
|
||||
{% elif current_endpoint == "profile" %}
|
||||
<link rel="stylesheet"
|
||||
href="css/pages/profile.css"
|
||||
href="{{ url_for('static', filename='css/pages/profile.css') }}"
|
||||
nonce="{{ style_nonce }}" />
|
||||
{% endif %}
|
||||
<!-- Helpers -->
|
||||
<script src="js/helpers.js" nonce="{{ script_nonce }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/helpers.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
<!-- Config -->
|
||||
<script src="js/config.js" nonce="{{ script_nonce }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/config.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -68,33 +80,52 @@
|
|||
{% endif %}
|
||||
{% block page %}{% endblock %}
|
||||
<!-- Vendors JS -->
|
||||
<script src="libs/jquery/jquery.min.js" nonce="{{ script_nonce }}"></script>
|
||||
<script src="libs/popper/popper.min.js" nonce="{{ script_nonce }}"></script>
|
||||
<script src="libs/bootstrap/bootstrap.bundle.min.js"
|
||||
<script src="{{ url_for('static', filename='libs/jquery/jquery.min.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
<script src="libs/perfect-scrollbar/perfect-scrollbar.min.js"
|
||||
<script src="{{ url_for('static', filename='libs/popper/popper.min.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
<script src="{{ url_for('static', filename='libs/bootstrap/bootstrap.bundle.min.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
<script src="{{ url_for('static', filename='libs/perfect-scrollbar/perfect-scrollbar.min.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
<script src="{{ url_for('static', filename='libs/purify/purify.min.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
<script src="libs/purify/purify.min.js" nonce="{{ script_nonce }}"></script>
|
||||
{% if current_endpoint == "instances" %}
|
||||
<script src="libs/datatables/datatables.min.js" nonce="{{ script_nonce }}"></script>
|
||||
<script src="{{ url_for('static', filename='libs/datatables/datatables.min.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
{% endif %}
|
||||
<!-- Core JS -->
|
||||
<script src="js/menu.js" nonce="{{ script_nonce }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/menu.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
{% if current_endpoint == "home" %}
|
||||
<script src="libs/apexcharts/apexcharts.min.js" nonce="{{ script_nonce }}"></script>
|
||||
<script src="js/dashboards-analytics.js" nonce="{{ script_nonce }}"></script>
|
||||
<script src="{{ url_for('static', filename='libs/apexcharts/apexcharts.min.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/dashboards-analytics.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
{% endif %}
|
||||
<!-- Main JS -->
|
||||
<script src="js/main.js" nonce="{{ script_nonce }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
{% if current_endpoint != "login" and current_endpoint != "totp" %}
|
||||
<script async defer src="js/sidebar.js" nonce="{{ script_nonce }}"></script>
|
||||
<script async
|
||||
defer
|
||||
src="{{ url_for('static', filename='js/sidebar.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
{% endif %}
|
||||
{% if current_endpoint == "global-config" or (current_endpoint != "services" and "services" in request.path) %}
|
||||
<script async
|
||||
defer
|
||||
src="{{ url_for('static', filename='js/plugins-settings.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
{% endif %}
|
||||
<!-- Page JS -->
|
||||
{% if current_endpoint == "profile" %}
|
||||
<script src="js/pages/profile.js" nonce="{{ script_nonce }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/pages/profile.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
{% elif current_endpoint == "instances" %}
|
||||
<script src="js/pages/instances.js" nonce="{{ script_nonce }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/pages/instances.js') }}"
|
||||
nonce="{{ script_nonce }}"></script>
|
||||
{% endif %}
|
||||
<script async defer src="js/buttons.js"></script>
|
||||
<script async defer src="{{ url_for('static', filename='js/buttons.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,21 @@
|
|||
<nav class="d-flex align-items-center" aria-label="breadcrumb">
|
||||
<ol class="breadcrumb mb-0">
|
||||
<!-- prettier-ignore -->
|
||||
{% with breadcrumbs = url_for(request.endpoint).split("/") %}
|
||||
{% with last_crumb = breadcrumbs[-1] %}
|
||||
{% for breadcrumb in breadcrumbs[1:] %}
|
||||
{% if breadcrumb == last_crumb %}
|
||||
<li class="breadcrumb-item active" aria-current="page">{% else %}</li>
|
||||
<li class="breadcrumb-item">
|
||||
{% endif %}
|
||||
<a href="{{ url_for(breadcrumb) }}">{{ breadcrumb }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
{% set breadcrumbs_url = url_for(request.endpoint) %}
|
||||
{% if current_endpoint != "services" and "services" in request.path %}
|
||||
{% set breadcrumbs_url = url_for("services") + "/" + current_endpoint %}
|
||||
{% endif %}
|
||||
{% with breadcrumbs = breadcrumbs_url.split("/") %}
|
||||
{% for breadcrumb in breadcrumbs[1:] %}
|
||||
{% set breadcrumb_url = url_for(breadcrumb.replace('_', '-')) %}
|
||||
{% if breadcrumb == current_endpoint %}
|
||||
{% set breadcrumb_url = breadcrumbs_url %}
|
||||
{% 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>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
</ol>
|
||||
</nav>
|
||||
|
|
|
|||
|
|
@ -13,16 +13,18 @@
|
|||
<!-- prettier-ignore -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-5">
|
||||
{% include "breadcrumb.html" %}
|
||||
{% if "services" in request.path %}
|
||||
<ul class="nav nav-pills flex-column flex-md-row" role="tablist">
|
||||
{% if current_endpoint != "services" and "services" in request.path %}
|
||||
<ul id="service-modes-menu"
|
||||
class="nav nav-pills flex-column flex-md-row"
|
||||
role="tablist">
|
||||
<li class="nav-item me-0 me-sm-3" role="presentation">
|
||||
<button type="button"
|
||||
class="rounded-pill nav-link d-flex align-items-center active"
|
||||
class="rounded-pill nav-link d-flex align-items-center{% if mode == 'easy' %} active{% endif %}"
|
||||
role="tab"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#navs-pills-easy"
|
||||
aria-controls="navs-pills-easy"
|
||||
aria-selected="true">
|
||||
data-bs-target="#navs-modes-easy"
|
||||
aria-controls="navs-modes-easy"
|
||||
{% if mode == 'easy' %}aria-selected="true"{% endif %}>
|
||||
<i class="bx bx-customize bx-sm"></i>
|
||||
|
||||
<span class="d-none d-sm-inline">Easy</span>
|
||||
|
|
@ -30,11 +32,12 @@
|
|||
</li>
|
||||
<li class="nav-item me-0 me-sm-3" role="presentation">
|
||||
<button type="button"
|
||||
class="rounded-pill nav-link d-flex align-items-center"
|
||||
class="rounded-pill nav-link d-flex align-items-center{% if mode == 'advanced' %} active{% endif %}"
|
||||
role="tab"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#navs-pills-advanced"
|
||||
aria-controls="navs-pills-advanced">
|
||||
data-bs-target="#navs-modes-advanced"
|
||||
aria-controls="navs-modes-advanced"
|
||||
{% if mode == 'advanced' %}aria-selected="true"{% endif %}>
|
||||
<i class="bx bx-shield-quarter bx-sm"></i>
|
||||
|
||||
<span class="d-none d-sm-inline">Advanced</span>
|
||||
|
|
@ -42,11 +45,12 @@
|
|||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button type="button"
|
||||
class="rounded-pill nav-link d-flex align-items-center"
|
||||
class="rounded-pill nav-link d-flex align-items-center{% if mode == 'raw' %} active{% endif %}"
|
||||
role="tab"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#navs-pills-raw"
|
||||
aria-controls="navs-pills-raw">
|
||||
data-bs-target="#navs-modes-raw"
|
||||
aria-controls="navs-modes-raw"
|
||||
{% if mode == 'raw' %}aria-selected="true"{% endif %}>
|
||||
<i class="bx bx-notepad bx-sm"></i>
|
||||
|
||||
<span class="d-none d-sm-inline">Raw</span>
|
||||
|
|
@ -62,7 +66,7 @@
|
|||
href="https://panel.bunkerweb.io/order/support/?utm_campaign=self&utm_source=ui"
|
||||
target="_blank"
|
||||
rel="noopener">
|
||||
<span class="bx bx-help-circle bx-18px me-0 me-md-2"></span>
|
||||
<span class="bx bx-help-circle me-0 me-md-2"></span>
|
||||
<span class="d-none d-md-inline">Need help?</span>
|
||||
</a>
|
||||
</li>
|
||||
|
|
@ -74,7 +78,7 @@
|
|||
data-bs-toggle="offcanvas"
|
||||
data-bs-target="#side-offcanvas"
|
||||
aria-controls="side-offcanvas">
|
||||
<span class="bx bx-news bx-18px me-0 me-md-2"></span>
|
||||
<span class="bx bx-news me-0 me-md-2"></span>
|
||||
<span class="d-none d-md-inline">News</span>
|
||||
</button>
|
||||
</li>
|
||||
|
|
@ -94,7 +98,10 @@
|
|||
target="_blank"
|
||||
rel="noopener">
|
||||
<span class="me-1 me-md-2 d-flex h-100 justify-content-center align-items-center">
|
||||
<div class="pro-icon"></div>
|
||||
<img src="{{ pro_diamond_url }}"
|
||||
alt="Pro plugin"
|
||||
width="18px"
|
||||
height="15.5px">
|
||||
</span>
|
||||
Upgrade to Pro</a>
|
||||
</div>
|
||||
|
|
|
|||
6
src/ui/app/templates/global_config.html
Normal file
6
src/ui/app/templates/global_config.html
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{% extends "dashboard.html" %}
|
||||
{% block content %}
|
||||
<!-- Content -->
|
||||
{% include "models/plugins_settings.html" %}
|
||||
<!-- / Content -->
|
||||
{% endblock %}
|
||||
|
|
@ -26,32 +26,40 @@
|
|||
<table id="instances" class="table w-100">
|
||||
<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="top"
|
||||
data-bs-placement="bottom"
|
||||
data-bs-original-title="The hostname of the Instance">Hostname</th>
|
||||
<th data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
data-bs-placement="bottom"
|
||||
data-bs-original-title="The user defined or auto-generated Instance's name">Name</th>
|
||||
<th data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
data-bs-placement="bottom"
|
||||
data-bs-original-title="The creation method of the Instance">Method</th>
|
||||
<th data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
data-bs-placement="bottom"
|
||||
data-bs-original-title="The Instance's health status">Health</th>
|
||||
<th data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
data-bs-placement="bottom"
|
||||
data-bs-original-title="The Instance's type">Type</th>
|
||||
<th data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
data-bs-placement="bottom"
|
||||
data-bs-original-title="The date and time when the Instance was created">Created</th>
|
||||
<th data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
data-bs-placement="bottom"
|
||||
data-bs-original-title="The date and time when the Instance was last seen">Last Seen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for instance in instances %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>{{ instance.hostname }}</td>
|
||||
<td>{{ instance.name }}</td>
|
||||
<td id="method-{{ instance.hostname }}">{{ instance.method }}</td>
|
||||
|
|
@ -69,11 +77,11 @@
|
|||
</td>
|
||||
<td>
|
||||
{% if instance.type == "container" %}
|
||||
<i class="bx bx-18px bxl-docker"></i> Container
|
||||
<i class="bx bxl-docker"></i> Container
|
||||
{% elif instance.type == "pod" %}
|
||||
<i class="bx bx-18px bxl-kubernetes"></i> Pod
|
||||
<i class="bx bxl-kubernetes"></i> Pod
|
||||
{% else %}
|
||||
<i class="bx bx-18px bx-microchip"></i> Static
|
||||
<i class="bx bx-microchip"></i> Static
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ instance.creation_date.astimezone().strftime("%Y-%m-%d %H:%M:%S %Z") }}</td>
|
||||
|
|
@ -98,7 +106,7 @@
|
|||
data-bs-dismiss="toast"
|
||||
aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body">If you read this, ck-t means that you're curious 👀</div>
|
||||
<div class="toast-body">If you read this, it means that you're curious 👀</div>
|
||||
</div>
|
||||
<div class="modal fade"
|
||||
id="modal-create-instance"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
<div class="container-xxl d-flex justify-content-center align-items-center min-vh-100">
|
||||
<div class="layout-main-wrapper">
|
||||
<div class="layout-main-placeholder">
|
||||
<img src="img/logo-menu-2.png" class="img-fluid pulsating" alt="Logo" />
|
||||
<img src="{{ url_for('static', filename='img/logo-menu-2.png') }}"
|
||||
class="img-fluid pulsating"
|
||||
alt="Logo" />
|
||||
</div>
|
||||
{% if message %}
|
||||
<div class="layout-main-info">
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
rel="noopener"
|
||||
class="app-brand-link gap-2">
|
||||
<span class="app-brand-logo login w-75">
|
||||
<img class="img-fluid" src="img/logo-menu.png" alt="BunkerWeb logo">
|
||||
<img class="img-fluid"
|
||||
src="{{ url_for('static', filename='img/logo-menu.png') }}"
|
||||
alt="BunkerWeb logo">
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
<!-- Menu -->
|
||||
<aside id="layout-menu" class="layout-menu menu-vertical menu bg-menu-theme">
|
||||
<div class="app-brand main">
|
||||
<div class="app-brand main mb-2">
|
||||
<a href="https://www.bunkerweb.io/?utm_campaign=self&utm_source=ui"
|
||||
target="_blank"
|
||||
class="app-brand-link">
|
||||
<span class="app-brand-logo main w-100">
|
||||
<img class="img-fluid" src="img/logo-menu.png" alt="BunkerWeb logo">
|
||||
<img class="img-fluid"
|
||||
src="{{ url_for('static', filename='img/logo-menu.png') }}"
|
||||
alt="BunkerWeb logo">
|
||||
</span>
|
||||
</a>
|
||||
<a href="javascript:void(0);"
|
||||
|
|
@ -13,7 +15,7 @@
|
|||
<i class="bx bx-chevron-left bx-sm d-flex align-items-center justify-content-center"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="menu-inner-shadow"></div>
|
||||
<div class="border border-primary border-0 border-top"></div>
|
||||
{% with menu_items = {
|
||||
"home": {"url": url_for('home'), "icon": "bx-home-smile"},
|
||||
"instances": {"url": url_for('instances'), "icon": "bx-server"},
|
||||
|
|
@ -29,7 +31,7 @@
|
|||
} %}
|
||||
<ul class="menu-inner py-1">
|
||||
{% for endpoint, item in menu_items.items() %}
|
||||
<li class="menu-item {% if current_endpoint == endpoint %}active{% endif %} {% if item.get('sub') and item.get('open', True) %}open{% endif %}">
|
||||
<li class="menu-item {% if endpoint in request.path %}active{% endif %} {% if item.get('sub') and item.get('open', True) %}open{% endif %}">
|
||||
<a href="{{ item['url'] }}"
|
||||
class="menu-link {% if item.get('sub') %}menu-toggle{% endif %}">
|
||||
<i class="menu-icon tf-icons bx {{ item['icon'] }}"></i>
|
||||
|
|
@ -59,31 +61,51 @@
|
|||
</li>
|
||||
{% endfor %}
|
||||
<!-- Plugins Pages -->
|
||||
<li class="menu-header small text-uppercase">
|
||||
<li class="menu-header text-uppercase align-items-center">
|
||||
<span class="menu-header-text">Plugins Pages</span>
|
||||
<button class="btn btn-link menu-header-text p-0"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#pluginsCollapse"
|
||||
aria-expanded="true"
|
||||
aria-controls="pluginsCollapse">
|
||||
<i class="bx bx-chevron-right chevron-icon chevron-rotate"></i>
|
||||
</button>
|
||||
</li>
|
||||
{% for plugin in plugins %}
|
||||
{% with not_pro_pro_plugin = not is_pro_version and plugin['type'] == "pro" %}
|
||||
{% if not_pro_pro_plugin or plugin['page'] %}
|
||||
<li class="menu-item {% if current_endpoint == plugin['id'] %}active{% endif %}">
|
||||
<a href="{% if not_pro_pro_plugin %}https://panel.bunkerweb.io/?utm_campaign=self&utm_source=ui#pro{% else %}{{ url_for("plugins") }}/{{ plugin['id'] }}{% endif %}"
|
||||
class="menu-link">
|
||||
<i class="menu-icon tf-icons bx bx-puzzle"></i>
|
||||
<div class="text-truncate" data-i18n="{{ plugin['name'] }}">{{ plugin['name'] }}</div>
|
||||
{% if plugin['type'] != "pro" %}
|
||||
<div class="badge rounded-pill bg-label-{% if plugin['type'] == 'core' %}secondary{% else %}primary{% endif %} text-uppercase fs-tiny ms-auto">
|
||||
{{ plugin['type'].title() }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="badge badge-center rounded-pill text-uppercase fs-tiny ms-auto">
|
||||
<img src="img/diamond.svg" alt="Pro plugin" width="18px" height="15.5px">
|
||||
</div>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
<div class="collapse show" id="pluginsCollapse">
|
||||
{% for plugin in plugins %}
|
||||
{% with not_pro_pro_plugin = not is_pro_version and plugin['type'] == "pro" %}
|
||||
{% if not_pro_pro_plugin or plugin['page'] %}
|
||||
<li class="menu-item {% if current_endpoint == plugin['id'] %}active{% endif %}">
|
||||
<a href="{% if not_pro_pro_plugin %}https://panel.bunkerweb.io/?utm_campaign=self&utm_source=ui#pro{% else %}{{ url_for("plugins") }}/{{ plugin['id'] }}{% endif %}"
|
||||
class="menu-link"
|
||||
{% if not_pro_pro_plugin %}target="_blank" rel="noopener"{% endif %}>
|
||||
<i class="menu-icon tf-icons bx bx-puzzle"></i>
|
||||
<div class="text-truncate{% if plugin['type'] == 'pro' %} text-primary shine shine-sm{% endif %}"
|
||||
data-i18n="{{ plugin['name'] }}">{{ plugin['name'] }}</div>
|
||||
{% if plugin['type'] != "pro" %}
|
||||
<div class="badge rounded-pill bg-label-{% if plugin['type'] == 'core' %}secondary{% else %}primary{% endif %} text-uppercase fs-tiny ms-auto">
|
||||
{{ plugin['type'].title() }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="badge badge-center rounded-pill text-uppercase fs-tiny ms-auto"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
data-bs-html="true"
|
||||
title="<i class='bx bx-diamond bx-xs'></i><span>Pro feature</span>">
|
||||
<img src="{{ pro_diamond_url }}"
|
||||
alt="Pro plugin"
|
||||
width="18px"
|
||||
height="15.5px">
|
||||
</div>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<!-- / Plugins Pages -->
|
||||
<!-- Misc -->
|
||||
<li class="menu-header small text-uppercase">
|
||||
<span class="menu-header-text">Misc</span>
|
||||
|
|
|
|||
13
src/ui/app/templates/models/checkbox_setting.html
Normal file
13
src/ui/app/templates/models/checkbox_setting.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<div class="form-check form-switch mt-1">
|
||||
<input id="{{ setting_id_prefix }}setting-{{ plugin['id'] }}-{{ setting_data['id'] }}"
|
||||
name="{{ setting }}"
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
aria-labelledby="label-{{ plugin['id'] }}-{{ setting_data['id'] }}"
|
||||
data-default="{{ setting_data['default'] }}"
|
||||
{% if setting_value == "yes" %}checked{% endif %}
|
||||
{% if disabled %}disabled{% endif %}>
|
||||
<label class="form-check setting-checkbox-label d-flex align-items-center ps-0"
|
||||
for="{{ setting_id_prefix }}setting-{{ plugin['id'] }}-{{ setting_data['id'] }}">{{ setting }}</label>
|
||||
</div>
|
||||
15
src/ui/app/templates/models/input_setting.html
Normal file
15
src/ui/app/templates/models/input_setting.html
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<div class="form-floating mt-1{% if setting_data['type'] == 'password' %} input-group input-group-merge form-password-toggle{% endif %}">
|
||||
<input id="{{ setting_id_prefix }}setting-{{ plugin['id'] }}-{{ setting_data['id'] }}"
|
||||
name="{{ setting }}"
|
||||
type="{{ setting_data['type'] }}"
|
||||
class="form-control plugin-setting"
|
||||
aria-labelledby="label-{{ plugin['id'] }}-{{ setting_data['id'] }}"
|
||||
pattern="{{ setting_data['regex'] }}"
|
||||
value="{{ setting_value }}"
|
||||
data-default="{{ setting_data['default'] }}"
|
||||
{% if disabled %}disabled{% endif %}>
|
||||
<label for="{{ setting_id_prefix }}setting-{{ plugin['id'] }}-{{ setting_data['id'] }}">{{ setting }}</label>
|
||||
{% if setting_data['type'] == 'password' %}
|
||||
<span class="input-group-text cursor-pointer"><i class="bx bx-hide"></i></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
240
src/ui/app/templates/models/plugins_settings.html
Normal file
240
src/ui/app/templates/models/plugins_settings.html
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
{% set blacklisted_settings = get_blacklisted_settings(current_endpoint == "global-config") %}
|
||||
<div class="card p-1 mb-4">
|
||||
<div class="d-flex flex-wrap justify-content-around align-items-center">
|
||||
<div class="dropdown btn-group">
|
||||
<button id="select-plugin"
|
||||
type="button"
|
||||
class="btn btn-outline-primary dropdown-toggle"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
<i class="bx bx-extension"></i>
|
||||
<span class="d-none d-md-inline"> Plugins</span>
|
||||
</button>
|
||||
<ul id="plugins-dropdown-menu"
|
||||
class="dropdown-menu nav-pills max-vh-60 overflow-auto pt-0"
|
||||
role="tablist">
|
||||
<div class="input-group input-group-merge mb-2">
|
||||
<span class="input-group-text p-2 border-0 border-primary border-bottom shadow-none"><i class="bx fs-6 bx-search"></i></span>
|
||||
<input id="plugin-search"
|
||||
type="text"
|
||||
class="form-control border-0 border-primary border-bottom shadow-none"
|
||||
placeholder="Search..."
|
||||
aria-label="Search...">
|
||||
</div>
|
||||
{% for plugin in plugins if get_filtered_settings(plugin["settings"], current_endpoint == "global-config") %}
|
||||
<li class="nav-item" data-type="{{ plugin['type'] }}">
|
||||
<button type="button"
|
||||
class="dropdown-item{% if loop.index == 1 %} active{% endif %}"
|
||||
role="tab"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#navs-plugins-{{ plugin['id'] }}"
|
||||
aria-controls="navs-plugins-{{ plugin['id'] }}"
|
||||
{% if loop.index == 1 %}aria-selected="true"{% endif %}>{{ plugin["name"] }}</button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="row align-items-center">
|
||||
<div class="col form-floating ps-0 pe-0 pe-md-2">
|
||||
<input id="plugin-keyword-search"
|
||||
type="text"
|
||||
class="form-control form-control-sm border-0 border-primary border-bottom shadow-none"
|
||||
placeholder="Keywords...">
|
||||
<label for="plugin-keyword-search">Keywords</label>
|
||||
</div>
|
||||
<div class="col-auto form-floating ps-0 pe-0 d-none d-md-block">
|
||||
<select id="plugin-type-select"
|
||||
class="form-select form-select-sm border-0 border-primary border-bottom shadow-none">
|
||||
<option value="all"{% if type == "all" %} selected{% endif %} value="all">All</option>
|
||||
<option value="core"{% if type == "core" %} selected{% endif %}>Core</option>
|
||||
<option value="external"{% if type == "external" %} selected{% endif %}>External</option>
|
||||
<option value="pro"{% if type == "pro" %} selected{% endif %}>Pro</option>
|
||||
</select>
|
||||
<label for="plugin-type-select">Type</label>
|
||||
</div>
|
||||
</div>
|
||||
<button id="save-settings"
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline-bw-green">
|
||||
<i class="bx bx-save bx-sm"></i>
|
||||
<span class="d-none d-md-inline"> Save</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% set plugin_types = {
|
||||
"core": {
|
||||
"icon": "<i class=\"bx bx-cube\"></i>",
|
||||
"title-class": " border-dark"
|
||||
},
|
||||
"external": {
|
||||
"icon": "<i class=\"bx bx-plug\"></i>",
|
||||
"title-class": " border-secondary text-secondary fw-bold"
|
||||
},
|
||||
"pro": {
|
||||
"title-class": " border-primary text-primary fw-bold shine"
|
||||
}
|
||||
} %}
|
||||
<div class="card tab-content position-relative">
|
||||
{% for plugin in plugins if get_filtered_settings(plugin["settings"], current_endpoint == "global-config") %}
|
||||
<div id="navs-plugins-{{ plugin['id'] }}"
|
||||
class="tab-pane fade{% if loop.index == 1 %} show active{% endif %}"
|
||||
role="tabpanel"
|
||||
aria-labelledby="navs-plugins-{{ plugin['id'] }}-tab"
|
||||
data-type="{{ plugin['type'] }}">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title d-inline border p-2{{ plugin_types[plugin['type']].get('title-class', '') }}">
|
||||
{{ plugin["name"] }} - v{{ plugin["version"] }} - {{ plugin_types[plugin["type"]].get('icon', '<img src="' + pro_diamond_url + '"
|
||||
alt="Pro plugin"
|
||||
width="18px"
|
||||
height="15.5px">') |safe }}
|
||||
</h5>
|
||||
<p class="card-subtitle text-muted mt-2">{{ plugin["description"] }}</p>
|
||||
</div>
|
||||
<div class="card-body row pb-0">
|
||||
{% for setting, setting_data in get_filtered_settings(plugin["settings"], current_endpoint == "global-config").items() if not setting_data.get('multiple', false) and setting not in blacklisted_settings and (not service_endpoint or setting_data['context'] == "multisite") %}
|
||||
{% set setting_config = config.get(setting, {}) %}
|
||||
{% set setting_value = setting_config.get("value", setting_data["default"]) %}
|
||||
{% set setting_method = setting_config.get("method", "default") %}
|
||||
{% set setting_template = setting_config.get("template", "") %}
|
||||
{% set disabled = setting_method not in ('ui', 'default') %}
|
||||
<div class="col-12 col-sm-6 col-lg-4 pb-3"
|
||||
{% if disabled %}data-bs-toggle="tooltip" data-bs-placement="top" title="Disabled by {{ setting_method }}"{% endif %}>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<label id="label-{{ plugin['id'] }}-{{ setting_data['id'] }}"
|
||||
for="setting-{{ plugin['id'] }}-{{ setting_data['id'] }}"
|
||||
class="form-label fw-semibold text-truncate">
|
||||
{{ setting_data["label"]|capitalize }}
|
||||
</label>
|
||||
<div class="d-flex align-items-center">
|
||||
{% if current_endpoint == "global-config" and setting_data["context"] == "multisite" %}
|
||||
<a role="badge"
|
||||
href='https://docs.bunkerweb.io/latest/concepts/?utm_campaign=self&utm_source=ui#multisite-mode'
|
||||
class="badge badge-center rounded-pill bg-secondary d-flex align-items-center justify-content-center p-1 me-1"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="Multisite setting"
|
||||
target="_blank"
|
||||
rel="noopener">
|
||||
<span class="bx bx-server bx-xs"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if setting_template %}
|
||||
<span class="badge badge-center rounded-pill bg-secondary d-flex align-items-center justify-content-center p-1 me-1"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="From template: {{ setting_template }}">
|
||||
<span class="bx bx-spreadsheet bx-xs"></span>
|
||||
</span>
|
||||
{% endif %}
|
||||
<span class="badge rounded-pill bg-secondary-subtle text-dark d-flex align-items-center justify-content-center p-1"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="{{ setting_data['help']|capitalize }}">
|
||||
<span class="bx bx-question-mark bx-xs"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% if setting_data["type"] == "select" %}
|
||||
{% include "models/select_setting.html" %}
|
||||
{% elif setting_data["type"] == "check" %}
|
||||
{% include "models/checkbox_setting.html" %}
|
||||
{% else %}
|
||||
{% include "models/input_setting.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% set multiples = get_multiples(get_filtered_settings(plugin["settings"], current_endpoint == "global-config")) %}
|
||||
{% if multiples %}
|
||||
{% set setting_id_prefix = "multiple-" %}
|
||||
{% set multiple_multiples = multiples|length > 1 %}
|
||||
<div class="card-body row card-body row border-primary border-top pt-3">
|
||||
<h5 class="row card-title text-uppercase">Multiple settings</h5>
|
||||
{% for multiple, settings in multiples.items() %}
|
||||
{% set multiple_settings = settings|length > 1 %}
|
||||
<div class="col-12{% if multiple_multiples %} col-md-6{% endif %}{% if multiples|length > 2 and not multiple_settings %} col-lg-4{% endif %} pb-3">
|
||||
<div class="row">
|
||||
<div class="ps-0 d-flex align-items-center justify-content-start">
|
||||
<h6 class="mb-0">{{ multiple.replace('-', ' ') | capitalize }}</h6>
|
||||
<button id="add-multiple-{{ plugin['id'] }}-{{ multiple }}"
|
||||
type="button"
|
||||
class="btn btn-xs btn-outline-bw-green rounded-pill add-multiple ms-2">
|
||||
<i class="bx bx-plus-circle bx-sm"></i> ADD
|
||||
</button>
|
||||
<button id="show-multiple-{{ plugin['id'] }}-{{ multiple }}"
|
||||
type="button"
|
||||
class="btn btn-xs btn-outline-secondary rounded-pill show-multiple ms-2"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#multiple-{{ plugin['id'] }}-{{ multiple }}"
|
||||
aria-expanded="true"
|
||||
aria-controls="multiple-{{ plugin['id'] }}-{{ multiple }}">
|
||||
<i class="bx bx-show-alt bx-sm"></i> HIDE
|
||||
</button>
|
||||
</div>
|
||||
<div id="multiple-{{ plugin['id'] }}-{{ multiple }}"
|
||||
class="collapse show multiple-collapse">
|
||||
<div class="row multiple-container mt-2 pt-2">
|
||||
{% for setting, setting_data in settings.items() if setting not in blacklisted_settings %}
|
||||
{% set setting_config = config.get(setting, {}) %}
|
||||
{% set setting_value = setting_config.get("value", setting_data["default"]) %}
|
||||
{% set setting_method = setting_config.get("method", "default") %}
|
||||
{% set setting_template = setting_config.get("template", "") %}
|
||||
{% set disabled = setting_method not in ('ui', 'default') %}
|
||||
<div id="multiple-{{ plugin['id'] }}-{{ multiple }}-{{ loop.index - 1 }}"
|
||||
class="col-12{% if multiple_multiples and multiple_settings %} col-md-6{% endif %}{% if not multiple_multiples %} col-lg-4{% endif %} ps-0 pb-2"
|
||||
{% if disabled %}data-bs-toggle="tooltip" data-bs-placement="top" title="Disabled by {{ setting_method }}"{% endif %}>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<label id="multiple-label-{{ plugin['id'] }}-{{ setting_data['id'] }}"
|
||||
for="multiple-setting-{{ plugin['id'] }}-{{ setting_data['id'] }}"
|
||||
class="form-label fw-semibold text-truncate">
|
||||
{{ setting_data["label"]|capitalize }}
|
||||
</label>
|
||||
<div class="d-flex align-items-center">
|
||||
{% if current_endpoint == "global-config" and setting_data["context"] == "multisite" %}
|
||||
<a role="badge"
|
||||
href='https://docs.bunkerweb.io/latest/concepts/?utm_campaign=self&utm_source=ui#multisite-mode'
|
||||
class="badge badge-center rounded-pill bg-secondary d-flex align-items-center justify-content-center p-1 me-1"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="Multisite setting"
|
||||
target="_blank"
|
||||
rel="noopener">
|
||||
<span class="bx bx-server bx-xs"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if setting_template %}
|
||||
<span class="badge badge-center rounded-pill bg-secondary d-flex align-items-center justify-content-center p-1 me-1"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="From template: {{ setting_template }}">
|
||||
<span class="bx bx-spreadsheet bx-xs"></span>
|
||||
</span>
|
||||
{% endif %}
|
||||
<span class="badge rounded-pill bg-secondary-subtle text-dark d-flex align-items-center justify-content-center p-1"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="{{ setting_data['help']|capitalize }}">
|
||||
<span class="bx bx-question-mark bx-xs"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% if setting_data["type"] == "select" %}
|
||||
{% include "models/select_setting.html" %}
|
||||
{% elif setting_data["type"] == "check" %}
|
||||
{% include "models/checkbox_setting.html" %}
|
||||
{% else %}
|
||||
{% include "models/input_setting.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
14
src/ui/app/templates/models/select_setting.html
Normal file
14
src/ui/app/templates/models/select_setting.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<div class="form-floating mt-1">
|
||||
<select id="{{ setting_id_prefix }}setting-{{ plugin['id'] }}-{{ setting_data['id'] }}"
|
||||
name="{{ setting }}"
|
||||
class="form-select"
|
||||
aria-labelledby="label-{{ plugin['id'] }}-{{ setting_data['id'] }}"
|
||||
data-default="{{ setting_data['default'] }}"
|
||||
{% if disabled %}disabled{% endif %}>
|
||||
{% for option in setting_data["select"] %}
|
||||
<option value="{{ option }}"
|
||||
{% if setting_value == option %}selected{% endif %}>{{ option }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<label for="{{ setting_id_prefix }}setting-{{ plugin['id'] }}-{{ setting_data['id'] }}">{{ setting }}</label>
|
||||
</div>
|
||||
|
|
@ -9,24 +9,45 @@
|
|||
<div class="navbar-collapse collapse navbar-nav-right d-flex align-items-center"
|
||||
id="navbar-collapse">
|
||||
<!-- Buttons -->
|
||||
{% if current_endpoint == 'instances' %}
|
||||
{% set documentation_endpoint = "/integrations" %}
|
||||
{% elif current_endpoint == 'global-config' or 'services' in request.path %}
|
||||
{% set documentation_endpoint = "/settings" %}
|
||||
{% elif current_endpoint == 'configs' %}
|
||||
{% set documentation_endpoint = "/concepts" %}
|
||||
{% set documentation_fragment = "#custom-configurations" %}
|
||||
{% elif 'plugins' in request.path %}
|
||||
{% set documentation_endpoint = "/plugins" %}
|
||||
{% elif current_endpoint == 'cache' %}
|
||||
{% set documentation_endpoint = "/concepts" %}
|
||||
{% set documentation_fragment = "#database" %}
|
||||
{% elif current_endpoint == 'reports' or current_endpoint == 'bans' %}
|
||||
{% set documentation_fragment = "#security-features" %}
|
||||
{% elif current_endpoint == 'jobs' %}
|
||||
{% set documentation_endpoint = "/concepts" %}
|
||||
{% set documentation_fragment = "#scheduler" %}
|
||||
{% elif current_endpoint == 'logs' %}
|
||||
{% set documentation_endpoint = "/web-ui" %}
|
||||
{% set documentation_fragment = "#accessing-logs" %}
|
||||
{% endif %}
|
||||
<div class="navbar-nav align-items-center">
|
||||
<div class="nav-item d-flex align-items-center">
|
||||
<a role="button"
|
||||
class="btn btn-outline-secondary p-1 p-md-2"
|
||||
aria-pressed="true"
|
||||
href="https://docs.bunkerweb.io/latest/?utm_campaign=self&utm_source=ui"
|
||||
href="https://docs.bunkerweb.io/latest{{ documentation_endpoint }}/?utm_campaign=self&utm_source=ui{{ documentation_fragment }}"
|
||||
target="_blank"
|
||||
rel="noopener">
|
||||
<span class="tf-icons bx bx-file bx-18px me-md-2"></span>
|
||||
<span class="tf-icons bx bx-file me-md-2"></span>
|
||||
<span class="d-none d-md-inline">Documentation</span>
|
||||
</a>
|
||||
<a role="button"
|
||||
class="btn btn-outline-github p-1 p-md-2 ms-1 ms-md-2"
|
||||
aria-pressed="true"
|
||||
href="https://github.com/bunkerity/bunkerweb"
|
||||
href="https://github.com/bunkerity/bunkerweb/?utm_campaign=self&utm_source=ui"
|
||||
target="_blank"
|
||||
rel="noopener">
|
||||
<i class="tf-icons bx bxl-github bx-18px me-md-2"></i>
|
||||
<i class="tf-icons bx bxl-github me-md-2"></i>
|
||||
<span class="d-none d-md-inline">Github</span>
|
||||
</a>
|
||||
<a role="button"
|
||||
|
|
@ -35,7 +56,7 @@
|
|||
href="https://discord.bunkerity.com/?utm_campaign=self&utm_source=ui"
|
||||
target="_blank"
|
||||
rel="noopener">
|
||||
<i class="tf-icons bx bxl-discord bx-18px me-md-2"></i>
|
||||
<i class="tf-icons bx bxl-discord me-md-2"></i>
|
||||
<span class="d-none d-md-inline">Discord</span>
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -59,7 +80,8 @@
|
|||
aria-pressed="true"
|
||||
href="https://github.com/bunkerity/bunkerweb/releases/latest"
|
||||
target="_blank"
|
||||
rel="noopener">
|
||||
rel="noopener"
|
||||
{% if bw_version != latest_version %} data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-original-title="New version available" {% endif %}>
|
||||
Version {{ bw_version }}
|
||||
{% if bw_version != latest_version %}
|
||||
<span class="badge-dot position-absolute top-0 start-100 translate-middle bg-danger border border-light rounded-circle">
|
||||
|
|
@ -75,50 +97,39 @@
|
|||
href="javascript:void(0);"
|
||||
data-bs-toggle="dropdown">
|
||||
<div class="avatar avatar-online">
|
||||
<img src="img/avatar_profil_BW.png"
|
||||
<img src="{{ avatar_url }}"
|
||||
alt="User Avatar"
|
||||
class="w-px-40 h-auto rounded-circle" />
|
||||
</div>
|
||||
</a>
|
||||
{% with profile_url = url_for('profile') %}
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ profile_url }}">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="flex-shrink-0 me-2 me-md-3">
|
||||
<div class="avatar avatar-online">
|
||||
<img src="img/avatar_profil_BW.png"
|
||||
alt="Admin Avatar"
|
||||
class="w-px-40 h-auto rounded-circle" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="mb-0 text-truncate">{{ current_user.get_id() |title }}</h6>
|
||||
<small class="text-muted text-truncate">{{ current_user.list_roles[0] }}</small>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ url_for('profile') }}">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="flex-shrink-0 me-2 me-md-3">
|
||||
<div class="avatar avatar-online">
|
||||
<img src="{{ avatar_url }}"
|
||||
alt="Admin Avatar"
|
||||
class="w-px-40 h-auto rounded-circle" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<div class="dropdown-divider my-1"></div>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item d-flex align-items-center"
|
||||
href="{{ profile_url }}">
|
||||
<i class="bx bx-user bx-md me-2"></i><span>My Profile</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<div class="dropdown-divider my-1"></div>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item d-flex align-items-center"
|
||||
href="{{ url_for('logout') }}">
|
||||
<i class="bx bx-power-off bx-md me-2"></i><span>Log Out</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endwith %}
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="mb-0 text-truncate">{{ current_user.get_id() |title }}</h6>
|
||||
<small class="text-muted text-truncate">{{ current_user.list_roles[0] }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<div class="dropdown-divider my-1"></div>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item d-flex align-items-center"
|
||||
href="{{ url_for('logout') }}">
|
||||
<i class="bx bx-power-off bx-md me-2"></i><span>Log Out</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<!--/ User -->
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
{% extends "dashboard.html" %}
|
||||
{% block content %}
|
||||
<!-- Content -->
|
||||
<div class="d-flex row">
|
||||
<div class="card p-1">
|
||||
<div class="d-flex flex-wrap justify-content-around align-items-center">
|
||||
<div class="btn-group">
|
||||
<button id="select-plugin"
|
||||
type="button"
|
||||
class="btn btn-outline-primary dropdown-toggle"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
<i class="bx bx-extension"></i>
|
||||
<span class="d-none d-md-inline"> Plugins</span>
|
||||
</button>
|
||||
<ul id="plugins-dropdown-menu"
|
||||
class="dropdown-menu nav-pills max-vh-60 overflow-auto"
|
||||
role="tablist">
|
||||
<input id="plugin-search"
|
||||
type="text"
|
||||
class="form-control border-0 border-bottom shadow-none mb-2"
|
||||
placeholder="Search...">
|
||||
{% for plugin in plugins %}
|
||||
<li class="nav-item">
|
||||
<button type="button"
|
||||
class="dropdown-item{% if loop.index == 1 %} active{% endif %}"
|
||||
role="tab"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#navs-plugins-{{ plugin['id'] }}"
|
||||
aria-controls="navs-plugins-{{ plugin['id'] }}"
|
||||
{% if loop.index == 1 %}aria-selected="true"{% endif %}>
|
||||
{{ plugin["name"] }}
|
||||
</button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="row align-items-center">
|
||||
<div class="col form-floating ps-0 pe-0 pe-md-1">
|
||||
<input id="plugin-keyword-search"
|
||||
type="text"
|
||||
class="form-control form-control-sm border-0 border-primary border-bottom shadow-none"
|
||||
placeholder="Keywords...">
|
||||
<label for="plugin-keyword-search">Keywords</label>
|
||||
</div>
|
||||
<div class="col form-floating ps-0 pe-1 d-none d-md-block">
|
||||
<input id="plugin-context-search"
|
||||
type="text"
|
||||
class="form-control form-control-sm border-0 border-primary border-bottom shadow-none"
|
||||
placeholder="Context...">
|
||||
<label for="plugin-context-search">Context</label>
|
||||
</div>
|
||||
<div class="col-auto form-floating ps-0 pe-0 d-none d-md-block">
|
||||
<select id="plugin-type-select"
|
||||
class="form-select form-select-sm border-0 border-primary border-bottom shadow-none">
|
||||
<option selected>All</option>
|
||||
<option value="core">Core</option>
|
||||
<option value="external">External</option>
|
||||
<option value="pro">Pro</option>
|
||||
</select>
|
||||
<label for="plugin-type-select">Type</label>
|
||||
</div>
|
||||
</div>
|
||||
<button id="save-settings"
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline-bw-green">
|
||||
<i class="bx bx-save bx-sm"></i>
|
||||
<span class="d-none d-md-inline"> Save</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- / Content -->
|
||||
{% endblock %}
|
||||
|
|
@ -86,7 +86,7 @@
|
|||
<h5 class="card-header">Edit Profile</h5>
|
||||
<div class="card-body pb-2">
|
||||
<div class="d-flex align-items-start align-items-sm-center gap-6 pb-4 border-bottom">
|
||||
<img src="img/avatar_profil_BW.png"
|
||||
<img src="{{ avatar_url }}"
|
||||
alt="Admin Avatar"
|
||||
class="d-block w-px-100 h-px-100 rounded"
|
||||
id="uploadedAvatar">
|
||||
|
|
|
|||
16
src/ui/app/templates/service_settings.html
Normal file
16
src/ui/app/templates/service_settings.html
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{% extends "dashboard.html" %}
|
||||
{% block content %}
|
||||
<!-- Content -->
|
||||
<div class="tab-content p-0 position-relative">
|
||||
<div class="tab-pane fade{% if mode == 'easy' %} show active{% endif %}"
|
||||
id="navs-modes-easy"
|
||||
role="tabpanel">TODO: Add Easy mode</div>
|
||||
<div class="tab-pane fade{% if mode == 'advanced' %} show active{% endif %}"
|
||||
id="navs-modes-advanced"
|
||||
role="tabpanel">{% include "models/plugins_settings.html" %}</div>
|
||||
<div class="tab-pane fade{% if mode == 'raw' %} show active{% endif %}"
|
||||
id="navs-modes-raw"
|
||||
role="tabpanel">TODO: Add Raw mode</div>
|
||||
</div>
|
||||
<!-- / Content -->
|
||||
{% endblock %}
|
||||
|
|
@ -4,97 +4,77 @@
|
|||
data-bs-keyboard="false"
|
||||
data-bs-backdrop="false">
|
||||
<div class="offcanvas-header">
|
||||
<div class="nav-align-top">
|
||||
<ul class="nav nav-pills nav-fill" role="tablist">
|
||||
<li class="nav-item me-0 me-sm-2" role="presentation">
|
||||
<button type="button"
|
||||
class="nav-link active"
|
||||
role="tab"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#navs-pills-justified-news"
|
||||
aria-controls="navs-pills-justified-news"
|
||||
aria-selected="true">
|
||||
<span class="d-none d-sm-block" id="news-pill"><i class="tf-icons bx bx-news bx-xs me-1_5 align-text-bottom"></i>
|
||||
News</span><i class="bx bx-news bx-xs d-sm-none"></i>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button type="button"
|
||||
class="nav-link"
|
||||
role="tab"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#navs-pills-justified-notifications"
|
||||
aria-controls="navs-pills-justified-notifications"
|
||||
aria-selected="false"
|
||||
tabindex="-1">
|
||||
<span class="d-none d-sm-block"><i class="tf-icons bx bx-notification bx-xs me-1_5 align-text-bottom"></i>
|
||||
Notifications</span><i class="bx bx-notification bx-xs d-sm-none"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button type="button"
|
||||
class="btn-close text-reset"
|
||||
data-bs-dismiss="offcanvas"
|
||||
aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body px-0 position-relative">
|
||||
<div class="tab-content position-relative">
|
||||
<div class="tab-pane fade show active"
|
||||
id="navs-pills-justified-news"
|
||||
role="tabpanel">
|
||||
<div data-news-container class="flex-auto">
|
||||
<p class="text-center col-span-12 relative w-full p-4 text-primary rounded-lg fw-bold">
|
||||
Impossible to connect to blog news.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade"
|
||||
id="navs-pills-justified-notifications"
|
||||
role="tabpanel">
|
||||
<p>
|
||||
<!-- TODO -->
|
||||
Donut dragée jelly pie halvah. Danish gingerbread bonbon cookie wafer
|
||||
candy oat cake ice cream. Gummies halvah tootsie roll muffin biscuit
|
||||
icing dessert gingerbread. Pastry ice cream cheesecake fruitcake.
|
||||
</p>
|
||||
<p class="mb-0">
|
||||
Jelly-o jelly beans icing pastry cake cake lemon drops. Muffin muffin
|
||||
pie tiramisu halvah cotton candy liquorice caramels.
|
||||
</p>
|
||||
<div class="social-buttons">
|
||||
<a href="https://discord.bunkerity.com/?utm_campaign=self&utm_source=ui"
|
||||
class="btn btn-link"
|
||||
target="_blank"
|
||||
rel="noopener">
|
||||
<i class='bx bxl-discord-alt bx-sm'></i>
|
||||
</a>
|
||||
<a href="https://www.linkedin.com/company/bunkerity/"
|
||||
class="btn btn-link"
|
||||
target="_blank"
|
||||
rel="noopener">
|
||||
<i class='bx bxl-linkedin bx-sm'></i>
|
||||
</a>
|
||||
<a href="https://www.reddit.com/r/BunkerWeb/"
|
||||
class="btn btn-link"
|
||||
target="_blank"
|
||||
rel="noopener">
|
||||
<i class='bx bxl-reddit bx-sm'></i>
|
||||
</a>
|
||||
<a href="https://www.instagram.com/bunkerweb/"
|
||||
class="btn btn-link"
|
||||
target="_blank"
|
||||
rel="noopener">
|
||||
<i class='bx bxl-instagram bx-sm'></i>
|
||||
</a>
|
||||
<a href="https://x.com/bunkerity/"
|
||||
class="btn btn-link"
|
||||
target="_blank"
|
||||
rel="noopener">
|
||||
<i class='bx bxl-twitter bx-sm'></i>
|
||||
</a>
|
||||
</div>
|
||||
<button type="button"
|
||||
class="btn-close text-reset"
|
||||
data-bs-dismiss="offcanvas"
|
||||
aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 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&id=37076d9d67"
|
||||
method="POST"
|
||||
id="subscribe-newsletter">
|
||||
<div class="mb-3">
|
||||
<input type="email"
|
||||
id="newsletter-email"
|
||||
name="EMAIL"
|
||||
class="form-control"
|
||||
placeholder="John.doe@example.com"
|
||||
required />
|
||||
</div>
|
||||
<div class="form-check mb-3">
|
||||
<input type="checkbox"
|
||||
class="form-check-input"
|
||||
id="newsletter-check"
|
||||
name="newsletter-check"
|
||||
required />
|
||||
<label class="form-check-label" for="privacyPolicyCheck">
|
||||
I've read and agree to the
|
||||
<a class="fst-italic"
|
||||
href="https://www.bunkerity.com/en/privacy-policy?utm_campaign=self&utm_source=ui"
|
||||
target="_blank"
|
||||
rel="noopener">privacy policy</a>
|
||||
</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100 text-uppercase">Subscribe</button>
|
||||
</form>
|
||||
</div>
|
||||
<!-- End Newsletter Signup Section -->
|
||||
<div data-news-container
|
||||
class="offcanvas-body position-relative ps-3 pe-3">
|
||||
<p class="text-center relative w-full p-2 text-primary rounded-lg fw-bold">Impossible to connect to blog news.</p>
|
||||
</div>
|
||||
<!-- 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&id=37076d9d67"
|
||||
method="POST"
|
||||
id="subscribe-newsletter">
|
||||
<div class="mb-3">
|
||||
<input type="email"
|
||||
id="newsletter-email"
|
||||
name="EMAIL"
|
||||
class="form-control"
|
||||
placeholder="John.doe@example.com"
|
||||
required />
|
||||
</div>
|
||||
<div class="form-check mb-3">
|
||||
<input type="checkbox"
|
||||
class="form-check-input"
|
||||
id="newsletter-check"
|
||||
name="newsletter-check"
|
||||
required />
|
||||
<label class="form-check-label" for="privacyPolicyCheck">
|
||||
I've read and agree to the
|
||||
<a class="fst-italic"
|
||||
href="https://www.bunkerity.com/en/privacy-policy?utm_campaign=self&utm_source=ui"
|
||||
target="_blank"
|
||||
rel="noopener">privacy policy</a>
|
||||
</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100 text-uppercase">Subscribe</button>
|
||||
</form>
|
||||
</div>
|
||||
<!-- End Newsletter Signup Section -->
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@
|
|||
rel="noopener"
|
||||
class="app-brand-link gap-2">
|
||||
<span class="app-brand-logo login w-75">
|
||||
<img class="img-fluid" src="img/logo-menu.png" alt="BunkerWeb logo">
|
||||
<img class="img-fluid"
|
||||
src="{{ url_for('static', filename='img/logo-menu.png') }}"
|
||||
alt="BunkerWeb logo">
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ from os import _exit, getenv
|
|||
from os.path import join, sep
|
||||
from pathlib import Path
|
||||
from subprocess import PIPE, Popen, call
|
||||
from typing import List, Optional
|
||||
from typing import Dict, List, Optional, Set
|
||||
|
||||
from bcrypt import checkpw, gensalt, hashpw
|
||||
from magic import Magic
|
||||
from regex import compile as re_compile
|
||||
from regex import compile as re_compile, match
|
||||
from requests import get
|
||||
|
||||
from logger import setup_logger # type: ignore
|
||||
|
|
@ -43,8 +43,31 @@ def handle_stop(signum, frame):
|
|||
stop(0, False)
|
||||
|
||||
|
||||
def check_settings(settings: dict, check: str) -> bool:
|
||||
return any(setting["context"] == check for setting in settings.values())
|
||||
def get_multiples(settings: dict) -> Dict[str, dict]:
|
||||
multiples = {}
|
||||
for setting, data in settings.items():
|
||||
multiple = data.get("multiple")
|
||||
if multiple:
|
||||
if multiple not in multiples:
|
||||
multiples[multiple] = {}
|
||||
multiples[multiple].update({setting: data | {"setting_no_suffix": setting.rsplit("_", 1)[0] if match(r".+_\d+$", setting) else setting}})
|
||||
return multiples
|
||||
|
||||
|
||||
def get_filtered_settings(settings: dict, global_config: bool = False) -> Dict[str, dict]:
|
||||
multisites = {}
|
||||
for setting, data in settings.items():
|
||||
if not global_config and data["context"] == "global":
|
||||
continue
|
||||
multisites[setting] = data
|
||||
return multisites
|
||||
|
||||
|
||||
def get_blacklisted_settings(global_config: bool = False) -> Set[str]:
|
||||
blacklisted_settings = {"IS_LOADING", "AUTOCONF_MODE", "SWARM_MODE", "KUBERNETES_MODE", "IS_DRAFT", "BUNKERWEB_INSTANCES"}
|
||||
if global_config:
|
||||
blacklisted_settings.update({"SERVER_NAME", "USE_TEMPLATE"})
|
||||
return blacklisted_settings
|
||||
|
||||
|
||||
def gen_password_hash(password: str) -> bytes:
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ from app.routes.totp import totp
|
|||
|
||||
from app.dependencies import BW_CONFIG, DATA, DB
|
||||
from app.models.models import AnonymousUser
|
||||
from app.utils import TMP_DIR, LOGGER, check_settings, get_latest_stable_release, handle_stop, stop
|
||||
from app.utils import TMP_DIR, LOGGER, get_blacklisted_settings, get_filtered_settings, get_latest_stable_release, get_multiples, handle_stop, stop
|
||||
|
||||
signal(SIGINT, handle_stop)
|
||||
signal(SIGTERM, handle_stop)
|
||||
|
|
@ -97,15 +97,18 @@ with app.app_context():
|
|||
|
||||
def custom_url_for(endpoint, **values):
|
||||
try:
|
||||
if endpoint not in ("index", "loading", "check", "check_reloading") and "_page" not in endpoint:
|
||||
if endpoint not in ("static", "index", "loading", "check", "check_reloading") and "_page" not in endpoint:
|
||||
return url_for(f"{endpoint}.{endpoint}_page", **values)
|
||||
return url_for(endpoint, **values)
|
||||
except BuildError:
|
||||
except BuildError as e:
|
||||
LOGGER.debug(f"Couldn't build the URL for {endpoint}: {e}")
|
||||
return "#"
|
||||
|
||||
# Declare functions for jinja2
|
||||
app.jinja_env.globals.update(
|
||||
check_settings=check_settings,
|
||||
get_multiples=get_multiples,
|
||||
get_filtered_settings=get_filtered_settings,
|
||||
get_blacklisted_settings=get_blacklisted_settings,
|
||||
url_for=custom_url_for,
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue