precommit + filter plugin by type

This commit is contained in:
Jordan Blasenhauer 2024-04-15 15:44:23 +02:00
parent 6f17203b4d
commit 393f557d52
27 changed files with 209 additions and 64 deletions

View file

@ -15,7 +15,10 @@ def pre_render(**kwargs):
}
except BaseException:
print(format_exc(), flush=True)
return {"counter_failed_challenges": {"value": "unknown", "title": "Challenge", "subtitle": "Failed", "subtitle_color": "info", "svg_color": "blue"}, "error" : format_exc()}
return {
"counter_failed_challenges": {"value": "unknown", "title": "Challenge", "subtitle": "Failed", "subtitle_color": "info", "svg_color": "blue"},
"error": format_exc(),
}
def antibot(**kwargs):

View file

@ -2,6 +2,7 @@ from datetime import datetime
from json import loads
from traceback import format_exc
def pre_render(app, *args, **kwargs):
try:
data = loads(app.config["DB"].get_job_cache_file("backup-data", "backup.json") or "{}")
@ -12,7 +13,8 @@ def pre_render(app, *args, **kwargs):
return data
except BaseException:
print(format_exc(), flush=True)
return {"date": None, "files": [], "error" : format_exc()}
return {"date": None, "files": [], "error": format_exc()}
def backup(**kwargs):
pass

View file

@ -1,6 +1,7 @@
from operator import itemgetter
from traceback import format_exc
def pre_render(**kwargs):
try:
# Here we will have a list { 'counter_403': X, 'counter_401': Y ... }
@ -10,7 +11,7 @@ def pre_render(**kwargs):
format_data.sort(key=itemgetter("count"), reverse=True)
return {"top_bad_behavior": format_data}
except BaseException:
print(format_exc(), flush=True)
print(format_exc(), flush=True)
return {"top_bad_behavior": "unknown", "error": format_exc()}

View file

@ -1,5 +1,6 @@
from traceback import format_exc
def pre_render(**kwargs):
metrics = {
"counter_blacklist_url": {"value": "unknown", "title": "URL", "subtitle": "denied", "subtitle_color": "error", "svg_color": "red"},
@ -15,7 +16,7 @@ def pre_render(**kwargs):
metrics[key]["value"] = data.get(key, 0)
return metrics
except BaseException:
print(format_exc(), flush=True)
print(format_exc(), flush=True)
metrics["error"] = format_exc()
return metrics

View file

@ -1,11 +1,12 @@
from traceback import format_exc
def pre_render(**kwargs):
try:
ping_data = kwargs["app"].config["INSTANCES"].get_ping("bunkernet")
return {"ping_status": {"title": "BUNKERNET STATUS", "value": ping_data["status"]}}
except BaseException:
print(format_exc(), flush=True)
print(format_exc(), flush=True)
return {"ping_status": {"title": "BUNKERNET STATUS", "value": "error"}, "error": format_exc()}

View file

@ -1,5 +1,6 @@
from traceback import format_exc
def pre_render(**kwargs):
try:
data = kwargs["app"].config["INSTANCES"].get_metrics("cors")
@ -14,8 +15,11 @@ def pre_render(**kwargs):
}
except BaseException:
print(format_exc(), flush=True)
return {"counter_failed_cors": {"value": "unknown", "title": "CORS", "subtitle": "request blocked", "subtitle_color": "error", "svg_color": "red"}, "error" : format_exc()}
print(format_exc(), flush=True)
return {
"counter_failed_cors": {"value": "unknown", "title": "CORS", "subtitle": "request blocked", "subtitle_color": "error", "svg_color": "red"},
"error": format_exc(),
}
def cors(**kwargs):

View file

@ -1,5 +1,6 @@
from traceback import format_exc
def pre_render(**kwargs):
try:
data = kwargs["app"].config["INSTANCES"].get_metrics("country")

View file

