mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
add filter context on global config page
This commit is contained in:
parent
6fc9bbab02
commit
3f77c085ef
4 changed files with 332 additions and 80 deletions
|
|
@ -17,7 +17,7 @@
|
|||
- [UI] General : dark mode enhancement
|
||||
- [UI] General : add visual feedback when filtering is matching nothing
|
||||
- [UI] General : blog news working and add dynamic banner news
|
||||
- [UI] Global config page : Add the possibility to edit multisite settings as well
|
||||
- [UI] Global config page : Add multisite edit, add context filter
|
||||
- [UI] Global config / Service page : remove tabs for select and enhance filtering (plugin name includes)
|
||||
- [UI] Service page : add the possibility to clone a service in the web UI
|
||||
- [UI] Service page : add the possibility to set a service as draft in the web UI
|
||||
|
|
|
|||
|
|
@ -7,6 +7,177 @@ import {
|
|||
showInvalid,
|
||||
} from "./utils/settings.js";
|
||||
|
||||
class Dropdown {
|
||||
constructor(prefix = "global-config") {
|
||||
this.prefix = prefix;
|
||||
this.container = document.querySelector("main");
|
||||
this.lastDrop = "";
|
||||
this.initDropdown();
|
||||
}
|
||||
|
||||
initDropdown() {
|
||||
this.container.addEventListener("click", (e) => {
|
||||
//SELECT BTN LOGIC
|
||||
try {
|
||||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`data-${this.prefix}-setting-select`) &&
|
||||
!e.target.closest("button").hasAttribute(`disabled`)
|
||||
) {
|
||||
const btnName = e.target
|
||||
.closest("button")
|
||||
.getAttribute(`data-${this.prefix}-setting-select`);
|
||||
if (this.lastDrop !== btnName) {
|
||||
this.lastDrop = btnName;
|
||||
this.closeAllDrop();
|
||||
}
|
||||
|
||||
this.toggleSelectBtn(e);
|
||||
}
|
||||
} catch (err) {}
|
||||
//SELECT DROPDOWN BTN LOGIC
|
||||
try {
|
||||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`data-${this.prefix}-setting-select-dropdown-btn`)
|
||||
) {
|
||||
const btn = e.target.closest("button");
|
||||
const btnValue = btn.getAttribute("value");
|
||||
const btnSetting = btn.getAttribute(
|
||||
`data-${this.prefix}-setting-select-dropdown-btn`,
|
||||
);
|
||||
//stop if same value to avoid new fetching
|
||||
const isSameVal = this.isSameValue(btnSetting, btnValue);
|
||||
if (isSameVal) return this.hideDropdown(btnSetting);
|
||||
//else, add new value to custom
|
||||
this.setSelectNewValue(btnSetting, btnValue);
|
||||
//close dropdown and change style
|
||||
this.hideDropdown(btnSetting);
|
||||
|
||||
if (
|
||||
!e.target.closest("button").hasAttribute(`data-${this.prefix}-file`)
|
||||
) {
|
||||
this.changeDropBtnStyle(btnSetting, btn);
|
||||
}
|
||||
}
|
||||
} catch (err) {}
|
||||
});
|
||||
}
|
||||
|
||||
closeAllDrop() {
|
||||
const drops = document.querySelectorAll(
|
||||
`[data-${this.prefix}-setting-select-dropdown]`,
|
||||
);
|
||||
drops.forEach((drop) => {
|
||||
drop.classList.add("hidden");
|
||||
drop.classList.remove("flex");
|
||||
document
|
||||
.querySelector(
|
||||
`svg[data-${this.prefix}-setting-select="${drop.getAttribute(
|
||||
`data-${this.prefix}-setting-select-dropdown`,
|
||||
)}"]`,
|
||||
)
|
||||
.classList.remove("rotate-180");
|
||||
});
|
||||
}
|
||||
|
||||
isSameValue(btnSetting, value) {
|
||||
const selectCustom = document.querySelector(
|
||||
`[data-${this.prefix}-setting-select-text="${btnSetting}"]`,
|
||||
);
|
||||
const currVal = selectCustom.textContent;
|
||||
return currVal === value ? true : false;
|
||||
}
|
||||
|
||||
setSelectNewValue(btnSetting, value) {
|
||||
const selectCustom = document.querySelector(
|
||||
`[data-${this.prefix}-setting-select="${btnSetting}"]`,
|
||||
);
|
||||
selectCustom.querySelector(
|
||||
`[data-${this.prefix}-setting-select-text]`,
|
||||
).textContent = value;
|
||||
}
|
||||
|
||||
hideDropdown(btnSetting) {
|
||||
//hide dropdown
|
||||
const dropdownEl = document.querySelector(
|
||||
`[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}"]`,
|
||||
);
|
||||
dropdownChevron.classList.remove("rotate-180");
|
||||
}
|
||||
|
||||
changeDropBtnStyle(btnSetting, selectedBtn) {
|
||||
const dropdownEl = document.querySelector(
|
||||
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`,
|
||||
);
|
||||
//reset dropdown btns
|
||||
const btnEls = dropdownEl.querySelectorAll("button");
|
||||
|
||||
btnEls.forEach((btn) => {
|
||||
btn.classList.remove(
|
||||
"bg-primary",
|
||||
"dark:bg-primary",
|
||||
"text-gray-300",
|
||||
"text-gray-300",
|
||||
);
|
||||
btn.classList.add("bg-white", "dark:bg-slate-700", "text-gray-700");
|
||||
});
|
||||
//highlight clicked btn
|
||||
selectedBtn.classList.remove(
|
||||
"bg-white",
|
||||
"dark:bg-slate-700",
|
||||
"text-gray-700",
|
||||
);
|
||||
selectedBtn.classList.add("dark:bg-primary", "bg-primary", "text-gray-300");
|
||||
}
|
||||
|
||||
toggleSelectBtn(e) {
|
||||
const attribute = e.target
|
||||
.closest("button")
|
||||
.getAttribute(`data-${this.prefix}-setting-select`);
|
||||
//toggle dropdown
|
||||
const dropdownEl = document.querySelector(
|
||||
`[data-${this.prefix}-setting-select-dropdown="${attribute}"]`,
|
||||
);
|
||||
const dropdownChevron = document.querySelector(
|
||||
`svg[data-${this.prefix}-setting-select="${attribute}"]`,
|
||||
);
|
||||
dropdownEl.classList.toggle("hidden");
|
||||
dropdownEl.classList.toggle("flex");
|
||||
dropdownChevron.classList.toggle("rotate-180");
|
||||
}
|
||||
|
||||
//hide date filter on local
|
||||
hideFilterOnLocal(type) {
|
||||
if (type === "local") {
|
||||
this.hideInp(`input#from-date`);
|
||||
this.hideInp(`input#to-date`);
|
||||
}
|
||||
|
||||
if (type !== "local") {
|
||||
this.showInp(`input#from-date`);
|
||||
this.showInp(`input#to-date`);
|
||||
}
|
||||
}
|
||||
|
||||
showInp(selector) {
|
||||
document.querySelector(selector).closest("div").classList.add("flex");
|
||||
document.querySelector(selector).closest("div").classList.remove("hidden");
|
||||
}
|
||||
|
||||
hideInp(selector) {
|
||||
document.querySelector(selector).closest("div").classList.add("hidden");
|
||||
document.querySelector(selector).closest("div").classList.remove("flex");
|
||||
}
|
||||
}
|
||||
class Multiple {
|
||||
constructor(prefix) {
|
||||
this.prefix = prefix;
|
||||
|
|
@ -532,6 +703,7 @@ class Multiple {
|
|||
}
|
||||
|
||||
const setPopover = new Popover("main", "global-config");
|
||||
const setDrop = new Dropdown();
|
||||
const setTabsSelect = new TabsSelect(
|
||||
document.querySelector("[data-global-config-tabs-select-container]"),
|
||||
document.querySelector("[data-global-config-plugins-container]"),
|
||||
|
|
@ -556,3 +728,17 @@ const checkServiceModalKeyword = new CheckNoMatchFilter(
|
|||
document.querySelector("[data-global-config-form]"),
|
||||
document.querySelector("[data-global-config-nomatch]"),
|
||||
);
|
||||
|
||||
try {
|
||||
const checkServiceCardSelect = new CheckNoMatchFilter(
|
||||
document.querySelectorAll(
|
||||
"button[data-global-config-setting-select-dropdown-btn]",
|
||||
),
|
||||
"select",
|
||||
document
|
||||
.querySelector("[data-global-config-plugins-container]")
|
||||
.querySelectorAll("[data-plugin-item]"),
|
||||
document.querySelector("[data-global-config-form]"),
|
||||
document.querySelector("[data-global-config-nomatch]"),
|
||||
);
|
||||
} catch (e) {}
|
||||
|
|
|
|||
|
|
@ -196,102 +196,161 @@ class FormatValue {
|
|||
class FilterSettings {
|
||||
constructor(inputID, tabContainer, contentContainer) {
|
||||
this.input = document.querySelector(`input#${inputID}`);
|
||||
this.contextTxtEl = document.querySelector(
|
||||
'span[data-global-config-setting-select-text="context"]',
|
||||
);
|
||||
this.tabContainer = tabContainer;
|
||||
this.contentContainer = contentContainer;
|
||||
this.tabsEls = this.tabContainer.querySelectorAll(
|
||||
`[data-tab-select-handler]`,
|
||||
);
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.input.addEventListener("input", () => {
|
||||
this.resetFilter();
|
||||
//get inp format
|
||||
const inpValue = this.input.value.trim().toLowerCase();
|
||||
|
||||
//loop all tabs
|
||||
this.tabsEls.forEach((tab) => {
|
||||
//get settings of tabs except multiples
|
||||
const settings = this.getSettingsFromTab(tab);
|
||||
|
||||
//compare total count to currCount to determine
|
||||
//if tabs need to be hidden
|
||||
const settingCount = settings.length;
|
||||
let hiddenCount = 0;
|
||||
settings.forEach((setting) => {
|
||||
try {
|
||||
const title = setting
|
||||
.querySelector("h5")
|
||||
.textContent.trim()
|
||||
.toLowerCase();
|
||||
if (!title.includes(inpValue)) {
|
||||
setting.classList.add("hidden");
|
||||
hiddenCount++;
|
||||
}
|
||||
} catch (err) {}
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
if (this.input) {
|
||||
this.input.addEventListener("input", () => {
|
||||
this.runFilter();
|
||||
});
|
||||
//case no setting match, check if match at least tab name
|
||||
//if not, hide tab
|
||||
if (settingCount === hiddenCount) {
|
||||
const tabName = tab.getAttribute(`data-tab-select-handler`);
|
||||
const tabTxt = tab.textContent.trim().toLowerCase();
|
||||
if (!tabTxt.includes(inpValue)) {
|
||||
tab.classList.add("!hidden");
|
||||
}
|
||||
|
||||
this.contentContainer
|
||||
.querySelector(`[data-plugin-item=${tabName}]`)
|
||||
.classList.add("hidden");
|
||||
window.addEventListener("click", (e) => {
|
||||
try {
|
||||
if (
|
||||
e.target.hasAttribute(
|
||||
"data-global-config-setting-select-dropdown-btn",
|
||||
) &&
|
||||
e.target.getAttribute(
|
||||
"data-global-config-setting-select-dropdown-btn",
|
||||
) === "context"
|
||||
) {
|
||||
return this.runFilter();
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// check current tabs states
|
||||
let isAllHidden = true;
|
||||
let firstNotHiddenEl = null;
|
||||
for (let i = 0; i < this.tabsEls.length; i++) {
|
||||
const tab = this.tabsEls[i];
|
||||
if (!tab.classList.contains("!hidden")) {
|
||||
isAllHidden = false;
|
||||
firstNotHiddenEl = tab;
|
||||
break;
|
||||
runFilter() {
|
||||
this.resetFilter();
|
||||
//get inp format
|
||||
const inpValue = this.input.value.trim().toLowerCase();
|
||||
|
||||
//loop all tabs
|
||||
this.tabsEls.forEach((tab) => {
|
||||
//get settings of tabs except multiples
|
||||
const settings = this.getSettingsFromTab(tab);
|
||||
|
||||
//compare total count to currCount to determine
|
||||
//if tabs need to be hidden
|
||||
const settingCount = settings.length;
|
||||
let hiddenCount = 0;
|
||||
settings.forEach((setting) => {
|
||||
try {
|
||||
let needToHide = false;
|
||||
const title = setting
|
||||
.querySelector("h5")
|
||||
.textContent.trim()
|
||||
.toLowerCase();
|
||||
if (!title.includes(inpValue)) {
|
||||
needToHide = true;
|
||||
}
|
||||
|
||||
// check context if filter exists
|
||||
try {
|
||||
if (this.contextTxtEl) {
|
||||
const currContextFilter =
|
||||
this.contextTxtEl.textContent.toLowerCase();
|
||||
|
||||
if (currContextFilter !== "all") {
|
||||
const settingContext = setting
|
||||
.getAttribute("data-global-config-context")
|
||||
.toLowerCase();
|
||||
if (settingContext !== currContextFilter) {
|
||||
needToHide = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (needToHide) {
|
||||
setting.classList.add("hidden");
|
||||
hiddenCount++;
|
||||
}
|
||||
} catch (err) {}
|
||||
});
|
||||
//case no setting match, check if match at least tab name
|
||||
// if no context, else we don't care about name
|
||||
if (settingCount === hiddenCount) {
|
||||
const tabName = tab.getAttribute(`data-tab-select-handler`);
|
||||
const tabTxt = tab.textContent.trim().toLowerCase();
|
||||
let needHideTab = false;
|
||||
try {
|
||||
if (this.contextTxtEl.textContent.toLowerCase() !== "all")
|
||||
needHideTab = true;
|
||||
} catch (e) {}
|
||||
|
||||
if (!tabTxt.includes(inpValue)) needHideTab = true;
|
||||
|
||||
if (needHideTab) {
|
||||
tab.classList.add("!hidden");
|
||||
|
||||
this.contentContainer
|
||||
.querySelector(`[data-plugin-item=${tabName}]`)
|
||||
.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
// case no tab match
|
||||
if (isAllHidden) {
|
||||
this.tabContainer
|
||||
.querySelector("[data-tab-select-dropdown-btn]")
|
||||
.setAttribute("data-tab-id", "no-match");
|
||||
return (this.tabContainer.querySelector(
|
||||
"[data-tab-select-dropdown-btn] span",
|
||||
).textContent = "No match");
|
||||
}
|
||||
|
||||
// click first not hidden tab
|
||||
const currTabEl = this.tabContainer.querySelector(
|
||||
"[data-tab-select-dropdown-btn]",
|
||||
);
|
||||
|
||||
const currTabName = currTabEl.getAttribute("data-tab-id");
|
||||
|
||||
// case previously no match
|
||||
if (currTabName === "no-match" && !isAllHidden) {
|
||||
return firstNotHiddenEl.click();
|
||||
}
|
||||
|
||||
const currTabBtn = this.tabContainer.querySelector(
|
||||
`[data-tab-select-handler='${currTabName}']`,
|
||||
);
|
||||
|
||||
if (!currTabBtn.classList.contains("!hidden")) {
|
||||
return currTabBtn.click();
|
||||
}
|
||||
|
||||
if (currTabBtn.classList.contains("!hidden")) {
|
||||
return firstNotHiddenEl.click();
|
||||
}
|
||||
});
|
||||
|
||||
// check current tabs states
|
||||
let isAllHidden = true;
|
||||
let firstNotHiddenEl = null;
|
||||
for (let i = 0; i < this.tabsEls.length; i++) {
|
||||
const tab = this.tabsEls[i];
|
||||
if (!tab.classList.contains("!hidden")) {
|
||||
isAllHidden = false;
|
||||
firstNotHiddenEl = tab;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("is all hidden", isAllHidden);
|
||||
|
||||
// case no tab match
|
||||
if (isAllHidden) {
|
||||
this.tabContainer
|
||||
.querySelector("[data-tab-select-dropdown-btn]")
|
||||
.setAttribute("data-tab-id", "no-match");
|
||||
return (this.tabContainer.querySelector(
|
||||
"[data-tab-select-dropdown-btn] span",
|
||||
).textContent = "No match");
|
||||
}
|
||||
|
||||
// click first not hidden tab
|
||||
const currTabEl = this.tabContainer.querySelector(
|
||||
"[data-tab-select-dropdown-btn]",
|
||||
);
|
||||
|
||||
const currTabName = currTabEl.getAttribute("data-tab-id");
|
||||
|
||||
// case previously no match
|
||||
if (currTabName === "no-match" && !isAllHidden) {
|
||||
return firstNotHiddenEl.click();
|
||||
}
|
||||
|
||||
const currTabBtn = this.tabContainer.querySelector(
|
||||
`[data-tab-select-handler='${currTabName}']`,
|
||||
);
|
||||
|
||||
if (!currTabBtn.classList.contains("!hidden")) {
|
||||
return currTabBtn.click();
|
||||
}
|
||||
|
||||
if (currTabBtn.classList.contains("!hidden")) {
|
||||
return firstNotHiddenEl.click();
|
||||
}
|
||||
}
|
||||
|
||||
resetFilter() {
|
||||
|
|
|
|||
7
src/ui/templates/global_config.html
vendored
7
src/ui/templates/global_config.html
vendored
|
|
@ -18,6 +18,13 @@
|
|||
"id": "keyword",
|
||||
"placeholder": "keyword",
|
||||
"pattern": "(.*?)"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"name": "Context",
|
||||
"id": "context",
|
||||
"value": "all",
|
||||
"values": ["all", "global", "multisite"]
|
||||
}
|
||||
] %}
|
||||
<div data-global-config-filter
|
||||
|
|
|
|||
Loading…
Reference in a new issue