mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
Add the possibility to edit multisite settings in the global config page of the web UI + Lint html files with djlint
This commit is contained in:
parent
5a3d4814fe
commit
ae3b8f1973
13 changed files with 787 additions and 314 deletions
|
|
@ -7,3 +7,4 @@ src/ui/templates/account.html:hashicorp-tf-password:417
|
|||
src/ui/templates/account.html:hashicorp-tf-password:470
|
||||
src/ui/templates/settings_plugins.html:hashicorp-tf-password:87
|
||||
src/ui/templates/settings_plugins.html:hashicorp-tf-password:297
|
||||
src/ui/templates/settings_plugins.html:hashicorp-tf-password:106
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
{% if USE_UI == "yes" +%}
|
||||
SecRule REQUEST_FILENAME "@rx /services$" "id:7771,ctl:ruleRemoveByTag=attack-rce,ctl:ruleRemoveByTag=attack-xss,ctl:ruleRemoveByTag=attack-generic,ctl:ruleRemoveByTag=attack-lfi,ctl:ruleRemoveByTag=attack-rfi,ctl:ruleRemoveByTag=attack-ssrf,nolog"
|
||||
SecRule REQUEST_FILENAME "@rx /global_config$" "id:7772,ctl:ruleRemoveByTag=platform-pgsql,ctl:ruleRemoveByTag=attack-lfi,ctl:ruleRemoveByTag=attack-rfi,ctl:ruleRemoveByTag=attack-ssrf,nolog"
|
||||
SecRule REQUEST_FILENAME "@rx /configs$" "id:7773,ctl:ruleRemoveByTag=language-shell,ctl:ruleRemoveByTag=attack-lfi,ctl:ruleRemoveByTag=attack-rfi,ctl:ruleRemoveByTag=attack-ssrf,nolog"
|
||||
SecRule REQUEST_FILENAME "@rx /(global_config|services)$" "id:7771,ctl:ruleRemoveByTag=language-shell,ctl:ruleRemoveByTag=platform-pgsql,ctl:ruleRemoveByTag=attack-xss,ctl:ruleRemoveByTag=attack-lfi,ctl:ruleRemoveByTag=attack-rfi,ctl:ruleRemoveByTag=attack-ssrf,nolog"
|
||||
SecRule REQUEST_FILENAME "@rx /configs$" "id:7772,ctl:ruleRemoveByTag=language-shell,ctl:ruleRemoveByTag=attack-lfi,ctl:ruleRemoveByTag=attack-rfi,ctl:ruleRemoveByTag=attack-ssrf,nolog"
|
||||
{% endif +%}
|
||||
|
|
|
|||
|
|
@ -787,7 +787,7 @@ def services():
|
|||
|
||||
# Edit check fields and remove already existing ones
|
||||
for variable, value in deepcopy(variables).items():
|
||||
if variable.endswith("SCHEMA"):
|
||||
if variable == "IS_DRAFT" or variable.endswith("SCHEMA"):
|
||||
del variables[variable]
|
||||
continue
|
||||
|
||||
|
|
@ -906,13 +906,14 @@ def services():
|
|||
def global_config():
|
||||
if request.method == "POST":
|
||||
# Check variables
|
||||
variables = deepcopy(request.form.to_dict())
|
||||
variables = request.form.to_dict().copy()
|
||||
del variables["csrf_token"]
|
||||
|
||||
# Edit check fields and remove already existing ones
|
||||
config = app.config["CONFIG"].get_config(methods=False)
|
||||
for variable, value in deepcopy(variables).items():
|
||||
if variable.endswith("SCHEMA"):
|
||||
config = app.config["CONFIG"].get_config(methods=False, with_drafts=True)
|
||||
services = config["SERVER_NAME"].split(" ")
|
||||
for variable, value in variables.copy().items():
|
||||
if variable in ("AUTOCONF_MODE", "SWARM_MODE", "KUBERNETES_MODE", "SERVER_NAME", "IS_LOADING", "IS_DRAFT") or variable.endswith("SCHEMA"):
|
||||
del variables[variable]
|
||||
continue
|
||||
|
||||
|
|
@ -921,13 +922,13 @@ def global_config():
|
|||
elif value == "off":
|
||||
value = "no"
|
||||
|
||||
if value == config.get(variable, None):
|
||||
if value == config.get(variable, None) or any(variable.startswith(f"{service}_") for service in services):
|
||||
del variables[variable]
|
||||
|
||||
if not variables:
|
||||
return redirect_flash_error("The global configuration was not edited because no values were changed.", "global_config", True)
|
||||
|
||||
error = app.config["CONFIG"].check_variables(variables, True)
|
||||
error = app.config["CONFIG"].check_variables(variables)
|
||||
|
||||
if error:
|
||||
return redirect_flash_error("The global configuration variable checks returned error", "global_config", True)
|
||||
|
|
@ -952,12 +953,13 @@ def global_config():
|
|||
)
|
||||
)
|
||||
|
||||
global_config = app.config["CONFIG"].get_config()
|
||||
for service in global_config["SERVER_NAME"]["value"].split(" "):
|
||||
for key in global_config.copy():
|
||||
if key.startswith(f"{service}_"):
|
||||
global_config.pop(key)
|
||||
# Display global config
|
||||
return render_template(
|
||||
"global_config.html",
|
||||
username=current_user.get_id(),
|
||||
global_config=app.config["CONFIG"].get_config(),
|
||||
)
|
||||
return render_template("global_config.html", username=current_user.get_id(), global_config=global_config, dumped_global_config=dumps(global_config))
|
||||
|
||||
|
||||
@app.route("/configs", methods=["GET", "POST"])
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ class Config:
|
|||
"""
|
||||
return self.__db.get_services_settings(methods=methods, with_drafts=with_drafts)
|
||||
|
||||
def check_variables(self, variables: dict, _global: bool = False) -> int:
|
||||
def check_variables(self, variables: dict) -> int:
|
||||
"""Testify that the variables passed are valid
|
||||
|
||||
Parameters
|
||||
|
|
@ -141,11 +141,6 @@ class Config:
|
|||
check = False
|
||||
|
||||
if k in plugins_settings:
|
||||
if _global ^ (plugins_settings[k]["context"] == "global"):
|
||||
error = 1
|
||||
flash(f"Variable {k} is not valid.", "error")
|
||||
continue
|
||||
|
||||
setting = k
|
||||
else:
|
||||
setting = k[0 : k.rfind("_")] # noqa: E203
|
||||
|
|
@ -154,7 +149,7 @@ class Config:
|
|||
flash(f"Variable {k} is not valid.", "error")
|
||||
continue
|
||||
|
||||
if not (_global ^ (plugins_settings[setting]["context"] == "global")) and re_search(plugins_settings[setting]["regex"], v):
|
||||
if re_search(plugins_settings[setting]["regex"], v):
|
||||
check = True
|
||||
|
||||
if not check:
|
||||
|
|
|
|||
|
|
@ -9,10 +9,451 @@ import {
|
|||
class Multiple {
|
||||
constructor(prefix) {
|
||||
this.prefix = prefix;
|
||||
this.container = document.querySelector("main");
|
||||
this.init();
|
||||
}
|
||||
//hide multiples handler if no multiple setting on plugin
|
||||
|
||||
init() {
|
||||
window.addEventListener("load", () => {
|
||||
this.hiddenIfNoMultiples();
|
||||
|
||||
try {
|
||||
//remove all multiples
|
||||
this.removePrevMultiples();
|
||||
//get multiple service values and parse as obj
|
||||
const globalConfigSettings = document
|
||||
.querySelector(`[data-${this.prefix}-settings]`)
|
||||
.getAttribute("data-value");
|
||||
const obj = JSON.parse(globalConfigSettings);
|
||||
//keep only multiple settings value
|
||||
const multipleSettings = this.getMultiplesOnly(obj);
|
||||
const sortMultiples =
|
||||
this.sortMultipleByContainerAndSuffixe(multipleSettings);
|
||||
this.setMultipleToDOM(sortMultiples);
|
||||
} catch (err) {}
|
||||
});
|
||||
|
||||
document
|
||||
.querySelector(`[data-${this.prefix}-form]`)
|
||||
.addEventListener("click", (e) => {
|
||||
//ADD BTN
|
||||
try {
|
||||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`data-${this.prefix}-multiple-add`)
|
||||
) {
|
||||
//get plugin from btn
|
||||
const btn = e.target.closest("button");
|
||||
const attName = btn.getAttribute(
|
||||
`data-${this.prefix}-multiple-add`,
|
||||
);
|
||||
//get all multiple groups
|
||||
const multipleEls = document.querySelectorAll(
|
||||
`[data-${this.prefix}-settings-multiple*="${attName}"]`,
|
||||
);
|
||||
//case no schema
|
||||
if (multipleEls.length <= 0) return;
|
||||
|
||||
//get the next container number logic
|
||||
//default is 0
|
||||
let topNum = 0;
|
||||
//loop on curr multiples, get the name suffix for each
|
||||
//and keep the highest num
|
||||
multipleEls.forEach((container) => {
|
||||
const ctnrName = container.getAttribute(
|
||||
`data-${this.prefix}-settings-multiple`,
|
||||
);
|
||||
const num = this.getSuffixNumOrFalse(ctnrName);
|
||||
if (!isNaN(num) && num > topNum) topNum = num;
|
||||
});
|
||||
//the final number is num
|
||||
//num is total - 1 because of hidden SCHEMA container
|
||||
const currNum = `${multipleEls.length >= 2 ? topNum + 1 : topNum}`;
|
||||
const setNum = +currNum === 0 ? `` : `_${currNum}`;
|
||||
//the default (schema) group is the last group
|
||||
const schema = document.querySelector(
|
||||
`[data-${this.prefix}-settings-multiple="${attName}_SCHEMA"]`,
|
||||
);
|
||||
//clone schema to create a group with new num
|
||||
const schemaClone = schema.cloneNode(true);
|
||||
//add special attribute for disabled logic
|
||||
this.changeCloneSuffix(schemaClone, setNum);
|
||||
//set disabled / enabled state
|
||||
this.setDisabledMultNew(schemaClone);
|
||||
this.showClone(schema, schemaClone);
|
||||
//insert new group before first one
|
||||
//show all groups
|
||||
this.showMultByAtt(attName);
|
||||
}
|
||||
} catch (err) {}
|
||||
|
||||
//TOGGLE BTN
|
||||
try {
|
||||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`data-${this.prefix}-multiple-toggle`)
|
||||
) {
|
||||
const att = e.target
|
||||
.closest("button")
|
||||
.getAttribute(`data-${this.prefix}-multiple-toggle`);
|
||||
this.toggleMultByAtt(att);
|
||||
}
|
||||
//remove last child
|
||||
} catch (err) {}
|
||||
|
||||
//REMOVE BTN
|
||||
try {
|
||||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`data-${this.prefix}-multiple-delete`)
|
||||
) {
|
||||
const multContainer = e.target.closest(
|
||||
`[data-${this.prefix}-settings-multiple]`,
|
||||
);
|
||||
multContainer.remove();
|
||||
}
|
||||
//remove last child
|
||||
} catch (err) {}
|
||||
});
|
||||
}
|
||||
|
||||
sortMultipleByContainerAndSuffixe(obj) {
|
||||
const sortMultiples = {};
|
||||
for (const [name, value] of Object.entries(obj)) {
|
||||
//split name and check if there is a suffixe
|
||||
const splitName = name.split("_");
|
||||
//suffixe start with number 1, if none give arbitrary 0 value to store on same group
|
||||
const isSuffixe = !isNaN(splitName[splitName.length - 1]) ? true : false;
|
||||
const suffixe = isSuffixe ? splitName[splitName.length - 1] : "0";
|
||||
//remove suffix if exists and query related name_SCHEMA to get container info
|
||||
const nameSuffixLess = isSuffixe
|
||||
? name.replace(`_${splitName[splitName.length - 1]}`, "").trim()
|
||||
: name.trim();
|
||||
const relateSetting = document.querySelector(
|
||||
`[data-setting-container=${nameSuffixLess}_SCHEMA]`,
|
||||
);
|
||||
const relateCtnr = relateSetting.closest(
|
||||
`[data-${this.prefix}-settings-multiple]`,
|
||||
);
|
||||
const relateCtnrName = relateCtnr.getAttribute(
|
||||
`data-${this.prefix}-settings-multiple`,
|
||||
);
|
||||
//then we sort the setting on the right container name by suffixe number
|
||||
if (!(relateCtnrName in sortMultiples)) {
|
||||
sortMultiples[relateCtnrName] = {};
|
||||
}
|
||||
|
||||
if (!(suffixe in sortMultiples[relateCtnrName])) {
|
||||
sortMultiples[relateCtnrName][suffixe] = {};
|
||||
}
|
||||
sortMultiples[relateCtnrName][suffixe][name] = value;
|
||||
}
|
||||
return sortMultiples;
|
||||
}
|
||||
|
||||
addOneMultGroup() {
|
||||
const settings = document.querySelector(`[data-${this.prefix}-modal-form]`);
|
||||
const multAddBtns = settings.querySelectorAll(
|
||||
`[data-${this.prefix}-multiple-add]`,
|
||||
);
|
||||
multAddBtns.forEach((btn) => {
|
||||
//check if already one (SCHEMA exclude so length >= 2)
|
||||
const plugin = btn.closest("[data-plugin-item]");
|
||||
if (
|
||||
plugin.querySelectorAll(`[data-${this.prefix}-settings-multiple]`)
|
||||
.length >= 2
|
||||
)
|
||||
return;
|
||||
btn.click();
|
||||
});
|
||||
}
|
||||
|
||||
showMultByAtt(att) {
|
||||
const multContainers = document.querySelectorAll(
|
||||
`[data-${this.prefix}-settings-multiple^=${att}]`,
|
||||
);
|
||||
multContainers.forEach((container) => {
|
||||
if (
|
||||
!container
|
||||
.getAttribute(`data-${this.prefix}-settings-multiple`)
|
||||
.includes("SCHEMA")
|
||||
)
|
||||
container.classList.remove("hidden");
|
||||
});
|
||||
}
|
||||
|
||||
toggleMultByAtt(att) {
|
||||
const multContainers = document.querySelectorAll(
|
||||
`[data-${this.prefix}-settings-multiple^=${att}]`,
|
||||
);
|
||||
multContainers.forEach((container) => {
|
||||
if (
|
||||
!container
|
||||
.getAttribute(`data-${this.prefix}-settings-multiple`)
|
||||
.includes("SCHEMA")
|
||||
)
|
||||
container.classList.toggle("hidden");
|
||||
});
|
||||
}
|
||||
|
||||
getMultiplesOnly(settings) {
|
||||
//get schema settings
|
||||
const multiples = {};
|
||||
const schemaSettings = document.querySelectorAll(
|
||||
`[data-setting-container$="SCHEMA"]`,
|
||||
);
|
||||
// loop on every schema settings
|
||||
schemaSettings.forEach((schema) => {
|
||||
const schemaName = schema
|
||||
.getAttribute("data-setting-container")
|
||||
.replace("_SCHEMA", "")
|
||||
.trim();
|
||||
//check if match with service setting
|
||||
for (const [key, data] of Object.entries(settings)) {
|
||||
if (key.includes(schemaName)) {
|
||||
multiples[key] = {
|
||||
value: data["value"],
|
||||
method: data["method"],
|
||||
global: data["global"],
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
return multiples;
|
||||
}
|
||||
|
||||
//put multiple on the right plugin, on schema container
|
||||
setMultipleToDOM(sortMultObj) {
|
||||
//we loop on each multiple that contains values to render to DOM
|
||||
for (const [schemaCtnrName, multGroupBySuffix] of Object.entries(
|
||||
sortMultObj,
|
||||
)) {
|
||||
//we need to access the DOM schema container
|
||||
const schemaCtnr = document.querySelector(
|
||||
`[data-${this.prefix}-settings-multiple="${schemaCtnrName}"]`,
|
||||
);
|
||||
//now we have to loop on each multiple settings group
|
||||
for (const [suffix, settings] of Object.entries(multGroupBySuffix)) {
|
||||
//we have to clone schema container first
|
||||
const schemaCtnrClone = schemaCtnr.cloneNode(true);
|
||||
//remove id to avoid duplicate and for W3C
|
||||
schemaCtnr.removeAttribute("id");
|
||||
//now we replace _SCHEMA by current suffix everywhere we need
|
||||
//unless it is 0 that means no suffix
|
||||
const suffixFormat = +suffix === 0 ? `` : `_${suffix}`;
|
||||
this.changeCloneSuffix(schemaCtnrClone, suffixFormat);
|
||||
//then we have to loop on every settings of current group to change clone values by right ones
|
||||
for (const [name, data] of Object.entries(settings)) {
|
||||
//get setting container of clone container
|
||||
const settingContainer = schemaCtnrClone.querySelector(
|
||||
`[data-setting-container="${name}"]`,
|
||||
);
|
||||
//replace input info and disabled state
|
||||
this.setSetting(
|
||||
data["value"],
|
||||
data["method"],
|
||||
data["global"],
|
||||
settingContainer,
|
||||
);
|
||||
}
|
||||
//send schema clone to DOM and show it
|
||||
this.showClone(schemaCtnr, schemaCtnrClone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changeCloneSuffix(schemaCtnrClone, suffix) {
|
||||
//rename multiple container
|
||||
schemaCtnrClone.setAttribute(
|
||||
`data-${this.prefix}-settings-multiple`,
|
||||
schemaCtnrClone
|
||||
.getAttribute(`data-${this.prefix}-settings-multiple`)
|
||||
.replace("_SCHEMA", suffix),
|
||||
);
|
||||
|
||||
//rename title
|
||||
const titles = schemaCtnrClone.querySelectorAll("h5");
|
||||
titles.forEach((title) => {
|
||||
const text = title.textContent;
|
||||
title.textContent = `${text} ${
|
||||
suffix ? `#${suffix.replace("_", "")}` : ``
|
||||
}`;
|
||||
});
|
||||
|
||||
//rename setting container
|
||||
const settingCtnrs = schemaCtnrClone.querySelectorAll(
|
||||
"[data-setting-container]",
|
||||
);
|
||||
settingCtnrs.forEach((settingCtnr) => {
|
||||
settingCtnr.setAttribute(
|
||||
"data-setting-container",
|
||||
settingCtnr
|
||||
.getAttribute("data-setting-container")
|
||||
.replace("_SCHEMA", suffix),
|
||||
);
|
||||
settingCtnr.setAttribute(
|
||||
"id",
|
||||
settingCtnr.getAttribute("id").replace("_SCHEMA", suffix),
|
||||
);
|
||||
});
|
||||
|
||||
//rename input
|
||||
try {
|
||||
const inps = schemaCtnrClone.querySelectorAll("input");
|
||||
this.renameLoop(inps, suffix);
|
||||
} catch (err) {}
|
||||
|
||||
//rename select
|
||||
try {
|
||||
const selects = schemaCtnrClone.querySelectorAll("select");
|
||||
this.renameLoop(selects, suffix);
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
renameLoop(inps, suffix) {
|
||||
inps.forEach((inp) => {
|
||||
const newName = inp.getAttribute("name").replace("_SCHEMA", suffix);
|
||||
inp.setAttribute("name", newName);
|
||||
if (inp.hasAttribute("id")) inp.setAttribute("id", newName);
|
||||
});
|
||||
}
|
||||
|
||||
setSetting(value, method, global, settingContainer) {
|
||||
//update input
|
||||
try {
|
||||
const inps = settingContainer.querySelectorAll("input");
|
||||
inps.forEach((inp) => {
|
||||
//form related values are excludes
|
||||
const inpName = inp.getAttribute("name");
|
||||
if (
|
||||
inpName === "csrf_token" ||
|
||||
inpName === "OLD_SERVER_NAME" ||
|
||||
inpName === "is_draft" ||
|
||||
inpName === "operation" ||
|
||||
inpName === "settings-filter"
|
||||
)
|
||||
return;
|
||||
|
||||
//for settings input
|
||||
if (inp.getAttribute("type") === "checkbox") {
|
||||
try {
|
||||
if (inp.hasAttribute("aria-checked")) {
|
||||
value === "yes"
|
||||
? inp.setAttribute("aria-checked", "true")
|
||||
: inp.setAttribute("aria-checked", "false");
|
||||
}
|
||||
} catch (err) {}
|
||||
|
||||
try {
|
||||
value === "yes"
|
||||
? inp.setAttribute("data-checked", "true")
|
||||
: inp.setAttribute("data-checked", "false");
|
||||
} catch (err) {}
|
||||
|
||||
inp.setAttribute("value", value);
|
||||
inp.setAttribute("data-method", method);
|
||||
inp.checked = true;
|
||||
}
|
||||
|
||||
if (inp.getAttribute("type") !== "checkbox") {
|
||||
inp.setAttribute("value", value);
|
||||
inp.value = value;
|
||||
inp.setAttribute("data-method", method);
|
||||
}
|
||||
this.setDisabledMultServ(inp, method, global);
|
||||
});
|
||||
} catch (err) {}
|
||||
//update select
|
||||
try {
|
||||
const select = settingContainer.querySelector("select");
|
||||
select.setAttribute("data-method", method);
|
||||
|
||||
//click the custom select dropdown btn value to update select value
|
||||
select.parentElement
|
||||
.querySelector(
|
||||
`button[data-setting-select-dropdown-btn][value='${defaultVal}']`,
|
||||
)
|
||||
.click();
|
||||
|
||||
//set state to custom visible el
|
||||
const btnCustom = document.querySelector(
|
||||
`[data-setting-select=${select.getAttribute(
|
||||
"data-setting-select-default",
|
||||
)}]`,
|
||||
);
|
||||
|
||||
this.setDisabledMultServ(btnCustom, method, global);
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
showClone(schemaCtnr, schemaCtnrClone) {
|
||||
schemaCtnr.insertAdjacentElement("afterend", schemaCtnrClone);
|
||||
schemaCtnrClone.classList.remove("hidden");
|
||||
schemaCtnrClone.classList.add("grid");
|
||||
}
|
||||
|
||||
//global value isn't check at this point
|
||||
setDisabledMultNew(container) {
|
||||
const settings = container.querySelectorAll("[data-setting-container]");
|
||||
|
||||
settings.forEach((setting) => {
|
||||
//replace input info
|
||||
try {
|
||||
const inps = setting.querySelectorAll("input");
|
||||
inps.forEach((inp) => {
|
||||
const method = inp.getAttribute("data-default-method");
|
||||
if (method === "ui" || method === "default") {
|
||||
inp.removeAttribute("disabled");
|
||||
} else {
|
||||
inp.setAttribute("disabled", "");
|
||||
}
|
||||
});
|
||||
} catch (err) {}
|
||||
//or select
|
||||
try {
|
||||
const selects = setting.querySelectorAll("select");
|
||||
selects.forEach((select) => {
|
||||
const method = select.getAttribute("data-default-method");
|
||||
const name = select.getAttribute(
|
||||
`data-${this.prefix}-setting-select-default`,
|
||||
);
|
||||
const selDOM = document.querySelector(
|
||||
`button[data-${this.prefix}-setting-select='${name}']`,
|
||||
);
|
||||
if (method === "ui" || method === "default") {
|
||||
selDOM.removeAttribute("disabled", "");
|
||||
} else {
|
||||
selDOM.setAttribute("disabled", "");
|
||||
}
|
||||
});
|
||||
} catch (err) {}
|
||||
});
|
||||
}
|
||||
|
||||
//for already existing global config multiples
|
||||
//global is check
|
||||
setDisabledMultServ(inp, method, global) {
|
||||
if (global) return inp.removeAttribute("disabled");
|
||||
|
||||
if (method === "ui" || method === "default") {
|
||||
inp.removeAttribute("disabled");
|
||||
} else {
|
||||
inp.setAttribute("disabled", "");
|
||||
}
|
||||
}
|
||||
//UTILS
|
||||
|
||||
getSuffixNumOrFalse(name) {
|
||||
const num = !isNaN(Number(name.substring(name.lastIndexOf("_") + 1)))
|
||||
? Number(name.substring(name.lastIndexOf("_") + 1))
|
||||
: "";
|
||||
return num;
|
||||
}
|
||||
|
||||
hiddenIfNoMultiples() {
|
||||
//hide multiple btn if no multiple exist on a plugin
|
||||
const multiples = document.querySelectorAll(
|
||||
`[data-${this.prefix}-settings-multiple]`,
|
||||
|
|
@ -24,6 +465,39 @@ class Multiple {
|
|||
.classList.add("hidden");
|
||||
});
|
||||
}
|
||||
|
||||
removePrevMultiples() {
|
||||
const multiPlugins = document.querySelectorAll(
|
||||
`[data-${this.prefix}-settings-multiple]`,
|
||||
);
|
||||
multiPlugins.forEach((multiGrp) => {
|
||||
if (
|
||||
!multiGrp
|
||||
.getAttribute(`data-${this.prefix}-settings-multiple`)
|
||||
.includes("SCHEMA")
|
||||
)
|
||||
multiGrp.remove();
|
||||
});
|
||||
}
|
||||
|
||||
showMultiple(el) {
|
||||
el.classList.add("grid");
|
||||
el.classList.remove("hidden");
|
||||
}
|
||||
|
||||
setNameIDloop(iterable, value) {
|
||||
iterable.forEach((item) => {
|
||||
const currID = item.getAttribute("id");
|
||||
const currName = item.getAttribute("name");
|
||||
item.setAttribute("id", `${currID}_${value}`);
|
||||
item.setAttribute("name", `${currName}_${value}`);
|
||||
});
|
||||
}
|
||||
|
||||
setNameID(el, value) {
|
||||
el.setAttribute("id", `${value}`);
|
||||
el.setAttribute("name", `${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
const setPopover = new Popover("main", "global-config");
|
||||
|
|
@ -32,7 +506,6 @@ const setTabsSelect = new TabsSelect(
|
|||
document.querySelector("[data-global-config-plugins-container]"),
|
||||
);
|
||||
const format = new FormatValue();
|
||||
const setMultiple = new Multiple("global-config");
|
||||
|
||||
const setFilterGlobal = new FilterSettings(
|
||||
"keyword",
|
||||
|
|
@ -40,6 +513,8 @@ const setFilterGlobal = new FilterSettings(
|
|||
document.querySelector("[data-global-config-plugins-container]"),
|
||||
);
|
||||
|
||||
const setMultiple = new Multiple("global-config");
|
||||
|
||||
const checkServiceModalKeyword = new CheckNoMatchFilter(
|
||||
document.querySelector("input#keyword"),
|
||||
"input",
|
||||
|
|
|
|||
22
src/ui/templates/global_config.html
vendored
22
src/ui/templates/global_config.html
vendored
|
|
@ -1,15 +1,14 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<div data-global-config-tabs-select-container
|
||||
class="z-100 w-full grid grid-cols-12 h-fit max-h-100 sm:max-h-125 col-span-12 md:col-span-6 lg:col-span-4 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
|
||||
<div data-{{ current_endpoint }}-tabs-select-header class="col-span-12">
|
||||
<div class="flex flex-col xs:flex-row xs:justify-start xs:items-center gap-x-4 gap-y-2 mb-4">
|
||||
<h5 class="transition duration-300 ease-in-out 0 ml-2 font-bold text-md uppercase dark:text-white/90 mb-0">PLUGINS</h5>
|
||||
<div data-global-config-tabs-select-container
|
||||
class="z-100 w-full grid grid-cols-12 h-fit max-h-100 sm:max-h-125 col-span-12 md:col-span-6 lg:col-span-4 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
|
||||
<div data-{{ current_endpoint }}-tabs-select-header class="col-span-12">
|
||||
<div class="flex flex-col xs:flex-row xs:justify-start xs:items-center gap-x-4 gap-y-2 mb-4">
|
||||
<h5 class="transition duration-300 ease-in-out 0 ml-2 font-bold text-md uppercase dark:text-white/90 mb-0">PLUGINS</h5>
|
||||
</div>
|
||||
{% include "settings_tabs_select.html" %}
|
||||
</div>
|
||||
{% include "settings_tabs_select.html" %}
|
||||
</div>
|
||||
</div>
|
||||
<!-- filter -->
|
||||
{% set filters = [
|
||||
{
|
||||
|
|
@ -87,13 +86,15 @@ class="z-100 w-full grid grid-cols-12 h-fit max-h-100 sm:max-h-125 col-span-12
|
|||
</div>
|
||||
</div>
|
||||
<!-- end filter -->
|
||||
|
||||
<div data-global-config-plugins-container
|
||||
class="col-span-12 gap-y-4 grid grid-cols-12">
|
||||
<div data-global-config-settings
|
||||
class="hidden"
|
||||
data-value="{{ dumped_global_config }}"></div>
|
||||
<!-- form global conf -->
|
||||
<form data-global-config-form
|
||||
id="form-edit-global-config"
|
||||
method="POST"
|
||||
method="post"
|
||||
class="flex flex-col justify-between overflow-hidden overflow-y-auto dark:brightness-110 col-span-12 break-words bg-white shadow-xl p-4 dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
<!-- plugin item -->
|
||||
|
|
@ -121,5 +122,4 @@ class="z-100 w-full grid grid-cols-12 h-fit max-h-100 sm:max-h-125 col-span-12
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
|
|
|||
3
src/ui/templates/header.html
vendored
3
src/ui/templates/header.html
vendored
|
|
@ -7,7 +7,8 @@
|
|||
<h6 class="mb-0 text-lg font-bold text-white capitalize">{{ current_endpoint }}</h6>
|
||||
<ul class="flex flex-wrap pt-1 mr-12 bg-transparent rounded-lg sm:mr-16">
|
||||
<li class="text-sm leading-normal">
|
||||
<a class="text-white opacity-50 dark:opacity-100 dark:text-gray-500" href="javascript:;">BunkerWeb</a>
|
||||
<a class="text-white opacity-50 dark:opacity-100 dark:text-gray-500"
|
||||
href="javascript:;">BunkerWeb</a>
|
||||
</li>
|
||||
<li class="hidden sm:inline text-sm pl-0 xs:pl-2 capitalize leading-normal text-white before:float-left before:pr-2 before:text-white before:content-['/']"
|
||||
aria-current="page">{{ current_endpoint }}</li>
|
||||
|
|
|
|||
35
src/ui/templates/logs.html
vendored
35
src/ui/templates/logs.html
vendored
|
|
@ -53,9 +53,7 @@
|
|||
<h5 class="col-span-12 mb-1 mt-2 text-[1.1rem] font-bold dark:text-white/90">Date options</h5>
|
||||
<!-- from date input -->
|
||||
<div class="flex flex-col relative col-span-12 sm: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">
|
||||
From date
|
||||
</h5>
|
||||
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">From date</h5>
|
||||
<div class="relative">
|
||||
<input type="text"
|
||||
id="from-date"
|
||||
|
|
@ -124,7 +122,6 @@
|
|||
</div>
|
||||
</div>
|
||||
<!-- end refresh inp-->
|
||||
|
||||
<!-- refresh delay input -->
|
||||
<div class="flex flex-col relative col-span-12 sm: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">
|
||||
|
|
@ -139,7 +136,6 @@
|
|||
required />
|
||||
</div>
|
||||
<!-- end refresh delay input -->
|
||||
|
||||
<div class="col-span-12 w-full justify-center flex mt-2">
|
||||
<button data-submit-date
|
||||
id="submit-data"
|
||||
|
|
@ -247,22 +243,21 @@
|
|||
</div>
|
||||
<!-- end filter -->
|
||||
<div data-logs-no-run
|
||||
class="w-full overflow-hidden grid grid-cols-12 max-h-100 sm:max-h-125 col-span-12 p-4 relative break-words">
|
||||
<div class="col-span-12 flex flex-col justify-center items-center h-fit">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="mb-2 w-8 h-8 stroke-white">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607ZM10.5 7.5v6m3-3h-6" />
|
||||
</svg>
|
||||
<h5 class="font-bold dark:text-white/90 mx-2 text-white">No logs to show</h5>
|
||||
class="w-full overflow-hidden grid grid-cols-12 max-h-100 sm:max-h-125 col-span-12 p-4 relative break-words">
|
||||
<div class="col-span-12 flex flex-col justify-center items-center h-fit">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="mb-2 w-8 h-8 stroke-white">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607ZM10.5 7.5v6m3-3h-6" />
|
||||
</svg>
|
||||
<h5 class="font-bold dark:text-white/90 mx-2 text-white">No logs to show</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div data-logs-card class="hidden w-full overflow-hidden grid grid-cols-12 max-h-100 sm:max-h-125 col-span-12 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
|
||||
<div data-logs-card
|
||||
class="hidden w-full overflow-hidden grid grid-cols-12 max-h-100 sm:max-h-125 col-span-12 p-4 relative break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
|
||||
<div class="col-span-12">
|
||||
<h5 class="mb-4 mt-2 font-bold dark:text-white/90 mx-2">LOGS</h5>
|
||||
</div>
|
||||
|
|
|
|||
8
src/ui/templates/menu.html
vendored
8
src/ui/templates/menu.html
vendored
|
|
@ -201,7 +201,9 @@
|
|||
<div>
|
||||
<ul>
|
||||
<li class="w-full mt-4">
|
||||
<h6 class="pl-6 ml-2 text-xs font-bold leading-tight uppercase dark:text-gray-400 dark:opacity-100 opacity-60">PLUGINS PAGE</h6>
|
||||
<h6 class="pl-6 ml-2 text-xs font-bold leading-tight uppercase dark:text-gray-400 dark:opacity-100 opacity-60">
|
||||
PLUGINS PAGE
|
||||
</h6>
|
||||
</li>
|
||||
{% for plugin in plugins %}
|
||||
{% if plugin['page'] and plugin['type'] != "pro" %}
|
||||
|
|
@ -221,9 +223,7 @@
|
|||
{% endif %}
|
||||
{% if plugin['page'] and plugin['type'] == "pro" %}
|
||||
<li class="mt-0.5 w-full">
|
||||
<a {% if not is_pro_version %}target="_blank" rel="noopener"{% endif %}
|
||||
class="dark:hover:bg-primary/20 hover:bg-primary/5 hover:rounded-lg dark:text-gray-200 py-1 text-sm ease-nav-brand my-0 mx-2 flex items-center whitespace-nowrap px-4 transition"
|
||||
href="{% if not is_pro_version %}https://panel.bunkerweb.io/?utm_campaign=self&utm_source=ui#pro{% else %}javascript:void(0){% endif %}"
|
||||
<a {% if not is_pro_version %}target="_blank" rel="noopener"{% endif %} class="dark:hover:bg-primary/20 hover:bg-primary/5 hover:rounded-lg dark:text-gray-200 py-1 text-sm ease-nav-brand my-0 mx-2 flex items-center whitespace-nowrap px-4 transition" href="{% if not is_pro_version %}https://panel.bunkerweb.io/?utm_campaign=self&utm_source=ui#pro{% else %}javascript:void(0){% endif %}"
|
||||
<div class="mr-2 flex items-center justify-center rounded-lg bg-center stroke-0 text-center p-1 xl:p-1.5">
|
||||
<svg class="h-5 w-5 dark:brightness-90"
|
||||
viewBox="0 0 48 46"
|
||||
|
|
|
|||
25
src/ui/templates/services_modal.html
vendored
25
src/ui/templates/services_modal.html
vendored
|
|
@ -42,12 +42,9 @@
|
|||
</svg>
|
||||
</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="w-full sm:min-w-[250px] max-w-[300px]">
|
||||
{% include "settings_tabs_select.html" %}
|
||||
</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="w-full sm:min-w-[250px] max-w-[300px]">{% include "settings_tabs_select.html" %}</div>
|
||||
<!-- search inpt-->
|
||||
<div class="flex relative w-full max-w-[200px]">
|
||||
<label class="sr-only" for="settings-filter">search</label>
|
||||
|
|
@ -60,14 +57,11 @@
|
|||
required />
|
||||
</div>
|
||||
<!-- end search inpt-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="w-full min-w-[300px] my-1 sm:my-0">
|
||||
<hr class="separator" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div data-services-nomatch
|
||||
class="hidden w-full overflow-hidden grid grid-cols-12 max-h-100 sm:max-h-125 col-span-12 p-4 relative break-words">
|
||||
<div class="col-span-12 flex flex-col justify-center items-center h-fit">
|
||||
|
|
@ -91,19 +85,18 @@
|
|||
<input type="hidden" id="operation" value="new" name="operation" />
|
||||
<input type="hidden" value="new" name="OLD_SERVER_NAME" />
|
||||
<input type="hidden" value="no" name="is_draft" />
|
||||
|
||||
{% include "settings_plugins.html" %}
|
||||
<!-- action button -->
|
||||
<div class="w-full flex-col items-center justify-center flex mt-10">
|
||||
<div class="flex justify-center">
|
||||
|
||||
<button data-services-modal-close
|
||||
type="button"
|
||||
class="close-btn mb-4 mr-3 text-base">Close</button>
|
||||
<button data-services-modal-submit type="submit" class="mb-4 valid-btn">Save</button>
|
||||
type="button"
|
||||
class="close-btn mb-4 mr-3 text-base">Close</button>
|
||||
<button data-services-modal-submit type="submit" class="mb-4 valid-btn">Save</button>
|
||||
</div>
|
||||
<!-- end action button-->
|
||||
<p data-services-modal-error-msg class="hidden text-red-500 font-bold dark:opacity-80 mb-0 text-center"></p>
|
||||
<p data-services-modal-error-msg
|
||||
class="hidden text-red-500 font-bold dark:opacity-80 mb-0 text-center"></p>
|
||||
</div>
|
||||
</form>
|
||||
<!-- end new and edit form -->
|
||||
|
|
|
|||
371
src/ui/templates/settings_plugins.html
vendored
371
src/ui/templates/settings_plugins.html
vendored
|
|
@ -46,203 +46,199 @@
|
|||
<p class="text-sm dark:text-gray-300 mb-1">{{ plugin['description'] }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{# get number of multiple groups for the plugin #}
|
||||
{% set multList = [] %}
|
||||
<!-- end title and desc -->
|
||||
<div data-plugin-settings class="w-full grid grid-cols-12">
|
||||
<!-- plugin settings not multiple -->
|
||||
{% for setting, value in plugin["settings"].items() %}
|
||||
{% if setting not in ["IS_LOADING", "IS_DRAFT"] and current_endpoint
|
||||
== "global-config" and value['context'] == "global" and not value['multiple'] or setting != "IS_DRAFT" and current_endpoint ==
|
||||
"services" and value['context'] == "multisite" and not value['multiple'] %}
|
||||
<div data-setting-container data-{{ current_endpoint }}-context="{{ value['context'] }}" class="mx-0 sm:mx-2 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>
|
||||
<svg data-popover-btn="{{ value["label"] }}"
|
||||
class="popover-settings-svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512">
|
||||
<path d="M256 512c141.4 0 256-114.6 256-256S397.4 0 256 0S0 114.6 0 256S114.6 512 256 512zM216 336h24V272H216c-13.3 0-24-10.7-24-24s10.7-24 24-24h48c13.3 0 24 10.7 24 24v88h8c13.3 0 24 10.7 24 24s-10.7 24-24 24H216c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-144c-17.7 0-32-14.3-32-32s14.3-32 32-32s32 14.3 32 32s-14.3 32-32 32z" />
|
||||
</svg>
|
||||
<!-- popover -->
|
||||
<div role="alert"
|
||||
aria-description="show detail"
|
||||
class="popover-settings-container hidden"
|
||||
data-popover-content="{{ value["label"] }}">
|
||||
<p class="popover-settings-text">{{ value['help'] }}</p>
|
||||
</div>
|
||||
<!-- end popover -->
|
||||
</div>
|
||||
<!-- end title and info -->
|
||||
<!-- input -->
|
||||
{% if value["type"] != "select" and value["type"] != "check" %}
|
||||
<div class="relative flex items-center">
|
||||
<label class="sr-only" for="{{ setting }}">{{ setting }}</label>
|
||||
<input {% if setting == "SERVER_NAME" %}required{% endif %}
|
||||
data-default-value="{{ global_config[setting]['value'] }}"
|
||||
data-default-method="{{ global_config[setting]['method'] }}"
|
||||
{% if global_config[setting]['method'] != 'ui' and global_config[setting]['method'] != 'default' %}disabled{% endif %}
|
||||
id="{{ setting }}"
|
||||
name="{{ setting }}"
|
||||
class="regular-input"
|
||||
value="{% if global_config[setting]['value'] %} {{ global_config[setting]['value'] }} {% else %} {{ value['default'] }} {% endif %}"
|
||||
type="{{ value['type'] }}"
|
||||
pattern="{{ value['regex']|safe }}" />
|
||||
{% if value['type'] == "password" %}
|
||||
<div data-setting-password-container class="absolute flex right-2 h-5 w-5">
|
||||
<button type="button"
|
||||
data-setting-password="visible"
|
||||
class="h-5 w-5 flex items-center align-middle">
|
||||
<svg class="fill-primary pointer-events-none dark:fill-blue-500 hover:brightness-75 transition-all"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 576 512">
|
||||
<path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button"
|
||||
data-setting-password="invisible"
|
||||
class="hidden -translate-y-0.2 scale-110 h-5 w-5 items-center align-middle">
|
||||
<svg class="fill-primary pointer-events-none dark:fill-blue-500 hover:brightness-75 transition-all"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 640 512">
|
||||
<path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<!-- end input -->
|
||||
<!-- select -->
|
||||
{% if value["type"] == "select" %}
|
||||
<!-- default hidden-->
|
||||
<select data-default-method="{{ global_config[setting]['method'] }}"
|
||||
data-default-value="{{ value['default'] }}"
|
||||
id="{{ setting }}"
|
||||
name="{{ setting }}"
|
||||
data-setting-select-default="{{ value['id'] }}"
|
||||
data-type="form-select"
|
||||
id="{{ setting }}"
|
||||
name="{{ setting }}"
|
||||
class="hidden">
|
||||
{% for item in value['select'] %}
|
||||
<option {% if not item %}label="empty"{% endif %}
|
||||
value="{{ item }}"
|
||||
{% if global_config[setting]['value'] and global_config[setting]['value'] == item or not global_config[setting]['value'] and value['default'] == item %} selected{% endif %}>
|
||||
{{ item }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<!-- end default hidden-->
|
||||
<!--custom-->
|
||||
<div data-select-container class="relative">
|
||||
<button {% if global_config[setting]['method'] != 'ui' and global_config[setting]['method'] != 'default' %}disabled{% endif %}
|
||||
data-setting-select="{{ value['id'] }}"
|
||||
data-default-value="{{ global_config[setting]['value'] }}"
|
||||
data-default-method="{{ global_config[setting]['method'] }}"
|
||||
aria-controls="{{ value['id'] }}-dropdown"
|
||||
type="button"
|
||||
class="custom-select-btn">
|
||||
{% for item in value['select'] %}
|
||||
{% if global_config[setting]['value'] and
|
||||
global_config[setting]['value'] == item %}
|
||||
<span data-setting-select-text="{{ value['id'] }}"
|
||||
data-value="{{ global_config[setting]['value'] }}">{{ global_config[setting]['value'] }}</span>
|
||||
{% elif not global_config[setting]['value'] and value['default'] == item %}
|
||||
<span aria-description="current value"
|
||||
data-setting-select-text="{{ value['id'] }}"
|
||||
data-value="{{ value['default'] }}">{{ value['default'] }}</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<!-- chevron -->
|
||||
<svg data-setting-select="{{ value['id'] }}"
|
||||
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" />
|
||||
</svg>
|
||||
<!-- end chevron -->
|
||||
</button>
|
||||
<!-- dropdown-->
|
||||
<div id="{{ value['id'] }}-dropdown"
|
||||
role="listbox"
|
||||
data-setting-select-dropdown="{{ value['id'] }}"
|
||||
class="hidden z-[20] absolute h-full flex-col w-full mt-2">
|
||||
{% for item in value['select'] %}
|
||||
{% if global_config[setting]['value'] and
|
||||
global_config[setting]['value'] == item or not global_config[setting]['value']
|
||||
and value['default'] == item %}
|
||||
<button role="option"
|
||||
value="{{ item }}"
|
||||
data-setting-select-dropdown-btn="{{ value['id'] }}"
|
||||
type="button"
|
||||
class="active custom-dropdown-btn {% if loop.index == 1 %}border-t rounded-t{% endif %} {% if loop.index == loop.length %}rounded-b{% endif %} ">
|
||||
{{ item }}
|
||||
</button>
|
||||
{% else %}
|
||||
<button role="option"
|
||||
value="{{ item }}"
|
||||
data-setting-select-dropdown-btn="{{ value['id'] }}"
|
||||
type="button"
|
||||
class="custom-dropdown-btn {% if loop.index == 1 %}border-t rounded-t{% endif %} {% if loop.index == loop.length %}rounded-b{% endif %} ">
|
||||
{{ item }}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<!-- end dropdown-->
|
||||
</div>
|
||||
<!-- end custom-->
|
||||
{% endif %}
|
||||
<!-- checkbox -->
|
||||
{% if value["type"] == "check" %}
|
||||
<div data-checkbox-handler="{{ value['id'] }}"
|
||||
class="relative mb-7 md:mb-0 z-10 ">
|
||||
<label class="sr-only" for="{{ setting }}">{{ setting }}</label>
|
||||
<input id="{{ setting }}"
|
||||
name="{{ setting }}"
|
||||
data-default-method="{% if setting in ['AUTOCONF_MODE', 'SWARM_MODE', 'KUBERNETES_MODE'] %}mode{% else %}{{ global_config[setting]['method'] }}{% endif %}"
|
||||
data-default-value="{{ global_config[setting]['value'] }}"
|
||||
{% if setting in ['AUTOCONF_MODE', 'SWARM_MODE', 'KUBERNETES_MODE'] or global_config[setting]['method'] != 'ui' and global_config[setting]['method'] != 'default' %} disabled {% endif %}
|
||||
data-checked="{% if global_config[setting]['value'] == "yes" %}true{% else %}false{% endif %}"
|
||||
checked
|
||||
id="checkbox-{{ value['id'] }}"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
data-pattern="{{ value['regex']|safe }}"
|
||||
value="{{ global_config[setting]['value'] }}" />
|
||||
<svg data-checkbox-handler="{{ value['id'] }}"
|
||||
class="pointer-events-none absolute fill-white dark:fill-gray-300 left-0 top-0 translate-x-1 translate-y-2 h-3 w-3"
|
||||
{% if setting != "IS_DRAFT" and (current_endpoint == "global-config" and setting not in ["SERVER_NAME", "IS_LOADING"] or current_endpoint == "services" and value['context'] == "multisite") %}
|
||||
{% if value['multiple'] and value['multiple'] not in multList %}
|
||||
{% if multList.append(value['multiple']) %}{% endif %}
|
||||
{% endif %}
|
||||
{% if not value['multiple'] %}
|
||||
<div data-setting-container data-{{ current_endpoint }}-context="{{ value['context'] }}" class="mx-0 sm:mx-2 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>
|
||||
<svg data-popover-btn="{{ value["label"] }}"
|
||||
class="popover-settings-svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512">
|
||||
<path class="pointer-events-none" d="M470.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L192 338.7 425.4 105.4c12.5-12.5 32.8-12.5 45.3 0z">
|
||||
</path>
|
||||
<path d="M256 512c141.4 0 256-114.6 256-256S397.4 0 256 0S0 114.6 0 256S114.6 512 256 512zM216 336h24V272H216c-13.3 0-24-10.7-24-24s10.7-24 24-24h48c13.3 0 24 10.7 24 24v88h8c13.3 0 24 10.7 24 24s-10.7 24-24 24H216c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-144c-17.7 0-32-14.3-32-32s14.3-32 32-32s32 14.3 32 32s-14.3 32-32 32z" />
|
||||
</svg>
|
||||
<!-- popover -->
|
||||
<div role="alert"
|
||||
aria-description="show detail"
|
||||
class="popover-settings-container hidden"
|
||||
data-popover-content="{{ value["label"] }}">
|
||||
<p class="popover-settings-text">{{ value['help'] }}</p>
|
||||
</div>
|
||||
<!-- end popover -->
|
||||
</div>
|
||||
{% endif %}
|
||||
<!-- end checkbox -->
|
||||
<!-- invalid feedback -->
|
||||
<div role="alert"
|
||||
aria-label="show when invalid input"
|
||||
class="hidden text-sm dark:text-red-500">
|
||||
{{ value['label'] }} is invalid and must match this pattern:
|
||||
{{ value['regex']|safe }}
|
||||
<!-- end title and info -->
|
||||
<!-- input -->
|
||||
{% if value["type"] != "select" and value["type"] != "check" %}
|
||||
<div class="relative flex items-center">
|
||||
<label class="sr-only" for="{{ setting }}">{{ setting }}</label>
|
||||
<input {% if setting == "SERVER_NAME" %}required{% endif %}
|
||||
data-default-value="{{ global_config[setting]['value'] }}"
|
||||
data-default-method="{{ global_config[setting]['method'] }}"
|
||||
{% if global_config[setting]['method'] != 'ui' and global_config[setting]['method'] != 'default' %}disabled{% endif %}
|
||||
id="{{ setting }}"
|
||||
name="{{ setting }}"
|
||||
class="regular-input"
|
||||
value="{% if global_config[setting]['value'] %} {{ global_config[setting]['value'] }} {% else %} {{ value['default'] }} {% endif %}"
|
||||
type="{{ value['type'] }}"
|
||||
pattern="{{ value['regex']|safe }}" />
|
||||
{% if value['type'] == "password" %}
|
||||
<div data-setting-password-container class="absolute flex right-2 h-5 w-5">
|
||||
<button type="button"
|
||||
data-setting-password="visible"
|
||||
class="h-5 w-5 flex items-center align-middle">
|
||||
<svg class="fill-primary pointer-events-none dark:fill-blue-500 hover:brightness-75 transition-all"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 576 512">
|
||||
<path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button"
|
||||
data-setting-password="invisible"
|
||||
class="hidden -translate-y-0.2 scale-110 h-5 w-5 items-center align-middle">
|
||||
<svg class="fill-primary pointer-events-none dark:fill-blue-500 hover:brightness-75 transition-all"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 640 512">
|
||||
<path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<!-- end input -->
|
||||
<!-- select -->
|
||||
{% if value["type"] == "select" %}
|
||||
<!-- default hidden-->
|
||||
<select data-default-method="{{ global_config[setting]['method'] }}"
|
||||
data-default-value="{{ value['default'] }}"
|
||||
id="{{ setting }}"
|
||||
name="{{ setting }}"
|
||||
data-setting-select-default="{{ value['id'] }}"
|
||||
data-type="form-select"
|
||||
id="{{ setting }}"
|
||||
name="{{ setting }}"
|
||||
class="hidden">
|
||||
{% for item in value['select'] %}
|
||||
<option {% if not item %}label="empty"{% endif %}
|
||||
value="{{ item }}"
|
||||
{% if global_config[setting]['value'] and global_config[setting]['value'] == item or not global_config[setting]['value'] and value['default'] == item %} selected{% endif %}>
|
||||
{{ item }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<!-- end default hidden-->
|
||||
<!--custom-->
|
||||
<div data-select-container class="relative">
|
||||
<button {% if global_config[setting]['method'] != 'ui' and global_config[setting]['method'] != 'default' %}disabled{% endif %}
|
||||
data-setting-select="{{ value['id'] }}"
|
||||
data-default-value="{{ global_config[setting]['value'] }}"
|
||||
data-default-method="{{ global_config[setting]['method'] }}"
|
||||
aria-controls="{{ value['id'] }}-dropdown"
|
||||
type="button"
|
||||
class="custom-select-btn">
|
||||
{% for item in value['select'] %}
|
||||
{% if global_config[setting]['value'] and
|
||||
global_config[setting]['value'] == item %}
|
||||
<span data-setting-select-text="{{ value['id'] }}"
|
||||
data-value="{{ global_config[setting]['value'] }}">{{ global_config[setting]['value'] }}</span>
|
||||
{% elif not global_config[setting]['value'] and value['default'] == item %}
|
||||
<span aria-description="current value"
|
||||
data-setting-select-text="{{ value['id'] }}"
|
||||
data-value="{{ value['default'] }}">{{ value['default'] }}</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<!-- chevron -->
|
||||
<svg data-setting-select="{{ value['id'] }}"
|
||||
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" />
|
||||
</svg>
|
||||
<!-- end chevron -->
|
||||
</button>
|
||||
<!-- dropdown-->
|
||||
<div id="{{ value['id'] }}-dropdown"
|
||||
role="listbox"
|
||||
data-setting-select-dropdown="{{ value['id'] }}"
|
||||
class="hidden z-[20] absolute h-full flex-col w-full mt-2">
|
||||
{% for item in value['select'] %}
|
||||
{% if global_config[setting]['value'] and
|
||||
global_config[setting]['value'] == item or not global_config[setting]['value']
|
||||
and value['default'] == item %}
|
||||
<button role="option"
|
||||
value="{{ item }}"
|
||||
data-setting-select-dropdown-btn="{{ value['id'] }}"
|
||||
type="button"
|
||||
class="active custom-dropdown-btn {% if loop.index == 1 %}border-t rounded-t{% endif %} {% if loop.index == loop.length %}rounded-b{% endif %} ">
|
||||
{{ item }}
|
||||
</button>
|
||||
{% else %}
|
||||
<button role="option"
|
||||
value="{{ item }}"
|
||||
data-setting-select-dropdown-btn="{{ value['id'] }}"
|
||||
type="button"
|
||||
class="custom-dropdown-btn {% if loop.index == 1 %}border-t rounded-t{% endif %} {% if loop.index == loop.length %}rounded-b{% endif %} ">
|
||||
{{ item }}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<!-- end dropdown-->
|
||||
</div>
|
||||
<!-- end custom-->
|
||||
{% endif %}
|
||||
<!-- checkbox -->
|
||||
{% if value["type"] == "check" %}
|
||||
<div data-checkbox-handler="{{ value['id'] }}"
|
||||
class="relative mb-7 md:mb-0 z-10 ">
|
||||
<label class="sr-only" for="{{ setting }}">{{ setting }}</label>
|
||||
<input id="{{ setting }}"
|
||||
name="{{ setting }}"
|
||||
data-default-method="{% if setting in ['AUTOCONF_MODE', 'SWARM_MODE', 'KUBERNETES_MODE'] %}mode{% else %}{{ global_config[setting]['method'] }}{% endif %}"
|
||||
data-default-value="{{ global_config[setting]['value'] }}"
|
||||
{% if setting in ['AUTOCONF_MODE', 'SWARM_MODE', 'KUBERNETES_MODE'] or global_config[setting]['method'] != 'ui' and global_config[setting]['method'] != 'default' %} disabled {% endif %}
|
||||
data-checked="{% if global_config[setting]['value'] == "yes" %}true{% else %}false{% endif %}"
|
||||
checked
|
||||
id="checkbox-{{ value['id'] }}"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
data-pattern="{{ value['regex']|safe }}"
|
||||
value="{{ global_config[setting]['value'] }}" />
|
||||
<svg data-checkbox-handler="{{ value['id'] }}"
|
||||
class="pointer-events-none absolute fill-white dark:fill-gray-300 left-0 top-0 translate-x-1 translate-y-2 h-3 w-3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512">
|
||||
<path class="pointer-events-none" d="M470.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L192 338.7 425.4 105.4c12.5-12.5 32.8-12.5 45.3 0z">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
{% endif %}
|
||||
<!-- end checkbox -->
|
||||
<!-- invalid feedback -->
|
||||
<div role="alert"
|
||||
aria-label="show when invalid input"
|
||||
class="hidden text-sm dark:text-red-500">
|
||||
{{ value['label'] }} is invalid and must match this pattern:
|
||||
{{ value['regex']|safe }}
|
||||
</div>
|
||||
<!--end invalid feedback-->
|
||||
</div>
|
||||
<!--end invalid feedback-->
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<!-- end plugin settings -->
|
||||
</div>
|
||||
<!-- end plugin settings not multiple -->
|
||||
{# get number of multiple groups for the plugin #}
|
||||
{% set multList = [] %}
|
||||
{% for setting, value in plugin["settings"].items() %}
|
||||
{% if current_endpoint
|
||||
== "global-config" and value['context'] == "global" and value['multiple'] and not value['multiple'] in multList or current_endpoint ==
|
||||
"services" and value['context'] == "multisite" and value['multiple'] and not value['multiple'] in multList %}
|
||||
{% if multList.append(value['multiple']) %}{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if multList|length > 0 %}
|
||||
<h5 class="transition duration-300 ease-in-out ml-2 font-bold text-[1.1rem] uppercase dark:text-white/90 mt-2 mb-0">
|
||||
multiple settings
|
||||
|
|
@ -265,9 +261,10 @@
|
|||
<div data-{{ current_endpoint }}-settings-multiple="{{ multiple }}_SCHEMA" class="bg-gray-50 dark:bg-slate-900/30 hidden w-full mb-4 mt-2 grid-cols-12 border dark:border-gray-700 rounded">
|
||||
{% for setting, value in plugin["settings"].items() %}
|
||||
{# render only setting that match the multiple id and context #}
|
||||
{% if current_endpoint
|
||||
== "global-config" and value['context'] == "global" and value['multiple'] == multiple or current_endpoint ==
|
||||
"services" and value['context'] == "multisite" and value['multiple'] == multiple %}
|
||||
{% if value['multiple'] == multiple and (
|
||||
current_endpoint == "global-config"
|
||||
or current_endpoint == "services" and value['context'] == "multisite"
|
||||
) %}
|
||||
<div data-setting-container="{{ setting }}_SCHEMA"
|
||||
class="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">
|
||||
|
|
@ -291,7 +288,7 @@
|
|||
</div>
|
||||
<!-- end title and info -->
|
||||
<!-- input -->
|
||||
{% if value["type"] != "select" and value["type"] != "check" %}
|
||||
{% if value["type"] not in ["select", "check"] %}
|
||||
<div class="relative flex items-center">
|
||||
<label class="sr-only" for="{{ setting }}_SCHEMA">{{ setting }}</label>
|
||||
<input data-default-value="{{ value['default'] }}"
|
||||
|
|
|
|||
19
src/ui/templates/settings_tabs_select.html
vendored
19
src/ui/templates/settings_tabs_select.html
vendored
|
|
@ -9,7 +9,8 @@
|
|||
{% if current_endpoint == "global-config" %}general{% endif %}
|
||||
</span>
|
||||
<!-- chevron -->
|
||||
<svg data-tab-select-dropdown-arrow class="transition-transform h-4 w-4 fill-primary dark:fill-gray-300"
|
||||
<svg data-tab-select-dropdown-arrow
|
||||
class="transition-transform h-4 w-4 fill-primary dark:fill-gray-300"
|
||||
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" />
|
||||
|
|
@ -24,14 +25,14 @@
|
|||
{% set first_el = "True" %}
|
||||
{% for plugin in plugins %}
|
||||
{% if current_endpoint == "services" and plugin["settings"]
|
||||
and check_settings(plugin["settings"], "multisite") or current_endpoint == "global-config" and plugin["settings"]
|
||||
and check_settings(plugin["settings"], "global") %}
|
||||
<button role="option"
|
||||
data-tab-select-handler="{{ plugin['id'] }}"
|
||||
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">{{ plugin['name'] }}</button>
|
||||
and check_settings(plugin["settings"], "multisite") or current_endpoint == "global-config" %}
|
||||
<button role="option"
|
||||
data-tab-select-handler="{{ plugin['id'] }}"
|
||||
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">
|
||||
{{ plugin['name'] }}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
|
|
|||
98
src/ui/templates/setup.html
vendored
98
src/ui/templates/setup.html
vendored
|
|
@ -123,7 +123,9 @@
|
|||
<h2 class="col-span-12 block text-left font-bold my-4 text-2xl">Account</h2>
|
||||
<!-- username inpt-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">Username<strong class="required-mark">*</strong></h5>
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
Username<strong class="required-mark">*</strong>
|
||||
</h5>
|
||||
<label class="sr-only" for="admin_username">Username</label>
|
||||
<input type="text"
|
||||
id="admin_username"
|
||||
|
|
@ -138,7 +140,9 @@
|
|||
<!-- end username inpt-->
|
||||
<!-- password inpt-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">Password<strong class="required-mark">*</strong></h5>
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
Password<strong class="required-mark">*</strong>
|
||||
</h5>
|
||||
<label class="sr-only" for="admin_password">Password</label>
|
||||
<input type="password"
|
||||
id="admin_password"
|
||||
|
|
@ -153,7 +157,9 @@
|
|||
<!-- end password inpt-->
|
||||
<!-- password inpt-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">Confirm Password<strong class="required-mark">*</strong></h5>
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
Confirm Password<strong class="required-mark">*</strong>
|
||||
</h5>
|
||||
<label class="sr-only" for="admin_password_check">Confirm Password</label>
|
||||
<input type="password"
|
||||
id="admin_password_check"
|
||||
|
|
@ -169,47 +175,51 @@
|
|||
<!-- end password inpt-->
|
||||
<!-- email inpt-->
|
||||
<div class="flex flex-col relative col-span-12 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base mb-1 transition duration-300 ease-in-out text-md font-bold m-0">Email</h5>
|
||||
<label class="sr-only" for="newsletter-email">email</label>
|
||||
<input type="email"
|
||||
id="newsletter-email"
|
||||
name="EMAIL"
|
||||
class="col-span-12 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-4 py-2 font-normal text-gray-700 transition-all placeholder:text-gray-500"
|
||||
placeholder="example@gmail.com"
|
||||
value=""/>
|
||||
</div>
|
||||
<!-- auto privacy policy-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0"> I've read and agree to the
|
||||
<a class="privacy-link"
|
||||
href="https://www.bunkerity.com/privacy-policy/?utm_campaign=self&utm_source=ui"
|
||||
target="_blank"
|
||||
rel="noopener">privacy policy</a></h5>
|
||||
<label class="sr-only" for="newsletter-check">privacy policy</label>
|
||||
<div data-checkbox-handler="newsletter-check"
|
||||
class="relative mb-7 md:mb-0 z-10">
|
||||
<input data-check
|
||||
type="checkbox"
|
||||
id="newsletter-check"
|
||||
name="newsletter-check"
|
||||
data-checked="false"
|
||||
class="checkbox"
|
||||
value="no" />
|
||||
<svg data-checkbox-handler="newsletter-check"
|
||||
class="pointer-events-none absolute fill-white left-0 top-0 translate-x-1 translate-y-2 h-3 w-3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512">
|
||||
<path class="pointer-events-none" d="M470.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L192 338.7 425.4 105.4c12.5-12.5 32.8-12.5 45.3 0z">
|
||||
</path>
|
||||
</svg>
|
||||
<h5 class="text-base mb-1 transition duration-300 ease-in-out text-md font-bold m-0">Email</h5>
|
||||
<label class="sr-only" for="newsletter-email">email</label>
|
||||
<input type="email"
|
||||
id="newsletter-email"
|
||||
name="EMAIL"
|
||||
class="col-span-12 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-4 py-2 font-normal text-gray-700 transition-all placeholder:text-gray-500"
|
||||
placeholder="example@gmail.com"
|
||||
value="" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- end auto privacy policy-->
|
||||
<!-- end email inpt-->
|
||||
<!-- auto privacy policy-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
I've read and agree to the
|
||||
<a class="privacy-link"
|
||||
href="https://www.bunkerity.com/privacy-policy/?utm_campaign=self&utm_source=ui"
|
||||
target="_blank"
|
||||
rel="noopener">privacy policy</a>
|
||||
</h5>
|
||||
<label class="sr-only" for="newsletter-check">privacy policy</label>
|
||||
<div data-checkbox-handler="newsletter-check"
|
||||
class="relative mb-7 md:mb-0 z-10">
|
||||
<input data-check
|
||||
type="checkbox"
|
||||
id="newsletter-check"
|
||||
name="newsletter-check"
|
||||
data-checked="false"
|
||||
class="checkbox"
|
||||
value="no" />
|
||||
<svg data-checkbox-handler="newsletter-check"
|
||||
class="pointer-events-none absolute fill-white left-0 top-0 translate-x-1 translate-y-2 h-3 w-3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512">
|
||||
<path class="pointer-events-none" d="M470.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L192 338.7 425.4 105.4c12.5-12.5 32.8-12.5 45.3 0z">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end auto privacy policy-->
|
||||
<!-- end email inpt-->
|
||||
<h2 class="col-span-12 block text-left font-bold mb-4 mt-2 text-2xl">Settings</h2>
|
||||
<!-- ui host-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">UI Host (REVERSE_PROXY_HOST)<strong class="required-mark">*</strong></h5>
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
UI Host (REVERSE_PROXY_HOST)<strong class="required-mark">*</strong>
|
||||
</h5>
|
||||
<label class="sr-only" for="ui_host">ui host</label>
|
||||
<input type="text"
|
||||
id="ui_host"
|
||||
|
|
@ -223,7 +233,9 @@
|
|||
<!-- end ui host-->
|
||||
<!-- ui url-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">UI URL (REVERSE_PROXY_URL)<strong class="required-mark">*</strong></h5>
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
UI URL (REVERSE_PROXY_URL)<strong class="required-mark">*</strong>
|
||||
</h5>
|
||||
<label class="sr-only" for="ui_url">ui url</label>
|
||||
<input type="text"
|
||||
id="ui_url"
|
||||
|
|
@ -237,7 +249,9 @@
|
|||
<!-- end ui url-->
|
||||
<!-- server name-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">Server name<strong class="required-mark">*</strong></h5>
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
Server name<strong class="required-mark">*</strong>
|
||||
</h5>
|
||||
<label class="sr-only" for="server_name">server name</label>
|
||||
<input type="text"
|
||||
id="server_name"
|
||||
|
|
|
|||
Loading…
Reference in a new issue