Merge pull request #451 from bunkerity/ui

UI
This commit is contained in:
Théophile Diot 2023-04-26 15:28:24 +02:00 committed by GitHub
commit 1530745a7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 3745 additions and 47 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
import { Checkbox, Select, Password } from "./utils/form.js";
import { Checkbox, Select, Password, DisabledPop } from "./utils/form.js";
import {
Popover,
Tabs,
@ -29,6 +29,7 @@ class Multiple {
const setCheckbox = new Checkbox();
const setSelect = new Select();
const setPassword = new Password();
const setDisabledPop = new DisabledPop();
const setPopover = new Popover("main", "global-config");
const setTabs = new Tabs("[global-config-tabs]", "global-config");

View File

@ -1,4 +1,4 @@
import { Checkbox, Select, Password } from "./utils/form.js";
import { Checkbox, Select, Password, DisabledPop } from "./utils/form.js";
import {
Popover,
Tabs,
@ -12,12 +12,16 @@ class ServiceModal {
this.modal = document.querySelector("[data-services-modal]");
this.modalTitle = this.modal.querySelector("[data-services-modal-title]");
this.modalTabs = this.modal.querySelector(["[data-services-tabs]"]);
this.modalTabsHeader = this.modal.querySelector(["[data-services-tabs-header]"]);
this.modalTabsHeader = this.modal.querySelector([
"[data-services-tabs-header]",
]);
this.modalCard = this.modal.querySelector("[data-services-modal-card]");
//modal forms
this.formNewEdit = this.modal.querySelector("[data-services-modal-form]");
this.formDelete = this.modal.querySelector("[data-services-modal-form-delete]");
this.formDelete = this.modal.querySelector(
"[data-services-modal-form-delete]"
);
//container
this.container = document.querySelector("main");
this.init();
@ -27,8 +31,12 @@ class ServiceModal {
//to update modal data on new button click
getActionAndServName(target) {
const action = target.closest("button").getAttribute("data-services-action");
const serviceName = target.closest("button").getAttribute("data-services-name");
const action = target
.closest("button")
.getAttribute("data-services-action");
const serviceName = target
.closest("button")
.getAttribute("data-services-name");
return [action, serviceName];
}
@ -37,7 +45,9 @@ class ServiceModal {
this.modal.addEventListener("click", (e) => {
//close
try {
if (e.target.closest("button").hasAttribute("data-services-modal-close")) {
if (
e.target.closest("button").hasAttribute("data-services-modal-close")
) {
this.closeModal();
}
} catch (err) {}
@ -47,7 +57,8 @@ class ServiceModal {
//edit action
try {
if (
e.target.closest("button").getAttribute("data-services-action") === "edit"
e.target.closest("button").getAttribute("data-services-action") ===
"edit"
) {
//set form info and right form
const [action, serviceName] = this.getActionAndServName(e.target);
@ -61,13 +72,15 @@ class ServiceModal {
const obj = JSON.parse(servicesSettings);
this.updateModalData(obj);
//show modal
this.changeSubmitBtnName("EDIT");
this.openModal();
}
} catch (err) {}
//new action
try {
if (
e.target.closest("button").getAttribute("data-services-action") === "new"
e.target.closest("button").getAttribute("data-services-action") ===
"new"
) {
//set form info and right form
const [action, serviceName] = this.getActionAndServName(e.target);
@ -77,9 +90,11 @@ class ServiceModal {
//server name is unset
const inpServName = document.querySelector("input#SERVER_NAME");
inpServName.getAttribute("value", "");
inpServName.removeAttribute("disabled", "");
inpServName.value = "";
//show modal
this.changeSubmitBtnName("CREATE");
this.openModal();
}
} catch (err) {}
@ -99,6 +114,13 @@ class ServiceModal {
});
}
changeSubmitBtnName(text) {
const submitBtn = document.querySelector(
"button[data-services-modal-submit]"
);
submitBtn.textContent = text;
}
setSettingsDefault() {
const inps = this.modal.querySelectorAll("input");
inps.forEach((inp) => {
@ -112,7 +134,7 @@ class ServiceModal {
return;
//for all other settings values
const defaultMethod = "default";
const defaultMethod = inp.getAttribute("data-default-method");
const defaultVal = inp.getAttribute("data-default-value") || "";
//SET VALUE
@ -139,7 +161,9 @@ class ServiceModal {
document
.querySelector(
`[data-setting-select=${select.getAttribute("data-setting-select-default")}]`
`[data-setting-select=${select.getAttribute(
"data-setting-select-default"
)}]`
)
.removeAttribute("disabled");
@ -331,7 +355,8 @@ class Multiple {
//edit button
try {
if (
e.target.closest("button").getAttribute("data-services-action") === "edit"
e.target.closest("button").getAttribute("data-services-action") ===
"edit"
) {
//remove all multiples
this.removePrevMultiples();
@ -351,7 +376,8 @@ class Multiple {
//new button
try {
if (
e.target.closest("button").getAttribute("data-services-action") === "new"
e.target.closest("button").getAttribute("data-services-action") ===
"new"
) {
this.removePrevMultiples();
this.addOneMultGroup();
@ -363,7 +389,9 @@ class Multiple {
//ADD BTN
try {
if (
e.target.closest("button").hasAttribute(`data-${this.prefix}-multiple-add`)
e.target
.closest("button")
.hasAttribute(`data-${this.prefix}-multiple-add`)
) {
//get plugin from btn
const btn = e.target.closest("button");
@ -453,7 +481,9 @@ class Multiple {
const relateSetting = document.querySelector(
`[data-setting-container=${nameSuffixLess}_SCHEMA]`
);
const relateCtnr = relateSetting.closest("[data-services-settings-multiple]");
const relateCtnr = relateSetting.closest(
"[data-services-settings-multiple]"
);
const relateCtnrName = relateCtnr.getAttribute(
"data-services-settings-multiple"
);
@ -472,11 +502,15 @@ class Multiple {
addOneMultGroup() {
const settings = document.querySelector("[data-services-modal-form]");
const multAddBtns = settings.querySelectorAll("[data-services-multiple-add]");
const multAddBtns = settings.querySelectorAll(
"[data-services-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-services-settings-multiple]").length >= 2)
if (
plugin.querySelectorAll("[data-services-settings-multiple]").length >= 2
)
return;
btn.click();
});
@ -488,7 +522,9 @@ class Multiple {
);
multContainers.forEach((container) => {
if (
!container.getAttribute("data-services-settings-multiple").includes("SCHEMA")
!container
.getAttribute("data-services-settings-multiple")
.includes("SCHEMA")
)
container.classList.remove("hidden");
});
@ -500,7 +536,9 @@ class Multiple {
);
multContainers.forEach((container) => {
if (
!container.getAttribute("data-services-settings-multiple").includes("SCHEMA")
!container
.getAttribute("data-services-settings-multiple")
.includes("SCHEMA")
)
container.classList.toggle("hidden");
});
@ -546,7 +584,7 @@ class Multiple {
//we have to clone schema container first
const schemaCtnrClone = schemaCtnr.cloneNode(true);
//remove id to avoid duplicate and for W3C
schemaCtnr.removeAttribute('id')
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}`;
@ -594,9 +632,14 @@ class Multiple {
settingCtnrs.forEach((settingCtnr) => {
settingCtnr.setAttribute(
"data-setting-container",
settingCtnr.getAttribute("data-setting-container").replace("_SCHEMA", suffix)
settingCtnr
.getAttribute("data-setting-container")
.replace("_SCHEMA", suffix)
);
settingCtnr.setAttribute(
"id",
settingCtnr.getAttribute("id").replace("_SCHEMA", suffix)
);
settingCtnr.setAttribute('id', settingCtnr.getAttribute('id').replace("_SCHEMA", suffix))
});
//rename input
@ -702,7 +745,9 @@ class Multiple {
const selects = setting.querySelectorAll("select");
selects.forEach((select) => {
const method = select.getAttribute("data-method") || "default";
const name = select.getAttribute("data-services-setting-select-default");
const name = select.getAttribute(
"data-services-setting-select-default"
);
const selDOM = document.querySelector(
`button[data-services-setting-select='${name}']`
);
@ -745,7 +790,9 @@ class Multiple {
);
multiPlugins.forEach((multiGrp) => {
if (
!multiGrp.getAttribute("data-services-settings-multiple").includes("SCHEMA")
!multiGrp
.getAttribute("data-services-settings-multiple")
.includes("SCHEMA")
)
multiGrp.remove();
});
@ -774,6 +821,7 @@ class Multiple {
const setCheckbox = new Checkbox();
const setSelect = new Select();
const setPassword = new Password();
const setDisabledPop = new DisabledPop();
const setPopover = new Popover();
const setTabs = new Tabs();

View File

@ -47,9 +47,13 @@ class Select {
select.classList.add("hidden");
select.classList.remove("flex");
});
const btnEls = document.querySelectorAll("button[data-setting-select]");
const btnEls = document.querySelectorAll(
"button[data-setting-select]"
);
btnEls.forEach((btn) => {
const dropdownChevron = btn.querySelector(`svg[data-setting-select]`);
const dropdownChevron = btn.querySelector(
`svg[data-setting-select]`
);
dropdownChevron.classList.remove("rotate-180");
});
}
@ -67,9 +71,13 @@ class Select {
//SELECT DROPDOWN BTN LOGIC
try {
if (
e.target.closest("button").hasAttribute(`data-setting-select-dropdown-btn`)
e.target
.closest("button")
.hasAttribute(`data-setting-select-dropdown-btn`)
) {
const btn = e.target.closest(`button[data-setting-select-dropdown-btn]`);
const btn = e.target.closest(
`button[data-setting-select-dropdown-btn]`
);
const btnValue = btn.getAttribute("value");
//add new value to custom
@ -106,8 +114,9 @@ class Select {
btn.classList.add("dark:bg-primary", "bg-primary", "text-gray-300");
//close dropdown
const dropdownChevron =
selectCustom.querySelector(`svg[data-setting-select]`);
const dropdownChevron = selectCustom.querySelector(
`svg[data-setting-select]`
);
dropdownChevron.classList.remove("rotate-180");
//update real select element
@ -158,7 +167,9 @@ class Password {
if (e.target.closest("button").hasAttribute("data-setting-password")) {
const btn = e.target.closest("button");
const action = btn.getAttribute("data-setting-password");
const inp = btn.closest("[data-setting-container]").querySelector("input");
const inp = btn
.closest("[data-setting-container]")
.querySelector("input");
this.setValDisplay(action, inp);
this.hiddenBtns(btn);
this.showOppositeBtn(btn, action);
@ -202,4 +213,49 @@ class Password {
}
}
export { Checkbox, Select, Password };
class DisabledPop {
constructor() {
this.init();
}
init() {
window.addEventListener("pointerover", (e) => {
//for checkbox and regular inputs
if (e.target.tagName === "INPUT") {
const el = e.target;
this.showPopup(el, "input");
}
//for select custom
if (
e.target.tagName === "BUTTON" &&
e.target.hasAttribute("data-setting-select")
) {
const el = e.target;
this.showPopup(el, "select");
}
});
window.addEventListener("pointerout", (e) => {
try {
const popupEl = e.target
.closest("div")
.querySelector("div[data-disabled-info]");
popupEl.remove();
} catch (err) {}
});
}
showPopup(el, type = "input") {
if (!el.hasAttribute("disabled")) return;
const method = el.getAttribute("data-default-method");
const popupHTML = `
<div data-disabled-info class="${
type === "select" ? "translate-y-2" : ""
} bg-blue-500 absolute right-2 rounded-lg px-2 py-1 z-20 dark:brightness-90">
<p class="m-0 text-xs text-white dark:text-gray-100">disabled by ${method}</p>
</div>`;
el.insertAdjacentHTML("beforebegin", popupHTML);
}
}
export { Checkbox, Select, Password, DisabledPop };

View File

@ -13,7 +13,7 @@
Version
</p>
<!-- version of user -->
<h5 class="mb-1 font-bold dark:text-white">{{ version }}</h5>
<h5 class="mb-1 font-bold dark:text-gray-400">{{ version }}</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<!-- case no remote fetch -->
@ -64,7 +64,7 @@
>
Instances
</p>
<h5 class="mb-1 font-bold dark:text-white">{{ instances_number }}</h5>
<h5 class="mb-1 font-bold dark:text-gray-400">{{ instances_number }}</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-emerald-500 mx-0.5"
>{{instance_health_count}} / {{ instances_number }}</span
@ -103,7 +103,7 @@
>
Services
</p>
<h5 class="mb-1 font-bold dark:text-white">{{ services_number }}</h5>
<h5 class="mb-1 font-bold dark:text-gray-400">{{ services_number }}</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-sky-600 mx-0.5"
>{{services_ui_count}}</span
@ -150,8 +150,7 @@
>
Plugins
</p>
<!-- add {{ plugins_number }} && {{ plugins_error}}-->
<h5 class="mb-1 font-bold dark:text-white">1</h5>
<h5 class="mb-1 font-bold dark:text-gray-400">{{ plugins_number }}</h5>
<p class="mb-0 dark:text-white dark:opacity-60">
<span class="font-bold leading-normal text-sm text-red-500 mx-0.5"
>{{plugins_errors}}</span

View File

@ -33,7 +33,7 @@ data-plugin-item="{{plugin['id']}}"
class="mx-0 sm:mx-4 my-2 col-span-12 md:mx-6 md:my-3 md:col-span-6 2xl:mx-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">
<div class="flex items-center my-1 relative z-10">
<h5
class="transition duration-300 ease-in-out dark:opacity-90 text-sm sm:text-md font-bold m-0 dark:text-gray-300"
>
@ -50,10 +50,10 @@ data-plugin-item="{{plugin['id']}}"
/>
</svg>
<!-- popover -->
<div class="hidden transition z-50 rounded-md p-3 left-0 -translate-y-7 bottom-0 absolute bg-blue-500"
<div class="dark:brightness-90 hidden transition z-50 rounded-md p-3 left-0 -translate-y-7 bottom-0 absolute bg-blue-500"
data-popover-content="{{ value["label"] }}"
>
<p class="transition duration-300 ease-in-out dark:opacity-90 font-bold text-sm text-white m-0" >{{value['help']}}
<p class="transition duration-300 ease-in-out dark:opacity-90 font-bold text-sm text-white dark:text-gray-100 m-0" >{{value['help']}}
</p>
</div>
<!-- end popover -->
@ -102,6 +102,7 @@ data-plugin-item="{{plugin['id']}}"
<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']}}"
type="button"
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-primary 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 md:py-2 font-normal text-gray-700 transition-all placeholder:text-gray-500"
>
@ -168,7 +169,7 @@ data-plugin-item="{{plugin['id']}}"
<!-- checkbox -->
{% if value["type"] == "check" %}
<div data-checkbox-handler="{{value['id']}}" class="relative mb-7 md:mb-0">
<div data-checkbox-handler="{{value['id']}}" class="relative mb-7 md:mb-0 z-10">
<input id="{{setting}}" name="{{setting}}"
data-default-method="{{global_config[setting]['method']}}"
data-default-value="{{global_config[setting]['value']}}" {% if
@ -176,7 +177,7 @@ data-plugin-item="{{plugin['id']}}"
!= 'default' %} disabled {% endif %} {% if global_config[setting]['value'] and
global_config[setting]['value'] == 'yes' or not
global_config[setting]['value'] and value['default'] == 'yes' %} checked {%
endif %} id="checkbox-{{value['id']}}" class="cursor-pointer disabled:cursor-default disabled:pointer-events-none
endif %} id="checkbox-{{value['id']}}" class="cursor-pointer disabled:cursor-default
relative dark:border-slate-600 dark:bg-slate-700 z-10 checked:z-0 w-5 h-5 ease
text-base rounded-1.4 checked:bg-primary checked:border-primary
dark:checked:bg-primary dark:checked:border-primary duration-250 float-left
@ -258,7 +259,7 @@ data-plugin-item="{{plugin['id']}}"
mx-0 sm:mx-4 my-2 col-span-12 md:mx-6 md:my-3 md:col-span-6 2xl:mx-6 2xl:my-3 2xl:col-span-4"
id="form-edit-{{current_endpoint}}-{{ value["id"] }}_SCHEMA">
<!-- title and info -->
<div class="flex items-center my-1 relative">
<div class="flex items-center my-1 relative z-10">
<h5
class="transition duration-300 ease-in-out dark:opacity-90 text-sm sm:text-md font-bold m-0 dark:text-gray-300"
>
@ -275,10 +276,10 @@ data-plugin-item="{{plugin['id']}}"
/>
</svg>
<!-- popover -->
<div class="hidden transition z-50 rounded-md p-3 left-0 -translate-y-7 bottom-0 absolute bg-blue-500"
<div class="dark:brightness-80 hidden transition z-50 rounded-md p-3 left-0 -translate-y-7 bottom-0 absolute bg-blue-500"
data-popover-content="{{ value["label"] }}"
>
<p class="transition duration-300 ease-in-out dark:opacity-90 font-bold text-sm text-white m-0" >{{value['help']}}
<p class="transition duration-300 ease-in-out dark:opacity-90 font-bold text-sm text-white dark:text-gray-100 m-0" >{{value['help']}}
</p>
</div>
<!-- end popover -->
@ -385,7 +386,7 @@ data-plugin-item="{{plugin['id']}}"
<input id="{{setting}}_SCHEMA" name="{{setting}}_SCHEMA"
data-default-method="default"
data-default-value="{{value['default']}}" {% if value['default'] == 'yes' %} checked {%
endif %} id="checkbox-{{value['id']}}" class="relative cursor-pointer disabled:cursor-default disabled:pointer-events-none
endif %} id="checkbox-{{value['id']}}" class="relative cursor-pointer disabled:cursor-default
dark:border-slate-600 dark:bg-slate-700 z-10 checked:z-0 w-5 h-5 ease
text-base rounded-1.4 checked:bg-primary checked:border-primary
dark:checked:bg-primary dark:checked:border-primary duration-250 float-left