Compare commits

..

1 Commits

Author SHA1 Message Date
GitHub Actions
03c40fad1c Update .app files 2025-11-17 16:08:04 +00:00
353 changed files with 2939 additions and 2428 deletions

View File

@@ -22,18 +22,6 @@ body:
validations:
required: true
- type: dropdown
id: verbose_run
attributes:
label: 🔎 Did you run the script with verbose mode enabled?
description: "Required for debugging any script issue. A verbose log is mandatory."
options:
- ""
- "Yes, verbose mode was enabled and the output is included below"
- "No (this issue will likely be closed automatically)"
validations:
required: true
- type: input
id: script_name
attributes:

View File

@@ -10,89 +10,16 @@
> [!CAUTION]
Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit the project's popularity for potentially malicious purposes.
## 2025-11-22
### 🌐 Website
- #### ✨ New Features
- Refactor /data page [@BramSuurdje](https://github.com/BramSuurdje) ([#9343](https://github.com/community-scripts/ProxmoxVE/pull/9343))
## 2025-11-21
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- plex: prevent [] syntax issue [@MickLesk](https://github.com/MickLesk) ([#9318](https://github.com/community-scripts/ProxmoxVE/pull/9318))
- fix: karakeep strip "v" from release version [@CrazyWolf13](https://github.com/CrazyWolf13) ([#9324](https://github.com/community-scripts/ProxmoxVE/pull/9324))
- NetVisor: fix grep in update [@vhsdream](https://github.com/vhsdream) ([#9334](https://github.com/community-scripts/ProxmoxVE/pull/9334))
- Immich: pin correct version [@vhsdream](https://github.com/vhsdream) ([#9332](https://github.com/community-scripts/ProxmoxVE/pull/9332))
- #### 🔧 Refactor
- Refactor IPv6 disable logic and add 'disable' option [@MickLesk](https://github.com/MickLesk) ([#9326](https://github.com/community-scripts/ProxmoxVE/pull/9326))
## 2025-11-20
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- core: change 'uv cache clear' to 'uv cache clean' [@MickLesk](https://github.com/MickLesk) ([#9299](https://github.com/community-scripts/ProxmoxVE/pull/9299))
- #### ✨ New Features
- Immich v2.3.1: OpenVINO tuning, OCR fixes, Maintenance mode, workflows/plugin framework [@vhsdream](https://github.com/vhsdream) ([#9310](https://github.com/community-scripts/ProxmoxVE/pull/9310))
- kasm: add: update [@CrazyWolf13](https://github.com/CrazyWolf13) ([#9253](https://github.com/community-scripts/ProxmoxVE/pull/9253))
- tools/pve: expand PVE support to 9.09.1 (post-install & netdata) [@MickLesk](https://github.com/MickLesk) ([#9298](https://github.com/community-scripts/ProxmoxVE/pull/9298))
- #### 💥 Breaking Changes
- Omada - AVX-only support [@MickLesk](https://github.com/MickLesk) ([#9295](https://github.com/community-scripts/ProxmoxVE/pull/9295))
## 2025-11-19
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- HotFix: Fix NetVisor env var [@vhsdream](https://github.com/vhsdream) ([#9286](https://github.com/community-scripts/ProxmoxVE/pull/9286))
- Jotty: reduce RAM requirement [@vhsdream](https://github.com/vhsdream) ([#9272](https://github.com/community-scripts/ProxmoxVE/pull/9272))
- Nginx Proxy Manager: Pin version to v2.13.4 [@tremor021](https://github.com/tremor021) ([#9259](https://github.com/community-scripts/ProxmoxVE/pull/9259))
- #### ✨ New Features
- PVE 9.1 version support [@MickLesk](https://github.com/MickLesk) ([#9280](https://github.com/community-scripts/ProxmoxVE/pull/9280))
- force disable IPv6 if IPV6_METHOD = none [@MickLesk](https://github.com/MickLesk) ([#9277](https://github.com/community-scripts/ProxmoxVE/pull/9277))
- #### 💥 Breaking Changes
- NetVisor: v0.10.0 fixes [@vhsdream](https://github.com/vhsdream) ([#9255](https://github.com/community-scripts/ProxmoxVE/pull/9255))
## 2025-11-18
### 🚀 Updated Scripts
- librenms: Fix password to short [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#9236](https://github.com/community-scripts/ProxmoxVE/pull/9236))
- #### 🐞 Bug Fixes
- Huntarr: Downgrade Python to 3.12 [@MickLesk](https://github.com/MickLesk) ([#9246](https://github.com/community-scripts/ProxmoxVE/pull/9246))
- kasm: fix release fetching [@MickLesk](https://github.com/MickLesk) ([#9244](https://github.com/community-scripts/ProxmoxVE/pull/9244))
## 2025-11-17
### 🆕 New Scripts
- Passbolt ([#9226](https://github.com/community-scripts/ProxmoxVE/pull/9226))
- Domain-Locker ([#9214](https://github.com/community-scripts/ProxmoxVE/pull/9214))
- Domain-Locker ([#9214](https://github.com/community-scripts/ProxmoxVE/pull/9214))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Domain Monitor: Fix encryption key length in install script [@tremor021](https://github.com/tremor021) ([#9239](https://github.com/community-scripts/ProxmoxVE/pull/9239))
- NetVisor: add build deps, increase RAM [@vhsdream](https://github.com/vhsdream) ([#9205](https://github.com/community-scripts/ProxmoxVE/pull/9205))
- fix: restart apache2 after installing zabbix config [@AlphaLawless](https://github.com/AlphaLawless) ([#9206](https://github.com/community-scripts/ProxmoxVE/pull/9206))
@@ -104,12 +31,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- Refactor: paperless-ngx (Breaking Change Inside) [@MickLesk](https://github.com/MickLesk) ([#9223](https://github.com/community-scripts/ProxmoxVE/pull/9223))
### 🧰 Maintenance
- #### 📂 Github
- github: add verbose mode check to bug report template [@MickLesk](https://github.com/MickLesk) ([#9234](https://github.com/community-scripts/ProxmoxVE/pull/9234))
## 2025-11-16
### 🆕 New Scripts

View File

@@ -1,6 +1,6 @@
module proxmox-api
go 1.24.0
go 1.23.2
require (
github.com/gorilla/mux v1.8.1
@@ -17,7 +17,7 @@ require (
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
golang.org/x/crypto v0.45.0 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/text v0.31.0 // indirect
golang.org/x/crypto v0.35.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/text v0.22.0 // indirect
)

View File

@@ -27,16 +27,16 @@ go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793Sqyh
go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -48,8 +48,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

View File

@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-12}"
var_version="${var_version:-13}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
@@ -29,7 +29,7 @@ function update_script() {
exit
fi
PYTHON_VERSION="3.12" setup_uv
setup_uv
if check_for_gh_release "huntarr" "plexguide/Huntarr.io"; then
msg_info "Stopping Service"

View File

@@ -61,15 +61,6 @@ EOF
msg_ok "Installed libmimalloc3"
fi
if [[ ! -f /etc/apt/sources.list.d/mise.list ]]; then
msg_info "Installing Mise"
curl -fSs https://mise.jdx.dev/gpg-key.pub | tee /etc/apt/keyrings/mise-archive-keyring.pub 1>/dev/null
echo "deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.pub arch=amd64] https://mise.jdx.dev/deb stable main" | tee /etc/apt/sources.list.d/mise.list
$STD apt update
$STD apt install -y mise
msg_ok "Installed Mise"
fi
STAGING_DIR=/opt/staging
BASE_DIR=${STAGING_DIR}/base-images
SOURCE_DIR=${STAGING_DIR}/image-source
@@ -102,7 +93,7 @@ EOF
msg_ok "Image-processing libraries up to date"
fi
RELEASE="2.3.1"
RELEASE="2.2.3"
if check_for_gh_release "immich" "immich-app/immich" "${RELEASE}"; then
msg_info "Stopping Services"
systemctl stop immich-web
@@ -130,7 +121,6 @@ EOF
UPLOAD_DIR="$(sed -n '/^IMMICH_MEDIA_LOCATION/s/[^=]*=//p' /opt/immich/.env)"
SRC_DIR="${INSTALL_DIR}/source"
APP_DIR="${INSTALL_DIR}/app"
PLUGIN_DIR="${APP_DIR}/corePlugin"
ML_DIR="${APP_DIR}/machine-learning"
GEO_DIR="${INSTALL_DIR}/geodata"
@@ -155,7 +145,9 @@ EOF
rm -rf "${APP_DIR:?}"/*
)
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v${RELEASE}" "$SRC_DIR"
rm -rf "$SRC_DIR"
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v${RELEASE}" "$SRC_DIR"
msg_info "Updating ${APP} web and microservices"
cd "$SRC_DIR"/server
@@ -188,18 +180,7 @@ EOF
$STD pnpm --filter @immich/cli --prod --no-optional deploy "$APP_DIR"/cli
cd "$APP_DIR"
mv "$INSTALL_DIR"/start.sh "$APP_DIR"/bin
# plugins
cd "$SRC_DIR"
$STD mise trust --ignore ./mise.toml
$STD mise trust ./plugins/mise.toml
cd plugins
$STD mise install
$STD mise run build
mkdir -p "$PLUGIN_DIR"
cp -r ./dist "$PLUGIN_DIR"/dist
cp ./manifest.json "$PLUGIN_DIR"
msg_ok "Updated ${APP} server, web, cli and plugins"
msg_ok "Updated ${APP} web and microservices"
cd "$SRC_DIR"/machine-learning
mkdir -p "$ML_DIR" && chown -R immich:immich "$ML_DIR"

View File

@@ -8,7 +8,7 @@ source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/m
APP="jotty"
var_tags="${var_tags:-tasks;notes}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-3072}"
var_ram="${var_ram:-4096}"
var_disk="${var_disk:-6}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"

View File

@@ -82,7 +82,7 @@ function update_script() {
cd /opt/karakeep/packages/db
$STD pnpm migrate
$STD pnpm store prune
sed -i "s/^SERVER_VERSION=.*$/SERVER_VERSION=${CHECK_UPDATE_RELEASE#v}/" /etc/karakeep/karakeep.env
sed -i "s/^SERVER_VERSION=.*$/SERVER_VERSION=${CHECK_UPDATE_RELEASE}/" /etc/karakeep/karakeep.env
msg_ok "Updated Karakeep"
msg_info "Starting Services"

View File

@@ -25,51 +25,14 @@ function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/kasm/current ]]; then
if [[ ! -d /var ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Checking for new version"
CURRENT_VERSION=$(readlink -f /opt/kasm/current | awk -F'/' '{print $4}')
KASM_URL=$(curl -fsSL "https://www.kasm.com/downloads" | tr '\n' ' ' | grep -oE 'https://kasm-static-content[^"]*kasm_release_[0-9]+\.[0-9]+\.[0-9]+\.[a-z0-9]+\.tar\.gz' | head -n 1)
if [[ -z "$KASM_URL" ]]; then
msg_error "Unable to detect latest Kasm release URL."
exit 1
fi
KASM_VERSION=$(echo "$KASM_URL" | sed -E 's/.*kasm_release_([0-9]+\.[0-9]+\.[0-9]+).*/\1/')
msg_info "Checked for new version"
msg_info "Removing outdated docker-compose plugin"
[ -f ~/.docker/cli-plugins/docker-compose ] && rm -rf ~/.docker/cli-plugins/docker-compose
msg_ok "Removed outdated docker-compose plugin"
if [[ -z "$CURRENT_VERSION" ]] || [[ "$KASM_VERSION" != "$CURRENT_VERSION" ]]; then
msg_info "Updating Kasm"
cd /tmp
msg_warn "WARNING: This script will run an external installer from a third-party source (https://www.kasmweb.com/)."
msg_warn "The following code is NOT maintained or audited by our repository."
msg_warn "If you have any doubts or concerns, please review the installer code before proceeding:"
msg_custom "${TAB3}${GATEWAY}${BGN}${CL}" "\e[1;34m" "→ upgrade.sh inside tar.gz $KASM_URL"
echo
read -r -p "${TAB3}Do you want to continue? [y/N]: " CONFIRM
if [[ ! "$CONFIRM" =~ ^([yY][eE][sS]|[yY])$ ]]; then
msg_error "Aborted by user. No changes have been made."
exit 10
fi
curl -fsSL -o "/tmp/kasm_release_${KASM_VERSION}.tar.gz" "$KASM_URL"
tar -xf "kasm_release_${KASM_VERSION}.tar.gz"
chmod +x /tmp/kasm_release/install.sh
rm -f /tmp/kasm_release_${KASM_VERSION}.tar.gz
bash /tmp/kasm_release/upgrade.sh --proxy-port 443
rm -rf /tmp/kasm_release
msg_ok "Updated Successfully"
else
msg_ok "No update required. Kasm is already at v${KASM_VERSION}"
fi
msg_info "Updating LXC"
$STD apt update
$STD apt -y upgrade
msg_ok "Updated LXC"
exit
}

View File

@@ -35,7 +35,7 @@ function update_script() {
msg_ok "Stopped services"
msg_info "Backing up configurations"
cp /opt/netvisor/.env /opt/netvisor.env.bak
cp /opt/netvisor/.env /opt/netvisor.env
msg_ok "Backed up configurations"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "netvisor" "mayanayza/netvisor" "tarball" "latest" "/opt/netvisor"
@@ -49,16 +49,10 @@ function update_script() {
TOOLCHAIN="$(grep "channel" /opt/netvisor/backend/rust-toolchain.toml | awk -F\" '{print $2}')"
RUST_TOOLCHAIN=$TOOLCHAIN setup_rust
cp /opt/netvisor.env.bak /opt/netvisor/.env
LOCAL_IP="$(hostname -I | awk '{print $1}')"
if ! grep -q "PUBLIC_URL" /opt/netvisor/.env; then
sed -i "\|_PATH=|a\NETVISOR_PUBLIC_URL=http://${LOCAL_IP}:60072" /opt/netvisor/.env
fi
sed -i 's|_TARGET=.*$|_URL=http://127.0.0.1:60072|' /opt/netvisor/.env
mv /opt/netvisor.env /opt/netvisor/.env
msg_info "Creating frontend UI"
export PUBLIC_SERVER_HOSTNAME=default
export PUBLIC_SERVER_PORT=""
export PUBLIC_SERVER_PORT=60072
cd /opt/netvisor/ui
$STD npm ci --no-fund --no-audit
$STD npm run build
@@ -70,16 +64,10 @@ function update_script() {
mv ./target/release/server /usr/bin/netvisor-server
msg_ok "Built Netvisor-server"
msg_info "Building Netvisor-daemon"
msg_info "Building Netvisor-daemon (amd64 version)"
$STD cargo build --release --bin daemon
cp ./target/release/daemon /usr/bin/netvisor-daemon
msg_ok "Built Netvisor-daemon"
sed -i -e 's|-target|-url|' \
-e 's| --server-port |:|' \
/etc/systemd/system/netvisor-daemon.service
sed -i '/^ \"server_target.*$/d' /root/.config/daemon/config.json
systemctl daemon-reload
msg_ok "Built Netvisor-daemon (amd64 version)"
msg_info "Starting services"
systemctl start netvisor-server netvisor-daemon

View File

@@ -49,13 +49,12 @@ function update_script() {
NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs
#RELEASE=$(curl -fsSL https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest |
#grep "tag_name" |
#awk '{print substr($2, 3, length($2)-4) }')
RELEASE=$(curl -fsSL https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest |
grep "tag_name" |
awk '{print substr($2, 3, length($2)-4) }')
fetch_and_deploy_gh_release "nginxproxymanager" "NginxProxyManager/nginx-proxy-manager"
RELEASE="2.13.4"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "nginxproxymanager" "NginxProxyManager/nginx-proxy-manager" "tarball" "v${RELEASE}" "/opt/nginxproxymanager"
msg_info "Stopping Services"
systemctl stop openresty
systemctl stop npm

View File

@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-3072}"
var_disk="${var_disk:-8}"
var_os="${var_os:-debian}"
var_version="${var_version:-12}"
var_version="${var_version:-13}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
@@ -32,11 +32,19 @@ function update_script() {
if lscpu | grep -q 'avx'; then
MONGO_VERSION="8.0" setup_mongodb
else
msg_error "No AVX detected (CPU-Flag)! We have discontinued support for this. You are welcome to try it manually with a Debian LXC, but due to the many issues with Omada, we currently only support AVX CPUs."
exit 10
msg_warn "No AVX detected: Using older MongoDB 4.4"
MONGO_VERSION="4.4" setup_mongodb
fi
JAVA_VERSION="21" setup_java
msg_info "Checking if right Azul Zulu Java is installed"
java_version=$(java -version 2>&1 | awk -F[\"_] '/version/ {print $2}')
if [[ "$java_version" =~ ^1\.8\.* ]]; then
$STD apt remove --purge -y zulu8-jdk
$STD apt -y install zulu21-jre-headless
msg_ok "Updated Azul Zulu Java to 21"
else
msg_ok "Azul Zulu Java 21 already installed"
fi
msg_info "Updating Omada Controller"
OMADA_URL=$(curl -fsSL "https://support.omadanetworks.com/en/download/software/omada-controller/" |

View File

@@ -23,8 +23,7 @@ function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /etc/apt/sources.list.d/plexmediaserver.list ]] \
&& [[ ! -f /etc/apt/sources.list.d/plexmediaserver.sources ]]; then
if [ ! -f /etc/apt/sources.list.d/plexmediaserver.list ]] && [[ ! -f /etc/apt/sources.list.d/plexmediaserver.sources ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi

100
frontend/bun.lock generated
View File

@@ -11,7 +11,6 @@
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-navigation-menu": "^1.2.5",
"@radix-ui/react-popover": "^1.1.6",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.1.6",
"@radix-ui/react-separator": "^1.1.2",
"@radix-ui/react-slot": "^1.1.2",
@@ -27,7 +26,7 @@
"date-fns": "^4.1.0",
"framer-motion": "^11.18.2",
"fuse.js": "^7.1.0",
"lucide-react": "^0.554.0",
"lucide-react": "^0.542.0",
"mini-svg-data-uri": "^1.4.4",
"motion": "^12.23.12",
"next": "15.5.2",
@@ -44,7 +43,6 @@
"react-icons": "^5.5.0",
"react-simple-typewriter": "^5.0.1",
"react-use-measure": "^2.1.7",
"recharts": "2.15.4",
"sharp": "^0.33.5",
"simple-icons": "^13.21.0",
"sonner": "^1.7.4",
@@ -419,8 +417,6 @@
"@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q=="],
"@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="],
"@radix-ui/react-select": ["@radix-ui/react-select@2.2.5", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA=="],
"@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="],
@@ -519,24 +515,6 @@
"@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="],
"@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="],
"@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="],
"@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="],
"@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="],
"@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="],
"@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="],
"@types/d3-shape": ["@types/d3-shape@3.1.7", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg=="],
"@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="],
"@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="],
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
@@ -787,28 +765,6 @@
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="],
"d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="],
"d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="],
"d3-format": ["d3-format@3.1.0", "", {}, "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA=="],
"d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="],
"d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="],
"d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="],
"d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="],
"d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="],
"d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="],
"d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="],
"damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="],
"data-urls": ["data-urls@5.0.0", "", { "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0" } }, "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg=="],
@@ -827,8 +783,6 @@
"decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="],
"decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="],
"decode-named-character-reference": ["decode-named-character-reference@1.2.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="],
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
@@ -853,8 +807,6 @@
"doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="],
"dom-helpers": ["dom-helpers@5.2.1", "", { "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA=="],
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
@@ -987,16 +939,12 @@
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
"eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="],
"exsolve": ["exsolve@1.0.7", "", {}, "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
"fast-equals": ["fast-equals@5.3.3", "", {}, "sha512-/boTcHZeIAQ2r/tL11voclBHDeP9WPxLt+tyAbVSyyXuUFyh0Tne7gJZTqGbxnvj79TjLdCXLOY7UIPhyG5MTw=="],
"fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="],
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
@@ -1111,8 +1059,6 @@
"internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="],
"internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
"is-alphabetical": ["is-alphabetical@1.0.4", "", {}, "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg=="],
"is-alphanumerical": ["is-alphanumerical@1.0.4", "", { "dependencies": { "is-alphabetical": "^1.0.0", "is-decimal": "^1.0.0" } }, "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A=="],
@@ -1245,7 +1191,7 @@
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"lucide-react": ["lucide-react@0.554.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-St+z29uthEJVx0Is7ellNkgTEhaeSoA42I7JjOCBCrc5X6LYMGSv0P/2uS5HDLTExP5tpiqRD2PyUEOS6s9UXA=="],
"lucide-react": ["lucide-react@0.542.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-w3hD8/SQB7+lzU2r4VdFyzzOzKnUjTZIF/MQJGSSvni7Llewni4vuViRppfRAa2guOsY5k4jZyxw/i9DQHv+dw=="],
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
@@ -1509,7 +1455,7 @@
"react-icons": ["react-icons@5.5.0", "", { "peerDependencies": { "react": "*" } }, "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw=="],
"react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
"react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
"react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
@@ -1519,24 +1465,16 @@
"react-simple-typewriter": ["react-simple-typewriter@5.0.1", "", { "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-vA5HkABwJKL/DJ4RshSlY/igdr+FiVY4MLsSQYJX6FZG/f1/VwN4y1i3mPXRyfaswrvI8xii1kOVe1dYtO2Row=="],
"react-smooth": ["react-smooth@4.0.4", "", { "dependencies": { "fast-equals": "^5.0.1", "prop-types": "^15.8.1", "react-transition-group": "^4.4.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q=="],
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
"react-syntax-highlighter": ["react-syntax-highlighter@15.6.1", "", { "dependencies": { "@babel/runtime": "^7.3.1", "highlight.js": "^10.4.1", "highlightjs-vue": "^1.0.0", "lowlight": "^1.17.0", "prismjs": "^1.27.0", "refractor": "^3.6.0" }, "peerDependencies": { "react": ">= 0.14.0" } }, "sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg=="],
"react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="],
"react-use-measure": ["react-use-measure@2.1.7", "", { "peerDependencies": { "react": ">=16.13", "react-dom": ">=16.13" } }, "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg=="],
"read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="],
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
"recharts": ["recharts@2.15.4", "", { "dependencies": { "clsx": "^2.0.0", "eventemitter3": "^4.0.1", "lodash": "^4.17.21", "react-is": "^18.3.1", "react-smooth": "^4.0.4", "recharts-scale": "^0.4.4", "tiny-invariant": "^1.3.1", "victory-vendor": "^36.6.8" }, "peerDependencies": { "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw=="],
"recharts-scale": ["recharts-scale@0.4.5", "", { "dependencies": { "decimal.js-light": "^2.4.1" } }, "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w=="],
"refa": ["refa@0.12.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.8.0" } }, "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g=="],
"reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="],
@@ -1687,8 +1625,6 @@
"thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="],
"tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="],
"tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="],
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
@@ -1757,8 +1693,6 @@
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
"victory-vendor": ["victory-vendor@36.9.2", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ=="],
"vite": ["vite@7.1.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx"], "bin": "bin/vite.js" }, "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ=="],
"vite-tsconfig-paths": ["vite-tsconfig-paths@5.1.4", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" } }, "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w=="],
@@ -1823,18 +1757,18 @@
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@eslint/config-array/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"@eslint/eslintrc/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"@eslint/eslintrc/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"@eslint/plugin-kit/@eslint/core": ["@eslint/core@0.15.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA=="],
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
"@radix-ui/react-scroll-area/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
"@radix-ui/react-scroll-area/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
"@types/hast/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
"@typescript-eslint/typescript-estree/fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
@@ -1863,18 +1797,24 @@
"eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"eslint-plugin-import/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"eslint-plugin-jsdoc/@es-joy/jsdoccomment": ["@es-joy/jsdoccomment@0.52.0", "", { "dependencies": { "@types/estree": "^1.0.8", "@typescript-eslint/types": "^8.34.1", "comment-parser": "1.4.1", "esquery": "^1.6.0", "jsdoc-type-pratt-parser": "~4.1.0" } }, "sha512-BXuN7BII+8AyNtn57euU2Yxo9yA/KUDNzrpXyi3pfqKmBhhysR6ZWOebFh3vyPoqA3/j1SOvGgucElMGwlXing=="],
"eslint-plugin-jsonc/synckit": ["synckit@0.11.8", "", { "dependencies": { "@pkgr/core": "^0.2.4" } }, "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A=="],
"eslint-plugin-jsx-a11y/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"eslint-plugin-n/globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="],
"eslint-plugin-n/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"eslint-plugin-n/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"eslint-plugin-react/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"eslint-plugin-react/resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="],
"eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
@@ -1911,8 +1851,6 @@
"path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"refractor/prismjs": ["prismjs@1.27.0", "", {}, "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA=="],
@@ -1935,6 +1873,8 @@
"tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": "lib/cli.js" }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="],
"w3c-xmlserializer/xml-name-validator": ["xml-name-validator@5.0.0", "", {}, "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg=="],
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
@@ -1943,14 +1883,24 @@
"yaml-eslint-parser/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@eslint/config-array/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"@eslint/eslintrc/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"@typescript-eslint/typescript-estree/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"eslint-plugin-import/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"eslint-plugin-jsonc/synckit/@pkgr/core": ["@pkgr/core@0.2.7", "", {}, "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg=="],
"eslint-plugin-jsx-a11y/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"eslint-plugin-n/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"eslint-plugin-react/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"eslint-plugin-unicorn/@eslint/plugin-kit/@eslint/core": ["@eslint/core@0.13.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw=="],
"glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],

4
frontend/package.json generated
View File

@@ -23,7 +23,6 @@
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-navigation-menu": "^1.2.5",
"@radix-ui/react-popover": "^1.1.6",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.1.6",
"@radix-ui/react-separator": "^1.1.2",
"@radix-ui/react-slot": "^1.1.2",
@@ -39,7 +38,7 @@
"date-fns": "^4.1.0",
"framer-motion": "^11.18.2",
"fuse.js": "^7.1.0",
"lucide-react": "^0.554.0",
"lucide-react": "^0.542.0",
"mini-svg-data-uri": "^1.4.4",
"motion": "^12.23.12",
"next": "15.5.2",
@@ -56,7 +55,6 @@
"react-icons": "^5.5.0",
"react-simple-typewriter": "^5.0.1",
"react-use-measure": "^2.1.7",
"recharts": "2.15.4",
"sharp": "^0.33.5",
"simple-icons": "^13.21.0",
"sonner": "^1.7.4",

View File

@@ -11,7 +11,7 @@
"privileged": false,
"interface_port": 8080,
"documentation": null,
"website": "https://filebrowser.org/index.html#features",
"website": "https://filebrowser.org/features",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/file-browser.webp",
"config_path": "",
"description": "File Browser offers a user-friendly web interface for managing files within a designated directory. It allows you to perform various actions such as uploading, deleting, previewing, renaming, and editing files.",

View File

@@ -23,7 +23,7 @@
"ram": 1024,
"hdd": 4,
"os": "debian",
"version": "12"
"version": "13"
}
}
],

View File

@@ -20,7 +20,7 @@
"script": "ct/jotty.sh",
"resources": {
"cpu": 2,
"ram": 3072,
"ram": 4096,
"hdd": 6,
"os": "debian",
"version": "13"

View File

@@ -6,7 +6,7 @@
],
"date_created": "2025-05-26",
"type": "ct",
"updateable": true,
"updateable": false,
"privileged": true,
"config_path": "",
"interface_port": 443,

View File

@@ -28,13 +28,8 @@
}
],
"default_credentials": {
"username": null,
"password": null
"username": "admin",
"password": "admin"
},
"notes": [
{
"text": "After installation, the admin user credentials are saved in the file ~/librenms.creds inside the container.",
"type": "info"
}
]
"notes": []
}

View File

@@ -35,10 +35,6 @@
{
"text": "The integrated daemon config is located at `/root/.config/daemon/config.json`",
"type": "info"
},
{
"text": "When using a reverse proxy, edit `/opt/netvisor/ui/build/_app/env.js`: add 443 to `PUBLIC_SERVER_PORT` and remove 'default' from `PUBLIC_SERVER_HOSTNAME`.",
"type": "info"
}
]
}