@ -1,5 +1,6 @@
from traceback import format_exc
def pre_render(**kwargs):
try:
data = kwargs["app"].config["INSTANCES"].get_metrics("dnsbl")
@ -13,8 +14,11 @@ def pre_render(**kwargs):
}
}
except BaseException:
print(format_exc(), flush=True)
return {"counter_failed_dnsbl": {"value": "unknown", "title": "DNSBL", "subtitle": "request blocked", "subtitle_color": "error", "svg_color": "red"}, "error" : format_exc()}
print(format_exc(), flush=True)
return {
"counter_failed_dnsbl": {"value": "unknown", "title": "DNSBL", "subtitle": "request blocked", "subtitle_color": "error", "svg_color": "red"},
"error": format_exc(),
}
def dnsbl(**kwargs):

View file

@ -1,6 +1,7 @@
from operator import itemgetter
from traceback import format_exc
def pre_render(**kwargs):
try:
# Here we will have a list { 'counter_403': X, 'counter_401': Y ... }

View file

@ -1,5 +1,6 @@
from traceback import format_exc
def pre_render(**kwargs):
try:
data = kwargs["app"].config["INSTANCES"].get_metrics("greylist")

View file

@ -1,6 +1,7 @@
from operator import itemgetter
from traceback import format_exc
def pre_render(**kwargs):
try:
# Here we will have a list { 'limit_uri_url1': X, 'limit_uri_url2': Y ... }
@ -17,7 +18,7 @@ def pre_render(**kwargs):
format_data.sort(key=itemgetter("count"), reverse=True)
return {"top_limit": format_data}
except BaseException:
print(format_exc(), flush=True)
print(format_exc(), flush=True)
return {"top_limit": [], "error": format_exc()}

View file

@ -1,5 +1,6 @@
from traceback import format_exc
def pre_render(**kwargs):
try:
data = kwargs["app"].config["INSTANCES"].get_metrics("misc")
@ -21,7 +22,7 @@ def pre_render(**kwargs):
},
}
except BaseException:
print(format_exc(), flush=True)
print(format_exc(), flush=True)
return {
"counter_failed_default": {
"value": "unknown",
@ -31,7 +32,7 @@ def pre_render(**kwargs):
"svg_color": "sky",
},
"counter_failed_method": {"value": "unknown", "title": "DISALLOWED METHODS", "subtitle": "count", "subtitle_color": "info", "svg_color": "lime"},
"error" : format_exc()
"error": format_exc(),
}

View file

@ -1,5 +1,6 @@
from traceback import format_exc
def pre_render(**kwargs):
ping = {}
data = {}
@ -25,13 +26,13 @@ def pre_render(**kwargs):
}
except BaseException:
print(format_exc(), flush=True)
error += format_exc()
print(format_exc(), flush=True)
error += format_exc()
data = {"counter_redis_nb_keys": {"value": "unknown", "title": "REDIS KEYS", "subtitle": "total number", "subtitle_color": "info", "svg_color": "sky"}}
if error:
return ping | data | {"error": error}
return ping | data

View file

@ -1,6 +1,7 @@
from operator import itemgetter
from traceback import format_exc
def pre_render(**kwargs):
try:
# Here we will have a list { 'counter_403': X, 'counter_401': Y ... }

View file

@ -1,5 +1,6 @@
from traceback import format_exc
def pre_render(**kwargs):
try:
data = kwargs["app"].config["INSTANCES"].get_metrics("whitelist")

View file

