enhance templating + precommit

* create global info card block and set it pages
* create global filter card block and set it pages
* create global nomatch block and set it on pages
* add attribute_name jinja variable used for those new blocks
* fix multisite popover position
* fix filtering no match hidden / show element after updating list elements
This commit is contained in:
Jordan Blasenhauer 2024-04-21 19:12:13 +02:00
parent 2ab7161653
commit 2133baab81
15 changed files with 259 additions and 693 deletions

View file

@ -17,19 +17,19 @@ class ServiceModal {
"[data-services-tabs-select-header]",
]);
this.modalErrMsg = this.modal.querySelector(
"[data-services-modal-error-msg]"
"[data-services-modal-error-msg]",
);
this.modalCard = this.modal.querySelector("[data-services-modal-card]");
this.switchModeBtn = this.modal.querySelector(
"[data-toggle-settings-mode-btn]"
"[data-toggle-settings-mode-btn]",
);
//modal forms
this.formNewEdit = this.modal.querySelector("[data-services-modal-form]");
this.formDelete = this.modal.querySelector(
"[data-services-modal-form-delete]"
"[data-services-modal-form-delete]",
);
this.submitBtn = document.querySelector(
"button[data-services-modal-submit]"
"button[data-services-modal-submit]",
);
//container
this.container = document.querySelector("main");
@ -93,7 +93,7 @@ class ServiceModal {
this.switchModeBtn.addEventListener("click", () => {
const currMode = this.switchModeBtn.getAttribute(
"data-toggle-settings-mode-btn"
"data-toggle-settings-mode-btn",
);
const switchMode = currMode === "advanced" ? "simple" : "advanced";
@ -109,7 +109,7 @@ class ServiceModal {
) {
//set form info and right form
const [action, serviceName, isDraft, method] = this.getActionData(
e.target
e.target,
);
const oldServName = e.target
.closest("[data-services-service]")
@ -121,7 +121,7 @@ class ServiceModal {
oldServName,
this.formNewEdit,
isDraft,
method
method,
);
//get service data and parse it
//multiple type logic is launch at same time on relate class
@ -145,7 +145,7 @@ class ServiceModal {
) {
//set form info and right form
const [action, serviceName, isDraft, method] = this.getActionData(
e.target
e.target,
);
this.setForm(
action,
@ -153,7 +153,7 @@ class ServiceModal {
serviceName,
this.formNewEdit,
isDraft,
method
method,
);
//set default value with method default
//get service data and parse it
@ -185,7 +185,7 @@ class ServiceModal {
) {
//set form info and right form
const [action, serviceName, isDraft, method] = this.getActionData(
e.target
e.target,
);
this.setForm(
action,
@ -193,7 +193,7 @@ class ServiceModal {
serviceName,
this.formNewEdit,
isDraft,
method
method,
);
//set default value with method default
this.setSettingsDefault();
@ -217,7 +217,7 @@ class ServiceModal {
) {
//set form info and right form
const [action, serviceName, isDraft, method] = this.getActionData(
e.target
e.target,
);
this.setForm(
action,
@ -225,7 +225,7 @@ class ServiceModal {
serviceName,
this.formDelete,
isDraft,
method
method,
);
//show modal
this.openModal();
@ -246,7 +246,7 @@ class ServiceModal {
"delete-btn",
"valid-btn",
"edit-btn",
"info-btn"
"info-btn",
);
this.submitBtn.classList.add(btnType);
}
@ -308,15 +308,15 @@ class ServiceModal {
//click the custom select dropdown to update select value
select.parentElement
.querySelector(
`button[data-setting-select-dropdown-btn][value='${defaultVal}']`
`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"
)}]`
"data-setting-select-default",
)}]`,
);
this.setDisabledDefault(btnCustom, defaultMethod);
@ -389,9 +389,8 @@ class ServiceModal {
if (action === "delete") {
this.showDeleteForm();
formEl.querySelector(
`[data-services-modal-text]`
).textContent = `Are you sure you want to delete ${serviceName} ?`;
formEl.querySelector(`[data-services-modal-text]`).textContent =
`Are you sure you want to delete ${serviceName} ?`;
const nameInp = formEl.querySelector(`input[name="SERVER_NAME"]`);
nameInp.setAttribute("value", serviceName);
nameInp.value = serviceName;
@ -404,7 +403,7 @@ class ServiceModal {
disabledSaveCases() {
window.addEventListener("DOMContentLoaded", () => {
const serverNameInput = document.querySelector(
'input[name="SERVER_NAME"]'
'input[name="SERVER_NAME"]',
);
window.addEventListener("click", (e) => {
@ -441,7 +440,7 @@ class ServiceModal {
// button
this.switchModeBtn.setAttribute("data-toggle-settings-mode-btn", mode);
const switchEls = this.switchModeBtn.querySelectorAll(
"[data-toggle-settings-mode]"
"[data-toggle-settings-mode]",
);
switchEls.forEach((el) => {
el.getAttribute("data-toggle-settings-mode") === mode
@ -588,7 +587,7 @@ class ServiceModal {
if (inp.tagName === "SELECT") {
inp.parentElement
.querySelector(
`button[data-setting-select-dropdown-btn][value='${value}']`
`button[data-setting-select-dropdown-btn][value='${value}']`,
)
.click();
inp.setAttribute("data-method", method);
@ -702,7 +701,7 @@ class Multiple {
const attName = btn.getAttribute(`data-${this.prefix}-multiple-add`);
//get all multiple groups
const multipleEls = document.querySelectorAll(
`[data-${this.prefix}-settings-multiple*="${attName}"]`
`[data-${this.prefix}-settings-multiple*="${attName}"]`,
);
//case no schema
if (multipleEls.length <= 0) return;
@ -714,7 +713,7 @@ class Multiple {
//and keep the highest num
multipleEls.forEach((container) => {
const ctnrName = container.getAttribute(
"data-services-settings-multiple"
"data-services-settings-multiple",
);
const num = this.getSuffixNumOrFalse(ctnrName);
if (!isNaN(num) && num > topNum) topNum = num;
@ -725,7 +724,7 @@ class Multiple {
const setNum = +currNum === 0 ? `` : `_${currNum}`;
//the default (schema) group is the last group
const schema = document.querySelector(
`[data-${this.prefix}-settings-multiple="${attName}_SCHEMA"]`
`[data-${this.prefix}-settings-multiple="${attName}_SCHEMA"]`,
);
//clone schema to create a group with new num
const schemaClone = schema.cloneNode(true);
@ -765,12 +764,12 @@ class Multiple {
// We are not removing it really, just hiding it and update values to default
// By setting default value, group will be send to server and delete (because a setting with default value is useless to keep)
const multContainer = e.target.closest(
`[data-${this.prefix}-settings-multiple]`
`[data-${this.prefix}-settings-multiple]`,
);
multContainer.classList.add("hidden-multiple");
// get setting container
const settings = multContainer.querySelectorAll(
`[data-setting-container]`
`[data-setting-container]`,
);
settings.forEach((setting) => {
// for regular input
@ -797,7 +796,7 @@ class Multiple {
// for select
try {
const selects = setting.querySelectorAll(
"button[data-setting-select]"
"button[data-setting-select]",
);
selects.forEach((select) => {
const defaultVal = select.getAttribute("data-default") || "";
@ -808,8 +807,8 @@ class Multiple {
defaultVal;
const dropdown = document.querySelector(
`[data-setting-select-dropdown="${select.getAttribute(
"data-setting-select"
)}"]`
"data-setting-select",
)}"]`,
);
dropdown.querySelector(`button[value=${defaultVal}]`).click();
});
@ -834,13 +833,13 @@ class Multiple {
? name.replace(`_${splitName[splitName.length - 1]}`, "").trim()
: name.trim();
const relateSetting = document.querySelector(
`[data-setting-container=${nameSuffixLess}_SCHEMA]`
`[data-setting-container=${nameSuffixLess}_SCHEMA]`,
);
const relateCtnr = relateSetting.closest(
"[data-services-settings-multiple]"
"[data-services-settings-multiple]",
);
const relateCtnrName = relateCtnr.getAttribute(
"data-services-settings-multiple"
"data-services-settings-multiple",
);
//then we sort the setting on the right container name by suffixe number
if (!(relateCtnrName in sortMultiples)) {
@ -858,7 +857,7 @@ class Multiple {
addOneMultGroup() {
const settings = document.querySelector("[data-services-modal-form]");
const multAddBtns = settings.querySelectorAll(
"[data-services-multiple-add]"
"[data-services-multiple-add]",
);
multAddBtns.forEach((btn) => {
//check if already one (SCHEMA exclude so length >= 2)
@ -873,7 +872,7 @@ class Multiple {
showMultByAtt(att) {
const multContainers = document.querySelectorAll(
`[data-services-settings-multiple^=${att}]`
`[data-services-settings-multiple^=${att}]`,
);
multContainers.forEach((container) => {
if (
@ -887,7 +886,7 @@ class Multiple {
toggleMultByAtt(att) {
const multContainers = document.querySelectorAll(
`[data-services-settings-multiple^=${att}]`
`[data-services-settings-multiple^=${att}]`,
);
multContainers.forEach((container) => {
if (
@ -903,7 +902,7 @@ class Multiple {
//get schema settings
const multiples = {};
const schemaSettings = document.querySelectorAll(
`[data-setting-container$="SCHEMA"]`
`[data-setting-container$="SCHEMA"]`,
);
// loop on every schema settings
schemaSettings.forEach((schema) => {
@ -929,11 +928,11 @@ class Multiple {
setMultipleToDOM(sortMultObj, setMethodUI = false) {
//we loop on each multiple that contains values to render to DOM
for (const [schemaCtnrName, multGroupBySuffix] of Object.entries(
sortMultObj
sortMultObj,
)) {
//we need to access the DOM schema container
const schemaCtnr = document.querySelector(
`[data-services-settings-multiple="${schemaCtnrName}"]`
`[data-services-settings-multiple="${schemaCtnrName}"]`,
);
//now we have to loop on each multiple settings group
for (const [suffix, settings] of Object.entries(multGroupBySuffix)) {
@ -949,14 +948,14 @@ class Multiple {
for (const [name, data] of Object.entries(settings)) {
//get setting container of clone container
const settingContainer = schemaCtnrClone.querySelector(
`[data-setting-container="${name}"]`
`[data-setting-container="${name}"]`,
);
//replace input info and disabled state
this.setSetting(
data["value"],
setMethodUI ? "ui" : data["method"],
data["global"],
settingContainer
settingContainer,
);
}
//send schema clone to DOM and show it
@ -971,7 +970,7 @@ class Multiple {
"data-services-settings-multiple",
schemaCtnrClone
.getAttribute("data-services-settings-multiple")
.replace("_SCHEMA", suffix)
.replace("_SCHEMA", suffix),
);
//rename title
@ -985,18 +984,18 @@ class Multiple {
//rename setting container
const settingCtnrs = schemaCtnrClone.querySelectorAll(
"[data-setting-container]"
"[data-setting-container]",
);
settingCtnrs.forEach((settingCtnr) => {
settingCtnr.setAttribute(
"data-setting-container",
settingCtnr
.getAttribute("data-setting-container")
.replace("_SCHEMA", suffix)
.replace("_SCHEMA", suffix),
);
settingCtnr.setAttribute(
"id",
settingCtnr.getAttribute("id").replace("_SCHEMA", suffix)
settingCtnr.getAttribute("id").replace("_SCHEMA", suffix),
);
});
@ -1005,7 +1004,7 @@ class Multiple {
labelEls.forEach((label) => {
label.setAttribute(
"for",
label.getAttribute("for").replace("_SCHEMA", suffix)
label.getAttribute("for").replace("_SCHEMA", suffix),
);
});
@ -1014,19 +1013,19 @@ class Multiple {
popoverBtns.forEach((popoverBtn) => {
popoverBtn.setAttribute(
"data-popover-btn",
popoverBtn.getAttribute("data-popover-btn").replace("_SCHEMA", suffix)
popoverBtn.getAttribute("data-popover-btn").replace("_SCHEMA", suffix),
);
});
const popoverContents = schemaCtnrClone.querySelectorAll(
"[data-popover-content]"
"[data-popover-content]",
);
popoverContents.forEach((popoverContent) => {
popoverContent.setAttribute(
"data-popover-content",
popoverContent
.getAttribute("data-popover-content")
.replace("_SCHEMA", suffix)
.replace("_SCHEMA", suffix),
);
});
@ -1035,7 +1034,7 @@ class Multiple {
invalidEls.forEach((invalidEl) => {
invalidEl.setAttribute(
"data-invalid",
invalidEl.getAttribute("data-invalid").replace("_SCHEMA", suffix)
invalidEl.getAttribute("data-invalid").replace("_SCHEMA", suffix),
);
});
@ -1113,15 +1112,15 @@ class Multiple {
//click the custom select dropdown btn value to update select value
select.parentElement
.querySelector(
`button[data-setting-select-dropdown-btn][value='${defaultVal}']`
`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"
)}]`
"data-setting-select-default",
)}]`,
);
this.setDisabledMultServ(btnCustom, method, global);
@ -1157,10 +1156,10 @@ class Multiple {
selects.forEach((select) => {
const method = select.getAttribute("data-default-method");
const name = select.getAttribute(
"data-services-setting-select-default"
"data-services-setting-select-default",
);
const selDOM = document.querySelector(
`button[data-services-setting-select='${name}']`
`button[data-services-setting-select='${name}']`,
);
if (method === "ui" || method === "default") {
selDOM.removeAttribute("disabled", "");
@ -1195,7 +1194,7 @@ class Multiple {
hiddenIfNoMultiples() {
//hide multiple btn if no multiple exist on a plugin
const multiples = document.querySelectorAll(
`[data-${this.prefix}-settings-multiple]`
`[data-${this.prefix}-settings-multiple]`,
);
multiples.forEach((container) => {
if (container.querySelectorAll(`[data-setting-container]`).length <= 0)
@ -1207,7 +1206,7 @@ class Multiple {
removePrevMultiples() {
const multiPlugins = document.querySelectorAll(
`[data-${this.prefix}-settings-multiple]`
`[data-${this.prefix}-settings-multiple]`,
);
multiPlugins.forEach((multiGrp) => {
if (
@ -1278,7 +1277,7 @@ class Dropdown {
const btn = e.target.closest("button");
const btnValue = btn.getAttribute("value");
const btnSetting = btn.getAttribute(
`data-${this.prefix}-setting-select-dropdown-btn`
`data-${this.prefix}-setting-select-dropdown-btn`,
);
//stop if same value to avoid new fetching
const isSameVal = this.isSameValue(btnSetting, btnValue);
@ -1304,7 +1303,7 @@ class Dropdown {
closeAllDrop() {
const drops = document.querySelectorAll(
`[data-${this.prefix}-setting-select-dropdown]`
`[data-${this.prefix}-setting-select-dropdown]`,
);
drops.forEach((drop) => {
drop.classList.add("hidden");
@ -1312,8 +1311,8 @@ class Dropdown {
document
.querySelector(
`svg[data-${this.prefix}-setting-select="${drop.getAttribute(
`data-${this.prefix}-setting-select-dropdown`
)}"]`
`data-${this.prefix}-setting-select-dropdown`,
)}"]`,
)
.classList.remove("rotate-180");
});
@ -1321,7 +1320,7 @@ class Dropdown {
isSameValue(btnSetting, value) {
const selectCustom = document.querySelector(
`[data-${this.prefix}-setting-select-text="${btnSetting}"]`
`[data-${this.prefix}-setting-select-text="${btnSetting}"]`,
);
const currVal = selectCustom.textContent;
return currVal === value ? true : false;
@ -1329,30 +1328,30 @@ class Dropdown {
setSelectNewValue(btnSetting, value) {
const selectCustom = document.querySelector(
`[data-${this.prefix}-setting-select="${btnSetting}"]`
`[data-${this.prefix}-setting-select="${btnSetting}"]`,
);
selectCustom.querySelector(
`[data-${this.prefix}-setting-select-text]`
`[data-${this.prefix}-setting-select-text]`,
).textContent = value;
}
hideDropdown(btnSetting) {
//hide dropdown
const dropdownEl = document.querySelector(
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`,
);
dropdownEl.classList.add("hidden");
dropdownEl.classList.remove("flex");
//svg effect
const dropdownChevron = document.querySelector(
`svg[data-${this.prefix}-setting-select="${btnSetting}"]`
`svg[data-${this.prefix}-setting-select="${btnSetting}"]`,
);
dropdownChevron.classList.remove("rotate-180");
}
changeDropBtnStyle(btnSetting, selectedBtn) {
const dropdownEl = document.querySelector(
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`,
);
//reset dropdown btns
const btnEls = dropdownEl.querySelectorAll("button");
@ -1362,7 +1361,7 @@ class Dropdown {
"bg-primary",
"dark:bg-primary",
"text-gray-300",
"text-gray-300"
"text-gray-300",
);
btn.classList.add("bg-white", "dark:bg-slate-700", "text-gray-700");
});
@ -1370,7 +1369,7 @@ class Dropdown {
selectedBtn.classList.remove(
"bg-white",
"dark:bg-slate-700",
"text-gray-700"
"text-gray-700",
);
selectedBtn.classList.add("dark:bg-primary", "bg-primary", "text-gray-300");
}
@ -1381,10 +1380,10 @@ class Dropdown {
.getAttribute(`data-${this.prefix}-setting-select`);
//toggle dropdown
const dropdownEl = document.querySelector(
`[data-${this.prefix}-setting-select-dropdown="${attribute}"]`
`[data-${this.prefix}-setting-select-dropdown="${attribute}"]`,
);
const dropdownChevron = document.querySelector(
`svg[data-${this.prefix}-setting-select="${attribute}"]`
`svg[data-${this.prefix}-setting-select="${attribute}"]`,
);
dropdownEl.classList.toggle("hidden");
dropdownEl.classList.toggle("flex");
@ -1440,7 +1439,7 @@ class Filter {
setTimeout(() => {
const value = document
.querySelector(
`[data-${this.prefix}-setting-select-text="state"]`
`[data-${this.prefix}-setting-select-text="state"]`,
)
.textContent.trim()
.toLowerCase();
@ -1464,7 +1463,7 @@ class Filter {
setTimeout(() => {
const value = document
.querySelector(
`[data-${this.prefix}-setting-select-text="method"]`
`[data-${this.prefix}-setting-select-text="method"]`,
)
.textContent.trim()
.toLowerCase();
@ -1541,7 +1540,7 @@ const setDropdown = new Dropdown();
const setFilter = new Filter();
const setTabsSelect = new TabsSelect(
document.querySelector("[data-services-tabs-select]"),
document.querySelector("[data-services-modal-form]")
document.querySelector("[data-services-modal-form]"),
);
const setPopover = new Popover();
@ -1552,7 +1551,7 @@ const setFilterGlobal = new FilterSettings(
"settings-filter",
document.querySelector("[data-services-tabs-select]"),
document.querySelector("[data-services-modal-form]"),
"services"
"services",
);
const setMultiple = new Multiple("services");
@ -1564,19 +1563,19 @@ const checkServiceModalKeyword = new CheckNoMatchFilter(
.querySelector("[data-services-modal-form]")
.querySelectorAll("[data-plugin-item]"),
document.querySelector("[data-services-modal-form]"),
document.querySelector("[data-services-nomatch]")
document.querySelector("[data-services-nomatch]"),
);
const checkServiceModalSelect = new CheckNoMatchFilter(
document.querySelectorAll(
"button[data-services-setting-select-dropdown-btn]"
"button[data-services-setting-select-dropdown-btn]",
),
"select",
document
.querySelector("[data-services-modal-form]")
.querySelectorAll("[data-plugin-item]"),
document.querySelector("[data-services-modal-form]"),
document.querySelector("[data-services-nomatch]")
document.querySelector("[data-services-nomatch]"),
);
try {
@ -1585,16 +1584,16 @@ try {
"input",
document.querySelectorAll("[data-services-card]"),
false,
document.querySelector("[data-services-nomatch-card]")
document.querySelector("[data-services-nomatch-card]"),
);
const checkServiceCardSelect = new CheckNoMatchFilter(
document.querySelectorAll(
"button[data-services-setting-select-dropdown-btn]"
"button[data-services-setting-select-dropdown-btn]",
),
"select",
document.querySelectorAll("[data-services-card]"),
false,
document.querySelector("[data-services-nomatch-card]")
document.querySelector("[data-services-nomatch-card]"),
);
} catch (e) {}

View file

@ -10,6 +10,8 @@
{% if terms.append(ban["term"]) %}{% endif %}
{% endif %}
{% endfor %}
{% set attribute_name = "bans" %}
<!-- actions -->
<div class="col-span-12 relative flex justify-center min-w-0 break-words rounded-2xl bg-clip-border">
<button data-add-ban
@ -72,94 +74,17 @@
"values": terms
}
] %}
<div data-bans-filter
class="{% if bans|length == 0 %}hidden{% endif %} h-fit col-span-12 md:col-span-8 2xl:col-span-6 3xl:col-span-5 p-4 relative flex flex-col min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
<h5 class="mb-2 font-bold dark:text-white/90">FILTER</h5>
<div class="mx-2 grid grid-cols-12 gap-x-4 gap-y-2">
{% for filter in filters %}
{% if filter['type'] == 'input' %}
<!-- search inpt-->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<label for="{{ filter['id'] }}" class="sr-only">{{ filter['label'] }}</label>
<input type="text"
id="{{ filter['id'] }}"
name="{{ filter['id'] }}"
class="dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-3 py-1 font-normal text-gray-700 transition-all placeholder:text-gray-500"
placeholder="{{ filter['placeholder'] }}"
pattern="{{ filter['pattern'] }}"
required />
</div>
<!-- end search inpt-->
{% endif %}
{% if filter['type'] == 'select' %}
<!-- select -->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<button aria-controls="filter-{{ filter['id'] }}"
data-bans-setting-select="{{ filter['id'] }}"
class="disabled:opacity-75 dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 duration-300 ease-in-out dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 focus:border-green-500 flex justify-between align-middle items-center text-left text-sm leading-5.6 ease w-full rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 py-1 md:px-3 font-normal text-gray-700 transition-all placeholder:text-gray-500">
<span aria-description="current filter state value"
id="bans-{{ filter['id'] }}"
data-name="bans-{{ filter['id'] }}"
data-bans-setting-select-text="{{ filter['id'] }}">{{ filter['value'] }}</span>
<!-- chevron -->
<svg data-bans-setting-select="{{ filter['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>
</button>
<!-- end chevron -->
<!-- dropdown-->
<div id="filter-{{ filter['id'] }}"
role="listbox"
data-bans-setting-select-dropdown="{{ filter['id'] }}"
class="mt-1 hidden z-100 absolute flex-col w-full translate-y-16 max-h-[350px] overflow-hidden overflow-y-auto">
{% for value in filter['values'] %}
<button role="option"
data-bans-setting-select-dropdown-btn="{{ filter['id'] }}"
value="{{ value }}"
class="{% if loop.first %}dark:bg-primary bg-primary text-gray-300 border-t rounded-t {% else %} bg-white dark:bg-slate-700 {% endif %} {% if loop.last %}rounded-b{% endif %} border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300">
{{ value }}
</button>
{% endfor %}
</div>
<!-- end dropdown-->
</div>
<!-- end select -->
{% endif %}
{% endfor %}
</div>
</div>
<!-- end filter -->
<div data-bans-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">
<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 bans match</h5>
</div>
</div>
<div class="{% if bans|length == 0 %}hidden{% endif %} overflow-auto w-full 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">
{% include "card_filter.html" %}
{% include "filter_nomatch.html" %}
<div data-{{attribute_name}}-list-container class="{% if bans|length == 0 %}hidden{% endif %} overflow-auto w-full 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="mx-2 font-bold dark:text-white/90 mx-2">BANS LIST</h5>
</div>
<div data-bans-list-container
<div
class="w-full overflow-auto grid grid-cols-12 col-span-12 p-4 relative">
<div class=" max-h-100 sm:max-h-125 col-span-12 overflow-y-auto overflow-x-auto">
<div data-bans-bans-list>
<div data-{{attribute_name}}-bans-list>
<!-- list container-->
{% set bans_headers = [
{
@ -200,12 +125,12 @@
{% endfor %}
<!-- end header-->
<!-- list -->
<ul class="col-span-12 w-full" data-bans-list>
<ul class="col-span-12 w-full" data-{{attribute_name}}-list>
{% for ban in bans %}
<li data-bans-item
data-bans-list-item="{{ ban }}"
<li data-{{attribute_name}}-item
data-{{attribute_name}}-list-item="{{ ban }}"
class="items-center grid grid-cols-12 border-b border-gray-300 py-2.5">
<div data-bans-ban-select
<div data-{{attribute_name}}-ban-select
data-checkbox-handler="ban-item-{{ loop.index }}"
class="relative mb-7 md:mb-0 z-10 ml-2">
<label class="sr-only" for="ban-item-{{ loop.index }}">Ban ip {{ loop.index }}</label>
@ -227,16 +152,16 @@
</svg>
</div>
<p class="dark:text-gray-400 text-sm col-span-2 m-0 my-1"
data-bans-ip="{{ ban['ip'] }}">{{ ban['ip'] }}</p>
data-{{attribute_name}}-ip="{{ ban['ip'] }}">{{ ban['ip'] }}</p>
<p class="dark:text-gray-400 text-sm col-span-2 m-0 my-1"
data-bans-reason="{{ ban['reason'] }}">{{ ban['reason'] }}</p>
data-{{attribute_name}}-reason="{{ ban['reason'] }}">{{ ban['reason'] }}</p>
<p class="dark:text-gray-400 text-sm col-span-2 m-0 my-1"
data-bans-ban_start="{{ ban['ban_start'] }}">{{ ban['ban_start'] }}</p>
data-{{attribute_name}}-ban_start="{{ ban['ban_start'] }}">{{ ban['ban_start'] }}</p>
<p class="dark:text-gray-400 text-sm col-span-2 m-0 my-1"
data-bans-ban_end="{{ ban['ban_end'] }}">{{ ban['ban_end'] }}</p>
data-{{attribute_name}}-ban_end="{{ ban['ban_end'] }}">{{ ban['ban_end'] }}</p>
<p class="dark:text-gray-400 text-sm col-span-3 m-0 my-1"
data-bans-remain="{{ ban['remain'] }}">{{ ban['remain'] }}</p>
<p class="hidden" data-bans-term="{{ ban['term'] }}">{{ ban['term'] }}</p>
data-{{attribute_name}}-remain="{{ ban['remain'] }}">{{ ban['remain'] }}</p>
<p class="hidden" data-{{attribute_name}}-term="{{ ban['term'] }}">{{ ban['term'] }}</p>
</li>
{% endfor %}
</ul>

65
src/ui/templates/card_filter.html vendored Normal file
View file

@ -0,0 +1,65 @@
<div data-{{attribute_name}}-filter
class="h-fit col-span-12 md:col-span-8 2xl:col-span-6 3xl:col-span-4 p-4 relative flex flex-col min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
<h5 class="mb-2 font-bold dark:text-white/90">FILTER</h5>
<div class="mx-2 grid grid-cols-12 gap-4">
{% for filter in filters %}
{% if filter['type'] == 'input' %}
<!-- search inpt-->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<label for="{{ filter['id'] }}" class="sr-only">{{ filter['label'] }}</label>
<input type="text"
id="{{ filter['id'] }}"
name="{{ filter['id'] }}"
class="dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-3 py-1 font-normal text-gray-700 transition-all placeholder:text-gray-500"
placeholder="{{ filter['placeholder'] }}"
pattern="{{ filter['pattern'] }}"
required />
</div>
<!-- end search inpt-->
{% endif %}
{% if filter['type'] == 'select' %}
<!-- select -->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<button aria-controls="filter-{{ filter['id'] }}"
data-{{attribute_name}}-setting-select="{{ filter['id'] }}"
class="disabled:opacity-75 dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 duration-300 ease-in-out dark:opacity-90 dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 focus:border-green-500 flex justify-between align-middle items-center text-left text-sm leading-5.6 ease w-full rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 py-1 md:px-3 font-normal text-gray-700 transition-all placeholder:text-gray-500">
<span aria-description="current filter state value"
id="services-{{ filter['id'] }}"
data-name="services-{{ filter['id'] }}"
data-{{attribute_name}}-setting-select-text="{{ filter['id'] }}">{{ filter['value'] }}</span>
<!-- chevron -->
<svg data-{{attribute_name}}-setting-select="{{ filter['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>
</button>
<!-- end chevron -->
<!-- dropdown-->
<div id="filter-{{ filter['id'] }}"
role="listbox"
data-{{attribute_name}}-setting-select-dropdown="{{ filter['id'] }}"
class="mt-1 hidden z-100 absolute flex-col w-full translate-y-16 max-h-[350px] overflow-hidden overflow-y-auto">
{% for value in filter['values'] %}
<button role="option"
data-{{attribute_name}}-setting-select-dropdown-btn="{{ filter['id'] }}"
value="{{ value }}"
class="{% if loop.first %}dark:bg-primary bg-primary text-gray-300 border-t rounded-t {% else %} bg-white dark:bg-slate-700 {% endif %} {% if loop.last %}rounded-b{% endif %} border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300">
{{ value }}
</button>
{% endfor %}
</div>
<!-- end dropdown-->
</div>
<!-- end select -->
{% endif %}
{% endfor %}
</div>
</div>

View file

@ -12,4 +12,4 @@
{% endfor %}
</div>
</div>
{% endif %}
{% endif %}

View file

@ -1,5 +1,7 @@
{% extends "base.html" %}
{% block content %}
{% set attribute_name = "configs" %}
{% set infos = [
{
"id": "total-conf",
@ -12,6 +14,7 @@
"data": "unknown"
}
] %}
{% include "card_info.html" %}
<!-- end info -->
<!-- filter -->
@ -36,72 +39,9 @@
"true"
]
}
] %}
<div data-configs-filter
class="h-fit col-span-12 md:col-span-8 lg:col-span-5 2xl:col-span-4 3xl:col-span-3 p-4 relative flex flex-col min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
<h5 class="mb-2 font-bold dark:text-white/90">FILTER</h5>
<div class="mx-2 grid grid-cols-12 gap-x-4 gap-y-2">
{% for filter in filters %}
{% if filter['type'] == 'input' %}
<!-- search inpt-->
<div class="flex flex-col relative col-span-12">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<label for="{{ filter['id'] }}" class="sr-only">{{ filter['label'] }}</label>
<input type="text"
id="{{ filter['id'] }}"
name="{{ filter['id'] }}"
class="dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-3 py-1 font-normal text-gray-700 transition-all placeholder:text-gray-500"
placeholder="{{ filter['placeholder'] }}"
pattern="{{ filter['pattern'] }}"
required />
</div>
<!-- end search inpt-->
{% endif %}
{% if filter['type'] == 'select' %}
<!-- select -->
<div class="flex flex-col relative col-span-12">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<button aria-controls="filter-{{ filter['id'] }}"
data-configs-setting-select="{{ filter['id'] }}"
class="disabled:opacity-75 dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 duration-300 ease-in-out dark:opacity-90 dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 focus:border-green-500 flex justify-between align-middle items-center text-left text-sm leading-5.6 ease w-full rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 py-1 md:px-3 font-normal text-gray-700 transition-all placeholder:text-gray-500">
<span aria-description="current filter state value"
id="configs{{ filter['id'] }}"
data-name="configs{{ filter['id'] }}"
data-configs-setting-select-text="{{ filter['id'] }}">{{ filter['value'] }}</span>
<!-- chevron -->
<svg data-configs-setting-select="{{ filter['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>
</button>
<!-- end chevron -->
<!-- dropdown-->
<div id="filter-{{ filter['id'] }}"
role="listbox"
data-configs-setting-select-dropdown="{{ filter['id'] }}"
class="mt-1 hidden z-100 absolute flex-col w-full translate-y-16 max-h-[350px] overflow-hidden overflow-y-auto">
{% for value in filter['values'] %}
<button role="option"
data-configs-setting-select-dropdown-btn="{{ filter['id'] }}"
value="{{ value }}"
class="{% if loop.first %}dark:bg-primary bg-primary text-gray-300 border-t rounded-t {% else %} bg-white dark:bg-slate-700 {% endif %} {% if loop.last %}rounded-b{% endif %} border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300">
{{ value }}
</button>
{% endfor %}
</div>
<!-- end dropdown-->
</div>
<!-- end select -->
{% endif %}
{% endfor %}
</div>
</div>
]
%}
{% include "card_filter.html" %}
<!-- end filter -->
{% include "file_manager.html" %}
{% endblock content %}

14
src/ui/templates/filter_nomatch.html vendored Normal file
View file

@ -0,0 +1,14 @@
<div data-{{attribute_name}}-nomatch-card data-{{attribute_name}}-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">
<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 {{attribute_name.replace('-', ' ').replace('_', ' ')|lower}} match</h5>
</div>
</div>

View file

@ -1,5 +1,7 @@
{% extends "base.html" %}
{% block content %}
{% set attribute_name = "global-config" %}
<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">
@ -43,71 +45,8 @@
]
}
] %}
<div data-global-config-filter
class="h-fit p-4 col-span-12 md:col-span-6 3xl:col-span-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
<h5 class="mb-2 font-bold dark:text-white/90">FILTER</h5>
<div class="mx-2 grid grid-cols-12 gap-x-4 gap-y-2">
{% for filter in filters %}
{% if filter['type'] == 'input' %}
<!-- search inpt-->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<label for="{{ filter['id'] }}" class="sr-only">{{ filter['label'] }}</label>
<input type="text"
id="{{ filter['id'] }}"
name="{{ filter['id'] }}"
class="dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-3 py-1 font-normal text-gray-700 transition-all placeholder:text-gray-500"
placeholder="{{ filter['placeholder'] }}"
pattern="{{ filter['pattern'] }}"
required />
</div>
<!-- end search inpt-->
{% endif %}
{% if filter['type'] == 'select' %}
<!-- select -->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<button aria-controls="filter-{{ filter['id'] }}"
data-global-config-setting-select="{{ filter['id'] }}"
class="disabled:opacity-75 dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 duration-300 ease-in-out dark:opacity-90 dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 focus:border-green-500 flex justify-between align-middle items-center text-left text-sm leading-5.6 ease w-full rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 py-1 md:px-3 font-normal text-gray-700 transition-all placeholder:text-gray-500">
<span aria-description="current filter state value"
id="global-config-{{ filter['id'] }}"
data-name="global-config-{{ filter['id'] }}"
data-global-config-setting-select-text="{{ filter['id'] }}">{{ filter['value'] }}</span>
<!-- chevron -->
<svg data-global-config-setting-select="{{ filter['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>
</button>
<!-- end chevron -->
<!-- dropdown-->
<div id="filter-{{ filter['id'] }}"
role="listbox"
data-global-config-setting-select-dropdown="{{ filter['id'] }}"
class="mt-1 hidden z-100 absolute flex-col w-full translate-y-16 max-h-[350px] overflow-hidden overflow-y-auto">
{% for value in filter['values'] %}
<button role="option"
data-global-config-setting-select-dropdown-btn="{{ filter['id'] }}"
value="{{ value }}"
class="{% if loop.first %}dark:bg-primary bg-primary text-gray-300 border-t rounded-t {% else %} bg-white dark:bg-slate-700 {% endif %} {% if loop.last %}rounded-b{% endif %} border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300">
{{ value }}
</button>
{% endfor %}
</div>
<!-- end dropdown-->
</div>
<!-- end select -->
{% endif %}
{% endfor %}
</div>
</div>
{% include "card_filter.html" %}
<!-- end filter -->
<div data-global-config-plugins-container
class="col-span-12 gap-y-4 grid grid-cols-12">
@ -130,19 +69,6 @@
<!-- end submit -->
</form>
<!--end form global conf -->
<div data-global-config-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">
<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 settings match</h5>
</div>
</div>
{% include "filter_nomatch.html" %}
</div>
{% endblock content %}

View file

@ -1,5 +1,6 @@
{% extends "base.html" %}
{% block content %}
{% set attribute_name = "jobs" %}
{% set run_times = ["all"] %}
{% for job_name, value in jobs.items() %}
{% if value['every'] not in run_times %}
@ -54,91 +55,14 @@
"values": run_times
}
] %}
<div data-jobs-filter
class="h-fit col-span-12 md:col-span-8 2xl:col-span-6 3xl:col-span-5 p-4 relative flex flex-col min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
<h5 class="mb-2 font-bold dark:text-white/90">FILTER</h5>
<div class="mx-2 grid grid-cols-12 gap-x-4 gap-y-2">
{% for filter in filters %}
{% if filter['type'] == 'input' %}
<!-- search inpt-->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<label for="{{ filter['id'] }}" class="sr-only">{{ filter['label'] }}</label>
<input type="text"
id="{{ filter['id'] }}"
name="{{ filter['id'] }}"
class="dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-3 py-1 font-normal text-gray-700 transition-all placeholder:text-gray-500"
placeholder="{{ filter['placeholder'] }}"
pattern="{{ filter['pattern'] }}"
required />
</div>
<!-- end search inpt-->
{% endif %}
{% if filter['type'] == 'select' %}
<!-- select -->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<button aria-controls="filter-{{ filter['id'] }}"
data-jobs-setting-select="{{ filter['id'] }}"
class="disabled:opacity-75 dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 duration-300 ease-in-out dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 focus:border-green-500 flex justify-between align-middle items-center text-left text-sm leading-5.6 ease w-full rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 py-1 md:px-3 font-normal text-gray-700 transition-all placeholder:text-gray-500">
<span aria-description="current filter state value"
id="jobs-{{ filter['id'] }}"
data-name="jobs-{{ filter['id'] }}"
data-jobs-setting-select-text="{{ filter['id'] }}">{{ filter['value'] }}</span>
<!-- chevron -->
<svg data-jobs-setting-select="{{ filter['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>
</button>
<!-- end chevron -->
<!-- dropdown-->
<div id="filter-{{ filter['id'] }}"
role="listbox"
data-jobs-setting-select-dropdown="{{ filter['id'] }}"
class="mt-1 hidden z-100 absolute flex-col w-full translate-y-16 max-h-[350px] overflow-hidden overflow-y-auto">
{% for value in filter['values'] %}
<button role="option"
data-jobs-setting-select-dropdown-btn="{{ filter['id'] }}"
value="{{ value }}"
class="{% if loop.first %}dark:bg-primary bg-primary text-gray-300 border-t rounded-t {% else %} bg-white dark:bg-slate-700 {% endif %} {% if loop.last %}rounded-b{% endif %} border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300">
{{ value }}
</button>
{% endfor %}
</div>
<!-- end dropdown-->
</div>
<!-- end select -->
{% endif %}
{% endfor %}
</div>
</div>
<!-- end filter -->
<div data-jobs-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">
<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 jobs match</h5>
</div>
</div>
<div class="overflow-auto w-full 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">
{% include "card_filter.html" %}
{% include "filter_nomatch.html" %}
<div data-{{attribute_name}}-list-container class="overflow-auto w-full 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="mx-2 font-bold dark:text-white/90 mx-2">JOBS LIST</h5>
</div>
<div data-jobs-list-container
<div
class="relative min-w-[900px] w-full overflow-auto grid grid-cols-12 max-h-100 sm:max-h-125">
<div class="col-span-12">
@ -178,7 +102,7 @@
{% endfor %}
<!-- end header-->
<!-- list -->
<ul class="col-span-12 w-full" data-jobs-list>
<ul class="col-span-12 w-full" data-{{attribute_name}}-list>
{% for job_name, value in jobs.items() %}
<!-- job item-->
{% set jobs_data = [
@ -189,16 +113,16 @@
{"type" : "check", "filter_name" : "success", "value" : value['success'], "custom_class" : "col-span-1"},
{"type" : "select", "filter_name" : "success", "value" : value['success'], "custom_class" : "col-span-3"},
] %}
<li data-jobs-item
<li data-{{attribute_name}}-item
class="items-center grid grid-cols-12 border-b border-gray-300 py-2.5">
{% for data in jobs_data %}
{% if data['type'] == "text" %}
<p class="{{ data['custom_class'] }} dark:text-gray-400 text-sm m-0 my-1" data-jobs-{{ data['filter_name'] }}="{{ data['value'] }}">
<p class="{{ data['custom_class'] }} dark:text-gray-400 text-sm m-0 my-1" data-{{attribute_name}}-{{ data['filter_name'] }}="{{ data['value'] }}">
{{ data['value'] }}
</p>
{% endif %}
{% if data['type'] == "check" and data['value'] %}
<p class="{{ data['custom_class'] }} flex justify-center dark:text-gray-400 text-sm m-0 my-1" data-jobs-{{ data['filter_name'] }}="true">
<p class="{{ data['custom_class'] }} flex justify-center dark:text-gray-400 text-sm m-0 my-1" data-{{attribute_name}}-{{ data['filter_name'] }}="true">
<svg class="fill-green-500 h-5 w-5"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512">
@ -207,7 +131,7 @@
</p>
{% endif %}
{% if data['type'] == "check" and not data['value'] %}
<p class="{{ data['custom_class'] }} flex justify-center dark:text-gray-400 text-sm m-0 my-1" data-jobs-{{ data['filter_name'] }}="false">
<p class="{{ data['custom_class'] }} flex justify-center dark:text-gray-400 text-sm m-0 my-1" data-{{attribute_name}}-{{ data['filter_name'] }}="false">
<svg class="fill-red-500 h-5 w-5"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512">
@ -217,15 +141,15 @@
{% endif %}
{% if data['type'] == "select" %}
<div class="{{ data['custom_class'] }} relative dark:text-gray-400 text-sm m-0 my-1"
data-jobs-files>
data-{{attribute_name}}-files>
{% if value['cache'] %}
<button data-jobs-setting-select="{{ job_name }}"
<button data-{{attribute_name}}-setting-select="{{ job_name }}"
class="py-1 text-sm disabled:opacity-75 dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 duration-300 ease-in-out dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 focus:border-green-500 flex justify-between align-middle items-center text-left leading-6 ease w-full rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 md:px-3 font-normal text-gray-700 transition-all placeholder:text-gray-500">
<span id="jobs-{{ job_name }}"
data-name="jobs-{{ job_name }}"
data-jobs-setting-select-text="{{ job_name }}">files</span>
data-{{attribute_name}}-setting-select-text="{{ job_name }}">files</span>
<!-- chevron -->
<svg data-jobs-setting-select="{{ job_name }}"
<svg data-{{attribute_name}}-setting-select="{{ job_name }}"
class="transition-transform h-4 w-4 fill-gray-500"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512">
@ -234,13 +158,13 @@
</button>
<!-- end chevron -->
<!-- dropdown-->
<div data-jobs-setting-select-dropdown="{{ job_name }}"
<div data-{{attribute_name}}-setting-select-dropdown="{{ job_name }}"
class="hidden z-100 absolute h-full flex-col w-full translate-y-0.5">
{% for file in value['cache'] %}
<button data-jobs-plugin="{{ value['plugin_id'] }}"
data-jobs-download="{{ job_name }}"
data-jobs-file="{{ file['file_name'] }}"
data-jobs-setting-select-dropdown-btn="{{ job_name }}"
<button data-{{attribute_name}}-plugin="{{ value['plugin_id'] }}"
data-{{attribute_name}}-download="{{ job_name }}"
data-{{attribute_name}}-file="{{ file['file_name'] }}"
data-{{attribute_name}}-setting-select-dropdown-btn="{{ job_name }}"
value="files"
class="{% if loop.index == loop.length %}rounded-b-lg {% endif %}{% if loop.first %}rounded-t-lg{% endif %} border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300 bg-white dark:bg-slate-700 text-gray-700">
<span class="flex justify-start items-center">

View file

@ -1,5 +1,7 @@
{% extends "base.html" %}
{% block content %}
{% set attribute_name = "plugins" %}
{%
include "plugins_modal.html" %}
<!-- info -->
@ -12,7 +14,7 @@
{% include "card_info.html" %}
<!-- upload layout -->
<div data-plugins-upload
<div data-{{attribute_name}}-upload
class="p-4 col-span-12 md:col-span-7 2xl:col-span-4 grid grid-cols-12 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
<h5 class="col-span-12 mb-4 font-bold dark:text-gray-100">UPLOAD / RELOAD</h5>
<div class="mx-2 p-0 col-span-12 grid grid-cols-12">
@ -70,83 +72,20 @@
]
}
] %}
<div data-plugins-filter
class="h-fit p-4 col-span-12 md:col-span-6 2xl:col-span-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
<h5 class="mb-2 font-bold dark:text-white/90">FILTER</h5>
<div class="mx-2 grid grid-cols-12 gap-x-4 gap-y-2">
{% for filter in filters %}
{% if filter['type'] == 'input' %}
<!-- search inpt-->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<label for="{{ filter['id'] }}" class="sr-only">{{ filter['label'] }}</label>
<input type="text"
id="{{ filter['id'] }}"
name="{{ filter['id'] }}"
class="dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-3 py-1 font-normal text-gray-700 transition-all placeholder:text-gray-500"
placeholder="{{ filter['placeholder'] }}"
pattern="{{ filter['pattern'] }}"
required />
</div>
<!-- end search inpt-->
{% endif %}
{% if filter['type'] == 'select' %}
<!-- select -->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<button aria-controls="filter-{{ filter['id'] }}"
data-plugins-setting-select="{{ filter['id'] }}"
class="disabled:opacity-75 dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 duration-300 ease-in-out dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 focus:border-green-500 flex justify-between align-middle items-center text-left text-sm leading-5.6 ease w-full rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 py-1 md:px-3 font-normal text-gray-700 transition-all placeholder:text-gray-500">
<span aria-description="current filter state value"
id="plugins-{{ filter['id'] }}"
data-name="plugins-{{ filter['id'] }}"
data-plugins-setting-select-text="{{ filter['id'] }}">{{ filter['value'] }}</span>
<!-- chevron -->
<svg data-plugins-setting-select="{{ filter['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>
</button>
<!-- end chevron -->
<!-- dropdown-->
<div id="filter-{{ filter['id'] }}"
role="listbox"
data-plugins-setting-select-dropdown="{{ filter['id'] }}"
class="mt-1 hidden z-100 absolute flex-col w-full translate-y-16 max-h-[350px] overflow-hidden overflow-y-auto">
{% for value in filter['values'] %}
<button role="option"
data-plugins-setting-select-dropdown-btn="{{ filter['id'] }}"
value="{{ value }}"
class="{% if loop.first %}dark:bg-primary bg-primary text-gray-300 border-t rounded-t {% else %} bg-white dark:bg-slate-700 {% endif %} {% if loop.last %}rounded-b{% endif %} border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300">
{{ value }}
</button>
{% endfor %}
</div>
<!-- end dropdown-->
</div>
<!-- end select -->
{% endif %}
{% endfor %}
</div>
</div>
<!-- end filter -->
<div class="overflow-auto w-full 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">
{% include "card_filter.html" %}
{% include "filter_nomatch.html" %}
<div data-{{attribute_name}}-list-container class="overflow-auto w-full 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="mx-2 font-bold dark:text-white/90 mx-2">PLUGINS LIST</h5>
</div>
<div data-plugins-list-container
<div
class="min-h-[55vh] max-h-80 overflow-auto p-2 col-span-12 relative">
<div data-plugins-list class="grid grid-cols-12 gap-3">
<div data-{{attribute_name}}-list class="grid grid-cols-12 gap-3">
{% for plugin in plugins %}
<div data-plugins-type="{{ plugin['type'] }}"
<div data-{{attribute_name}}-type="{{ plugin['type'] }}"
class="py-3 min-h-12 relative col-span-12 sm:col-span-6 2xl:col-span-4 3xl:col-span-3 p-1 flex justify-between items-center transition rounded {% if plugin['type'] != 'pro' or plugin['type'] == 'pro' and is_pro_version %} bg-gray-100 hover:bg-gray-300 dark:bg-slate-700 dark:hover:bg-slate-800 {% else %} cursor-not-allowed bg-gray-300 dark:bg-gray-800 {% endif %}">
<p data-plugins-content
<p data-{{attribute_name}}-content
class="{% if plugin['type'] == 'pro' and not is_pro_version %} opacity-80 dark:opacity-60 {% endif %} ml-3 mr-2 break-words mb-0 transition duration-300 ease-in-out text-left text-sm md:text-base text-slate-700 dark:text-gray-200">
{{ plugin['name'] }}
</p>
@ -164,7 +103,7 @@
</a>
{% endif %}
{% if plugin['type'] == "external" %}
<button data-plugins-action="delete"
<button data-{{attribute_name}}-action="delete"
name="{{ plugin['id'] }}"
aria-label="delete plugin"
class="z-20 mx-2 inline-block font-bold text-left text-white uppercase align-middle transition-all cursor-pointer text-xs ease-in tracking-tight-rem hover:-translate-y-px">
@ -193,20 +132,6 @@
</div>
{% endfor %}
</div>
</div>
<div data-plugins-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">
<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 plugins match</h5>
</div>
</div>
</div>

View file

@ -1,5 +1,6 @@
{% extends "base.html" %}
{% block content %}
{% set attribute_name = "reports" %}
{% set methods = ["all"] %}
{% set codes = ["all"] %}
{% set reasons = ["all"] %}
@ -114,91 +115,14 @@
"values": reasons
}
] %}
<div data-reports-filter
class="h-fit col-span-12 md:col-span-8 2xl:col-span-6 3xl:col-span-5 p-4 relative flex flex-col min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
<h5 class="mb-2 font-bold dark:text-white/90">FILTER</h5>
<div class="mx-2 grid grid-cols-12 gap-x-4 gap-y-2">
{% for filter in filters %}
{% if filter['type'] == 'input' %}
<!-- search inpt-->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<label for="{{ filter['id'] }}" class="sr-only">{{ filter['label'] }}</label>
<input type="text"
id="{{ filter['id'] }}"
name="{{ filter['id'] }}"
class="dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-3 py-1 font-normal text-gray-700 transition-all placeholder:text-gray-500"
placeholder="{{ filter['placeholder'] }}"
pattern="{{ filter['pattern'] }}"
required />
</div>
<!-- end search inpt-->
{% endif %}
{% if filter['type'] == 'select' %}
<!-- select -->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<button aria-controls="filter-{{ filter['id'] }}"
data-reports-setting-select="{{ filter['id'] }}"
class="disabled:opacity-75 dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 duration-300 ease-in-out dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 focus:border-green-500 flex justify-between align-middle items-center text-left text-sm leading-5.6 ease w-full rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 py-1 md:px-3 font-normal text-gray-700 transition-all placeholder:text-gray-500">
<span aria-description="current filter state value"
id="reports-{{ filter['id'] }}"
data-name="reports-{{ filter['id'] }}"
data-reports-setting-select-text="{{ filter['id'] }}">{{ filter['value'] }}</span>
<!-- chevron -->
<svg data-reports-setting-select="{{ filter['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>
</button>
<!-- end chevron -->
<!-- dropdown-->
<div id="filter-{{ filter['id'] }}"
role="listbox"
data-reports-setting-select-dropdown="{{ filter['id'] }}"
class="mt-1 hidden z-100 absolute flex-col w-full translate-y-16 max-h-[350px] overflow-hidden overflow-y-auto">
{% for value in filter['values'] %}
<button role="option"
data-reports-setting-select-dropdown-btn="{{ filter['id'] }}"
value="{{ value }}"
class="{% if loop.first %}dark:bg-primary bg-primary text-gray-300 border-t rounded-t {% else %} bg-white dark:bg-slate-700 {% endif %} {% if loop.last %}rounded-b{% endif %} border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300">
{{ value }}
</button>
{% endfor %}
</div>
<!-- end dropdown-->
</div>
<!-- end select -->
{% endif %}
{% endfor %}
</div>
</div>
<!-- end filter -->
<div data-reports-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">
<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 reports match</h5>
</div>
</div>
<div class="overflow-auto w-full 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">
{% include "card_filter.html" %}
{% include "filter_nomatch.html" %}
<div data-{{attribute_name}}-list-container class="overflow-auto w-full 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="mx-2 font-bold dark:text-white/90 mx-2">REPORTING LIST</h5>
</div>
<div data-reports-list-container
<div
class="w-full overflow-auto grid grid-cols-12 col-span-12 p-4 relative">
<div class=" max-h-100 sm:max-h-125 col-span-12 overflow-y-auto overflow-x-auto">
<!-- list container-->
@ -249,28 +173,28 @@
{% endfor %}
<!-- end header-->
<!-- list -->
<ul class="col-span-12 w-full" data-reports-list>
<ul class="col-span-12 w-full" data-{{attribute_name}}-list>
{% for report in reports %}
<li data-reports-item
<li data-{{attribute_name}}-item
class="items-center grid grid-cols-12 border-b border-gray-300 py-2.5">
<p class="text-center flex justify-center dark:text-gray-400 text-sm col-span-1 m-0 my-1"
data-reports-date="{{ report['date'] }}">{{ report['date'] }}</p>
data-{{attribute_name}}-date="{{ report['date'] }}">{{ report['date'] }}</p>
<p class="flex justify-center dark:text-gray-400 text-sm col-span-1 m-0 my-1"
data-reports-ip="{{ report['ip'] }}">{{ report['ip'] }}</p>
data-{{attribute_name}}-ip="{{ report['ip'] }}">{{ report['ip'] }}</p>
<p class="flex justify-center dark:text-gray-400 text-sm col-span-1 m-0 my-1"
data-reports-country="{{ report['country'] }}">{{ report['country'] }}</p>
data-{{attribute_name}}-country="{{ report['country'] }}">{{ report['country'] }}</p>
<p class="flex justify-center dark:text-gray-400 text-sm col-span-1 m-0 my-1 "
data-reports-method="{{ report['method'] }}">{{ report["method"] }}</p>
data-{{attribute_name}}-method="{{ report['method'] }}">{{ report["method"] }}</p>
<p class="flex justify-center dark:text-gray-400 text-sm col-span-2 m-0 my-1"
data-reports-url="{{ report['url'] }}">{{ report['url'] }}</p>
data-{{attribute_name}}-url="{{ report['url'] }}">{{ report['url'] }}</p>
<p class="flex justify-center dark:text-gray-400 text-sm col-span-1 m-0 my-1 "
data-reports-status="{{ report['status'] }}">{{ report["status"] }}</p>
data-{{attribute_name}}-status="{{ report['status'] }}">{{ report["status"] }}</p>
<p class="flex justify-center dark:text-gray-400 text-sm col-span-2 m-0 my-1 "
data-reports-user_agent="{{ report['user_agent'] }}">{{ report["user_agent"] }}</p>
data-{{attribute_name}}-user_agent="{{ report['user_agent'] }}">{{ report["user_agent"] }}</p>
<p class="flex justify-center dark:text-gray-400 text-sm col-span-1 m-0 my-1 "
data-reports-reason="{{ report['reason'] }}">{{ report["reason"] }}</p>
data-{{attribute_name}}-reason="{{ report['reason'] }}">{{ report["reason"] }}</p>
<p class="flex justify-center dark:text-gray-400 text-sm col-span-2 m-0 my-1"
data-reports-data="{{ report['data'] }}">{{ report["data"] }}</p>
data-{{attribute_name}}-data="{{ report['data'] }}">{{ report["data"] }}</p>
</li>
{% endfor %}
</ul>

View file

@ -1,5 +1,6 @@
{% extends "base.html" %}
{% block content %}
{% set attribute_name = "services" %}
{% set methods = ["all"] %}
{% set states = ["all", "draft", "online"] %}
{% set draft_services = [] %}
@ -15,12 +16,12 @@
{% endif %}
{% endfor %}
<!-- actions -->
<div data-services-service
<div data-{{attribute_name}}-service
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-services-action="new"
data-services-name="service"
<button data-{{attribute_name}}-action="new"
data-{{attribute_name}}-name="service"
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">
<span class="mr-2">new service</span>
@ -72,85 +73,8 @@
"values": states
}
] %}
<div data-services-filter
class="h-fit col-span-12 md:col-span-8 2xl:col-span-6 3xl:col-span-4 p-4 relative flex flex-col min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
<h5 class="mb-2 font-bold dark:text-white/90">FILTER</h5>
<div class="mx-2 grid grid-cols-12 gap-4">
{% for filter in filters %}
{% if filter['type'] == 'input' %}
<!-- search inpt-->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<label for="{{ filter['id'] }}" class="sr-only">{{ filter['label'] }}</label>
<input type="text"
id="{{ filter['id'] }}"
name="{{ filter['id'] }}"
class="dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-3 py-1 font-normal text-gray-700 transition-all placeholder:text-gray-500"
placeholder="{{ filter['placeholder'] }}"
pattern="{{ filter['pattern'] }}"
required />
</div>
<!-- end search inpt-->
{% endif %}
{% if filter['type'] == 'select' %}
<!-- select -->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5 class="my-1 transition duration-300 ease-in-out text-sm sm:text-md font-bold m-0 dark:text-gray-200">
{{ filter['name'] }}
</h5>
<button aria-controls="filter-{{ filter['id'] }}"
data-services-setting-select="{{ filter['id'] }}"
class="disabled:opacity-75 dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 duration-300 ease-in-out dark:opacity-90 dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 focus:border-green-500 flex justify-between align-middle items-center text-left text-sm leading-5.6 ease w-full rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 py-1 md:px-3 font-normal text-gray-700 transition-all placeholder:text-gray-500">
<span aria-description="current filter state value"
id="services-{{ filter['id'] }}"
data-name="services-{{ filter['id'] }}"
data-services-setting-select-text="{{ filter['id'] }}">{{ filter['value'] }}</span>
<!-- chevron -->
<svg data-services-setting-select="{{ filter['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>
</button>
<!-- end chevron -->
<!-- dropdown-->
<div id="filter-{{ filter['id'] }}"
role="listbox"
data-services-setting-select-dropdown="{{ filter['id'] }}"
class="mt-1 hidden z-100 absolute flex-col w-full translate-y-16 max-h-[350px] overflow-hidden overflow-y-auto">
{% for value in filter['values'] %}
<button role="option"
data-services-setting-select-dropdown-btn="{{ filter['id'] }}"
value="{{ value }}"
class="{% if loop.first %}dark:bg-primary bg-primary text-gray-300 border-t rounded-t {% else %} bg-white dark:bg-slate-700 {% endif %} {% if loop.last %}rounded-b{% endif %} border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300">
{{ value }}
</button>
{% endfor %}
</div>
<!-- end dropdown-->
</div>
<!-- end select -->
{% endif %}
{% endfor %}
</div>
</div>
<div data-services-nomatch-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">
<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 services match</h5>
</div>
</div>
{% include "card_filter.html" %}
{% include "filter_nomatch.html" %}
</div>
{% endif %}
<!-- end service info and actions -->
@ -167,10 +91,10 @@
<!-- end filter -->
{% for service in services %}
{% set id_server_name = service["SERVER_NAME"]['value'].replace(".", "-") %}
<div data-services-card
data-services-service="{{ service['SERVER_NAME']['value'] }}"
<div data-{{attribute_name}}-card
data-{{attribute_name}}-service="{{ service['SERVER_NAME']['value'] }}"
class="dark:brightness-110 overflow-hidden hover:scale-102 transition col-span-12 lg:col-span-6 3xl:col-span-4 p-4 w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
<div data-services-settings
<div data-{{attribute_name}}-settings
class="hidden"
data-value="{{ service['settings'] }}"></div>
<div data-old-service-name
@ -183,13 +107,13 @@
class="hidden"
data-value="{{ service['SERVER_NAME']['method'] }}"></div>
<div class="flex justify-between items-start">
<h5 data-services-name="{{ service["SERVER_NAME"]['value'] }}"
<h5 data-{{attribute_name}}-name="{{ service["SERVER_NAME"]['value'] }}"
class="transition duration-300 ease-in-out text-center sm:text-left mb-1 font-bold dark:text-white/90">
{{ service["SERVER_NAME"]['value'] }}
</h5>
{% if service.get('IS_DRAFT', "no") == "yes" and service["SERVER_NAME"]['method'] in ["ui", "default"] %}
<button class="group relative">
<p data-services-state="draft"
<p data-{{attribute_name}}-state="draft"
class="dark:text-gray-300 -z-10 opacity-0 group-hover:z-10 group-hover:opacity-100 transition fixed bg-white dark:bg-slate-800 rounded right-12 px-1 py-0.5">
Draft
</p>
@ -202,7 +126,7 @@
</button>
{% else %}
<button class="group relative">
<p data-services-state="online"
<p data-{{attribute_name}}-state="online"
class="dark:text-gray-300 -z-10 opacity-0 group-hover:z-10 group-hover:opacity-100 transition fixed bg-white dark:bg-slate-800 rounded right-12 px-1 py-0.5">
Online
</p>
@ -216,7 +140,7 @@
</button>
{% endif %}
</div>
<h6 data-services-method="{{ service["SERVER_NAME"]['method'] }}"
<h6 data-{{attribute_name}}-method="{{ service["SERVER_NAME"]['method'] }}"
class="text-left sm:mb-2 font-semibold text-gray-600 dark:text-white/80">
{{ service["SERVER_NAME"]['method'] }}
</h6>
@ -341,9 +265,9 @@
{% endif %}
{% endif %}
{% for button in action_buttons %}
<button data-services-action="{{ button['name'] }}"
<button data-{{attribute_name}}-action="{{ button['name'] }}"
aria-label="{{ button['label'] }}"
data-services-name="{{ service['SERVER_NAME']['value'] }}"
data-{{attribute_name}}-name="{{ service['SERVER_NAME']['value'] }}"
class="dark:brightness-90 z-20 mx-1 bg-{{ button['color'] }} hover:bg-{{ button['color'] }}/80 focus:bg-{{ button['color'] }}/80 inline-block p-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer leading-normal text-xs ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 active:opacity-85 hover:shadow-md">
{% if button['name'] == "clone" %}
<svg xmlns="http://www.w3.org/2000/svg"

View file

@ -1,9 +1,9 @@
{% set steps = [
{
{
"name" : "STEP 1 - SERVER NAME",
"description" : "We need this to...",
"settings" : [
{"plugin_id" : "general", "setting_id": "SERVER_NAME", "label" : "What is your host ?", "levels" : {"standard" : "", "advanced" : "", "high" : ""} },
{"plugin_id" : "general", "setting_id": "SERVER_NAME", "label" : "What is your host ?", "levels" : {"standard" : "", "advanced" : "", "high" : ""} },
],
"configs": [
{"name": "my_config_1", "type": "modsec", "data": "..."},

View file

@ -26,4 +26,4 @@
</path>
</svg>
</div>
{% endif %}
{% endif %}

View file

@ -9,7 +9,7 @@
aria-label="show when invalid input"
class="block md:absolute hidden md:hidden text-sm text-red-500">
Invalid value
<span class="sr-only">
<span class="sr-only">
{{ inp_label }} is invalid and must match this pattern:
{{ inp_regex|safe }}
</span>

View file

@ -108,7 +108,7 @@
{% include "setting_input.html"%}
{% include "setting_select.html"%}
{% include "setting_checkbox.html"%}
{% include "setting_invalid.html"%}
{% include "setting_invalid.html"%}
</div>
{% endif %}
{% endfor %}