Merge branch 'dev' of github.com:bunkerity/bunkerweb into dev
This commit is contained in:
commit
aa3ce13a81
|
@ -279,6 +279,22 @@ You can use the following settings to set up whitelisting :
|
|||
| `WHITELIST_USER_AGENT_URLS` | | List of URLs containing User-Agent to whitelist. |
|
||||
| `WHITELIST_URI` | | List of requests URI to whitelist. |
|
||||
| `WHITELIST_URI_URLS` | | List of URLs containing request(s) URI to whitelist. |
|
||||
## ReverseScan
|
||||
|
||||
ReverseScan" is a feature designed to detect open ports by establishing TCP connections with clients' IP addresses.
|
||||
Consider adding this feature if you want to detect possible open proxies or connections from servers.
|
||||
|
||||
We provide a list of suspicious ports by default, but it can be modified to fit your needs.Be mindful, Adding too many ports to the list can significantly slow down clients' connections due to the caching process.If a listed port is open, the client's access will be denied.
|
||||
|
||||
Please be aware, this feature is new and further improvements will be added soon.
|
||||
|
||||
Here is the list of settings related to ReverseScan:
|
||||
|
||||
| Setting | Default | Description |
|
||||
| :----------: | :--------------------------------------------------------------------------: | :--------------------------------------------- |
|
||||
| `USE_REVERSE_SCAN` | `no` | When set to `yes`, will enable ReverseScan. |
|
||||
| `REVERSE_SCAN_PORTS` | `22 80 443 3128 8000 8080` | List of suspicious ports to scan. |
|
||||
| `REVERSE_SCAN_TIMEOUT` | `500` | Specify the maximum timeout (in ms) when scanning a port. |
|
||||
|
||||
## BunkerNet
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ Because the web UI is a web application, the recommended installation procedure
|
|||
-e bwadm.example.com_REVERSE_PROXY_URL=/changeme/ \
|
||||
-e bwadm.example.com_REVERSE_PROXY_HOST=http://bw-ui:7000 \
|
||||
-e "bwadm.example.com_REVERSE_PROXY_HEADERS=X-Script-Name /changeme" \
|
||||
-e bwadm.example.com_INTERCEPTED_ERROR_CODES="400 401 405 413 429 500 501 502 503 504" \
|
||||
-e bwadm.example.com_INTERCEPTED_ERROR_CODES="400 401 404 405 413 429 500 501 502 503 504" \
|
||||
-l bunkerweb.INSTANCE \
|
||||
bunkerity/bunkerweb:1.5.0-beta && \
|
||||
docker network connect bw-universe bunkerweb
|
||||
|
@ -645,7 +645,7 @@ Because the web UI is a web application, the recommended installation procedure
|
|||
- bunkerweb.REVERSE_PROXY_URL=/changeme
|
||||
- bunkerweb.REVERSE_PROXY_HOST=http://bw-ui:7000
|
||||
- bunkerweb.REVERSE_PROXY_HEADERS=X-Script-Name /changeme
|
||||
- bunkerweb.INTERCEPTED_ERROR_CODES=400 401 405 413 429 500 501 502 503 504
|
||||
- bunkerweb.INTERCEPTED_ERROR_CODES=400 401 404 405 413 429 500 501 502 503 504
|
||||
|
||||
volumes:
|
||||
bw-data:
|
||||
|
|
|
@ -186,7 +186,11 @@ if __name__ == "__main__":
|
|||
retries += 1
|
||||
sleep(5)
|
||||
|
||||
proc = run(["nginx", "-s", "reload"], stdin=DEVNULL, stderr=STDOUT)
|
||||
proc = run(
|
||||
["sudo", "/usr/sbin/nginx", "-s", "reload"],
|
||||
stdin=DEVNULL,
|
||||
stderr=STDOUT,
|
||||
)
|
||||
if proc.returncode != 0:
|
||||
status = 1
|
||||
logger.error("Error while reloading nginx")
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from datetime import datetime
|
||||
from logging import (
|
||||
CRITICAL,
|
||||
DEBUG,
|
||||
|
@ -31,10 +30,6 @@ class BWLogger(Logger):
|
|||
stack_info=False,
|
||||
stacklevel=1,
|
||||
):
|
||||
if self.name == "UI":
|
||||
with open("/var/log/nginx/ui.log", "a") as f:
|
||||
f.write(f"[{datetime.now().replace(microsecond=0)}] {msg}\n")
|
||||
|
||||
return super(BWLogger, self)._log(
|
||||
level, msg, args, exc_info, extra, stack_info, stacklevel
|
||||
)
|
||||
|
|
|
@ -5,7 +5,7 @@ After=bunkerweb.service
|
|||
|
||||
[Service]
|
||||
Restart=no
|
||||
User=root
|
||||
User=nginx
|
||||
PIDFile=/var/tmp/bunkerweb/ui.pid
|
||||
ExecStart=/usr/share/bunkerweb/scripts/bunkerweb-ui.sh start
|
||||
ExecStop=/usr/share/bunkerweb/scripts/bunkerweb-ui.sh stop
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Set the PYTHONPATH
|
||||
export PYTHONPATH=/usr/share/bunkerweb/deps/python
|
||||
export PYTHONPATH=/usr/share/bunkerweb/deps/python:/usr/share/bunkerweb/ui
|
||||
|
||||
# Create the ui.env file if it doesn't exist
|
||||
if [ ! -f /etc/bunkerweb/ui.env ]; then
|
||||
echo "ADMIN_USERNAME=admin" > /etc/bunkerweb/ui.env
|
||||
echo "ADMIN_PASSWORD=changeme" >> /etc/bunkerweb/ui.env
|
||||
echo "ABSOLUTE_URI=http://mydomain.ext/mypath/" >> /etc/bunkerweb/ui.env
|
||||
echo "ABSOLUTE_URI=http://bwadm.example.com/changeme/" >> /etc/bunkerweb/ui.env
|
||||
fi
|
||||
|
||||
# Function to start the UI
|
||||
|
@ -18,7 +18,7 @@ start() {
|
|||
fi
|
||||
source /etc/bunkerweb/ui.env
|
||||
export $(cat /etc/bunkerweb/ui.env)
|
||||
python3 -m gunicorn --graceful-timeout=0 --bind=127.0.0.1:7000 --chdir /usr/share/bunkerweb/ui/ --workers=1 --threads=4 main:app &
|
||||
python3 -m gunicorn main:app --worker-class gevent --bind 127.0.0.1:7000 --graceful-timeout 0 --access-logfile - --error-logfile - &
|
||||
echo $! > /var/tmp/bunkerweb/ui.pid
|
||||
}
|
||||
|
||||
|
|
|
@ -80,9 +80,12 @@ function start() {
|
|||
|
||||
log "SYSTEMCTL" "ℹ️" "Starting BunkerWeb service ..."
|
||||
|
||||
echo "nginx ALL=(ALL) NOPASSWD: /usr/sbin/nginx" > /etc/sudoers.d/bunkerweb
|
||||
chown -R nginx:nginx /etc/nginx
|
||||
|
||||
# Create dummy variables.env
|
||||
if [ ! -f /etc/bunkerweb/variables.env ]; then
|
||||
echo -ne "# remove IS_LOADING=yes when your config is ready\nIS_LOADING=yes\nHTTP_PORT=80\nHTTPS_PORT=443\nAPI_LISTEN_IP=127.0.0.1\nSERVER_NAME=\n" > /etc/bunkerweb/variables.env
|
||||
sudo -E -u nginx -g nginx /bin/bash -c "echo -ne '\# remove IS_LOADING=yes when your config is ready\nIS_LOADING=yes\nHTTP_PORT=80\nHTTPS_PORT=443\nAPI_LISTEN_IP=127.0.0.1\nSERVER_NAME=\n' > /etc/bunkerweb/variables.env"
|
||||
log "SYSTEMCTL" "ℹ️" "Created dummy variables.env file"
|
||||
fi
|
||||
|
||||
|
@ -101,8 +104,8 @@ function start() {
|
|||
if [ "$HTTPS_PORT" = "" ] ; then
|
||||
HTTPS_PORT="8443"
|
||||
fi
|
||||
echo -ne "IS_LOADING=yes\nHTTP_PORT=${HTTP_PORT}\nHTTPS_PORT=${HTTPS_PORT}\nAPI_LISTEN_IP=127.0.0.1\nSERVER_NAME=\n" > /var/tmp/bunkerweb/tmp.env
|
||||
/usr/share/bunkerweb/gen/main.py --variables /var/tmp/bunkerweb/tmp.env --no-linux-reload
|
||||
sudo -E -u nginx -g nginx /bin/bash -c "echo -ne 'IS_LOADING=yes\nHTTP_PORT=${HTTP_PORT}\nHTTPS_PORT=${HTTPS_PORT}\nAPI_LISTEN_IP=127.0.0.1\nSERVER_NAME=\n' > /var/tmp/bunkerweb/tmp.env"
|
||||
sudo -E -u nginx -g nginx /bin/bash -c "/usr/share/bunkerweb/gen/main.py --variables /var/tmp/bunkerweb/tmp.env --no-linux-reload"
|
||||
if [ $? -ne 0 ] ; then
|
||||
log "SYSTEMCTL" "❌" "Error while generating config from /var/tmp/bunkerweb/tmp.env"
|
||||
exit 1
|
||||
|
@ -134,9 +137,9 @@ function start() {
|
|||
# Update database
|
||||
log "SYSTEMCTL" "ℹ️" "Updating database ..."
|
||||
if [ ! -f /var/lib/bunkerweb/db.sqlite3 ]; then
|
||||
/usr/share/bunkerweb/gen/save_config.py --variables /etc/bunkerweb/variables.env --init
|
||||
else
|
||||
/usr/share/bunkerweb/gen/save_config.py --variables /etc/bunkerweb/variables.env
|
||||
sudo -E -u nginx -g nginx /bin/bash -c "/usr/share/bunkerweb/gen/save_config.py --variables /etc/bunkerweb/variables.env --init"
|
||||
else
|
||||
sudo -E -u nginx -g nginx /bin/bash -c "/usr/share/bunkerweb/gen/save_config.py --variables /etc/bunkerweb/variables.env"
|
||||
fi
|
||||
if [ $? -ne 0 ] ; then
|
||||
log "SYSTEMCTL" "❌" "save_config failed"
|
||||
|
@ -146,7 +149,7 @@ function start() {
|
|||
|
||||
# Execute scheduler
|
||||
log "SYSTEMCTL" "ℹ️ " "Executing scheduler ..."
|
||||
/usr/share/bunkerweb/scheduler/main.py --variables /etc/bunkerweb/variables.env
|
||||
sudo -E -u nginx -g nginx /bin/bash -c "/usr/share/bunkerweb/scheduler/main.py --variables /etc/bunkerweb/variables.env"
|
||||
if [ "$?" -ne 0 ] ; then
|
||||
log "SYSTEMCTL" "❌" "Scheduler failed"
|
||||
exit 1
|
||||
|
|
|
@ -79,7 +79,10 @@ class JobScheduler(ApiCaller):
|
|||
if self.__integration not in ("Autoconf", "Swarm", "Kubernetes", "Docker"):
|
||||
self.__logger.info("Reloading nginx ...")
|
||||
proc = run(
|
||||
["nginx", "-s", "reload"], stdin=DEVNULL, stderr=PIPE, env=self.__env
|
||||
["sudo", "/usr/sbin/nginx", "-s", "reload"],
|
||||
stdin=DEVNULL,
|
||||
stderr=PIPE,
|
||||
env=self.__env,
|
||||
)
|
||||
reload = proc.returncode == 0
|
||||
if reload:
|
||||
|
|
|
@ -315,9 +315,6 @@ if __name__ == "__main__":
|
|||
"Looks like BunkerWeb configuration is already generated, will not generate it again ..."
|
||||
)
|
||||
|
||||
if Path("/var/lib/bunkerweb/db.sqlite3").exists():
|
||||
chmod("/var/lib/bunkerweb/db.sqlite3", 0o760)
|
||||
|
||||
first_run = True
|
||||
while True:
|
||||
# Instantiate scheduler
|
||||
|
@ -386,7 +383,7 @@ if __name__ == "__main__":
|
|||
# Stop temp nginx
|
||||
logger.info("Stopping temp nginx ...")
|
||||
proc = subprocess_run(
|
||||
["/usr/sbin/nginx", "-s", "stop"],
|
||||
["sudo", "/usr/sbin/nginx", "-s", "stop"],
|
||||
stdin=DEVNULL,
|
||||
stderr=STDOUT,
|
||||
env=deepcopy(env),
|
||||
|
@ -408,7 +405,7 @@ if __name__ == "__main__":
|
|||
# Start nginx
|
||||
logger.info("Starting nginx ...")
|
||||
proc = subprocess_run(
|
||||
["/usr/sbin/nginx"],
|
||||
["sudo", "/usr/sbin/nginx"],
|
||||
stdin=DEVNULL,
|
||||
stderr=STDOUT,
|
||||
env=deepcopy(env),
|
||||
|
@ -475,7 +472,7 @@ if __name__ == "__main__":
|
|||
# Reloading the nginx server.
|
||||
proc = subprocess_run(
|
||||
# Reload nginx
|
||||
["/usr/sbin/nginx", "-s", "reload"],
|
||||
["sudo", "/usr/sbin/nginx", "-s", "reload"],
|
||||
stdin=DEVNULL,
|
||||
stderr=STDOUT,
|
||||
env=deepcopy(env),
|
||||
|
|
|
@ -55,13 +55,13 @@ from kubernetes.client.exceptions import ApiException as kube_ApiException
|
|||
from os import _exit, getenv, getpid, listdir
|
||||
from re import match as re_match
|
||||
from requests import get
|
||||
from shutil import move, rmtree, copytree
|
||||
from shutil import move, rmtree
|
||||
from signal import SIGINT, signal, SIGTERM
|
||||
from subprocess import PIPE, Popen, call
|
||||
from tarfile import CompressionError, HeaderError, ReadError, TarError, open as tar_open
|
||||
from threading import Thread
|
||||
from tempfile import NamedTemporaryFile
|
||||
from time import time
|
||||
from time import sleep, time
|
||||
from traceback import format_exc
|
||||
from typing import Optional
|
||||
from zipfile import BadZipFile, ZipFile
|
||||
|
@ -80,10 +80,6 @@ from utils import (
|
|||
from logger import setup_logger
|
||||
from Database import Database
|
||||
|
||||
if not Path("/var/log/nginx/ui.log").exists():
|
||||
Path("/var/log/nginx").mkdir(parents=True, exist_ok=True)
|
||||
Path("/var/log/nginx/ui.log").touch()
|
||||
|
||||
logger = setup_logger("UI", getenv("LOG_LEVEL", "INFO"))
|
||||
|
||||
|
||||
|
@ -113,8 +109,8 @@ def handle_stop(signum, frame):
|
|||
signal(SIGINT, handle_stop)
|
||||
signal(SIGTERM, handle_stop)
|
||||
|
||||
|
||||
Path("/var/tmp/bunkerweb/ui.pid").write_text(str(getpid()))
|
||||
if not Path("/var/tmp/bunkerweb/ui.pid").is_file():
|
||||
Path("/var/tmp/bunkerweb/ui.pid").write_text(str(getpid()))
|
||||
|
||||
# Flask app
|
||||
app = Flask(
|
||||
|
@ -187,6 +183,24 @@ elif integration == "Kubernetes":
|
|||
kubernetes_client = kube_client.CoreV1Api()
|
||||
|
||||
db = Database(logger)
|
||||
|
||||
while not db.is_initialized():
|
||||
logger.warning(
|
||||
"Database is not initialized, retrying in 5s ...",
|
||||
)
|
||||
sleep(5)
|
||||
|
||||
env = db.get_config()
|
||||
while not db.is_first_config_saved() or not env:
|
||||
logger.warning(
|
||||
"Database doesn't have any config saved yet, retrying in 5s ...",
|
||||
)
|
||||
sleep(5)
|
||||
env = db.get_config()
|
||||
|
||||
logger.info("Database is ready")
|
||||
Path("/var/tmp/bunkerweb/ui.healthy").write_text("ok")
|
||||
|
||||
with open("/usr/share/bunkerweb/VERSION", "r") as f:
|
||||
bw_version = f.read().strip()
|
||||
|
||||
|
@ -196,7 +210,7 @@ try:
|
|||
SECRET_KEY=vars["FLASK_SECRET"],
|
||||
ABSOLUTE_URI=vars["ABSOLUTE_URI"],
|
||||
INSTANCES=Instances(docker_client, kubernetes_client, integration),
|
||||
CONFIG=Config(logger, db),
|
||||
CONFIG=Config(db),
|
||||
CONFIGFILES=ConfigFiles(logger, db),
|
||||
SESSION_COOKIE_DOMAIN=vars["ABSOLUTE_URI"]
|
||||
.replace("http://", "")
|
||||
|
@ -449,7 +463,7 @@ def services():
|
|||
del variables["OLD_SERVER_NAME"]
|
||||
|
||||
# Edit check fields and remove already existing ones
|
||||
config = app.config["CONFIG"].get_config(methods=True)
|
||||
config = app.config["CONFIG"].get_config(methods=False)
|
||||
for variable, value in deepcopy(variables).items():
|
||||
if variable.endswith("SCHEMA"):
|
||||
del variables[variable]
|
||||
|
@ -460,19 +474,15 @@ def services():
|
|||
elif value == "off":
|
||||
value = "no"
|
||||
|
||||
config_setting = config.get(
|
||||
f"{variables['SERVER_NAME'].split(' ')[0]}_{variable}", None
|
||||
)
|
||||
|
||||
if variable in variables and (
|
||||
request.form["operation"] == "edit"
|
||||
and variable != "SERVER_NAME"
|
||||
and config_setting is not None
|
||||
and value == config_setting["value"]
|
||||
variable != "SERVER_NAME"
|
||||
and value == config.get(variable, None)
|
||||
or not value.strip()
|
||||
):
|
||||
del variables[variable]
|
||||
|
||||
print(variables, flush=True)
|
||||
|
||||
if len(variables) <= 1:
|
||||
flash(
|
||||
f"{variables['SERVER_NAME'].split(' ')[0]} was not edited because no values were changed."
|
||||
|
@ -630,6 +640,8 @@ def configs():
|
|||
|
||||
operation = app.config["CONFIGFILES"].check_path(variables["path"])
|
||||
|
||||
print(variables, flush=True)
|
||||
|
||||
if operation:
|
||||
flash(operation, "error")
|
||||
return redirect(url_for("loading", next=url_for("configs"))), 500
|
||||
|
@ -736,6 +748,7 @@ def plugins():
|
|||
f"Couldn't update external plugins to database: {err}",
|
||||
"error",
|
||||
)
|
||||
flash(f"Deleted plugin {variables['name']} successfully")
|
||||
else:
|
||||
if not Path("/var/tmp/bunkerweb/ui").exists() or not listdir(
|
||||
"/var/tmp/bunkerweb/ui"
|
||||
|
@ -1231,9 +1244,7 @@ def custom_plugin(plugin):
|
|||
f"The <i>actions.py</i> file for the plugin <b>{plugin}</b> does not exist",
|
||||
"error",
|
||||
)
|
||||
return redirect(
|
||||
url_for("loading", next=url_for("plugins", plugin_id=plugin))
|
||||
)
|
||||
return redirect(url_for("loading", next=url_for("plugins", plugin_id=plugin)))
|
||||
|
||||
try:
|
||||
# Try to import the custom plugin
|
||||
|
@ -1248,9 +1259,7 @@ def custom_plugin(plugin):
|
|||
f"An error occurred while importing the plugin <b>{plugin}</b>:<br/>{format_exc()}",
|
||||
"error",
|
||||
)
|
||||
return redirect(
|
||||
url_for("loading", next=url_for("plugins", plugin_id=plugin))
|
||||
)
|
||||
return redirect(url_for("loading", next=url_for("plugins", plugin_id=plugin)))
|
||||
|
||||
error = False
|
||||
res = None
|
||||
|
@ -1542,6 +1551,9 @@ def logs_container(container_id):
|
|||
log = " ".join(splitted[1:])
|
||||
log_lower = log.lower()
|
||||
|
||||
if "[48;2" in log or not log.strip():
|
||||
continue
|
||||
|
||||
logs.append(
|
||||
{
|
||||
"content": log,
|
||||
|
|
|
@ -10,36 +10,17 @@ from pathlib import Path
|
|||
from re import search as re_search
|
||||
from subprocess import run, DEVNULL, STDOUT
|
||||
from tarfile import open as tar_open
|
||||
from time import sleep
|
||||
from typing import List, Tuple
|
||||
from uuid import uuid4
|
||||
|
||||
|
||||
class Config:
|
||||
def __init__(self, logger, db) -> None:
|
||||
def __init__(self, db) -> None:
|
||||
with open("/usr/share/bunkerweb/settings.json", "r") as f:
|
||||
self.__settings: dict = json_load(f)
|
||||
|
||||
self.__logger = logger
|
||||
self.__db = db
|
||||
|
||||
while not self.__db.is_initialized():
|
||||
self.__logger.warning(
|
||||
"Database is not initialized, retrying in 5s ...",
|
||||
)
|
||||
sleep(5)
|
||||
|
||||
env = self.__db.get_config()
|
||||
while not self.__db.is_first_config_saved() or not env:
|
||||
self.__logger.warning(
|
||||
"Database doesn't have any config saved yet, retrying in 5s ...",
|
||||
)
|
||||
sleep(5)
|
||||
env = self.__db.get_config()
|
||||
|
||||
self.__logger.info("Database is ready")
|
||||
Path("/var/tmp/bunkerweb/ui.healthy").write_text("ok")
|
||||
|
||||
def __env_to_dict(self, filename: str) -> dict:
|
||||
"""Converts the content of an env file into a dict
|
||||
|
||||
|
|
|
@ -1,13 +1,29 @@
|
|||
from glob import glob
|
||||
from os import listdir, replace, walk
|
||||
from os.path import dirname, join
|
||||
from pathlib import Path
|
||||
from re import compile as re_compile
|
||||
from shutil import rmtree, move as shutil_move
|
||||
from typing import Tuple
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
from utils import path_to_dict
|
||||
|
||||
|
||||
def generate_custom_configs(
|
||||
custom_configs: List[Dict[str, Any]],
|
||||
*,
|
||||
original_path: str = "/data/configs",
|
||||
):
|
||||
Path(original_path).mkdir(parents=True, exist_ok=True)
|
||||
for custom_config in custom_configs:
|
||||
tmp_path = f"{original_path}/{custom_config['type'].replace('_', '-')}"
|
||||
if custom_config["service_id"]:
|
||||
tmp_path += f"/{custom_config['service_id']}"
|
||||
tmp_path += f"/{custom_config['name']}.conf"
|
||||
Path(dirname(tmp_path)).mkdir(parents=True, exist_ok=True)
|
||||
Path(tmp_path).write_bytes(custom_config["data"])
|
||||
|
||||
|
||||
class ConfigFiles:
|
||||
def __init__(self, logger, db):
|
||||
self.__name_regex = re_compile(r"^[a-zA-Z0-9_\-.]{1,64}$")
|
||||
|
@ -19,6 +35,21 @@ class ConfigFiles:
|
|||
self.__logger = logger
|
||||
self.__db = db
|
||||
|
||||
if not Path("/usr/sbin/nginx").is_file():
|
||||
custom_configs = self.__db.get_custom_configs()
|
||||
|
||||
if custom_configs:
|
||||
self.__logger.info("Refreshing custom configs ...")
|
||||
# Remove old custom configs files
|
||||
for file in glob("/data/configs/*"):
|
||||
if Path(file).is_symlink() or Path(file).is_file():
|
||||
Path(file).unlink()
|
||||
elif Path(file).is_dir():
|
||||
rmtree(file, ignore_errors=False)
|
||||
|
||||
generate_custom_configs(custom_configs)
|
||||
self.__logger.info("Custom configs refreshed successfully")
|
||||
|
||||
def save_configs(self) -> str:
|
||||
custom_configs = []
|
||||
root_dirs = listdir("/etc/bunkerweb/configs")
|
||||
|
@ -109,8 +140,8 @@ class ConfigFiles:
|
|||
return f"The file {file_path} was successfully created", 0
|
||||
|
||||
def edit_folder(self, path: str, name: str, old_name: str) -> Tuple[str, int]:
|
||||
new_folder_path = dirname(join(path, name))
|
||||
old_folder_path = dirname(join(path, old_name))
|
||||
new_folder_path = join(dirname(path), name)
|
||||
old_folder_path = join(dirname(path), old_name)
|
||||
|
||||
if old_folder_path == new_folder_path:
|
||||
return (
|
||||
|
@ -131,8 +162,8 @@ class ConfigFiles:
|
|||
def edit_file(
|
||||
self, path: str, name: str, old_name: str, content: str
|
||||
) -> Tuple[str, int]:
|
||||
new_path = dirname(join(path, name))
|
||||
old_path = dirname(join(path, old_name))
|
||||
new_path = join(dirname(path), name)
|
||||
old_path = join(dirname(path), old_name)
|
||||
|
||||
try:
|
||||
file_content = Path(old_path).read_text()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from pathlib import Path
|
||||
from subprocess import run
|
||||
from subprocess import DEVNULL, STDOUT, run
|
||||
from sys import path as sys_path
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
|
@ -56,8 +56,9 @@ class Instance:
|
|||
if self._type == "local":
|
||||
return (
|
||||
run(
|
||||
["sudo", "systemctl", "reload", "bunkerweb"],
|
||||
capture_output=True,
|
||||
["sudo", "/usr/sbin/nginx", "-s", "reload"],
|
||||
stdin=DEVNULL,
|
||||
stderr=STDOUT,
|
||||
).returncode
|
||||
== 0
|
||||
)
|
||||
|
@ -68,8 +69,9 @@ class Instance:
|
|||
if self._type == "local":
|
||||
return (
|
||||
run(
|
||||
["sudo", "systemctl", "start", "bunkerweb"],
|
||||
capture_output=True,
|
||||
["sudo", "/usr/sbin/nginx"],
|
||||
stdin=DEVNULL,
|
||||
stderr=STDOUT,
|
||||
).returncode
|
||||
== 0
|
||||
)
|
||||
|
@ -80,8 +82,9 @@ class Instance:
|
|||
if self._type == "local":
|
||||
return (
|
||||
run(
|
||||
["sudo", "systemctl", "stop", "bunkerweb"],
|
||||
capture_output=True,
|
||||
["sudo", "/usr/sbin/nginx", "-s", "stop"],
|
||||
stdin=DEVNULL,
|
||||
stderr=STDOUT,
|
||||
).returncode
|
||||
== 0
|
||||
)
|
||||
|
@ -92,8 +95,9 @@ class Instance:
|
|||
if self._type == "local":
|
||||
return (
|
||||
run(
|
||||
["sudo", "systemctl", "restart", "bunkerweb"],
|
||||
capture_output=True,
|
||||
["sudo", "/usr/sbin/nginx", "-s", "restart"],
|
||||
stdin=DEVNULL,
|
||||
stderr=STDOUT,
|
||||
).returncode
|
||||
== 0
|
||||
)
|
||||
|
@ -159,27 +163,24 @@ class Instances:
|
|||
status = "up"
|
||||
|
||||
apis = []
|
||||
for instance in self.__docker_client.services.list(
|
||||
filters={"label": "bunkerweb.INSTANCE"}
|
||||
):
|
||||
api_http_port = None
|
||||
api_server_name = None
|
||||
api_http_port = None
|
||||
api_server_name = None
|
||||
|
||||
for var in instance.attrs["Spec"]["TaskTemplate"]["ContainerSpec"][
|
||||
"Env"
|
||||
]:
|
||||
if var.startswith("API_HTTP_PORT="):
|
||||
api_http_port = var.replace("API_HTTP_PORT=", "", 1)
|
||||
elif var.startswith("API_SERVER_NAME="):
|
||||
api_server_name = var.replace("API_SERVER_NAME=", "", 1)
|
||||
for var in instance.attrs["Spec"]["TaskTemplate"]["ContainerSpec"][
|
||||
"Env"
|
||||
]:
|
||||
if var.startswith("API_HTTP_PORT="):
|
||||
api_http_port = var.replace("API_HTTP_PORT=", "", 1)
|
||||
elif var.startswith("API_SERVER_NAME="):
|
||||
api_server_name = var.replace("API_SERVER_NAME=", "", 1)
|
||||
|
||||
for task in instance.tasks():
|
||||
apis.append(
|
||||
API(
|
||||
f"http://{instance.name}.{task['NodeID']}.{task['ID']}:{api_http_port or '5000'}",
|
||||
host=api_server_name or "bwapi",
|
||||
)
|
||||
for task in instance.tasks():
|
||||
apis.append(
|
||||
API(
|
||||
f"http://{instance.name}.{task['NodeID']}.{task['ID']}:{api_http_port or '5000'}",
|
||||
host=api_server_name or "bwapi",
|
||||
)
|
||||
)
|
||||
apiCaller = ApiCaller(apis=apis)
|
||||
|
||||
instances.append(
|
||||
|
@ -202,33 +203,17 @@ class Instances:
|
|||
and "bunkerweb.io/INSTANCE" in pod.metadata.annotations
|
||||
):
|
||||
env_variables = {
|
||||
e.name: e.value for e in pod.spec.containers[0].env
|
||||
env.name: env.value or "" for env in pod.spec.containers[0].env
|
||||
}
|
||||
|
||||
apis = []
|
||||
config.load_incluster_config()
|
||||
corev1 = self.__kubernetes_client.CoreV1Api()
|
||||
for pod in corev1.list_pod_for_all_namespaces(watch=False).items:
|
||||
if (
|
||||
pod.metadata.annotations != None
|
||||
and "bunkerweb.io/INSTANCE" in pod.metadata.annotations
|
||||
):
|
||||
api_http_port = None
|
||||
api_server_name = None
|
||||
|
||||
for pod_env in pod.spec.containers[0].env:
|
||||
if pod_env.name == "API_HTTP_PORT":
|
||||
api_http_port = pod_env.value or "5000"
|
||||
elif pod_env.name == "API_SERVER_NAME":
|
||||
api_server_name = pod_env.value or "bwapi"
|
||||
|
||||
apis.append(
|
||||
API(
|
||||
f"http://{pod.status.pod_ip}:{api_http_port or '5000'}",
|
||||
host=api_server_name or "bwapi",
|
||||
)
|
||||
apiCaller = ApiCaller(
|
||||
apis=[
|
||||
API(
|
||||
f"http://{pod.status.pod_ip}:{env_variables.get('API_HTTP_PORT', '5000')}",
|
||||
host=env_variables.get("API_SERVER_NAME", "bwapi"),
|
||||
)
|
||||
apiCaller = ApiCaller(apis=apis)
|
||||
]
|
||||
)
|
||||
|
||||
status = "up"
|
||||
if pod.status.conditions is not None:
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -8,7 +8,7 @@ import {
|
|||
class Download {
|
||||
constructor(prefix = "cache") {
|
||||
this.prefix = prefix;
|
||||
this.listContainer = document.querySelector(`[cache-container]`);
|
||||
this.listContainer = document.querySelector(`[data-cache-container]`);
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
@ -16,11 +16,11 @@ class Download {
|
|||
this.listContainer.addEventListener("click", (e) => {
|
||||
try {
|
||||
if (
|
||||
e.target.closest("button").hasAttribute(`${this.prefix}-download`)
|
||||
e.target.closest("button").hasAttribute(`data-${this.prefix}-download`)
|
||||
) {
|
||||
const btnEl = e.target.closest("button");
|
||||
const jobName = btnEl.getAttribute("cache-download");
|
||||
const fileName = btnEl.getAttribute("cache-file");
|
||||
const jobName = btnEl.getAttribute("data-cache-download");
|
||||
const fileName = btnEl.getAttribute("data-cache-file");
|
||||
this.sendFileToDL(jobName, fileName);
|
||||
}
|
||||
} catch (err) {}
|
||||
|
|
|
@ -2,9 +2,9 @@ import { Checkbox } from "./utils/form.js";
|
|||
|
||||
class Menu {
|
||||
constructor() {
|
||||
this.sidebarEl = document.querySelector("[sidebar-menu]");
|
||||
this.toggleBtn = document.querySelector("[sidebar-menu-toggle]");
|
||||
this.closeBtn = document.querySelector("[sidebar-menu-close]");
|
||||
this.sidebarEl = document.querySelector("[data-sidebar-menu]");
|
||||
this.toggleBtn = document.querySelector("[data-sidebar-menu-toggle]");
|
||||
this.closeBtn = document.querySelector("[data-sidebar-menu-close]");
|
||||
|
||||
this.toggleBtn.addEventListener("click", this.toggle.bind(this));
|
||||
this.closeBtn.addEventListener("click", this.close.bind(this));
|
||||
|
@ -15,7 +15,7 @@ class Menu {
|
|||
window.addEventListener("click", (e) => {
|
||||
try {
|
||||
if (
|
||||
e.target.closest("aside").hasAttribute("sidebar-menu") &&
|
||||
e.target.closest("aside").hasAttribute("data-sidebar-menu") &&
|
||||
e.target.closest("button").getAttribute("role") === "tab"
|
||||
) {
|
||||
this.close();
|
||||
|
@ -53,7 +53,7 @@ class News {
|
|||
}
|
||||
|
||||
render(lastNews) {
|
||||
const newsContainer = document.querySelector("[news-container]");
|
||||
const newsContainer = document.querySelector("[data-news-container]");
|
||||
//remove default message
|
||||
newsContainer.textContent = "";
|
||||
//render last news
|
||||
|
@ -76,7 +76,7 @@ class News {
|
|||
);
|
||||
//add to DOM
|
||||
document
|
||||
.querySelector("[news-container]")
|
||||
.querySelector("[data-news-container]")
|
||||
.insertAdjacentHTML("afterbegin", cardHTML);
|
||||
});
|
||||
}
|
||||
|
@ -157,8 +157,8 @@ class Sidebar {
|
|||
class darkMode {
|
||||
constructor() {
|
||||
this.htmlEl = document.querySelector("html");
|
||||
this.darkToggleEl = document.querySelector("[dark-toggle]");
|
||||
this.darkToggleLabel = document.querySelector("[dark-toggle-label]");
|
||||
this.darkToggleEl = document.querySelector("[data-dark-toggle]");
|
||||
this.darkToggleLabel = document.querySelector("[data-dark-toggle-label]");
|
||||
this.csrf = document.querySelector("input#csrf_token");
|
||||
this.init();
|
||||
}
|
||||
|
@ -197,8 +197,8 @@ class darkMode {
|
|||
|
||||
class FlashMsg {
|
||||
constructor() {
|
||||
this.openBtn = document.querySelector("[flash-sidebar-open]");
|
||||
this.flashCount = document.querySelector("[flash-count]");
|
||||
this.openBtn = document.querySelector("[data-flash-sidebar-open]");
|
||||
this.flashCount = document.querySelector("[data-flash-count]");
|
||||
this.isMsgCheck = false;
|
||||
this.init();
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ class FlashMsg {
|
|||
//stop animate if clicked once
|
||||
this.openBtn.addEventListener("click", (e) => {
|
||||
try {
|
||||
if (e.target.closest("button").hasAttribute("flash-sidebar-open")) {
|
||||
if (e.target.closest("button").hasAttribute("data-flash-sidebar-open")) {
|
||||
this.isMsgCheck = true;
|
||||
}
|
||||
} catch (err) {}
|
||||
|
@ -219,14 +219,14 @@ class FlashMsg {
|
|||
//remove flash message and change count
|
||||
window.addEventListener("click", (e) => {
|
||||
try {
|
||||
if (e.target.closest("button").hasAttribute("close-flash-message")) {
|
||||
if (e.target.closest("button").hasAttribute("data-close-flash-message")) {
|
||||
//remove logic
|
||||
const closeBtn = e.target.closest("button");
|
||||
const flashEl = closeBtn.closest("[flash-message]");
|
||||
const flashEl = closeBtn.closest("[data-flash-message]");
|
||||
flashEl.remove();
|
||||
//update count
|
||||
this.flashCount.textContent =
|
||||
document.querySelectorAll("[flash-message]").length;
|
||||
document.querySelectorAll("[data-flash-message]").length;
|
||||
}
|
||||
} catch (err) {}
|
||||
});
|
||||
|
@ -254,9 +254,9 @@ class FlashMsg {
|
|||
|
||||
class Loader {
|
||||
constructor() {
|
||||
this.menuContainer = document.querySelector("[menu-container]");
|
||||
this.logoContainer = document.querySelector("[loader]");
|
||||
this.logoEl = document.querySelector("[loader-img]");
|
||||
this.menuContainer = document.querySelector("[data-menu-container]");
|
||||
this.logoContainer = document.querySelector("[data-loader]");
|
||||
this.logoEl = document.querySelector("[data-loader-img]");
|
||||
this.isLoading = true;
|
||||
this.init();
|
||||
}
|
||||
|
@ -292,14 +292,14 @@ class Loader {
|
|||
const setLoader = new Loader();
|
||||
const setMenu = new Menu();
|
||||
const setNewsSidebar = new Sidebar(
|
||||
"[sidebar-info]",
|
||||
"[sidebar-info-open]",
|
||||
"[sidebar-info-close]"
|
||||
"[data-sidebar-info]",
|
||||
"[data-sidebar-info-open]",
|
||||
"[data-sidebar-info-close]"
|
||||
);
|
||||
const setFlashSidebar = new Sidebar(
|
||||
"[flash-sidebar]",
|
||||
"[flash-sidebar-open]",
|
||||
"[flash-sidebar-close]"
|
||||
"[data-flash-sidebar]",
|
||||
"[data-flash-sidebar-open]",
|
||||
"[data-flash-sidebar-close]"
|
||||
);
|
||||
const setNews = new News();
|
||||
const setDarkM = new darkMode();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Checkbox, Select, Password } from "./utils/form.js";
|
||||
import { Checkbox, Select, Password, DisabledPop } from "./utils/form.js";
|
||||
import {
|
||||
Popover,
|
||||
Tabs,
|
||||
|
@ -15,12 +15,12 @@ class Multiple {
|
|||
init() {
|
||||
//hide multiple btn if no multiple exist on a plugin
|
||||
const multiples = document.querySelectorAll(
|
||||
`[${this.prefix}-settings-multiple]`
|
||||
`[data-${this.prefix}-settings-multiple]`
|
||||
);
|
||||
multiples.forEach((container) => {
|
||||
if (container.querySelectorAll(`[setting-container]`).length <= 0)
|
||||
if (container.querySelectorAll(`[data-setting-container]`).length <= 0)
|
||||
container.parentElement
|
||||
.querySelector("[multiple-handler]")
|
||||
.querySelector("[data-multiple-handler]")
|
||||
.classList.add("hidden");
|
||||
});
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -36,5 +37,5 @@ const format = new FormatValue();
|
|||
const setMultiple = new Multiple("global-config");
|
||||
const setFilterGlobal = new FilterSettings(
|
||||
"settings-filter",
|
||||
"[service-content='settings']"
|
||||
"[data-service-content='settings']"
|
||||
);
|
||||
|
|
|
@ -13,12 +13,12 @@ class Dropdown {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`${this.prefix}-setting-select`) &&
|
||||
.hasAttribute(`data-${this.prefix}-setting-select`) &&
|
||||
!e.target.closest("button").hasAttribute(`disabled`)
|
||||
) {
|
||||
const btnName = e.target
|
||||
.closest("button")
|
||||
.getAttribute(`${this.prefix}-setting-select`);
|
||||
.getAttribute(`data-${this.prefix}-setting-select`);
|
||||
if (this.lastDrop !== btnName) {
|
||||
this.lastDrop = btnName;
|
||||
this.closeAllDrop();
|
||||
|
@ -32,12 +32,12 @@ class Dropdown {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`${this.prefix}-setting-select-dropdown-btn`)
|
||||
.hasAttribute(`data-${this.prefix}-setting-select-dropdown-btn`)
|
||||
) {
|
||||
const btn = e.target.closest("button");
|
||||
const btnValue = btn.getAttribute("value");
|
||||
const btnSetting = btn.getAttribute(
|
||||
`${this.prefix}-setting-select-dropdown-btn`
|
||||
`data-${this.prefix}-setting-select-dropdown-btn`
|
||||
);
|
||||
//stop if same value to avoid new fetching
|
||||
const isSameVal = this.isSameValue(btnSetting, btnValue);
|
||||
|
@ -46,10 +46,13 @@ class Dropdown {
|
|||
this.setSelectNewValue(btnSetting, btnValue);
|
||||
//close dropdown and change style
|
||||
this.hideDropdown(btnSetting);
|
||||
this.changeDropBtnStyle(btnSetting, btn);
|
||||
|
||||
if (!e.target.closest("button").hasAttribute(`data-${prefix}-file`)) {
|
||||
this.changeDropBtnStyle(btnSetting, btn);
|
||||
}
|
||||
//show / hide filter
|
||||
if (btnSetting === "instances") {
|
||||
this.hideFilterOnLocal(btn.getAttribute("_type"));
|
||||
this.hideFilterOnLocal(btn.getAttribute("data-_type"));
|
||||
}
|
||||
}
|
||||
} catch (err) {}
|
||||
|
@ -58,15 +61,15 @@ class Dropdown {
|
|||
|
||||
closeAllDrop() {
|
||||
const drops = document.querySelectorAll(
|
||||
`[${this.prefix}-setting-select-dropdown]`
|
||||
`[data-${this.prefix}-setting-select-dropdown]`
|
||||
);
|
||||
drops.forEach((drop) => {
|
||||
drop.classList.add("hidden");
|
||||
drop.classList.remove("flex");
|
||||
document
|
||||
.querySelector(
|
||||
`svg[${this.prefix}-setting-select="${drop.getAttribute(
|
||||
`${this.prefix}-setting-select-dropdown`
|
||||
`svg[data-${this.prefix}-setting-select="${drop.getAttribute(
|
||||
`data-${this.prefix}-setting-select-dropdown`
|
||||
)}"]`
|
||||
)
|
||||
.classList.remove("rotate-180");
|
||||
|
@ -75,7 +78,7 @@ class Dropdown {
|
|||
|
||||
isSameValue(btnSetting, value) {
|
||||
const selectCustom = document.querySelector(
|
||||
`[${this.prefix}-setting-select-text="${btnSetting}"]`
|
||||
`[data-${this.prefix}-setting-select-text="${btnSetting}"]`
|
||||
);
|
||||
const currVal = selectCustom.textContent;
|
||||
return currVal === value ? true : false;
|
||||
|
@ -83,39 +86,38 @@ class Dropdown {
|
|||
|
||||
setSelectNewValue(btnSetting, value) {
|
||||
const selectCustom = document.querySelector(
|
||||
`[${this.prefix}-setting-select="${btnSetting}"]`
|
||||
`[data-${this.prefix}-setting-select="${btnSetting}"]`
|
||||
);
|
||||
selectCustom.querySelector(
|
||||
`[${this.prefix}-setting-select-text]`
|
||||
`[data-${this.prefix}-setting-select-text]`
|
||||
).textContent = value;
|
||||
}
|
||||
|
||||
hideDropdown(btnSetting) {
|
||||
//hide dropdown
|
||||
const dropdownEl = document.querySelector(
|
||||
`[${this.prefix}-setting-select-dropdown="${btnSetting}"]`
|
||||
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`
|
||||
);
|
||||
dropdownEl.classList.add("hidden");
|
||||
dropdownEl.classList.remove("flex");
|
||||
//svg effect
|
||||
const dropdownChevron = document.querySelector(
|
||||
`svg[${this.prefix}-setting-select="${btnSetting}"]`
|
||||
`svg[data-${this.prefix}-setting-select="${btnSetting}"]`
|
||||
);
|
||||
dropdownChevron.classList.remove("rotate-180");
|
||||
}
|
||||
|
||||
changeDropBtnStyle(btnSetting, selectedBtn) {
|
||||
const dropdownEl = document.querySelector(
|
||||
`[${this.prefix}-setting-select-dropdown="${btnSetting}"]`
|
||||
`[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",
|
||||
"bg-primary",
|
||||
"bg-primary",
|
||||
"text-gray-300",
|
||||
"text-gray-300"
|
||||
);
|
||||
|
@ -133,13 +135,13 @@ class Dropdown {
|
|||
toggleSelectBtn(e) {
|
||||
const attribut = e.target
|
||||
.closest("button")
|
||||
.getAttribute(`${this.prefix}-setting-select`);
|
||||
.getAttribute(`data-${this.prefix}-setting-select`);
|
||||
//toggle dropdown
|
||||
const dropdownEl = document.querySelector(
|
||||
`[${this.prefix}-setting-select-dropdown="${attribut}"]`
|
||||
`[data-${this.prefix}-setting-select-dropdown="${attribut}"]`
|
||||
);
|
||||
const dropdownChevron = document.querySelector(
|
||||
`svg[${this.prefix}-setting-select="${attribut}"]`
|
||||
`svg[data-${this.prefix}-setting-select="${attribut}"]`
|
||||
);
|
||||
dropdownEl.classList.toggle("hidden");
|
||||
dropdownEl.classList.toggle("flex");
|
||||
|
@ -173,7 +175,7 @@ class Dropdown {
|
|||
class Filter {
|
||||
constructor(prefix = "jobs") {
|
||||
this.prefix = prefix;
|
||||
this.container = document.querySelector(`[${this.prefix}-filter]`);
|
||||
this.container = document.querySelector(`[data-${this.prefix}-filter]`);
|
||||
this.keyInp = document.querySelector("input#keyword");
|
||||
this.successValue = "all";
|
||||
this.reloadValue = "all";
|
||||
|
@ -189,12 +191,14 @@ class Filter {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.getAttribute(`${this.prefix}-setting-select-dropdown-btn`) ===
|
||||
.getAttribute(`data-${this.prefix}-setting-select-dropdown-btn`) ===
|
||||
"success"
|
||||
) {
|
||||
setTimeout(() => {
|
||||
const value = document
|
||||
.querySelector(`[${this.prefix}-setting-select-text="success"]`)
|
||||
.querySelector(
|
||||
`[data-${this.prefix}-setting-select-text="success"]`
|
||||
)
|
||||
.textContent.trim();
|
||||
|
||||
this.successValue = value;
|
||||
|
@ -210,12 +214,14 @@ class Filter {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.getAttribute(`${this.prefix}-setting-select-dropdown-btn`) ===
|
||||
.getAttribute(`data-${this.prefix}-setting-select-dropdown-btn`) ===
|
||||
"reload"
|
||||
) {
|
||||
setTimeout(() => {
|
||||
const value = document
|
||||
.querySelector(`[${this.prefix}-setting-select-text="reload"]`)
|
||||
.querySelector(
|
||||
`[data-${this.prefix}-setting-select-text="reload"]`
|
||||
)
|
||||
.textContent.trim();
|
||||
|
||||
this.reloadValue = value;
|
||||
|
@ -232,7 +238,7 @@ class Filter {
|
|||
}
|
||||
|
||||
filter() {
|
||||
const jobs = document.querySelector(`[${this.prefix}-list]`).children;
|
||||
const jobs = document.querySelector(`[data-${this.prefix}-list]`).children;
|
||||
if (jobs.length === 0) return;
|
||||
//reset
|
||||
for (let i = 0; i < jobs.length; i++) {
|
||||
|
@ -250,8 +256,8 @@ class Filter {
|
|||
for (let i = 0; i < jobs.length; i++) {
|
||||
const el = jobs[i];
|
||||
const type = el
|
||||
.querySelector(`[${this.prefix}-success]`)
|
||||
.getAttribute(`${this.prefix}-success`)
|
||||
.querySelector(`[data-${this.prefix}-success]`)
|
||||
.getAttribute(`data-${this.prefix}-success`)
|
||||
.trim();
|
||||
if (type !== this.successValue) el.classList.add("hidden");
|
||||
}
|
||||
|
@ -262,8 +268,8 @@ class Filter {
|
|||
for (let i = 0; i < jobs.length; i++) {
|
||||
const el = jobs[i];
|
||||
const type = el
|
||||
.querySelector(`[${this.prefix}-reload]`)
|
||||
.getAttribute(`${this.prefix}-reload`)
|
||||
.querySelector(`[data-${this.prefix}-reload]`)
|
||||
.getAttribute(`data-${this.prefix}-reload`)
|
||||
.trim();
|
||||
if (type !== this.reloadValue) el.classList.add("hidden");
|
||||
}
|
||||
|
@ -275,15 +281,15 @@ class Filter {
|
|||
for (let i = 0; i < jobs.length; i++) {
|
||||
const el = jobs[i];
|
||||
const name = el
|
||||
.querySelector(`[${this.prefix}-name`)
|
||||
.querySelector(`[data-${this.prefix}-name]`)
|
||||
.textContent.trim()
|
||||
.toLowerCase();
|
||||
const date = el
|
||||
.querySelector(`[${this.prefix}-last_run`)
|
||||
.querySelector(`[data-${this.prefix}-last_run]`)
|
||||
.textContent.trim()
|
||||
.toLowerCase();
|
||||
const every = el
|
||||
.querySelector(`[${this.prefix}-every`)
|
||||
.querySelector(`[data-${this.prefix}-every]`)
|
||||
.textContent.trim()
|
||||
.toLowerCase();
|
||||
|
||||
|
@ -300,7 +306,7 @@ class Filter {
|
|||
class Download {
|
||||
constructor(prefix = "jobs") {
|
||||
this.prefix = prefix;
|
||||
this.listContainer = document.querySelector(`[${this.prefix}-list]`);
|
||||
this.listContainer = document.querySelector(`[data-${this.prefix}-list]`);
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
@ -308,11 +314,13 @@ class Download {
|
|||
this.listContainer.addEventListener("click", (e) => {
|
||||
try {
|
||||
if (
|
||||
e.target.closest("button").hasAttribute(`${this.prefix}-download`)
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`data-${this.prefix}-download`)
|
||||
) {
|
||||
const btnEl = e.target.closest("button");
|
||||
const jobName = btnEl.getAttribute("jobs-download");
|
||||
const fileName = btnEl.getAttribute("jobs-file");
|
||||
const jobName = btnEl.getAttribute("data-jobs-download");
|
||||
const fileName = btnEl.getAttribute("data-jobs-file");
|
||||
this.sendFileToDL(jobName, fileName);
|
||||
}
|
||||
} catch (err) {}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Checkbox } from "./utils/form.js";
|
||||
import { Checkbox, Select } from "./utils/form.js";
|
||||
|
||||
class Dropdown {
|
||||
constructor(prefix = "logs") {
|
||||
|
@ -14,12 +14,12 @@ class Dropdown {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`${this.prefix}-setting-select`) &&
|
||||
.hasAttribute(`data-${this.prefix}-setting-select`) &&
|
||||
!e.target.closest("button").hasAttribute(`disabled`)
|
||||
) {
|
||||
const btnName = e.target
|
||||
.closest("button")
|
||||
.getAttribute(`${this.prefix}-setting-select`);
|
||||
.getAttribute(`data-${this.prefix}-setting-select`);
|
||||
if (this.lastDrop !== btnName) {
|
||||
this.lastDrop = btnName;
|
||||
this.closeAllDrop();
|
||||
|
@ -32,12 +32,12 @@ class Dropdown {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`${this.prefix}-setting-select-dropdown-btn`)
|
||||
.hasAttribute(`data-${this.prefix}-setting-select-dropdown-btn`)
|
||||
) {
|
||||
const btn = e.target.closest("button");
|
||||
const btnValue = btn.getAttribute("value");
|
||||
const btnSetting = btn.getAttribute(
|
||||
`${this.prefix}-setting-select-dropdown-btn`
|
||||
`data-${this.prefix}-setting-select-dropdown-btn`
|
||||
);
|
||||
//stop if same value to avoid new fetching
|
||||
const isSameVal = this.isSameValue(btnSetting, btnValue);
|
||||
|
@ -49,7 +49,7 @@ class Dropdown {
|
|||
this.changeDropBtnStyle(btnSetting, btn);
|
||||
//show / hide filter
|
||||
if (btnSetting === "instances") {
|
||||
this.hideFilterOnLocal(btn.getAttribute("_type"));
|
||||
this.hideFilterOnLocal(btn.getAttribute("data-_type"));
|
||||
}
|
||||
}
|
||||
} catch (err) {}
|
||||
|
@ -58,15 +58,15 @@ class Dropdown {
|
|||
|
||||
closeAllDrop() {
|
||||
const drops = document.querySelectorAll(
|
||||
`[${this.prefix}-setting-select-dropdown]`
|
||||
`[data-${this.prefix}-setting-select-dropdown]`
|
||||
);
|
||||
drops.forEach((drop) => {
|
||||
drop.classList.add("hidden");
|
||||
drop.classList.remove("flex");
|
||||
document
|
||||
.querySelector(
|
||||
`svg[${this.prefix}-setting-select="${drop.getAttribute(
|
||||
`${this.prefix}-setting-select-dropdown`
|
||||
`svg[data-${this.prefix}-setting-select="${drop.getAttribute(
|
||||
`data-${this.prefix}-setting-select-dropdown`
|
||||
)}"]`
|
||||
)
|
||||
.classList.remove("rotate-180");
|
||||
|
@ -75,7 +75,7 @@ class Dropdown {
|
|||
|
||||
isSameValue(btnSetting, value) {
|
||||
const selectCustom = document.querySelector(
|
||||
`[${this.prefix}-setting-select-text="${btnSetting}"]`
|
||||
`[data-${this.prefix}-setting-select-text="${btnSetting}"]`
|
||||
);
|
||||
const currVal = selectCustom.textContent;
|
||||
return currVal === value ? true : false;
|
||||
|
@ -83,39 +83,38 @@ class Dropdown {
|
|||
|
||||
setSelectNewValue(btnSetting, value) {
|
||||
const selectCustom = document.querySelector(
|
||||
`[${this.prefix}-setting-select="${btnSetting}"]`
|
||||
`[data-${this.prefix}-setting-select="${btnSetting}"]`
|
||||
);
|
||||
selectCustom.querySelector(
|
||||
`[${this.prefix}-setting-select-text]`
|
||||
`[data-${this.prefix}-setting-select-text]`
|
||||
).textContent = value;
|
||||
}
|
||||
|
||||
hideDropdown(btnSetting) {
|
||||
//hide dropdown
|
||||
const dropdownEl = document.querySelector(
|
||||
`[${this.prefix}-setting-select-dropdown="${btnSetting}"]`
|
||||
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`
|
||||
);
|
||||
dropdownEl.classList.add("hidden");
|
||||
dropdownEl.classList.remove("flex");
|
||||
//svg effect
|
||||
const dropdownChevron = document.querySelector(
|
||||
`svg[${this.prefix}-setting-select="${btnSetting}"]`
|
||||
`svg[data-${this.prefix}-setting-select="${btnSetting}"]`
|
||||
);
|
||||
dropdownChevron.classList.remove("rotate-180");
|
||||
}
|
||||
|
||||
changeDropBtnStyle(btnSetting, selectedBtn) {
|
||||
const dropdownEl = document.querySelector(
|
||||
`[${this.prefix}-setting-select-dropdown="${btnSetting}"]`
|
||||
`[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",
|
||||
"bg-primary",
|
||||
"bg-primary",
|
||||
"text-gray-300",
|
||||
"text-gray-300"
|
||||
);
|
||||
|
@ -133,13 +132,13 @@ class Dropdown {
|
|||
toggleSelectBtn(e) {
|
||||
const attribut = e.target
|
||||
.closest("button")
|
||||
.getAttribute(`${this.prefix}-setting-select`);
|
||||
.getAttribute(`data-${this.prefix}-setting-select`);
|
||||
//toggle dropdown
|
||||
const dropdownEl = document.querySelector(
|
||||
`[${this.prefix}-setting-select-dropdown="${attribut}"]`
|
||||
`[data-${this.prefix}-setting-select-dropdown="${attribut}"]`
|
||||
);
|
||||
const dropdownChevron = document.querySelector(
|
||||
`svg[${this.prefix}-setting-select="${attribut}"]`
|
||||
`svg[data-${this.prefix}-setting-select="${attribut}"]`
|
||||
);
|
||||
dropdownEl.classList.toggle("hidden");
|
||||
dropdownEl.classList.toggle("flex");
|
||||
|
@ -174,7 +173,7 @@ class FetchLogs {
|
|||
constructor(prefix = "logs") {
|
||||
this.prefix = prefix;
|
||||
this.instance = document.querySelector(
|
||||
`[${this.prefix}-setting-select-text="instances"]`
|
||||
`[data-${this.prefix}-setting-select-text="instances"]`
|
||||
);
|
||||
this.instanceName = "";
|
||||
this.updateInp = document.querySelector("input#update-date");
|
||||
|
@ -184,17 +183,67 @@ class FetchLogs {
|
|||
this.toDateInp = document.querySelector("input#to-date");
|
||||
this.fromDate = "";
|
||||
this.toDate = "";
|
||||
this.isLiveUpdate = false;
|
||||
this.isLiveON = false;
|
||||
this.updateDelay = 2000;
|
||||
this.lastUpdate = Date.now() - 86400000;
|
||||
this.container = document.querySelector(`[${this.prefix}-settings]`);
|
||||
this.logListContainer = document.querySelector(`[${this.prefix}-list]`);
|
||||
this.submitSettings = document.querySelector("button#submit-settings");
|
||||
this.container = document.querySelector(`[data-${this.prefix}-settings]`);
|
||||
this.logListContainer = document.querySelector(
|
||||
`[data-${this.prefix}-list]`
|
||||
);
|
||||
this.submitDate = document.querySelector("button[data-submit-date]");
|
||||
this.submitLive = document.querySelector("button[data-submit-live]");
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.submitSettings.addEventListener("click", (e) => {
|
||||
//change submit btn text
|
||||
this.liveUpdateInp.addEventListener("change", (e) => {
|
||||
const currValue = this.liveUpdateInp.getAttribute("value");
|
||||
|
||||
if (currValue === "yes") {
|
||||
this.submitDate.classList.add("hidden");
|
||||
this.submitLive.classList.remove("hidden");
|
||||
}
|
||||
|
||||
if (currValue === "no") {
|
||||
this.submitDate.classList.remove("hidden");
|
||||
this.submitLive.classList.add("hidden");
|
||||
}
|
||||
});
|
||||
|
||||
this.submitLive.addEventListener("click", (e) => {
|
||||
//change state
|
||||
this.submitLive.setAttribute(
|
||||
"data-submit-live",
|
||||
this.submitLive.getAttribute("data-submit-live") === "yes"
|
||||
? "no"
|
||||
: "yes"
|
||||
);
|
||||
|
||||
if (this.submitLive.getAttribute("data-submit-live") === "yes") {
|
||||
this.submitLive.textContent = "Stop live";
|
||||
//check if min setting to fetch
|
||||
const isSettings = this.isSettings();
|
||||
if (!isSettings) return;
|
||||
//if can fetch, remove previous logs
|
||||
this.logListContainer.textContent = "";
|
||||
//get new settings data
|
||||
this.setSettings();
|
||||
//two cases
|
||||
//live update is checked, get data since last update or all if undefined
|
||||
return this.getLogsSinceLastUpdate();
|
||||
}
|
||||
|
||||
if (this.submitLive.getAttribute("data-submit-live") === "no") {
|
||||
this.submitLive.textContent = "Go live";
|
||||
}
|
||||
});
|
||||
|
||||
//when submit btn click
|
||||
this.submitDate.addEventListener("click", (e) => {
|
||||
//logic for the current state
|
||||
|
||||
//check if min setting to fetch
|
||||
const isSettings = this.isSettings();
|
||||
if (!isSettings) return;
|
||||
|
@ -203,13 +252,9 @@ class FetchLogs {
|
|||
//get new settings data
|
||||
this.setSettings();
|
||||
//two cases
|
||||
if (this.isLiveUpdate) {
|
||||
//live update is checked, get data since last update or all if undefined
|
||||
return this.getLogsSinceLastUpdate();
|
||||
} else {
|
||||
//get data from the range from/to (defined or default)
|
||||
return this.getLogsFromToDate();
|
||||
}
|
||||
|
||||
//get data from the range from/to (defined or default)
|
||||
return this.getLogsFromToDate();
|
||||
});
|
||||
|
||||
//to date is disabled if live update is set
|
||||
|
@ -262,16 +307,14 @@ class FetchLogs {
|
|||
//set update delay
|
||||
this.updateDelay =
|
||||
this.updateDelayInp.value * 1000 ? this.updateDelayInp.value : 2000;
|
||||
//look if live update
|
||||
this.isLiveUpdate = this.liveUpdateInp.checked;
|
||||
}
|
||||
|
||||
goBottomList() {
|
||||
document
|
||||
.querySelector(`[${this.prefix}-list]`)
|
||||
.querySelector(`[data-${this.prefix}-list]`)
|
||||
.scrollTo(
|
||||
0,
|
||||
document.querySelector(`[${this.prefix}-list]`).scrollHeight
|
||||
document.querySelector(`[data-${this.prefix}-list]`).scrollHeight
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -283,7 +326,7 @@ class FetchLogs {
|
|||
`${location.href}/${this.instanceName}?from_date=${this.fromDate}&to_date=${this.toDate}`
|
||||
);
|
||||
const data = await res.json();
|
||||
return await this.showLogs(data);
|
||||
return await this.showLogsDate(data);
|
||||
}
|
||||
//case from date and to date defined
|
||||
if (!this.toDate) {
|
||||
|
@ -291,7 +334,7 @@ class FetchLogs {
|
|||
`${location.href}/${this.instanceName}?from_date=${this.fromDate}`
|
||||
);
|
||||
const data = await res.json();
|
||||
return await this.showLogs(data);
|
||||
return await this.showLogsDate(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,10 +344,10 @@ class FetchLogs {
|
|||
(this.lastUpdate ? `?last_update=${this.lastUpdate}` : "")
|
||||
);
|
||||
const data = await response.json();
|
||||
return await this.showLogs(data);
|
||||
return await this.showLogsLive(data);
|
||||
}
|
||||
|
||||
async showLogs(res) {
|
||||
async showLogsDate(res, type) {
|
||||
//get last update timestamp
|
||||
this.lastUpdate = res.last_update;
|
||||
//render logs
|
||||
|
@ -318,21 +361,53 @@ class FetchLogs {
|
|||
typeEl.className =
|
||||
"dark:text-gray-400 dark:opacity-80 text-sm col-span-3 m-0";
|
||||
typeEl.textContent = log.type;
|
||||
typeEl.setAttribute("logs-type", "");
|
||||
typeEl.setAttribute("data-logs-type", "");
|
||||
logContainer.appendChild(typeEl);
|
||||
//content
|
||||
const contentEl = document.createElement("p");
|
||||
contentEl.className =
|
||||
"dark:text-gray-400 dark:opacity-80 text-sm col-span-9 m-0";
|
||||
contentEl.textContent = log.content;
|
||||
contentEl.setAttribute("logs-content", "");
|
||||
contentEl.setAttribute("data-logs-content", "");
|
||||
logContainer.appendChild(contentEl);
|
||||
//show on DOM
|
||||
this.logListContainer.appendChild(logContainer);
|
||||
});
|
||||
|
||||
//force scroll when no live update
|
||||
const logListEl = document.querySelector(`[data-${this.prefix}-list]`);
|
||||
logListEl.scrollTop = logListEl.scrollHeight;
|
||||
}
|
||||
|
||||
async showLogsLive(res, type) {
|
||||
//get last update timestamp
|
||||
this.lastUpdate = res.last_update;
|
||||
//render logs
|
||||
res.logs.forEach((log) => {
|
||||
//container
|
||||
const logContainer = document.createElement("li");
|
||||
logContainer.className =
|
||||
"grid grid-cols-12 border-b border-gray-300 py-2";
|
||||
//type
|
||||
const typeEl = document.createElement("p");
|
||||
typeEl.className =
|
||||
"dark:text-gray-400 dark:opacity-80 text-sm col-span-3 m-0";
|
||||
typeEl.textContent = log.type;
|
||||
typeEl.setAttribute("data-logs-type", "");
|
||||
logContainer.appendChild(typeEl);
|
||||
//content
|
||||
const contentEl = document.createElement("p");
|
||||
contentEl.className =
|
||||
"dark:text-gray-400 dark:opacity-80 text-sm col-span-9 m-0";
|
||||
contentEl.textContent = log.content;
|
||||
contentEl.setAttribute("data-logs-content", "");
|
||||
logContainer.appendChild(contentEl);
|
||||
//show on DOM
|
||||
this.logListContainer.appendChild(logContainer);
|
||||
});
|
||||
|
||||
//if live update, refetch to last update every defined delay
|
||||
if (this.isLiveUpdate) {
|
||||
if (this.submitLive.getAttribute("data-submit-live") === "yes") {
|
||||
setTimeout(() => {
|
||||
this.getLogsSinceLastUpdate();
|
||||
}, this.updateDelay);
|
||||
|
@ -343,7 +418,7 @@ class FetchLogs {
|
|||
class Filter {
|
||||
constructor(prefix = "logs") {
|
||||
this.prefix = prefix;
|
||||
this.container = document.querySelector(`[${this.prefix}-filter]`);
|
||||
this.container = document.querySelector(`[data-${this.prefix}-filter]`);
|
||||
this.keyInp = document.querySelector("input#keyword");
|
||||
this.lastType = "all";
|
||||
this.initHandler();
|
||||
|
@ -356,13 +431,13 @@ class Filter {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.getAttribute(`${this.prefix}-setting-select-dropdown-btn`) ===
|
||||
.getAttribute(`data-${this.prefix}-setting-select-dropdown-btn`) ===
|
||||
"types"
|
||||
) {
|
||||
const btn = e.target.closest("button");
|
||||
const btnValue = btn.getAttribute("value");
|
||||
const btnSetting = btn.getAttribute(
|
||||
`${this.prefix}-setting-select-dropdown-btn`
|
||||
`data-${this.prefix}-setting-select-dropdown-btn`
|
||||
);
|
||||
|
||||
this.lastType = btnValue;
|
||||
|
@ -378,7 +453,7 @@ class Filter {
|
|||
}
|
||||
|
||||
filter() {
|
||||
const logs = document.querySelector(`[${this.prefix}-list]`).children;
|
||||
const logs = document.querySelector(`[data-${this.prefix}-list]`).children;
|
||||
if (logs.length === 0) return;
|
||||
//reset
|
||||
for (let i = 0; i < logs.length; i++) {
|
||||
|
@ -395,7 +470,7 @@ class Filter {
|
|||
|
||||
for (let i = 0; i < logs.length; i++) {
|
||||
const el = logs[i];
|
||||
const typeEl = el.querySelector("[logs-type]");
|
||||
const typeEl = el.querySelector("[data-logs-type]");
|
||||
if (this.lastType !== "misc" && typeEl.textContent !== this.lastType)
|
||||
el.classList.add("hidden");
|
||||
if (
|
||||
|
@ -413,7 +488,7 @@ class Filter {
|
|||
for (let i = 0; i < logs.length; i++) {
|
||||
const el = logs[i];
|
||||
const content = el
|
||||
.querySelector("[logs-content]")
|
||||
.querySelector("[data-logs-content]")
|
||||
.textContent.trim()
|
||||
.toLowerCase();
|
||||
if (!content.includes(keyword)) el.classList.add("hidden");
|
||||
|
@ -422,6 +497,7 @@ class Filter {
|
|||
}
|
||||
|
||||
const setCheckbox = new Checkbox();
|
||||
const setSelect = new Select();
|
||||
const dropdown = new Dropdown("logs");
|
||||
const setLogs = new FetchLogs();
|
||||
const setFilter = new Filter("logs");
|
||||
|
|
|
@ -12,12 +12,12 @@ class Dropdown {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`${this.prefix}-setting-select`) &&
|
||||
.hasAttribute(`data-${this.prefix}-setting-select`) &&
|
||||
!e.target.closest("button").hasAttribute(`disabled`)
|
||||
) {
|
||||
const btnName = e.target
|
||||
.closest("button")
|
||||
.getAttribute(`${this.prefix}-setting-select`);
|
||||
.getAttribute(`data-${this.prefix}-setting-select`);
|
||||
if (this.lastDrop !== btnName) {
|
||||
this.lastDrop = btnName;
|
||||
this.closeAllDrop();
|
||||
|
@ -31,12 +31,12 @@ class Dropdown {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`${this.prefix}-setting-select-dropdown-btn`)
|
||||
.hasAttribute(`data-${this.prefix}-setting-select-dropdown-btn`)
|
||||
) {
|
||||
const btn = e.target.closest("button");
|
||||
const btnValue = btn.getAttribute("value");
|
||||
const btnSetting = btn.getAttribute(
|
||||
`${this.prefix}-setting-select-dropdown-btn`
|
||||
`data-${this.prefix}-setting-select-dropdown-btn`
|
||||
);
|
||||
//stop if same value to avoid new fetching
|
||||
const isSameVal = this.isSameValue(btnSetting, btnValue);
|
||||
|
@ -48,7 +48,7 @@ class Dropdown {
|
|||
this.changeDropBtnStyle(btnSetting, btn);
|
||||
//show / hide filter
|
||||
if (btnSetting === "instances") {
|
||||
this.hideFilterOnLocal(btn.getAttribute("_type"));
|
||||
this.hideFilterOnLocal(btn.getAttribute("data-_type"));
|
||||
}
|
||||
}
|
||||
} catch (err) {}
|
||||
|
@ -57,15 +57,15 @@ class Dropdown {
|
|||
|
||||
closeAllDrop() {
|
||||
const drops = document.querySelectorAll(
|
||||
`[${this.prefix}-setting-select-dropdown]`
|
||||
`[data-${this.prefix}-setting-select-dropdown]`
|
||||
);
|
||||
drops.forEach((drop) => {
|
||||
drop.classList.add("hidden");
|
||||
drop.classList.remove("flex");
|
||||
document
|
||||
.querySelector(
|
||||
`svg[${this.prefix}-setting-select="${drop.getAttribute(
|
||||
`${this.prefix}-setting-select-dropdown`
|
||||
`svg[data-${this.prefix}-setting-select="${drop.getAttribute(
|
||||
`data-${this.prefix}-setting-select-dropdown`
|
||||
)}"]`
|
||||
)
|
||||
.classList.remove("rotate-180");
|
||||
|
@ -74,7 +74,7 @@ class Dropdown {
|
|||
|
||||
isSameValue(btnSetting, value) {
|
||||
const selectCustom = document.querySelector(
|
||||
`[${this.prefix}-setting-select-text="${btnSetting}"]`
|
||||
`[data-${this.prefix}-setting-select-text="${btnSetting}"]`
|
||||
);
|
||||
const currVal = selectCustom.textContent;
|
||||
return currVal === value ? true : false;
|
||||
|
@ -82,30 +82,30 @@ class Dropdown {
|
|||
|
||||
setSelectNewValue(btnSetting, value) {
|
||||
const selectCustom = document.querySelector(
|
||||
`[${this.prefix}-setting-select="${btnSetting}"]`
|
||||
`[data-${this.prefix}-setting-select="${btnSetting}"]`
|
||||
);
|
||||
selectCustom.querySelector(
|
||||
`[${this.prefix}-setting-select-text]`
|
||||
`[data-${this.prefix}-setting-select-text]`
|
||||
).textContent = value;
|
||||
}
|
||||
|
||||
hideDropdown(btnSetting) {
|
||||
//hide dropdown
|
||||
const dropdownEl = document.querySelector(
|
||||
`[${this.prefix}-setting-select-dropdown="${btnSetting}"]`
|
||||
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`
|
||||
);
|
||||
dropdownEl.classList.add("hidden");
|
||||
dropdownEl.classList.remove("flex");
|
||||
//svg effect
|
||||
const dropdownChevron = document.querySelector(
|
||||
`svg[${this.prefix}-setting-select="${btnSetting}"]`
|
||||
`svg[data-${this.prefix}-setting-select="${btnSetting}"]`
|
||||
);
|
||||
dropdownChevron.classList.remove("rotate-180");
|
||||
}
|
||||
|
||||
changeDropBtnStyle(btnSetting, selectedBtn) {
|
||||
const dropdownEl = document.querySelector(
|
||||
`[${this.prefix}-setting-select-dropdown="${btnSetting}"]`
|
||||
`[data-${this.prefix}-setting-select-dropdown="${btnSetting}"]`
|
||||
);
|
||||
//reset dropdown btns
|
||||
const btnEls = dropdownEl.querySelectorAll("button");
|
||||
|
@ -132,13 +132,13 @@ class Dropdown {
|
|||
toggleSelectBtn(e) {
|
||||
const attribut = e.target
|
||||
.closest("button")
|
||||
.getAttribute(`${this.prefix}-setting-select`);
|
||||
.getAttribute(`data-${this.prefix}-setting-select`);
|
||||
//toggle dropdown
|
||||
const dropdownEl = document.querySelector(
|
||||
`[${this.prefix}-setting-select-dropdown="${attribut}"]`
|
||||
`[data-${this.prefix}-setting-select-dropdown="${attribut}"]`
|
||||
);
|
||||
const dropdownChevron = document.querySelector(
|
||||
`svg[${this.prefix}-setting-select="${attribut}"]`
|
||||
`svg[data-${this.prefix}-setting-select="${attribut}"]`
|
||||
);
|
||||
dropdownEl.classList.toggle("hidden");
|
||||
dropdownEl.classList.toggle("flex");
|
||||
|
@ -172,7 +172,7 @@ class Dropdown {
|
|||
class Filter {
|
||||
constructor(prefix = "plugins") {
|
||||
this.prefix = prefix;
|
||||
this.container = document.querySelector(`[${this.prefix}-filter]`);
|
||||
this.container = document.querySelector(`[data-${this.prefix}-filter]`);
|
||||
this.keyInp = document.querySelector("input#keyword");
|
||||
this.lastType = "all";
|
||||
this.initHandler();
|
||||
|
@ -185,7 +185,7 @@ class Filter {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.getAttribute(`${this.prefix}-setting-select-dropdown-btn`) ===
|
||||
.getAttribute(`data-${this.prefix}-setting-select-dropdown-btn`) ===
|
||||
"types"
|
||||
) {
|
||||
const btn = e.target.closest("button");
|
||||
|
@ -204,7 +204,7 @@ class Filter {
|
|||
}
|
||||
|
||||
filter() {
|
||||
const logs = document.querySelector(`[${this.prefix}-list]`).children;
|
||||
const logs = document.querySelector(`[data-${this.prefix}-list]`).children;
|
||||
if (logs.length === 0) return;
|
||||
//reset
|
||||
for (let i = 0; i < logs.length; i++) {
|
||||
|
@ -220,7 +220,7 @@ class Filter {
|
|||
if (this.lastType === "all") return;
|
||||
for (let i = 0; i < logs.length; i++) {
|
||||
const el = logs[i];
|
||||
const type = el.getAttribute(`${this.prefix}-external`).trim();
|
||||
const type = el.getAttribute(`data-${this.prefix}-external`).trim();
|
||||
if (type !== this.lastType) el.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ class Filter {
|
|||
for (let i = 0; i < logs.length; i++) {
|
||||
const el = logs[i];
|
||||
const content = el
|
||||
.querySelector(`[${this.prefix}-content]`)
|
||||
.querySelector(`[data-${this.prefix}-content]`)
|
||||
.textContent.trim()
|
||||
.toLowerCase();
|
||||
|
||||
|
@ -242,7 +242,7 @@ class Filter {
|
|||
|
||||
class Upload {
|
||||
constructor() {
|
||||
this.container = document.querySelector("[plugins-upload]");
|
||||
this.container = document.querySelector("[data-plugins-upload]");
|
||||
this.form = document.querySelector("#dropzone-form");
|
||||
this.dropZoneElement = document.querySelector(".drop-zone");
|
||||
this.fileInput = document.querySelector(".file-input");
|
||||
|
@ -286,8 +286,8 @@ class Upload {
|
|||
//close fail/success log
|
||||
this.container.addEventListener("click", (e) => {
|
||||
try {
|
||||
if (e.target.closest("button").hasAttribute("upload-message-delete")) {
|
||||
const message = e.target.closest("div[upload-message]");
|
||||
if (e.target.closest("button").hasAttribute("data-upload-message-delete")) {
|
||||
const message = e.target.closest("div[data-upload-message]");
|
||||
message.remove();
|
||||
}
|
||||
} catch (err) {}
|
||||
|
@ -362,18 +362,21 @@ class Upload {
|
|||
}
|
||||
|
||||
allowReload() {
|
||||
const reloadBtn = document.querySelector("[plugin-reload-btn]");
|
||||
const reloadBtn = document.querySelector("[data-plugin-reload-btn]");
|
||||
reloadBtn.removeAttribute("disabled");
|
||||
}
|
||||
|
||||
fileLoad(name, fileSize) {
|
||||
const str = `<div u class="mt-2 rounded p-2 w-full bg-gray-100 dark:bg-gray-800">
|
||||
const str = `<div class="mt-2 rounded p-2 w-full bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-between">
|
||||
<svg class="fill-sky-500 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M256 512c141.4 0 256-114.6 256-256S397.4 0 256 0S0 114.6 0 256S114.6 512 256 512zM385 215c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-71-71V392c0 13.3-10.7 24-24 24s-24-10.7-24-24V177.9l-71 71c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9L239 103c9.4-9.4 24.6-9.4 33.9 0L385 215z"/></svg>
|
||||
<svg class="fill-sky-500 stroke-sky-500 h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" />
|
||||
</svg>
|
||||
<span class="text-sm text-slate-700 dark:text-gray-300 mr-4">${name} </span>
|
||||
<span class="text-sm text-slate-700 dark:text-gray-300">${fileSize}</span>
|
||||
<svg class=" fill-gray-600 dark:fill-gray-300 dark:opacity-80 h-3 w-3 " xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" />
|
||||
|
||||
<svg class=" fill-gray-600 dark:fill-gray-300 dark:opacity-80 h-3 w-3 " viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="50" cy="50" r="50"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -382,7 +385,7 @@ class Upload {
|
|||
}
|
||||
|
||||
fileSuccess(name, fileSize) {
|
||||
const str = `<div upload-message class="mt-2 rounded p-2 w-full bg-gray-100 dark:bg-gray-800">
|
||||
const str = `<div data-upload-message class="mt-2 rounded p-2 w-full bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-between">
|
||||
<svg
|
||||
class="fill-green-500 h-5 w-5"
|
||||
|
@ -395,10 +398,10 @@ class Upload {
|
|||
</svg>
|
||||
<span class="text-sm text-slate-700 dark:text-gray-300 mr-4">${name} </span>
|
||||
<span class="text-sm text-slate-700 dark:text-gray-300">${fileSize}</span>
|
||||
<button type="button" upload-message-delete>
|
||||
<button type="button" data-upload-message-delete>
|
||||
<svg class="cursor-pointer fill-gray-600 dark:fill-gray-300 dark:opacity-80 h-4 w-4 " xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path d="M310.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L160 210.7 54.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L114.7 256 9.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 301.3 265.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L205.3 256 310.6 150.6z"></path>
|
||||
</svg>
|
||||
<path d="M310.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L160 210.7 54.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L114.7 256 9.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 301.3 265.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L205.3 256 310.6 150.6z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -407,7 +410,7 @@ class Upload {
|
|||
}
|
||||
|
||||
fileFail(name, fileSize) {
|
||||
const str = `<div upload-message class="mt-2 rounded p-2 w-full bg-gray-100 dark:bg-gray-800">
|
||||
const str = `<div data-upload-message class="mt-2 rounded p-2 w-full bg-gray-100 dark:bg-gray-800">
|
||||
<div class="flex items-center justify-between">
|
||||
<svg
|
||||
class="fill-red-500 h-5 w-5 mr-4"
|
||||
|
@ -420,7 +423,7 @@ class Upload {
|
|||
</svg>
|
||||
<span class="text-sm text-slate-700 dark:text-gray-300 mr-4">${name} </span>
|
||||
<span class="text-sm text-slate-700 dark:text-gray-300">${fileSize}</span>
|
||||
<button type="button" upload-message-delete>
|
||||
<button type="button" data-upload-message-delete>
|
||||
|
||||
<svg class="cursor-pointer fill-gray-600 dark:fill-gray-300 dark:opacity-80 h-4 w-4 " xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||
<path d="M310.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L160 210.7 54.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L114.7 256 9.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 301.3 265.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L205.3 256 310.6 150.6z"></path>
|
||||
|
@ -437,13 +440,13 @@ class Upload {
|
|||
class Modal {
|
||||
constructor(prefix = "plugins") {
|
||||
this.prefix = prefix;
|
||||
this.container = document.querySelector(`[${this.prefix}-list]`);
|
||||
this.modal = document.querySelector(`[${this.prefix}-modal]`);
|
||||
this.container = document.querySelector(`[data-${this.prefix}-list]`);
|
||||
this.modal = document.querySelector(`[data-${this.prefix}-modal]`);
|
||||
this.modalNameInp = this.modal.querySelector("input#name");
|
||||
this.modalExtInp = this.modal.querySelector("input#external");
|
||||
|
||||
this.modalTitle = this.modal.querySelector(`[${this.prefix}-modal-title]`);
|
||||
this.modalTxt = this.modal.querySelector(`[${this.prefix}-modal-text]`);
|
||||
this.modalTitle = this.modal.querySelector(`[data-${this.prefix}-modal-title]`);
|
||||
this.modalTxt = this.modal.querySelector(`[data-${this.prefix}-modal-text]`);
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
@ -452,7 +455,7 @@ class Modal {
|
|||
//DELETE HANDLER
|
||||
try {
|
||||
if (
|
||||
e.target.closest("button").getAttribute(`${this.prefix}-action`) ===
|
||||
e.target.closest("button").getAttribute(`data-${this.prefix}-action`) ===
|
||||
"delete"
|
||||
) {
|
||||
const btnEl = e.target.closest("button");
|
||||
|
@ -466,7 +469,7 @@ class Modal {
|
|||
//CLOSE MODAL HANDLER
|
||||
try {
|
||||
if (
|
||||
e.target.closest("button").hasAttribute(`${this.prefix}-modal-close`)
|
||||
e.target.closest("button").hasAttribute(`data-${this.prefix}-modal-close`)
|
||||
) {
|
||||
this.hideModal();
|
||||
}
|
||||
|
@ -482,8 +485,8 @@ class Modal {
|
|||
this.modalTxt.textContent = `Are you sure you want to delete ${elName} ?`;
|
||||
//external
|
||||
const isExternal = el
|
||||
.closest("[plugins-external]")
|
||||
.getAttribute("plugins-external")
|
||||
.closest("[data-plugins-external]")
|
||||
.getAttribute("data-plugins-external")
|
||||
.trim()
|
||||
.includes("external")
|
||||
? "True"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Checkbox, Select, Password } from "./utils/form.js";
|
||||
import { Checkbox, Select, Password, DisabledPop } from "./utils/form.js";
|
||||
import {
|
||||
Popover,
|
||||
Tabs,
|
||||
|
@ -9,15 +9,19 @@ import {
|
|||
class ServiceModal {
|
||||
constructor() {
|
||||
//modal elements
|
||||
this.modal = document.querySelector("[services-modal]");
|
||||
this.modalTitle = this.modal.querySelector("[services-modal-title]");
|
||||
this.modalTabs = this.modal.querySelector(["[services-tabs]"]);
|
||||
this.modalTabsHeader = this.modal.querySelector(["[services-tabs-header]"]);
|
||||
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.modalCard = this.modal.querySelector("[services-modal-card]");
|
||||
this.modalCard = this.modal.querySelector("[data-services-modal-card]");
|
||||
//modal forms
|
||||
this.formNewEdit = this.modal.querySelector("[services-modal-form]");
|
||||
this.formDelete = this.modal.querySelector("[services-modal-form-delete]");
|
||||
this.formNewEdit = this.modal.querySelector("[data-services-modal-form]");
|
||||
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("services-action");
|
||||
const serviceName = target.closest("button").getAttribute("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("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("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);
|
||||
|
@ -55,19 +66,21 @@ class ServiceModal {
|
|||
//get service data and parse it
|
||||
//multiple type logic is launch at same time on relate class
|
||||
const servicesSettings = e.target
|
||||
.closest("[services-service]")
|
||||
.querySelector("[services-settings]")
|
||||
.getAttribute("value");
|
||||
.closest("[data-services-service]")
|
||||
.querySelector("[data-services-settings]")
|
||||
.getAttribute("data-value");
|
||||
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("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,16 +90,18 @@ 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) {}
|
||||
//delete action
|
||||
try {
|
||||
if (
|
||||
e.target.closest("button").getAttribute("services-action") ===
|
||||
e.target.closest("button").getAttribute("data-services-action") ===
|
||||
"delete"
|
||||
) {
|
||||
//set form info and right form
|
||||
|
@ -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,20 +134,20 @@ class ServiceModal {
|
|||
return;
|
||||
|
||||
//for all other settings values
|
||||
const defaultMethod = "default";
|
||||
const defaultVal = inp.getAttribute("default-value") || "";
|
||||
const defaultMethod = inp.getAttribute("data-default-method");
|
||||
const defaultVal = inp.getAttribute("data-default-value") || "";
|
||||
|
||||
//SET VALUE
|
||||
if (inp.getAttribute("type") === "checkbox") {
|
||||
inp.checked = defaultVal === "yes" ? true : false;
|
||||
inp.setAttribute("value", defaultVal);
|
||||
inp.value = defaultVal;
|
||||
inp.setAttribute("method", defaultMethod);
|
||||
inp.setAttribute("data-method", defaultMethod);
|
||||
}
|
||||
|
||||
if (inp.getAttribute("type") !== "checkbox") {
|
||||
inp.setAttribute("value", defaultVal);
|
||||
inp.setAttribute("method", defaultMethod);
|
||||
inp.setAttribute("data-method", defaultMethod);
|
||||
}
|
||||
|
||||
//SET METHOD
|
||||
|
@ -135,17 +157,19 @@ class ServiceModal {
|
|||
const selects = this.modal.querySelectorAll("select");
|
||||
selects.forEach((select) => {
|
||||
const defaultMethod = "default";
|
||||
const defaultVal = select.getAttribute("default-value") || "";
|
||||
const defaultVal = select.getAttribute("data-default-value") || "";
|
||||
|
||||
document
|
||||
.querySelector(
|
||||
`[setting-select=${select.getAttribute("setting-select-default")}]`
|
||||
`[data-setting-select=${select.getAttribute(
|
||||
"data-setting-select-default"
|
||||
)}]`
|
||||
)
|
||||
.removeAttribute("disabled");
|
||||
|
||||
select.parentElement
|
||||
.querySelector(
|
||||
`button[setting-select-dropdown-btn][value='${defaultVal}']`
|
||||
`button[data-setting-select-dropdown-btn][value='${defaultVal}']`
|
||||
)
|
||||
.click();
|
||||
|
||||
|
@ -178,7 +202,7 @@ class ServiceModal {
|
|||
if (action === "delete") {
|
||||
this.showDeleteForm();
|
||||
formEl.querySelector(
|
||||
`[services-modal-text]`
|
||||
`[data-services-modal-text]`
|
||||
).textContent = `Are you sure you want to delete ${serviceName} ?`;
|
||||
const nameInp = formEl.querySelector(`input[name="SERVER_NAME"]`);
|
||||
nameInp.setAttribute("value", serviceName);
|
||||
|
@ -258,7 +282,7 @@ class ServiceModal {
|
|||
) {
|
||||
inp.setAttribute("value", value);
|
||||
inp.value = value;
|
||||
inp.setAttribute("method", method);
|
||||
inp.setAttribute("data-method", method);
|
||||
}
|
||||
//for checkbox
|
||||
if (
|
||||
|
@ -267,24 +291,24 @@ class ServiceModal {
|
|||
) {
|
||||
inp.checked = value === "yes" ? true : false;
|
||||
inp.setAttribute("value", value);
|
||||
inp.setAttribute("method", method);
|
||||
inp.setAttribute("data-method", method);
|
||||
|
||||
if (inp.hasAttribute("disabled")) {
|
||||
const hidden_inp = inp
|
||||
.closest("div[checkbox-handler]")
|
||||
.closest("div[data-checkbox-handler]")
|
||||
.querySelector("input[type='hidden']");
|
||||
hidden_inp.setAttribute("value", value);
|
||||
hidden_inp.setAttribute("method", method);
|
||||
hidden_inp.setAttribute("data-method", method);
|
||||
}
|
||||
}
|
||||
//for select
|
||||
if (inp.tagName === "SELECT") {
|
||||
inp.parentElement
|
||||
.querySelector(
|
||||
`button[setting-select-dropdown-btn][value='${value}']`
|
||||
`button[data-setting-select-dropdown-btn][value='${value}']`
|
||||
)
|
||||
.click();
|
||||
inp.setAttribute("method", method);
|
||||
inp.setAttribute("data-method", method);
|
||||
}
|
||||
|
||||
//check disabled/enabled after setting values and methods
|
||||
|
@ -307,7 +331,7 @@ class ServiceModal {
|
|||
|
||||
openModal() {
|
||||
//switch to first setting
|
||||
document.querySelector("button[tab-handler]").click();
|
||||
document.querySelector("button[data-tab-handler]").click();
|
||||
//show modal el
|
||||
this.modal.classList.add("flex");
|
||||
this.modal.classList.remove("hidden");
|
||||
|
@ -318,7 +342,7 @@ class Multiple {
|
|||
constructor(prefix) {
|
||||
this.prefix = prefix;
|
||||
this.container = document.querySelector("main");
|
||||
this.modalForm = document.querySelector(`[${this.prefix}-modal-form]`);
|
||||
this.modalForm = document.querySelector(`[data-${this.prefix}-modal-form]`);
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
@ -331,15 +355,16 @@ class Multiple {
|
|||
//edit button
|
||||
try {
|
||||
if (
|
||||
e.target.closest("button").getAttribute("services-action") === "edit"
|
||||
e.target.closest("button").getAttribute("data-services-action") ===
|
||||
"edit"
|
||||
) {
|
||||
//remove all multiples
|
||||
this.removePrevMultiples();
|
||||
//get multiple service values and parse as obj
|
||||
const servicesSettings = e.target
|
||||
.closest("[services-service]")
|
||||
.querySelector("[services-settings]")
|
||||
.getAttribute("value");
|
||||
.closest("[data-services-service]")
|
||||
.querySelector("[data-services-settings]")
|
||||
.getAttribute("data-value");
|
||||
const obj = JSON.parse(servicesSettings);
|
||||
//keep only multiple settings value
|
||||
const multipleSettings = this.getMultiplesOnly(obj);
|
||||
|
@ -351,7 +376,8 @@ class Multiple {
|
|||
//new button
|
||||
try {
|
||||
if (
|
||||
e.target.closest("button").getAttribute("services-action") === "new"
|
||||
e.target.closest("button").getAttribute("data-services-action") ===
|
||||
"new"
|
||||
) {
|
||||
this.removePrevMultiples();
|
||||
this.addOneMultGroup();
|
||||
|
@ -363,14 +389,16 @@ class Multiple {
|
|||
//ADD BTN
|
||||
try {
|
||||
if (
|
||||
e.target.closest("button").hasAttribute(`${this.prefix}-multiple-add`)
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`data-${this.prefix}-multiple-add`)
|
||||
) {
|
||||
//get plugin from btn
|
||||
const btn = e.target.closest("button");
|
||||
const attName = btn.getAttribute(`${this.prefix}-multiple-add`);
|
||||
const attName = btn.getAttribute(`data-${this.prefix}-multiple-add`);
|
||||
//get all multiple groups
|
||||
const multipleEls = document.querySelectorAll(
|
||||
`[${this.prefix}-settings-multiple*="${attName}"]`
|
||||
`[data-${this.prefix}-settings-multiple*="${attName}"]`
|
||||
);
|
||||
//case no schema
|
||||
if (multipleEls.length <= 0) return;
|
||||
|
@ -382,7 +410,7 @@ class Multiple {
|
|||
//and keep the highest num
|
||||
multipleEls.forEach((container) => {
|
||||
const ctnrName = container.getAttribute(
|
||||
"services-settings-multiple"
|
||||
"data-services-settings-multiple"
|
||||
);
|
||||
const num = this.getSuffixNumOrFalse(ctnrName);
|
||||
if (!isNaN(num) && num > topNum) topNum = num;
|
||||
|
@ -393,7 +421,7 @@ class Multiple {
|
|||
const setNum = +currNum === 0 ? `` : `_${currNum}`;
|
||||
//the default (schema) group is the last group
|
||||
const schema = document.querySelector(
|
||||
`[${this.prefix}-settings-multiple="${attName}_SCHEMA"]`
|
||||
`[data-${this.prefix}-settings-multiple="${attName}_SCHEMA"]`
|
||||
);
|
||||
//clone schema to create a group with new num
|
||||
const schemaClone = schema.cloneNode(true);
|
||||
|
@ -411,11 +439,11 @@ class Multiple {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`${this.prefix}-multiple-toggle`)
|
||||
.hasAttribute(`data-${this.prefix}-multiple-toggle`)
|
||||
) {
|
||||
const att = e.target
|
||||
.closest("button")
|
||||
.getAttribute(`${this.prefix}-multiple-toggle`);
|
||||
.getAttribute(`data-${this.prefix}-multiple-toggle`);
|
||||
this.toggleMultByAtt(att);
|
||||
}
|
||||
//remove last child
|
||||
|
@ -426,10 +454,10 @@ class Multiple {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`${this.prefix}-multiple-delete`)
|
||||
.hasAttribute(`data-${this.prefix}-multiple-delete`)
|
||||
) {
|
||||
const multContainer = e.target.closest(
|
||||
"[services-settings-multiple]"
|
||||
"[data-services-settings-multiple]"
|
||||
);
|
||||
multContainer.remove();
|
||||
}
|
||||
|
@ -451,11 +479,13 @@ class Multiple {
|
|||
? name.replace(`_${splitName[splitName.length - 1]}`, "").trim()
|
||||
: name.trim();
|
||||
const relateSetting = document.querySelector(
|
||||
`[setting-container=${nameSuffixLess}_SCHEMA]`
|
||||
`[data-setting-container=${nameSuffixLess}_SCHEMA]`
|
||||
);
|
||||
const relateCtnr = relateSetting.closest(
|
||||
"[data-services-settings-multiple]"
|
||||
);
|
||||
const relateCtnr = relateSetting.closest("[services-settings-multiple]");
|
||||
const relateCtnrName = relateCtnr.getAttribute(
|
||||
"services-settings-multiple"
|
||||
"data-services-settings-multiple"
|
||||
);
|
||||
//then we sort the setting on the right container name by suffixe number
|
||||
if (!(relateCtnrName in sortMultiples)) {
|
||||
|
@ -471,12 +501,16 @@ class Multiple {
|
|||
}
|
||||
|
||||
addOneMultGroup() {
|
||||
const settings = document.querySelector("[services-modal-form]");
|
||||
const multAddBtns = settings.querySelectorAll("[services-multiple-add]");
|
||||
const settings = document.querySelector("[data-services-modal-form]");
|
||||
const multAddBtns = settings.querySelectorAll(
|
||||
"[data-services-multiple-add]"
|
||||
);
|
||||
multAddBtns.forEach((btn) => {
|
||||
//check if already one (SCHEMA exclude so length >= 2)
|
||||
const plugin = btn.closest("[plugin-item]");
|
||||
if (plugin.querySelectorAll("[services-settings-multiple]").length >= 2)
|
||||
const plugin = btn.closest("[data-plugin-item]");
|
||||
if (
|
||||
plugin.querySelectorAll("[data-services-settings-multiple]").length >= 2
|
||||
)
|
||||
return;
|
||||
btn.click();
|
||||
});
|
||||
|
@ -484,11 +518,13 @@ class Multiple {
|
|||
|
||||
showMultByAtt(att) {
|
||||
const multContainers = document.querySelectorAll(
|
||||
`[services-settings-multiple^=${att}]`
|
||||
`[data-services-settings-multiple^=${att}]`
|
||||
);
|
||||
multContainers.forEach((container) => {
|
||||
if (
|
||||
!container.getAttribute("services-settings-multiple").includes("SCHEMA")
|
||||
!container
|
||||
.getAttribute("data-services-settings-multiple")
|
||||
.includes("SCHEMA")
|
||||
)
|
||||
container.classList.remove("hidden");
|
||||
});
|
||||
|
@ -496,11 +532,13 @@ class Multiple {
|
|||
|
||||
toggleMultByAtt(att) {
|
||||
const multContainers = document.querySelectorAll(
|
||||
`[services-settings-multiple^=${att}]`
|
||||
`[data-services-settings-multiple^=${att}]`
|
||||
);
|
||||
multContainers.forEach((container) => {
|
||||
if (
|
||||
!container.getAttribute("services-settings-multiple").includes("SCHEMA")
|
||||
!container
|
||||
.getAttribute("data-services-settings-multiple")
|
||||
.includes("SCHEMA")
|
||||
)
|
||||
container.classList.toggle("hidden");
|
||||
});
|
||||
|
@ -510,12 +548,12 @@ class Multiple {
|
|||
//get schema settings
|
||||
const multiples = {};
|
||||
const schemaSettings = document.querySelectorAll(
|
||||
`[setting-container$="SCHEMA"]`
|
||||
`[data-setting-container$="SCHEMA"]`
|
||||
);
|
||||
// loop on every schema settings
|
||||
schemaSettings.forEach((schema) => {
|
||||
const schemaName = schema
|
||||
.getAttribute("setting-container")
|
||||
.getAttribute("data-setting-container")
|
||||
.replace("_SCHEMA", "")
|
||||
.trim();
|
||||
//check if match with service setting
|
||||
|
@ -539,12 +577,14 @@ class Multiple {
|
|||
)) {
|
||||
//we need to access the DOM schema container
|
||||
const schemaCtnr = document.querySelector(
|
||||
`[services-settings-multiple="${schemaCtnrName}"]`
|
||||
`[data-services-settings-multiple="${schemaCtnrName}"]`
|
||||
);
|
||||
//now we have to loop on each multiple settings group
|
||||
for (const [suffix, settings] of Object.entries(multGroupBySuffix)) {
|
||||
//we have to clone schema container first
|
||||
const schemaCtnrClone = schemaCtnr.cloneNode(true);
|
||||
//remove id to avoid duplicate and for W3C
|
||||
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}`;
|
||||
|
@ -553,7 +593,7 @@ class Multiple {
|
|||
for (const [name, data] of Object.entries(settings)) {
|
||||
//get setting container of clone container
|
||||
const settingContainer = schemaCtnrClone.querySelector(
|
||||
`[setting-container="${name}"]`
|
||||
`[data-setting-container="${name}"]`
|
||||
);
|
||||
//replace input info
|
||||
this.setSetting(data["value"], data["method"], settingContainer);
|
||||
|
@ -570,9 +610,9 @@ class Multiple {
|
|||
changeCloneSuffix(schemaCtnrClone, suffix) {
|
||||
//rename multiple container
|
||||
schemaCtnrClone.setAttribute(
|
||||
"services-settings-multiple",
|
||||
"data-services-settings-multiple",
|
||||
schemaCtnrClone
|
||||
.getAttribute("services-settings-multiple")
|
||||
.getAttribute("data-services-settings-multiple")
|
||||
.replace("_SCHEMA", suffix)
|
||||
);
|
||||
|
||||
|
@ -587,12 +627,18 @@ class Multiple {
|
|||
|
||||
//rename setting container
|
||||
const settingCtnrs = schemaCtnrClone.querySelectorAll(
|
||||
"[setting-container]"
|
||||
"[data-setting-container]"
|
||||
);
|
||||
settingCtnrs.forEach((settingCtnr) => {
|
||||
settingCtnr.setAttribute(
|
||||
"setting-container",
|
||||
settingCtnr.getAttribute("setting-container").replace("_SCHEMA", suffix)
|
||||
"data-setting-container",
|
||||
settingCtnr
|
||||
.getAttribute("data-setting-container")
|
||||
.replace("_SCHEMA", suffix)
|
||||
);
|
||||
settingCtnr.setAttribute(
|
||||
"id",
|
||||
settingCtnr.getAttribute("id").replace("_SCHEMA", suffix)
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -636,22 +682,22 @@ class Multiple {
|
|||
inp.checked = value === "yes" ? true : false;
|
||||
if (inp.hasAttribute("disabled")) {
|
||||
const hidden_inp = inp
|
||||
.closest("div[checkbox-handler]")
|
||||
.closest("div[data-checkbox-handler]")
|
||||
.querySelector("input[type='hidden']");
|
||||
hidden_inp.setAttribute("value", value);
|
||||
}
|
||||
}
|
||||
|
||||
inp.value = value;
|
||||
inp.setAttribute("method", method);
|
||||
inp.setAttribute("data-method", method);
|
||||
});
|
||||
} catch (err) {}
|
||||
//update select
|
||||
try {
|
||||
const select = settingContainer.querySelector("select");
|
||||
const name = select.getAttribute("services-setting-select-default");
|
||||
const name = select.getAttribute("data-services-setting-select-default");
|
||||
const selTxt = document.querySelector(
|
||||
`[services-setting-select-text='${name}']`
|
||||
`[data-services-setting-select-text='${name}']`
|
||||
);
|
||||
|
||||
selTxt.textContent = value;
|
||||
|
@ -664,7 +710,7 @@ class Multiple {
|
|||
? option.setAttribute("selected")
|
||||
: option.removeAttribute("selected");
|
||||
}
|
||||
select.setAttribute("method", method);
|
||||
select.setAttribute("data-method", method);
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
|
@ -676,17 +722,17 @@ class Multiple {
|
|||
|
||||
setDisabled() {
|
||||
const multipleCtnr = document.querySelectorAll(
|
||||
"[services-settings-multiple]"
|
||||
"[data-services-settings-multiple]"
|
||||
);
|
||||
multipleCtnr.forEach((container) => {
|
||||
const settings = container.querySelectorAll("[setting-container]");
|
||||
const settings = container.querySelectorAll("[data-setting-container]");
|
||||
|
||||
settings.forEach((setting) => {
|
||||
//replace input info
|
||||
try {
|
||||
const inps = setting.querySelectorAll("input");
|
||||
inps.forEach((inp) => {
|
||||
const method = inp.getAttribute("method") || "default";
|
||||
const method = inp.getAttribute("data-method") || "default";
|
||||
if (method === "ui" || method === "default") {
|
||||
inp.removeAttribute("disabled");
|
||||
} else {
|
||||
|
@ -698,10 +744,12 @@ class Multiple {
|
|||
try {
|
||||
const selects = setting.querySelectorAll("select");
|
||||
selects.forEach((select) => {
|
||||
const method = select.getAttribute("method") || "default";
|
||||
const name = select.getAttribute("services-setting-select-default");
|
||||
const method = select.getAttribute("data-method") || "default";
|
||||
const name = select.getAttribute(
|
||||
"data-services-setting-select-default"
|
||||
);
|
||||
const selDOM = document.querySelector(
|
||||
`button[services-setting-select='${name}']`
|
||||
`button[data-services-setting-select='${name}']`
|
||||
);
|
||||
if (method === "ui" || method === "default") {
|
||||
selDOM.removeAttribute("disabled", "");
|
||||
|
@ -726,23 +774,25 @@ class Multiple {
|
|||
hiddenIfNoMultiples() {
|
||||
//hide multiple btn if no multiple exist on a plugin
|
||||
const multiples = document.querySelectorAll(
|
||||
`[${this.prefix}-settings-multiple]`
|
||||
`[data-${this.prefix}-settings-multiple]`
|
||||
);
|
||||
multiples.forEach((container) => {
|
||||
if (container.querySelectorAll(`[setting-container]`).length <= 0)
|
||||
if (container.querySelectorAll(`[data-setting-container]`).length <= 0)
|
||||
container.parentElement
|
||||
.querySelector("[multiple-handler]")
|
||||
.querySelector("[data-multiple-handler]")
|
||||
.classList.add("hidden");
|
||||
});
|
||||
}
|
||||
|
||||
removePrevMultiples() {
|
||||
const multiPlugins = document.querySelectorAll(
|
||||
`[${this.prefix}-settings-multiple]`
|
||||
`[data-${this.prefix}-settings-multiple]`
|
||||
);
|
||||
multiPlugins.forEach((multiGrp) => {
|
||||
if (
|
||||
!multiGrp.getAttribute("services-settings-multiple").includes("SCHEMA")
|
||||
!multiGrp
|
||||
.getAttribute("data-services-settings-multiple")
|
||||
.includes("SCHEMA")
|
||||
)
|
||||
multiGrp.remove();
|
||||
});
|
||||
|
@ -771,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();
|
||||
|
@ -778,7 +829,7 @@ const setModal = new ServiceModal();
|
|||
const format = new FormatValue();
|
||||
const setFilterGlobal = new FilterSettings(
|
||||
"settings-filter",
|
||||
"[service-content='settings']"
|
||||
"[data-service-content='settings']"
|
||||
);
|
||||
|
||||
const setMultiple = new Multiple("services");
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
class FolderNav {
|
||||
constructor(prefix) {
|
||||
this.prefix = prefix;
|
||||
this.breadContainer = document.querySelector(`[${this.prefix}-breadcrumb]`);
|
||||
this.container = document.querySelector(`[${this.prefix}-container]`);
|
||||
this.listContainer = document.querySelector(`[${this.prefix}-folders]`);
|
||||
this.els = document.querySelectorAll(`div[${this.prefix}-element]`);
|
||||
this.breadContainer = document.querySelector(`[data-${this.prefix}-breadcrumb]`);
|
||||
this.container = document.querySelector(`[data-${this.prefix}-container]`);
|
||||
this.listContainer = document.querySelector(`[data-${this.prefix}-folders]`);
|
||||
this.els = document.querySelectorAll(`div[data-${this.prefix}-element]`);
|
||||
this.files = document.querySelectorAll(
|
||||
`div[${this.prefix}-element][_type='file']`
|
||||
`div[data-${this.prefix}-element][data-_type='file']`
|
||||
);
|
||||
this.addFileEl = document.querySelector(`[${this.prefix}-add-file]`);
|
||||
this.addFolderEl = document.querySelector(`[${this.prefix}-add-folder]`);
|
||||
this.addFileEl = document.querySelector(`[data-${this.prefix}-add-file]`);
|
||||
this.addFolderEl = document.querySelector(`[data-${this.prefix}-add-folder]`);
|
||||
this.initSorted();
|
||||
this.initNav();
|
||||
}
|
||||
|
@ -25,9 +25,9 @@ class FolderNav {
|
|||
this.container.addEventListener("click", (e) => {
|
||||
//GO ON NESTED FOLDER
|
||||
try {
|
||||
if (e.target.closest("div").getAttribute("_type") === "folder") {
|
||||
if (e.target.closest("div").getAttribute("data-_type") === "folder") {
|
||||
//avoid logic on action btn click
|
||||
const folder = e.target.closest("div[_type='folder']");
|
||||
const folder = e.target.closest("div[data-_type='folder']");
|
||||
this.updatedNested(folder);
|
||||
}
|
||||
} catch (err) {}
|
||||
|
@ -36,8 +36,8 @@ class FolderNav {
|
|||
if (
|
||||
e.target
|
||||
.closest("li")
|
||||
.hasAttribute(`${this.prefix}-breadcrumb-item`) &&
|
||||
!e.target.closest("li").hasAttribute(`${this.prefix}-back`) &&
|
||||
.hasAttribute(`data-${this.prefix}-breadcrumb-item`) &&
|
||||
!e.target.closest("li").hasAttribute(`data-${this.prefix}-back`) &&
|
||||
e.target.closest("li").nextSibling !== null
|
||||
) {
|
||||
const breadItem = e.target.closest("li");
|
||||
|
@ -47,8 +47,8 @@ class FolderNav {
|
|||
//BREADCRUMB BACK LOGIC
|
||||
try {
|
||||
if (
|
||||
e.target.closest("li").hasAttribute(`${this.prefix}-back`) &&
|
||||
+this.breadContainer.lastElementChild.getAttribute("level") !== 0
|
||||
e.target.closest("li").hasAttribute(`data-${this.prefix}-back`) &&
|
||||
+this.breadContainer.lastElementChild.getAttribute("data-level") !== 0
|
||||
) {
|
||||
//back is like clicking on last prev element
|
||||
const prevItem =
|
||||
|
@ -81,7 +81,7 @@ class FolderNav {
|
|||
//remove useless bread
|
||||
this.removeBreadElByLvl(+prevLvl);
|
||||
const folder = document.querySelector(
|
||||
`div[${this.prefix}-element][path='${item.getAttribute("path")}']`
|
||||
`div[data-${this.prefix}-element][data-path='${item.getAttribute("data-path")}']`
|
||||
);
|
||||
this.updateActions(folder);
|
||||
}
|
||||
|
@ -91,8 +91,8 @@ class FolderNav {
|
|||
//by default
|
||||
this.hideAddConf();
|
||||
//check if folder allow add file/folder
|
||||
const isAddFile = folder.getAttribute("can-create-file");
|
||||
const isAddFolder = folder.getAttribute("can-create-folder");
|
||||
const isAddFile = folder.getAttribute("data-can-create-file");
|
||||
const isAddFolder = folder.getAttribute("data-can-create-folder");
|
||||
isAddFile === "True" ? this.addFileEl.classList.remove("hidden") : "";
|
||||
isAddFolder === "True" ? this.addFolderEl.classList.remove("hidden") : "";
|
||||
}
|
||||
|
@ -104,11 +104,11 @@ class FolderNav {
|
|||
|
||||
showCurrentFolderEls(path, lvl) {
|
||||
const nestedEl = document.querySelectorAll(
|
||||
`div[path^="${path}/"][level="${+lvl + 1}"]`
|
||||
`div[data-path^="${path}/"][data-level="${+lvl + 1}"]`
|
||||
);
|
||||
for (let i = 0; i < nestedEl.length; i++) {
|
||||
const el = nestedEl[i];
|
||||
el.setAttribute("current-el", "");
|
||||
el.setAttribute("data-current-el", "");
|
||||
el.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
|
@ -117,28 +117,28 @@ class FolderNav {
|
|||
//the clicked bread item
|
||||
removeBreadElByLvl(lvl) {
|
||||
const breadcrumbItem = this.breadContainer.querySelectorAll(
|
||||
`[${this.prefix}-breadcrumb-item]`
|
||||
`[data-${this.prefix}-breadcrumb-item]`
|
||||
);
|
||||
breadcrumbItem.forEach((item) => {
|
||||
if (item.hasAttribute("level") && +item.getAttribute("level") > lvl)
|
||||
if (item.hasAttribute("data-level") && +item.getAttribute("data-level") > lvl)
|
||||
item.remove();
|
||||
});
|
||||
}
|
||||
|
||||
//retrieve path, level and text
|
||||
getElAtt(el) {
|
||||
const newPath = el.getAttribute("path");
|
||||
const newLvl = el.getAttribute("level");
|
||||
const newTxt = el.getAttribute("name");
|
||||
const newPath = el.getAttribute("data-path");
|
||||
const newLvl = el.getAttribute("data-level");
|
||||
const newTxt = el.getAttribute("data-name");
|
||||
return [newPath, newLvl, newTxt];
|
||||
}
|
||||
|
||||
//hidden all folders
|
||||
hiddenConfEls() {
|
||||
this.els = document.querySelectorAll(`div[${this.prefix}-element]`);
|
||||
this.els = document.querySelectorAll(`div[data-${this.prefix}-element]`);
|
||||
this.els.forEach((el) => {
|
||||
el.classList.add("hidden");
|
||||
el.removeAttribute("current-el");
|
||||
el.removeAttribute("data-current-el");
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -149,10 +149,10 @@ class FolderNav {
|
|||
itemEl.className = "leading-normal text-sm";
|
||||
//set item atts
|
||||
const itemAtt = [
|
||||
["path", path],
|
||||
[`${this.prefix}-breadcrumb-item`, ""],
|
||||
["level", level],
|
||||
["name", name],
|
||||
["data-path", path],
|
||||
[`data-${this.prefix}-breadcrumb-item`, ""],
|
||||
["data-level", level],
|
||||
["data-name", name],
|
||||
];
|
||||
for (let i = 0; i < itemAtt.length; i++) {
|
||||
itemEl.setAttribute(`${itemAtt[i][0]}`, `${itemAtt[i][1]}`);
|
||||
|
@ -171,9 +171,9 @@ class FolderNav {
|
|||
class FolderDropdown {
|
||||
constructor(prefix) {
|
||||
this.prefix = prefix;
|
||||
this.container = document.querySelector(`[${this.prefix}-container]`);
|
||||
this.container = document.querySelector(`[data-${this.prefix}-container]`);
|
||||
this.dropEls = document.querySelectorAll(
|
||||
`[${this.prefix}-action-dropdown]`
|
||||
`[data-${this.prefix}-action-dropdown]`
|
||||
);
|
||||
this.init();
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ class FolderDropdown {
|
|||
//remove when none click
|
||||
try {
|
||||
if (
|
||||
!e.target.closest("div").hasAttribute(`${this.prefix}-action-button`)
|
||||
!e.target.closest("div").hasAttribute(`data-${this.prefix}-action-button`)
|
||||
) {
|
||||
this.hideDropEls();
|
||||
}
|
||||
|
@ -192,11 +192,11 @@ class FolderDropdown {
|
|||
//show dropdown actions for folders
|
||||
try {
|
||||
if (
|
||||
e.target.closest("div").hasAttribute(`${this.prefix}-action-button`)
|
||||
e.target.closest("div").hasAttribute(`data-${this.prefix}-action-button`)
|
||||
) {
|
||||
const dropEl = e.target
|
||||
.closest(`div[${this.prefix}-element]`)
|
||||
.querySelector(`[${this.prefix}-action-dropdown]`);
|
||||
.closest(`div[data-${this.prefix}-element]`)
|
||||
.querySelector(`[data-${this.prefix}-action-dropdown]`);
|
||||
//avoid multiple dropdown
|
||||
if (prevActionBtn === "") prevActionBtn = dropEl;
|
||||
if (prevActionBtn !== dropEl) this.hideDropEls();
|
||||
|
@ -209,13 +209,13 @@ class FolderDropdown {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`${this.prefix}-action-dropdown-btn`)
|
||||
.hasAttribute(`data-${this.prefix}-action-dropdown-btn`)
|
||||
) {
|
||||
const att = e.target
|
||||
.closest("button")
|
||||
.getAttribute(`${this.prefix}-action-dropdown-btn`);
|
||||
.getAttribute(`data-${this.prefix}-action-dropdown-btn`);
|
||||
const dropEl = document.querySelector(
|
||||
`[${this.prefix}-action-dropdown="${att}"]`
|
||||
`[data-${this.prefix}-action-dropdown="${att}"]`
|
||||
);
|
||||
this.hideDrop(dropEl);
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ class FolderDropdown {
|
|||
class FolderEditor {
|
||||
constructor() {
|
||||
this.editor = ace.edit("editor");
|
||||
this.darkMode = document.querySelector("[dark-toggle]");
|
||||
this.darkMode = document.querySelector("[data-dark-toggle]");
|
||||
this.initEditor();
|
||||
this.listenDarkToggle();
|
||||
}
|
||||
|
@ -287,32 +287,32 @@ class FolderModal {
|
|||
constructor(prefix) {
|
||||
this.prefix = prefix;
|
||||
//container
|
||||
this.container = document.querySelector(`[${this.prefix}-container]`);
|
||||
this.container = document.querySelector(`[data-${this.prefix}-container]`);
|
||||
//add service/file elements
|
||||
this.breadContainer = document.querySelector(`[${this.prefix}-breadcrumb]`);
|
||||
this.breadContainer = document.querySelector(`[data-${this.prefix}-breadcrumb]`);
|
||||
this.addConfContainer = document.querySelector(
|
||||
`[${this.prefix}-add-container]`
|
||||
`[data-${this.prefix}-add-container]`
|
||||
);
|
||||
//modal DOM elements
|
||||
this.form = document.querySelector(`[${this.prefix}-modal-form]`);
|
||||
this.modalEl = document.querySelector(`[${this.prefix}-modal]`);
|
||||
this.form = document.querySelector(`[data-${this.prefix}-modal-form]`);
|
||||
this.modalEl = document.querySelector(`[data-${this.prefix}-modal]`);
|
||||
this.modalTitle = this.modalEl.querySelector(
|
||||
`[${this.prefix}-modal-title]`
|
||||
`[data-${this.prefix}-modal-title]`
|
||||
);
|
||||
this.modalPath = this.modalEl.querySelector(`[${this.prefix}-modal-path]`);
|
||||
this.modalPath = this.modalEl.querySelector(`[data-${this.prefix}-modal-path]`);
|
||||
this.modalEditor = this.modalEl.querySelector(
|
||||
`[${this.prefix}-modal-editor]`
|
||||
`[data-${this.prefix}-modal-editor]`
|
||||
);
|
||||
this.modalPathPrev = this.modalPath.querySelector(
|
||||
`p[${this.prefix}-modal-path-prefix]`
|
||||
`p[data-${this.prefix}-modal-path-prefix]`
|
||||
);
|
||||
this.modalPathName = this.modalPath.querySelector("input");
|
||||
this.modalPathSuffix = this.modalPath.querySelector(
|
||||
`p[${this.prefix}-modal-path-suffix]`
|
||||
`p[data-${this.prefix}-modal-path-suffix]`
|
||||
);
|
||||
|
||||
this.modalSubmit = this.modalEl.querySelector(
|
||||
`[${this.prefix}-modal-submit]`
|
||||
`[data-${this.prefix}-modal-submit]`
|
||||
);
|
||||
//hidden input for backend
|
||||
this.modalInpPath = this.modalEl.querySelector("#path");
|
||||
|
@ -336,7 +336,7 @@ class FolderModal {
|
|||
this.addConfContainer.addEventListener("click", (e) => {
|
||||
//add folder
|
||||
try {
|
||||
if (e.target.closest("li").hasAttribute(`${this.prefix}-add-folder`)) {
|
||||
if (e.target.closest("li").hasAttribute(`data-${this.prefix}-add-folder`)) {
|
||||
this.setModal(
|
||||
"new",
|
||||
this.getPathFromBread(),
|
||||
|
@ -349,7 +349,7 @@ class FolderModal {
|
|||
} catch (err) {}
|
||||
//add file
|
||||
try {
|
||||
if (e.target.closest("li").hasAttribute(`${this.prefix}-add-file`)) {
|
||||
if (e.target.closest("li").hasAttribute(`data-${this.prefix}-add-file`)) {
|
||||
this.setModal(
|
||||
"new",
|
||||
this.getPathFromBread(),
|
||||
|
@ -367,10 +367,10 @@ class FolderModal {
|
|||
this.container.addEventListener("click", (e) => {
|
||||
//click on file logic
|
||||
try {
|
||||
if (e.target.closest("div").getAttribute("_type") == "file") {
|
||||
if (e.target.closest("div").getAttribute("data-_type") == "file") {
|
||||
const btnEl = e.target
|
||||
.closest("div")
|
||||
.querySelector('button[value="view"]');
|
||||
.querySelector('button[value]');
|
||||
const [action, path, type, content, name, level] =
|
||||
this.getInfoFromActionBtn(btnEl);
|
||||
this.setModal(action, path, type, content, name, level);
|
||||
|
@ -382,7 +382,7 @@ class FolderModal {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`${this.prefix}-action-dropdown-btn`) &&
|
||||
.hasAttribute(`data-${this.prefix}-action-dropdown-btn`) &&
|
||||
e.target.closest("button").getAttribute("value") !== "download"
|
||||
) {
|
||||
const btnEl = e.target.closest("button");
|
||||
|
@ -397,7 +397,7 @@ class FolderModal {
|
|||
if (
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`${this.prefix}-action-dropdown-btn`) &&
|
||||
.hasAttribute(`data-${this.prefix}-action-dropdown-btn`) &&
|
||||
e.target.closest("button").getAttribute("value") === "download"
|
||||
) {
|
||||
const btnEl = e.target.closest("button");
|
||||
|
@ -414,7 +414,7 @@ class FolderModal {
|
|||
//close modal logic
|
||||
try {
|
||||
if (
|
||||
e.target.closest("button").hasAttribute(`${this.prefix}-modal-close`)
|
||||
e.target.closest("button").hasAttribute(`data-${this.prefix}-modal-close`)
|
||||
) {
|
||||
this.closeModal();
|
||||
}
|
||||
|
@ -467,12 +467,12 @@ class FolderModal {
|
|||
//for add file/folder btn
|
||||
//get path of last bread element
|
||||
getPathFromBread() {
|
||||
const path = this.breadContainer.lastElementChild.getAttribute("path");
|
||||
const path = this.breadContainer.lastElementChild.getAttribute("data-path");
|
||||
return `${path}/`;
|
||||
}
|
||||
|
||||
getLevelFromBread() {
|
||||
const level = this.breadContainer.lastElementChild.getAttribute("level");
|
||||
const level = this.breadContainer.lastElementChild.getAttribute("data-level");
|
||||
return level;
|
||||
}
|
||||
//set all needed data from btn action and folder info
|
||||
|
@ -562,16 +562,16 @@ class FolderModal {
|
|||
//get all needed info when clicking on action btn
|
||||
getInfoFromActionBtn(btnEl) {
|
||||
const action = btnEl.getAttribute("value");
|
||||
const name = btnEl.getAttribute(`${this.prefix}-action-dropdown-btn`);
|
||||
const folder = btnEl.closest(`[${this.prefix}-element]`);
|
||||
const level = folder.getAttribute("level");
|
||||
const path = folder.getAttribute("path");
|
||||
const type = folder.getAttribute("_type");
|
||||
const name = btnEl.getAttribute(`data-${this.prefix}-action-dropdown-btn`);
|
||||
const folder = btnEl.closest(`[data-${this.prefix}-element]`);
|
||||
const level = folder.getAttribute("data-level");
|
||||
const path = folder.getAttribute("data-path");
|
||||
const type = folder.getAttribute("data-_type");
|
||||
let content;
|
||||
try {
|
||||
content = folder
|
||||
.querySelector(`[${this.prefix}-content]`)
|
||||
.getAttribute("value");
|
||||
.querySelector(`[data-${this.prefix}-content]`)
|
||||
.getAttribute("data-value");
|
||||
} catch (err) {
|
||||
content = "";
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ class Checkbox {
|
|||
try {
|
||||
//case a related checkbox element is clicked and checkbox is enabled
|
||||
if (
|
||||
e.target.closest("div").hasAttribute("checkbox-handler") &&
|
||||
e.target.closest("div").hasAttribute("data-checkbox-handler") &&
|
||||
!e.target
|
||||
.closest("div")
|
||||
.querySelector('input[type="checkbox"]')
|
||||
|
@ -41,15 +41,19 @@ class Select {
|
|||
try {
|
||||
if (!e.target.closest("button")) {
|
||||
const selectEls = document.querySelectorAll(
|
||||
"div[setting-select-dropdown]"
|
||||
"div[data-setting-select-dropdown]"
|
||||
);
|
||||
selectEls.forEach((select) => {
|
||||
select.classList.add("hidden");
|
||||
select.classList.remove("flex");
|
||||
});
|
||||
const btnEls = document.querySelectorAll("button[setting-select]");
|
||||
const btnEls = document.querySelectorAll(
|
||||
"button[data-setting-select]"
|
||||
);
|
||||
btnEls.forEach((btn) => {
|
||||
const dropdownChevron = btn.querySelector(`svg[setting-select]`);
|
||||
const dropdownChevron = btn.querySelector(
|
||||
`svg[data-setting-select]`
|
||||
);
|
||||
dropdownChevron.classList.remove("rotate-180");
|
||||
});
|
||||
}
|
||||
|
@ -57,7 +61,7 @@ class Select {
|
|||
//SELECT BTN LOGIC
|
||||
try {
|
||||
if (
|
||||
e.target.closest("button").hasAttribute(`setting-select`) &&
|
||||
e.target.closest("button").hasAttribute(`data-setting-select`) &&
|
||||
!e.target.closest("button").hasAttribute(`disabled`)
|
||||
) {
|
||||
const btnEl = e.target.closest("button");
|
||||
|
@ -67,22 +71,26 @@ class Select {
|
|||
//SELECT DROPDOWN BTN LOGIC
|
||||
try {
|
||||
if (
|
||||
e.target.closest("button").hasAttribute(`setting-select-dropdown-btn`)
|
||||
e.target
|
||||
.closest("button")
|
||||
.hasAttribute(`data-setting-select-dropdown-btn`)
|
||||
) {
|
||||
const btn = e.target.closest(`button[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
|
||||
const selectCustom = btn
|
||||
.closest("div[select-container]")
|
||||
.querySelector(`button[setting-select]`);
|
||||
.closest("div[data-select-container]")
|
||||
.querySelector(`button[data-setting-select]`);
|
||||
|
||||
selectCustom.querySelector(`[setting-select-text]`).textContent =
|
||||
selectCustom.querySelector(`[data-setting-select-text]`).textContent =
|
||||
btnValue;
|
||||
//add selected to new value
|
||||
|
||||
//change style
|
||||
const dropdownEl = btn.closest(`div[setting-select-dropdown]`);
|
||||
const dropdownEl = btn.closest(`div[data-setting-select-dropdown]`);
|
||||
dropdownEl.classList.add("hidden");
|
||||
dropdownEl.classList.remove("flex");
|
||||
|
||||
|
@ -93,8 +101,6 @@ class Select {
|
|||
btn.classList.remove(
|
||||
"dark:bg-primary",
|
||||
"bg-primary",
|
||||
"bg-primary",
|
||||
"text-gray-300",
|
||||
"text-gray-300"
|
||||
);
|
||||
btn.classList.add("bg-white", "dark:bg-slate-700", "text-gray-700");
|
||||
|
@ -108,13 +114,14 @@ class Select {
|
|||
btn.classList.add("dark:bg-primary", "bg-primary", "text-gray-300");
|
||||
|
||||
//close dropdown
|
||||
const dropdownChevron =
|
||||
selectCustom.querySelector(`svg[setting-select]`);
|
||||
const dropdownChevron = selectCustom.querySelector(
|
||||
`svg[data-setting-select]`
|
||||
);
|
||||
dropdownChevron.classList.remove("rotate-180");
|
||||
|
||||
//update real select element
|
||||
const realSel = btn
|
||||
.closest("div[setting-container]")
|
||||
.closest("div[data-setting-container]")
|
||||
.querySelector("select");
|
||||
this.updateSelected(realSel, btnValue);
|
||||
}
|
||||
|
@ -141,8 +148,8 @@ class Select {
|
|||
//toggle dropdown
|
||||
const dropdownEl = btn
|
||||
.closest("div")
|
||||
.querySelector(`[setting-select-dropdown]`);
|
||||
const dropdownChevron = btn.querySelector(`svg[setting-select]`);
|
||||
.querySelector(`[data-setting-select-dropdown]`);
|
||||
const dropdownChevron = btn.querySelector(`svg[data-setting-select]`);
|
||||
dropdownEl.classList.toggle("hidden");
|
||||
dropdownEl.classList.toggle("flex");
|
||||
dropdownChevron.classList.toggle("rotate-180");
|
||||
|
@ -157,10 +164,12 @@ class Password {
|
|||
init() {
|
||||
window.addEventListener("click", (e) => {
|
||||
try {
|
||||
if (e.target.closest("button").hasAttribute("setting-password")) {
|
||||
if (e.target.closest("button").hasAttribute("data-setting-password")) {
|
||||
const btn = e.target.closest("button");
|
||||
const action = btn.getAttribute("setting-password");
|
||||
const inp = btn.closest("[setting-container]").querySelector("input");
|
||||
const action = btn.getAttribute("data-setting-password");
|
||||
const inp = btn
|
||||
.closest("[data-setting-container]")
|
||||
.querySelector("input");
|
||||
this.setValDisplay(action, inp);
|
||||
this.hiddenBtns(btn);
|
||||
this.showOppositeBtn(btn, action);
|
||||
|
@ -174,7 +183,7 @@ class Password {
|
|||
const opposite = action === "visible" ? "invisible" : "visible";
|
||||
|
||||
btnEls.forEach((btn) => {
|
||||
const action = btn.getAttribute("setting-password");
|
||||
const action = btn.getAttribute("data-setting-password");
|
||||
|
||||
if (action === opposite) {
|
||||
btn.classList.add("flex");
|
||||
|
@ -199,9 +208,54 @@ class Password {
|
|||
|
||||
getBtns(btnEl) {
|
||||
return btnEl
|
||||
.closest("[setting-container]")
|
||||
.querySelectorAll("button[setting-password]");
|
||||
.closest("[data-setting-container]")
|
||||
.querySelectorAll("button[data-setting-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 };
|
||||
|
|
|
@ -7,7 +7,7 @@ class Popover {
|
|||
window.addEventListener("pointerover", (e) => {
|
||||
//POPOVER LOGIC
|
||||
try {
|
||||
if (e.target.closest("svg").hasAttribute(`popover-btn`)) {
|
||||
if (e.target.closest("svg").hasAttribute(`data-popover-btn`)) {
|
||||
this.showPopover(e.target);
|
||||
}
|
||||
} catch (err) {}
|
||||
|
@ -16,7 +16,7 @@ class Popover {
|
|||
window.addEventListener("pointerout", (e) => {
|
||||
//POPOVER LOGIC
|
||||
try {
|
||||
if (e.target.closest("svg").hasAttribute(`popover-btn`)) {
|
||||
if (e.target.closest("svg").hasAttribute(`data-popover-btn`)) {
|
||||
this.hidePopover(e.target);
|
||||
}
|
||||
} catch (err) {}
|
||||
|
@ -26,14 +26,14 @@ class Popover {
|
|||
showPopover(el) {
|
||||
const btn = el.closest("svg");
|
||||
//toggle curr popover
|
||||
const popover = btn.parentElement.querySelector(`[popover-content]`);
|
||||
const popover = btn.parentElement.querySelector(`[data-popover-content]`);
|
||||
popover.classList.remove("hidden");
|
||||
}
|
||||
|
||||
hidePopover(el) {
|
||||
const btn = el.closest("svg");
|
||||
//toggle curr popover
|
||||
const popover = btn.parentElement.querySelector(`[popover-content]`);
|
||||
const popover = btn.parentElement.querySelector(`[data-popover-content]`);
|
||||
popover.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
@ -47,15 +47,15 @@ class Tabs {
|
|||
window.addEventListener("click", (e) => {
|
||||
try {
|
||||
if (
|
||||
e.target.closest("button").hasAttribute("tab-handler") ||
|
||||
e.target.closest("button").hasAttribute("tab-handler-mobile")
|
||||
e.target.closest("button").hasAttribute("data-tab-handler") ||
|
||||
e.target.closest("button").hasAttribute("data-tab-handler-mobile")
|
||||
) {
|
||||
//get needed data
|
||||
const tab = e.target.closest("button");
|
||||
const tabAtt =
|
||||
tab.getAttribute("tab-handler") ||
|
||||
tab.getAttribute("tab-handler-mobile");
|
||||
const container = tab.closest("div[service-content]");
|
||||
tab.getAttribute("data-tab-handler") ||
|
||||
tab.getAttribute("data-tab-handler-mobile");
|
||||
const container = tab.closest("div[data-service-content]");
|
||||
// change style
|
||||
this.resetTabsStyle(container);
|
||||
this.highlightClicked(container, tabAtt);
|
||||
|
@ -69,9 +69,9 @@ class Tabs {
|
|||
} catch (err) {}
|
||||
|
||||
try {
|
||||
if (e.target.closest("button").hasAttribute("tab-dropdown-btn")) {
|
||||
if (e.target.closest("button").hasAttribute("data-tab-dropdown-btn")) {
|
||||
const dropBtn = e.target.closest("button");
|
||||
const container = dropBtn.closest("div[service-content]");
|
||||
const container = dropBtn.closest("div[data-service-content]");
|
||||
this.toggleDropdown(container);
|
||||
}
|
||||
} catch (err) {}
|
||||
|
@ -80,13 +80,13 @@ class Tabs {
|
|||
|
||||
resetTabsStyle(container) {
|
||||
//reset desktop style
|
||||
const tabsDesktop = container.querySelectorAll("button[tab-handler]");
|
||||
const tabsDesktop = container.querySelectorAll("button[data-tab-handler]");
|
||||
tabsDesktop.forEach((tab) => {
|
||||
tab.classList.remove("brightness-90", "z-[1001]");
|
||||
tab.classList.add("z-1000");
|
||||
});
|
||||
//reset mobile style
|
||||
const tabsMobile = container.querySelectorAll("button[tab-handler-mobile]");
|
||||
const tabsMobile = container.querySelectorAll("button[data-tab-handler-mobile]");
|
||||
tabsMobile.forEach((tab) => {
|
||||
tab.classList.add(
|
||||
"bg-white",
|
||||
|
@ -107,13 +107,13 @@ class Tabs {
|
|||
highlightClicked(container, tabAtt) {
|
||||
//desktop case
|
||||
const tabDesktop = container.querySelector(
|
||||
`button[tab-handler='${tabAtt}']`
|
||||
`button[data-tab-handler='${tabAtt}']`
|
||||
);
|
||||
tabDesktop.classList.add("brightness-90", "z-[1001]");
|
||||
|
||||
//mobile case
|
||||
const tabMobile = container.querySelector(
|
||||
`button[tab-handler-mobile='${tabAtt}']`
|
||||
`button[data-tab-handler-mobile='${tabAtt}']`
|
||||
);
|
||||
tabMobile.classList.add("dark:bg-primary", "bg-primary", "text-gray-300");
|
||||
tabMobile.classList.remove(
|
||||
|
@ -124,30 +124,30 @@ class Tabs {
|
|||
}
|
||||
|
||||
hideAllSettings(container) {
|
||||
const plugins = container.querySelectorAll("[plugin-item]");
|
||||
const plugins = container.querySelectorAll("[data-plugin-item]");
|
||||
plugins.forEach((plugin) => {
|
||||
plugin.classList.add("hidden");
|
||||
});
|
||||
}
|
||||
|
||||
showSettingClicked(container, tabAtt) {
|
||||
const plugin = container.querySelector(`[plugin-item='${tabAtt}']`);
|
||||
const plugin = container.querySelector(`[data-plugin-item='${tabAtt}']`);
|
||||
plugin.classList.remove("hidden");
|
||||
}
|
||||
|
||||
setDropBtnText(container, tabAtt) {
|
||||
const dropBtn = container.querySelector("[tab-dropdown-btn]");
|
||||
const dropBtn = container.querySelector("[data-tab-dropdown-btn]");
|
||||
dropBtn.querySelector("span").textContent = tabAtt;
|
||||
}
|
||||
|
||||
closeDropdown(container) {
|
||||
const dropdown = container.querySelector("[tab-dropdown]");
|
||||
const dropdown = container.querySelector("[data-tab-dropdown]");
|
||||
dropdown.classList.add("hidden");
|
||||
dropdown.classList.remove("flex");
|
||||
}
|
||||
|
||||
toggleDropdown(container) {
|
||||
const dropdown = container.querySelector("[tab-dropdown]");
|
||||
const dropdown = container.querySelector("[data-tab-dropdown]");
|
||||
dropdown.classList.toggle("hidden");
|
||||
dropdown.classList.toggle("flex");
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ class FilterSettings {
|
|||
this.input = document.querySelector(`input#${inputID}`);
|
||||
//DESKTOP
|
||||
this.container = document.querySelector(container);
|
||||
this.deskTabs = this.container.querySelectorAll(`[tab-handler]`);
|
||||
this.deskTabs = this.container.querySelectorAll(`[data-tab-handler]`);
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
@ -206,15 +206,15 @@ class FilterSettings {
|
|||
});
|
||||
//case no setting match, hidden tab and content
|
||||
if (settingCount === hiddenCount) {
|
||||
const tabName = tab.getAttribute(`tab-handler`);
|
||||
const tabName = tab.getAttribute(`data-tab-handler`);
|
||||
//hide mobile and desk tabs
|
||||
tab.classList.add("hidden");
|
||||
this.container
|
||||
.querySelector(`[tab-handler-mobile="${tabName}"]`)
|
||||
.querySelector(`[data-tab-handler-mobile="${tabName}"]`)
|
||||
.classList.add("hidden");
|
||||
this.container
|
||||
.querySelector(`[plugin-item=${tabName}]`)
|
||||
.querySelector("[setting-header]")
|
||||
.querySelector(`[data-plugin-item=${tabName}]`)
|
||||
.querySelector("[data-setting-header]")
|
||||
|
||||
.classList.add("hidden");
|
||||
}
|
||||
|
@ -224,15 +224,15 @@ class FilterSettings {
|
|||
|
||||
resetFilter() {
|
||||
this.deskTabs.forEach((tab) => {
|
||||
const tabName = tab.getAttribute(`tab-handler`);
|
||||
const tabName = tab.getAttribute(`data-tab-handler`);
|
||||
//hide mobile and desk tabs
|
||||
tab.classList.remove("hidden");
|
||||
this.container
|
||||
.querySelector(`[tab-handler-mobile="${tabName}"]`)
|
||||
.querySelector(`[data-tab-handler-mobile="${tabName}"]`)
|
||||
.classList.remove("hidden");
|
||||
this.container
|
||||
.querySelector(`[plugin-item=${tabName}]`)
|
||||
.querySelector("[setting-header]")
|
||||
.querySelector(`[data-plugin-item=${tabName}]`)
|
||||
.querySelector("[data-setting-header]")
|
||||
.classList.remove("hidden");
|
||||
const settings = this.getSettingsFromTab(tab);
|
||||
settings.forEach((setting) => {
|
||||
|
@ -242,11 +242,11 @@ class FilterSettings {
|
|||
}
|
||||
|
||||
getSettingsFromTab(tabEl) {
|
||||
const tabName = tabEl.getAttribute(`tab-handler`);
|
||||
const tabName = tabEl.getAttribute(`data-tab-handler`);
|
||||
const settingContainer = this.container
|
||||
.querySelector(`[plugin-item="${tabName}"]`)
|
||||
.querySelector(`[plugin-settings]`);
|
||||
const settings = settingContainer.querySelectorAll("[setting-container]");
|
||||
.querySelector(`[data-plugin-item="${tabName}"]`)
|
||||
.querySelector(`[data-plugin-settings]`);
|
||||
const settings = settingContainer.querySelectorAll("[data-setting-container]");
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
>Your browser does not support JavaScript!</noscript
|
||||
>
|
||||
<div
|
||||
loader
|
||||
data-loader
|
||||
class="fixed z-[10000] transition duration-300 h-screen w-screen bg-primary flex justify-center align-middle items-center"
|
||||
>
|
||||
<img
|
||||
loader-img
|
||||
data-loader-img
|
||||
src="images/logo-menu-2.png"
|
||||
class="duration-300 w-40 h-12 sm:w-50 sm:h-14 md:w-60 md:h-16 lg:w-80 lg:h-24 inline transition-all"
|
||||
alt="main logo"
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
{% extends "base.html" %} {% block content %} {% include "file-manager.html" %}
|
||||
{% extends "base.html" %} {% block content %} {% include "file_manager.html" %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
{% extends "base.html" %} {% block content %} {% include "file-manager.html" %}
|
||||
{% extends "base.html" %} {% block content %} {% include "file_manager.html" %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
||||
<!-- main container -->
|
||||
<div
|
||||
{{current_endpoint}}-container
|
||||
data-{{current_endpoint}}-container
|
||||
class="dark:brightness-110 md:min-h-75-screen col-span-12 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"
|
||||
>
|
||||
<div class="w-full grid-cols-12 grid">
|
||||
|
@ -13,12 +13,12 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
</h5>
|
||||
<!--breadcrumb -->
|
||||
<ul
|
||||
{{current_endpoint}}-breadcrumb
|
||||
data-{{current_endpoint}}-breadcrumb
|
||||
class="flex flex-wrap bg-transparent rounded-lg md:mb-8"
|
||||
>
|
||||
<li
|
||||
{{current_endpoint}}-breadcrumb-item
|
||||
{{current_endpoint}}-back
|
||||
data-{{current_endpoint}}-breadcrumb-item
|
||||
data-{{current_endpoint}}-back
|
||||
class="mr-2 cursor-pointer text-sm capitalize leading-normal text-gray-700"
|
||||
aria-current="page"
|
||||
>
|
||||
|
@ -39,10 +39,10 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
</svg>
|
||||
</li>
|
||||
<li
|
||||
{{current_endpoint}}-breadcrumb-item
|
||||
level="0"
|
||||
path="{% if current_endpoint == "cache" %}/var/cache/bunkerweb{% elif current_endpoint == "configs" %}/etc/bunkerweb/{{current_endpoint}}{% endif %}"
|
||||
name="{{current_endpoint}}"
|
||||
data-{{current_endpoint}}-breadcrumb-item
|
||||
data-level="0"
|
||||
data-path="{% if current_endpoint == "cache" %}/var/cache/bunkerweb{% elif current_endpoint == "configs" %}/etc/bunkerweb/{{current_endpoint}}{% endif %}"
|
||||
data-name="{{current_endpoint}}"
|
||||
class="leading-normal text-sm"
|
||||
>
|
||||
<button
|
||||
|
@ -57,11 +57,11 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
</div>
|
||||
<!-- actions -->
|
||||
<ul
|
||||
{{current_endpoint}}-add-container
|
||||
data-{{current_endpoint}}-add-container
|
||||
class="col-span-12 md:col-span-4 my-2 md:my-0 w-full flex justify-center md:justify-end items-center mb-3"
|
||||
>
|
||||
<li
|
||||
{{current_endpoint}}-add-folder
|
||||
data-{{current_endpoint}}-add-folder
|
||||
class="rounded transition hidden flex-col items-center mx-2 p-2 md:py-4 md:px-6 relative cursor-pointer hover:bg-gray-100 dark:hover:bg-slate-800"
|
||||
>
|
||||
<button type="button">
|
||||
|
@ -80,16 +80,15 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
d="M5.25 14.25h13.5m-13.5 0a3 3 0 01-3-3m3 3a3 3 0 100 6h13.5a3 3 0 100-6m-16.5-3a3 3 0 013-3h13.5a3 3 0 013 3m-19.5 0a4.5 4.5 0 01.9-2.7L5.737 5.1a3.375 3.375 0 012.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 01.9 2.7m0 0a3 3 0 01-3 3m0 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm-3 6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<p
|
||||
<span
|
||||
class="dark:text-gray-500 pt-1 mb-0 font-sans font-semibold leading-normal uppercase text-sm lg:text-md"
|
||||
>
|
||||
ADD SERVICE
|
||||
</p>
|
||||
</span>
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
{{current_endpoint}}-add-file
|
||||
data-{{current_endpoint}}-add-file
|
||||
class="rounded transition hidden flex-col items-center mx-2 p-2 md:py-4 md:px-6 relative cursor-pointer hover:bg-gray-100 dark:hover:bg-slate-800"
|
||||
>
|
||||
<button type="button">
|
||||
|
@ -109,11 +108,11 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
/>
|
||||
</svg>
|
||||
|
||||
<p
|
||||
<span
|
||||
class="dark:text-gray-500 pt-1 mb-0 font-sans font-semibold leading-normal uppercase text-sm lg:text-md"
|
||||
>
|
||||
ADD FILE
|
||||
</p>
|
||||
</span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -121,48 +120,42 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
</div>
|
||||
|
||||
<!-- folders-->
|
||||
<div {{current_endpoint}}-folders
|
||||
<div data-{{current_endpoint}}-folders
|
||||
class="grid grid-cols-12 gap-3">
|
||||
{% for folder in folders %} {% for child in folder['children'] recursive %}
|
||||
{{loop(child['children'])}}
|
||||
<!-- folder -->
|
||||
<div
|
||||
{{current_endpoint}}-element="{{child['name']}}"
|
||||
name="{{child['name']}}"
|
||||
can-create-folder="{{child['can_create_folders']}}"
|
||||
can-create-file="{{child['can_create_files']}}"
|
||||
path="{{child['path']}}"
|
||||
level="{{loop.depth}}"
|
||||
_type="{{child['type']}}"
|
||||
data-{{current_endpoint}}-element="{{child['name']}}"
|
||||
data-name="{{child['name']}}"
|
||||
data-can-create-folder="{{child['can_create_folders']}}"
|
||||
data-can-create-file="{{child['can_create_files']}}"
|
||||
data-path="{{child['path']}}"
|
||||
data-level="{{loop.depth}}"
|
||||
data-_type="{{child['type']}}"
|
||||
class="cursor-pointer {% if loop.depth != 1%} hidden {% endif %} relative min-h-20 col-span-12 md:col-span-6 2xl:col-span-4 3xl:col-span-3 p-3 flex justify-center items-center h-full transition rounded bg-gray-100 hover:bg-gray-300 dark:bg-slate-700 dark:hover:bg-slate-800"
|
||||
>
|
||||
{% if child['content'] %}
|
||||
<span
|
||||
value="{{child['content']}}"
|
||||
{{current_endpoint}}-content
|
||||
data-value="{{child['content']}}"
|
||||
data-{{current_endpoint}}-content
|
||||
class="hidden"
|
||||
></span>
|
||||
{% endif %}
|
||||
<span>
|
||||
<div class="pointer-events-none">
|
||||
<!-- service root-->
|
||||
{% if child['type'] == "folder" and current_endpoint == "configs" and loop.depth == 1 %}
|
||||
<svg
|
||||
class="absolute left-3 top-5 h-10 w-10 fill-primary stroke-gray-100 dark:stroke-gray-600 dark:brightness-150"
|
||||
class=" absolute left-3 top-5 h-10 w-10 fill-primary stroke-gray-100 dark:stroke-gray-600 dark:brightness-150"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="{1.5}"
|
||||
stroke="currentColor"
|
||||
className="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z"
|
||||
/>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
|
@ -171,42 +164,41 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
|
||||
<!-- services folder -->
|
||||
{% if child['type'] == "folder" and current_endpoint == "configs" and loop.depth != 1 %}
|
||||
<svg class="absolute left-3 top-5 h-10 w-10 fill-primary stroke-gray-100 dark:stroke-gray-600 dark:brightness-150" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 17.25v-.228a4.5 4.5 0 00-.12-1.03l-2.268-9.64a3.375 3.375 0 00-3.285-2.602H7.923a3.375 3.375 0 00-3.285 2.602l-2.268 9.64a4.5 4.5 0 00-.12 1.03v.228m19.5 0a3 3 0 01-3 3H5.25a3 3 0 01-3-3m19.5 0a3 3 0 00-3-3H5.25a3 3 0 00-3 3m16.5 0h.008v.008h-.008v-.008zm-3 0h.008v.008h-.008v-.008z" /></svg> {% endif %}
|
||||
<svg class=" absolute left-3 top-5 h-10 w-10 fill-primary stroke-gray-100 dark:stroke-gray-600 dark:brightness-150" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 17.25v-.228a4.5 4.5 0 00-.12-1.03l-2.268-9.64a3.375 3.375 0 00-3.285-2.602H7.923a3.375 3.375 0 00-3.285 2.602l-2.268 9.64a4.5 4.5 0 00-.12 1.03v.228m19.5 0a3 3 0 01-3 3H5.25a3 3 0 01-3-3m19.5 0a3 3 0 00-3-3H5.25a3 3 0 00-3 3m16.5 0h.008v.008h-.008v-.008zm-3 0h.008v.008h-.008v-.008z" /></svg> {% endif %}
|
||||
<!-- end services folder-->
|
||||
<!-- services files -->
|
||||
{% if child['type'] == "file" and current_endpoint == "configs" and loop.depth != 1 %}
|
||||
<svg class="absolute left-3 top-5 h-10 w-10 fill-primary stroke-gray-100 dark:stroke-gray-600 dark:brightness-150" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" /></svg>
|
||||
<svg class=" absolute left-3 top-5 h-10 w-10 fill-primary stroke-gray-100 dark:stroke-gray-600 dark:brightness-150" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" /></svg>
|
||||
{% endif %}
|
||||
<!-- end services files-->
|
||||
<!-- cache folder-->
|
||||
{% if child['type'] == "folder" and current_endpoint == "cache" and loop.depth == 1 %}
|
||||
<svg class="absolute left-3 top-5 h-10 w-10 fill-primary stroke-gray-100 dark:stroke-gray-600 dark:brightness-150" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<svg class=" absolute left-3 top-5 h-10 w-10 fill-primary stroke-gray-100 dark:stroke-gray-600 dark:brightness-150" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M20.25 7.5l-.625 10.632a2.25 2.25 0 01-2.247 2.118H6.622a2.25 2.25 0 01-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z" />
|
||||
</svg>
|
||||
{% endif %}
|
||||
<!-- end cache folder -->
|
||||
<!-- cache file -->
|
||||
{% if child['type'] == "file" and current_endpoint == "cache" %}
|
||||
<svg class="absolute left-3 top-5 h-10 w-10 fill-primary stroke-gray-100 dark:stroke-gray-600 dark:brightness-150"
|
||||
<svg class=" absolute left-3 top-5 h-10 w-10 fill-primary stroke-gray-100 dark:stroke-gray-600 dark:brightness-150"
|
||||
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 13.5H9m4.06-7.19l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z" />
|
||||
</svg>
|
||||
{% endif %}
|
||||
<!-- end cache file -->
|
||||
|
||||
|
||||
|
||||
|
||||
<p
|
||||
{{current_endpoint}}-element-text
|
||||
class="transition duration-300 ease-in-out dark:opacity-90 text-center ml-12 mr-7 mb-0 text-sm md:text-base text-slate-700 dark:text-gray-300"
|
||||
<span
|
||||
data-{{current_endpoint}}-element-text
|
||||
class="pointer-events-none transition duration-300 ease-in-out dark:opacity-90 text-center ml-12 mr-7 mb-0 text-sm md:text-base text-slate-700 dark:text-gray-300"
|
||||
>
|
||||
{{child['name']}}
|
||||
</p>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<!-- action button -->
|
||||
<div
|
||||
{{current_endpoint}}-action-button="{{child['name']}}"
|
||||
type="button"
|
||||
data-{{current_endpoint}}-action-button="{{child['name']}}"
|
||||
class="dark:brightness-125 dark:hover:brightness-100 flex justify-center items-center absolute h-full w-10 bg-primary fill-white first-letter:absolute top-0 -right-1 font-bold text-center text-white uppercase transition-all rounded-none rounded-r-lg cursor-pointer leading-normal text-xs ease-in tracking-tight-rem bg-150 bg-x-25 active:opacity-85"
|
||||
>
|
||||
<svg
|
||||
|
@ -226,20 +218,21 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
</svg>
|
||||
</div>
|
||||
<!-- end action button -->
|
||||
</span>
|
||||
</div>
|
||||
<!-- dropdown actions -->
|
||||
<div
|
||||
{{current_endpoint}}-action-dropdown="{{child['name']}}"
|
||||
<div role="tablist"
|
||||
data-{{current_endpoint}}-action-dropdown="{{child['name']}}"
|
||||
class="absolute hidden flex-col z-110 w-48 right-0 top-0 translate-y-16"
|
||||
>
|
||||
<!-- view button-->
|
||||
<button
|
||||
role="tab"
|
||||
type="button"
|
||||
value="view"
|
||||
{{current_endpoint}}-action-dropdown-btn="{{child['name']}}"
|
||||
data-{{current_endpoint}}-action-dropdown-btn="{{child['name']}}"
|
||||
class="duration-300 border-gray-300 hover:brightness-90 bg-white text-white my-0 relative px-6 py-2 text-center 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 w-full border-t rounded-t border-b border-l border-r hover:bg-gray-100"
|
||||
>
|
||||
<div class="flex justify-start items-center">
|
||||
<span class="flex justify-start items-center">
|
||||
<svg
|
||||
class="h-6 w-6 stroke-green-700 dark:brightness-125"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -264,7 +257,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
class="transition duration-300 ease-in-out text-gray-700 dark:text-gray-300 dark:opacity-80 ml-4 font-bold uppercase"
|
||||
>view</span
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
</button>
|
||||
<!-- end view button-->
|
||||
|
||||
|
@ -272,12 +265,13 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
{% if child['type'] == "file" and child['can_edit'] == True or
|
||||
child['type'] == "folder" and child['can_edit'] == True %}
|
||||
<button
|
||||
role="tab"
|
||||
type="button"
|
||||
value="edit"
|
||||
{{current_endpoint}}-action-dropdown-btn="{{child['name']}}"
|
||||
data-{{current_endpoint}}-action-dropdown-btn="{{child['name']}}"
|
||||
class="duration-300 border-gray-300 hover:brightness-90 bg-white my-0 relative px-6 py-2 text-center 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 w-full border-b border-l border-r hover:bg-gray-100"
|
||||
>
|
||||
<div class="flex justify-start items-center">
|
||||
<span class="flex justify-start items-center">
|
||||
<svg class="h-6 w-6 stroke-orange-500"
|
||||
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125" />
|
||||
|
@ -287,7 +281,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
class="transition duration-300 ease-in-out text-gray-700 dark:text-gray-300 dark:opacity-80 ml-4 font-bold uppercase"
|
||||
>edit</span
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
<!-- end edit button -->
|
||||
|
@ -296,14 +290,15 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
{% if child['type'] == "file" and child['can_download'] == True %}
|
||||
{% if current_endpoint == "cache" %}
|
||||
<button
|
||||
role="tab"
|
||||
type="button"
|
||||
value="download"
|
||||
{{current_endpoint}}-download="{{child['name'].split('/')[0]}}"
|
||||
{{current_endpoint}}-file="{{child['name'].split('/')[1]}}"
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="{{child['name'].split('/')[0]}}"
|
||||
data-{{current_endpoint}}-download="{{child['name'].split('/')[0]}}"
|
||||
data-{{current_endpoint}}-file="{{child['name'].split('/')[1]}}"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="{{child['name'].split('/')[0]}}"
|
||||
class="duration-300 border-gray-300 hover:brightness-90 bg-white text-white my-0 relative px-6 py-2 text-center 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 w-full border-b border-l border-r hover:bg-gray-100"
|
||||
>
|
||||
<div class="flex justify-start items-center">
|
||||
<span class="flex justify-start items-center">
|
||||
<svg class="h-6 w-6 stroke-sky-500"
|
||||
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75l3 3m0 0l3-3m-3 3v-7.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
|
@ -314,16 +309,17 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
class="transition duration-300 ease-in-out text-gray-700 dark:text-gray-300 dark:opacity-80 ml-4 font-bold uppercase"
|
||||
>download</span
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
</button>
|
||||
{%else%}
|
||||
<button
|
||||
role="tab"
|
||||
type="button"
|
||||
value="download"
|
||||
{{current_endpoint}}-action-dropdown-btn="{{child['name']}}"
|
||||
data-{{current_endpoint}}-action-dropdown-btn="{{child['name']}}"
|
||||
class="duration-300 border-gray-300 hover:brightness-90 bg-white text-white my-0 relative px-6 py-2 text-center 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 w-full border-b border-l border-r hover:bg-gray-100"
|
||||
>
|
||||
<div class="flex justify-start items-center">
|
||||
<span class="flex justify-start items-center">
|
||||
<svg class="h-6 w-6 stroke-sky-500"
|
||||
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75l3 3m0 0l3-3m-3 3v-7.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
|
@ -334,7 +330,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
class="transition duration-300 ease-in-out text-gray-700 dark:text-gray-300 dark:opacity-80 ml-4 font-bold uppercase"
|
||||
>download</span
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
</button>
|
||||
{%endif %}
|
||||
{% endif %}
|
||||
|
@ -343,12 +339,13 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
<!-- delete button -->
|
||||
{% if child['can_delete'] == True %}
|
||||
<button
|
||||
role="tab"
|
||||
type="button"
|
||||
value="delete"
|
||||
{{current_endpoint}}-action-dropdown-btn="{{child['name']}}"
|
||||
data-{{current_endpoint}}-action-dropdown-btn="{{child['name']}}"
|
||||
class="bg-white duration-300 border-gray-300 hover:brightness-90 text-white my-0 relative px-6 py-2 text-center 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 w-full border-b border-l border-r hover:bg-gray-100"
|
||||
>
|
||||
<div class="flex justify-start items-center">
|
||||
<span class="flex justify-start items-center">
|
||||
<svg class="h-6 w-6 stroke-red-500"
|
||||
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" />
|
||||
|
@ -357,7 +354,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
class="transition duration-300 ease-in-out text-gray-700 dark:text-gray-300 dark:opacity-80 ml-4 font-bold uppercase"
|
||||
>delete</span
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
<!-- end delete button -->
|
||||
|
@ -375,7 +372,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
|
||||
<!-- modal -->
|
||||
<div
|
||||
{{current_endpoint}}-modal
|
||||
data-{{current_endpoint}}-modal
|
||||
class="hidden w-screen h-screen fixed bg-gray-600/50 z-[1001] top-0 left-0 justify-center items-center"
|
||||
>
|
||||
<div
|
||||
|
@ -383,24 +380,24 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
>
|
||||
<div class="w-full flex justify-between">
|
||||
<p
|
||||
{{current_endpoint}}-modal-title
|
||||
data-{{current_endpoint}}-modal-title
|
||||
class="dark:text-white mb-0 font-sans font-semibold leading-normal uppercase text-sm"
|
||||
>
|
||||
TITLE
|
||||
</p>
|
||||
</div>
|
||||
<form
|
||||
{{current_endpoint}}-modal-form
|
||||
data-{{current_endpoint}}-modal-form
|
||||
class="w-full"
|
||||
id="form-services"
|
||||
method="POST"
|
||||
>
|
||||
<div
|
||||
class="mb-2 flex flex-col sm:flex-row justify-start align-middle items-start sm:items-center"
|
||||
{{current_endpoint}}-modal-path
|
||||
data-{{current_endpoint}}-modal-path
|
||||
>
|
||||
<p
|
||||
{{current_endpoint}}-modal-path-prefix
|
||||
data-{{current_endpoint}}-modal-path-prefix
|
||||
class="mb-0 dark:text-white dark:opacity-75 text-gray-700 opacity-50 text-sm"
|
||||
></p>
|
||||
<input
|
||||
|
@ -412,7 +409,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
required
|
||||
/>
|
||||
<p
|
||||
{{current_endpoint}}-modal-path-suffix
|
||||
data-{{current_endpoint}}-modal-path-suffix
|
||||
class="mb-0 dark:text-white dark:opacity-75 text-gray-700 opacity-50 text-sm"
|
||||
>
|
||||
suffix
|
||||
|
@ -423,10 +420,10 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
<input type="hidden" id="path" value="" name="path" />
|
||||
<input type="hidden" id="old_name" value="" name="old_name" />
|
||||
<input type="hidden" id="_type" value="file" name="type" />
|
||||
<textarea class="hidden" id="content" name="content" value=""></textarea>
|
||||
<textarea class="hidden" id="content" name="content"></textarea>
|
||||
<!-- editor-->
|
||||
<div
|
||||
{{current_endpoint}}-modal-editor
|
||||
data-{{current_endpoint}}-modal-editor
|
||||
id="editor"
|
||||
class="text-base w-full h-48 overflow-hidden overflow-y-auto my-2 border border-gray-300 dark:border-slate-800"
|
||||
></div>
|
||||
|
@ -434,14 +431,14 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
|
||||
<div class="mt-4 w-full justify-end flex">
|
||||
<button
|
||||
{{current_endpoint}}-modal-close
|
||||
data-{{current_endpoint}}-modal-close
|
||||
type="button"
|
||||
class="dark:brightness-90 mr-3 inline-block px-6 py-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-red-500 hover:bg-red-500/80 focus:bg-red-500/80 leading-normal text-xs ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button
|
||||
{{current_endpoint}}-modal-submit
|
||||
data-{{current_endpoint}}-modal-submit
|
||||
type="submit"
|
||||
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-sky-500 hover:bg-sky-500/80 focus:bg-sky-500/80 leading-normal text-xs ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md"
|
||||
>
|
|
@ -1,37 +1,39 @@
|
|||
<!-- float button-->
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
<button
|
||||
type="button"
|
||||
flash-sidebar-open
|
||||
class="transition scale-90 sm:scale-100 dark:brightness-95 dark:hover:brightness-105 hover:brightness-75 fixed p-3 text-xl bg-white shadow-sm cursor-pointer top-2 sm:top-3 right-19 sm:right-24 xl:right-24 z-990 rounded-circle text-slate-700"
|
||||
>
|
||||
<svg
|
||||
class="fill-yellow-500 -translate-y-0.4 h-6 w-6"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 448 512"
|
||||
<div class="fixed top-2 sm:top-3 right-19 sm:right-24 xl:right-24 z-990">
|
||||
<button
|
||||
type="button"
|
||||
data-flash-sidebar-open
|
||||
class="transition scale-90 sm:scale-100 dark:brightness-95 dark:hover:brightness-105 hover:brightness-75 p-3 text-xl bg-white shadow-sm cursor-pointer rounded-circle text-slate-700"
|
||||
>
|
||||
<path
|
||||
d="M224 0c-17.7 0-32 14.3-32 32V51.2C119 66 64 130.6 64 208v18.8c0 47-17.3 92.4-48.5 127.6l-7.4 8.3c-8.4 9.4-10.4 22.9-5.3 34.4S19.4 416 32 416H416c12.6 0 24-7.4 29.2-18.9s3.1-25-5.3-34.4l-7.4-8.3C401.3 319.2 384 273.9 384 226.8V208c0-77.4-55-142-128-156.8V32c0-17.7-14.3-32-32-32zm45.3 493.3c12-12 18.7-28.3 18.7-45.3H224 160c0 17 6.7 33.3 18.7 45.3s28.3 18.7 45.3 18.7s33.3-6.7 45.3-18.7z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
class="fill-yellow-500 -translate-y-0.4 h-6 w-6"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 448 512"
|
||||
>
|
||||
<path
|
||||
d="M224 0c-17.7 0-32 14.3-32 32V51.2C119 66 64 130.6 64 208v18.8c0 47-17.3 92.4-48.5 127.6l-7.4 8.3c-8.4 9.4-10.4 22.9-5.3 34.4S19.4 416 32 416H416c12.6 0 24-7.4 29.2-18.9s3.1-25-5.3-34.4l-7.4-8.3C401.3 319.2 384 273.9 384 226.8V208c0-77.4-55-142-128-156.8V32c0-17.7-14.3-32-32-32zm45.3 493.3c12-12 18.7-28.3 18.7-45.3H224 160c0 17 6.7 33.3 18.7 45.3s28.3 18.7 45.3 18.7s33.3-6.7 45.3-18.7z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<div
|
||||
class="px-2 translate-x-2 bottom-0 right-0 absolute rounded-full bg-white"
|
||||
>
|
||||
<p flash-count class="mb-0 text-sm text-bold text-red-500">
|
||||
<p data-flash-count class="mb-0 text-sm text-bold text-red-500">
|
||||
{%if messages %} {{messages|length}}{%else%} 0 {%endif%}
|
||||
</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<!-- end float button-->
|
||||
|
||||
<!-- right sidebar -->
|
||||
<aside
|
||||
flash-sidebar
|
||||
data-flash-sidebar
|
||||
class="translate-x-90 -right-0 transition z-sticky dark:bg-slate-850 dark:brightness-110 shadow-3xl max-w-full w-90 ease fixed top-0 left-auto flex h-full min-w-0 flex-col break-words rounded-none border-0 bg-white bg-clip-border px-0.5"
|
||||
>
|
||||
<!-- close btn-->
|
||||
<svg
|
||||
flash-sidebar-close
|
||||
data-flash-sidebar-close
|
||||
class="cursor-pointer fill-gray-600 dark:fill-gray-300 dark:opacity-80 absolute h-8 w-8 top-4 right-4"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 320 512"
|
||||
|
@ -51,7 +53,7 @@
|
|||
<!-- close button -->
|
||||
<div class="float-right mt-6">
|
||||
<button
|
||||
flash-sidebar-close
|
||||
data-flash-sidebar-close
|
||||
class="inline-block p-0 mb-4 text-sm font-bold leading-normal text-center uppercase align-middle transition-all ease-in bg-transparent border-0 rounded-lg shadow-none cursor-pointer hover:-translate-y-px tracking-tight-rem bg-150 bg-x-25 active:opacity-85 dark:text-white text-slate-700"
|
||||
>
|
||||
<i class="fa fa-close"></i>
|
||||
|
@ -69,7 +71,7 @@
|
|||
<!-- flash message-->
|
||||
{% for category, message in messages %}
|
||||
<div
|
||||
flash-message
|
||||
data-flash-message
|
||||
class="{% if category == 'error' %}bg-red-500 {%else%} bg-green-500 {%endif %} my-2 border relative p-4 w-11/12 min-h-20 rounded-lg hover:scale-102 transition shadow-md break-words dark:brightness-90"
|
||||
>
|
||||
<div class="flex justify-between align-top items-start">
|
||||
|
@ -79,8 +81,7 @@
|
|||
<h5 class="text-lg mb-0 text-white">Success</h5>
|
||||
{%endif%}
|
||||
<button
|
||||
close-flash-message
|
||||
role="close alert message"
|
||||
data-close-flash-message
|
||||
type="button"
|
||||
class="absolute right-8 top-2"
|
||||
>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{% extends "base.html" %} {% block content %}
|
||||
|
||||
<div service-content="settings" class="col-span-12 gap-y-4 grid grid-cols-12">
|
||||
<div data-service-content="settings" class="col-span-12 gap-y-4 grid grid-cols-12">
|
||||
<div class="p-4 col-span-12 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"
|
||||
>
|
||||
<div {{current_endpoint}}-tabs-header class="flex justify-start items-center gap-x-4 gap-y-2 my-3">
|
||||
<div data-{{current_endpoint}}-tabs-header class="flex justify-start items-center gap-x-4 gap-y-2 my-3">
|
||||
<h5 class="transition duration-300 ease-in-out dark:opacity-90 ml-2 font-bold text-md uppercase dark:text-white mb-0">CONFIGS</h5>
|
||||
<!-- search inpt-->
|
||||
<div class="flex relative col-span-12 sm:col-span-6 lg:col-span-4 3xl:col-span-3">
|
||||
|
@ -27,7 +27,7 @@
|
|||
|
||||
<!-- form global conf -->
|
||||
<form
|
||||
global-config-form
|
||||
data-global-config-form
|
||||
id="form-edit-global-configs"
|
||||
method="POST"
|
||||
class="flex flex-col justify-between overflow-hidden overflow-y-auto max-h-135 md:max-h-160 dark:brightness-110 col-span-12 break-words bg-white shadow-xl p-4 dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
%}
|
||||
|
||||
<head>
|
||||
<base href="{{ config["ABSOLUTE_URI"] }}">
|
||||
<meta charset="utf-8" />
|
||||
<base href="{{ config["ABSOLUTE_URI"] }}">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta
|
||||
name="viewport"
|
||||
|
@ -21,41 +21,37 @@
|
|||
<!-- tailwind style -->
|
||||
<link rel="stylesheet" type="text/css" href="./css/dashboard.css" />
|
||||
|
||||
<script type="module" defer src="./js/global.js"></script>
|
||||
<script type="module" src="./js/global.js"></script>
|
||||
|
||||
<script
|
||||
type="text/javascript"
|
||||
charset="utf-8"
|
||||
defer
|
||||
src="./js/editor/ace.js"
|
||||
></script>
|
||||
|
||||
{% if current_endpoint == "global_config" %}
|
||||
<script defer type="module" src="./js/global_config.js"></script>
|
||||
<script type="module" src="./js/global_config.js"></script>
|
||||
{% elif current_endpoint == "configs" %}
|
||||
<script defer type="module" src="./js/configs.js"></script>
|
||||
<script type="module" src="./js/configs.js"></script>
|
||||
{% elif current_endpoint == "services" %}
|
||||
<script defer type="module" src="./js/services.js"></script>
|
||||
<script type="module" src="./js/services.js"></script>
|
||||
{% elif current_endpoint == "plugins" %}
|
||||
<script type="module" defer src="./js/plugins.js"></script>
|
||||
<script type="module" src="./js/plugins.js"></script>
|
||||
{% elif current_endpoint == "cache" %}
|
||||
<script defer type="module" src="./js/cache.js"></script>
|
||||
<script type="module" src="./js/cache.js"></script>
|
||||
{% elif current_endpoint == "logs" %}
|
||||
<link rel="stylesheet" type="text/css" href="./css/flatpickr.css" />
|
||||
<link rel="stylesheet" type="text/css" href="./css/flatpickr.dark.css" />
|
||||
|
||||
<script type="module" defer src="./js/utils/flatpickr.js"></script>
|
||||
<script type="module" defer src="./js/utils/fr.js"></script>
|
||||
<script type="module" src="./js/utils/flatpickr.js"></script>
|
||||
<script type="module" src="./js/utils/fr.js"></script>
|
||||
|
||||
<script type="module" defer src="./js/logs.js"></script>
|
||||
<script type="module" defer src="./js/datepicker/datepicker.js"></script>
|
||||
<script type="module" src="./js/logs.js"></script>
|
||||
<script type="module" src="./js/datepicker/datepicker.js"></script>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="./css/datepicker-foundation.css"
|
||||
/>
|
||||
{% elif current_endpoint == "jobs" %}
|
||||
<script defer type="module" src="./js/jobs.js"></script>
|
||||
|
||||
<script type="module" src="./js/jobs.js"></script>
|
||||
{% endif %}
|
||||
</head>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<nav>
|
||||
<!-- breadcrumb -->
|
||||
<h6 class="mb-0 text-lg font-bold text-white capitalize">
|
||||
{{ current_endpoint}}
|
||||
{{current_endpoint}}
|
||||
</h6>
|
||||
<ol class="flex flex-wrap pt-1 mr-12 bg-transparent rounded-lg sm:mr-16">
|
||||
<li class="text-sm leading-normal">
|
||||
|
@ -23,7 +23,7 @@
|
|||
class="text-sm pl-2 capitalize leading-normal text-white before:float-left before:pr-2 before:text-white before:content-['/']"
|
||||
aria-current="page"
|
||||
>
|
||||
{{ current_endpoint}}
|
||||
{{current_endpoint}}
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
|
|
@ -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,9 @@
|
|||
>
|
||||
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">
|
||||
{{ config["CONFIG"].get_plugins()|length }}
|
||||
</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
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
instances_batched %}
|
||||
<!-- instance card -->
|
||||
<div
|
||||
href="https://github.com/bunkerity/bunkerweb"
|
||||
class="overflow-hidden max-h-none sm:max-h- hover:scale-102 transition col-span-12 lg:col-span-6 3xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:brightness-110 dark:shadow-dark-xl rounded-2xl bg-clip-border"
|
||||
>
|
||||
<form class="w-full" id="form-instance-{{ instance._id }}" method="POST">
|
||||
|
@ -43,7 +42,7 @@ instances_batched %}
|
|||
<p
|
||||
class="transition duration-300 ease-in-out pl-2 col-span-1 mb-0 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-80"
|
||||
>
|
||||
{{ instance._type}}
|
||||
{{ instance._type }}
|
||||
</p>
|
||||
</div>
|
||||
<!-- end detail -->
|
||||
|
@ -57,7 +56,7 @@ instances_batched %}
|
|||
<p
|
||||
class="transition duration-300 ease-in-out pl-2 col-span-1 mb-0 font-sans text-sm font-semibold leading-normal uppercase dark:text-white dark:opacity-90"
|
||||
>
|
||||
{{ instance.hostname}}
|
||||
{{ instance.hostname }}
|
||||
</p>
|
||||
</div>
|
||||
<!-- end detail -->
|
||||
|
|
|
@ -5,7 +5,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
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"
|
||||
>
|
||||
<h5 class="mb-2 font-bold dark:text-white">INFO</h5>
|
||||
<div class="flex items-center my-4">
|
||||
<div class="mx-1 flex items-center my-4">
|
||||
<p
|
||||
class="transition duration-300 ease-in-out font-bold mb-0 font-sans text-sm leading-normal uppercase dark:text-gray-500 dark:opacity-80"
|
||||
>
|
||||
|
@ -17,7 +17,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
{{jobs|length}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center my-4">
|
||||
<div class="mx-1 flex items-center my-4">
|
||||
<p
|
||||
class="transition duration-300 ease-in-out font-bold mb-0 font-sans text-sm leading-normal uppercase dark:text-gray-500 dark:opacity-80"
|
||||
>
|
||||
|
@ -34,11 +34,11 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
|
||||
<!-- filter -->
|
||||
<div
|
||||
{{current_endpoint}}-filter
|
||||
data-{{current_endpoint}}-filter
|
||||
class="col-span-12 md:col-span-8 2xl: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"
|
||||
>
|
||||
<h5 class="mb-2 font-bold dark:text-white">FILTER</h5>
|
||||
<div class="grid grid-cols-12 gap-x-4 gap-y-2">
|
||||
<div class="mx-2 grid grid-cols-12 gap-x-4 gap-y-2">
|
||||
<!-- search inpt-->
|
||||
<div class="flex flex-col relative col-span-12 md:col-span-6">
|
||||
<h5
|
||||
|
@ -66,19 +66,19 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
Success state
|
||||
</h5>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select="success"
|
||||
data-{{current_endpoint}}-setting-select="success"
|
||||
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-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
|
||||
id="{{current_endpoint}}-success"
|
||||
name="{{current_endpoint}}-success"
|
||||
{{current_endpoint}}-setting-select-text="success"
|
||||
data-name="{{current_endpoint}}-success"
|
||||
data-{{current_endpoint}}-setting-select-text="success"
|
||||
>all</span
|
||||
>
|
||||
<!-- chevron -->
|
||||
<svg
|
||||
{{current_endpoint}}-setting-select="success"
|
||||
data-{{current_endpoint}}-setting-select="success"
|
||||
class="transition-transform h-4 w-4 fill-gray-500"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -91,11 +91,11 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
<!-- end chevron -->
|
||||
<!-- dropdown-->
|
||||
<div
|
||||
{{current_endpoint}}-setting-select-dropdown="success"
|
||||
data-{{current_endpoint}}-setting-select-dropdown="success"
|
||||
class="hidden z-100 absolute h-full flex-col w-full translate-y-16"
|
||||
>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="success"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="success"
|
||||
type="button"
|
||||
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"
|
||||
|
@ -103,7 +103,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
all
|
||||
</button>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="success"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="success"
|
||||
type="button"
|
||||
value="false"
|
||||
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"
|
||||
|
@ -111,10 +111,10 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
false
|
||||
</button>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="success"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="success"
|
||||
type="button"
|
||||
value="true"
|
||||
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"
|
||||
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"
|
||||
>
|
||||
true
|
||||
</button>
|
||||
|
@ -130,19 +130,19 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
Reload state
|
||||
</h5>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select="reload"
|
||||
data-{{current_endpoint}}-setting-select="reload"
|
||||
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-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
|
||||
id="{{current_endpoint}}-reload"
|
||||
name="{{current_endpoint}}-reload"
|
||||
{{current_endpoint}}-setting-select-text="reload"
|
||||
data-name="{{current_endpoint}}-reload"
|
||||
data-{{current_endpoint}}-setting-select-text="reload"
|
||||
>all</span
|
||||
>
|
||||
<!-- chevron -->
|
||||
<svg
|
||||
{{current_endpoint}}-setting-select="reload"
|
||||
data-{{current_endpoint}}-setting-select="reload"
|
||||
class="transition-transform h-4 w-4 fill-gray-500"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -155,11 +155,11 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
<!-- end chevron -->
|
||||
<!-- dropdown-->
|
||||
<div
|
||||
{{current_endpoint}}-setting-select-dropdown="reload"
|
||||
data-{{current_endpoint}}-setting-select-dropdown="reload"
|
||||
class="hidden z-100 absolute h-full flex-col w-full translate-y-16"
|
||||
>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="reload"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="reload"
|
||||
type="button"
|
||||
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"
|
||||
|
@ -167,7 +167,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
all
|
||||
</button>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="reload"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="reload"
|
||||
type="button"
|
||||
value="false"
|
||||
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"
|
||||
|
@ -175,10 +175,10 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
false
|
||||
</button>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="reload"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="reload"
|
||||
type="button"
|
||||
value="true"
|
||||
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"
|
||||
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"
|
||||
>
|
||||
true
|
||||
</button>
|
||||
|
@ -229,7 +229,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
</p>
|
||||
<!-- end header-->
|
||||
<!-- list -->
|
||||
<ul class="col-span-12 w-full" {{current_endpoint}}-list>
|
||||
<ul class="col-span-12 w-full" data-{{current_endpoint}}-list>
|
||||
{% for job_name, value in jobs.items() %}
|
||||
<!-- job item-->
|
||||
<li
|
||||
|
@ -237,26 +237,26 @@ 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"
|
||||
{{current_endpoint}}-name
|
||||
data-{{current_endpoint}}-name
|
||||
>
|
||||
{{job_name}}
|
||||
</p>
|
||||
<p
|
||||
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-3 m-0 my-1"
|
||||
{{current_endpoint}}-last_run
|
||||
data-{{current_endpoint}}-last_run
|
||||
>
|
||||
{{value['last_run']}}
|
||||
</p>
|
||||
<p
|
||||
class="dark:text-gray-400 dark:opacity-80 text-sm col-span-1 m-0 my-1"
|
||||
{{current_endpoint}}-every
|
||||
data-{{current_endpoint}}-every
|
||||
>
|
||||
{{value["every"]}}
|
||||
</p>
|
||||
{% if value["reload"] %}
|
||||
<p
|
||||
class="ml-6 dark:text-gray-400 dark:opacity-80 text-sm col-span-1 m-0 my-1"
|
||||
{{current_endpoint}}-reload="true"
|
||||
data-{{current_endpoint}}-reload="true"
|
||||
>
|
||||
<svg
|
||||
class="fill-green-500 h-5 w-5"
|
||||
|
@ -272,7 +272,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
{%endif %} {% if not value["reload"] %}
|
||||
<p
|
||||
class="ml-6 dark:text-gray-400 dark:opacity-80 text-sm col-span-1 m-0 my-1"
|
||||
{{current_endpoint}}-reload="false"
|
||||
data-{{current_endpoint}}-reload="false"
|
||||
>
|
||||
<svg
|
||||
class="fill-red-500 h-5 w-5"
|
||||
|
@ -287,7 +287,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
{% endif %} {% if value["success"] %}
|
||||
<p
|
||||
class="ml-6 dark:text-gray-400 dark:opacity-80 text-sm col-span-1 m-0 my-1"
|
||||
{{current_endpoint}}-success="true"
|
||||
data-{{current_endpoint}}-success="true"
|
||||
>
|
||||
<svg
|
||||
class="fill-green-500 h-5 w-5"
|
||||
|
@ -302,7 +302,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
{% elif not value["success"] %}
|
||||
<p
|
||||
class="ml-6 dark:text-gray-400 dark:opacity-80 text-sm col-span-1 m-0 my-1"
|
||||
{{current_endpoint}}-success="false"
|
||||
data-{{current_endpoint}}-success="false"
|
||||
>
|
||||
<svg
|
||||
class="fill-red-500 h-5 w-5"
|
||||
|
@ -317,23 +317,23 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
{% endif %}
|
||||
<div
|
||||
class="relative dark:text-gray-400 text-sm col-span-3 m-0 my-1"
|
||||
{{current_endpoint}}-files
|
||||
data-{{current_endpoint}}-files
|
||||
>
|
||||
{% if value['cache']%}
|
||||
<button
|
||||
{{current_endpoint}}-setting-select="{{job_name}}"
|
||||
data-{{current_endpoint}}-setting-select="{{job_name}}"
|
||||
type="button"
|
||||
class="py-1 text-sm disabled:opacity-75 dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 duration-300 ease-in-out dark: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 leading-6 ease w-full rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 md:px-3 font-normal text-gray-700 transition-all placeholder:text-gray-500"
|
||||
>
|
||||
<span
|
||||
id="{{current_endpoint}}-{{job_name}}"
|
||||
name="{{current_endpoint}}-{{job_name}}"
|
||||
{{current_endpoint}}-setting-select-text="{{job_name}}"
|
||||
data-name="{{current_endpoint}}-{{job_name}}"
|
||||
data-{{current_endpoint}}-setting-select-text="{{job_name}}"
|
||||
>files</span
|
||||
>
|
||||
<!-- chevron -->
|
||||
<svg
|
||||
{{current_endpoint}}-setting-select="{{job_name}}"
|
||||
data-{{current_endpoint}}-setting-select="{{job_name}}"
|
||||
class="transition-transform h-4 w-4 fill-gray-500"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -346,19 +346,19 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
<!-- end chevron -->
|
||||
<!-- dropdown-->
|
||||
<div
|
||||
{{current_endpoint}}-setting-select-dropdown="{{job_name}}"
|
||||
data-{{current_endpoint}}-setting-select-dropdown="{{job_name}}"
|
||||
class="hidden z-100 absolute h-full flex-col w-full translate-y-0.5"
|
||||
>
|
||||
{% for file in value['cache'] %}
|
||||
<button
|
||||
{{current_endpoint}}-download="{{job_name}}"
|
||||
{{current_endpoint}}-file="{{file['file_name']}}"
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="{{job_name}}"
|
||||
data-{{current_endpoint}}-download="{{job_name}}"
|
||||
data-{{current_endpoint}}-file="{{file['file_name']}}"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="{{job_name}}"
|
||||
type="button"
|
||||
value="list"
|
||||
class="{% if loop.index == loop.length %}rounded-b-lg {% endif %}{% if loop.first %}rounded-t-lg{% endif %} border-b border-l border-r border-gray-300 dark:hover:brightness-90 hover:brightness-90 my-0 relative py-2 px-3 text-left align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:text-gray-300 bg-white dark:bg-slate-700 text-gray-700"
|
||||
>
|
||||
<div class="flex justify-start items-center">
|
||||
<span class="flex justify-start items-center">
|
||||
<svg
|
||||
class="h-6 w-6 fill-sky-500"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -372,7 +372,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %}
|
|||
class="transition duration-300 ease-in-out text-gray-700 dark:text-gray-300 dark:opacity-80 ml-2"
|
||||
>{{file['file_name']}}</span
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
</button>
|
||||
{%endfor %}
|
||||
</div>
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
</head>
|
||||
<body>
|
||||
<div
|
||||
loader
|
||||
data-loader
|
||||
class="fixed z-[10000] transition duration-300 h-screen w-screen bg-primary flex justify-center align-middle items-center"
|
||||
>
|
||||
<img
|
||||
loader-img
|
||||
data-loader-img
|
||||
src="images/logo-menu-2.png"
|
||||
class="duration-300 w-40 h-12 sm:w-50 sm:h-14 md:w-60 md:h-16 lg:w-80 lg:h-24 inline transition-all"
|
||||
alt="main logo"
|
||||
|
@ -32,11 +32,11 @@
|
|||
<!-- flash message-->
|
||||
{% for category, message in messages %}
|
||||
<div
|
||||
flash-message
|
||||
data-flash-message
|
||||
class="p-4 mb-1 md:mb-3 md:mr-3 z-[1001] flex flex-col fixed bottom-0 right-0 w-full md:w-1/2 max-w-[300px] min-h-20 bg-white rounded-lg dark:brightness-110 hover:scale-102 transition shadow-md break-words dark:bg-slate-850 dark:shadow-dark-xl bg-clip-border"
|
||||
>
|
||||
<button
|
||||
close-flash-message
|
||||
data-close-flash-message
|
||||
role="close alert message"
|
||||
type="button"
|
||||
class="absolute right-7 top-1.5"
|
||||
|
@ -164,9 +164,9 @@
|
|||
<script>
|
||||
class Loader {
|
||||
constructor() {
|
||||
this.menuContainer = document.querySelector("[menu-container]");
|
||||
this.logoContainer = document.querySelector("[loader]");
|
||||
this.logoEl = document.querySelector("[loader-img]");
|
||||
this.menuContainer = document.querySelector("[data-menu-container]");
|
||||
this.logoContainer = document.querySelector("[data-loader]");
|
||||
this.logoEl = document.querySelector("[data-loader-img]");
|
||||
this.isLoading = true;
|
||||
this.init();
|
||||
}
|
||||
|
@ -209,7 +209,7 @@
|
|||
init() {
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
try {
|
||||
const flashEl = document.querySelector("[flash-message]");
|
||||
const flashEl = document.querySelector("[data-flash-message]");
|
||||
setTimeout(() => {
|
||||
try {
|
||||
flashEl.remove();
|
||||
|
@ -221,10 +221,10 @@
|
|||
window.addEventListener("click", (e) => {
|
||||
try {
|
||||
if (
|
||||
e.target.closest("button").hasAttribute("close-flash-message")
|
||||
e.target.closest("button").hasAttribute("data-close-flash-message")
|
||||
) {
|
||||
const closeBtn = e.target.closest("button");
|
||||
const flashEl = closeBtn.closest("[flash-message]");
|
||||
const flashEl = closeBtn.closest("[data-flash-message]");
|
||||
flashEl.remove();
|
||||
}
|
||||
} catch (err) {}
|
||||
|
|
|
@ -3,11 +3,11 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
|
||||
<!-- settings -->
|
||||
<div
|
||||
{{current_endpoint}}-settings
|
||||
data-{{current_endpoint}}-settings
|
||||
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">
|
||||
<div class="mx-2 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 2xl:col-span-4 3xl:col-span-3"
|
||||
|
@ -18,14 +18,14 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
Select instance
|
||||
</h5>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select="instances"
|
||||
data-{{current_endpoint}}-setting-select="instances"
|
||||
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-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
|
||||
id="logs-instance"
|
||||
name="logs-instance"
|
||||
{{current_endpoint}}-setting-select-text="instances"
|
||||
data-name="logs-instance"
|
||||
data-{{current_endpoint}}-setting-select-text="instances"
|
||||
>
|
||||
{% for instance in instances %} {% if loop.first %} {% if
|
||||
instance.name %} {{instance.name}} {%else%} no instance {%endif%}
|
||||
|
@ -33,7 +33,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
</span>
|
||||
<!-- chevron -->
|
||||
<svg
|
||||
{{current_endpoint}}-setting-select="instances"
|
||||
data-{{current_endpoint}}-setting-select="instances"
|
||||
class="transition-transform h-4 w-4 fill-gray-500"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -46,15 +46,15 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
<!-- end chevron -->
|
||||
<!-- dropdown-->
|
||||
<div
|
||||
{{current_endpoint}}-setting-select-dropdown="instances"
|
||||
data-{{current_endpoint}}-setting-select-dropdown="instances"
|
||||
class="hidden z-100 absolute h-full flex-col w-full translate-y-16"
|
||||
>
|
||||
{% for instance in instances %}
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="instances"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="instances"
|
||||
type="button"
|
||||
value="{{instance.name}}"
|
||||
_type="{{instance._type}}"
|
||||
data-_type="{{instance._type}}"
|
||||
class="{% if loop.index == 1 %} border-t rounded-t {% endif %} {% if loop.index == loop.length %}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"
|
||||
>
|
||||
{{instance.name}}
|
||||
|
@ -91,7 +91,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
<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
|
||||
To date (default today)
|
||||
</h5>
|
||||
<input
|
||||
type="text"
|
||||
|
@ -120,7 +120,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
name="update-delay"
|
||||
class="disabled:bg-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 dark:disabled:text-gray-300 disabled:text-gray-700 col-span-12 sm:col-span-6 2xl: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="(.*?)"
|
||||
data-pattern="(.*?)"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
@ -134,26 +134,26 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
>
|
||||
Live update
|
||||
</h5>
|
||||
<div checkbox-handler="live-update" class="relative mb-7 md:mb-0">
|
||||
<div data-checkbox-handler="live-update" class="relative mb-7 md:mb-0">
|
||||
<input
|
||||
id="live-update"
|
||||
name="live-update"
|
||||
default-method="default"
|
||||
default-value="no"
|
||||
data-default-method="default"
|
||||
data-default-value="no"
|
||||
class="relative cursor-pointer disabled:cursor-default disabled:pointer-events-none 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 mt-1 appearance-none border border-gray-300 bg-white bg-contain bg-center bg-no-repeat align-top transition-all disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 disabled:text-gray-700 dark:disabled:text-gray-300"
|
||||
type="checkbox"
|
||||
pattern="^(yes|no)$"
|
||||
data-pattern="^(yes|no)$"
|
||||
value="no"
|
||||
/>
|
||||
<input
|
||||
type="hidden"
|
||||
name="live-update"
|
||||
default-method="default"
|
||||
default-value="no"
|
||||
data-default-method="default"
|
||||
data-default-value="no"
|
||||
value="no"
|
||||
/>
|
||||
<svg
|
||||
checkbox-handler="live-update"
|
||||
data-checkbox-handler="live-update"
|
||||
class="pointer-events-none absolute fill-white dark:fill-gray-300 left-0 top-0 translate-x-1 translate-y-2 h-3 w-3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -168,11 +168,20 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
|
||||
<div class="col-span-12 w-full justify-center flex mt-2">
|
||||
<button
|
||||
data-submit-date
|
||||
type="button"
|
||||
id="submit-settings"
|
||||
class="tracking-wide dark:brightness-125 hover:brightness-75 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 leading-normal text-xs ease-in shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md"
|
||||
>
|
||||
Submit
|
||||
Submit Date
|
||||
</button>
|
||||
<button
|
||||
data-submit-live="no"
|
||||
type="button"
|
||||
id="submit-settings"
|
||||
class="hidden tracking-wide dark:brightness-125 hover:brightness-75 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 leading-normal text-xs ease-in shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md"
|
||||
>
|
||||
Go Live
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -181,11 +190,11 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
|
||||
<!-- filter -->
|
||||
<div
|
||||
{{current_endpoint}}-filter
|
||||
data-{{current_endpoint}}-filter
|
||||
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">
|
||||
<div class="mx-2 grid grid-cols-12 gap-x-4 gap-y-2">
|
||||
<!-- search inpt-->
|
||||
<div class="flex flex-col relative col-span-12">
|
||||
<h5
|
||||
|
@ -212,19 +221,19 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
Select types
|
||||
</h5>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select="types"
|
||||
data-{{current_endpoint}}-setting-select="types"
|
||||
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-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
|
||||
id="logs-types"
|
||||
name="logs-types"
|
||||
{{current_endpoint}}-setting-select-text="types"
|
||||
data-name="logs-types"
|
||||
data-{{current_endpoint}}-setting-select-text="types"
|
||||
>all</span
|
||||
>
|
||||
<!-- chevron -->
|
||||
<svg
|
||||
{{current_endpoint}}-setting-select="types"
|
||||
data-{{current_endpoint}}-setting-select="types"
|
||||
class="transition-transform h-4 w-4 fill-gray-500"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -237,11 +246,11 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
<!-- end chevron -->
|
||||
<!-- dropdown-->
|
||||
<div
|
||||
{{current_endpoint}}-setting-select-dropdown="types"
|
||||
data-{{current_endpoint}}-setting-select-dropdown="types"
|
||||
class="hidden z-100 absolute h-full flex-col w-full translate-y-16"
|
||||
>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
type="button"
|
||||
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"
|
||||
|
@ -249,7 +258,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
all
|
||||
</button>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
type="button"
|
||||
value="message"
|
||||
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"
|
||||
|
@ -257,7 +266,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
message
|
||||
</button>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
type="button"
|
||||
value="error"
|
||||
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"
|
||||
|
@ -265,7 +274,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
error
|
||||
</button>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
type="button"
|
||||
value="warn"
|
||||
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"
|
||||
|
@ -273,7 +282,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
warn
|
||||
</button>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
type="button"
|
||||
value="info"
|
||||
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"
|
||||
|
@ -281,7 +290,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
info
|
||||
</button>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
type="button"
|
||||
value="misc"
|
||||
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"
|
||||
|
@ -317,7 +326,7 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
|
|||
<!-- list -->
|
||||
<ul
|
||||
class="col-span-12 w-full max-h-100 overflow-y-auto"
|
||||
{{current_endpoint}}-list
|
||||
data-{{current_endpoint}}-list
|
||||
></ul>
|
||||
<!-- end list-->
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<!-- float button-->
|
||||
<button
|
||||
type="button"
|
||||
sidebar-menu-toggle
|
||||
data-sidebar-menu-toggle
|
||||
class="scale-90 sm:scale-100 dark:brightness-95 dark:hover:brightness-105 hover:brightness-75 xl:hidden fixed p-3 text-xl bg-white shadow-sm cursor-pointer top-2 sm:top-3 right-5 sm:right-6 z-990 rounded-circle text-slate-700"
|
||||
>
|
||||
<svg
|
||||
|
@ -22,13 +22,13 @@
|
|||
|
||||
<!-- left sidebar -->
|
||||
<aside
|
||||
sidebar-menu
|
||||
data-sidebar-menu
|
||||
class="fixed flex inset-y-0 flex-wrap justify-between w-full p-0 my-4 overflow-y-auto antialiased transition-transform duration-200 -translate-x-full bg-white border-0 shadow-xl dark:shadow-none dark:bg-slate-850 dark:brightness-110 max-w-64 z-[1000] xl:ml-6 rounded-2xl xl:left-0 xl:translate-x-0"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<!-- close btn-->
|
||||
<svg
|
||||
sidebar-menu-close
|
||||
data-sidebar-menu-close
|
||||
class="sm:hidden cursor-pointer fill-gray-600 dark:fill-gray-300 dark:opacity-80 absolute h-6 w-6 top-4 right-4"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 320 512"
|
||||
|
@ -435,7 +435,7 @@
|
|||
value="{{ csrf_token() }}"
|
||||
/>
|
||||
<input {% if dark_mode == True %}checked{% endif %} id="darkMode"
|
||||
dark-toggle class="dark:brightness-125 hover:brightness-75 rounded-10
|
||||
data-dark-toggle class="dark:brightness-125 hover:brightness-75 rounded-10
|
||||
duration-300 ease-in-out after:rounded-circle after:shadow-2xl
|
||||
after:duration-300 checked:after:translate-x-5.3 h-5 mt-0.5 relative
|
||||
float-left w-10 cursor-pointer appearance-none border border-solid
|
||||
|
@ -446,7 +446,7 @@
|
|||
checked:bg-right" type="checkbox" />
|
||||
<label
|
||||
for="darkMode"
|
||||
dark-toggle-label
|
||||
data-dark-toggle-label
|
||||
class="dark:text-white dark:opacity-80 transition inline-block pl-3 mb-0 ml-0 font-normal cursor-pointer select-none text-sm text-slate-700"
|
||||
>
|
||||
{% if dark_mode == True %}dark mode{% else %} light mode{% endif %}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!-- float button-->
|
||||
<button
|
||||
type="button"
|
||||
sidebar-info-open
|
||||
data-sidebar-info-open
|
||||
class="scale-90 sm:scale-100 dark:brightness-95 dark:hover:brightness-105 hover:brightness-75 fixed p-3 text-xl bg-white shadow-sm cursor-pointer top-16 sm:top-3 right-5 sm:right-40 xl:right-6 z-990 rounded-circle text-slate-700"
|
||||
>
|
||||
<svg
|
||||
|
@ -18,12 +18,12 @@
|
|||
|
||||
<!-- right sidebar -->
|
||||
<aside
|
||||
sidebar-info
|
||||
data-sidebar-info
|
||||
class="translate-x-90 -right-0 transition z-sticky dark:bg-slate-850 dark:brightness-110 shadow-3xl max-w-full w-90 ease fixed top-0 left-auto flex h-full min-w-0 flex-col break-words rounded-none border-0 bg-white bg-clip-border px-0.5"
|
||||
>
|
||||
<!-- close btn-->
|
||||
<svg
|
||||
sidebar-info-close
|
||||
data-sidebar-info-close
|
||||
class="cursor-pointer fill-gray-600 dark:fill-gray-300 dark:opacity-80 absolute h-8 w-8 top-4 right-4"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 320 512"
|
||||
|
@ -43,7 +43,7 @@
|
|||
<!-- close button -->
|
||||
<div class="float-right mt-6">
|
||||
<button
|
||||
sidebar-info-close
|
||||
data-sidebar-info-close
|
||||
class="inline-block p-0 mb-4 text-sm font-bold leading-normal text-center uppercase align-middle transition-all ease-in bg-transparent border-0 rounded-lg shadow-none cursor-pointer hover:-translate-y-px tracking-tight-rem bg-150 bg-x-25 active:opacity-85 dark:text-white text-slate-700"
|
||||
>
|
||||
<i class="fa fa-close"></i>
|
||||
|
@ -56,7 +56,7 @@
|
|||
/>
|
||||
<!-- end header -->
|
||||
<!-- news-->
|
||||
<div news-container class="flex-auto overflow-auto">
|
||||
<div data-news-container class="flex-auto overflow-auto">
|
||||
<p
|
||||
class="text-center col-span-12 relative w-full p-4 text-blue-500 rounded-lg"
|
||||
>
|
||||
|
@ -90,16 +90,16 @@
|
|||
</div>
|
||||
<div class="block mt-2 mb-4">
|
||||
<div class="relative">
|
||||
<div checkbox-handler="newsletter-check" class="relative mb-7 md:mb-0">
|
||||
<div data-checkbox-handler="newsletter-check" class="relative mb-7 md:mb-0">
|
||||
<input
|
||||
id="newsletter-check"
|
||||
class="mr-2 relative cursor-pointer 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 mt-1 appearance-none border border-gray-300 bg-white bg-contain bg-center bg-no-repeat align-top transition-all disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 disabled:text-gray-700 dark:disabled:text-gray-300"
|
||||
type="checkbox"
|
||||
pattern="^(yes|no)$"
|
||||
data-pattern="^(yes|no)$"
|
||||
value="no"
|
||||
/>
|
||||
<svg
|
||||
checkbox-handler="newsletter-check"
|
||||
data-checkbox-handler="newsletter-check"
|
||||
class="pointer-events-none cursor-pointer absolute fill-white dark:fill-gray-300 left-0 top-0 translate-x-1 translate-y-2 h-3 w-3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -115,7 +115,7 @@
|
|||
<a
|
||||
class="italic"
|
||||
href="https://www.bunkerity.com/privacy-policy/"
|
||||
_target="_blank"
|
||||
target="_blank"
|
||||
>privacy policy</a
|
||||
>
|
||||
</label>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{% extends "base.html" %} {% block content %}{% set current_endpoint =
|
||||
url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %} {%
|
||||
include "plugins-modal.html" %}
|
||||
include "plugins_modal.html" %}
|
||||
|
||||
<!-- info -->
|
||||
<div
|
||||
class="p-4 col-span-12 md:col-span-5 2xl:col-span-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
|
||||
>
|
||||
<h5 class="col-span-12 mb-4 font-bold dark:text-white">INFO</h5>
|
||||
<div class="flex items-center my-4">
|
||||
<div class="mx-1 flex items-center my-4">
|
||||
<p
|
||||
class="transition duration-300 ease-in-out font-bold mb-0 font-sans text-sm leading-normal uppercase dark:text-gray-500 dark:opacity-80"
|
||||
>
|
||||
|
@ -19,7 +19,7 @@ include "plugins-modal.html" %}
|
|||
{{plugins|length}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center my-4">
|
||||
<div class="mx-1 flex items-center my-4">
|
||||
<p
|
||||
class="transition duration-300 ease-in-out font-bold mb-0 font-sans text-sm leading-normal uppercase dark:text-gray-500 dark:opacity-80"
|
||||
>
|
||||
|
@ -31,7 +31,7 @@ include "plugins-modal.html" %}
|
|||
{{plugins_internal}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center my-4">
|
||||
<div class="mx-1 flex items-center my-4">
|
||||
<p
|
||||
class="transition duration-300 ease-in-out font-bold mb-0 font-sans text-sm leading-normal uppercase dark:text-gray-500 dark:opacity-80"
|
||||
>
|
||||
|
@ -43,7 +43,7 @@ include "plugins-modal.html" %}
|
|||
{{plugins_external}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center my-4">
|
||||
<div class="mx-1 flex items-center my-4">
|
||||
<p
|
||||
class="transition duration-300 ease-in-out font-bold mb-0 font-sans text-sm leading-normal uppercase dark:text-gray-500 dark:opacity-80"
|
||||
>
|
||||
|
@ -60,24 +60,19 @@ include "plugins-modal.html" %}
|
|||
|
||||
<!-- upload layout -->
|
||||
<div
|
||||
{{current_endpoint}}-upload
|
||||
data-{{current_endpoint}}-upload
|
||||
class="p-4 col-span-12 md:col-span-7 2xl:col-span-4 grid grid-cols-12 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
|
||||
>
|
||||
<h5 class="col-span-12 mb-4 font-bold dark:text-white">UPLOAD / RELOAD</h5>
|
||||
|
||||
<div class="p-0 col-span-12 grid grid-cols-12">
|
||||
<div class="mx-2 p-0 col-span-12 grid grid-cols-12">
|
||||
<!-- dropzone -->
|
||||
<form
|
||||
id="dropzone-form"
|
||||
action="#"
|
||||
class="hover:bg-gray-100 dark:hover:bg-slate-700/50 cursor-pointer col-span-12 border-2 rounded-lg p-2 border-dashed border-primary dark:brightness-125 drop-zone"
|
||||
>
|
||||
<input
|
||||
type="hidden"
|
||||
id="csrf_token"
|
||||
name="csrf_token"
|
||||
value="{{ csrf_token() }}"
|
||||
/>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
<input
|
||||
class="file-input drop-zone__input"
|
||||
type="file"
|
||||
|
@ -90,8 +85,8 @@ include "plugins-modal.html" %}
|
|||
click or drag and drop
|
||||
</p>
|
||||
</form>
|
||||
<section class="col-span-12 progress-area"></section>
|
||||
<section class="col-span-12 uploaded-area"></section>
|
||||
<div class="col-span-12 progress-area"></div>
|
||||
<div class="col-span-12 uploaded-area"></div>
|
||||
|
||||
<!-- end dropzone -->
|
||||
<div class="col-span-12 flex flex-col justify-center items-center mt-2">
|
||||
|
@ -102,7 +97,7 @@ include "plugins-modal.html" %}
|
|||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
|
||||
<button
|
||||
plugin-reload-btn
|
||||
data-plugin-reload-btn
|
||||
disabled
|
||||
type="submit"
|
||||
class="disabled:hover:translate-y-0 disabled:cursor-not-allowed 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 tracking-wide dark:brightness-125 hover:brightness-75 w-full 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 leading-normal text-xs ease-in shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md"
|
||||
|
@ -117,11 +112,11 @@ include "plugins-modal.html" %}
|
|||
|
||||
<!-- filter -->
|
||||
<div
|
||||
{{current_endpoint}}-filter
|
||||
data-{{current_endpoint}}-filter
|
||||
class="p-4 col-span-12 2xl:col-span-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
|
||||
>
|
||||
<h5 class="mb-2 font-bold dark:text-white">FILTER</h5>
|
||||
<div class="grid grid-cols-12 gap-x-4 gap-y-2">
|
||||
<div class="mx-2 grid grid-cols-12 gap-x-4 gap-y-2">
|
||||
<!-- search inpt-->
|
||||
<div class="flex flex-col relative col-span-12">
|
||||
<h5
|
||||
|
@ -148,19 +143,19 @@ include "plugins-modal.html" %}
|
|||
Select types
|
||||
</h5>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select="types"
|
||||
data-{{current_endpoint}}-setting-select="types"
|
||||
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-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
|
||||
id="types"
|
||||
name="types"
|
||||
{{current_endpoint}}-setting-select-text="types"
|
||||
data-name="types"
|
||||
data-{{current_endpoint}}-setting-select-text="types"
|
||||
>all</span
|
||||
>
|
||||
<!-- chevron -->
|
||||
<svg
|
||||
{{current_endpoint}}-setting-select="types"
|
||||
data-{{current_endpoint}}-setting-select="types"
|
||||
class="transition-transform h-4 w-4 fill-gray-500"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -173,11 +168,11 @@ include "plugins-modal.html" %}
|
|||
<!-- end chevron -->
|
||||
<!-- dropdown-->
|
||||
<div
|
||||
{{current_endpoint}}-setting-select-dropdown="types"
|
||||
data-{{current_endpoint}}-setting-select-dropdown="types"
|
||||
class="hidden z-100 absolute h-full flex-col w-full translate-y-16"
|
||||
>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
type="button"
|
||||
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"
|
||||
|
@ -185,7 +180,7 @@ include "plugins-modal.html" %}
|
|||
all
|
||||
</button>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
type="button"
|
||||
value="internal"
|
||||
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"
|
||||
|
@ -193,7 +188,7 @@ include "plugins-modal.html" %}
|
|||
internal
|
||||
</button>
|
||||
<button
|
||||
{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
data-{{current_endpoint}}-setting-select-dropdown-btn="types"
|
||||
type="button"
|
||||
value="external"
|
||||
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"
|
||||
|
@ -213,14 +208,14 @@ include "plugins-modal.html" %}
|
|||
>
|
||||
<h5 class="mb-4 mt-2 font-bold dark:text-white mx-2">LIST</h5>
|
||||
|
||||
<div {{current_endpoint}}-list class="grid grid-cols-12 gap-3">
|
||||
<div data-{{current_endpoint}}-list class="grid grid-cols-12 gap-3">
|
||||
{% for plugin in plugins %} {% if plugin['external'] %}
|
||||
<div
|
||||
{{current_endpoint}}-external="{% if plugin['external'] %} external {% else %} internal {% endif %}"
|
||||
data-{{current_endpoint}}-external="{% if plugin['external'] %} external {% else %} internal {% endif %}"
|
||||
class="py-3 min-h-12 relative col-span-12 sm:col-span-6 2xl:col-span-4 3xl:col-span-3 p-1 flex justify-between items-center transition rounded bg-gray-100 hover:bg-gray-300 dark:bg-slate-700 dark:hover:bg-slate-800"
|
||||
>
|
||||
<p
|
||||
{{current_endpoint}}-content
|
||||
data-{{current_endpoint}}-content
|
||||
class="ml-3 mr-2 mb-0 transition duration-300 ease-in-out dark:opacity-90 text-left text-sm md:text-base text-slate-700 dark:text-gray-200"
|
||||
>
|
||||
{{plugin['name']}}
|
||||
|
@ -243,7 +238,7 @@ include "plugins-modal.html" %}
|
|||
</a>
|
||||
{%endif%}
|
||||
<button
|
||||
{{current_endpoint}}-action="delete"
|
||||
data-{{current_endpoint}}-action="delete"
|
||||
name="{{plugin['id']}}"
|
||||
type="button"
|
||||
class="z-20 mx-2 inline-block font-bold text-left text-white uppercase align-middle transition-all cursor-pointer text-xs ease-in tracking-tight-rem hover:-translate-y-px"
|
||||
|
@ -262,11 +257,11 @@ include "plugins-modal.html" %}
|
|||
</div>
|
||||
{% else %}
|
||||
<div
|
||||
{{current_endpoint}}-external="{% if plugin['external'] %} external {%else%} internal {%endif%}"
|
||||
data-{{current_endpoint}}-external="{% if plugin['external'] %} external {%else%} internal {%endif%}"
|
||||
class="py-3 min-h-12 relative col-span-12 sm:col-span-6 2xl:col-span-4 3xl:col-span-3 p-1 flex justify-between items-center transition rounded bg-gray-100 hover:bg-gray-300 dark:bg-slate-700 dark:hover:bg-slate-800"
|
||||
>
|
||||
<p
|
||||
{{current_endpoint}}-content
|
||||
data-{{current_endpoint}}-content
|
||||
class="ml-3 mb-0 transition duration-300 ease-in-out dark:opacity-90 text-left text-sm md:text-base text-slate-700 dark:text-gray-200"
|
||||
>
|
||||
{{plugin['name']}}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
<!-- modal -->
|
||||
<div
|
||||
plugins-modal
|
||||
data-plugins-modal
|
||||
class="dark:brightness-110 w-screen h-screen fixed bg-gray-600/50 z-[1001] top-0 left-0 hidden justify-center items-center"
|
||||
>
|
||||
<div
|
||||
plugins-modal-card
|
||||
data-plugins-modal-card
|
||||
class="min-w-[500px ]overflow-y-auto mx-3 ml-2 mr-6 sm:mx-6 lg:mx-8 my-3 px-4 pt-4 pb-8 w-full max-w-[400px] flex flex-col break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
|
||||
>
|
||||
<div class="w-full flex justify-between mb-2">
|
||||
<p
|
||||
plugins-modal-title
|
||||
data-plugins-modal-title
|
||||
class="transition duration-300 ease-in-out dark:opacity-90 dark:text-gray-300 mb-2 font-sans font-semibold leading-normal uppercase text-md"
|
||||
>
|
||||
DELETE PLUGINS
|
||||
</p>
|
||||
<button class="-translate-y-1" type="button" plugins-modal-close>
|
||||
<button class="-translate-y-1" type="button" data-plugins-modal-close>
|
||||
<svg
|
||||
class="transition duration-300 ease-in-out dark:opacity-90 h-6 w-6 sm:h-7 sm:w-7 fill-slate-800 dark:fill-gray-300"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -28,7 +28,7 @@
|
|||
</div>
|
||||
<!-- delete form-->
|
||||
<form
|
||||
plugins-modal-form-delete
|
||||
data-plugins-modal-form-delete
|
||||
class="w-full h-full flex flex-col justify-between"
|
||||
id="form-delete-plugin"
|
||||
method="POST"
|
||||
|
@ -39,14 +39,14 @@
|
|||
<input type="hidden" value="delete" name="operation" id="operation" />
|
||||
<div>
|
||||
<p
|
||||
plugins-modal-text
|
||||
data-plugins-modal-text
|
||||
class="text-center mx-2 mb-2 mt-8 font-semibold font-sans leading-normal uppercase text-sm"
|
||||
></p>
|
||||
</div>
|
||||
<!-- action button -->
|
||||
<div class="w-full justify-center flex mt-10">
|
||||
<button
|
||||
plugins-modal-close
|
||||
data-plugins-modal-close
|
||||
type="button"
|
||||
class="dark:brightness-90 mr-3 inline-block px-6 py-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-red-500 hover:bg-red-500/80 focus:bg-red-500/80 leading-normal text-md ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md"
|
||||
>
|
|
@ -4,8 +4,8 @@
|
|||
class="col-span-12 relative flex justify-center min-w-0 break-words rounded-2xl bg-clip-border"
|
||||
>
|
||||
<button
|
||||
services-action="new"
|
||||
services-name="service"
|
||||
data-services-action="new"
|
||||
data-services-name="service"
|
||||
type="button"
|
||||
class="dark:bg-green-500/90 duration-300 dark:opacity-90 w-80 inline-block px-6 py-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-green-500 hover:bg-green-500/80 focus:bg-green-500/80 leading-normal text-base ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md"
|
||||
>
|
||||
|
@ -15,7 +15,7 @@
|
|||
<!-- end actions -->
|
||||
<!-- services container-->
|
||||
<div
|
||||
class="gap-3 p-4 grid grid-cols-12 col-span-12 relative min-w-0 break-words rounded-2xl bg-clip-border"
|
||||
class="gap-8 p-4 grid grid-cols-12 col-span-12 relative min-w-0 break-words rounded-2xl bg-clip-border"
|
||||
>
|
||||
{% if services|length == 0 %}
|
||||
<div class="col-span-12 sm:col-span-4 sm:col-start-5">
|
||||
|
@ -28,10 +28,10 @@
|
|||
{% else %}{% for services_batched in services|batch(3) %} {% for service in
|
||||
services_batched %} {% set id_server_name =
|
||||
service["SERVER_NAME"]['value'].replace(".", "-") %}
|
||||
<div services-service
|
||||
<div data-services-service
|
||||
class="dark:brightness-110 overflow-hidden hover:scale-102 transition col-span-12 lg:col-span-6 3xl:col-span-4 p-4 w-full shadow-md break-words bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
|
||||
>
|
||||
<div services-settings class="hidden" value="{{service['settings']}}"></div>
|
||||
<div data-services-settings class="hidden" data-value="{{service['settings']}}"></div>
|
||||
<h5 class="transition duration-300 ease-in-out dark:opacity-90 text-center sm:text-left mb-1 font-bold dark:text-white">
|
||||
{{ service["SERVER_NAME"]['value'] }}
|
||||
</h5>
|
||||
|
@ -339,9 +339,9 @@
|
|||
|
||||
|
||||
<button
|
||||
services-action="edit"
|
||||
data-services-action="edit"
|
||||
type="button"
|
||||
services-name="{{service["SERVER_NAME"]['value']}}"
|
||||
data-services-name="{{service["SERVER_NAME"]['value']}}"
|
||||
|
||||
class="dark:brightness-90 z-20 mx-1 bg-blue-500 hover:bg-blue-500/80 focus:bg-yellow-500/80 inline-block p-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer leading-normal text-xs ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 active:opacity-85 hover:shadow-md"
|
||||
>
|
||||
|
@ -354,9 +354,9 @@
|
|||
|
||||
{% if service["SERVER_NAME"]['method'] == "ui" %}
|
||||
<button
|
||||
services-action="delete"
|
||||
data-services-action="delete"
|
||||
type="button"
|
||||
services-name="{{service["SERVER_NAME"]['value']}}"
|
||||
data-services-name="{{service["SERVER_NAME"]['value']}}"
|
||||
class="dark:brightness-90 z-20 mx-1 bg-red-500 hover:bg-red-500/80 focus:bg-red-500/80 inline-block p-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer leading-normal text-xs ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 active:opacity-85 hover:shadow-md"
|
||||
>
|
||||
<svg
|
||||
|
@ -379,5 +379,5 @@
|
|||
<!-- end services container-->
|
||||
|
||||
<!-- modal -->
|
||||
{% include "services-modal.html" %}
|
||||
{% include "services_modal.html" %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
<!-- modal -->
|
||||
<div
|
||||
service-content="settings"
|
||||
services-modal
|
||||
data-service-content="settings"
|
||||
data-services-modal
|
||||
class="dark:brightness-110 hidden w-screen h-screen fixed bg-gray-600/50 z-[1001] top-0 left-0 justify-center items-center"
|
||||
>
|
||||
<div
|
||||
services-modal-card
|
||||
data-services-modal-card
|
||||
class="overflow-y-auto mx-3 ml-2 mr-6 sm:mx-6 lg:mx-8 my-3 px-4 pt-4 pb-8 w-full min-w-[500px] h-[90vh] flex flex-col break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border"
|
||||
>
|
||||
<div class="w-full flex justify-between mb-2">
|
||||
<p
|
||||
services-modal-title
|
||||
data-services-modal-title
|
||||
class="transition duration-300 ease-in-out dark:opacity-90 dark:text-gray-200 mb-2 font-sans font-semibold leading-normal uppercase text-md"
|
||||
>
|
||||
SERVICE MODAL
|
||||
</p>
|
||||
<button class="-translate-y-1" type="button" services-modal-close>
|
||||
<button class="-translate-y-1" type="button" data-services-modal-close>
|
||||
<svg
|
||||
class="transition duration-300 ease-in-out dark:opacity-90 h-6 w-6 sm:h-7 sm:w-7 fill-slate-800 dark:fill-gray-300"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -28,7 +28,7 @@
|
|||
</button>
|
||||
</div>
|
||||
<div
|
||||
services-tabs-header
|
||||
data-services-tabs-header
|
||||
class="flex justify-start items-center gap-x-4 gap-y-2 my-3"
|
||||
>
|
||||
<h5
|
||||
|
@ -55,7 +55,7 @@
|
|||
{% include "settings_tabs.html" %}
|
||||
<!-- new and edit form -->
|
||||
<form
|
||||
services-modal-form
|
||||
data-services-modal-form
|
||||
class="w-full h-full flex flex-col justify-between"
|
||||
id="form-new"
|
||||
method="POST"
|
||||
|
@ -69,14 +69,14 @@
|
|||
<!-- action button -->
|
||||
<div class="w-full justify-center flex mt-10">
|
||||
<button
|
||||
services-modal-close
|
||||
data-services-modal-close
|
||||
type="button"
|
||||
class="dark:brightness-90 mb-4 mr-3 inline-block px-6 py-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-sky-500 hover:bg-sky-500/80 focus:bg-sky-500/80 leading-normal text-md ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button
|
||||
services-modal-submit
|
||||
data-services-modal-submit
|
||||
type="submit"
|
||||
class="dark:brightness-90 mb-4 inline-block px-6 py-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-green-500 hover:bg-green-500/80 focus:bg-green-500/80 leading-normal text-md ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md"
|
||||
>
|
||||
|
@ -88,7 +88,7 @@
|
|||
<!-- end new and edit form -->
|
||||
<!-- delete form-->
|
||||
<form
|
||||
services-modal-form-delete
|
||||
data-services-modal-form-delete
|
||||
class="w-full h-full flex flex-col justify-between"
|
||||
id="form-delete-server_name"
|
||||
method="POST"
|
||||
|
@ -99,14 +99,14 @@
|
|||
|
||||
<div class="flex justify-center">
|
||||
<p
|
||||
services-modal-text
|
||||
data-services-modal-text
|
||||
class="mx-2 mb-2 mt-8 font-semibold font-sans leading-normal uppercase text-sm"
|
||||
></p>
|
||||
</div>
|
||||
<!-- action button -->
|
||||
<div class="w-full justify-center flex mt-10">
|
||||
<button
|
||||
services-modal-close
|
||||
data-services-modal-close
|
||||
type="button"
|
||||
class="dark:brightness-90 mr-3 inline-block px-6 py-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-sky-500 hover:bg-sky-500/80 focus:bg-sky-500/80 leading-normal text-md ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md"
|
||||
>
|
|
@ -6,12 +6,12 @@
|
|||
{% for plugin in plugins %}
|
||||
|
||||
<div
|
||||
plugin-item="{{plugin['id']}}"
|
||||
data-plugin-item="{{plugin['id']}}"
|
||||
id="{{plugin['id']}}"
|
||||
class="{% if loop.index != 1 %}hidden{%endif%} w-full"
|
||||
>
|
||||
<!-- title and desc -->
|
||||
<div class="col-span-12" setting-header>
|
||||
<div class="col-span-12" data-setting-header>
|
||||
<h5
|
||||
class="transition duration-300 ease-in-out dark:opacity-90 ml-2 font-bold text-md uppercase dark:text-white mb-0"
|
||||
>
|
||||
|
@ -24,24 +24,23 @@
|
|||
</div>
|
||||
</div>
|
||||
<!-- end title and desc -->
|
||||
<div plugin-settings class="w-full grid grid-cols-12">
|
||||
<div data-plugin-settings class="w-full grid grid-cols-12">
|
||||
<!-- plugin settings not multiple -->
|
||||
{% for setting, value in plugin["settings"].items() %}{% if setting != "IS_LOADING" and current_endpoint
|
||||
== "global-config" and value['context'] == "global" and not value['multiple'] or current_endpoint ==
|
||||
"services" and value['context'] == "multisite" and not value['multiple'] %}
|
||||
<div setting-container
|
||||
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"
|
||||
<div data-setting-container
|
||||
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"
|
||||
>
|
||||
{{value["label"]}}
|
||||
</h5>
|
||||
<svg
|
||||
popover-btn="{{ value["label"] }}"
|
||||
data-popover-btn="{{ value["label"] }}"
|
||||
class="cursor-pointer fill-blue-500 h-5 w-5 ml-2 hover:brightness-75"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -51,10 +50,10 @@
|
|||
/>
|
||||
</svg>
|
||||
<!-- popover -->
|
||||
<div class="hidden transition z-50 rounded-md p-3 left-0 -translate-y-7 bottom-0 absolute bg-blue-500"
|
||||
popover-content="{{ value["label"] }}"
|
||||
<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 -->
|
||||
|
@ -66,17 +65,17 @@
|
|||
<div class="relative flex items-center">
|
||||
<input
|
||||
{% if setting == "SERVER_NAME" %}required{%endif%}
|
||||
default-value="{{global_config[setting]['value']}}" default-method="{{global_config[setting]['method']}}"
|
||||
data-default-value="{{global_config[setting]['value']}}" data-default-method="{{global_config[setting]['method']}}"
|
||||
{% if global_config[setting]['method'] != 'ui' and global_config[setting]['method'] != 'default' %} disabled {% endif %} id="{{setting}}" name="{{setting}}"
|
||||
class="outline-none dark:opacity-90 dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:border-gray-300/0 focus:ring-1 focus:valid:ring-green-500 focus:invalid:ring-red-500 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-1.5 py-1 md:px-3 md:py-2 font-normal text-gray-700 transition-all placeholder:text-gray-500 disabled:bg-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 dark:disabled:text-gray-300 disabled:text-gray-700"
|
||||
value="{% if global_config[setting]['value'] %} {{global_config[setting]['value']}} {% else %} {{value['default']}} {% endif %}" type="{{value['type']}}" pattern="{{value['regex']|safe}}" />
|
||||
|
||||
{% if value['type'] == "password" %}
|
||||
<div setting-password-container class="absolute flex right-2 h-5 w-5">
|
||||
<button type="button" setting-password="visible" class="h-5 w-5 flex items-center align-middle" type="button">
|
||||
<div data-setting-password-container class="absolute flex right-2 h-5 w-5">
|
||||
<button type="button" data-setting-password="visible" class="h-5 w-5 flex items-center align-middle" type="button">
|
||||
<svg class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg>
|
||||
</button>
|
||||
<button type="button" setting-password="invisible" class="hidden -translate-y-0.2 scale-110 h-5 w-5 items-center align-middle">
|
||||
<button type="button" data-setting-password="invisible" class="hidden -translate-y-0.2 scale-110 h-5 w-5 items-center align-middle">
|
||||
<svg class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -89,8 +88,8 @@
|
|||
<!-- select -->
|
||||
{% if value["type"] == "select" %}
|
||||
<!-- default hidden-->
|
||||
<select default-method="{{global_config[setting]['method']}}" default-value="{{value['default']}}"
|
||||
id="{{setting}}" name="{{setting}}" setting-select-default="{{value['id']}}" type="form-select" id="{{setting}}" name="{{setting}}"
|
||||
<select data-default-method="{{global_config[setting]['method']}}" data-default-value="{{value['default']}}"
|
||||
id="{{setting}}" name="{{setting}}" data-setting-select-default="{{value['id']}}" data-type="form-select" id="{{setting}}" name="{{setting}}"
|
||||
class="hidden">
|
||||
{% for item in value['select'] %}
|
||||
<option value="{{item}}" {% if global_config[setting]['value'] and global_config[setting]['value'] == item or not global_config[setting]['value'] and value['default'] == item %} selected{% endif %}>{{item}}</option>
|
||||
|
@ -99,30 +98,31 @@
|
|||
<!-- end default hidden-->
|
||||
|
||||
<!--custom-->
|
||||
<div select-container class="relative">
|
||||
<div data-select-container class="relative">
|
||||
<button
|
||||
{% if global_config[setting]['method'] != 'ui' and global_config[setting]['method'] != 'default' %} disabled {% endif %} setting-select="{{value['id']}}"
|
||||
default-value="{{global_config[setting]['value']}}"
|
||||
{% 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"
|
||||
>
|
||||
{% for item in value['select'] %} {% if global_config[setting]['value'] and
|
||||
global_config[setting]['value'] == item %}
|
||||
<span
|
||||
setting-select-text="{{value['id']}}"
|
||||
value="{{global_config[setting]['value']}}"
|
||||
data-setting-select-text="{{value['id']}}"
|
||||
data-value="{{global_config[setting]['value']}}"
|
||||
>{{global_config[setting]['value']}}</span
|
||||
>
|
||||
{% elif not global_config[setting]['value'] and value['default'] == item %}
|
||||
<span
|
||||
setting-select-text="{{value['id']}}"
|
||||
value="{{value['default']}}"
|
||||
data-setting-select-text="{{value['id']}}"
|
||||
data-value="{{value['default']}}"
|
||||
>{{value['default']}}</span
|
||||
>
|
||||
{% endif %} {% endfor %}
|
||||
<!-- chevron -->
|
||||
<svg
|
||||
setting-select="{{value['id']}}"
|
||||
data-setting-select="{{value['id']}}"
|
||||
class="transition-transform h-4 w-4 fill-gray-500"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -135,7 +135,7 @@
|
|||
</button>
|
||||
<!-- dropdown-->
|
||||
<div
|
||||
setting-select-dropdown="{{value['id']}}"
|
||||
data-setting-select-dropdown="{{value['id']}}"
|
||||
class="hidden z-[20] absolute h-full flex-col w-full mt-2"
|
||||
>
|
||||
{% for item in value['select'] %} {% if global_config[setting]['value'] and
|
||||
|
@ -144,9 +144,9 @@
|
|||
<button
|
||||
type="button"
|
||||
value="{{item}}"
|
||||
setting-select-dropdown-btn="{{value['id']}}"
|
||||
data-setting-select-dropdown-btn="{{value['id']}}"
|
||||
type="button"
|
||||
class="{% if loop.index == 1 %} border-t rounded-t {% endif %} {% if loop.index == loop.length %}rounded-b {% endif %} border-b border-l border-r border-gray-300 hover:brightness-90 bg-primary text-white my-0 relative px-6 py-2 text-center 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"
|
||||
class="min-h-[38px] {% if loop.index == 1 %} border-t rounded-t {% endif %} {% if loop.index == loop.length %}rounded-b {% endif %} border-b border-l border-r border-gray-300 hover:brightness-90 bg-primary text-white my-0 relative px-6 py-2 text-center 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"
|
||||
>
|
||||
{{item}}
|
||||
</button>
|
||||
|
@ -154,9 +154,9 @@
|
|||
<button
|
||||
type="button"
|
||||
value="{{item}}"
|
||||
setting-select-dropdown-btn="{{value['id']}}"
|
||||
data-setting-select-dropdown-btn="{{value['id']}}"
|
||||
type="button"
|
||||
class="{% if loop.index == 1 %} border-t rounded-t {% endif %} {% if loop.index == loop.length %}rounded-b {% endif %} border-b border-l border-r border-gray-300 hover:brightness-90 bg-white text-gray-700 my-0 relative px-6 py-2 text-center 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"
|
||||
class="min-h-[38px] {% if loop.index == 1 %} border-t rounded-t {% endif %} {% if loop.index == loop.length %}rounded-b {% endif %} border-b border-l border-r border-gray-300 hover:brightness-90 bg-white text-gray-700 my-0 relative px-6 py-2 text-center 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"
|
||||
>
|
||||
{{item}}
|
||||
</button>
|
||||
|
@ -169,15 +169,15 @@
|
|||
|
||||
<!-- checkbox -->
|
||||
{% if value["type"] == "check" %}
|
||||
<div 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}}"
|
||||
default-method="{{global_config[setting]['method']}}"
|
||||
default-value="{{global_config[setting]['value']}}" {% if
|
||||
data-default-method="{{global_config[setting]['method']}}"
|
||||
data-default-value="{{global_config[setting]['value']}}" {% if
|
||||
setting in ["AUTOCONF_MODE", "SWARM_MODE", "KUBERNETES_MODE"] or global_config[setting]['method'] != 'ui' and global_config[setting]['method']
|
||||
!= '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
|
||||
|
@ -185,17 +185,17 @@
|
|||
bg-no-repeat align-top transition-all disabled:bg-gray-400
|
||||
disabled:border-gray-400 dark:disabled:bg-gray-800
|
||||
dark:disabled:border-gray-800 disabled:text-gray-700
|
||||
dark:disabled:text-gray-300" type="checkbox" pattern="{{value['regex']|safe}}"
|
||||
dark:disabled:text-gray-300" type="checkbox" data-pattern="{{value['regex']|safe}}"
|
||||
value="{% if global_config[setting]['value'] %}
|
||||
{{global_config[setting]['value']}} {% else %} {{value['default']}} {% endif
|
||||
%}" />
|
||||
<input type="hidden" name="{{setting}}" value="{% if
|
||||
setting in ["AUTOCONF_MODE", "SWARM_MODE", "KUBERNETES_MODE"] or global_config[setting]['method'] != 'ui' and global_config[setting]['method']
|
||||
!= 'default' %}{{global_config[setting]['value']}}{% else %}no{% endif %}" default-value="{% if
|
||||
!= 'default' %}{{global_config[setting]['value']}}{% else %}no{% endif %}" data-default-value="{% if
|
||||
setting in ["AUTOCONF_MODE", "SWARM_MODE", "KUBERNETES_MODE"] or global_config[setting]['method'] != 'ui' and global_config[setting]['method']
|
||||
!= 'default' %}{{global_config[setting]['value']}}{% else %}no{% endif %}" default-method="default" />
|
||||
!= 'default' %}{{global_config[setting]['value']}}{% else %}no{% endif %}" data-default-method="default" />
|
||||
<svg
|
||||
checkbox-handler="{{value['id']}}"
|
||||
data-checkbox-handler="{{value['id']}}"
|
||||
class="pointer-events-none absolute fill-white dark:fill-gray-300 left-0 top-0 translate-x-1 translate-y-2 h-3 w-3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -232,41 +232,41 @@
|
|||
|
||||
{%for multiple in multList %}
|
||||
<!-- plugin multiple handler -->
|
||||
<div multiple-handler class="flex items-center mx-0 sm:mx-4 md:mx-6 md:my-3 my-2 2xl:mx-6 2xl:my-3 col-span-12 ">
|
||||
<div data-multiple-handler class="flex items-center mx-0 sm:mx-4 md:mx-6 md:my-3 my-2 2xl:mx-6 2xl:my-3 col-span-12 ">
|
||||
<h5
|
||||
class="transition duration-300 ease-in-out dark:opacity-90 text-sm sm:text-md font-bold m-0 dark:text-gray-300"
|
||||
>
|
||||
{{multiple}}
|
||||
</h5>
|
||||
<button {{current_endpoint}}-multiple-add="{{multiple}}" type="button" class="ml-3 dark:brightness-90 inline-block px-3 py-1.5 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-green-500 hover:bg-green-500/80 focus:bg-green-500/80 leading-normal text-md ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">
|
||||
<button data-{{current_endpoint}}-multiple-add="{{multiple}}" type="button" class="ml-3 dark:brightness-90 inline-block px-3 py-1.5 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-green-500 hover:bg-green-500/80 focus:bg-green-500/80 leading-normal text-md ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">
|
||||
Add
|
||||
</button>
|
||||
<button {{current_endpoint}}-multiple-toggle="{{multiple}}" type="button" class="ml-3 dark:brightness-90 inline-block px-3 py-1.5 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-sky-500 hover:bg-sky-500/80 focus:bg-sky-500/80 leading-normal text-md ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">
|
||||
<button data-{{current_endpoint}}-multiple-toggle="{{multiple}}" type="button" class="ml-3 dark:brightness-90 inline-block px-3 py-1.5 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-sky-500 hover:bg-sky-500/80 focus:bg-sky-500/80 leading-normal text-md ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">
|
||||
SHOW / HIDE
|
||||
</button>
|
||||
</div>
|
||||
<!-- end plugin multiple handler-->
|
||||
|
||||
<!-- multiple settings -->
|
||||
<div {{current_endpoint}}-settings-multiple="{{multiple}}_SCHEMA" class="bg-gray-50 dark:bg-slate-900/30 hidden w-full mb-8 grid-cols-12 border dark:border-gray-700 rounded">
|
||||
<div data-{{current_endpoint}}-settings-multiple="{{multiple}}_SCHEMA" class="bg-gray-50 dark:bg-slate-900/30 hidden w-full mb-8 grid-cols-12 border dark:border-gray-700 rounded">
|
||||
{% for setting, value in plugin["settings"].items() %}
|
||||
{# render only setting that match the multiple id and context #}
|
||||
{% if current_endpoint
|
||||
== "global-config" and value['context'] == "global" and value['multiple'] == multiple or current_endpoint ==
|
||||
"services" and value['context'] == "multisite" and value['multiple'] == multiple %}
|
||||
<div setting-container="{{setting}}_SCHEMA"
|
||||
<div data-setting-container="{{setting}}_SCHEMA"
|
||||
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"] }}">
|
||||
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"
|
||||
>
|
||||
{{value["label"]}}
|
||||
</h5>
|
||||
<svg
|
||||
popover-btn="{{ value["label"] }}"
|
||||
data-popover-btn="{{ value["label"] }}"
|
||||
class="cursor-pointer fill-blue-500 h-5 w-5 ml-2 hover:brightness-75"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -276,10 +276,10 @@
|
|||
/>
|
||||
</svg>
|
||||
<!-- popover -->
|
||||
<div class="hidden transition z-50 rounded-md p-3 left-0 -translate-y-7 bottom-0 absolute bg-blue-500"
|
||||
popover-content="{{ value["label"] }}"
|
||||
<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 -->
|
||||
|
@ -290,16 +290,16 @@
|
|||
{% if value["type"] != "select" and value["type"] != "check" %}
|
||||
<div class="relative flex items-center">
|
||||
<input
|
||||
default-value="{{value['default']}}" default-method="default" id="{{setting}}_SCHEMA" name="{{setting}}_SCHEMA"
|
||||
data-default-value="{{value['default']}}" data-default-method="default" id="{{setting}}_SCHEMA" name="{{setting}}_SCHEMA"
|
||||
class="outline-none dark:opacity-90 dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:border-gray-300/0 focus:ring-1 focus:valid:ring-green-500 focus:invalid:ring-red-500 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-1.5 py-1 md:px-3 md:py-2 font-normal text-gray-700 transition-all placeholder:text-gray-500 disabled:bg-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 dark:disabled:text-gray-300 disabled:text-gray-700"
|
||||
value="{{value['default']}}" type="{{value['type']}}" pattern="{{value['regex']|safe}}" />
|
||||
|
||||
{% if value['type'] == "password" %}
|
||||
<div setting-password-container class="absolute flex right-2 h-5 w-5">
|
||||
<button type="button" setting-password="visible" class="h-5 w-5 flex items-center align-middle" type="button">
|
||||
<div data-setting-password-container class="absolute flex right-2 h-5 w-5">
|
||||
<button type="button"data- setting-password="visible" class="h-5 w-5 flex items-center align-middle" type="button">
|
||||
<svg class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg>
|
||||
</button>
|
||||
<button type="button" setting-password="invisible" class="hidden -translate-y-0.2 scale-110 h-5 w-5 items-center align-middle">
|
||||
<button type="button" data-setting-password="invisible" class="hidden -translate-y-0.2 scale-110 h-5 w-5 items-center align-middle">
|
||||
<svg class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -311,8 +311,8 @@
|
|||
<!-- select -->
|
||||
{% if value["type"] == "select" %}
|
||||
<!-- default hidden-->
|
||||
<select default-method="default" default-value="{{value['default']}}"
|
||||
id="{{setting}}_SCHEMA" name="{{setting}}_SCHEMA" select-default="{{value['id']}}" type="form-select" id="{{setting}}" name="{{setting}}"
|
||||
<select data-default-method="default" data-default-value="{{value['default']}}"
|
||||
id="{{setting}}_SCHEMA" name="{{setting}}_SCHEMA" data-select-default="{{value['id']}}" data-type="form-select" id="{{setting}}" name="{{setting}}"
|
||||
class="hidden">
|
||||
{% for item in value['select'] %}
|
||||
<option value="{{item}}" {% if value['default'] == item %} selected {% endif %}>{{item}}</option>
|
||||
|
@ -321,23 +321,23 @@
|
|||
<!-- end default hidden-->
|
||||
|
||||
<!--custom-->
|
||||
<div select-container class="relative">
|
||||
<div data-select-container class="relative">
|
||||
<button
|
||||
setting-select="{{value['id']}}"
|
||||
default-value="{{value['default']}}"
|
||||
data-setting-select="{{value['id']}}"
|
||||
data-default-value="{{value['default']}}"
|
||||
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"
|
||||
>
|
||||
{% for item in value['select'] %} {% if value['default'] == item %}
|
||||
<span
|
||||
setting-select-text="{{value['id']}}"
|
||||
value="{{value['default']}}"
|
||||
data-setting-select-text="{{value['id']}}"
|
||||
data-value="{{value['default']}}"
|
||||
>{{value['default']}}</span
|
||||
>
|
||||
{% endif %} {% endfor %}
|
||||
<!-- chevron -->
|
||||
<svg
|
||||
setting-select="{{value['id']}}"
|
||||
data-setting-select="{{value['id']}}"
|
||||
class="transition-transform h-4 w-4 fill-gray-500"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -350,16 +350,16 @@
|
|||
</button>
|
||||
<!-- dropdown-->
|
||||
<div
|
||||
setting-select-dropdown="{{value['id']}}"
|
||||
data-setting-select-dropdown="{{value['id']}}"
|
||||
class="hidden z-[20] absolute h-full flex-col w-full mt-2"
|
||||
>
|
||||
{% for item in value['select'] %} {% if value['default'] == item %}
|
||||
<button
|
||||
type="button"
|
||||
value="{{item}}"
|
||||
setting-select-dropdown-btn="{{value['id']}}"
|
||||
data-setting-select-dropdown-btn="{{value['id']}}"
|
||||
type="button"
|
||||
class="{% if loop.index == 1 %} border-t rounded-t {% endif %} {% if loop.index == loop.length %}rounded-b {% endif %} border-b border-l border-r border-gray-300 hover:brightness-90 bg-primary text-white my-0 relative px-6 py-2 text-center 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"
|
||||
class="min-h-[38px] {% if loop.index == 1 %} border-t rounded-t {% endif %} {% if loop.index == loop.length %}rounded-b {% endif %} border-b border-l border-r border-gray-300 hover:brightness-90 bg-primary text-white my-0 relative px-6 py-2 text-center 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"
|
||||
>
|
||||
{{item}}
|
||||
</button>
|
||||
|
@ -367,9 +367,9 @@
|
|||
<button
|
||||
type="button"
|
||||
value="{{item}}"
|
||||
setting-select-dropdown-btn="{{value['id']}}"
|
||||
data-setting-select-dropdown-btn="{{value['id']}}"
|
||||
type="button"
|
||||
class="{% if loop.index == 1 %} border-t rounded-t {% endif %} {% if loop.index == loop.length %}rounded-b {% endif %} border-b border-l border-r border-gray-300 hover:brightness-90 bg-white text-gray-700 my-0 relative px-6 py-2 text-center 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"
|
||||
class="min-h-[38px] {% if loop.index == 1 %} border-t rounded-t {% endif %} {% if loop.index == loop.length %}rounded-b {% endif %} border-b border-l border-r border-gray-300 hover:brightness-90 bg-white text-gray-700 my-0 relative px-6 py-2 text-center 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"
|
||||
>
|
||||
{{item}}
|
||||
</button>
|
||||
|
@ -382,11 +382,11 @@
|
|||
|
||||
<!-- checkbox -->
|
||||
{% if value["type"] == "check" %}
|
||||
<div checkbox-handler="{{value['id']}}" class="relative mb-7 md:mb-0">
|
||||
<div data-checkbox-handler="{{value['id']}}" class="relative mb-7 md:mb-0">
|
||||
<input id="{{setting}}_SCHEMA" name="{{setting}}_SCHEMA"
|
||||
default-method="default"
|
||||
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
|
||||
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
|
||||
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
|
||||
|
@ -394,11 +394,11 @@
|
|||
bg-no-repeat align-top transition-all disabled:bg-gray-400
|
||||
disabled:border-gray-400 dark:disabled:bg-gray-800
|
||||
dark:disabled:border-gray-800 disabled:text-gray-700
|
||||
dark:disabled:text-gray-300" type="checkbox" pattern="{{value['regex']|safe}}"
|
||||
dark:disabled:text-gray-300" type="checkbox" data-pattern="{{value['regex']|safe}}"
|
||||
value="{{value['default']}}" />
|
||||
<input type="hidden" name="{{setting}}_SCHEMA" value="no" default-value="no" default-method="default" />
|
||||
<input type="hidden" name="{{setting}}_SCHEMA" value="no" data-default-value="no" data-default-method="default" />
|
||||
<svg
|
||||
checkbox-handler="{{value['id']}}"
|
||||
data-checkbox-handler="{{value['id']}}"
|
||||
class="pointer-events-none absolute fill-white dark:fill-gray-300 left-0 top-0 translate-x-1 translate-y-2 h-3 w-3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -419,8 +419,8 @@
|
|||
<!--end invalid feedback-->
|
||||
</div>
|
||||
{% endif %} {% endfor %}
|
||||
<div multiple-delete-container class="col-span-12 flex justify-center my-4">
|
||||
<button {{current_endpoint}}-multiple-delete="{{plugin['name']}}" type="button" class="ml-3 dark:brightness-90 inline-block px-3 py-1.5 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-red-500 hover:bg-red-500/80 focus:bg-red-500/80 leading-normal text-md ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">
|
||||
<div data-multiple-delete-container class="col-span-12 flex justify-center my-4">
|
||||
<button data-{{current_endpoint}}-multiple-delete="{{plugin['name']}}" type="button" class="ml-3 dark:brightness-90 inline-block px-3 py-1.5 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-red-500 hover:bg-red-500/80 focus:bg-red-500/80 leading-normal text-md ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">
|
||||
Remove
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -2,23 +2,23 @@
|
|||
{% set current_endpoint = url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-')
|
||||
%}
|
||||
{% set plugins = config["CONFIG"].get_plugins() %}
|
||||
<div {{current_endpoint}}-tabs class="col-span-12 grid grid-cols-12 {% if current_endpoint == 'services' %}mb-4{% endif %}">
|
||||
<div data-{{current_endpoint}}-tabs class="col-span-12 grid grid-cols-12 {% if current_endpoint == 'services' %}mb-4{% endif %}">
|
||||
<!-- desktop tabs -->
|
||||
<div {{current_endpoint}}-tabs-desktop class="hidden md:block col-span-12">
|
||||
<div role="tablist" data-{{current_endpoint}}-tabs-desktop class="hidden md:block col-span-12">
|
||||
<!-- tabs -->
|
||||
{% for plugin in plugins %} {% if current_endpoint == "services" and plugin["settings"]
|
||||
and check_settings(plugin["settings"], "multisite") or current_endpoint == "global-config" and plugin["settings"]
|
||||
and check_settings(plugin["settings"], "global") %}
|
||||
<button
|
||||
tab-handler="{{ plugin['id'] }}"
|
||||
<button role="tab"
|
||||
data-tab-handler="{{ plugin['id'] }}"
|
||||
type="button"
|
||||
class="{% if loop.first %} brightness-90 z-[1001]{%else %} {% endif %} border-primary dark:hover:bg-slate-800 dark:border-slate-600 dark:bg-slate-700 border my-1 relative inline-block px-3 py-3 font-bold text-center uppercase align-middle transition-all rounded-none cursor-pointer bg-white hover:bg-gray-100 leading-normal text-sm ease-in tracking-tight-rem shadow-xs hover:shadow-md"
|
||||
>
|
||||
<div class="w-full flex justify-between items-center">
|
||||
<span class="w-full flex justify-between items-center">
|
||||
<!-- text and icon -->
|
||||
<span class="text-primary transition duration-300 ease-in-out dark:opacity-90 pl-3 pr-2 dark:text-gray-300"> {{ plugin["name"] }} </span>
|
||||
<svg
|
||||
popover-btn="{{ plugin["name"] }}"
|
||||
data-popover-btn="{{ plugin["name"] }}"
|
||||
class=" fill-blue-500 h-5 w-5 mr-2 hover:brightness-95"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
|
@ -29,14 +29,14 @@
|
|||
</svg>
|
||||
<!-- end text and icon -->
|
||||
<!-- popover -->
|
||||
<div
|
||||
popover-content="{{ plugin["name"] }}"
|
||||
<span
|
||||
data-popover-content="{{ plugin["name"] }}"
|
||||
class="top-[60px] min-w-[150px] dark:brightness-90 bg-blue-500 hidden transition z-50 rounded-md p-3 left-0 absolute"
|
||||
>
|
||||
<p class="font-bold text-sm text-white m-0">{{ plugin['description'] }}</p>
|
||||
</div>
|
||||
<span class="font-bold text-sm text-white m-0">{{ plugin['description'] }}</span>
|
||||
</span>
|
||||
<!-- end popover -->
|
||||
</div>
|
||||
</span>
|
||||
</button>
|
||||
{% endif %} {% endfor %}
|
||||
<!--end tabs-->
|
||||
|
@ -45,7 +45,7 @@
|
|||
<!-- mobile tabs -->
|
||||
<div class="md:hidden relative col-span-12 h-full">
|
||||
<button
|
||||
tab-dropdown-btn
|
||||
data-tab-dropdown-btn
|
||||
type="button"
|
||||
class="dark:hover:brightness-95 dark:border-slate-600 dark:bg-slate-700 border-primary border w-full flex items-center justify-between rounded-lg hover:-translate-y-px my-1 px-6 py-3 font-bold text-center uppercase align-middle transition-all cursor-pointer bg-white hover:bg-gray-50 leading-normal text-sm ease-in tracking-tight-rem shadow-xs hover:shadow-md"
|
||||
>
|
||||
|
@ -65,7 +65,7 @@
|
|||
</button>
|
||||
<!-- dropdown-->
|
||||
<div
|
||||
tab-dropdown
|
||||
data-tab-dropdown
|
||||
class="hidden z-100 absolute flex-col w-full overflow-hidden overflow-y-auto max-h-90"
|
||||
>
|
||||
{% set first_el = "True" %}
|
||||
|
@ -75,7 +75,7 @@
|
|||
|
||||
{% if loop.first %}
|
||||
<button
|
||||
tab-handler-mobile="{{ plugin['id'] }}"
|
||||
data-tab-handler-mobile="{{ plugin['id'] }}"
|
||||
type="button"
|
||||
data-select="false"
|
||||
id="edit-{{current_endpoint}}-{{ plugin['id'] }}-tab"
|
||||
|
@ -84,7 +84,7 @@
|
|||
</button>
|
||||
{% else %}
|
||||
<button
|
||||
tab-handler-mobile="{{ plugin['id'] }}"
|
||||
data-tab-handler-mobile="{{ plugin['id'] }}"
|
||||
type="button"
|
||||
data-select="false"
|
||||
id="edit-{{current_endpoint}}-{{ plugin['id'] }}-tab"
|
||||
|
|
Loading…
Reference in New Issue