@ -202,6 +202,7 @@ def generate_external_plugins(plugins: List[Dict[str, Any]], *, original_path: U
if not ret:
logger.error(f"Sending {'pro ' if pro else ''}external plugins failed, configuration will not work as expected...")
def generate_caches(plugins: List[Any], db: Database):
for plugin in plugins:
job_cache_files = db.get_jobs_cache_files(plugin_id=plugin["id"])
@ -250,6 +251,7 @@ def generate_caches(plugins: List[Any], db: Database):
logger.debug(f"Removing empty directory {file}")
rmtree(file, ignore_errors=True)
def api_to_instance(api):
hostname_port = api.endpoint.replace("http://", "").replace("https://", "").replace("/", "").split(":")
return {
@ -257,6 +259,7 @@ def api_to_instance(api):
"env": {"API_HTTP_PORT": int(hostname_port[1]), "API_SERVER_NAME": api.host},
}
def run_in_slave_mode(db: Database, dotenv_env: Dict[str, Any]):
# Instantiate db
db = Database(logger, sqlalchemy_string=dotenv_env.get("DATABASE_URI", getenv("DATABASE_URI", None)))
@ -272,7 +275,7 @@ def run_in_slave_mode(db: Database, dotenv_env: Dict[str, Any]):
logger.warning("Database doesn't have any config saved yet, retrying in 5s ...")
sleep(5)
env = db.get_config()
# Download plugins
pro_plugins = db.get_plugins(_type="pro", with_data=True)
generate_external_plugins(pro_plugins, original_path=PRO_PLUGINS_PATH)
@ -314,6 +317,7 @@ def run_in_slave_mode(db: Database, dotenv_env: Dict[str, Any]):
while True:
sleep(5)
if __name__ == "__main__":
try:
# Don't execute if pid file exists
@ -393,7 +397,7 @@ if __name__ == "__main__":
# Override instances if needed
override_instances = env.get("OVERRIDE_INSTANCES", "")
apis=[]
apis = []
if override_instances:
for instance in override_instances.split(" "):
apis.append(API(instance))

View file

@ -637,7 +637,7 @@ def home():
config = app.config["CONFIG"].get_config(with_drafts=True)
override_instances = config["OVERRIDE_INSTANCES"]["value"] != ""
instances = app.config["INSTANCES"].get_instances(override_instances=override_instances)
instance_health_count = 0
for instance in instances:

View file

@ -8,8 +8,7 @@ from typing import Any, List, Optional, Tuple, Union
from API import API # type: ignore
from ApiCaller import ApiCaller # type: ignore
from dotenv import dotenv_values # type: ignore
from Database import Database # type: ignore
from dotenv import dotenv_values # type: ignore
class Instance:
@ -168,13 +167,12 @@ class Instances:
ApiCaller(
[
API(
f"http://{instance['hostname']}:{str(instance['port'])}",
f"http://{instance['hostname']}:{instance['port']}",
instance["server_name"],
)
]
)
),
)
)
return instances
# Docker instances (containers or services)

File diff suppressed because one or more lines are too long

View file