View File

@@ -23,7 +23,7 @@
"ram": 3072,
"hdd": 8,
"os": "debian",
"version": "12"
"version": "13"
}
}
],

View File

@@ -4,7 +4,7 @@
"categories": [
6
],
"date_created": "2025-11-17",
"date_created": "2025-09-04",
"type": "ct",
"updateable": true,
"privileged": false,
@@ -33,7 +33,7 @@
},
"notes": [
{
"text": "Type `cat ~/passbolt.creds` to see MariaDB database credentials. You will need those to setup Passbolt.",
"text": "Type `cat ~/.Passbolt.creds` to see MariaDB database credentials. You will need those to setup Passbolt.",
"type": "info"
},
{

View File

@@ -6,7 +6,7 @@
],
"date_created": "2025-08-26",
"type": "ct",
"updateable": false,
"updateable": true,
"privileged": false,
"interface_port": 8888,
"documentation": "https://docs.searxng.org/",

File diff suppressed because it is too large Load Diff

View File

@@ -1,67 +1,9 @@
"use client";
import {
ArrowUpDown,
Box,
CheckCircle2,
ChevronLeft,
ChevronRight,
List,
Loader2,
Trophy,
XCircle,
} from "lucide-react";
import {
Bar,
BarChart,
CartesianGrid,
Cell,
LabelList,
XAxis,
} from "recharts";
import React, { useEffect, useMemo, useState } from "react";
import React, { useEffect, useState } from "react";
import "react-datepicker/dist/react-datepicker.css";
import type { ChartConfig } from "@/components/ui/chart";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart";
import { formattedBadge } from "@/components/command-menu";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import ApplicationChart from "../../components/application-chart";
type DataModel = {
id: number;
@@ -88,76 +30,42 @@ type SummaryData = {
nsapp_count: Record<string, number>;
};
// Chart colors optimized for both light and dark modes
// Medium-toned colors that are visible and not too flashy in both themes
const CHART_COLORS = [
"#5B8DEF", // blue - medium tone
"#4ECDC4", // teal - medium tone
"#FF8C42", // orange - medium tone
"#A78BFA", // purple - medium tone
"#F472B6", // pink - medium tone
"#38BDF8", // cyan - medium tone
"#4ADE80", // green - medium tone
"#FBBF24", // yellow - medium tone
"#818CF8", // indigo - medium tone
"#FB7185", // rose - medium tone
"#2DD4BF", // turquoise - medium tone
"#C084FC", // violet - medium tone
"#60A5FA", // sky blue - medium tone
"#84CC16", // lime - medium tone
"#F59E0B", // amber - medium tone
"#A855F7", // purple - medium tone
"#10B981", // emerald - medium tone
"#EAB308", // gold - medium tone
"#3B82F6", // royal blue - medium tone
"#EF4444", // red - medium tone
];
const chartConfigApps = {
count: {
label: "Installations",
color: "hsl(var(--chart-1))",
},
} satisfies ChartConfig;
export default function DataPage() {
const DataFetcher: React.FC = () => {
const [data, setData] = useState<DataModel[]>([]);
const [summary, setSummary] = useState<SummaryData | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(25);
const [sortConfig, setSortConfig] = useState<{
key: string;
direction: "ascending" | "descending";
} | null>(null);
const [sortConfig, setSortConfig] = useState<{ key: string; direction: "ascending" | "descending" } | null>(null);
const nf = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
useEffect(() => {
const fetchData = async () => {
const fetchSummary = async () => {
try {
const response = await fetch("https://api.htl-braunau.at/data/summary");
if (!response.ok)
throw new Error(`Failed to fetch summary: ${response.statusText}`);
const result: SummaryData = await response.json();
setSummary(result);
}
catch (err) {
setError((err as Error).message);
}
};
fetchSummary();
}, []);
useEffect(() => {
const fetchPaginatedData = async () => {
setLoading(true);
try {
const [summaryRes, dataRes] = await Promise.all([
fetch("https://api.htl-braunau.at/data/summary"),
fetch(
`https://api.htl-braunau.at/data/paginated?page=${currentPage}&limit=${itemsPerPage === 0 ? "" : itemsPerPage
}`,
),
]);
if (!summaryRes.ok) {
throw new Error(`Failed to fetch summary: ${summaryRes.statusText}`);
}
if (!dataRes.ok) {
throw new Error(`Failed to fetch data: ${dataRes.statusText}`);
}
const summaryData: SummaryData = await summaryRes.json();
const pageData: DataModel[] = await dataRes.json();
setSummary(summaryData);
setData(pageData);
const response = await fetch(`https://api.htl-braunau.at/data/paginated?page=${currentPage}&limit=${itemsPerPage === 0 ? "" : itemsPerPage}`);
if (!response.ok)
throw new Error(`Failed to fetch data: ${response.statusText}`);
const result: DataModel[] = await response.json();
setData(result);
}
catch (err) {
setError((err as Error).message);
@@ -167,13 +75,13 @@ export default function DataPage() {
}
};
fetchData();
fetchPaginatedData();
}, [currentPage, itemsPerPage]);
const sortedData = useMemo(() => {
const sortedData = React.useMemo(() => {
if (!sortConfig)
return data;
return [...data].sort((a, b) => {
const sorted = [...data].sort((a, b) => {
if (a[sortConfig.key] < b[sortConfig.key]) {
return sortConfig.direction === "ascending" ? -1 : 1;
}
@@ -182,15 +90,23 @@ export default function DataPage() {
}
return 0;
});
return sorted;
}, [data, sortConfig]);
if (loading)
return <p>Loading...</p>;
if (error) {
return (
<p>
Error:
{error}
</p>
);
}
const requestSort = (key: string) => {
let direction: "ascending" | "descending" = "ascending";
if (
sortConfig
&& sortConfig.key === key
&& sortConfig.direction === "ascending"
) {
if (sortConfig && sortConfig.key === key && sortConfig.direction === "ascending") {
direction = "descending";
}
setSortConfig({ key, direction });
@@ -198,447 +114,135 @@ export default function DataPage() {
const formatDate = (dateString: string): string => {
const date = new Date(dateString);
return new Intl.DateTimeFormat("en-US", {
dateStyle: "medium",
timeStyle: "short",
}).format(date);
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const timezoneOffset = dateString.slice(-6);
return `${day}.${month}.${year} ${hours}:${minutes} ${timezoneOffset} GMT`;
};
const getTypeBadge = (type: string) => {
if (type === "lxc")
return formattedBadge("ct");
if (type === "vm")
return formattedBadge("vm");
return null;
};
// Stats calculations
const successCount = summary?.status_count.done ?? 0;
const failureCount = summary?.status_count.failed ?? 0;
const totalCount = summary?.total_entries ?? 0;
const successRate = totalCount > 0 ? (successCount / totalCount) * 100 : 0;
const allApps = useMemo(() => {
if (!summary?.nsapp_count)
return [];
return Object.entries(summary.nsapp_count).sort(([, a], [, b]) => b - a);
}, [summary]);
const topApps = useMemo(() => {
return allApps.slice(0, 15);
}, [allApps]);
const mostPopularApp = topApps[0];
// Chart Data
const appsChartData = topApps.map(([name, count], index) => ({
app: name,
count,
fill: CHART_COLORS[index % CHART_COLORS.length],
}));
if (error) {
return (
<div className="p-6 text-center text-red-500">
<p>
Error loading data:
{error}
</p>
</div>
);
}
return (
<div className="mb-3">
<div className="mt-20 flex sm:px-4 xl:px-0">
<div className="mx-4 w-full sm:mx-0 space-y-8">
{/* Header */}
<div>
<h1 className="text-3xl font-bold tracking-tight">Analytics</h1>
<p className="text-muted-foreground">
Overview of container installations and system statistics.
</p>
</div>
{/* Widgets */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Created</CardTitle>
<Box className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{nf.format(totalCount)}</div>
<p className="text-xs text-muted-foreground">
Total LXC/VM entries found
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Success Rate</CardTitle>
<CheckCircle2 className="h-4 w-4 text-green-500" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">
{successRate.toFixed(1)}
%
</div>
<p className="text-xs text-muted-foreground">
{nf.format(successCount)}
{" "}
successful installations
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Failures</CardTitle>
<XCircle className="h-4 w-4 text-red-500" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{nf.format(failureCount)}</div>
<p className="text-xs text-muted-foreground">
Installations encountered errors
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Most Popular</CardTitle>
<Trophy className="h-4 w-4 text-yellow-500" />
</CardHeader>
<CardContent>
<div className="truncate text-2xl font-bold">
{mostPopularApp ? mostPopularApp[0] : "N/A"}
</div>
<p className="text-xs text-muted-foreground">
{mostPopularApp ? nf.format(mostPopularApp[1]) : 0}
{" "}
installations
</p>
</CardContent>
</Card>
</div>
{/* Graphs */}
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<div className="space-y-1.5">
<CardTitle>Top Applications</CardTitle>
<CardDescription>
The most frequently installed applications.
</CardDescription>
</div>
<Dialog>
<DialogTrigger asChild>
<Button variant="outline" size="sm" className="ml-auto">
<List className="mr-2 h-4 w-4" />
View All
</Button>
</DialogTrigger>
<DialogContent className="max-h-[80vh] sm:max-w-md">
<DialogHeader>
<DialogTitle>Application Statistics</DialogTitle>
<DialogDescription>
Installation counts for all
{" "}
{allApps.length}
{" "}
applications.
</DialogDescription>
</DialogHeader>
<ScrollArea className="h-[60vh] w-full rounded-md border p-4">
<div className="space-y-4">
{allApps.map(([name, count], index) => (
<div
key={name}
className="flex items-center justify-between text-sm"
>
<div className="flex items-center gap-2">
<span className="w-8 font-mono text-muted-foreground">
{index + 1}
.
</span>
<span className="font-medium">{name}</span>
</div>
<span className="font-mono">{nf.format(count)}</span>
</div>
))}
</div>
</ScrollArea>
</DialogContent>
</Dialog>
</CardHeader>
<CardContent className="pl-2">
<div className="h-[300px] w-full">
{loading
? (
<div className="flex h-full w-full items-center justify-center">
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>
)
: (
<ChartContainer config={chartConfigApps} className="h-full w-full">
<BarChart
accessibilityLayer
data={appsChartData}
margin={{
top: 20,
}}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="app"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={value => (value.length > 8 ? `${value.slice(0, 8)}...` : value)}
/>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent nameKey="app" />}
/>
<Bar dataKey="count" radius={8}>
{appsChartData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.fill} />
))}
<LabelList
position="top"
offset={12}
className="fill-foreground"
fontSize={12}
/>
</Bar>
</BarChart>
</ChartContainer>
)}
</div>
</CardContent>
</Card>
{/* Data Table */}
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<div>
<CardTitle>Installation Log</CardTitle>
<CardDescription>
Detailed records of all container creation attempts.
</CardDescription>
</div>
<div className="flex items-center gap-2">
<Select
value={String(itemsPerPage)}
onValueChange={val => setItemsPerPage(Number(val))}
>
<SelectTrigger className="w-[80px]">
<SelectValue placeholder="Limit" />
</SelectTrigger>
<SelectContent>
<SelectItem value="10">10</SelectItem>
<SelectItem value="25">25</SelectItem>
<SelectItem value="50">50</SelectItem>
<SelectItem value="100">100</SelectItem>
</SelectContent>
</Select>
</div>
</CardHeader>
<CardContent>
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead
className="w-[100px] cursor-pointer"
onClick={() => requestSort("status")}
>
Status
{sortConfig?.key === "status" && (
<ArrowUpDown className="ml-2 inline h-4 w-4" />
)}
</TableHead>
<TableHead
className="cursor-pointer"
onClick={() => requestSort("type")}
>
Type
{sortConfig?.key === "type" && (
<ArrowUpDown className="ml-2 inline h-4 w-4" />
)}
</TableHead>
<TableHead
className="cursor-pointer"
onClick={() => requestSort("nsapp")}
>
Application
{sortConfig?.key === "nsapp" && (
<ArrowUpDown className="ml-2 inline h-4 w-4" />
)}
</TableHead>
<TableHead
className="hidden cursor-pointer md:table-cell"
onClick={() => requestSort("os_type")}
>
OS
{sortConfig?.key === "os_type" && (
<ArrowUpDown className="ml-2 inline h-4 w-4" />
)}
</TableHead>
<TableHead
className="hidden cursor-pointer md:table-cell"
onClick={() => requestSort("disk_size")}
>
Disk Size
{sortConfig?.key === "disk_size" && (
<ArrowUpDown className="ml-2 inline h-4 w-4" />
)}
</TableHead>
<TableHead
className="hidden cursor-pointer lg:table-cell"
onClick={() => requestSort("core_count")}
>
Core Count
{sortConfig?.key === "core_count" && (
<ArrowUpDown className="ml-2 inline h-4 w-4" />
)}
</TableHead>
<TableHead
className="hidden cursor-pointer lg:table-cell"
onClick={() => requestSort("ram_size")}
>
RAM Size
{sortConfig?.key === "ram_size" && (
<ArrowUpDown className="ml-2 inline h-4 w-4" />
)}
</TableHead>
<TableHead
className="cursor-pointer text-right"
onClick={() => requestSort("created_at")}
>
Created At
{sortConfig?.key === "created_at" && (
<ArrowUpDown className="ml-2 inline h-4 w-4" />
)}
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{loading
<div className="p-6 mt-20">
<h1 className="text-2xl font-bold mb-4 text-center">Created LXCs</h1>
<ApplicationChart data={summary} />
<p className="text-lg font-bold mt-4"> </p>
<div className="mb-4 flex justify-between items-center">
<p className="text-lg font-bold">
{nf.format(
summary?.total_entries ?? 0,
)}
{" "}
results found
</p>
<p className="text-lg font">
Status Legend: 🔄 installing
{" "}
{nf.format(summary?.status_count.installing ?? 0)}
{" "}
| completed
{" "}
{nf.format(summary?.status_count.done ?? 0)}
{" "}
| failed
{" "}
{nf.format(summary?.status_count.failed ?? 0)}
{" "}
| unknown
</p>
</div>
<div className="overflow-x-auto">
<div className="overflow-y-auto lg:overflow-y-visible">
<table className="min-w-full table-auto border-collapse">
<thead>
<tr>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("status")}>Status</th>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("type")}>Type</th>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("nsapp")}>Application</th>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("os_type")}>OS</th>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("os_version")}>OS Version</th>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("disk_size")}>Disk Size</th>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("core_count")}>Core Count</th>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("ram_size")}>RAM Size</th>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("method")}>Method</th>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("pve_version")}>PVE Version</th>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("error")}>Error Message</th>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("created_at")}>Created At</th>
</tr>
</thead>
<tbody>
{sortedData.map((item, index) => (
<tr key={index}>
<td className="px-4 py-2 border-b">
{item.status === "done"
? (
<TableRow>
<TableCell colSpan={8} className="h-24 text-center">
<div className="flex items-center justify-center gap-2">
<Loader2 className="h-4 w-4 animate-spin" />
{" "}
Loading data...
</div>
</TableCell>
</TableRow>
"✔️"
)
: sortedData.length > 0
: item.status === "failed"
? (
sortedData.map((item, idx) => (
<TableRow key={`${item.id}-${idx}`}>
<TableCell>
{item.status === "done"
? (
<Badge className="text-green-500/75 border-green-500/75">
Success
</Badge>
)
: item.status === "failed"
? (
<Badge className="text-red-500/75 border-red-500/75">
Failed
</Badge>
)
: item.status === "installing"
? (
<Badge className="text-blue-500/75 border-blue-500/75">
Installing
</Badge>
)
: (
<Badge variant="outline">
{item.status}
</Badge>
)}
</TableCell>
<TableCell>
{getTypeBadge(item.type) || (
<Badge variant="outline">
{item.type}
</Badge>
)}
</TableCell>
<TableCell className="font-medium">
{item.nsapp}
</TableCell>
<TableCell className="hidden md:table-cell">
{item.os_type}
{" "}
{item.os_version}
</TableCell>
<TableCell className="hidden md:table-cell">
{item.disk_size}
MB
</TableCell>
<TableCell className="hidden lg:table-cell">
{item.core_count}
</TableCell>
<TableCell className="hidden lg:table-cell">
{item.ram_size}
MB
</TableCell>
<TableCell className="text-right">
{formatDate(item.created_at)}
</TableCell>
</TableRow>
))
"❌"
)
: item.status === "installing"
? (
"🔄"
)
: (
item.status
)}
</td>
<td className="px-4 py-2 border-b">
{item.type === "lxc"
? (
"📦"
)
: item.type === "vm"
? (
"🖥️"
)
: (
<TableRow>
<TableCell colSpan={8} className="h-24 text-center">
No results found.
</TableCell>
</TableRow>
item.type
)}
</TableBody>
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
<Button
variant="outline"
size="sm"
onClick={() => setCurrentPage(prev => Math.max(prev - 1, 1))}
disabled={currentPage === 1 || loading}
>
<ChevronLeft className="mr-2 h-4 w-4" />
Previous
</Button>
<div className="text-sm text-muted-foreground">
Page
{" "}
{currentPage}
</div>
<Button
variant="outline"
size="sm"
onClick={() => setCurrentPage(prev => prev + 1)}
disabled={loading || sortedData.length < itemsPerPage}
>
Next
<ChevronRight className="ml-2 h-4 w-4" />
</Button>
</div>
</CardContent>
</Card>
</td>
<td className="px-4 py-2 border-b">{item.nsapp}</td>
<td className="px-4 py-2 border-b">{item.os_type}</td>
<td className="px-4 py-2 border-b">{item.os_version}</td>
<td className="px-4 py-2 border-b">{item.disk_size}</td>
<td className="px-4 py-2 border-b">{item.core_count}</td>
<td className="px-4 py-2 border-b">{item.ram_size}</td>
<td className="px-4 py-2 border-b">{item.method}</td>
<td className="px-4 py-2 border-b">{item.pve_version}</td>
<td className="px-4 py-2 border-b">{item.error}</td>
<td className="px-4 py-2 border-b">{formatDate(item.created_at)}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<div className="mt-4 flex justify-between items-center">
<button onClick={() => setCurrentPage(prev => Math.max(prev - 1, 1))} disabled={currentPage === 1} className="p-2 border">Previous</button>
<span>
Page
{currentPage}
</span>
<button onClick={() => setCurrentPage(prev => prev + 1)} className="p-2 border">Next</button>
<select
value={itemsPerPage}
onChange={e => setItemsPerPage(Number(e.target.value))}
className="p-2 border"
>
<option value={10}>10</option>
<option value={20}>20</option>
<option value={50}>50</option>
<option value={100}>100</option>
<option value={250}>250</option>
<option value={500}>500</option>
<option value={5000}>5000</option>
</select>
</div>
</div>
);
}
};
export default DataFetcher;

