update levels handling + simple mode

* handle security level as service settings for standard handling
* remove useless levels logic in templating
* move regular input rendering to main class Settings to be used on simple mode in addition to advanced mode
* switching mode is now working
* now store more data on Settings class (method, force enabled, empty server name...) to retrieve them easily on some cases
* add on SettingsService simple mode settings rendering + security level event handler
* simple mode first rendering now working on any actions (need to handle security level with existing disabled settings value for edit action)
* start implementing filter and merge logic to handle security level settings with disabled edit settings)
This commit is contained in:
Jordan Blasenhauer 2024-04-29 16:02:59 +02:00
parent 337fbc54f1
commit fe9a73ed70
8 changed files with 337 additions and 170 deletions

View file

@ -13,19 +13,21 @@ import {
class SettingsService {
constructor() {
this.prefix = "services";
this.settingsMultiple = JSON.parse(
document
.querySelector("input[data-plugins-multiple]")
.getAttribute("data-plugins-multiple")
.replaceAll(`'`, `"`),
);
this.advancedSettings = new SettingsAdvanced(
"advanced",
document.querySelector("[data-advanced][data-services-modal-form]"),
JSON.parse(
document
.querySelector("input[data-plugins-multiple]")
.getAttribute("data-plugins-multiple")
.replaceAll(`'`, `"`),
),
this.settingsMultiple,
"services",
);
this.simpleSettings = new SettingsSimple(
document.querySelector("[data-simple][data-services-modal-form]"),
this.settingsMultiple,
"services",
document.querySelector("input#settings-filter"),
document.querySelector('[data-services-setting-select="type"]'),
document.querySelector("[data-tab-select-dropdown]"),
);
this.initSettingsService();
@ -50,14 +52,12 @@ class SettingsService {
.querySelector("[data-service-method]")
.getAttribute("data-value") || "no";
let oldServName = "";
const oldServName =
target
.closest("[data-services-service]")
.querySelector("[data-old-name]")
.getAttribute("data-value") || "";
if (action !== "new")
oldServName =
target
.closest("[data-services-service]")
.querySelector("[data-old-name]")
.getAttribute("data-value") || "";
this.currMethod = method;
const operation = action === "clone" || action === "new" ? "new" : action;
@ -102,13 +102,25 @@ class SettingsService {
operation,
] = this.getActionData(e.target);
//simple
const forceEnabled = action === "new" ? true : false;
const setMethodUI =
action === "new" || action === "clone" ? true : false;
const emptyServerName =
action === "new" || action === "clone" ? true : false;
this.advancedSettings.setAdvanced(
action,
oldServName,
operation,
settings,
setMethodUI,
forceEnabled,
emptyServerName,
);
// Click on right security level dropdown btn
// This will fire security level event listener
this.simpleSettings.updateData(
action,
oldServName,
operation,
@ -117,11 +129,34 @@ class SettingsService {
setMethodUI,
emptyServerName,
);
if (action === "new") {
document
.querySelector(
`button[data-setting-select-dropdown-btn="security-level"][value="standard"]`,
)
.click();
document
.querySelector(
`button[data-setting-select-dropdown-btn="security-level"][value="custom"]`,
)
.setAttribute("disabled", "true");
} else {
document
.querySelector(
`button[data-setting-select-dropdown-btn="security-level"][value="custom"]`,
)
.click();
document
.querySelector(
`button[data-setting-select-dropdown-btn="security-level"][value="custom"]`,
)
.removeAttribute("disabled");
}
}
} catch (err) {
console.log(err);
}
// security
// security level
try {
if (
e.target
@ -129,6 +164,80 @@ class SettingsService {
.getAttribute("data-setting-select-dropdown-btn") ==
"security-level"
) {
// get current common values
const action = this.simpleSettings.currAction;
const oldServName = this.simpleSettings.oldServName;
const operation = this.simpleSettings.operation;
const forceEnabled = this.simpleSettings.forceEnabled;
const setMethodUI = this.simpleSettings.setMethodUI;
const emptyServerName = this.simpleSettings.emptyServerName;
// get custom security level settings of service if custom choose
const value = e.target.closest("button").getAttribute("value");
// mainSettings is the settings of the service
let mainSettings;
// Try to get settings in a valid format
try {
mainSettings = JSON.parse(
document
.querySelector(`[data-old-name][data-value="${oldServName}"]`)
.closest("[data-services-service]")
.getAttribute("data-settings"),
);
} catch (err) {}
try {
if (!settings) {
mainSettings = JSON.parse(
document
.querySelector(`[data-old-name][data-value="${oldServName}"]`)
.closest("[data-services-service]")
.getAttribute("data-settings")
.replaceAll(`'`, `"`),
);
}
} catch (err) {}
// In case we want a security level, we need to get the settings of the security level
// In order to filter and merge both to avoid overriding disabled settings (method != ui|default)
let compareSettings = null;
if (value !== "custom") {
// Try to get settings in a valid format
try {
compareSettings = JSON.parse(
document
.querySelector(`input#security-level-${value}`)
.getAttribute("data-settings"),
);
} catch (err) {}
try {
if (!compareSettings) {
compareSettings = JSON.parse(
document
.querySelector(`input#security-level-${value}`)
.getAttribute("data-settings")
.replaceAll(`'`, `"`),
);
}
} catch (err) {}
}
console.log("mainSettings", mainSettings);
console.log("compareSettings", compareSettings);
this.simpleSettings.setSimple(
action,
oldServName,
operation,
mainSettings,
compareSettings,
setMethodUI,
forceEnabled,
emptyServerName,
true,
);
}
} catch (err) {}
});
@ -364,7 +473,7 @@ class ServiceModal {
}
setModeVisible(action) {
if (action === "new") {
if (action === "new" || action === "clone" || action === "edit") {
this.switchModeBtn.classList.remove("hidden");
} else {
this.switchModeBtn.classList.add("hidden");
@ -728,7 +837,13 @@ const setFilterGlobal = new FilterSettings(
);
const settings = new SettingsService();
// const setAdvancedMultiple = new MultipleActions("services", document.querySelector("[data-advanced][data-services-modal-form]"));
const switchSettings = new SettingsSwitch(
document.querySelector("[data-toggle-settings-mode-btn]"),
document.querySelector("main"),
["advanced", "simple"],
"services",
);
const checkServiceModalKeyword = new CheckNoMatchFilter(
document.querySelector("input#settings-filter"),

View file

@ -998,6 +998,10 @@ class Settings {
this.currAction = "";
this.currMethod = "";
this.oldServName = "";
this.setMethodUI = false;
this.forceEnabled = false;
this.emptyServerName = false;
this.currSettings = {};
this.initSettings();
}
@ -1027,8 +1031,7 @@ class Settings {
inpName === "is_draft" ||
inpName === "operation" ||
inpName === "settings-filter" ||
inp.hasAttribute("data-combobox") ||
(this.mode === "simple" && inpName === "SERVER_NAME")
inp.hasAttribute("data-combobox")
)
return true;
}
@ -1150,11 +1153,24 @@ class Settings {
}
}
updateData(action, oldServName, operation) {
updateData(
action,
oldServName,
operation,
settings,
setMethodUI,
forceEnabled,
emptyServerName,
) {
// Get global needed data
this.currAction = action;
this.oldServName = oldServName;
this.operation = operation;
this.currSettings = settings;
this.setMethodUI = setMethodUI;
this.forceEnabled = forceEnabled;
this.emptyServerName = emptyServerName;
this.updateOperation();
this.updateOldNameValue();
}
@ -1180,6 +1196,76 @@ class Settings {
inp.value = this.operation;
});
}
// Avoid multiple settings because it is handle by Multiple class
getRegularInps(settings) {
this.multSettingsName.forEach((name) => {
// check if a settings is starting with a multiple name
// if yes, remove it
for (const [key, value] of Object.entries(settings)) {
if (key.startsWith(name)) {
delete settings[key];
}
}
});
return settings;
}
setRegularInps(allSettings, forceEnabled, setMethodUI) {
const settings = this.getRegularInps(allSettings);
// Case we have settings, like when we edit a service
// We need to update the settings with the right values
if (Object.keys(settings).length > 0) {
// use this to select inputEl and change value
for (const [key, data] of Object.entries(settings)) {
//change format to match id
const value = data["value"];
const method = setMethodUI ? "ui" : data["method"];
const global = data["global"];
try {
// get only inputs without attribute data-is-multiple
const inps = this.container.querySelectorAll(
`[name='${key}']:not([data-is-multiple])`,
);
inps.forEach((inp) => {
//form related values are excludes
const inpName = inp.getAttribute("name");
if (this.isAvoidInpList("input", inp, inpName, this.container))
return;
//SET DISABLED / ENABLED
//for regular input
this.setCheckbox(inp, method, value);
this.setInput(inp, method, value);
//for select
if (inp.tagName === "SELECT") {
inp.parentElement
.querySelector(
`button[data-setting-select-dropdown-btn][value='${value}']`,
)
.click();
inp.setAttribute("data-method", method);
}
if (forceEnabled) {
inp.removeAttribute("disabled");
} else {
if (method === "ui" || method === "default") {
inp.removeAttribute("disabled");
} else {
inp.setAttribute("disabled", "");
}
if (global) inp.removeAttribute("disabled");
}
});
} catch (err) {}
}
}
}
}
class SettingsMultiple extends Settings {
@ -1612,8 +1698,8 @@ class SettingsMultiple extends Settings {
}
class SettingsAdvanced extends SettingsMultiple {
constructor(mode, formEl, multSettingsName, prefix = "services") {
super(mode, formEl, multSettingsName, prefix);
constructor(formEl, multSettingsName, prefix = "services") {
super("advanced", formEl, multSettingsName, prefix);
this.initAdvanced();
}
@ -1634,7 +1720,15 @@ class SettingsAdvanced extends SettingsMultiple {
forceEnabled = false,
emptyServerName = false,
) {
this.updateData(action, oldServName, operation);
this.updateData(
action,
oldServName,
operation,
settings,
setMethodUI,
forceEnabled,
emptyServerName,
);
this.setSettingsAdvanced(
settings,
setMethodUI,
@ -1651,76 +1745,6 @@ class SettingsAdvanced extends SettingsMultiple {
this.setMultipleInps(settings);
}
// Avoid multiple settings because it is handle by Multiple class
getRegularInps(settings) {
this.multSettingsName.forEach((name) => {
// check if a settings is starting with a multiple name
// if yes, remove it
for (const [key, value] of Object.entries(settings)) {
if (key.startsWith(name)) {
delete settings[key];
}
}
});
return settings;
}
setRegularInps(allSettings, forceEnabled, setMethodUI) {
const settings = this.getRegularInps(allSettings);
// Case we have settings, like when we edit a service
// We need to update the settings with the right values
if (Object.keys(settings).length > 0) {
// use this to select inputEl and change value
for (const [key, data] of Object.entries(settings)) {
//change format to match id
const value = data["value"];
const method = setMethodUI ? "ui" : data["method"];
const global = data["global"];
try {
// get only inputs without attribute data-is-multiple
const inps = this.container.querySelectorAll(
`[name='${key}']:not([data-is-multiple])`,
);
inps.forEach((inp) => {
//form related values are excludes
const inpName = inp.getAttribute("name");
if (this.isAvoidInpList("input", inp, inpName, this.container))
return;
//SET DISABLED / ENABLED
//for regular input
this.setCheckbox(inp, method, value);
this.setInput(inp, method, value);
//for select
if (inp.tagName === "SELECT") {
inp.parentElement
.querySelector(
`button[data-setting-select-dropdown-btn][value='${value}']`,
)
.click();
inp.setAttribute("data-method", method);
}
if (forceEnabled) {
inp.removeAttribute("disabled");
} else {
if (method === "ui" || method === "default") {
inp.removeAttribute("disabled");
} else {
inp.setAttribute("disabled", "");
}
if (global) inp.removeAttribute("disabled");
}
});
} catch (err) {}
}
}
}
checkVisibleInpsValidity() {
try {
const inps = this.container.querySelectorAll(
@ -1797,8 +1821,8 @@ class SettingsAdvanced extends SettingsMultiple {
}
class SettingsSimple extends SettingsMultiple {
constructor(mode, formEl, multSettingsName, prefix = "services") {
super(mode, formEl, multSettingsName, prefix);
constructor(formEl, multSettingsName, prefix = "services") {
super("simple", formEl, multSettingsName, prefix);
this.nextBtn = this.container.querySelector("button[data-simple-next]");
this.backBtn = this.container.querySelector("button[data-simple-back]");
this.initSimple();
@ -1822,29 +1846,41 @@ class SettingsSimple extends SettingsMultiple {
}
setSimple(
action,
oldServName,
operation,
settings,
action = this.currAction,
oldServName = this.oldServName,
operation = this.operation,
mainSettings,
compareSettings = null,
setMethodUI = false,
forceEnabled = false,
emptyServerName = false,
resetSteps = false,
) {
this.updateData(action, oldServName, operation);
this.setSettingsSimple(
const settings = compareSettings
? this.filterSettings(mainSettings, compareSettings)
: mainSettings;
console.log(settings);
this.updateData(
action,
oldServName,
operation,
settings,
setMethodUI,
forceEnabled,
emptyServerName,
);
this.setSettingsSimple(settings, setMethodUI, forceEnabled);
if (emptyServerName) this.resetServerName();
if (resetSteps) this.resetSimpleMode();
this.checkVisibleInpsValidity();
}
filterSettings(mainSettings, compareSettings) {
console.log("filter");
return {};
}
setSettingsSimple(settings, setMethodUI = false, forceEnabled = false) {
this.setSettingsByAtt();
this.setRegularInps(settings, forceEnabled, setMethodUI);
this.setMultipleInps(settings);
}
@ -2021,51 +2057,67 @@ class SettingsRaw extends SettingsMultiple {
forceEnabled = false,
emptyServerName = false,
) {
this.updateData(action, oldServName, operation);
this.updateData(
action,
oldServName,
operation,
settings,
setMethodUI,
forceEnabled,
emptyServerName,
);
this.setSettingsRaw(settings, setMethodUI, forceEnabled, emptyServerName);
}
setSettingsRaw(settings, setMethodUI = false, forceEnabled = false) {
this.setSettingsByAtt();
this.setRegularInps(settings, forceEnabled, setMethodUI);
this.setMultipleInps(settings);
}
setSettingsRaw(settings, setMethodUI = false, forceEnabled = false) {}
}
class SettingsSwitch {
constructor(switchBtn, settingsForms, prefix = "services") {
constructor(
switchBtn,
container = document.querySelector("main"),
modes = ["advanced", "simple"],
prefix = "services",
) {
this.prefix = prefix;
this.modes = modes;
this.switchModeBtn = switchBtn;
// dict with mode as key and form element as value
this.settingsForms = settingsForms;
// dict wth mode as key and form element as value
this.container = container;
this.init();
}
init() {
this.switchModeBtn.addEventListener("click", () => {
setTimeout(() => {
this.checkVisibleInpsValidity();
}, 20);
// Get
const currMode = this.switchModeBtn.getAttribute(
"data-toggle-settings-mode-btn",
);
// Get current mode index in this.modes to get next one or first element if no next
const currModeIndex = this.modes.indexOf(currMode);
const nextMode = this.modes[currModeIndex + 1] || this.modes[0];
this.setSettingMode(nextMode);
});
}
// Switch settings mode and update button
setSettingMode(mode) {
if (this.mode === mode) return;
const currMode = this.switchModeBtn.getAttribute(
"data-toggle-settings-mode-btn",
);
if (currMode === mode) return;
if (!this.switchModeBtn) return;
const elsToShow =
mode === "advanced"
? document.querySelectorAll("[data-advanced]")
: document.querySelectorAll("[data-simple]");
? this.container.querySelectorAll("[data-advanced]")
: this.container.querySelectorAll("[data-simple]");
const elsToHide =
mode === "advanced"
? document.querySelectorAll("[data-simple]")
: document.querySelectorAll("[data-advanced]");
? this.container.querySelectorAll("[data-simple]")
: this.container.querySelectorAll("[data-advanced]");
elsToHide.forEach((setting) => {
setting.classList.add("!hidden");
});

View file

@ -27,12 +27,14 @@
{% endfor %}
<input class="hidden" data-plugins-multiple='{{multiple_settings}}' />
<!-- actions -->
<div data-{{attribute_name}}-service
<div data-{{attribute_name}}-service data-settings="{}"
class="col-span-12 relative flex justify-center min-w-0 break-words rounded-2xl bg-clip-border">
<div data-is-draft class="hidden" data-value="no"></div>
<div data-service-method class="hidden" data-value="ui"></div>
<button data-{{attribute_name}}-action="new"
data-{{attribute_name}}-name="service"
data-old-name
data-value="new"
data-settings="{}"
type="button"
class="dark:bg-green-500/90 duration-300 dark:text-gray-100 w-80 flex justify-center items-center px-6 py-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-green-500 hover:bg-green-500/80 focus:bg-green-500/80 leading-normal text-base ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">

View file

@ -1,4 +1,29 @@
{% set security_levels = ['standard', 'advanced', 'high'] %}
{% set security_levels = ['standard', 'advanced', 'high', 'custom'] %}
{% set standard = {
"USE_ANTIBOT": {
"value": "javascript",
"method": "default"
},
"SERVER_NAME": {
"value": "test",
"method": "default"
},
}%}
{% set advanced = {
"USE_ANTIBOT": {
"value": "no",
"method": "default"
},
}%}
{% set high = {
"USE_ANTIBOT": {
"value": "javascript",
"method": "default"
},
}%}
{# When multiple, setting_id need to be a setting that is part of a multiple to get all settings on the same group #}
{# On levels, we should set a list of dict with setting_id as key and value as value #}
@ -8,25 +33,9 @@
"name" : "STEP 1 - STARTING UP",
"description" : "we need some information to get started.",
"settings" : [
{"plugin_id" : "general", "setting_id": "SERVER_NAME", "title" : "DEFINE HOST", "subtitle" : "We need this to connect BunkerWeb to your application. You need to set your domain name.", "levels" : {} },
{"plugin_id" : "security-level", "setting_id": "SECURITY_LEVEL", "title" : "DEFINE SECURITY LEVEL", "subtitle" : "This will determine default settings value for the next steps. You'll be allow to modify settings to match your case if needed.", "levels" : {}, "setting" : {'context': 'global', 'default': 'standard', 'help': 'Determine the default settings value. You can override them.', 'id': 'security-level', 'label': 'Security level', 'regex': '^(security_levels[0]|security_levels[1]|security_levels[2])$', 'type': 'select', 'select': [security_levels[0], security_levels[1], security_levels[2]]} },
{"plugin_id" : "limit", "setting_id": "LIMIT_REQ_URL", "title" : "Define header", "subtitle" : "test header multiple rendering", "levels" : [{
security_levels[0] : {
"LIMIT_REQ_URL_1": "/",
"LIMIT_REQ_RATE_1": "2r/s"
}
, security_levels[1] : {
"LIMIT_REQ_URL_1": "/",
"LIMIT_REQ_RATE_1": "2r/s"
}
, security_levels[2] : {
"LIMIT_REQ_URL_1": "/",
"LIMIT_REQ_RATE_1": "2r/s",
"LIMIT_REQ_URL_2": "/admin",
"LIMIT_REQ_RATE_2": "4r/s"
}
}]
},
{"plugin_id" : "security-level", "setting_id": "SECURITY_LEVEL", "title" : "DEFINE SECURITY LEVEL", "subtitle" : "This will determine default settings value for the next steps. You'll be allow to modify settings to match your case if needed.", "setting" : {'context': 'global', 'default': 'standard', 'help': 'Determine the default settings value. You can override them.', 'id': 'security-level', 'label': 'Security level', 'regex': '^(security_levels[0]|security_levels[1]|security_levels[2]|security_levels[3])$', 'type': 'select', 'select': [security_levels[0], security_levels[1], security_levels[2], security_levels[3]]} },
{"plugin_id" : "general", "setting_id": "SERVER_NAME", "title" : "DEFINE HOST", "subtitle" : "We need this to connect BunkerWeb to your application. You need to set your domain name."},
{"plugin_id" : "limit", "setting_id": "LIMIT_REQ_URL", "title" : "Define header", "subtitle" : "test header multiple rendering" },
],
"configs": []
},
@ -34,11 +43,11 @@
"name" : "STEP 2 - ANTIBOT",
"description" : "Avoid spammer and bot to access your website.",
"settings" : [
{"plugin_id" : "antibot", "setting_id": "USE_ANTIBOT", "title" : "Define the type of your antibot", "subtitle" : "Javascript, Captcha or Cookie don't need additionnal settings to be fill. Recaptcha, Hcaptcha and Turnstile need secret key and site key delivered from providers.", "levels" : {security_levels[0] : "no", security_levels[1] : "javascript", security_levels[2] : "javascript"} },
{"plugin_id" : "antibot", "setting_id": "USE_ANTIBOT", "title" : "Define the type of your antibot", "subtitle" : "Javascript, Captcha or Cookie don't need additionnal settings to be fill. Recaptcha, Hcaptcha and Turnstile need secret key and site key delivered from providers." },
],
"configs": [
{"name": "my_config_1", "type": "modsec", "subtitle" : "This will determine the modsecurity rules to apply to this service.", "levels" : {security_levels[0] : "no", security_levels[1] : "javascript", security_levels[2] : "javascript"} },
{"name": "my_config_2", "type": "server-http", "subtitle" : "This will determine the server http...", "levels" : {security_levels[0] : "no", security_levels[1] : "javascript", security_levels[2] : "javascript"} }
{"name": "my_config_1", "type": "modsec", "subtitle" : "This will determine the modsecurity rules to apply to this service."},
{"name": "my_config_2", "type": "server-http", "subtitle" : "This will determine the server http..."}
]
},
]
@ -70,6 +79,10 @@
{% endfor %}
{% endfor %}
<input type="hidden" id="security-level-{{security_levels[0]}}" data-settings="{{ standard }}" />
<input type="hidden" id="security-level-{{security_levels[1]}}" data-settings="{{ advanced }}" />
<input type="hidden" id="security-level-{{security_levels[2]}}" data-settings="{{ high }}" />
<!-- new and edit form -->
<form data-simple data-services-modal-form
class="!hidden w-full h-[90vh] overflow-auto flex flex-col justify-between"

View file

@ -6,7 +6,6 @@
{% set inp_regex = setting_input['regex'] %}
{% set inp_default = setting_input['default'] %}
{% set inp_value = setting_input['value'] %}
{% set inp_levels = setting_input['levels'] %}
{% set global_config_method = global_config.get(inp_name, {'method' : inp_method }).get('method') %}
{% set global_config_value = global_config.get(inp_name, {'value' : inp_value }).get('value') %}
@ -25,9 +24,6 @@
type="checkbox"
data-pattern="{{ inp_regex|safe }}"
value="{{ global_config_value }}"
{% for level_name, value in inp_levels.items() %}
data-security-level-{{level_name}}="{{value}}"
{% endfor %}
{% if is_multiple %} data-is-multiple {% endif %}
/>
<svg data-checkbox-handler="{{ inp_id }}"

View file

@ -7,7 +7,6 @@
{% set inp_default = setting_input['default'] %}
{% set inp_value = setting_input['value'] %}
{% set inp_regex = setting_input['regex'] %}
{% set inp_levels = setting_input['levels'] %}
{% set global_config_method = global_config.get(inp_name, {'method' : inp_method }).get('method') %}
{% set global_config_value = global_config.get(inp_name, {'value' : inp_value }).get('value') %}
@ -24,9 +23,6 @@
value="{% if global_config_value %} {{ global_config_value }} {% else %} {{ inp_default }} {% endif %}"
type="{{ inp_type }}"
pattern="{{ inp_regex|safe }}"
{% for level_name, value in inp_levels.items() %}
data-security-level-{{level_name}}="{{value}}"
{% endfor %}
{% if is_multiple %} data-is-multiple {% endif %}
/>
{% if inp_type == "password" %}

View file

@ -6,7 +6,6 @@
{% set inp_value = setting_input['value'] %}
{% set inp_method = setting_input['method'] %}
{% set inp_items = setting_input['select'] %}
{% set inp_levels = setting_input['levels'] %}
{% set inp_id = setting_input['id'] %}
{% set inp_is_simple = setting_input['is_simple'] %}
{% set global_config_method = global_config.get(inp_name, {'method' : inp_method }).get('method') %}
@ -20,9 +19,6 @@
data-setting-select-default="{{ inp_id }}"
data-type="form-select"
class="hidden"
{% for level_name, value in inp_levels.items() %}
data-security-level-{{level_name}}="{{value}}"
{% endfor %}
{% if is_multiple %} data-is-multiple {% endif %}
>
{% for item in inp_items %}
@ -42,9 +38,6 @@
data-default-method="{{ global_config_method }}"
aria-controls="{{ inp_id }}-dropdown"
type="button"
{% for level_name, value in inp_levels.items() %}
data-security-level-{{level_name}}="{{value}}"
{% endfor %}
class="custom-select-btn">
{% for item in inp_items %}
{% if global_config_value and

View file

@ -2,7 +2,7 @@
<!-- plugin item -->
<div class="w-full grid grid-cols-12">
{% for setting_simple in plugin_simple %}
{% set setting_input = { "name" : setting_simple.get('setting_id'), "multiples" : setting_simple.get("multiples", {}), "method" : setting_simple.get('setting').get("method", "default"), "help" : setting_simple.get('setting').get("help"), "label" : setting_simple.get('setting').get("label"), "id" : setting_simple.get('setting').get("id"), "type" : setting_simple.get('setting').get("type"), "default" : setting_simple.get('setting').get("default", "default"), "select" : setting_simple.get('setting').get("select"), "regex" : setting_simple.get('setting').get("regex"), "value" : setting_simple.get('setting').get("value"), "is_multiple" : True if setting_simple.get('setting').get("multiple", "") else False, "levels" : setting_simple.get('levels', {}) if not setting_simple.get('setting').get("multiples", "") else {}, "multiple_name" : setting_simple.get('setting').get('multiple') } %}
{% set setting_input = { "name" : setting_simple.get('setting_id'), "multiples" : setting_simple.get("multiples", {}), "method" : setting_simple.get('setting').get("method", "default"), "help" : setting_simple.get('setting').get("help"), "label" : setting_simple.get('setting').get("label"), "id" : setting_simple.get('setting').get("id"), "type" : setting_simple.get('setting').get("type"), "default" : setting_simple.get('setting').get("default", "default"), "select" : setting_simple.get('setting').get("select"), "regex" : setting_simple.get('setting').get("regex"), "value" : setting_simple.get('setting').get("value"), "is_multiple" : True if setting_simple.get('setting').get("multiple", "") else False, "multiple_name" : setting_simple.get('setting').get('multiple') } %}
<div data-simple id="{{ setting_simple['plugin_id'] }}-simple"
class="w-full h-full px-1 mb-2 col-span-12 {% if not setting_input['is_multiple'] %} mt-2 md:col-span-6 {%else%} mt-4 {% endif %} grid grid-cols-12 h-full items-end">
<!-- title and desc -->
@ -32,7 +32,7 @@
{% if setting_input.get('is_multiple') %}
<!-- plugin multiple handler -->
<div data-multiple-handler="{{ setting_input['multiple_name'] }}" data-multiple-levels="{{ setting_input['levels'] }}"
<div data-multiple-handler="{{ setting_input['multiple_name'] }}"
class="flex items-center mx-4 mb-2 mt-5 col-span-12 ">
<h5 class="input-title max-w-[150px] sm:max-w-[350px]">{{ setting_simple['plugin_id'] }}</h5>
<button data-{{ attribute_name }}-multiple-add="{{ setting_input['multiple_name'] }}" type="button" class="ml-3 dark:brightness-90 inline-block px-3 py-1.5 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-green-500 hover:bg-green-500/80 focus:bg-green-500/80 leading-normal text-md ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">
@ -46,7 +46,7 @@
<!-- multiple settings -->
<div data-{{ attribute_name }}-settings-multiple="{{ setting_input['multiple_name'] }}_SCHEMA" class=" col-span-12 bg-gray-50 dark:bg-slate-900/30 hidden w-full mt-4 grid-cols-12 border dark:border-gray-700 rounded">
{% for setting in setting_input.get("multiples") %}
{% set setting_input = { "name" : setting.get("name"), "context" : setting.get("context"), "method" : setting.get("method", "default"), "help" : setting.get("help"), "label" : setting.get("label"), "id" : setting.get("id"), "type" : setting.get("type"), "default" : setting.get("default", "default"), "select" : setting.get("select"), "regex" : setting.get("regex"), "value" : setting.get("value", setting.get('default')), "is_multiple" : True, "levels" : {} } %}
{% set setting_input = { "name" : setting.get("name"), "context" : setting.get("context"), "method" : setting.get("method", "default"), "help" : setting.get("help"), "label" : setting.get("label"), "id" : setting.get("id"), "type" : setting.get("type"), "default" : setting.get("default", "default"), "select" : setting.get("select"), "regex" : setting.get("regex"), "value" : setting.get("value", setting.get('default')), "is_multiple" : True} %}
<div data-setting-container="{{ setting_input['name'] }}_SCHEMA" data-{{ attribute_name }}-type="{{ setting_input['type'] }}" data-{{ attribute_name }}-context="{{ setting_input['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-{{ attribute_name }}-{{ setting_input['id'] }}_SCHEMA">
<!-- title and info -->
{% include "setting_header.html" %}
@ -83,7 +83,7 @@
</div>
</div>
<div class="w-full col-span-12 px-4">
<textarea {% for level_name, value in config['levels'].items() %} data-content-{{level_name}}="{{ value}}" {% endfor %} data-simple-default-editor-content class="hidden" id="{{config['name']}}-content" name="{{config['name']}}-content"></textarea>
<textarea data-simple-default-editor-content class="hidden" id="{{config['name']}}-content" name="{{config['name']}}-content"></textarea>
<!-- editor-->
<div data-simple-editor id="{{config['name']}}-editor" class="text-base w-full h-50 overflow-hidden overflow-y-auto my-2 border border-gray-300 dark:border-slate-800">
</div>