@ -61,7 +61,6 @@ class TabPopover {
}
}
class SubmitAccount {
constructor() {
this.pwEl = document.querySelector("#admin_password");
@ -107,7 +106,7 @@ class SubmitAccount {
"focus:valid:!ring-red-500",
"active:!border-red-500",
"active:valid:!border-red-500",
"valid:!border-red-500"
"valid:!border-red-500",
);
this.pwAlertEl.classList.add("opacity-0");
this.pwAlertEl.setAttribute("aria-hidden", "true");
@ -121,7 +120,7 @@ class SubmitAccount {
"focus:valid:!ring-red-500",
"active:!border-red-500",
"active:valid:!border-red-500",
"valid:!border-red-500"
"valid:!border-red-500",
);
this.pwAlertEl.classList.remove("opacity-0");
this.pwAlertEl.setAttribute("aria-hidden", "false");
@ -139,14 +138,14 @@ class PwBtn {
const passwordContainer = e.target.closest("[data-input-group]");
const inpEl = passwordContainer.querySelector("input");
const invBtn = passwordContainer.querySelector(
'[data-setting-password="invisible"]'
'[data-setting-password="invisible"]',
);
const visBtn = passwordContainer.querySelector(
'[data-setting-password="visible"]'
'[data-setting-password="visible"]',
);
inpEl.setAttribute(
"type",
inpEl.getAttribute("type") === "password" ? "text" : "password"
inpEl.getAttribute("type") === "password" ? "text" : "password",
);
if (inpEl.getAttribute("type") === "password") {

View file

@ -1523,6 +1523,18 @@ const checkServiceModalKeyword = new CheckNoMatchFilter(
document.querySelector("[data-services-nomatch]"),
);
const checkServiceModalSelect = new CheckNoMatchFilter(
document.querySelectorAll(
"button[data-services-setting-select-dropdown-btn]",
),
"select",
document
.querySelector("[data-services-modal-form]")
.querySelectorAll("[data-plugin-item]"),
document.querySelector("[data-services-modal-form]"),
document.querySelector("[data-services-nomatch]"),
);
try {
const checkServiceCardKeyword = new CheckNoMatchFilter(
document.querySelectorAll("input#service-name-keyword"),

View file

@ -6,13 +6,15 @@ class Popover {
}
init() {
window.addEventListener("scroll", (e) => {
try {
this.hidePopover(this.relateBtn);
}catch(e) {
}
}, true);
window.addEventListener(
"scroll",
(e) => {
try {
this.hidePopover(this.relateBtn);
} catch (e) {}
},
true,
);
window.addEventListener("pointerover", (e) => {
//POPOVER LOGIC
@ -48,7 +50,7 @@ class Popover {
const popover = btn.parentElement.querySelector(
`[data-popover-content=${popoverName}]`,
);
popover.classList.add("transition-all", "delay-200", "opacity-0");
popover.classList.remove("hidden");
@ -82,10 +84,13 @@ class Popover {
const btnTop = btnRect.y;
const btnLeft = btnRect.x;
popover.style.top = `${btnTop - popover.getBoundingClientRect().height + 20}px`;
popover.style.left = `${btnLeft - popover.getBoundingClientRect().width / 3}px`;
popover.style.top = `${
btnTop - popover.getBoundingClientRect().height + 20
}px`;
popover.style.left = `${
btnLeft - popover.getBoundingClientRect().width / 3
}px`;
}
}
class TabsSelect {
@ -157,10 +162,7 @@ class TabsSelect {
}, 100);
}
}
}catch(e) {
}
} catch (e) {}
}
resetTabsStyle() {
@ -265,6 +267,9 @@ class FilterSettings {
this.contextTxtEl = document.querySelector(
`span[data-${this.prefix}-setting-select-text="context"]`,
);
this.typeTxtEl = document.querySelector(
`span[data-${this.prefix}-setting-select-text="type"]`,
);
this.tabContainer = tabContainer;
this.contentContainer = contentContainer;
this.tabsEls = this.tabContainer.querySelectorAll(
@ -285,12 +290,18 @@ class FilterSettings {
window.addEventListener("click", (e) => {
try {
if (
e.target.hasAttribute(
"data-global-config-setting-select-dropdown-btn",
(e.target.hasAttribute(
`data-${this.prefix}-setting-select-dropdown-btn`,
) &&
e.target.getAttribute(
"data-global-config-setting-select-dropdown-btn",
) === "context"
e.target.getAttribute(
`data-${this.prefix}-setting-select-dropdown-btn`,
) === `context`) ||
(e.target.hasAttribute(
`data-${this.prefix}-setting-select-dropdown-btn`,
) &&
e.target.getAttribute(
`data-${this.prefix}-setting-select-dropdown-btn`,
) === `type`)
) {
return this.runFilter();
}
@ -333,7 +344,7 @@ class FilterSettings {
if (currContextFilter !== "all") {
const settingContext = setting
.getAttribute("data-global-config-context")
.getAttribute(`data-${this.prefix}-context`)
.toLowerCase();
if (settingContext !== currContextFilter) {
needToHide = true;
@ -342,6 +353,22 @@ class FilterSettings {
}
} catch (e) {}
// check type if filter exists
try {
if (this.typeTxtEl) {
const currTypeFilter = this.typeTxtEl.textContent.toLowerCase();
if (currTypeFilter !== "all") {
const settingContext = setting
.getAttribute(`data-${this.prefix}-type`)
.toLowerCase();
if (settingContext !== currTypeFilter) {
needToHide = true;
}
}
}
} catch (e) {}
if (needToHide) {
setting.classList.add("hidden");
settingHiddenCount++;
@ -373,7 +400,7 @@ class FilterSettings {
if (currContextFilter !== "all") {
const settingContext = multSetting
.getAttribute("data-global-config-context")
.getAttribute(`data-${this.prefix}-context`)
.toLowerCase();
if (settingContext !== currContextFilter) {
needToHideMult = true;
@ -382,6 +409,21 @@ class FilterSettings {
}
} catch (e) {}
try {
if (this.typeTxtEl) {
const currtypeFilter = this.typeTxtEl.textContent.toLowerCase();
if (currtypeFilter !== "all") {
const settingtype = multSetting
.getAttribute(`data-${this.prefix}-type`)
.toLowerCase();
if (settingtype !== currtypeFilter) {
needToHideMult = true;
}
}
}
} catch (e) {}
if (needToHideMult) {
multSetting.classList.add("hidden");
multSettingHiddenCount++;
@ -443,7 +485,7 @@ class FilterSettings {
multTitle.classList.add("hidden");
}
//case no setting or no multiple match, check if match at least tab name
// case no setting or no multiple match, check if match at least tab name
// if no context, else we don't care about name
if (
settingCount === settingHiddenCount &&
@ -451,9 +493,21 @@ class FilterSettings {
) {
const tabName = tab.getAttribute(`data-tab-select-handler`);
const tabTxt = tab.textContent.trim().toLowerCase();
const tabType = tab.getAttribute(`data-tab-plugin-type`);
let needHideTab = false;
try {
if (this.contextTxtEl.textContent.toLowerCase() !== "all")
if (
this.contextTxtEl &&
this.contextTxtEl.textContent.toLowerCase() !== "all"
)
needHideTab = true;
} catch (e) {}
try {
if (
this.typeTxtEl &&
this.typeTxtEl.textContent.toLowerCase() !== tabType
)
needHideTab = true;
} catch (e) {}

View file

@ -95,7 +95,6 @@
@apply z-[1000] h-fit max-w-[250px] transition-all duration-500 dark:brightness-90 transition rounded-md p-3 -translate-y-7 fixed bg-blue-500;
}
.popover-tab {
@apply transition-all duration-500 dark:brightness-90 transition z-50 rounded-md p-3 left-0 -translate-y-7 bottom-0 absolute bg-blue-500;
}

View file

@ -29,16 +29,28 @@
"global",
"multisite"
]
},
{
"type": "select",
"name": "Type",
"id": "type",
"value": "all",
"values": [
"all",
"core",
"external",
"pro"
]
}
] %}
<div data-global-config-filter
class="h-fit p-4 col-span-12 md:col-span-6 lg:col-span-5 2xl:col-span-4 3xl:col-span-3 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
class="h-fit p-4 col-span-12 md:col-span-6 3xl:col-span-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
<h5 class="mb-2 font-bold dark:text-white/90">FILTER</h5>
<div class="mx-2 grid grid-cols-12 gap-x-4 gap-y-2">
{% for filter in filters %}
{% if filter['type'] == 'input' %}
<!-- search inpt-->
<div class="flex flex-col relative col-span-12">
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
@ -55,7 +67,7 @@
{% endif %}
{% if filter['type'] == 'select' %}
<!-- select -->
<div class="flex flex-col relative col-span-12">
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>

View file

@ -43,20 +43,62 @@
</button>
</div>
<div data-services-tabs-select-header class="flex flex-col">
<div class="flex flex-col sm:flex-row justify-start w-full items-start sm:items-center gap-y-3 gap-x-4">
<div class="flex flex-col md:flex-row justify-start w-full items-start md:items-end gap-y-3 gap-x-4">
<div class="w-full sm:min-w-[250px] max-w-[300px]">{% include "settings_tabs_select.html" %}</div>
<div class="flex flex-col sm:flex-row">
<!-- search inpt-->
<div class="flex relative w-full max-w-[200px]">
<div class="sm:mx-2 mb-1 min-w-[200px] flex flex-col relative col-span-12 md:col-span-6">
<h5 class="hidden sm:block my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
Search
</h5>
<label class="sr-only" for="settings-filter">search</label>
<input type="text"
id="settings-filter"
name="settings-filter"
class="col-span-12 dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-3 py-1 font-normal text-gray-700 transition-all placeholder:text-gray-500"
placeholder="search by keyword"
placeholder="keyword"
pattern="(.*?)"
required />
</div>
<!-- end search inpt-->
<!-- type plugin -->
<div class="hidden mx-2 mb-1 min-w-[200px] sm:flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
Type
</h5>
<button aria-controls="filter-type" data-services-setting-select="type" class="disabled:opacity-75 dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 duration-300 ease-in-out dark:opacity-90 dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 focus:border-green-500 flex justify-between align-middle items-center text-left text-sm leading-5.6 ease w-full rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 py-1 md:px-3 font-normal text-gray-700 transition-all placeholder:text-gray-500">
<span aria-description="current filter state value" id="services-type" data-name="services-type" data-services-setting-select-text="type">all</span>
<!-- chevron -->
<svg data-services-setting-select="type" class="transition-transform h-4 w-4 fill-gray-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"></path>
</svg>
</button>
<!-- end chevron -->
<!-- dropdown-->
<div id="filter-type" role="listbox" data-services-setting-select-dropdown="type" class="mt-1 hidden z-100 absolute flex-col w-full translate-y-16 max-h-[350px] overflow-hidden overflow-y-auto">
<button role="option" data-services-setting-select-dropdown-btn="type" value="all" class="dark:bg-primary bg-primary text-gray-300 border-t rounded-t border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300">
all
</button>
<button role="option" data-services-setting-select-dropdown-btn="type" value="core" class=" bg-white dark:bg-slate-700 border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300">
core
</button>
<button role="option" data-services-setting-select-dropdown-btn="type" value="external" class=" bg-white dark:bg-slate-700 border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300">
external
</button>
<button role="option" data-services-setting-select-dropdown-btn="type" value="pro" class=" bg-white dark:bg-slate-700 rounded-b border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300">
pro
</button>
</div>
<!-- end dropdown-->
</div>
<!-- end type plugin-->
</div>
</div>
<div class="w-full min-w-[300px] my-1 sm:my-0">
<hr class="separator" />

View file

@ -57,7 +57,7 @@
{% if multList.append(value['multiple']) %}{% endif %}
{% endif %}
{% if not value['multiple'] %}
<div data-setting-container data-{{ current_endpoint }}-context="{{ value['context'] }}" class="relative mx-0 sm:mx-2 md:mx-3 lg:mx-4 my-2 col-span-12 md:my-3 md:col-span-6 2xl:my-3 2xl:col-span-4" id="form-edit-{{ current_endpoint }}-{{ value["id"] }}">
<div data-setting-container data-{{ current_endpoint }}-type="{{ plugin['type'] }}" data-{{ current_endpoint }}-context="{{ value['context'] }}" class="relative mx-0 sm:mx-2 md:mx-3 lg:mx-4 my-2 col-span-12 md:my-3 md:col-span-6 2xl:my-3 2xl:col-span-4" id="form-edit-{{ current_endpoint }}-{{ value["id"] }}">
<!-- title and info -->
<div class="flex items-center my-1 relative z-10">
<h5 class="input-title">{{ value["label"] }}</h5>
@ -290,7 +290,7 @@
current_endpoint == "global-config"
or current_endpoint == "services" and value['context'] == "multisite"
) %}
<div data-setting-container="{{ setting }}_SCHEMA" data-{{ current_endpoint }}-context="{{ value['context'] }}" class="relative mx-2 md:mx-3 my-2 md:my-3 col-span-12 md:col-span-6 2xl:col-span-4" id="form-edit-{{ current_endpoint }}-{{ value["id"] }}_SCHEMA">
<div data-setting-container="{{ setting }}_SCHEMA" data-{{ current_endpoint }}-type="{{ plugin['type'] }}" data-{{ current_endpoint }}-context="{{ value['context'] }}" class="relative mx-2 md:mx-3 my-2 md:my-3 col-span-12 md:col-span-6 2xl:col-span-4" id="form-edit-{{ current_endpoint }}-{{ value["id"] }}_SCHEMA">
<!-- title and info -->
<div class="flex items-center my-1 relative z-10">
<h5 class="input-title">{{ value["label"] }}</h5>

View file

@ -28,9 +28,10 @@
and check_settings(plugin["settings"], "multisite") or current_endpoint == "global-config" %}
<button role="option"
data-tab-select-handler="{{ plugin['id'] }}"
data-tab-plugin-type="{{ plugin['type'] }}"
data-select="false"
id="edit-{{ current_endpoint }}-{{ plugin['id'] }}-tab"
class=" {% if loop.first %}active first{% endif %} {% if loop.last %}last{% endif %} settings-tabs-select-dropdown-btn">
class="{% if loop.first %}active first{% endif %} {% if loop.last %}last{% endif %} settings-tabs-select-dropdown-btn">
{{ plugin['name'] }}
</button>
{% endif %}