View File

@@ -0,0 +1,199 @@
"use client";
import { ArcElement, Chart as ChartJS, Tooltip as ChartTooltip, Legend } from "chart.js";
import ChartDataLabels from "chartjs-plugin-datalabels";
import { BarChart3, PieChart } from "lucide-react";
import React, { useState } from "react";
import { Pie } from "react-chartjs-2";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
ChartJS.register(ArcElement, ChartTooltip, Legend, ChartDataLabels);
type SummaryData = {
nsapp_count: Record<string, number>;
};
type ApplicationChartProps = {
data: SummaryData | null;
};
const ITEMS_PER_PAGE = 20;
const CHART_COLORS = [
"#ff6384",
"#36a2eb",
"#ffce56",
"#4bc0c0",
"#9966ff",
"#ff9f40",
"#4dc9f6",
"#f67019",
"#537bc4",
"#acc236",
"#166a8f",
"#00a950",
"#58595b",
"#8549ba",
];
export default function ApplicationChart({ data }: ApplicationChartProps) {
const [isChartOpen, setIsChartOpen] = useState(false);
const [isTableOpen, setIsTableOpen] = useState(false);
const [chartStartIndex, setChartStartIndex] = useState(0);
const [tableLimit, setTableLimit] = useState(ITEMS_PER_PAGE);
if (!data)
return null;
const sortedApps = Object.entries(data.nsapp_count)
.sort(([, a], [, b]) => b - a);
const chartApps = sortedApps.slice(
chartStartIndex,
chartStartIndex + ITEMS_PER_PAGE,
);
const chartData = {
labels: chartApps.map(([name]) => name),
datasets: [
{
data: chartApps.map(([, count]) => count),
backgroundColor: CHART_COLORS,
},
],
};
const chartOptions = {
plugins: {
legend: { display: false },
datalabels: {
color: "white",
font: { weight: "bold" as const },
formatter: (value: number, context: any) => {
const label = context.chart.data.labels?.[context.dataIndex];
return `${label}\n(${value})`;
},
},
},
responsive: true,
maintainAspectRatio: false,
};
return (
<div className="mt-6 flex justify-center gap-4">
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
size="icon"
onClick={() => setIsChartOpen(true)}
>
<PieChart className="h-5 w-5" />
</Button>
</TooltipTrigger>
<TooltipContent>Open Chart View</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
size="icon"
onClick={() => setIsTableOpen(true)}
>
<BarChart3 className="h-5 w-5" />
</Button>
</TooltipTrigger>
<TooltipContent>Open Table View</TooltipContent>
</Tooltip>
</TooltipProvider>
<Dialog open={isChartOpen} onOpenChange={setIsChartOpen}>
<DialogContent className="max-w-3xl">
<DialogHeader>
<DialogTitle>Applications Distribution</DialogTitle>
</DialogHeader>
<div className="h-[60vh] w-full">
<Pie data={chartData} options={chartOptions} />
</div>
<div className="flex justify-center gap-4">
<Button
variant="outline"
onClick={() => setChartStartIndex(Math.max(0, chartStartIndex - ITEMS_PER_PAGE))}
disabled={chartStartIndex === 0}
>
Previous
{" "}
{ITEMS_PER_PAGE}
</Button>
<Button
variant="outline"
onClick={() => setChartStartIndex(chartStartIndex + ITEMS_PER_PAGE)}
disabled={chartStartIndex + ITEMS_PER_PAGE >= sortedApps.length}
>
Next
{" "}
{ITEMS_PER_PAGE}
</Button>
</div>
</DialogContent>
</Dialog>
<Dialog open={isTableOpen} onOpenChange={setIsTableOpen}>
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle>Applications Count</DialogTitle>
</DialogHeader>
<div className="max-h-[60vh] overflow-y-auto">
<Table>
<TableHeader>
<TableRow>
<TableHead>Application</TableHead>
<TableHead className="text-right">Count</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{sortedApps.slice(0, tableLimit).map(([name, count]) => (
<TableRow key={name}>
<TableCell>{name}</TableCell>
<TableCell className="text-right">{count}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
{tableLimit < sortedApps.length && (
<Button
variant="outline"
className="w-full"
onClick={() => setTableLimit(prev => prev + ITEMS_PER_PAGE)}
>
Load More
</Button>
)}
</DialogContent>
</Dialog>
</div>
);
}

View File

@@ -1,369 +0,0 @@
"use client"
import * as React from "react"
import * as RechartsPrimitive from "recharts"
import { cn } from "@/lib/utils"
// Format: { THEME_NAME: CSS_SELECTOR }
const THEMES = { light: "", dark: ".dark" } as const
export type ChartConfig = {
[k in string]: {
label?: React.ReactNode
icon?: React.ComponentType
} & (
| { color?: string; theme?: never }
| { color?: never; theme: Record<keyof typeof THEMES, string> }
)
}
type ChartContextProps = {
config: ChartConfig
}
const ChartContext = React.createContext<ChartContextProps | null>(null)
function useChart() {
const context = React.useContext(ChartContext)
if (!context) {
throw new Error("useChart must be used within a <ChartContainer />")
}
return context
}
const ChartContainer = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & {
config: ChartConfig
children: React.ComponentProps<
typeof RechartsPrimitive.ResponsiveContainer
>["children"]
}
>(({ id, className, children, config, ...props }, ref) => {
const uniqueId = React.useId()
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
return (
<ChartContext.Provider value={{ config }}>
<div
data-chart={chartId}
ref={ref}
className={cn(
"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
className
)}
{...props}
>
<ChartStyle id={chartId} config={config} />
<RechartsPrimitive.ResponsiveContainer>
{children}
</RechartsPrimitive.ResponsiveContainer>
</div>
</ChartContext.Provider>
)
})
ChartContainer.displayName = "Chart"
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
const colorConfig = Object.entries(config).filter(
([, config]) => config.theme || config.color
)
if (!colorConfig.length) {
return null
}
return (
<style
dangerouslySetInnerHTML={{
__html: Object.entries(THEMES)
.map(
([theme, prefix]) => `
${prefix} [data-chart=${id}] {
${colorConfig
.map(([key, itemConfig]) => {
const color =
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
itemConfig.color
return color ? ` --color-${key}: ${color};` : null
})
.join("\n")}
}
`
)
.join("\n"),
}}
/>
)
}
const ChartTooltip = RechartsPrimitive.Tooltip
const ChartTooltipContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
React.ComponentProps<"div"> & {
hideLabel?: boolean
hideIndicator?: boolean
indicator?: "line" | "dot" | "dashed"
nameKey?: string
labelKey?: string
}
>(
(
{
active,
payload,
className,
indicator = "dot",
hideLabel = false,
hideIndicator = false,
label,
labelFormatter,
labelClassName,
formatter,
color,
nameKey,
labelKey,
},
ref
) => {
const { config } = useChart()
const tooltipLabel = React.useMemo(() => {
if (hideLabel || !payload?.length) {
return null
}
const [item] = payload
const key = `${labelKey || item?.dataKey || item?.name || "value"}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
const value =
!labelKey && typeof label === "string"
? config[label as keyof typeof config]?.label || label
: itemConfig?.label
if (labelFormatter) {
return (
<div className={cn("font-medium", labelClassName)}>
{labelFormatter(value, payload)}
</div>
)
}
if (!value) {
return null
}
return <div className={cn("font-medium", labelClassName)}>{value}</div>
}, [
label,
labelFormatter,
payload,
hideLabel,
labelClassName,
config,
labelKey,
])
if (!active || !payload?.length) {
return null
}
const nestLabel = payload.length === 1 && indicator !== "dot"
return (
<div
ref={ref}
className={cn(
"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
className
)}
>
{!nestLabel ? tooltipLabel : null}
<div className="grid gap-1.5">
{payload
.filter((item) => item.type !== "none")
.map((item, index) => {
const key = `${nameKey || item.name || item.dataKey || "value"}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
const indicatorColor = color || item.payload.fill || item.color
return (
<div
key={item.dataKey}
className={cn(
"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
indicator === "dot" && "items-center"
)}
>
{formatter && item?.value !== undefined && item.name ? (
formatter(item.value, item.name, item, index, item.payload)
) : (
<>
{itemConfig?.icon ? (
<itemConfig.icon />
) : (
!hideIndicator && (
<div
className={cn(
"shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
{
"h-2.5 w-2.5": indicator === "dot",
"w-1": indicator === "line",
"w-0 border-[1.5px] border-dashed bg-transparent":
indicator === "dashed",
"my-0.5": nestLabel && indicator === "dashed",
}
)}
style={
{
"--color-bg": indicatorColor,
"--color-border": indicatorColor,
} as React.CSSProperties
}
/>
)
)}
<div
className={cn(
"flex flex-1 justify-between leading-none",
nestLabel ? "items-end" : "items-center"
)}
>
<div className="grid gap-1.5">
{nestLabel ? tooltipLabel : null}
<span className="text-muted-foreground">
{itemConfig?.label || item.name}
</span>
</div>
{item.value && (
<span className="font-mono font-medium tabular-nums text-foreground">
{item.value.toLocaleString()}
</span>
)}
</div>
</>
)}
</div>
)
})}
</div>
</div>
)
}
)
ChartTooltipContent.displayName = "ChartTooltip"
const ChartLegend = RechartsPrimitive.Legend
const ChartLegendContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> &
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
hideIcon?: boolean
nameKey?: string
}
>(
(
{ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
ref
) => {
const { config } = useChart()
if (!payload?.length) {
return null
}
return (
<div
ref={ref}
className={cn(
"flex items-center justify-center gap-4",
verticalAlign === "top" ? "pb-3" : "pt-3",
className
)}
>
{payload
.filter((item) => item.type !== "none")
.map((item) => {
const key = `${nameKey || item.dataKey || "value"}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
return (
<div
key={item.value}
className={cn(
"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
)}
>
{itemConfig?.icon && !hideIcon ? (
<itemConfig.icon />
) : (
<div
className="h-2 w-2 shrink-0 rounded-[2px]"
style={{
backgroundColor: item.color,
}}
/>
)}
{itemConfig?.label}
</div>
)
})}
</div>
)
}
)
ChartLegendContent.displayName = "ChartLegend"
// Helper to extract item config from a payload.
function getPayloadConfigFromPayload(
config: ChartConfig,
payload: unknown,
key: string
) {
if (typeof payload !== "object" || payload === null) {
return undefined
}
const payloadPayload =
"payload" in payload &&
typeof payload.payload === "object" &&
payload.payload !== null
? payload.payload
: undefined
let configLabelKey: string = key
if (
key in payload &&
typeof payload[key as keyof typeof payload] === "string"
) {
configLabelKey = payload[key as keyof typeof payload] as string
} else if (
payloadPayload &&
key in payloadPayload &&
typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
) {
configLabelKey = payloadPayload[
key as keyof typeof payloadPayload
] as string
}
return configLabelKey in config
? config[configLabelKey]
: config[key as keyof typeof config]
}
export {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
ChartLegend,
ChartLegendContent,
ChartStyle,
}

View File

@@ -1,48 +0,0 @@
"use client"
import * as React from "react"
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
import { cn } from "@/lib/utils"
const ScrollArea = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<ScrollAreaPrimitive.Root
ref={ref}
className={cn("relative overflow-hidden", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
))
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
const ScrollBar = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
>(({ className, orientation = "vertical", ...props }, ref) => (
<ScrollAreaPrimitive.ScrollAreaScrollbar
ref={ref}
orientation={orientation}
className={cn(
"flex touch-none select-none transition-colors",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent p-[1px]",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
className
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
</ScrollAreaPrimitive.ScrollAreaScrollbar>
))
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
export { ScrollArea, ScrollBar }

View File

@@ -97,4 +97,9 @@ msg_ok "Configured Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -89,4 +89,9 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -41,4 +41,9 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -146,4 +146,9 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -30,7 +30,6 @@ curl -fsSL "$RELEASE" -o $(basename "$RELEASE")
$STD unzip Agent_Linux64*.zip
chmod +x ./Agent
echo $RELEASE >~/.agentdvr
rm -rf Agent_Linux64*.zip
msg_ok "Installed AgentDVR"
msg_info "Creating Service"
@@ -54,4 +53,10 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
rm -rf Agent_Linux64*.zip
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -34,4 +34,8 @@ msg_ok "Installed Apache Cassandra"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -36,4 +36,8 @@ msg_ok "Installed Apache CouchDB."
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -71,8 +71,6 @@ mv ~/mysql-connector-j-9.3.0/mysql-connector-j-9.3.0.jar /etc/guacamole/lib/
curl -fsSL "https://downloads.apache.org/guacamole/${RELEASE_SERVER}/binary/guacamole-auth-jdbc-${RELEASE_SERVER}.tar.gz" -o "/root/guacamole-auth-jdbc-${RELEASE_SERVER}.tar.gz"
$STD tar -xf ~/guacamole-auth-jdbc-$RELEASE_SERVER.tar.gz
mv ~/guacamole-auth-jdbc-$RELEASE_SERVER/mysql/guacamole-auth-jdbc-mysql-$RELEASE_SERVER.jar /etc/guacamole/extensions/
rm -rf ~/mysql-connector-j-9.3.0{,.tar.gz}
rm -rf ~/guacamole-auth-jdbc-$RELEASE_SERVER{,.tar.gz}
msg_ok "Setup Apache Guacamole"
msg_info "Setup Database"
@@ -148,4 +146,10 @@ msg_ok "Setup Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
rm -rf ~/mysql-connector-j-9.3.0{,.tar.gz}
rm -rf ~/guacamole-auth-jdbc-$RELEASE_SERVER{,.tar.gz}
$STD apt -y autoremove
$STD apt -y autoclean
msg_ok "Cleaned"

View File

@@ -69,4 +69,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -119,7 +119,7 @@ curl -fsSL "$TOMCAT_URL" -o "/tmp/tomcat.tar.gz"
mkdir -p /opt/tomcat-$TOMCAT_VERSION
tar --strip-components=1 -xzf /tmp/tomcat.tar.gz -C /opt/tomcat-$TOMCAT_VERSION
chown -R root:root /opt/tomcat-$TOMCAT_VERSION
rm -f /tmp/tomcat.tar.gz
cat <<EOF >/etc/systemd/system/tomcat.service
[Unit]
Description=Apache Tomcat Web Application Container
@@ -147,4 +147,9 @@ msg_ok "Tomcat $LATEST_VERSION installed and started"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
rm -f /tmp/tomcat.tar.gz
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -16,7 +16,7 @@ update_os
msg_info "Installing Apt-Cacher NG"
DEBIAN_FRONTEND=noninteractive $STD apt-get -o Dpkg::Options::="--force-confold" install -y apt-cacher-ng
sed -i 's/# PassThroughPattern: .* # this would allow CONNECT to everything/PassThroughPattern: .*/' /etc/apt-cacher-ng/acng.conf
cat <<EOF >/etc/apt/apt.conf.d/00aptproxy.conf
cat << EOF >/etc/apt/apt.conf.d/00aptproxy.conf
Acquire::http::Proxy "http://localhost:3142";
EOF
systemctl enable -q --now apt-cacher-ng
@@ -24,4 +24,8 @@ msg_ok "Installed Apt-Cacher NG"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -91,4 +91,9 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -82,4 +82,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -24,7 +24,6 @@ if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
systemctl disable -q --now nginx
curl -fsSL "$(curl -fsSL https://api.github.com/repos/mayswind/ariang/releases/latest | grep download | grep AllInOne.zip | cut -d\" -f4)" -o $(basename "$(curl -fsSL https://api.github.com/repos/mayswind/ariang/releases/latest | grep download | grep AllInOne.zip | cut -d\" -f4)")
$STD unzip AriaNg-*-AllInOne.zip -d /var/www
rm AriaNg-*-AllInOne.zip
rm /etc/nginx/sites-enabled/*
cat <<EOF >/etc/nginx/conf.d/ariang.conf
server {
@@ -85,4 +84,9 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
rm AriaNg-*-AllInOne.zip
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -88,7 +88,6 @@ curl -fsSL "$DOWNLOAD_URL" -o "$temp_file"
mkdir -p /opt/asterisk
tar zxf "$temp_file" --strip-components=1 -C /opt/asterisk
cd /opt/asterisk
rm -f "$temp_file"
msg_ok "Downloaded Asterisk ($RELEASE)"
msg_info "Installing Asterisk"
@@ -106,5 +105,10 @@ msg_ok "Installed Asterisk"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
rm -f "$temp_file"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -28,4 +28,8 @@ msg_ok "Setup audiobookshelf"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -66,4 +66,8 @@ msg_ok "Authelia Setup completed"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -46,4 +46,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -15,34 +15,34 @@ update_os
msg_info "Installing dependencies"
$STD apt-get install -y --no-install-recommends \
python3-dev \
sqlite3 \
build-essential \
libldap2-dev \
libssl-dev \
libsasl2-dev \
imagemagick \
ghostscript \
libmagic1 \
libxi6 \
libxslt1.1 \
libxtst6 \
libxrandr2 \
libxkbfile1 \
libxcomposite1 \
libopengl0 \
libnss3 \
libxkbcommon0 \
libegl1 \
libxdamage1 \
libgl1 \
libglx-mesa0 \
xz-utils \
xdg-utils \
inotify-tools \
binutils \
unrar-free \
zip
python3-dev \
sqlite3 \
build-essential \
libldap2-dev \
libssl-dev \
libsasl2-dev \
imagemagick \
ghostscript \
libmagic1 \
libxi6 \
libxslt1.1 \
libxtst6 \
libxrandr2 \
libxkbfile1 \
libxcomposite1 \
libopengl0 \
libnss3 \
libxkbcommon0 \
libegl1 \
libxdamage1 \
libgl1 \
libglx-mesa0 \
xz-utils \
xdg-utils \
inotify-tools \
binutils \
unrar-free \
zip
msg_ok "Installed dependencies"
fetch_and_deploy_gh_release "kepubify" "pgaskin/kepubify" "singlefile" "latest" "/usr/bin" "kepubify-linux-64bit"
@@ -323,4 +323,8 @@ msg_ok "Created scripts and service files"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -97,4 +97,8 @@ msg_ok "Configured NGINX"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -20,7 +20,6 @@ mkdir -p /opt/backrest/{bin,config,data}
curl -fsSL "https://github.com/garethgeorge/backrest/releases/download/v${RELEASE}/backrest_Linux_x86_64.tar.gz" -o "$temp_file"
tar xzf $temp_file -C /opt/backrest/bin
chmod +x /opt/backrest/bin/backrest
rm -f "$temp_file"
echo "${RELEASE}" >/opt/${APPLICATION}_version.txt
msg_ok "Installed Backrest"
@@ -47,5 +46,9 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
rm -f "$temp_file"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -25,10 +25,10 @@ DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13)
$STD sudo -u postgres psql -c "CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';"
$STD sudo -u postgres psql -c "CREATE DATABASE $DB_NAME WITH OWNER $DB_USER TEMPLATE template0;"
{
echo "Baikal Credentials"
echo "Baikal Database User: $DB_USER"
echo "Baikal Database Password: $DB_PASS"
echo "Baikal Database Name: $DB_NAME"
echo "Baikal Credentials"
echo "Baikal Database User: $DB_USER"
echo "Baikal Database Password: $DB_PASS"
echo "Baikal Database Name: $DB_NAME"
} >>~/baikal.creds
msg_ok "Set up PostgreSQL Database"
@@ -81,4 +81,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -17,10 +17,10 @@ update_os
msg_info "Installing Dependencies"
$STD apt-get install -y \
redis-server \
nginx \
lsb-release \
libvips
redis-server \
nginx \
lsb-release \
libvips
#php-{ffi,opcache,redis,zip,pdo-sqlite,bcmath,pdo,curl,dom,fpm}
msg_ok "Installed Dependencies"
@@ -41,14 +41,14 @@ msg_info "Configure MeiliSearch"
curl -fsSL https://raw.githubusercontent.com/meilisearch/meilisearch/latest/config.toml -o /etc/meilisearch.toml
MASTER_KEY=$(openssl rand -base64 12)
sed -i \
-e 's|^env =.*|env = "production"|' \
-e "s|^# master_key =.*|master_key = \"$MASTER_KEY\"|" \
-e 's|^db_path =.*|db_path = "/var/lib/meilisearch/data"|' \
-e 's|^dump_dir =.*|dump_dir = "/var/lib/meilisearch/dumps"|' \
-e 's|^snapshot_dir =.*|snapshot_dir = "/var/lib/meilisearch/snapshots"|' \
-e 's|^# no_analytics = true|no_analytics = true|' \
-e 's|^http_addr =.*|http_addr = "127.0.0.1:7700"|' \
/etc/meilisearch.toml
-e 's|^env =.*|env = "production"|' \
-e "s|^# master_key =.*|master_key = \"$MASTER_KEY\"|" \
-e 's|^db_path =.*|db_path = "/var/lib/meilisearch/data"|' \
-e 's|^dump_dir =.*|dump_dir = "/var/lib/meilisearch/dumps"|' \
-e 's|^snapshot_dir =.*|snapshot_dir = "/var/lib/meilisearch/snapshots"|' \
-e 's|^# no_analytics = true|no_analytics = true|' \
-e 's|^http_addr =.*|http_addr = "127.0.0.1:7700"|' \
/etc/meilisearch.toml
msg_ok "Configured MeiliSearch"
msg_info "Creating MeiliSearch service"
@@ -77,11 +77,11 @@ MeiliSearch_API_KEY=$(curl -s -X GET 'http://127.0.0.1:7700/keys' -H "Authorizat
MeiliSearch_API_KEY_UID=$(curl -s -X GET 'http://127.0.0.1:7700/keys' -H "Authorization: Bearer $MASTER_KEY" | grep -o '"uid":"[^"]*"' | head -n 1 | sed 's/"uid":"//;s/"//')
LOCAL_IP=$(hostname -I | awk '{print $1}')
sed -i -e "s|^APP_URL=|APP_URL=http://${LOCAL_IP}/bar/|" \
-e "s|^MEILISEARCH_HOST=|MEILISEARCH_HOST=http://127.0.0.1:7700|" \
-e "s|^MEILISEARCH_KEY=|MEILISEARCH_KEY=${MASTER_KEY}|" \
-e "s|^MEILISEARCH_API_KEY=|MEILISEARCH_API_KEY=${MeiliSearch_API_KEY}|" \
-e "s|^MEILISEARCH_API_KEY_UID=|MEILISEARCH_API_KEY_UID=${MeiliSearch_API_KEY_UID}|" \
/opt/bar-assistant/.env
-e "s|^MEILISEARCH_HOST=|MEILISEARCH_HOST=http://127.0.0.1:7700|" \
-e "s|^MEILISEARCH_KEY=|MEILISEARCH_KEY=${MASTER_KEY}|" \
-e "s|^MEILISEARCH_API_KEY=|MEILISEARCH_API_KEY=${MeiliSearch_API_KEY}|" \
-e "s|^MEILISEARCH_API_KEY_UID=|MEILISEARCH_API_KEY_UID=${MeiliSearch_API_KEY_UID}|" \
/opt/bar-assistant/.env
$STD composer install --no-interaction
$STD php artisan key:generate
touch storage/bar-assistant/database.ba3.sqlite
@@ -190,4 +190,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -49,4 +49,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -45,4 +45,9 @@ msg_ok "Created & started service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -39,4 +39,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -69,4 +69,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -80,4 +80,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -106,4 +106,8 @@ msg_ok "Created BookLore Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -105,4 +105,8 @@ msg_ok "Created Services"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get autoremove
$STD apt-get autoclean
msg_ok "Cleaned"

View File

@@ -44,4 +44,8 @@ msg_ok "Installed BunkerWeb v${RELEASE}"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -66,4 +66,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -43,4 +43,8 @@ fi
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -32,4 +32,8 @@ msg_ok "Installed CasaOS"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -141,4 +141,8 @@ msg_ok "Created Services"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -51,4 +51,8 @@ msg_ok "Installed Channels DVR Server"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -17,7 +17,6 @@ msg_info "Install Checkmk"
RELEASE=$(curl -fsSL https://api.github.com/repos/checkmk/checkmk/tags | grep "name" | awk '{print substr($2, 3, length($2)-4) }' | tr ' ' '\n' | grep -Ev 'rc|b' | sort -V | tail -n 1)
curl -fsSL "https://download.checkmk.com/checkmk/${RELEASE}/check-mk-raw-${RELEASE}_0.bookworm_amd64.deb" -o "/opt/checkmk.deb"
$STD apt-get install -y /opt/checkmk.deb
rm -rf /opt/checkmk.deb
echo "${RELEASE}" >"/opt/checkmk_version.txt"
msg_ok "Installed Checkmk"
@@ -41,4 +40,8 @@ $STD omd start "$SITE_NAME"
msg_ok "Created Service"
cleanup_lxc
msg_info "Cleaning up"
rm -rf /opt/checkmk.deb
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -39,4 +39,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -79,4 +79,8 @@ msg_ok "Setup Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -64,4 +64,9 @@ fi
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -36,4 +36,8 @@ msg_ok "Service Setup"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -60,4 +60,8 @@ fi
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
msg_ok "Cleaned"

View File

@@ -19,14 +19,11 @@ echo "${TAB3}[1]-None [2]-NVIDIA [3]-AMD [4]-Intel"
read -rp "${TAB3}Enter your choice [1-4] (default: 1): " gpu_choice
gpu_choice=${gpu_choice:-1}
case "$gpu_choice" in
1) comfyui_gpu_type="none" ;;
2) comfyui_gpu_type="nvidia" ;;
3) comfyui_gpu_type="amd" ;;
4) comfyui_gpu_type="intel" ;;
*)
comfyui_gpu_type="none"
echo "${TAB3}Invalid choice. Defaulting to ${comfyui_gpu_type}."
;;
1) comfyui_gpu_type="none";;
2) comfyui_gpu_type="nvidia";;
3) comfyui_gpu_type="amd";;
4) comfyui_gpu_type="intel";;
*) comfyui_gpu_type="none"; echo "${TAB3}Invalid choice. Defaulting to ${comfyui_gpu_type}." ;;
esac
echo
@@ -38,25 +35,25 @@ msg_info "Python dependencies"
$STD uv venv "/opt/ComfyUI/venv"
if [[ "${comfyui_gpu_type,,}" == "nvidia" ]]; then
$STD uv pip install \
torch \
torchvision \
torchaudio \
--extra-index-url "https://download.pytorch.org/whl/cu128" \
--python="/opt/ComfyUI/venv/bin/python"
torch \
torchvision \
torchaudio \
--extra-index-url "https://download.pytorch.org/whl/cu128" \
--python="/opt/ComfyUI/venv/bin/python"
elif [[ "${comfyui_gpu_type,,}" == "amd" ]]; then
$STD uv pip install \
torch \
torchvision \
torchaudio \
--index-url "https://download.pytorch.org/whl/rocm6.3" \
--python="/opt/ComfyUI/venv/bin/python"
torch \
torchvision \
torchaudio \
--index-url "https://download.pytorch.org/whl/rocm6.3" \
--python="/opt/ComfyUI/venv/bin/python"
elif [[ "${comfyui_gpu_type,,}" == "intel" ]]; then
$STD uv pip install \
torch \
torchvision \
torchaudio \
--index-url "https://download.pytorch.org/whl/xpu" \
--python="/opt/ComfyUI/venv/bin/python"
torch \
torchvision \
torchaudio \
--index-url "https://download.pytorch.org/whl/xpu" \
--python="/opt/ComfyUI/venv/bin/python"
fi
$STD uv pip install -r "/opt/ComfyUI/requirements.txt" --python="/opt/ComfyUI/venv/bin/python"
msg_ok "Python dependencies"
@@ -82,4 +79,9 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -39,4 +39,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -61,4 +61,9 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -75,4 +75,8 @@ msg_ok "Service Created"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -44,7 +44,6 @@ LATEST_RELEASE_NO_V=${LATEST_RELEASE#v}
mv /opt/cosmos/cosmos-cloud-${LATEST_RELEASE_NO_V}/* /opt/cosmos/
rmdir /opt/cosmos/cosmos-cloud-${LATEST_RELEASE_NO_V}
chmod +x /opt/cosmos/cosmos
rm -f "/opt/cosmos/cosmos-cloud-${LATEST_RELEASE#v}-amd64.zip"
msg_ok "Installed Cosmos"
msg_info "Creating Service"
@@ -74,4 +73,9 @@ msg_info "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
rm -f "/opt/cosmos/cosmos-cloud-${LATEST_RELEASE#v}-amd64.zip"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -87,4 +87,9 @@ msg_ok "Crafty-Controller service started"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
rm -rf /opt/crafty-4-v${RELEASE}.zip
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -28,4 +28,8 @@ msg_ok "Configured Cronicle Primary Server"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -39,4 +39,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -61,4 +61,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -20,9 +20,13 @@ msg_ok "Installed Dependencies"
msg_info "Installing Daemon Sync Server"
curl -fsSL "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/daemonsync_2.2.0.0059_amd64.deb" -o "daemonsync_2.2.0.0059_amd64.deb"
$STD dpkg -i daemonsync_2.2.0.0059_amd64.deb
rm -rf daemonsync_2.2.0.0059_amd64.deb
msg_ok "Installed Daemon Sync Server"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
rm -rf daemonsync_2.2.0.0059_amd64.deb
$STD apt-get autoremove >/dev/null
$STD apt-get autoclean >/dev/null
msg_ok "Cleaned"

View File

@@ -15,4 +15,10 @@ update_os
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -25,7 +25,6 @@ curl -fsSL "http://security.ubuntu.com/ubuntu/pool/main/o/openssl/$libssl" -o "$
$STD dpkg -i "$libssl"
$STD apt-get update
$STD apt-get install -y deconz
rm -rf "$libssl"
msg_ok "Installed deConz"
msg_info "Creating Service"
@@ -50,4 +49,9 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
rm -rf "$libssl"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -67,4 +67,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -15,14 +15,14 @@ update_os
msg_info "Installing Dependencies"
$STD apt install -y \
build-essential \
python3-dev \
libpq-dev \
nginx \
redis-server \
ffmpeg \
procps \
streamlink
build-essential \
python3-dev \
libpq-dev \
nginx \
redis-server \
ffmpeg \
procps \
streamlink
msg_ok "Installed Dependencies"
setup_uv
@@ -39,11 +39,11 @@ $STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET client_encoding TO 'utf8'
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET default_transaction_isolation TO 'read committed';"
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC';"
{
echo "Dispatcharr Credentials"
echo "Database Name: $DB_NAME"
echo "Database User: $DB_USER"
echo "Database Password: $DB_PASS"
echo ""
echo "Dispatcharr Credentials"
echo "Database Name: $DB_NAME"
echo "Database User: $DB_USER"
echo "Database Password: $DB_PASS"
echo ""
} >>~/dispatcharr.creds
msg_ok "Created PostgreSQL Database"
@@ -58,9 +58,9 @@ msg_ok "Installed Python Dependencies"
msg_info "Configuring Dispatcharr"
install -d -m 755 \
/data/{logos,recordings,plugins,db} \
/data/uploads/{m3us,epgs} \
/data/{m3us,epgs}
/data/{logos,recordings,plugins,db} \
/data/uploads/{m3us,epgs} \
/data/{m3us,epgs}
chown -R root:root /data
export DATABASE_URL="postgresql://${DB_USER}:${DB_PASS}@localhost:5432/${DB_NAME}"
export POSTGRES_DB=$DB_NAME
@@ -260,4 +260,9 @@ msg_ok "Created Services"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -69,15 +69,15 @@ fi
read -r -p "${TAB3}Expose Docker TCP socket (insecure) ? [n = No, l = Local only (127.0.0.1), a = All interfaces (0.0.0.0)] <n/l/a>: " socket_choice
case "${socket_choice,,}" in
l)
socket="tcp://127.0.0.1:2375"
;;
a)
socket="tcp://0.0.0.0:2375"
;;
*)
socket=""
;;
l)
socket="tcp://127.0.0.1:2375"
;;
a)
socket="tcp://0.0.0.0:2375"
;;
*)
socket=""
;;
esac
if [[ -n "$socket" ]]; then
@@ -85,10 +85,10 @@ if [[ -n "$socket" ]]; then
$STD apt-get install -y jq
tmpfile=$(mktemp)
jq --arg sock "$socket" '. + { "hosts": ["unix:///var/run/docker.sock", $sock] }' /etc/docker/daemon.json >"$tmpfile" && mv "$tmpfile" /etc/docker/daemon.json
jq --arg sock "$socket" '. + { "hosts": ["unix:///var/run/docker.sock", $sock] }' /etc/docker/daemon.json > "$tmpfile" && mv "$tmpfile" /etc/docker/daemon.json
mkdir -p /etc/systemd/system/docker.service.d
cat <<EOF >/etc/systemd/system/docker.service.d/override.conf
cat <<EOF > /etc/systemd/system/docker.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
@@ -107,4 +107,8 @@ fi
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -73,4 +73,8 @@ fi
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -78,4 +78,9 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -71,11 +71,7 @@ export TURBO_CACHE=1
export NEXT_TELEMETRY_DISABLED=1
export CYPRESS_INSTALL_BINARY=0
export NODE_OPTIONS="--max-old-space-size=4096"
$STD turbo prune --scope=@documenso/remix --docker
cd out
cp -r json/* .
$STD npm ci
cp -r full/* .
$STD turbo run build --filter=@documenso/remix
$STD npm run prisma:migrate-deploy
echo "${RELEASE}" >"/opt/${APPLICATION}_version.txt"
@@ -103,9 +99,13 @@ EnvironmentFile=/opt/documenso/.env
WantedBy=multi-user.target
EOF
systemctl enable -q --now documenso
$STD turbo daemon stop
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD turbo daemon stop
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -38,10 +38,14 @@ curl -fsSL "https://netcologne.dl.sourceforge.net/project/dolibarr/Dolibarr%20in
echo "dolibarr dolibarr/reconfigure-webserver multiselect apache2" | debconf-set-selections
$STD apt-get install ./$FILE -y
$STD apt install -f
rm -rf ~/$FILE
echo "${RELEASE}" >"/opt/${APPLICATION}_version.txt"
msg_ok "Setup Dolibarr"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
rm -rf ~/$FILE
$STD apt-get autoremove
$STD apt-get autoclean
msg_ok "Cleaned"

View File

@@ -33,7 +33,7 @@ MARIADB_DB_NAME="domain_monitor" MARIADB_DB_USER="domainmonitor" setup_mariadb_d
fetch_and_deploy_gh_release "domain-monitor" "Hosteroid/domain-monitor" "prebuild" "latest" "/opt/domain-monitor" "domain-monitor-v*.zip"
msg_info "Setting up Domain Monitor"
ENC_KEY=$(openssl rand -base64 32 | tr -d '\n')
ENC_KEY=$(openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c 32)
cd /opt/domain-monitor
$STD composer install
cp env.example.txt .env

View File

@@ -45,4 +45,10 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"

View File

@@ -105,4 +105,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -49,4 +49,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -83,4 +83,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -36,4 +36,8 @@ msg_ok "Configured Emby"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -34,7 +34,6 @@ msg_ok "Downloaded EMQX"
msg_info "Installing EMQX"
$STD apt-get install -y "$DEB_FILE"
rm -f "$DEB_FILE"
echo "$LATEST_VERSION" >~/.emqx
msg_ok "Installed EMQX"
@@ -44,5 +43,9 @@ msg_ok "Enabled EMQX service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
rm -f "$DEB_FILE"
$STD apt-get autoremove
$STD apt-get autoclean
msg_ok "Cleaned"

View File

@@ -78,4 +78,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -55,4 +55,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -45,4 +45,8 @@ msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

Some files were not shown because too many files have changed in this diff Show More