update block req page

*fix link on menu
*add keyword, status and method filtrer
*dropdown values are dynamic
*add script from head
This commit is contained in:
Jordan Blasenhauer 2024-01-18 18:37:07 +01:00
parent 723c8d17d5
commit e21aec6d72
4 changed files with 392 additions and 84 deletions

View file

@ -0,0 +1,303 @@
class Filter {
constructor(prefix = "block_requests") {
this.prefix = prefix;
this.container = document.querySelector(`[data-${this.prefix}-filter]`);
this.keyInp = document.querySelector("input#keyword");
this.methodValue = "all";
this.statusValue = "all";
this.initHandler();
}
initHandler() {
//METHOD HANDLER
this.container.addEventListener("click", (e) => {
try {
if (
e.target
.closest("button")
.getAttribute(`data-${this.prefix}-setting-select-dropdown-btn`) ===
"method"
) {
setTimeout(() => {
const value = document
.querySelector(
`[data-${this.prefix}-setting-select-text="method"]`
)
.textContent.trim();
this.methodValue = value;
//run filter
this.filter();
}, 10);
}
} catch (err) {}
});
//STATUS HANDLER
this.container.addEventListener("click", (e) => {
try {
if (
e.target
.closest("button")
.getAttribute(`data-${this.prefix}-setting-select-dropdown-btn`) ===
"status"
) {
setTimeout(() => {
const value = document
.querySelector(
`[data-${this.prefix}-setting-select-text="status"]`
)
.textContent.trim();
this.statusValue = value;
//run filter
this.filter();
}, 10);
}
} catch (err) {}
});
//KEYWORD HANDLER
this.keyInp.addEventListener("input", (e) => {
this.filter();
});
}
filter() {
const requests = document.querySelector(
`[data-${this.prefix}-list]`
).children;
if (requests.length === 0) return;
//reset
for (let i = 0; i < requests.length; i++) {
const el = requests[i];
el.classList.remove("hidden");
}
//filter type
this.setFilterMethod(requests);
this.setFilterKeyword(requests);
this.setFilterStatus(requests);
}
setFilterMethod(requests) {
if (this.methodValue === "all") return;
for (let i = 0; i < requests.length; i++) {
const el = requests[i];
const type = this.getElAttribut(el, "method");
if (type !== this.methodValue) el.classList.add("hidden");
}
}
setFilterKeyword(requests) {
const keyword = this.keyInp.value.trim().toLowerCase();
if (!keyword) return;
for (let i = 0; i < requests.length; i++) {
const el = requests[i];
const url = this.getElAttribut(el, "url");
const date = this.getElAttribut(el, "date");
const reason = this.getElAttribut(el, "reason");
const data = this.getElAttribut(el, "data");
if (
!url.includes(keyword) &&
!date.includes(keyword) &&
!reason.includes(keyword) &&
!data.includes(keyword)
)
el.classList.add("hidden");
}
}
setFilterStatus(requests) {
if (this.statusValue === "all") return;
for (let i = 0; i < requests.length; i++) {
const el = requests[i];
const type = this.getElAttribut(el, "status");
if (type !== this.statusValue) el.classList.add("hidden");
}
}
getElAttribut(el, attr) {
return el
.querySelector(`[data-${this.prefix}-${attr}]`)
.getAttribute(`data-${this.prefix}-${attr}`)
.trim();
}
}
class Dropdown {
constructor(prefix = "block_requests") {
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-${prefix}-file`)) {
this.changeDropBtnStyle(btnSetting, btn);
}
//show / hide filter
if (btnSetting === "instances") {
this.hideFilterOnLocal(btn.getAttribute("data-_type"));
}
}
} 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");
}
}
const setDropdown = new Dropdown();
const setFilter = new Filter();

View file

@ -1,5 +1,18 @@
{% extends "base.html" %} {% block content %} {% set current_endpoint =
url_for(request.endpoint)[1:].split("/")[-1].strip() %}
{% set methods = [] %}
{% set codes = [] %}
{% for request in block_requests %}
{% if request["method"] not in methods %}
{% set methods = methods.append(request["method"]) %}
{% endif %}
{% if request["status"] not in codes %}
{% set codes = codes.append(request["status"]) %}
{% endif %}
{% endfor %}
<!-- info-->
<div
class="col-span-12 md:col-span-4 3xl:col-span-3 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
@ -47,26 +60,6 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
</div>
<!-- end search inpt-->
<!-- status code inpt-->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5
class="my-1 transition duration-300 ease-in-out dark:opacity-90 text-sm sm:text-md font-bold m-0 dark:text-gray-300"
>
Status code
</h5>
<label for="status-code" class="sr-only">status code</label>
<input
type="text"
id="status-code"
name="status-code"
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="403"
pattern="/^\d+$/"
required
/>
</div>
<!-- end status code inpt-->
<!-- select method -->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5
@ -114,70 +107,78 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
>
all
</button>
{% for method in methods %}
<button
role="option"
data-{{current_endpoint}}-setting-select-dropdown-btn="method"
value="{{method}}"
class="{% if loop.last %}rounded-b{%endif%} border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 bg-white text-gray-700 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:bg-slate-700 dark:text-gray-300"
>
{{method}}
</button>
{% endfor %}
</div>
<!-- end dropdown-->
</div>
<!-- end select method -->
<!-- select status -->
<div class="flex flex-col relative col-span-12 md:col-span-6">
<h5
class="my-1 transition duration-300 ease-in-out dark:opacity-90 text-sm sm:text-md font-bold m-0 dark:text-gray-300"
>
Status code
</h5>
<button
aria-controls="filter-state"
data-{{current_endpoint}}-setting-select="status"
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="{{current_endpoint}}-status"
data-name="{{current_endpoint}}-status"
data-{{current_endpoint}}-setting-select-text="status"
>all</span
>
<!-- chevron -->
<svg
data-{{current_endpoint}}-setting-select="status"
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-state"
role="listbox"
data-{{current_endpoint}}-setting-select-dropdown="status"
class="hidden z-100 absolute h-full flex-col w-full translate-y-16"
>
<button
role="option"
data-{{current_endpoint}}-setting-select-dropdown-btn="method"
value="GET"
class="border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 bg-white text-gray-700 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:bg-slate-700 dark:text-gray-300"
data-{{current_endpoint}}-setting-select-dropdown-btn="status"
value="all"
class="border-t rounded-t 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 dark:bg-primary bg-primary text-gray-300"
>
GET
all
</button>
{% for code in codes %}
<button
role="option"
data-{{current_endpoint}}-setting-select-dropdown-btn="method"
value="PUT"
class="border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 bg-white text-gray-700 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:bg-slate-700 dark:text-gray-300"
data-{{current_endpoint}}-setting-select-dropdown-btn="status"
value="{{code}}"
class="{% if loop.last %}rounded-b{%endif%} border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 bg-white text-gray-700 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:bg-slate-700 dark:text-gray-300"
>
PUT
</button>
<button
role="option"
data-{{current_endpoint}}-setting-select-dropdown-btn="method"
value="POST"
class="border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 bg-white text-gray-700 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:bg-slate-700 dark:text-gray-300"
>
POST
</button>
<button
role="option"
data-{{current_endpoint}}-setting-select-dropdown-btn="method"
value="PATCH"
class="border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 bg-white text-gray-700 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:bg-slate-700 dark:text-gray-300"
>
PATCH
</button>
<button
role="option"
data-{{current_endpoint}}-setting-select-dropdown-btn="method"
value="CONNECT"
class="border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 bg-white text-gray-700 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:bg-slate-700 dark:text-gray-300"
>
CONNECT
</button>
<button
role="option"
data-{{current_endpoint}}-setting-select-dropdown-btn="method"
value="OPTIONS"
class="border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 bg-white text-gray-700 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:bg-slate-700 dark:text-gray-300"
>
OPTIONS
</button>
<button
role="option"
data-{{current_endpoint}}-setting-select-dropdown-btn="method"
value="TRACE"
class="border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 bg-white text-gray-700 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:bg-slate-700 dark:text-gray-300"
>
TRACE
</button>
<button
role="option"
data-{{current_endpoint}}-setting-select-dropdown-btn="method"
value="HEAD"
class="rounded-b border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 bg-white text-gray-700 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:bg-slate-700 dark:text-gray-300"
>
HEAD
{{code}}
</button>
{% endfor %}
</div>
<!-- end dropdown-->
</div>
@ -234,42 +235,42 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-3 m-0 my-1"
data-{{current_endpoint}}-url
data-{{current_endpoint}}-url="{{request['url']}}"
>
{{request['url']}}
</p>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-2 m-0 my-1"
data-{{current_endpoint}}-date
data-{{current_endpoint}}-date="{{request['date']}}"
>
{{request['date']}}
</p>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-1 m-0 my-1 pl-1 "
data-{{current_endpoint}}-method
data-{{current_endpoint}}-method="{{request['method']}}"
>
{{request["method"]}}
</p>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-1 m-0 my-1 pl-0.5 "
data-{{current_endpoint}}-status-code
data-{{current_endpoint}}-status="{{request['status']}}"
>
{{request["status"]}}
</p>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-2 m-0 my-1 pl-0.5 "
data-{{current_endpoint}}-reason
data-{{current_endpoint}}-reason="{{request['reason']}}"
>
{{request["reason"]}}
</p>
<p
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-3 m-0 my-1"
data-{{current_endpoint}}-data
data-{{current_endpoint}}-data="{{request['data']}}"
>
{{request["data"]}}
</p>

View file

@ -45,5 +45,9 @@
<script type="module" src="./js/jobs.js"></script>
{% elif current_endpoint == "account" %}
<script type="module" src="./js/account.js"></script>
{% elif current_endpoint == "block_requests" %}
<script type="module" src="./js/requests.js"></script>
{% elif current_endpoint == "bans" %}
<script type="module" src="./js/bans.js"></script>
{% endif %}
</head>

View file

@ -304,8 +304,8 @@
<!-- item -->
<li class="mt-0.5 w-full">
<a
class="{% if current_endpoint == 'bans' %}font-semibold text-slate-700 dark:bg-primary/50 rounded-lg dark:hover:bg-primary/60 bg-primary/20 hover:bg-primary/30{% else %}dark:hover:bg-primary/20 hover:bg-primary/5 {% endif %} hover:rounded-lg dark:text-white dark:opacity-80 py-1 text-sm ease-nav-brand my-0 mx-2 flex items-center whitespace-nowrap px-4 transition"
href="{% if current_endpoint == 'bans' %}#{% else %}loading?next={{ url_for('bans') }}{% endif %}"
class="{% if current_endpoint == 'block_requests' %}font-semibold text-slate-700 dark:bg-primary/50 rounded-lg dark:hover:bg-primary/60 bg-primary/20 hover:bg-primary/30{% else %}dark:hover:bg-primary/20 hover:bg-primary/5 {% endif %} hover:rounded-lg dark:text-white dark:opacity-80 py-1 text-sm ease-nav-brand my-0 mx-2 flex items-center whitespace-nowrap px-4 transition"
href="{% if current_endpoint == 'block_requests' %}#{% else %}loading?next={{ url_for('block_requests') }}{% endif %}"
>
<div
class="mr-2 flex items-center justify-center rounded-lg bg-center stroke-0 text-center p-1 xl:p-1.5"