Merge pull request #361 from TheophileDiot/dev
Changes on jobs in the back and the front
This commit is contained in:
commit
2087167228
|
@ -2,7 +2,7 @@
|
|||
|
||||
from ipaddress import ip_address, ip_network
|
||||
from os import _exit, getenv, makedirs
|
||||
from re import match
|
||||
from re import IGNORECASE, compile as re_compile
|
||||
from sys import exit as sys_exit, path as sys_path
|
||||
from traceback import format_exc
|
||||
|
||||
|
@ -16,6 +16,10 @@ from Database import Database
|
|||
from logger import setup_logger
|
||||
from jobs import cache_file, cache_hash, is_cached_file, file_hash
|
||||
|
||||
rdns_rx = re_compile(r"^(\.?[a-z\d\-]+)*\.[a-z]{2,}$", IGNORECASE)
|
||||
asn_rx = re_compile(r"^\d+$")
|
||||
uri_rx = re_compile(r"^/")
|
||||
|
||||
|
||||
def check_line(kind, line):
|
||||
if kind == "IP":
|
||||
|
@ -33,19 +37,19 @@ def check_line(kind, line):
|
|||
pass
|
||||
return False, ""
|
||||
elif kind == "RDNS":
|
||||
if match(r"^(\.?[A-Za-z0-9\-]+)*\.[A-Za-z]{2,}$", line):
|
||||
if rdns_rx.match(line):
|
||||
return True, line.lower()
|
||||
return False, ""
|
||||
elif kind == "ASN":
|
||||
real_line = line.replace("AS", "")
|
||||
if match(r"^\d+$", real_line):
|
||||
real_line = line.replace("AS", "").replace("as", "")
|
||||
if asn_rx.match(real_line):
|
||||
return True, real_line
|
||||
elif kind == "USER_AGENT":
|
||||
return True, line.replace("\\ ", " ").replace("\\.", "%.").replace(
|
||||
"\\\\", "\\"
|
||||
).replace("-", "%-")
|
||||
elif kind == "URI":
|
||||
if match(r"^/", line):
|
||||
if uri_rx.match(line):
|
||||
return True, line
|
||||
return False, ""
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from ipaddress import ip_address, ip_network
|
||||
from os import _exit, getenv, makedirs
|
||||
from re import match
|
||||
from re import IGNORECASE, compile as re_compile
|
||||
from sys import exit as sys_exit, path as sys_path
|
||||
from traceback import format_exc
|
||||
|
||||
|
@ -16,6 +16,10 @@ from Database import Database
|
|||
from logger import setup_logger
|
||||
from jobs import cache_file, cache_hash, is_cached_file, file_hash
|
||||
|
||||
rdns_rx = re_compile(r"^(\.?[a-z\d\-]+)*\.[a-z]{2,}$", IGNORECASE)
|
||||
asn_rx = re_compile(r"^\d+$")
|
||||
uri_rx = re_compile(r"^/")
|
||||
|
||||
|
||||
def check_line(kind, line):
|
||||
if kind == "IP":
|
||||
|
@ -33,19 +37,19 @@ def check_line(kind, line):
|
|||
pass
|
||||
return False, ""
|
||||
elif kind == "RDNS":
|
||||
if match(r"^(\.?[A-Za-z0-9\-]+)*\.[A-Za-z]{2,}$", line):
|
||||
if rdns_rx.match(line):
|
||||
return True, line.lower()
|
||||
return False, ""
|
||||
elif kind == "ASN":
|
||||
real_line = line.replace("AS", "")
|
||||
if match(r"^\d+$", real_line):
|
||||
real_line = line.replace("AS", "").replace("as", "")
|
||||
if asn_rx.match(real_line):
|
||||
return True, real_line
|
||||
elif kind == "USER_AGENT":
|
||||
return True, line.replace("\\ ", " ").replace("\\.", "%.").replace(
|
||||
"\\\\", "\\"
|
||||
).replace("-", "%-")
|
||||
elif kind == "URI":
|
||||
if match(r"^/", line):
|
||||
if uri_rx.match(line):
|
||||
return True, line
|
||||
return False, ""
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from ipaddress import ip_address, ip_network
|
||||
from os import _exit, getenv, makedirs
|
||||
from re import match
|
||||
from re import IGNORECASE, compile as re_compile
|
||||
from sys import exit as sys_exit, path as sys_path
|
||||
from traceback import format_exc
|
||||
|
||||
|
@ -16,6 +16,10 @@ from Database import Database
|
|||
from logger import setup_logger
|
||||
from jobs import cache_file, cache_hash, is_cached_file, file_hash
|
||||
|
||||
rdns_rx = re_compile(r"^(\.?[a-z\d\-]+)*\.[a-z]{2,}$", IGNORECASE)
|
||||
asn_rx = re_compile(r"^\d+$")
|
||||
uri_rx = re_compile(r"^/")
|
||||
|
||||
|
||||
def check_line(kind, line):
|
||||
if kind == "IP":
|
||||
|
@ -33,19 +37,19 @@ def check_line(kind, line):
|
|||
pass
|
||||
return False, ""
|
||||
elif kind == "RDNS":
|
||||
if match(r"^(\.?[A-Za-z0-9\-]+)*\.[A-Za-z]{2,}$", line):
|
||||
if rdns_rx.match(line):
|
||||
return True, line.lower()
|
||||
return False, ""
|
||||
elif kind == "ASN":
|
||||
real_line = line.replace("AS", "")
|
||||
if match(r"^\d+$", real_line):
|
||||
real_line = line.replace("AS", "").replace("as", "")
|
||||
if asn_rx.match(real_line):
|
||||
return True, real_line
|
||||
elif kind == "USER_AGENT":
|
||||
return True, line.replace("\\ ", " ").replace("\\.", "%.").replace(
|
||||
"\\\\", "\\"
|
||||
).replace("-", "%-")
|
||||
elif kind == "URI":
|
||||
if match(r"^/", line):
|
||||
if uri_rx.match(line):
|
||||
return True, line
|
||||
return False, ""
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
from copy import deepcopy
|
||||
from glob import glob
|
||||
from json import loads
|
||||
from logging import Logger
|
||||
from os import environ, getenv
|
||||
from subprocess import DEVNULL, PIPE, STDOUT, run
|
||||
from threading import Lock, Thread
|
||||
from schedule import (
|
||||
clear as schedule_clear,
|
||||
every as schedule_every,
|
||||
|
@ -36,6 +38,8 @@ class JobScheduler(ApiCaller):
|
|||
self.__env.update(environ)
|
||||
self.__jobs = self.__get_jobs()
|
||||
self.__lock = lock
|
||||
self.__thread_lock = Lock()
|
||||
self.__job_success = True
|
||||
|
||||
def __get_jobs(self):
|
||||
jobs = {}
|
||||
|
@ -101,7 +105,6 @@ class JobScheduler(ApiCaller):
|
|||
self.__logger.info(
|
||||
f"Executing job {name} from plugin {plugin} ...",
|
||||
)
|
||||
success = True
|
||||
try:
|
||||
proc = run(
|
||||
f"{path}/jobs/{file}",
|
||||
|
@ -109,29 +112,31 @@ class JobScheduler(ApiCaller):
|
|||
stderr=STDOUT,
|
||||
env=self.__env,
|
||||
)
|
||||
except:
|
||||
self.__logger.error(
|
||||
f"Exception while executing job {name} from plugin {plugin} :\n{format_exc()}",
|
||||
)
|
||||
success = False
|
||||
if success and proc.returncode >= 2:
|
||||
self.__logger.error(
|
||||
f"Error while executing job {name} from plugin {plugin}",
|
||||
)
|
||||
success = False
|
||||
except BaseException:
|
||||
with self.__thread_lock:
|
||||
self.__logger.error(
|
||||
f"Exception while executing job {name} from plugin {plugin} :\n{format_exc()}",
|
||||
)
|
||||
self.__job_success = False
|
||||
|
||||
err = self.__db.update_job(plugin, name, success)
|
||||
if self.__job_success and proc.returncode >= 2:
|
||||
with self.__thread_lock:
|
||||
self.__logger.error(
|
||||
f"Error while executing job {name} from plugin {plugin}",
|
||||
)
|
||||
self.__job_success = False
|
||||
|
||||
if not err:
|
||||
self.__logger.info(
|
||||
f"Successfully updated database for the job {name} from plugin {plugin}",
|
||||
)
|
||||
else:
|
||||
self.__logger.warning(
|
||||
f"Failed to update database for the job {name} from plugin {plugin}: {err}",
|
||||
)
|
||||
with self.__thread_lock:
|
||||
err = self.__db.update_job(plugin, name, self.__job_success)
|
||||
|
||||
return success
|
||||
if not err:
|
||||
self.__logger.info(
|
||||
f"Successfully updated database for the job {name} from plugin {plugin}",
|
||||
)
|
||||
else:
|
||||
self.__logger.warning(
|
||||
f"Failed to update database for the job {name} from plugin {plugin}: {err}",
|
||||
)
|
||||
|
||||
def setup(self):
|
||||
for plugin, jobs in self.__jobs.items():
|
||||
|
@ -184,19 +189,25 @@ class JobScheduler(ApiCaller):
|
|||
|
||||
def run_once(self):
|
||||
ret = True
|
||||
threads = []
|
||||
for plugin, jobs in self.__jobs.items():
|
||||
for job in jobs:
|
||||
try:
|
||||
path = job["path"]
|
||||
name = job["name"]
|
||||
file = job["file"]
|
||||
if self.__job_wrapper(path, plugin, name, file) >= 2:
|
||||
ret = False
|
||||
except BaseException:
|
||||
ret = False
|
||||
self.__logger.error(
|
||||
f"Exception while running jobs once for plugin {plugin} : {format_exc()}",
|
||||
)
|
||||
path = job["path"]
|
||||
name = job["name"]
|
||||
file = job["file"]
|
||||
thread = Thread(
|
||||
target=self.__job_wrapper, args=(path, plugin, name, file)
|
||||
)
|
||||
threads.append(thread)
|
||||
|
||||
for thread in threads:
|
||||
thread.start()
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
ret = self.__job_success
|
||||
self.__job_success = True
|
||||
|
||||
return ret
|
||||
|
||||
|
|
|
@ -827,14 +827,18 @@ h6 {
|
|||
grid-column: span 3 / span 3;
|
||||
}
|
||||
|
||||
.col-span-9 {
|
||||
grid-column: span 9 / span 9;
|
||||
}
|
||||
|
||||
.col-span-2 {
|
||||
grid-column: span 2 / span 2;
|
||||
}
|
||||
|
||||
.col-span-4 {
|
||||
grid-column: span 4 / span 4;
|
||||
}
|
||||
|
||||
.col-span-9 {
|
||||
grid-column: span 9 / span 9;
|
||||
}
|
||||
|
||||
.col-auto {
|
||||
grid-column: auto;
|
||||
}
|
||||
|
@ -903,16 +907,16 @@ h6 {
|
|||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.my-auto {
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
.my-1 {
|
||||
margin-top: 0.25rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.my-auto {
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
.my-4 {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
|
@ -1007,10 +1011,6 @@ h6 {
|
|||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.mb-7 {
|
||||
margin-bottom: 1.75rem;
|
||||
}
|
||||
|
@ -1019,6 +1019,10 @@ h6 {
|
|||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.mt-0 {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
@ -1139,14 +1143,14 @@ h6 {
|
|||
height: 3rem;
|
||||
}
|
||||
|
||||
.h-16 {
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
.h-3 {
|
||||
height: 0.75rem;
|
||||
}
|
||||
|
||||
.h-16 {
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
.h-19 {
|
||||
height: 4.75rem;
|
||||
}
|
||||
|
@ -1159,6 +1163,10 @@ h6 {
|
|||
height: calc(100vh - 360px);
|
||||
}
|
||||
|
||||
.h-5\.5 {
|
||||
height: 1.375rem;
|
||||
}
|
||||
|
||||
.h-30 {
|
||||
height: 7.5rem;
|
||||
}
|
||||
|
@ -1179,10 +1187,6 @@ h6 {
|
|||
height: 33.333333%;
|
||||
}
|
||||
|
||||
.h-5\.5 {
|
||||
height: 1.375rem;
|
||||
}
|
||||
|
||||
.max-h-screen {
|
||||
max-height: 100vh;
|
||||
}
|
||||
|
@ -1263,10 +1267,6 @@ h6 {
|
|||
width: 3rem;
|
||||
}
|
||||
|
||||
.w-60 {
|
||||
width: 15rem;
|
||||
}
|
||||
|
||||
.w-5 {
|
||||
width: 1.25rem;
|
||||
}
|
||||
|
@ -1275,6 +1275,10 @@ h6 {
|
|||
width: 0.75rem;
|
||||
}
|
||||
|
||||
.w-60 {
|
||||
width: 15rem;
|
||||
}
|
||||
|
||||
.w-28 {
|
||||
width: 7rem;
|
||||
}
|
||||
|
@ -1283,6 +1287,10 @@ h6 {
|
|||
width: auto;
|
||||
}
|
||||
|
||||
.w-5\.5 {
|
||||
width: 1.375rem;
|
||||
}
|
||||
|
||||
.w-90 {
|
||||
width: 22.5rem;
|
||||
}
|
||||
|
@ -1295,10 +1303,6 @@ h6 {
|
|||
width: 1.75rem;
|
||||
}
|
||||
|
||||
.w-5\.5 {
|
||||
width: 1.375rem;
|
||||
}
|
||||
|
||||
.min-w-0 {
|
||||
min-width: 0px;
|
||||
}
|
||||
|
@ -1397,13 +1401,13 @@ h6 {
|
|||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.translate-y-12 {
|
||||
--tw-translate-y: 3rem;
|
||||
.translate-x-1 {
|
||||
--tw-translate-x: 0.25rem;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.translate-x-1 {
|
||||
--tw-translate-x: 0.25rem;
|
||||
.translate-y-12 {
|
||||
--tw-translate-y: 3rem;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
|
@ -1566,6 +1570,11 @@ h6 {
|
|||
row-gap: 0.5rem;
|
||||
}
|
||||
|
||||
.gap-x-1 {
|
||||
-moz-column-gap: 0.25rem;
|
||||
column-gap: 0.25rem;
|
||||
}
|
||||
|
||||
.overflow-auto {
|
||||
overflow: auto;
|
||||
}
|
||||
|
@ -1918,6 +1927,10 @@ h6 {
|
|||
fill: #adb5bd;
|
||||
}
|
||||
|
||||
.fill-green-500 {
|
||||
fill: #22c55e;
|
||||
}
|
||||
|
||||
.fill-blue-400 {
|
||||
fill: #60a5fa;
|
||||
}
|
||||
|
@ -1934,26 +1947,14 @@ h6 {
|
|||
fill: #db2777;
|
||||
}
|
||||
|
||||
.fill-slate-800 {
|
||||
fill: #3a416f;
|
||||
}
|
||||
|
||||
.fill-green-500 {
|
||||
fill: #22c55e;
|
||||
}
|
||||
|
||||
.fill-emerald-500 {
|
||||
fill: #2dce89;
|
||||
}
|
||||
|
||||
.fill-emerald-800 {
|
||||
fill: #065f46;
|
||||
}
|
||||
|
||||
.fill-emerald-700 {
|
||||
fill: #047857;
|
||||
}
|
||||
|
||||
.fill-slate-800 {
|
||||
fill: #3a416f;
|
||||
}
|
||||
|
||||
.stroke-0 {
|
||||
stroke-width: 0;
|
||||
}
|
||||
|
@ -2104,14 +2105,14 @@ h6 {
|
|||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.pt-5 {
|
||||
padding-top: 1.25rem;
|
||||
}
|
||||
|
||||
.pb-2 {
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.pt-5 {
|
||||
padding-top: 1.25rem;
|
||||
}
|
||||
|
||||
.pl-6 {
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
@ -2922,10 +2923,6 @@ h6 {
|
|||
fill: #adb5bd;
|
||||
}
|
||||
|
||||
.dark .dark\:fill-emerald-500 {
|
||||
fill: #2dce89;
|
||||
}
|
||||
|
||||
.dark .dark\:text-white {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
|
@ -3267,6 +3264,22 @@ h6 {
|
|||
grid-column: span 6 / span 6;
|
||||
}
|
||||
|
||||
.lg\:col-span-12 {
|
||||
grid-column: span 12 / span 12;
|
||||
}
|
||||
|
||||
.lg\:col-span-9 {
|
||||
grid-column: span 9 / span 9;
|
||||
}
|
||||
|
||||
.lg\:col-span-3 {
|
||||
grid-column: span 3 / span 3;
|
||||
}
|
||||
|
||||
.lg\:col-span-8 {
|
||||
grid-column: span 8 / span 8;
|
||||
}
|
||||
|
||||
.lg\:mx-8 {
|
||||
margin-left: 2rem;
|
||||
margin-right: 2rem;
|
||||
|
|
|
@ -43,7 +43,9 @@ class LogsDropdown {
|
|||
this.hideDropdown(btnSetting);
|
||||
this.changeDropBtnStyle(btnSetting, btn);
|
||||
//show / hide filter
|
||||
this.hideFilterOnLocal(btn.getAttribute("_type"));
|
||||
if (btnSetting === "instances") {
|
||||
this.hideFilterOnLocal(btn.getAttribute("_type"));
|
||||
}
|
||||
}
|
||||
} catch (err) {}
|
||||
});
|
||||
|
@ -150,52 +152,56 @@ class LogsDropdown {
|
|||
class FetchLogs {
|
||||
constructor(prefix = "logs") {
|
||||
this.prefix = prefix;
|
||||
this.instanceInp = document.querySelector(
|
||||
`button[${this.prefix}-setting-select='instances']`
|
||||
this.instance = document.querySelector(
|
||||
`[${this.prefix}-setting-select-text="instances"]`
|
||||
);
|
||||
this.instanceName = "";
|
||||
this.updateInp = document.querySelector("input#update-date");
|
||||
this.liveUpdateInp = document.querySelector("input#live-update");
|
||||
this.updateDelayInp = document.querySelector("input#update-delay");
|
||||
this.fromDateInp = document.querySelector("input#from-date");
|
||||
this.toDateInp = document.querySelector("input#to-date");
|
||||
this.fromDate = "";
|
||||
this.toDate = "";
|
||||
|
||||
this.isLiveUpdate = false;
|
||||
this.updateDelay = 2000;
|
||||
this.lastUpdate = Math.round(Date.now() / 1000 - 86400);
|
||||
this.container = document.querySelector(`[${this.prefix}-settings]`);
|
||||
this.logListContainer = document.querySelector(`[${this.prefix}-list]`);
|
||||
this.initFetch();
|
||||
this.initLiveUpdate();
|
||||
this.submitSettings = document.querySelector("button#submit-settings");
|
||||
this.init();
|
||||
}
|
||||
|
||||
initLiveUpdate() {
|
||||
this.liveUpdateInp.addEventListener("click", (e) => {
|
||||
this.isLiveUpdate = this.liveUpdateInp.checked;
|
||||
init() {
|
||||
this.submitSettings.addEventListener("click", (e) => {
|
||||
//wait if live update previously
|
||||
if (this.isLiveUpdate) {
|
||||
setTimeout(() => {
|
||||
this.setLiveUpdate();
|
||||
const isSettings = this.getSettings();
|
||||
return isSettings ? this.getLogsFromToDate() : "";
|
||||
}, this.updateDelay);
|
||||
} else {
|
||||
const isSettings = this.getSettings();
|
||||
return isSettings ? this.getLogsFromToDate() : "";
|
||||
}
|
||||
});
|
||||
|
||||
this.updateDelayInp.addEventListener("input", (e) => {
|
||||
console.log(this.updateDelayInp.valueAsNumber);
|
||||
this.updateDelay = Math.round(this.updateDelayInp.valueAsNumber / 1000);
|
||||
console.log(this.updateDelay + " on change");
|
||||
});
|
||||
}
|
||||
|
||||
setLiveUpdate() {
|
||||
//loop
|
||||
if (this.isLiveUpdate) {
|
||||
setTimeout(() => {
|
||||
this.setLiveUpdate();
|
||||
}, this.updateDelay);
|
||||
}
|
||||
//conditions to live update
|
||||
const btnInstance = document.querySelector(
|
||||
`[${this.prefix}-setting-select-text]`
|
||||
);
|
||||
if (btnInstance.textContent === "none" || this.lastUpdate === "") return;
|
||||
//get data
|
||||
this.getInstanceLogs(btnInstance.textContent);
|
||||
getSettings() {
|
||||
//get settings
|
||||
this.instanceName = this.instance.textContent;
|
||||
if (!this.instanceName || this.instanceName.trim() === "none") return false;
|
||||
this.formDate = this.fromDateInp.valueAsNumber
|
||||
? this.fromDateInp.valueAsNumber
|
||||
: Math.round(Date.now() / 1000 - 86400);
|
||||
this.toDate = this.toDateInp.valueAsNumber
|
||||
? this.toDateInp.valueAsNumber
|
||||
: "";
|
||||
this.updateDelay =
|
||||
this.updateDelayInp.value * 1000 ? this.updateDelayInp.value : 2000;
|
||||
this.isLiveUpdate = this.liveUpdateInp.checked;
|
||||
return true;
|
||||
}
|
||||
|
||||
goBottomList() {
|
||||
|
@ -207,40 +213,24 @@ class FetchLogs {
|
|||
);
|
||||
}
|
||||
|
||||
initFetch() {
|
||||
this.container.addEventListener("click", (e) => {
|
||||
//SELECT INSTANCE
|
||||
try {
|
||||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.getAttribute(`${this.prefix}-setting-select-dropdown-btn`) ===
|
||||
"instances"
|
||||
) {
|
||||
const btn = e.target.closest("button");
|
||||
const btnValue = btn.getAttribute("value");
|
||||
//fetch data
|
||||
this.getInstanceLogs(btnValue);
|
||||
}
|
||||
} catch (err) {}
|
||||
//SELECT DATE
|
||||
this.updateInp.addEventListener("input", (e) => {
|
||||
this.lastUpdate = Math.round(this.updateInp.valueAsNumber / 1000);
|
||||
console.log(this.lastUpdate);
|
||||
//check if instance selected
|
||||
const btnInstance = document.querySelector(
|
||||
`[${this.prefix}-setting-select-text]`
|
||||
);
|
||||
if (btnInstance.textContent.trim() === "none") return;
|
||||
//fetch data
|
||||
this.getInstanceLogs(btnInstance.textContent);
|
||||
});
|
||||
});
|
||||
async getLogsFromToDate() {
|
||||
const response = await fetch(
|
||||
`${location.href}/${this.lastUpdate}?from_date=${this.fromDate}?to_date=${this.toDate}`
|
||||
);
|
||||
|
||||
if (response.status === 200) {
|
||||
const res = await response.json();
|
||||
//last update
|
||||
return await this.showLogs(res);
|
||||
} else {
|
||||
console.log(`Error: ${response.status}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async getInstanceLogs(instanceName) {
|
||||
async getLogsSinceLastUpdate() {
|
||||
const response = await fetch(
|
||||
`${location.href}/${instanceName}` +
|
||||
`${location.href}/${this.lastUpdate}` +
|
||||
(this.lastUpdate ? `?last_update=${this.lastUpdate}` : "")
|
||||
);
|
||||
|
||||
|
@ -256,7 +246,6 @@ class FetchLogs {
|
|||
|
||||
async showLogs(res) {
|
||||
this.lastUpdate = res.last_update;
|
||||
console.log(this.lastUpdate);
|
||||
res.logs.forEach((log) => {
|
||||
//container
|
||||
const logContainer = document.createElement("li");
|
||||
|
@ -279,9 +268,16 @@ class FetchLogs {
|
|||
//show on DOM
|
||||
this.logListContainer.appendChild(logContainer);
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.goBottomList();
|
||||
}, 100);
|
||||
//loop if true
|
||||
if (this.isLiveUpdate) {
|
||||
setTimeout(() => {
|
||||
this.getLogsSinceLastUpdate();
|
||||
}, this.updateDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,8 +286,6 @@ class FilterLogs {
|
|||
this.prefix = prefix;
|
||||
this.container = document.querySelector(`[${this.prefix}-filter]`);
|
||||
this.keyInp = document.querySelector("input#keyword");
|
||||
this.fromDateInp = document.querySelector("input#from-date");
|
||||
this.toDateInp = document.querySelector("input#to-date");
|
||||
this.lastType = "";
|
||||
this.initHandler();
|
||||
}
|
||||
|
@ -311,7 +305,7 @@ class FilterLogs {
|
|||
const btnSetting = btn.getAttribute(
|
||||
`${this.prefix}-setting-select-dropdown-btn`
|
||||
);
|
||||
if (this.lastType === btnValue) return;
|
||||
|
||||
this.lastType = btnValue;
|
||||
//run filter
|
||||
this.filter();
|
||||
|
@ -322,14 +316,6 @@ class FilterLogs {
|
|||
this.keyInp.addEventListener("input", (e) => {
|
||||
this.filter();
|
||||
});
|
||||
//FROM DATE
|
||||
this.fromDateInp.addEventListener("input", (e) => {
|
||||
this.filter();
|
||||
});
|
||||
//TO DATE
|
||||
this.toDateInp.addEventListener("input", (e) => {
|
||||
this.filter();
|
||||
});
|
||||
}
|
||||
|
||||
filter() {
|
||||
|
@ -343,23 +329,19 @@ class FilterLogs {
|
|||
//filter type
|
||||
this.setFilterType(logs);
|
||||
this.setFilterKeyword(logs);
|
||||
console.log("start date filtering");
|
||||
this.setFilterDate(logs);
|
||||
}
|
||||
|
||||
setFilterType(logs) {
|
||||
const type = document.querySelector(
|
||||
`[${this.prefix}-setting-select-text="types"]`
|
||||
).textContent;
|
||||
if (type === "all") return;
|
||||
if (this.lastType === "all") return;
|
||||
|
||||
for (let i = 0; i < logs.length; i++) {
|
||||
const el = logs[i];
|
||||
const typeEl = el.querySelector("[logs-type]");
|
||||
if (type !== "misc" && typeEl.textContent !== type)
|
||||
if (this.lastType !== "misc" && typeEl.textContent !== this.lastType)
|
||||
el.classList.add("hidden");
|
||||
if (
|
||||
type === "misc" &&
|
||||
this.lastType === "misc" &&
|
||||
typeEl.textContent !== "info" &&
|
||||
typeEl.textContent !== "message"
|
||||
)
|
||||
|
@ -376,124 +358,6 @@ class FilterLogs {
|
|||
if (!content.includes(keyword)) el.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
setFilterDate(logs) {
|
||||
//get date as timestamp to check if valid
|
||||
const isValidDate = this.isDateIntervalValid(
|
||||
this.fromDateInp.valueAsNumber,
|
||||
this.toDateInp.valueAsNumber
|
||||
);
|
||||
if (!isValidDate) return console.log("date invalid");
|
||||
this.setFromDate(logs);
|
||||
this.setToDate(logs);
|
||||
}
|
||||
|
||||
setToDate(logs) {
|
||||
//if from date value exist
|
||||
if (this.toDateInp.valueAsNumber) {
|
||||
//get it
|
||||
const toDate = this.toDateInp.value.split("-");
|
||||
const toMonthStr = this.monthNumToStr(toDate[1]);
|
||||
//stop if last log is after to date
|
||||
const isAfter = this.isToDateAfterLastLog();
|
||||
if (isAfter === true) return console.log("after");
|
||||
//else loop from bottom to top list
|
||||
for (let i = 0; i < logs.length; i++) {
|
||||
const el = logs[logs.length - 1 - i];
|
||||
const content = el.querySelector("[logs-content]").textContent;
|
||||
//all date format we can find on logs
|
||||
if (
|
||||
content.includes(`${toDate[0]}/${toDate[1]}/${toDate[2]}`) ||
|
||||
content.includes(`${toDate[0]}-${toDate[1]}-${toDate[2]}`) ||
|
||||
content.includes(`${toDate[0]}/${toMonthStr}/${toDate[2]}`)
|
||||
)
|
||||
break;
|
||||
|
||||
el.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isToDateAfterLastLog() {
|
||||
const lastLogContent = document
|
||||
.querySelector(`[${this.prefix}-list]`)
|
||||
.lastElementChild.querySelector("[logs-content]")
|
||||
.textContent.replaceAll(":", " ")
|
||||
.replaceAll("[", "[ ");
|
||||
|
||||
const lastLogDate = lastLogContent.match(
|
||||
/(\d{4}([\/.-])(\d{2}|\D{3})([\/.-])\d{2} | \d{2}([\/])(\d{2}|\D{3})([\/])\d{4})/g
|
||||
);
|
||||
const lastLogStamp = new Date(lastLogDate).getTime();
|
||||
console.log(
|
||||
"last log " + lastLogStamp + " input: " + this.toDateInp.valueAsNumber
|
||||
);
|
||||
|
||||
return this.toDateInp.valueAsNumber > lastLogStamp ? true : false;
|
||||
}
|
||||
setFromDate(logs) {
|
||||
//if from date value exist
|
||||
if (this.fromDateInp.valueAsNumber) {
|
||||
//get it
|
||||
const fromDate = this.fromDateInp.value.split("-");
|
||||
const fromMonthStr = this.monthNumToStr(fromDate[1]);
|
||||
//stop if first log is before date
|
||||
const isBefore = this.isFromDateBeforeFirstlog();
|
||||
if (isBefore === true) return;
|
||||
//else loop from top to bottom list
|
||||
for (let i = 0; i < logs.length; i++) {
|
||||
const el = logs[i];
|
||||
const content = el.querySelector("[logs-content]").textContent;
|
||||
//all date format we can find on logs
|
||||
if (
|
||||
content.includes(`${fromDate[0]}/${fromDate[1]}/${fromDate[2]}`) ||
|
||||
content.includes(`${fromDate[0]}-${fromDate[1]}-${fromDate[2]}`) ||
|
||||
content.includes(`${fromDate[0]}/${fromMonthStr}/${fromDate[2]}`)
|
||||
)
|
||||
break;
|
||||
|
||||
el.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isFromDateBeforeFirstlog() {
|
||||
const firstLogContent = document
|
||||
.querySelector(`[${this.prefix}-list]`)
|
||||
.firstElementChild.querySelector("[logs-content]").textContent;
|
||||
|
||||
const firstLogDate = firstLogContent.match(
|
||||
/(\d{4}([\/.-])(\d{2}|\D{3})([\/.-])\d{2} | \d{2}([\/])(\d{2}|\D{3})([\/])\d{4})/g
|
||||
);
|
||||
|
||||
const firstLogStamp = new Date(firstLogDate).getTime();
|
||||
return this.fromDateInp.valueAsNumber <= firstLogStamp ? true : false;
|
||||
}
|
||||
|
||||
isDateIntervalValid(fromDate, toDate) {
|
||||
//case one date
|
||||
if (fromDate === NaN || toDate === NaN) return false;
|
||||
if (fromDate >= toDate) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
monthNumToStr(month) {
|
||||
const monthStr = [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec",
|
||||
];
|
||||
return monthStr[+month - 1];
|
||||
}
|
||||
}
|
||||
|
||||
const setCheckbox = new Checkbox("[logs-settings]");
|
||||
|
|
|
@ -3,7 +3,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
<!-- filter -->
|
||||
<div
|
||||
{{current_endpoint}}-filter
|
||||
class="col-span-12 lg:col-span-6 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"
|
||||
class="col-span-12 lg:col-span-12 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">FILTER</h5>
|
||||
<div class="grid grid-cols-12 gap-x-4 gap-y-2">
|
||||
|
@ -178,25 +178,25 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
<p
|
||||
class="dark:text-gray-300 h-8 text-sm font-bold col-span-2 m-0 pb-2 border-b border-gray-400"
|
||||
>
|
||||
plugin
|
||||
Last run
|
||||
</p>
|
||||
<p
|
||||
class="dark:text-gray-300 h-8 text-sm font-bold col-span-2 m-0 pb-2 border-b border-gray-400"
|
||||
>
|
||||
Date
|
||||
Every
|
||||
</p>
|
||||
<p
|
||||
class="dark:text-gray-300 h-8 text-sm font-bold col-span-1 m-0 pb-2 border-b border-gray-400"
|
||||
class="dark:text-gray-300 h-8 text-sm font-bold col-span-2 m-0 pb-2 border-b border-gray-400"
|
||||
>
|
||||
Reload
|
||||
</p>
|
||||
<p
|
||||
class="dark:text-gray-300 h-8 text-sm font-bold col-span-1 m-0 pb-2 border-b border-gray-400"
|
||||
class="dark:text-gray-300 h-8 text-sm font-bold col-span-2 m-0 pb-2 border-b border-gray-400"
|
||||
>
|
||||
Success
|
||||
</p>
|
||||
<p
|
||||
class="dark:text-gray-300 h-8 text-sm font-bold col-span-3 m-0 pb-2 border-b border-gray-400"
|
||||
class="dark:text-gray-300 h-8 text-sm font-bold col-span-1 m-0 pb-2 border-b border-gray-400"
|
||||
>
|
||||
Files
|
||||
</p>
|
||||
|
@ -206,20 +206,20 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
class="col-span-12 w-full max-h-100 overflow-y-auto"
|
||||
{{current_endpoint}}-list
|
||||
>
|
||||
{{% for job in jobs %}}
|
||||
{% for job in jobs %}
|
||||
<!-- job item-->
|
||||
<li class="grid grid-cols-12 border-b border-gray-300 py-2">
|
||||
<p
|
||||
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-3 m-0"
|
||||
{{current_endpoint}}-name
|
||||
>
|
||||
{{job["name"]}}
|
||||
{{job}}
|
||||
</p>
|
||||
<p
|
||||
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-2 m-0"
|
||||
{{current_endpoint}}-plugin-id
|
||||
{{current_endpoint}}-last_run
|
||||
>
|
||||
{{job["plugin_id"]}}
|
||||
{{job["last_run"]}}
|
||||
</p>
|
||||
<p
|
||||
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-2 m-0"
|
||||
|
@ -228,10 +228,10 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
{{job["every"]}}
|
||||
</p>
|
||||
<p
|
||||
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-1 m-0"
|
||||
class="ml-6 dark:text-gray-400 dark:opacity-80 text-sm col-span-2 m-0"
|
||||
{{current_endpoint}}-reload
|
||||
>
|
||||
{% if job["reload"]%}
|
||||
{% if job["reload"] %}
|
||||
<svg
|
||||
class="fill-green-500 h-5 w-5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -241,7 +241,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
d="M256 512c141.4 0 256-114.6 256-256S397.4 0 256 0S0 114.6 0 256S114.6 512 256 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"
|
||||
/>
|
||||
</svg>
|
||||
{% else %}
|
||||
{%endif %} {% if not job["reload"] %}
|
||||
<svg
|
||||
class="fill-red-500 h-5 w-5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -251,23 +251,13 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
d="M256 512c141.4 0 256-114.6 256-256S397.4 0 256 0S0 114.6 0 256S114.6 512 256 512zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"
|
||||
/>
|
||||
</svg>
|
||||
{% else %}
|
||||
<svg
|
||||
class="fill-sky-500 h-5 w-5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
d="M256 512c141.4 0 256-114.6 256-256S397.4 0 256 0S0 114.6 0 256S114.6 512 256 512zM169.8 165.3c7.9-22.3 29.1-37.3 52.8-37.3h58.3c34.9 0 63.1 28.3 63.1 63.1c0 22.6-12.1 43.5-31.7 54.8L280 264.4c-.2 13-10.9 23.6-24 23.6c-13.3 0-24-10.7-24-24V250.5c0-8.6 4.6-16.5 12.1-20.8l44.3-25.4c4.7-2.7 7.6-7.7 7.6-13.1c0-8.4-6.8-15.1-15.1-15.1H222.6c-3.4 0-6.4 2.1-7.5 5.3l-.4 1.2c-4.4 12.5-18.2 19-30.6 14.6s-19-18.2-14.6-30.6l.4-1.2zM288 352c0 17.7-14.3 32-32 32s-32-14.3-32-32s14.3-32 32-32s32 14.3 32 32z"
|
||||
/>
|
||||
</svg>
|
||||
{% endif %}
|
||||
</p>
|
||||
<p
|
||||
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-1 m-0"
|
||||
class="ml-6 dark:text-gray-400 dark:opacity-80 text-sm col-span-2 m-0"
|
||||
{{current_endpoint}}-success
|
||||
>
|
||||
{% if job["success"] %}
|
||||
{% if job["success"] == True %}
|
||||
<svg
|
||||
class="fill-green-500 h-5 w-5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -300,14 +290,12 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
{% endif %}
|
||||
</p>
|
||||
<p
|
||||
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-3 m-0"
|
||||
{{current_endpoint}}-cache_file
|
||||
>
|
||||
{{job["cache_file"]}}
|
||||
</p>
|
||||
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-1 m-0"
|
||||
{{current_endpoint}}-files
|
||||
></p>
|
||||
</li>
|
||||
<!-- end job item-->
|
||||
{{% endfor %}}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<!-- end list-->
|
||||
</div>
|
||||
|
|
|
@ -4,12 +4,14 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
<!-- settings -->
|
||||
<div
|
||||
{{current_endpoint}}-settings
|
||||
class="col-span-12 lg:col-span-6 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"
|
||||
class="col-span-12 lg:col-span-8 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">SETTINGS</h5>
|
||||
<div class="grid grid-cols-12 gap-x-4 gap-y-2">
|
||||
<!-- select instance -->
|
||||
<div class="flex flex-col relative col-span-12 sm:col-span-6">
|
||||
<div
|
||||
class="flex flex-col relative col-span-12 sm:col-span-6 lg:col-span-4 3xl:col-span-3"
|
||||
>
|
||||
<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"
|
||||
>
|
||||
|
@ -60,26 +62,49 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
</div>
|
||||
<!-- end select instance -->
|
||||
<!-- from date input -->
|
||||
<div class="flex flex-col relative col-span-12 sm:col-span-6">
|
||||
<div
|
||||
class="flex flex-col relative col-span-12 sm:col-span-6 lg:col-span-4 3xl:col-span-3"
|
||||
>
|
||||
<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"
|
||||
>
|
||||
Fetch (default 1 day)
|
||||
From date
|
||||
</h5>
|
||||
<input
|
||||
datetimepicker
|
||||
type="date"
|
||||
id="update-date"
|
||||
name="update-date"
|
||||
class="col-span-12 sm:col-span-6 lg:col-span-4 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="update date"
|
||||
id="from-date"
|
||||
name="from-date"
|
||||
class="col-span-12 sm:col-span-6 lg:col-span-4 3xl:col-span-3 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="from date"
|
||||
pattern="(.*?)"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<!-- end from date input -->
|
||||
<!-- to date input -->
|
||||
<div
|
||||
class="flex flex-col relative col-span-12 sm:col-span-6 lg:col-span-4 3xl:col-span-3"
|
||||
>
|
||||
<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"
|
||||
>
|
||||
To date
|
||||
</h5>
|
||||
<input
|
||||
type="date"
|
||||
id="to-date"
|
||||
name="to-date"
|
||||
class="col-span-12 sm:col-span-6 lg:col-span-4 3xl:col-span-3 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="to date"
|
||||
pattern="(.*?)"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<!-- end to date input -->
|
||||
<!-- refresh input -->
|
||||
<div class="flex flex-col relative col-span-12 sm:col-span-6">
|
||||
<div
|
||||
class="flex flex-col relative col-span-12 sm:col-span-6 lg:col-span-4 3xl:col-span-3"
|
||||
>
|
||||
<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"
|
||||
>
|
||||
|
@ -107,7 +132,9 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
</div>
|
||||
<!-- end refresh input -->
|
||||
<!-- refresh delay input -->
|
||||
<div class="flex flex-col relative col-span-12 sm:col-span-6">
|
||||
<div
|
||||
class="flex flex-col relative col-span-12 sm:col-span-6 lg:col-span-4 3xl:col-span-3"
|
||||
>
|
||||
<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"
|
||||
>
|
||||
|
@ -117,13 +144,22 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
type="number"
|
||||
id="update-delay"
|
||||
name="update-delay"
|
||||
class="col-span-12 sm:col-span-6 lg:col-span-4 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"
|
||||
class="col-span-12 sm:col-span-6 lg:col-span-4 3xl:col-span-3 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="2"
|
||||
pattern="(.*?)"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<!-- end refresh delay input -->
|
||||
<div class="col-span-12 w-full justify-center flex">
|
||||
<button
|
||||
type="button"
|
||||
id="submit-settings"
|
||||
class="dark:brightness-90 inline-block px-6 py-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-gradient-to-tl bg-primary hover:bg-primary/80 focus:bg-primary/80 leading-normal text-sm ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end settings -->
|
||||
|
@ -131,12 +167,12 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
<!-- filter -->
|
||||
<div
|
||||
{{current_endpoint}}-filter
|
||||
class="col-span-12 lg:col-span-6 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"
|
||||
class="col-span-12 lg: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">FILTERS</h5>
|
||||
<div class="grid grid-cols-12 gap-x-4 gap-y-2">
|
||||
<!-- search inpt-->
|
||||
<div class="flex flex-col relative col-span-12 sm:col-span-6">
|
||||
<div class="flex flex-col relative col-span-12">
|
||||
<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"
|
||||
>
|
||||
|
@ -146,7 +182,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
type="text"
|
||||
id="keyword"
|
||||
name="keyword"
|
||||
class="col-span-12 sm:col-span-6 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"
|
||||
class="col-span-12 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="key words"
|
||||
pattern="(.*?)"
|
||||
required
|
||||
|
@ -154,7 +190,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
</div>
|
||||
<!-- end search inpt-->
|
||||
<!-- select types -->
|
||||
<div class="flex flex-col relative col-span-12 sm:col-span-6">
|
||||
<div class="flex flex-col relative col-span-12">
|
||||
<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"
|
||||
>
|
||||
|
@ -241,44 +277,6 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
<!-- end dropdown-->
|
||||
</div>
|
||||
<!-- end select types -->
|
||||
<!-- from date input -->
|
||||
<div class="flex flex-col relative col-span-12 sm:col-span-6">
|
||||
<h5
|
||||
class="my-1 transition duration-300 ease-in-out dark:opacity-90 text-sm sm:text-md font-bold m-0 dark:text-gray-300"
|
||||
>
|
||||
From date
|
||||
</h5>
|
||||
<input
|
||||
datetimepicker
|
||||
type="date"
|
||||
id="from-date"
|
||||
name="from-date"
|
||||
class="col-span-12 sm:col-span-6 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="from date"
|
||||
pattern="(.*?)"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<!-- end from date input -->
|
||||
<!-- to date input -->
|
||||
<div class="flex flex-col relative col-span-12 sm:col-span-6">
|
||||
<h5
|
||||
class="my-1 transition duration-300 ease-in-out dark:opacity-90 text-sm sm:text-md font-bold m-0 dark:text-gray-300"
|
||||
>
|
||||
To date
|
||||
</h5>
|
||||
<input
|
||||
datetimepicker
|
||||
type="date"
|
||||
id="to-date"
|
||||
name="to-date"
|
||||
class="col-span-12 sm:col-span-6 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="to date"
|
||||
pattern="(.*?)"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<!-- end to date input -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- end filter -->
|
||||
|
|
Loading…
Reference in New Issue