Compare commits

..

25 Commits

Author SHA1 Message Date
CanbiZ
a6e53dea01 Remove redundant cleanup steps from update scripts
Eliminated unnecessary 'Cleaning up' messages and duplicate cleanup commands from multiple service update scripts. Cleanup actions (such as removing backup files and temporary artifacts) are now performed directly without extra messaging, streamlining the update process and reducing log verbosity.
2025-11-22 14:35:05 +01:00
CanbiZ
e4b2e051bf fixes bug in setup_php 2025-11-22 13:23:40 +01:00
CanbiZ
e05a351712 Update tools.func 2025-11-22 13:20:18 +01:00
CanbiZ
053e5ab128 Merge branch 'main' of https://github.com/community-scripts/ProxmoxVE 2025-11-22 13:13:25 +01:00
CanbiZ
1f6a141341 Refactor PHP setup for stricter version enforcement
Reworks the PHP installation logic to always remove conflicting PHP versions before pinning and repository setup, ensuring only the desired version is present. Simplifies module installation by letting apt-get handle missing modules and improves error handling for individual package installations. Removes pre-checks and warnings for unavailable modules, streamlining the process and reducing complexity.
2025-11-22 13:08:30 +01:00
community-scripts-pr-app[bot]
b47d4747d6 Update versions.json (#9352)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-22 13:04:34 +01:00
CanbiZ
27bd55364c Improve PHP setup: enforce version pinning and cleanup
Enhances the PHP setup function to enforce APT pinning for PHP versions during updates and installations, ensuring correct version selection. Adds logic to remove conflicting PHP versions, improves module availability checks, and provides clearer messaging for installed and missing modules.
2025-11-22 13:02:53 +01:00
CanbiZ
8ad68e7c97 core: improve setup_php robustness and version validation
Enhances the setup_php function to enforce explicit PHP version pinning during installation, adds checks for available versions and missing modules, and improves error handling. The script now verifies the installed PHP version matches the requested version and provides fallback installation logic if version-constrained installs fail.
2025-11-22 12:52:47 +01:00
community-scripts-pr-app[bot]
088186712a Update CHANGELOG.md (#9348)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-22 08:10:53 +00:00
Bram
6dd0195912 Refactor /data page (#9343) 2025-11-22 09:10:29 +01:00
community-scripts-pr-app[bot]
afa385d225 Update CHANGELOG.md (#9345)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-22 00:12:30 +00:00
community-scripts-pr-app[bot]
f43efc1431 Update versions.json (#9344)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-22 01:12:09 +01:00
community-scripts-pr-app[bot]
06d8e5354a Update CHANGELOG.md (#9338)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-21 14:34:47 +00:00
community-scripts-pr-app[bot]
60fc5573aa Update CHANGELOG.md (#9337)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-21 14:34:11 +00:00
CanbiZ
29ee6cdff3 plex: prevent [] syntax issue (#9318) 2025-11-21 15:34:04 +01:00
community-scripts-pr-app[bot]
bda9286043 Update CHANGELOG.md (#9336)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-21 14:33:50 +00:00
Tobias
4389a43670 fix: karakeep strip "v" from release version (#9324)
* fix: karakeep strip "v" from release version

* fix: strip v from release for karakeep version

* Fix MODULE_VERSION and SERVER_VERSION formatting

* formatting
2025-11-21 15:33:44 +01:00
Chris
43877a8b17 NetVisor: fix grep in update (#9334) 2025-11-21 15:33:24 +01:00
CanbiZ
ff6cb3b87e Fix rustup update to avoid interactive prompts
Redirects stdin from /dev/null when running 'rustup update' to prevent any interactive prompts that may block automated scripts.
2025-11-21 15:22:01 +01:00
community-scripts-pr-app[bot]
4b0fb547e9 Update CHANGELOG.md (#9333)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-21 13:33:37 +00:00
Chris
e2c6020c64 pin correct version (#9332) 2025-11-21 14:33:09 +01:00
community-scripts-pr-app[bot]
33f4482012 Update versions.json (#9330)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-21 13:05:51 +01:00
community-scripts-pr-app[bot]
9b375bccab Update CHANGELOG.md (#9327)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-21 07:54:10 +00:00
CanbiZ
3f2f29d352 Refactor IPv6 disable logic and add 'disable' option (#9326)
Replaces previous IPv6 disabling method with a dedicated 'disable' option, storing sysctl settings in /etc/sysctl.d/99-disable-ipv6.conf. Updates build and install scripts to clarify the difference between 'none' (no assignment) and 'disable' (fully disables IPv6), adds user warnings, and disables IPv6 listeners in nginx if present.
2025-11-21 08:53:46 +01:00
しぐれ
636b0d3afd fix: update website URL in filebrowser.json (#9322) 2025-11-21 07:25:12 +01:00
74 changed files with 1571 additions and 1025 deletions

View File

@@ -10,8 +10,29 @@
> [!CAUTION] > [!CAUTION]
Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit the project's popularity for potentially malicious purposes. 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 ## 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 ## 2025-11-20
### 🚀 Updated Scripts ### 🚀 Updated Scripts

View File

@@ -57,15 +57,6 @@ function update_script() {
$STD composer install --no-dev --prefer-dist $STD composer install --no-dev --prefer-dist
php artisan 2fauth:install php artisan 2fauth:install
$STD systemctl restart nginx $STD systemctl restart nginx
msg_info "Cleaning Up"
if dpkg -l | grep -q 'php8.2'; then
$STD apt remove --purge -y php8.2*
fi
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -62,6 +62,7 @@ function update_script() {
cd /opt/adventurelog/frontend || exit cd /opt/adventurelog/frontend || exit
$STD pnpm i $STD pnpm i
$STD pnpm build $STD pnpm build
rm -rf /opt/adventurelog-backup
msg_ok "Updated ${APP}" msg_ok "Updated ${APP}"
msg_info "Starting Services" msg_info "Starting Services"
@@ -69,10 +70,6 @@ function update_script() {
systemctl start adventurelog-backend systemctl start adventurelog-backend
systemctl start adventurelog-frontend systemctl start adventurelog-frontend
msg_ok "Services Started" msg_ok "Services Started"
msg_info "Cleaning Up"
rm -rf /opt/adventurelog-backup
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -38,15 +38,13 @@ function update_script() {
curl -fsSL -o tika-server-standard-${RELEASE}.jar "https://dlcdn.apache.org/tika/${RELEASE}/tika-server-standard-${RELEASE}.jar" curl -fsSL -o tika-server-standard-${RELEASE}.jar "https://dlcdn.apache.org/tika/${RELEASE}/tika-server-standard-${RELEASE}.jar"
mv --force tika-server-standard.jar tika-server-standard-prev-version.jar mv --force tika-server-standard.jar tika-server-standard-prev-version.jar
mv tika-server-standard-${RELEASE}.jar tika-server-standard.jar mv tika-server-standard-${RELEASE}.jar tika-server-standard.jar
rm -rf /opt/apache-tika/tika-server-standard-prev-version.jar
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated ${APP} to v${RELEASE}" msg_ok "Updated ${APP} to v${RELEASE}"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start apache-tika systemctl start apache-tika
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning Up"
rm -rf /opt/apache-tika/tika-server-standard-prev-version.jar
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at v${RELEASE}" msg_ok "No update required. ${APP} is already at v${RELEASE}"

View File

@@ -31,15 +31,11 @@ function update_script() {
fi fi
if check_for_gh_release "authelia" "authelia/authelia"; then if check_for_gh_release "authelia" "authelia/authelia"; then
$STD apt-get update $STD apt update
$STD apt-get -y upgrade $STD apt -y upgrade
fetch_and_deploy_gh_release "authelia" "authelia/authelia" "binary" fetch_and_deploy_gh_release "authelia" "authelia/authelia" "binary"
msg_info "Cleaning Up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -39,16 +39,13 @@ function update_script() {
curl -fsSL "https://github.com/garethgeorge/backrest/releases/download/v${RELEASE}/backrest_Linux_x86_64.tar.gz" -o "$temp_file" 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 tar xzf $temp_file -C /opt/backrest/bin
chmod +x /opt/backrest/bin/backrest chmod +x /opt/backrest/bin/backrest
rm -f "$temp_file"
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated ${APP} to ${RELEASE}" msg_ok "Updated ${APP} to ${RELEASE}"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start backrest systemctl start backrest
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -f "$temp_file"
msg_ok "Cleaned up"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at ${RELEASE}" msg_ok "No update required. ${APP} is already at ${RELEASE}"

View File

@@ -47,15 +47,12 @@ function update_script() {
chmod -R 755 /opt/baikal/ chmod -R 755 /opt/baikal/
cd /opt/baikal cd /opt/baikal
$STD composer install $STD composer install
rm -rf /opt/baikal-backup
msg_ok "Configured Baikal" msg_ok "Configured Baikal"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start apache2 systemctl start apache2
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -rf /opt/baikal-backup
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -54,15 +54,12 @@ function update_script() {
$STD php artisan route:cache $STD php artisan route:cache
$STD php artisan event:cache $STD php artisan event:cache
chown -R www-data:www-data /opt/bar-assistant chown -R www-data:www-data /opt/bar-assistant
rm -rf /opt/bar-assistant-backup
msg_ok "Updated Bar-Assistant" msg_ok "Updated Bar-Assistant"
msg_info "Starting nginx" msg_info "Starting nginx"
systemctl start nginx systemctl start nginx
msg_ok "Started nginx" msg_ok "Started nginx"
msg_info "Cleaning up"
rm -rf /opt/bar-assistant-backup
msg_ok "Cleaned"
fi fi
if check_for_gh_release "vue-salt-rim" "karlomikus/vue-salt-rim"; then if check_for_gh_release "vue-salt-rim" "karlomikus/vue-salt-rim"; then
@@ -81,15 +78,12 @@ function update_script() {
cd /opt/vue-salt-rim cd /opt/vue-salt-rim
$STD npm install $STD npm install
$STD npm run build $STD npm run build
rm -rf /opt/vue-salt-rim-backup
msg_ok "Updated Vue Salt Rim" msg_ok "Updated Vue Salt Rim"
msg_info "Starting nginx" msg_info "Starting nginx"
systemctl start nginx systemctl start nginx
msg_ok "Started nginx" msg_ok "Started nginx"
msg_info "Cleaning up"
rm -rf /opt/vue-salt-rim-backup
msg_ok "Cleaned"
fi fi
if check_for_gh_release "meilisearch" "meilisearch/meilisearch"; then if check_for_gh_release "meilisearch" "meilisearch/meilisearch"; then

View File

@@ -57,15 +57,12 @@ function update_script() {
chmod -R 755 /opt/bookstack /opt/bookstack/bootstrap/cache /opt/bookstack/public/uploads /opt/bookstack/storage chmod -R 755 /opt/bookstack /opt/bookstack/bootstrap/cache /opt/bookstack/public/uploads /opt/bookstack/storage
chmod -R 775 /opt/bookstack/storage /opt/bookstack/bootstrap/cache /opt/bookstack/public/uploads chmod -R 775 /opt/bookstack/storage /opt/bookstack/bootstrap/cache /opt/bookstack/public/uploads
chmod -R 640 /opt/bookstack/.env chmod -R 640 /opt/bookstack/.env
rm -rf /opt/bookstack-backup
msg_ok "Configured BookStack" msg_ok "Configured BookStack"
msg_info "Starting Apache2" msg_info "Starting Apache2"
systemctl start apache2 systemctl start apache2
msg_ok "Started Apache2" msg_ok "Started Apache2"
msg_info "Cleaning Up"
rm -rf /opt/bookstack-backup
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -109,6 +109,7 @@ function update_script() {
fi fi
$STD uv run python manage.py migrate --noinput $STD uv run python manage.py migrate --noinput
$STD uv run python manage.py collectstatic --noinput $STD uv run python manage.py collectstatic --noinput
rm -f /tmp/dispatcharr_db_*.sql
msg_ok "Migrations Complete" msg_ok "Migrations Complete"
msg_info "Starting Services" msg_info "Starting Services"
@@ -117,10 +118,6 @@ function update_script() {
systemctl start dispatcharr-celerybeat systemctl start dispatcharr-celerybeat
systemctl start dispatcharr-daphne systemctl start dispatcharr-daphne
msg_ok "Started Services" msg_ok "Started Services"
msg_info "Cleaning up"
rm -f /tmp/dispatcharr_db_*.sql
msg_ok "Cleanup completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -76,11 +76,6 @@ function update_script() {
portainer/agent portainer/agent
msg_ok "Updated Portainer Agent" msg_ok "Updated Portainer Agent"
fi fi
msg_info "Cleaning up"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleanup complete"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
exit exit
} }

View File

@@ -50,16 +50,13 @@ function update_script() {
$STD turbo run build --filter=@documenso/remix $STD turbo run build --filter=@documenso/remix
$STD npm run prisma:migrate-deploy $STD npm run prisma:migrate-deploy
$STD turbo daemon stop $STD turbo daemon stop
rm -rf /opt/v${RELEASE}.zip
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated ${APP}" msg_ok "Updated ${APP}"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start documenso systemctl start documenso
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning Up"
rm -rf /opt/v${RELEASE}.zip
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at ${RELEASE}" msg_ok "No update required. ${APP} is already at ${RELEASE}"

View File

@@ -47,16 +47,13 @@ function update_script() {
msg_info "Installing EMQX" msg_info "Installing EMQX"
$STD apt-get install -y "$DEB_FILE" $STD apt-get install -y "$DEB_FILE"
rm -f "$DEB_FILE"
echo "$RELEASE" >~/.emqx
msg_ok "Installed EMQX v${RELEASE}" msg_ok "Installed EMQX v${RELEASE}"
msg_info "Starting EMQX" msg_info "Starting EMQX"
systemctl start emqx systemctl start emqx
echo "$RELEASE" >~/.emqx
msg_ok "Started EMQX" msg_ok "Started EMQX"
msg_info "Cleaning Up"
rm -f "$DEB_FILE"
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. EMQX is already at v${RELEASE}" msg_ok "No update required. EMQX is already at v${RELEASE}"

View File

@@ -48,16 +48,13 @@ function update_script() {
temp_file=$(mktemp) temp_file=$(mktemp)
curl -fsSL https://fileflows.com/downloads/zip -o "$temp_file" curl -fsSL https://fileflows.com/downloads/zip -o "$temp_file"
$STD unzip -o -d /opt/fileflows "$temp_file" $STD unzip -o -d /opt/fileflows "$temp_file"
rm -rf "$temp_file"
rm -rf "$backup_filename"
msg_ok "Updated $APP to latest version" msg_ok "Updated $APP to latest version"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start fileflows systemctl start fileflows
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning Up"
rm -rf "$temp_file"
rm -rf "$backup_filename"
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at latest version" msg_ok "No update required. ${APP} is already at latest version"

View File

@@ -56,10 +56,6 @@ function update_script() {
msg_info "Starting Service" msg_info "Starting Service"
systemctl start ghostfolio systemctl start ghostfolio
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning Up"
$STD npm cache clean --force
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -20,62 +20,57 @@ color
catch_errors catch_errors
function update_script() { function update_script() {
header_info header_info
check_container_storage check_container_storage
check_container_resources check_container_resources
if [[ ! -d /opt/jellyseerr ]]; then if [[ ! -d /opt/jellyseerr ]]; then
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
if [ "$(node -v | cut -c2-3)" -ne 22 ]; then if [ "$(node -v | cut -c2-3)" -ne 22 ]; then
msg_info "Updating Node.js Repository" msg_info "Updating Node.js Repository"
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" >/etc/apt/sources.list.d/nodesource.list echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" >/etc/apt/sources.list.d/nodesource.list
msg_ok "Updating Node.js Repository" msg_ok "Updating Node.js Repository"
msg_info "Updating Packages" msg_info "Updating Packages"
$STD apt-get update $STD apt-get update
$STD apt-get -y upgrade $STD apt-get -y upgrade
msg_ok "Updating Packages" msg_ok "Updating Packages"
fi
msg_info "Cleaning up" cd /opt/jellyseerr
apt-get -y autoremove output=$(git pull --no-rebase)
apt-get -y autoclean
msg_ok "Cleaning up"
fi
cd /opt/jellyseerr pnpm_current=$(pnpm --version 2>/dev/null)
output=$(git pull --no-rebase) pnpm_desired=$(grep -Po '"pnpm":\s*"\K[^"]+' /opt/jellyseerr/package.json)
pnpm_current=$(pnpm --version 2>/dev/null) if [ -z "$pnpm_current" ]; then
pnpm_desired=$(grep -Po '"pnpm":\s*"\K[^"]+' /opt/jellyseerr/package.json) msg_error "pnpm not found. Installing version $pnpm_desired..."
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
elif ! node -e "const semver = require('semver'); process.exit(semver.satisfies('$pnpm_current', '$pnpm_desired') ? 0 : 1)"; then
msg_error "Updating pnpm from version $pnpm_current to $pnpm_desired..."
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
else
msg_ok "pnpm is already installed and satisfies version $pnpm_desired."
fi
if [ -z "$pnpm_current" ]; then msg_info "Updating $APP"
msg_error "pnpm not found. Installing version $pnpm_desired..." if echo "$output" | grep -q "Already up to date."; then
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs msg_ok "$APP is already up to date."
elif ! node -e "const semver = require('semver'); process.exit(semver.satisfies('$pnpm_current', '$pnpm_desired') ? 0 : 1)"; then exit
msg_error "Updating pnpm from version $pnpm_current to $pnpm_desired..." fi
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
else
msg_ok "pnpm is already installed and satisfies version $pnpm_desired."
fi
msg_info "Updating $APP" systemctl stop jellyseerr
if echo "$output" | grep -q "Already up to date."; then rm -rf dist .next node_modules
msg_ok "$APP is already up to date." export CYPRESS_INSTALL_BINARY=0
exit cd /opt/jellyseerr
fi $STD pnpm install --frozen-lockfile
export NODE_OPTIONS="--max-old-space-size=3072"
$STD pnpm build
systemctl stop jellyseerr cat <<EOF >/etc/systemd/system/jellyseerr.service
rm -rf dist .next node_modules
export CYPRESS_INSTALL_BINARY=0
cd /opt/jellyseerr
$STD pnpm install --frozen-lockfile
export NODE_OPTIONS="--max-old-space-size=3072"
$STD pnpm build
cat <<EOF >/etc/systemd/system/jellyseerr.service
[Unit] [Unit]
Description=jellyseerr Service Description=jellyseerr Service
After=network.target After=network.target
@@ -91,10 +86,10 @@ ExecStart=/usr/bin/node dist/index.js
WantedBy=multi-user.target WantedBy=multi-user.target
EOF EOF
systemctl daemon-reload systemctl daemon-reload
systemctl start jellyseerr systemctl start jellyseerr
msg_ok "Updated $APP" msg_ok "Updated $APP"
exit exit
} }
start start

View File

@@ -49,15 +49,12 @@ function update_script() {
cp -a keycloak.old/conf/. keycloak/conf/ cp -a keycloak.old/conf/. keycloak/conf/
cp -a keycloak.old/providers/. keycloak/providers/ 2>/dev/null || true cp -a keycloak.old/providers/. keycloak/providers/ 2>/dev/null || true
cp -a keycloak.old/themes/. keycloak/themes/ 2>/dev/null || true cp -a keycloak.old/themes/. keycloak/themes/ 2>/dev/null || true
rm -rf keycloak.old
msg_ok "Updated Keycloak" msg_ok "Updated Keycloak"
msg_info "Restarting Service" msg_info "Restarting Service"
systemctl restart keycloak systemctl restart keycloak
msg_ok "Restarted Service" msg_ok "Restarted Service"
msg_info "Cleaning up"
rm -rf keycloak.old
msg_ok "Cleanup complete"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -50,15 +50,12 @@ function update_script() {
$STD yarn install $STD yarn install
$STD yarn build $STD yarn build
chown -R www-data:www-data /opt/koillection/public/uploads chown -R www-data:www-data /opt/koillection/public/uploads
rm -r /opt/koillection-backup
msg_ok "Updated Koillection" msg_ok "Updated Koillection"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start apache2 systemctl start apache2
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -r /opt/koillection-backup
msg_ok "Cleaned"
msg_ok "Updated Successfully!" msg_ok "Updated Successfully!"
fi fi
exit exit

View File

@@ -52,17 +52,14 @@ function update_script() {
$STD yarn web:build $STD yarn web:build
$STD yarn prisma:deploy $STD yarn prisma:deploy
[ -d /opt/data.bak ] && mv /opt/data.bak /opt/linkwarden/data [ -d /opt/data.bak ] && mv /opt/data.bak /opt/linkwarden/data
rm -rf ~/.cargo/registry ~/.cargo/git ~/.cargo/.package-cache ~/.rustup
rm -rf /root/.cache/yarn
rm -rf /opt/linkwarden/.next/cache
msg_ok "Updated ${APP}" msg_ok "Updated ${APP}"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start linkwarden systemctl start linkwarden
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -rf ~/.cargo/registry ~/.cargo/git ~/.cargo/.package-cache ~/.rustup
rm -rf /root/.cache/yarn
rm -rf /opt/linkwarden/.next/cache
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -42,15 +42,12 @@ function update_script() {
mv /opt/listmonk-backup/config.toml /opt/listmonk/config.toml mv /opt/listmonk-backup/config.toml /opt/listmonk/config.toml
mv /opt/listmonk-backup/uploads /opt/listmonk/uploads mv /opt/listmonk-backup/uploads /opt/listmonk/uploads
$STD /opt/listmonk/listmonk --upgrade --yes --config /opt/listmonk/config.toml $STD /opt/listmonk/listmonk --upgrade --yes --config /opt/listmonk/config.toml
rm -rf /opt/listmonk-backup/
msg_ok "Configured listmonk" msg_ok "Configured listmonk"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start listmonk systemctl start listmonk
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -rf /opt/listmonk-backup/
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -53,15 +53,12 @@ function update_script() {
msg_info "Configuring LubeLogger" msg_info "Configuring LubeLogger"
chmod 700 /opt/lubelogger/CarCareTracker chmod 700 /opt/lubelogger/CarCareTracker
cp -rf /tmp/lubeloggerData/* /opt/lubelogger/ cp -rf /tmp/lubeloggerData/* /opt/lubelogger/
rm -rf /tmp/lubeloggerData
msg_ok "Configured LubeLogger" msg_ok "Configured LubeLogger"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start lubelogger systemctl start lubelogger
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -rf /tmp/lubeloggerData
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -38,15 +38,9 @@ function update_script() {
curl -fsSL -o "$DEB_FILE" "$DEB_URL" curl -fsSL -o "$DEB_FILE" "$DEB_URL"
$STD apt install "$DEB_FILE" -y $STD apt install "$DEB_FILE" -y
systemctl restart lyrion systemctl restart lyrion
$STD rm -f "$DEB_FILE"
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated $APP to ${RELEASE}" msg_ok "Updated $APP to ${RELEASE}"
msg_info "Cleaning up"
$STD rm -f "$DEB_FILE"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "$APP is already up to date (${RELEASE})" msg_ok "$APP is already up to date (${RELEASE})"

View File

@@ -55,17 +55,13 @@ function update_script() {
mv /usr/local/bin/minio /usr/local/bin/minio_bak mv /usr/local/bin/minio /usr/local/bin/minio_bak
curl -fsSL "https://dl.min.io/server/minio/release/linux-amd64/minio" -o /usr/local/bin/minio curl -fsSL "https://dl.min.io/server/minio/release/linux-amd64/minio" -o /usr/local/bin/minio
chmod +x /usr/local/bin/minio chmod +x /usr/local/bin/minio
rm -f /usr/local/bin/minio_bak
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated ${APP}" msg_ok "Updated ${APP}"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start minio systemctl start minio
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -f /usr/local/bin/minio_bak
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at ${RELEASE}" msg_ok "No update required. ${APP} is already at ${RELEASE}"

View File

@@ -52,15 +52,12 @@ function update_script() {
$STD php artisan monica:update --force $STD php artisan monica:update --force
chown -R www-data:www-data /opt/monica chown -R www-data:www-data /opt/monica
chmod -R 775 /opt/monica/storage chmod -R 775 /opt/monica/storage
rm -r /opt/monica-backup
msg_ok "Configured monica" msg_ok "Configured monica"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start apache2 systemctl start apache2
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -r /opt/monica-backup
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -57,17 +57,14 @@ function update_script() {
fi fi
$STD /opt/netbox/upgrade.sh $STD /opt/netbox/upgrade.sh
rm -r "/opt/v${RELEASE}.zip"
rm -r /opt/netbox-backup
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated $APP to v${RELEASE}" msg_ok "Updated $APP to v${RELEASE}"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start netbox netbox-rq systemctl start netbox netbox-rq
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -r "/opt/v${RELEASE}.zip"
rm -r /opt/netbox-backup
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at v${RELEASE}" msg_ok "No update required. ${APP} is already at v${RELEASE}"

View File

@@ -51,7 +51,7 @@ function update_script() {
cp /opt/netvisor.env.bak /opt/netvisor/.env cp /opt/netvisor.env.bak /opt/netvisor/.env
LOCAL_IP="$(hostname -I | awk '{print $1}')" LOCAL_IP="$(hostname -I | awk '{print $1}')"
if ! grep -q "PUBLIC_URL"; then if ! grep -q "PUBLIC_URL" /opt/netvisor/.env; then
sed -i "\|_PATH=|a\NETVISOR_PUBLIC_URL=http://${LOCAL_IP}:60072" /opt/netvisor/.env sed -i "\|_PATH=|a\NETVISOR_PUBLIC_URL=http://${LOCAL_IP}:60072" /opt/netvisor/.env
fi fi
sed -i 's|_TARGET=.*$|_URL=http://127.0.0.1:60072|' /opt/netvisor/.env sed -i 's|_TARGET=.*$|_URL=http://127.0.0.1:60072|' /opt/netvisor/.env

View File

@@ -21,37 +21,34 @@ color
catch_errors catch_errors
function update_script() { function update_script() {
header_info header_info
check_container_storage check_container_storage
check_container_resources check_container_resources
if [[ ! -d /opt/nextpvr ]]; then if [[ ! -d /opt/nextpvr ]]; then
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Stopping Service"
systemctl stop nextpvr-server
msg_ok "Stopped Service"
msg_info "Updating LXC packages"
$STD apt update
$STD apt -y upgrade
msg_ok "Updated LXC packages"
msg_info "Updating ${APP}"
cd /opt
curl -fsSL "https://nextpvr.com/nextpvr-helper.deb" -o $(basename "https://nextpvr.com/nextpvr-helper.deb")
$STD dpkg -i nextpvr-helper.deb
msg_ok "Updated ${APP}"
msg_info "Starting Service"
systemctl start nextpvr-server
msg_ok "Started Service"
msg_info "Cleaning Up"
rm -rf /opt/nextpvr-helper.deb
msg_ok "Cleaned"
msg_ok "Updated successfully!"
exit exit
fi
msg_info "Stopping Service"
systemctl stop nextpvr-server
msg_ok "Stopped Service"
msg_info "Updating LXC packages"
$STD apt update
$STD apt -y upgrade
msg_ok "Updated LXC packages"
msg_info "Updating ${APP}"
cd /opt
curl -fsSL "https://nextpvr.com/nextpvr-helper.deb" -o $(basename "https://nextpvr.com/nextpvr-helper.deb")
$STD dpkg -i nextpvr-helper.deb
rm -rf /opt/nextpvr-helper.deb
msg_ok "Updated ${APP}"
msg_info "Starting Service"
systemctl start nextpvr-server
msg_ok "Started Service"
msg_ok "Updated successfully!"
exit
} }
start start

View File

@@ -42,17 +42,13 @@ function update_script() {
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
export DEBCONF_NOWARNINGS=yes export DEBCONF_NOWARNINGS=yes
$STD dpkg -i nxwitness-server-$RELEASE-linux_x64.deb $STD dpkg -i nxwitness-server-$RELEASE-linux_x64.deb
rm -f /tmp/nxwitness-server-$RELEASE-linux_x64.deb
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated ${APP}" msg_ok "Updated ${APP}"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start networkoptix-root-tool networkoptix-mediaserver systemctl start networkoptix-root-tool networkoptix-mediaserver
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -f /tmp/nxwitness-server-$RELEASE-linux_x64.deb
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at ${RELEASE}" msg_ok "No update required. ${APP} is already at ${RELEASE}"

View File

@@ -50,17 +50,13 @@ function update_script() {
msg_info "Updating ${APP} to ${LATEST_VERSION}" msg_info "Updating ${APP} to ${LATEST_VERSION}"
curl -fsSL https://nightly.odoo.com/${RELEASE}/nightly/deb/odoo_${RELEASE}.latest_all.deb -o /opt/odoo.deb curl -fsSL https://nightly.odoo.com/${RELEASE}/nightly/deb/odoo_${RELEASE}.latest_all.deb -o /opt/odoo.deb
$STD apt install -y /opt/odoo.deb $STD apt install -y /opt/odoo.deb
rm -f /opt/odoo.deb
echo "$LATEST_VERSION" >/opt/${APP}_version.txt echo "$LATEST_VERSION" >/opt/${APP}_version.txt
msg_ok "Updated ${APP} to ${LATEST_VERSION}" msg_ok "Updated ${APP} to ${LATEST_VERSION}"
msg_info "Starting ${APP} service" msg_info "Starting Service"
systemctl start odoo systemctl start odoo
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning Up"
rm -f /opt/odoo.deb
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at ${LATEST_VERSION}" msg_ok "No update required. ${APP} is already at ${LATEST_VERSION}"

View File

@@ -43,16 +43,13 @@ function update_script() {
mkdir -p /usr/local/lib/ollama mkdir -p /usr/local/lib/ollama
tar -xzf "${TMP_TAR}" -C /usr/local/lib/ollama tar -xzf "${TMP_TAR}" -C /usr/local/lib/ollama
ln -sf /usr/local/lib/ollama/bin/ollama /usr/local/bin/ollama ln -sf /usr/local/lib/ollama/bin/ollama /usr/local/bin/ollama
rm -f "${TMP_TAR}"
echo "${RELEASE}" >/opt/Ollama_version.txt echo "${RELEASE}" >/opt/Ollama_version.txt
msg_ok "Updated Ollama to ${RELEASE}" msg_ok "Updated Ollama to ${RELEASE}"
msg_info "Starting Services" msg_info "Starting Services"
systemctl start ollama systemctl start ollama
msg_ok "Started Services" msg_ok "Started Services"
msg_info "Cleaning Up"
rm -f "${TMP_TAR}"
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. Ollama is already at ${RELEASE}" msg_ok "No update required. Ollama is already at ${RELEASE}"

View File

@@ -39,17 +39,14 @@ function update_script() {
tar -xzf onedev-latest.tar.gz tar -xzf onedev-latest.tar.gz
$STD /opt/onedev-latest/bin/upgrade.sh /opt/onedev $STD /opt/onedev-latest/bin/upgrade.sh /opt/onedev
RELEASE=$(cat /opt/onedev/release.properties | grep "version" | cut -d'=' -f2) RELEASE=$(cat /opt/onedev/release.properties | grep "version" | cut -d'=' -f2)
rm -rf /opt/onedev-latest
rm -rf /opt/onedev-latest.tar.gz
echo "${RELEASE}" >"/opt/${APP}_version.txt" echo "${RELEASE}" >"/opt/${APP}_version.txt"
msg_ok "Updated ${APP} to v${RELEASE}" msg_ok "Updated ${APP} to v${RELEASE}"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start onedev systemctl start onedev
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -rf /opt/onedev-latest
rm -rf /opt/onedev-latest.tar.gz
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at v${RELEASE}." msg_ok "No update required. ${APP} is already at v${RELEASE}."

View File

@@ -65,17 +65,14 @@ EOF
$STD pip install --no-cache-dir -r requirements.txt $STD pip install --no-cache-dir -r requirements.txt
mkdir -p data/chromadb mkdir -p data/chromadb
$STD npm install $STD npm install
rm -rf /opt/v${RELEASE}.zip
rm -rf /opt/paperless-ai_bak
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated $APP to v${RELEASE}" msg_ok "Updated $APP to v${RELEASE}"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start paperless-ai systemctl start paperless-ai
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning Up"
rm -rf /opt/v${RELEASE}.zip
rm -rf /opt/paperless-ai_bak
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at v${RELEASE}" msg_ok "No update required. ${APP} is already at v${RELEASE}"

View File

@@ -20,48 +20,45 @@ color
catch_errors catch_errors
function update_script() { function update_script() {
header_info header_info
check_container_storage check_container_storage
check_container_resources check_container_resources
if [[ ! -d /opt/paperless-gpt ]]; then if [[ ! -d /opt/paperless-gpt ]]; then
msg_error "No Paperless-GPT installation found!" msg_error "No Paperless-GPT installation found!"
exit
fi
RELEASE=$(curl -fsSL https://api.github.com/repos/icereed/paperless-gpt/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
msg_info "Stopping Service"
systemctl stop paperless-gpt
msg_ok "Service Stopped"
msg_info "Updating Paperless-GPT to ${RELEASE}"
temp_file=$(mktemp)
curl -fsSL "https://github.com/icereed/paperless-gpt/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file"
tar zxf $temp_file
rm -rf /opt/paperless-gpt
mv paperless-gpt-${RELEASE} /opt/paperless-gpt
cd /opt/paperless-gpt/web-app
$STD npm install
$STD npm run build
cd /opt/paperless-gpt
go mod download
export CC=musl-gcc
CGO_ENABLED=1 go build -tags musl -o /dev/null github.com/mattn/go-sqlite3
CGO_ENABLED=1 go build -tags musl -o paperless-gpt .
echo "${RELEASE}" >"/opt/paperless-gpt_version.txt"
msg_ok "Updated Paperless-GPT to ${RELEASE}"
msg_info "Starting Service"
systemctl start paperless-gpt
msg_ok "Started Service"
msg_info "Cleaning Up"
rm -f $temp_file
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!"
else
msg_ok "No update required. ${APP} is already at ${RELEASE}"
fi
exit exit
fi
RELEASE=$(curl -fsSL https://api.github.com/repos/icereed/paperless-gpt/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
msg_info "Stopping Service"
systemctl stop paperless-gpt
msg_ok "Service Stopped"
msg_info "Updating Paperless-GPT to ${RELEASE}"
temp_file=$(mktemp)
curl -fsSL "https://github.com/icereed/paperless-gpt/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file"
tar zxf $temp_file
rm -rf /opt/paperless-gpt
mv paperless-gpt-${RELEASE} /opt/paperless-gpt
cd /opt/paperless-gpt/web-app
$STD npm install
$STD npm run build
cd /opt/paperless-gpt
go mod download
export CC=musl-gcc
CGO_ENABLED=1 go build -tags musl -o /dev/null github.com/mattn/go-sqlite3
CGO_ENABLED=1 go build -tags musl -o paperless-gpt .
rm -f $temp_file
echo "${RELEASE}" >"/opt/paperless-gpt_version.txt"
msg_ok "Updated Paperless-GPT to ${RELEASE}"
msg_info "Starting Service"
systemctl start paperless-gpt
msg_ok "Started Service"
msg_ok "Updated successfully!"
else
msg_ok "No update required. ${APP} is already at ${RELEASE}"
fi
exit
} }
start start

View File

@@ -52,17 +52,14 @@ function update_script() {
$STD php bin/console cache:clear $STD php bin/console cache:clear
$STD php bin/console doctrine:migrations:migrate -n $STD php bin/console doctrine:migrations:migrate -n
chown -R www-data:www-data /opt/partdb chown -R www-data:www-data /opt/partdb
rm -r "/opt/v${RELEASE}.zip"
rm -r /opt/partdb-backup
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated $APP to v${RELEASE}" msg_ok "Updated $APP to v${RELEASE}"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start apache2 systemctl start apache2
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -r "/opt/v${RELEASE}.zip"
rm -r /opt/partdb-backup
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at v${RELEASE}" msg_ok "No update required. ${APP} is already at v${RELEASE}"

View File

@@ -67,6 +67,7 @@ function update_script() {
$STD php artisan migrate --seed --force $STD php artisan migrate --seed --force
chown -R www-data:www-data /opt/pelican-panel chown -R www-data:www-data /opt/pelican-panel
chmod -R 755 /opt/pelican-panel/storage /opt/pelican-panel/bootstrap/cache/ chmod -R 755 /opt/pelican-panel/storage /opt/pelican-panel/bootstrap/cache/
rm -rf "/opt/pelican-panel/panel.tar.gz"
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated $APP to v${RELEASE}" msg_ok "Updated $APP to v${RELEASE}"
@@ -74,10 +75,6 @@ function update_script() {
$STD php artisan queue:restart $STD php artisan queue:restart
$STD php artisan up $STD php artisan up
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -rf "/opt/pelican-panel/panel.tar.gz"
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at v${RELEASE}" msg_ok "No update required. ${APP} is already at v${RELEASE}"

View File

@@ -23,7 +23,8 @@ function update_script() {
header_info header_info
check_container_storage check_container_storage
check_container_resources 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!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi

View File

@@ -70,6 +70,7 @@ EOF
$STD php artisan migrate --seed --force --no-interaction $STD php artisan migrate --seed --force --no-interaction
chown -R www-data:www-data /opt/pterodactyl-panel/* chown -R www-data:www-data /opt/pterodactyl-panel/*
chmod -R 755 /opt/pterodactyl-panel/storage /opt/pterodactyl-panel/bootstrap/cache/ chmod -R 755 /opt/pterodactyl-panel/storage /opt/pterodactyl-panel/bootstrap/cache/
rm -rf "/opt/pterodactyl-panel/panel.tar.gz"
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated $APP to v${RELEASE}" msg_ok "Updated $APP to v${RELEASE}"
@@ -77,10 +78,6 @@ EOF
$STD php artisan queue:restart $STD php artisan queue:restart
$STD php artisan up $STD php artisan up
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -rf "/opt/pterodactyl-panel/panel.tar.gz"
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at v${RELEASE}" msg_ok "No update required. ${APP} is already at v${RELEASE}"

View File

@@ -43,14 +43,11 @@ function update_script() {
$STD apt remove --purge -y dotnet-sdk-8.0 $STD apt remove --purge -y dotnet-sdk-8.0
$STD apt install -y dotnet-sdk-9.0 $STD apt install -y dotnet-sdk-9.0
fi fi
rm -rf /opt/rdtc-backup
msg_info "Starting Service" msg_info "Starting Service"
systemctl start rdtc systemctl start rdtc
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning Up"
rm -rf /opt/rdtc-backup
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -54,6 +54,7 @@ function update_script() {
cd /tmp cd /tmp
curl -fsSL https://dl.min.io/server/minio/release/linux-amd64/minio.deb -o minio.deb curl -fsSL https://dl.min.io/server/minio/release/linux-amd64/minio.deb -o minio.deb
$STD dpkg -i minio.deb $STD dpkg -i minio.deb
rm -f /tmp/minio.deb
msg_ok "Updated Minio" msg_ok "Updated Minio"
msg_info "Updating Browserless (Patience)" msg_info "Updating Browserless (Patience)"
@@ -75,16 +76,12 @@ function update_script() {
$STD npm run build:function $STD npm run build:function
$STD npm prune production $STD npm prune production
mv /opt/browserless.env /opt/browserless/.env mv /opt/browserless.env /opt/browserless/.env
rm -f "$brwsr_tmp"
msg_ok "Updated Browserless" msg_ok "Updated Browserless"
msg_info "Restarting services" msg_info "Restarting services"
systemctl start minio Reactive-Resume browserless systemctl start minio Reactive-Resume browserless
msg_ok "Restarted services" msg_ok "Restarted services"
msg_info "Cleaning Up"
rm -f /tmp/minio.deb
rm -f "$brwsr_tmp"
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -41,15 +41,12 @@ function update_script() {
$STD npm install $STD npm install
cp -f /opt/index.html /opt/revealjs cp -f /opt/index.html /opt/revealjs
sed -i '25s/localhost/0.0.0.0/g' /opt/revealjs/gulpfile.js sed -i '25s/localhost/0.0.0.0/g' /opt/revealjs/gulpfile.js
rm -f /opt/index.html
msg_ok "Updated $APP" msg_ok "Updated $APP"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start revealjs systemctl start revealjs
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning Up"
rm -f /opt/index.html
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -61,15 +61,12 @@ function update_script() {
$STD pip install -r requirements.txt $STD pip install -r requirements.txt
mv /opt/config.ini.bak /opt/soularr/config.ini mv /opt/config.ini.bak /opt/soularr/config.ini
mv /opt/run.sh.bak /opt/soularr/run.sh mv /opt/run.sh.bak /opt/soularr/run.sh
rm -rf /tmp/main.zip
msg_ok "Updated soularr" msg_ok "Updated soularr"
msg_info "Starting soularr timer" msg_info "Starting soularr timer"
systemctl start soularr.timer systemctl start soularr.timer
msg_ok "Started soularr timer" msg_ok "Started soularr timer"
msg_info "Cleaning Up"
rm -rf /tmp/main.zip
msg_ok "Cleanup Completed"
exit exit
} }

View File

@@ -43,17 +43,13 @@ function update_script() {
cd spoolman cd spoolman
$STD pip3 install -r requirements.txt $STD pip3 install -r requirements.txt
curl -fsSL "https://raw.githubusercontent.com/Donkie/Spoolman/master/.env.example" -o ".env" curl -fsSL "https://raw.githubusercontent.com/Donkie/Spoolman/master/.env.example" -o ".env"
rm -rf /opt/spoolman.zip
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated ${APP} to ${RELEASE}" msg_ok "Updated ${APP} to ${RELEASE}"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start spoolman systemctl start spoolman
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -rf /opt/spoolman.zip
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at ${RELEASE}" msg_ok "No update required. ${APP} is already at ${RELEASE}"

View File

@@ -64,16 +64,13 @@ EOF
cd /opt/tandoor cd /opt/tandoor
$STD /opt/tandoor/.venv/bin/python manage.py migrate $STD /opt/tandoor/.venv/bin/python manage.py migrate
$STD /opt/tandoor/.venv/bin/python manage.py collectstatic --no-input $STD /opt/tandoor/.venv/bin/python manage.py collectstatic --no-input
rm -rf /opt/tandoor.bak
msg_ok "Updated Trandoor" msg_ok "Updated Trandoor"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start tandoor systemctl start tandoor
systemctl reload nginx systemctl reload nginx
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning Up"
rm -rf /opt/tandoor.bak
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -45,16 +45,13 @@ function update_script() {
export NODE_OPTIONS=--openssl-legacy-provider export NODE_OPTIONS=--openssl-legacy-provider
$STD npm i $STD npm i
$STD yarn build $STD yarn build
rm -r "/opt/v${RELEASE}.tar.gz"
echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated TasmoCompiler" msg_ok "Updated TasmoCompiler"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start tasmocompiler systemctl start tasmocompiler
msg_ok "Started Service" msg_ok "Started Service"
echo "${RELEASE}" >/opt/${APP}_version.txt
msg_info "Cleaning up"
rm -r "/opt/v${RELEASE}.tar.gz"
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at v${RELEASE}" msg_ok "No update required. ${APP} is already at v${RELEASE}"

View File

@@ -37,11 +37,8 @@ function update_script() {
$STD unzip Tdarr_Updater.zip $STD unzip Tdarr_Updater.zip
chmod +x Tdarr_Updater chmod +x Tdarr_Updater
$STD ./Tdarr_Updater $STD ./Tdarr_Updater
msg_ok "Updated Tdarr"
msg_info "Cleaning up"
rm -rf /opt/tdarr/Tdarr_Updater.zip rm -rf /opt/tdarr/Tdarr_Updater.zip
msg_ok "Cleaned up" msg_ok "Updated Tdarr"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
exit exit
} }

View File

@@ -38,11 +38,8 @@ function update_script() {
msg_info "Updating Technitium DNS" msg_info "Updating Technitium DNS"
curl -fsSL "https://download.technitium.com/dns/DnsServerPortable.tar.gz" -o /opt/DnsServerPortable.tar.gz curl -fsSL "https://download.technitium.com/dns/DnsServerPortable.tar.gz" -o /opt/DnsServerPortable.tar.gz
$STD tar zxvf /opt/DnsServerPortable.tar.gz -C /opt/technitium/dns/ $STD tar zxvf /opt/DnsServerPortable.tar.gz -C /opt/technitium/dns/
msg_ok "Updated Technitium DNS"
msg_info "Cleaning up"
rm -f /opt/DnsServerPortable.tar.gz rm -f /opt/DnsServerPortable.tar.gz
msg_ok "Cleaned up" msg_ok "Updated Technitium DNS"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. Technitium DNS is already at v${RELEASE}." msg_ok "No update required. Technitium DNS is already at v${RELEASE}."

View File

@@ -41,15 +41,12 @@ function update_script() {
msg_info "Restoring data" msg_info "Restoring data"
cp -R /opt/teddycloud_bak/certs /opt/teddycloud_bak/config /opt/teddycloud_bak/data /opt/teddycloud cp -R /opt/teddycloud_bak/certs /opt/teddycloud_bak/config /opt/teddycloud_bak/data /opt/teddycloud
rm -rf /opt/teddycloud_bak
msg_ok "Data restored" msg_ok "Data restored"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start teddycloud systemctl start teddycloud
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -rf /opt/teddycloud_bak
msg_ok "Cleaned up"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -43,7 +43,7 @@ function update_script() {
fetch_and_deploy_gh_release "tianji" "msgbyte/tianji" fetch_and_deploy_gh_release "tianji" "msgbyte/tianji"
msg_info "Updating ${APP}" msg_info "Updating Tianji"
cd /opt/tianji cd /opt/tianji
export NODE_OPTIONS="--max_old_space_size=4096" export NODE_OPTIONS="--max_old_space_size=4096"
$STD pnpm install --filter @tianji/client... --config.dedupe-peer-dependents=false --frozen-lockfile $STD pnpm install --filter @tianji/client... --config.dedupe-peer-dependents=false --frozen-lockfile
@@ -55,7 +55,11 @@ function update_script() {
mv /opt/.env /opt/tianji/src/server/.env mv /opt/.env /opt/tianji/src/server/.env
cd src/server cd src/server
$STD pnpm db:migrate:apply $STD pnpm db:migrate:apply
msg_ok "Updated ${APP}" rm -rf /opt/tianji_bak
rm -rf /opt/tianji/src/client
rm -rf /opt/tianji/website
rm -rf /opt/tianji/reporter
msg_ok "Updated Tianji"
msg_info "Updating AppRise" msg_info "Updating AppRise"
$STD uv pip install apprise cryptography --system $STD uv pip install apprise cryptography --system
@@ -64,13 +68,6 @@ function update_script() {
msg_info "Starting Service" msg_info "Starting Service"
systemctl start tianji systemctl start tianji
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -rf /opt/tianji_bak
rm -rf /opt/tianji/src/client
rm -rf /opt/tianji/website
rm -rf /opt/tianji/reporter
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -50,18 +50,12 @@ function update_script() {
mv /opt/traccar.xml /opt/traccar/conf mv /opt/traccar.xml /opt/traccar/conf
[[ -d /opt/data ]] && mv /opt/data /opt/traccar [[ -d /opt/data ]] && mv /opt/data /opt/traccar
[[ -d /opt/media ]] && mv /opt/media /opt/traccar [[ -d /opt/media ]] && mv /opt/media /opt/traccar
[ -f README.txt ] || [ -f traccar.run ] && rm -f README.txt traccar.run
msg_ok "Data restored" msg_ok "Data restored"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start traccar systemctl start traccar
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
[ -f README.txt ] || [ -f traccar.run ] && rm -f README.txt traccar.run
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned up"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -55,14 +55,8 @@ function update_script() {
msg_info "Restoring Database" msg_info "Restoring Database"
mkdir -p "$(dirname "${DB_RESTORE_PATH}")" mkdir -p "$(dirname "${DB_RESTORE_PATH}")"
cp -r /opt/trilium_backup/$(basename "${DB_PATH}") "${DB_RESTORE_PATH}" cp -r /opt/trilium_backup/$(basename "${DB_PATH}") "${DB_RESTORE_PATH}"
msg_ok "Restored Database"
msg_info "Cleaning up"
rm -rf /opt/trilium_backup rm -rf /opt/trilium_backup
$STD apt -y autoremove msg_ok "Restored Database"
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start trilium systemctl start trilium

View File

@@ -43,12 +43,6 @@ function update_script() {
msg_info "Starting Service" msg_info "Starting Service"
systemctl start uhf-server systemctl start uhf-server
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -57,11 +57,8 @@ function update_script() {
else else
cp target/release/vaultwarden /opt/vaultwarden/bin/ cp target/release/vaultwarden /opt/vaultwarden/bin/
fi fi
msg_ok "Updated VaultWarden"
msg_info "Cleaning up"
cd ~ && rm -rf vaultwarden cd ~ && rm -rf vaultwarden
msg_ok "Cleaned" msg_ok "Updated VaultWarden"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start vaultwarden systemctl start vaultwarden
@@ -77,11 +74,8 @@ function update_script() {
msg_info "Updating Web-Vault to $WVRELEASE" msg_info "Updating Web-Vault to $WVRELEASE"
$STD curl -fsSLO https://github.com/dani-garcia/bw_web_builds/releases/download/"$WVRELEASE"/bw_web_"$WVRELEASE".tar.gz $STD curl -fsSLO https://github.com/dani-garcia/bw_web_builds/releases/download/"$WVRELEASE"/bw_web_"$WVRELEASE".tar.gz
$STD tar -zxf bw_web_"$WVRELEASE".tar.gz -C /opt/vaultwarden/ $STD tar -zxf bw_web_"$WVRELEASE".tar.gz -C /opt/vaultwarden/
msg_ok "Updated Web-Vault"
msg_info "Cleaning up"
rm bw_web_"$WVRELEASE".tar.gz rm bw_web_"$WVRELEASE".tar.gz
msg_ok "Cleaned" msg_ok "Updated Web-Vault"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start vaultwarden systemctl start vaultwarden

View File

@@ -39,16 +39,13 @@ function update_script() {
curl -fsSL "https://dl.vikunja.io/vikunja/$RELEASE/vikunja-$RELEASE-amd64.deb" -o $(basename "https://dl.vikunja.io/vikunja/$RELEASE/vikunja-$RELEASE-amd64.deb") curl -fsSL "https://dl.vikunja.io/vikunja/$RELEASE/vikunja-$RELEASE-amd64.deb" -o $(basename "https://dl.vikunja.io/vikunja/$RELEASE/vikunja-$RELEASE-amd64.deb")
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
$STD dpkg -i vikunja-"$RELEASE"-amd64.deb $STD dpkg -i vikunja-"$RELEASE"-amd64.deb
rm -rf /opt/vikunja-"$RELEASE"-amd64.deb
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated ${APP}" msg_ok "Updated ${APP}"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start vikunja systemctl start vikunja
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning Up"
rm -rf /opt/vikunja-"$RELEASE"-amd64.deb
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at ${RELEASE}" msg_ok "No update required. ${APP} is already at ${RELEASE}"

View File

@@ -73,16 +73,13 @@ EOF
cp -f wastebin* /opt/wastebin/ cp -f wastebin* /opt/wastebin/
chmod +x /opt/wastebin/wastebin chmod +x /opt/wastebin/wastebin
chmod +x /opt/wastebin/wastebin-ctl chmod +x /opt/wastebin/wastebin-ctl
rm -f "$temp_file"
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated Wastebin" msg_ok "Updated Wastebin"
msg_info "Starting Wastebin" msg_info "Starting Wastebin"
systemctl start wastebin systemctl start wastebin
msg_ok "Started Wastebin" msg_ok "Started Wastebin"
msg_info "Cleaning Up"
rm -f "$temp_file"
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at v${RELEASE}" msg_ok "No update required. ${APP} is already at v${RELEASE}"

View File

@@ -37,10 +37,7 @@ function update_script() {
fetch_and_deploy_gh_release "watchyourlan" "aceberg/WatchYourLAN" "binary" fetch_and_deploy_gh_release "watchyourlan" "aceberg/WatchYourLAN" "binary"
cp -R config.yaml /data/config.yaml cp -R config.yaml /data/config.yaml
sed -i 's|/etc/watchyourlan/config.yaml|/data/config.yaml|' /lib/systemd/system/watchyourlan.service sed -i 's|/etc/watchyourlan/config.yaml|/data/config.yaml|' /lib/systemd/system/watchyourlan.service
msg_info "Cleaning up"
rm ~/config.yaml rm ~/config.yaml
msg_ok "Cleaned up"
msg_info "Starting service" msg_info "Starting service"
systemctl enable -q --now watchyourlan systemctl enable -q --now watchyourlan

View File

@@ -45,16 +45,13 @@ function update_script() {
$STD python3 manage.py collectstatic --no-input $STD python3 manage.py collectstatic --no-input
$STD yarn install $STD yarn install
$STD yarn build:css:sass $STD yarn build:css:sass
rm -rf "$temp_file"
echo "${RELEASE}" >/opt/${APP}_version.txt echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated $APP to v${RELEASE}" msg_ok "Updated $APP to v${RELEASE}"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start wger systemctl start wger
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning Up"
rm -rf "$temp_file"
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else
msg_ok "No update required. ${APP} is already at v${RELEASE}" msg_ok "No update required. ${APP} is already at v${RELEASE}"

View File

@@ -54,15 +54,12 @@ function update_script() {
msg_info "Restoring Data" msg_info "Restoring Data"
cp -R /opt/wikijs-backup/* /opt/wikijs cp -R /opt/wikijs-backup/* /opt/wikijs
$SQLITE_INSTALL && $STD npm rebuild sqlite3 $SQLITE_INSTALL && $STD npm rebuild sqlite3
rm -rf /opt/wikijs-backup
msg_ok "Restored Data" msg_ok "Restored Data"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start wikijs systemctl start wikijs
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning Up"
rm -rf /opt/wikijs-backup
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -56,15 +56,12 @@ function update_script() {
if ! grep -q 'frozen' /opt/wizarr/start.sh; then if ! grep -q 'frozen' /opt/wizarr/start.sh; then
sed -i 's/run/& --frozen/' /opt/wizarr/start.sh sed -i 's/run/& --frozen/' /opt/wizarr/start.sh
fi fi
rm -rf "$BACKUP_FILE"
msg_ok "Updated Wizarr" msg_ok "Updated Wizarr"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start wizarr systemctl start wizarr
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning Up"
rm -rf "$BACKUP_FILE"
msg_ok "Cleanup Completed"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

View File

@@ -59,6 +59,7 @@ function update_script() {
xargs -I{} echo "https://repo.zabbix.com/zabbix/{}/release/debian/pool/main/z/zabbix-release/zabbix-release_latest+debian13_all.deb")" \ xargs -I{} echo "https://repo.zabbix.com/zabbix/{}/release/debian/pool/main/z/zabbix-release/zabbix-release_latest+debian13_all.deb")" \
-o /tmp/zabbix-release_latest+debian13_all.deb -o /tmp/zabbix-release_latest+debian13_all.deb
$STD dpkg -i zabbix-release_latest+debian13_all.deb $STD dpkg -i zabbix-release_latest+debian13_all.deb
rm -rf /tmp/zabbix-release_latest+debian13_all.deb
$STD apt update $STD apt update
$STD apt install --only-upgrade zabbix-server-pgsql zabbix-frontend-php php8.4-pgsql $STD apt install --only-upgrade zabbix-server-pgsql zabbix-frontend-php php8.4-pgsql
@@ -88,13 +89,6 @@ function update_script() {
systemctl start "$AGENT_SERVICE" systemctl start "$AGENT_SERVICE"
systemctl restart apache2 systemctl restart apache2
msg_ok "Started Services" msg_ok "Started Services"
msg_info "Cleaning Up"
rm -rf /tmp/zabbix-release_latest+debian13_all.deb
$STD apt -y autoremove
$STD apt -y autoclean
$STD apt -y clean
msg_ok "Cleaned"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
exit exit
} }

View File

@@ -47,18 +47,15 @@ function update_script() {
rm -rf /opt/zigbee2mqtt/data rm -rf /opt/zigbee2mqtt/data
mv /opt/z2m_backup/data /opt/zigbee2mqtt mv /opt/z2m_backup/data /opt/zigbee2mqtt
cd /opt/zigbee2mqtt cd /opt/zigbee2mqtt
grep -q "^packageImportMethod" ./pnpm-workspace.yaml || echo "packageImportMethod: hardlink" >> ./pnpm-workspace.yaml grep -q "^packageImportMethod" ./pnpm-workspace.yaml || echo "packageImportMethod: hardlink" >>./pnpm-workspace.yaml
$STD pnpm install --frozen-lockfile $STD pnpm install --frozen-lockfile
$STD pnpm build $STD pnpm build
rm -rf /opt/z2m_backup
msg_ok "Updated Zigbee2MQTT" msg_ok "Updated Zigbee2MQTT"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start zigbee2mqtt systemctl start zigbee2mqtt
msg_ok "Started Service" msg_ok "Started Service"
msg_info "Cleaning up"
rm -rf /opt/z2m_backup
msg_ok "Cleaned up"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit

100
frontend/bun.lock generated
View File

@@ -11,6 +11,7 @@
"@radix-ui/react-label": "^2.1.2", "@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-navigation-menu": "^1.2.5", "@radix-ui/react-navigation-menu": "^1.2.5",
"@radix-ui/react-popover": "^1.1.6", "@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-select": "^2.1.6",
"@radix-ui/react-separator": "^1.1.2", "@radix-ui/react-separator": "^1.1.2",
"@radix-ui/react-slot": "^1.1.2", "@radix-ui/react-slot": "^1.1.2",
@@ -26,7 +27,7 @@
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"framer-motion": "^11.18.2", "framer-motion": "^11.18.2",
"fuse.js": "^7.1.0", "fuse.js": "^7.1.0",
"lucide-react": "^0.542.0", "lucide-react": "^0.554.0",
"mini-svg-data-uri": "^1.4.4", "mini-svg-data-uri": "^1.4.4",
"motion": "^12.23.12", "motion": "^12.23.12",
"next": "15.5.2", "next": "15.5.2",
@@ -43,6 +44,7 @@
"react-icons": "^5.5.0", "react-icons": "^5.5.0",
"react-simple-typewriter": "^5.0.1", "react-simple-typewriter": "^5.0.1",
"react-use-measure": "^2.1.7", "react-use-measure": "^2.1.7",
"recharts": "2.15.4",
"sharp": "^0.33.5", "sharp": "^0.33.5",
"simple-icons": "^13.21.0", "simple-icons": "^13.21.0",
"sonner": "^1.7.4", "sonner": "^1.7.4",
@@ -417,6 +419,8 @@
"@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-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-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=="], "@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=="],
@@ -515,6 +519,24 @@
"@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="], "@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/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=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
@@ -765,6 +787,28 @@
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], "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=="], "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=="], "data-urls": ["data-urls@5.0.0", "", { "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0" } }, "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg=="],
@@ -783,6 +827,8 @@
"decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="], "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=="], "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=="], "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
@@ -807,6 +853,8 @@
"doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], "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=="], "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=="], "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
@@ -939,12 +987,16 @@
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], "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=="], "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-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-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-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=="], "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
@@ -1059,6 +1111,8 @@
"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=="], "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-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=="], "is-alphanumerical": ["is-alphanumerical@1.0.4", "", { "dependencies": { "is-alphabetical": "^1.0.0", "is-decimal": "^1.0.0" } }, "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A=="],
@@ -1191,7 +1245,7 @@
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"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=="], "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=="],
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
@@ -1455,7 +1509,7 @@
"react-icons": ["react-icons@5.5.0", "", { "peerDependencies": { "react": "*" } }, "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw=="], "react-icons": ["react-icons@5.5.0", "", { "peerDependencies": { "react": "*" } }, "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw=="],
"react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
"react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
@@ -1465,16 +1519,24 @@
"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-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-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-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=="], "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=="], "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=="], "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=="], "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=="], "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=="],
@@ -1625,6 +1687,8 @@
"thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], "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=="], "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=="], "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
@@ -1693,6 +1757,8 @@
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], "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": ["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=="], "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=="],
@@ -1757,18 +1823,18 @@
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], "@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/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"@eslint/eslintrc/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], "@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=="], "@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=="], "@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=="], "@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=="], "@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=="],
@@ -1797,24 +1863,18 @@
"eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], "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-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-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-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/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/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-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/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=="], "eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
@@ -1851,6 +1911,8 @@
"path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "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=="], "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"refractor/prismjs": ["prismjs@1.27.0", "", {}, "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA=="], "refractor/prismjs": ["prismjs@1.27.0", "", {}, "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA=="],
@@ -1873,8 +1935,6 @@
"tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": "lib/cli.js" }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], "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/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=="], "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=="],
@@ -1883,24 +1943,14 @@
"yaml-eslint-parser/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], "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/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=="], "@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-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-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=="], "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=="], "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,6 +23,7 @@
"@radix-ui/react-label": "^2.1.2", "@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-navigation-menu": "^1.2.5", "@radix-ui/react-navigation-menu": "^1.2.5",
"@radix-ui/react-popover": "^1.1.6", "@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-select": "^2.1.6",
"@radix-ui/react-separator": "^1.1.2", "@radix-ui/react-separator": "^1.1.2",
"@radix-ui/react-slot": "^1.1.2", "@radix-ui/react-slot": "^1.1.2",
@@ -38,7 +39,7 @@
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"framer-motion": "^11.18.2", "framer-motion": "^11.18.2",
"fuse.js": "^7.1.0", "fuse.js": "^7.1.0",
"lucide-react": "^0.542.0", "lucide-react": "^0.554.0",
"mini-svg-data-uri": "^1.4.4", "mini-svg-data-uri": "^1.4.4",
"motion": "^12.23.12", "motion": "^12.23.12",
"next": "15.5.2", "next": "15.5.2",
@@ -55,6 +56,7 @@
"react-icons": "^5.5.0", "react-icons": "^5.5.0",
"react-simple-typewriter": "^5.0.1", "react-simple-typewriter": "^5.0.1",
"react-use-measure": "^2.1.7", "react-use-measure": "^2.1.7",
"recharts": "2.15.4",
"sharp": "^0.33.5", "sharp": "^0.33.5",
"simple-icons": "^13.21.0", "simple-icons": "^13.21.0",
"sonner": "^1.7.4", "sonner": "^1.7.4",

View File

@@ -11,7 +11,7 @@
"privileged": false, "privileged": false,
"interface_port": 8080, "interface_port": 8080,
"documentation": null, "documentation": null,
"website": "https://filebrowser.org/features", "website": "https://filebrowser.org/index.html#features",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/file-browser.webp", "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/file-browser.webp",
"config_path": "", "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.", "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

@@ -1,24 +1,184 @@
[ [
{
"name": "pocketbase/pocketbase",
"version": "v0.34.0",
"date": "2025-11-22T09:18:14Z"
},
{
"name": "laurent22/joplin",
"version": "server-v3.4.4",
"date": "2025-09-25T13:19:26Z"
},
{
"name": "zwave-js/zwave-js-ui",
"version": "v11.8.0",
"date": "2025-11-22T07:54:42Z"
},
{
"name": "inventree/InvenTree",
"version": "1.1.5",
"date": "2025-11-22T07:02:52Z"
},
{
"name": "Jackett/Jackett",
"version": "v0.24.339",
"date": "2025-11-22T06:05:53Z"
},
{
"name": "theonedev/onedev",
"version": "v13.1.0",
"date": "2025-11-22T04:29:25Z"
},
{
"name": "jeedom/core",
"version": "4.4.20",
"date": "2025-11-22T00:27:05Z"
},
{
"name": "steveiliop56/tinyauth",
"version": "v4.0.1",
"date": "2025-10-15T16:53:55Z"
},
{
"name": "TwiN/gatus",
"version": "v5.33.0",
"date": "2025-11-21T22:54:49Z"
},
{
"name": "BerriAI/litellm",
"version": "v1.78.5-stable-patch-1",
"date": "2025-11-21T19:57:45Z"
},
{
"name": "homarr-labs/homarr",
"version": "v1.44.0",
"date": "2025-11-21T19:17:09Z"
},
{
"name": "gelbphoenix/autocaliweb",
"version": "v0.11.0",
"date": "2025-11-21T18:42:15Z"
},
{
"name": "rclone/rclone",
"version": "v1.72.0",
"date": "2025-11-21T18:20:58Z"
},
{
"name": "keycloak/keycloak",
"version": "26.4.5",
"date": "2025-11-12T15:24:23Z"
},
{
"name": "readeck/readeck",
"version": "0.21.1",
"date": "2025-11-21T17:17:52Z"
},
{
"name": "mattermost/mattermost",
"version": "v10.11.8",
"date": "2025-11-21T17:06:07Z"
},
{
"name": "home-assistant/core",
"version": "2025.11.3",
"date": "2025-11-21T17:03:22Z"
},
{
"name": "Bubka/2FAuth",
"version": "v5.6.1",
"date": "2025-11-21T16:51:21Z"
},
{
"name": "BookStackApp/BookStack",
"version": "v25.11.3",
"date": "2025-11-21T14:06:50Z"
},
{
"name": "pommee/goaway",
"version": "v0.62.19",
"date": "2025-11-21T13:24:09Z"
},
{
"name": "fuma-nama/fumadocs",
"version": "fumadocs-ui@16.1.0",
"date": "2025-11-21T13:02:57Z"
},
{
"name": "forgejo/forgejo",
"version": "v13.0.3",
"date": "2025-11-21T12:43:04Z"
},
{
"name": "bunkerity/bunkerweb",
"version": "v1.6.5",
"date": "2025-10-06T15:25:17Z"
},
{
"name": "chrisbenincasa/tunarr",
"version": "v0.23.0-alpha.24",
"date": "2025-11-21T12:16:39Z"
},
{
"name": "rcourtman/Pulse",
"version": "v4.32.3",
"date": "2025-11-21T11:16:25Z"
},
{
"name": "seriousm4x/UpSnap",
"version": "5.2.4",
"date": "2025-11-21T10:25:05Z"
},
{
"name": "emqx/emqx",
"version": "e6.0.2-beta.2",
"date": "2025-11-21T10:20:27Z"
},
{
"name": "sabnzbd/sabnzbd",
"version": "4.5.5",
"date": "2025-10-24T11:12:22Z"
},
{
"name": "openobserve/openobserve",
"version": "v0.16.3",
"date": "2025-11-21T08:54:06Z"
},
{
"name": "booklore-app/booklore",
"version": "v1.11.0",
"date": "2025-11-21T08:09:03Z"
},
{
"name": "MariaDB/server",
"version": "mariadb-12.1.2",
"date": "2025-11-18T15:16:21Z"
},
{
"name": "morpheus65535/bazarr",
"version": "v1.5.3",
"date": "2025-09-20T12:12:33Z"
},
{
"name": "bluenviron/mediamtx",
"version": "v1.15.4",
"date": "2025-11-21T01:21:03Z"
},
{ {
"name": "TasmoAdmin/TasmoAdmin", "name": "TasmoAdmin/TasmoAdmin",
"version": "v4.3.2", "version": "v4.3.2",
"date": "2025-10-18T12:11:00Z" "date": "2025-10-18T12:11:00Z"
}, },
{ {
"name": "rcourtman/Pulse", "name": "ollama/ollama",
"version": "v4.32.2", "version": "v0.13.1-rc0",
"date": "2025-11-20T22:25:40Z" "date": "2025-11-20T21:30:35Z"
}, },
{ {
"name": "project-zot/zot", "name": "project-zot/zot",
"version": "v2.1.11", "version": "v2.1.11",
"date": "2025-11-20T20:14:44Z" "date": "2025-11-20T20:14:44Z"
}, },
{
"name": "readeck/readeck",
"version": "0.21.0",
"date": "2025-11-20T18:35:59Z"
},
{ {
"name": "saltstack/salt", "name": "saltstack/salt",
"version": "v3007.9", "version": "v3007.9",
@@ -29,6 +189,11 @@
"version": "v1.30.12", "version": "v1.30.12",
"date": "2025-11-20T16:13:19Z" "date": "2025-11-20T16:13:19Z"
}, },
{
"name": "neo4j/neo4j",
"version": "5.26.17",
"date": "2025-11-20T16:09:28Z"
},
{ {
"name": "meilisearch/meilisearch", "name": "meilisearch/meilisearch",
"version": "prototype-v1.26.0.arm-native-docker-build-1", "version": "prototype-v1.26.0.arm-native-docker-build-1",
@@ -64,26 +229,11 @@
"version": "v2.1.1", "version": "v2.1.1",
"date": "2025-11-20T10:54:07Z" "date": "2025-11-20T10:54:07Z"
}, },
{
"name": "fuma-nama/fumadocs",
"version": "fumadocs-ui@16.0.15",
"date": "2025-11-20T10:52:04Z"
},
{
"name": "mattermost/mattermost",
"version": "v10.11.7",
"date": "2025-11-17T08:40:53Z"
},
{ {
"name": "Athou/commafeed", "name": "Athou/commafeed",
"version": "5.12.0", "version": "5.12.0",
"date": "2025-11-20T06:18:58Z" "date": "2025-11-20T06:18:58Z"
}, },
{
"name": "Jackett/Jackett",
"version": "v0.24.336",
"date": "2025-11-20T05:55:54Z"
},
{ {
"name": "documenso/documenso", "name": "documenso/documenso",
"version": "v2.0.14", "version": "v2.0.14",
@@ -99,31 +249,11 @@
"version": "v1.56.0", "version": "v1.56.0",
"date": "2025-11-20T02:28:35Z" "date": "2025-11-20T02:28:35Z"
}, },
{
"name": "BerriAI/litellm",
"version": "v1.80.0.dev6",
"date": "2025-11-20T02:03:21Z"
},
{
"name": "jeedom/core",
"version": "4.4.20",
"date": "2025-11-20T00:27:04Z"
},
{
"name": "steveiliop56/tinyauth",
"version": "v4.0.1",
"date": "2025-10-15T16:53:55Z"
},
{ {
"name": "coder/code-server", "name": "coder/code-server",
"version": "v4.106.2", "version": "v4.106.2",
"date": "2025-11-20T00:23:05Z" "date": "2025-11-20T00:23:05Z"
}, },
{
"name": "keycloak/keycloak",
"version": "26.4.5",
"date": "2025-11-12T15:24:23Z"
},
{ {
"name": "esphome/esphome", "name": "esphome/esphome",
"version": "2025.11.0", "version": "2025.11.0",
@@ -159,11 +289,6 @@
"version": "0.51.3", "version": "0.51.3",
"date": "2025-11-19T15:45:28Z" "date": "2025-11-19T15:45:28Z"
}, },
{
"name": "BookStackApp/BookStack",
"version": "v25.11.2",
"date": "2025-11-19T15:26:29Z"
},
{ {
"name": "grafana/grafana", "name": "grafana/grafana",
"version": "v12.3.0", "version": "v12.3.0",
@@ -184,11 +309,6 @@
"version": "2025.5", "version": "2025.5",
"date": "2025-11-19T14:48:47Z" "date": "2025-11-19T14:48:47Z"
}, },
{
"name": "ollama/ollama",
"version": "v0.13.0",
"date": "2025-11-19T14:16:07Z"
},
{ {
"name": "AdguardTeam/AdGuardHome", "name": "AdguardTeam/AdGuardHome",
"version": "v0.107.69", "version": "v0.107.69",
@@ -204,11 +324,6 @@
"version": "v7.5.0", "version": "v7.5.0",
"date": "2025-11-19T08:36:29Z" "date": "2025-11-19T08:36:29Z"
}, },
{
"name": "morpheus65535/bazarr",
"version": "v1.5.3",
"date": "2025-09-20T12:12:33Z"
},
{ {
"name": "element-hq/synapse", "name": "element-hq/synapse",
"version": "v1.143.0rc1", "version": "v1.143.0rc1",
@@ -224,16 +339,6 @@
"version": "v1.0.1-stable", "version": "v1.0.1-stable",
"date": "2025-11-10T16:51:44Z" "date": "2025-11-10T16:51:44Z"
}, },
{
"name": "bunkerity/bunkerweb",
"version": "testing",
"date": "2025-11-17T16:24:26Z"
},
{
"name": "chrisbenincasa/tunarr",
"version": "v0.23.0-alpha.23",
"date": "2025-11-18T21:36:15Z"
},
{ {
"name": "umami-software/umami", "name": "umami-software/umami",
"version": "v3.0.1", "version": "v3.0.1",
@@ -249,11 +354,6 @@
"version": "v3.6.2", "version": "v3.6.2",
"date": "2025-11-18T16:25:16Z" "date": "2025-11-18T16:25:16Z"
}, },
{
"name": "MariaDB/server",
"version": "mariadb-12.1.2",
"date": "2025-11-18T15:16:21Z"
},
{ {
"name": "redis/redis", "name": "redis/redis",
"version": "8.4.0", "version": "8.4.0",
@@ -269,11 +369,6 @@
"version": "v0.7.5", "version": "v0.7.5",
"date": "2025-11-18T10:50:21Z" "date": "2025-11-18T10:50:21Z"
}, },
{
"name": "emqx/emqx",
"version": "e6.1.0-alpha.1",
"date": "2025-11-18T10:33:45Z"
},
{ {
"name": "wazuh/wazuh", "name": "wazuh/wazuh",
"version": "coverity-w47-4.14.2", "version": "coverity-w47-4.14.2",
@@ -284,11 +379,6 @@
"version": "v0.28.2", "version": "v0.28.2",
"date": "2025-11-18T05:51:46Z" "date": "2025-11-18T05:51:46Z"
}, },
{
"name": "theonedev/onedev",
"version": "v13.1.0",
"date": "2025-11-18T00:06:49Z"
},
{ {
"name": "ipfs/kubo", "name": "ipfs/kubo",
"version": "v0.38.2", "version": "v0.38.2",
@@ -344,11 +434,6 @@
"version": "v0.21.0", "version": "v0.21.0",
"date": "2025-08-23T18:33:53Z" "date": "2025-08-23T18:33:53Z"
}, },
{
"name": "TwiN/gatus",
"version": "v5.32.0",
"date": "2025-11-16T21:08:56Z"
},
{ {
"name": "binwiederhier/ntfy", "name": "binwiederhier/ntfy",
"version": "v2.15.0", "version": "v2.15.0",
@@ -414,16 +499,6 @@
"version": "v0.16.1", "version": "v0.16.1",
"date": "2025-11-14T22:50:06Z" "date": "2025-11-14T22:50:06Z"
}, },
{
"name": "home-assistant/core",
"version": "2025.11.2",
"date": "2025-11-14T22:10:50Z"
},
{
"name": "homarr-labs/homarr",
"version": "v1.43.3",
"date": "2025-11-14T19:16:17Z"
},
{ {
"name": "mealie-recipes/mealie", "name": "mealie-recipes/mealie",
"version": "v3.5.0", "version": "v3.5.0",
@@ -434,11 +509,6 @@
"version": "22.0.3", "version": "22.0.3",
"date": "2025-11-14T14:49:25Z" "date": "2025-11-14T14:49:25Z"
}, },
{
"name": "openobserve/openobserve",
"version": "v0.16.2",
"date": "2025-11-14T12:05:36Z"
},
{ {
"name": "zitadel/zitadel", "name": "zitadel/zitadel",
"version": "v4.7.0", "version": "v4.7.0",
@@ -469,16 +539,6 @@
"version": "v1.7.7", "version": "v1.7.7",
"date": "2025-11-13T21:28:44Z" "date": "2025-11-13T21:28:44Z"
}, },
{
"name": "pommee/goaway",
"version": "v0.62.18",
"date": "2025-11-13T19:49:21Z"
},
{
"name": "pocketbase/pocketbase",
"version": "v0.33.0",
"date": "2025-11-13T14:09:14Z"
},
{ {
"name": "PrivateBin/PrivateBin", "name": "PrivateBin/PrivateBin",
"version": "1.7.9", "version": "1.7.9",
@@ -499,11 +559,6 @@
"version": "v1.0.25", "version": "v1.0.25",
"date": "2025-11-12T16:57:54Z" "date": "2025-11-12T16:57:54Z"
}, },
{
"name": "zwave-js/zwave-js-ui",
"version": "v11.7.0",
"date": "2025-11-12T14:09:36Z"
},
{ {
"name": "cockpit-project/cockpit", "name": "cockpit-project/cockpit",
"version": "351", "version": "351",
@@ -604,11 +659,6 @@
"version": "3.5.1", "version": "3.5.1",
"date": "2025-11-09T05:09:28Z" "date": "2025-11-09T05:09:28Z"
}, },
{
"name": "inventree/InvenTree",
"version": "1.1.3",
"date": "2025-11-09T00:28:21Z"
},
{ {
"name": "raydak-labs/configarr", "name": "raydak-labs/configarr",
"version": "v1.17.2", "version": "v1.17.2",
@@ -684,11 +734,6 @@
"version": "v0.9.1", "version": "v0.9.1",
"date": "2025-11-06T02:26:53Z" "date": "2025-11-06T02:26:53Z"
}, },
{
"name": "neo4j/neo4j",
"version": "5.26.16",
"date": "2025-11-05T20:41:40Z"
},
{ {
"name": "leiweibau/Pi.Alert", "name": "leiweibau/Pi.Alert",
"version": "v2025-11-05", "version": "v2025-11-05",
@@ -844,21 +889,11 @@
"version": "v1.11.1", "version": "v1.11.1",
"date": "2025-10-29T22:09:26Z" "date": "2025-10-29T22:09:26Z"
}, },
{
"name": "laurent22/joplin",
"version": "server-v3.4.4",
"date": "2025-09-25T13:19:26Z"
},
{ {
"name": "apache/cassandra", "name": "apache/cassandra",
"version": "cassandra-5.0.6", "version": "cassandra-5.0.6",
"date": "2025-10-29T07:40:47Z" "date": "2025-10-29T07:40:47Z"
}, },
{
"name": "booklore-app/booklore",
"version": "v1.10.0",
"date": "2025-10-28T19:04:35Z"
},
{ {
"name": "pi-hole/pi-hole", "name": "pi-hole/pi-hole",
"version": "v6.2.2", "version": "v6.2.2",
@@ -884,21 +919,11 @@
"version": "v25.8.0", "version": "v25.8.0",
"date": "2025-10-26T14:23:37Z" "date": "2025-10-26T14:23:37Z"
}, },
{
"name": "forgejo/forgejo",
"version": "v13.0.2",
"date": "2025-10-26T06:33:05Z"
},
{ {
"name": "usememos/memos", "name": "usememos/memos",
"version": "v0.25.2", "version": "v0.25.2",
"date": "2025-10-24T12:30:04Z" "date": "2025-10-24T12:30:04Z"
}, },
{
"name": "sabnzbd/sabnzbd",
"version": "4.5.5",
"date": "2025-10-24T11:12:22Z"
},
{ {
"name": "crowdsecurity/crowdsec", "name": "crowdsecurity/crowdsec",
"version": "v1.7.3", "version": "v1.7.3",
@@ -924,26 +949,11 @@
"version": "release-1.24.1", "version": "release-1.24.1",
"date": "2025-10-22T10:28:00Z" "date": "2025-10-22T10:28:00Z"
}, },
{
"name": "bluenviron/mediamtx",
"version": "v1.15.3",
"date": "2025-10-21T19:56:55Z"
},
{ {
"name": "kyantech/Palmr", "name": "kyantech/Palmr",
"version": "v3.2.5-beta", "version": "v3.2.5-beta",
"date": "2025-10-21T16:49:14Z" "date": "2025-10-21T16:49:14Z"
}, },
{
"name": "rclone/rclone",
"version": "v1.71.2",
"date": "2025-10-20T15:25:52Z"
},
{
"name": "seriousm4x/UpSnap",
"version": "5.2.3",
"date": "2025-10-19T20:50:15Z"
},
{ {
"name": "Part-DB/Part-DB-server", "name": "Part-DB/Part-DB-server",
"version": "v2.2.1", "version": "v2.2.1",
@@ -1009,11 +1019,6 @@
"version": "v5.0.85", "version": "v5.0.85",
"date": "2025-10-12T19:55:18Z" "date": "2025-10-12T19:55:18Z"
}, },
{
"name": "gelbphoenix/autocaliweb",
"version": "v0.10.4",
"date": "2025-10-11T19:53:39Z"
},
{ {
"name": "projectsend/projectsend", "name": "projectsend/projectsend",
"version": "r1945", "version": "r1945",
@@ -1314,11 +1319,6 @@
"version": "v1.11.11", "version": "v1.11.11",
"date": "2025-06-18T18:04:50Z" "date": "2025-06-18T18:04:50Z"
}, },
{
"name": "Bubka/2FAuth",
"version": "v5.6.0",
"date": "2025-06-18T12:19:54Z"
},
{ {
"name": "TriliumNext/Notes", "name": "TriliumNext/Notes",
"version": "v0.95.0", "version": "v0.95.0",

View File

@@ -1,9 +1,67 @@
"use client"; "use client";
import React, { useEffect, useState } from "react"; import {
import "react-datepicker/dist/react-datepicker.css"; 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 ApplicationChart from "../../components/application-chart"; 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";
type DataModel = { type DataModel = {
id: number; id: number;
@@ -30,42 +88,76 @@ type SummaryData = {
nsapp_count: Record<string, number>; nsapp_count: Record<string, number>;
}; };
const DataFetcher: React.FC = () => { // 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 [data, setData] = useState<DataModel[]>([]); const [data, setData] = useState<DataModel[]>([]);
const [summary, setSummary] = useState<SummaryData | null>(null); const [summary, setSummary] = useState<SummaryData | null>(null);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(25); 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 }); const nf = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
useEffect(() => { useEffect(() => {
const fetchSummary = async () => { const fetchData = 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); setLoading(true);
try { try {
const response = await fetch(`https://api.htl-braunau.at/data/paginated?page=${currentPage}&limit=${itemsPerPage === 0 ? "" : itemsPerPage}`); const [summaryRes, dataRes] = await Promise.all([
if (!response.ok) fetch("https://api.htl-braunau.at/data/summary"),
throw new Error(`Failed to fetch data: ${response.statusText}`); fetch(
const result: DataModel[] = await response.json(); `https://api.htl-braunau.at/data/paginated?page=${currentPage}&limit=${itemsPerPage === 0 ? "" : itemsPerPage
setData(result); }`,
),
]);
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);
} }
catch (err) { catch (err) {
setError((err as Error).message); setError((err as Error).message);
@@ -75,13 +167,13 @@ const DataFetcher: React.FC = () => {
} }
}; };
fetchPaginatedData(); fetchData();
}, [currentPage, itemsPerPage]); }, [currentPage, itemsPerPage]);
const sortedData = React.useMemo(() => { const sortedData = useMemo(() => {
if (!sortConfig) if (!sortConfig)
return data; return data;
const sorted = [...data].sort((a, b) => { return [...data].sort((a, b) => {
if (a[sortConfig.key] < b[sortConfig.key]) { if (a[sortConfig.key] < b[sortConfig.key]) {
return sortConfig.direction === "ascending" ? -1 : 1; return sortConfig.direction === "ascending" ? -1 : 1;
} }
@@ -90,23 +182,15 @@ const DataFetcher: React.FC = () => {
} }
return 0; return 0;
}); });
return sorted;
}, [data, sortConfig]); }, [data, sortConfig]);
if (loading)
return <p>Loading...</p>;
if (error) {
return (
<p>
Error:
{error}
</p>
);
}
const requestSort = (key: string) => { const requestSort = (key: string) => {
let direction: "ascending" | "descending" = "ascending"; let direction: "ascending" | "descending" = "ascending";
if (sortConfig && sortConfig.key === key && sortConfig.direction === "ascending") { if (
sortConfig
&& sortConfig.key === key
&& sortConfig.direction === "ascending"
) {
direction = "descending"; direction = "descending";
} }
setSortConfig({ key, direction }); setSortConfig({ key, direction });
@@ -114,135 +198,447 @@ const DataFetcher: React.FC = () => {
const formatDate = (dateString: string): string => { const formatDate = (dateString: string): string => {
const date = new Date(dateString); const date = new Date(dateString);
const year = date.getFullYear(); return new Intl.DateTimeFormat("en-US", {
const month = date.getMonth() + 1; dateStyle: "medium",
const day = date.getDate(); timeStyle: "short",
const hours = String(date.getHours()).padStart(2, "0"); }).format(date);
const minutes = String(date.getMinutes()).padStart(2, "0");
const timezoneOffset = dateString.slice(-6);
return `${day}.${month}.${year} ${hours}:${minutes} ${timezoneOffset} GMT`;
}; };
return ( const getTypeBadge = (type: string) => {
<div className="p-6 mt-20"> if (type === "lxc")
<h1 className="text-2xl font-bold mb-4 text-center">Created LXCs</h1> return formattedBadge("ct");
<ApplicationChart data={summary} /> if (type === "vm")
<p className="text-lg font-bold mt-4"> </p> return formattedBadge("vm");
<div className="mb-4 flex justify-between items-center"> return null;
<p className="text-lg font-bold"> };
{nf.format(
summary?.total_entries ?? 0, // Stats calculations
)} const successCount = summary?.status_count.done ?? 0;
{" "} const failureCount = summary?.status_count.failed ?? 0;
results found const totalCount = summary?.total_entries ?? 0;
</p> const successRate = totalCount > 0 ? (successCount / totalCount) * 100 : 0;
<p className="text-lg font">
Status Legend: 🔄 installing const allApps = useMemo(() => {
{" "} if (!summary?.nsapp_count)
{nf.format(summary?.status_count.installing ?? 0)} return [];
{" "} return Object.entries(summary.nsapp_count).sort(([, a], [, b]) => b - a);
| completed }, [summary]);
{" "}
{nf.format(summary?.status_count.done ?? 0)} const topApps = useMemo(() => {
{" "} return allApps.slice(0, 15);
| failed }, [allApps]);
{" "}
{nf.format(summary?.status_count.failed ?? 0)} const mostPopularApp = topApps[0];
{" "}
| unknown // 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> </p>
</div> </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> return (
<tr> <div className="mb-3">
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("status")}>Status</th> <div className="mt-20 flex sm:px-4 xl:px-0">
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("type")}>Type</th> <div className="mx-4 w-full sm:mx-0 space-y-8">
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("nsapp")}>Application</th> {/* Header */}
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("os_type")}>OS</th> <div>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("os_version")}>OS Version</th> <h1 className="text-3xl font-bold tracking-tight">Analytics</h1>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("disk_size")}>Disk Size</th> <p className="text-muted-foreground">
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("core_count")}>Core Count</th> Overview of container installations and system statistics.
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("ram_size")}>RAM Size</th> </p>
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("method")}>Method</th> </div>
<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> {/* Widgets */}
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("created_at")}>Created At</th> <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
</tr> <Card>
</thead> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<tbody> <CardTitle className="text-sm font-medium">Total Created</CardTitle>
{sortedData.map((item, index) => ( <Box className="h-4 w-4 text-muted-foreground" />
<tr key={index}> </CardHeader>
<td className="px-4 py-2 border-b"> <CardContent>
{item.status === "done" <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
? ( ? (
"✔️" <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>
) )
: item.status === "failed" : sortedData.length > 0
? ( ? (
"❌" sortedData.map((item, idx) => (
) <TableRow key={`${item.id}-${idx}`}>
: item.status === "installing" <TableCell>
? ( {item.status === "done"
"🔄" ? (
) <Badge className="text-green-500/75 border-green-500/75">
: ( Success
item.status </Badge>
)} )
</td> : item.status === "failed"
<td className="px-4 py-2 border-b"> ? (
{item.type === "lxc" <Badge className="text-red-500/75 border-red-500/75">
? ( Failed
"📦" </Badge>
) )
: item.type === "vm" : 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.type <TableRow>
<TableCell colSpan={8} className="h-24 text-center">
No results found.
</TableCell>
</TableRow>
)} )}
</td> </TableBody>
<td className="px-4 py-2 border-b">{item.nsapp}</td> </Table>
<td className="px-4 py-2 border-b">{item.os_type}</td> </div>
<td className="px-4 py-2 border-b">{item.os_version}</td>
<td className="px-4 py-2 border-b">{item.disk_size}</td> <div className="flex items-center justify-end space-x-2 py-4">
<td className="px-4 py-2 border-b">{item.core_count}</td> <Button
<td className="px-4 py-2 border-b">{item.ram_size}</td> variant="outline"
<td className="px-4 py-2 border-b">{item.method}</td> size="sm"
<td className="px-4 py-2 border-b">{item.pve_version}</td> onClick={() => setCurrentPage(prev => Math.max(prev - 1, 1))}
<td className="px-4 py-2 border-b">{item.error}</td> disabled={currentPage === 1 || loading}
<td className="px-4 py-2 border-b">{formatDate(item.created_at)}</td> >
</tr> <ChevronLeft className="mr-2 h-4 w-4" />
))} Previous
</tbody> </Button>
</table> <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>
</div> </div>
</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> </div>
); );
}; }
export default DataFetcher;

View File

@@ -1,199 +0,0 @@
"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

@@ -0,0 +1,369 @@
"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

@@ -0,0 +1,48 @@
"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

@@ -290,7 +290,7 @@ GEO_DIR="${INSTALL_DIR}/geodata"
mkdir -p "$INSTALL_DIR" mkdir -p "$INSTALL_DIR"
mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache} mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache}
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v2.2.3" "$SRC_DIR" fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v2.3.1" "$SRC_DIR"
msg_info "Installing ${APPLICATION} (patience)" msg_info "Installing ${APPLICATION} (patience)"

View File

@@ -17,7 +17,7 @@ msg_info "Installing Dependencies"
$STD apt install -y fping $STD apt install -y fping
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
PHP_VERSION="8.3" PHP_APACHE="YES" PHP_FPM="YES" PHP_MODULE="mysql,gmp,snmp,ldap,apcu" setup_php PHP_VERSION="8.3" PHP_APACHE="YES" PHP_FPM="YES" PHP_MODULE="pdo,pdo-mysql,gmp,snmp,ldap,apcu" setup_php
msg_info "Installing PHP-PEAR" msg_info "Installing PHP-PEAR"
$STD apt install -y \ $STD apt install -y \

View File

@@ -13,14 +13,17 @@ load_functions
verb_ip6() { verb_ip6() {
set_std_mode # Set STD mode based on VERBOSE set_std_mode # Set STD mode based on VERBOSE
if [ "$IPV6_METHOD" == "none" ] || [ "$DISABLEIPV6" == "yes" ]; then if [ "$IPV6_METHOD" == "disable" ]; then
msg_info "Disabling IPv6" msg_info "Disabling IPv6 (this may affect some services)"
$STD sysctl -w net.ipv6.conf.all.disable_ipv6=1 $STD sysctl -w net.ipv6.conf.all.disable_ipv6=1
$STD sysctl -w net.ipv6.conf.default.disable_ipv6=1 $STD sysctl -w net.ipv6.conf.default.disable_ipv6=1
$STD sysctl -w net.ipv6.conf.lo.disable_ipv6=1 $STD sysctl -w net.ipv6.conf.lo.disable_ipv6=1
echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf mkdir -p /etc/sysctl.d
echo "net.ipv6.conf.default.disable_ipv6 = 1" >>/etc/sysctl.conf $STD tee /etc/sysctl.d/99-disable-ipv6.conf >/dev/null <<EOF
echo "net.ipv6.conf.lo.disable_ipv6 = 1" >>/etc/sysctl.conf net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
EOF
$STD rc-update add sysctl default $STD rc-update add sysctl default
msg_ok "Disabled IPv6" msg_ok "Disabled IPv6"
fi fi

View File

@@ -627,11 +627,12 @@ advanced_settings() {
# IPv6 Address Management selection # IPv6 Address Management selection
while true; do while true; do
IPV6_METHOD=$(whiptail --backtitle "Proxmox VE Helper Scripts" --menu \ IPV6_METHOD=$(whiptail --backtitle "Proxmox VE Helper Scripts" --menu \
"Select IPv6 Address Management Type:" 15 58 4 \ "Select IPv6 Address Management Type:" 16 70 5 \
"auto" "SLAAC/AUTO (recommended, default)" \ "auto" "SLAAC/AUTO (recommended) - Dynamic IPv6 from network" \
"dhcp" "DHCPv6" \ "dhcp" "DHCPv6 - DHCP-assigned IPv6 address" \
"static" "Static (manual entry)" \ "static" "Static - Manual IPv6 address configuration" \
"none" "Disabled" \ "none" "None - No IPv6 assignment (most containers)" \
"disable" "Fully Disabled - (breaks some services)" \
--default-item "auto" 3>&1 1>&2 2>&3) --default-item "auto" 3>&1 1>&2 2>&3)
[ $? -ne 0 ] && exit_script [ $? -ne 0 ] && exit_script
@@ -680,7 +681,15 @@ advanced_settings() {
break break
;; ;;
none) none)
echo -e "${NETWORK}${BOLD}${DGN}IPv6: ${BGN}Disabled${CL}" echo -e "${NETWORK}${BOLD}${DGN}IPv6: ${BGN}None${CL}"
IPV6_ADDR="none"
IPV6_GATE=""
break
;;
disable)
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox \
"⚠️ WARNING - FULLY DISABLE IPv6:\n\nThis will completely disable IPv6 inside the container via sysctl.\n\nSide Effects:\n • Services requiring IPv6 will fail\n • Localhost IPv6 (::1) will not work\n • Some applications may not start\n\nOnly use if you have a specific reason to completely disable IPv6.\n\nFor most use cases, select 'None' instead." 14 70
echo -e "${NETWORK}${BOLD}${DGN}IPv6: ${BGN}Fully Disabled (IPv6 disabled via sysctl)${CL}"
IPV6_ADDR="none" IPV6_ADDR="none"
IPV6_GATE="" IPV6_GATE=""
break break

View File

@@ -15,12 +15,16 @@ load_functions
verb_ip6() { verb_ip6() {
set_std_mode # Set STD mode based on VERBOSE set_std_mode # Set STD mode based on VERBOSE
if [ "$IPV6_METHOD" == "none" ] || [ "$DISABLEIPV6" == "yes" ]; then if [ "$IPV6_METHOD" == "disable" ]; then
msg_info "Disabling IPv6" msg_info "Disabling IPv6 (this may affect some services)"
$STD echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf mkdir -p /etc/sysctl.d
$STD echo "net.ipv6.conf.default.disable_ipv6 = 1" >>/etc/sysctl.conf $STD tee /etc/sysctl.d/99-disable-ipv6.conf >/dev/null <<EOF
$STD echo "net.ipv6.conf.lo.disable_ipv6 = 1" >>/etc/sysctl.conf # Disable IPv6 (set by community-scripts)
$STD sysctl -p net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
EOF
$STD sysctl -p /etc/sysctl.d/99-disable-ipv6.conf
msg_ok "Disabled IPv6" msg_ok "Disabled IPv6"
fi fi
} }

View File

@@ -3628,59 +3628,57 @@ function setup_php() {
local CURRENT_PHP="" local CURRENT_PHP=""
CURRENT_PHP=$(is_tool_installed "php" 2>/dev/null) || true CURRENT_PHP=$(is_tool_installed "php" 2>/dev/null) || true
# Scenario 1: Already at target version - just update packages # CRITICAL: If wrong version is installed, remove it FIRST before any pinning
if [[ -n "$CURRENT_PHP" && "$CURRENT_PHP" == "$PHP_VERSION" ]]; then if [[ -n "$CURRENT_PHP" && "$CURRENT_PHP" != "$PHP_VERSION" ]]; then
msg_info "Update PHP $PHP_VERSION" msg_info "Removing conflicting PHP ${CURRENT_PHP} (need ${PHP_VERSION})"
stop_all_services "php.*-fpm"
# Ensure Sury repo is available $STD apt-get purge -y "php*" 2>/dev/null || true
if [[ ! -f /etc/apt/sources.list.d/php.sources ]]; then $STD apt-get autoremove -y 2>/dev/null || true
manage_tool_repository "php" "$PHP_VERSION" "" "https://packages.sury.org/debsuryorg-archive-keyring.deb" || {
msg_error "Failed to setup PHP repository"
return 1
}
fi
ensure_apt_working || return 1
# Perform upgrade with retry logic (non-fatal if fails)
upgrade_packages_with_retry "php${PHP_VERSION}" || true
cache_installed_version "php" "$PHP_VERSION"
msg_ok "Update PHP $PHP_VERSION"
else
# Scenario 2: Different version installed - clean upgrade
if [[ -n "$CURRENT_PHP" && "$CURRENT_PHP" != "$PHP_VERSION" ]]; then
msg_info "Upgrade PHP from $CURRENT_PHP to $PHP_VERSION"
# Stop and disable ALL PHP-FPM versions
stop_all_services "php.*-fpm"
remove_old_tool_version "php"
else
msg_info "Setup PHP $PHP_VERSION"
fi
# Prepare repository (cleanup + validation)
prepare_repository_setup "php" "deb.sury.org-php" || {
msg_error "Failed to prepare PHP repository"
return 1
}
# Setup Sury repository
manage_tool_repository "php" "$PHP_VERSION" "" "https://packages.sury.org/debsuryorg-archive-keyring.deb" || {
msg_error "Failed to setup PHP repository"
return 1
}
ensure_apt_working || return 1
fi fi
# Build module list # NOW create pinning for the desired version
mkdir -p /etc/apt/preferences.d
cat <<EOF >/etc/apt/preferences.d/php-pin
Package: php${PHP_VERSION}*
Pin: version ${PHP_VERSION}.*
Pin-Priority: 1001
Package: php[0-9].*
Pin: release o=packages.sury.org-php
Pin-Priority: -1
EOF
# Setup repository
prepare_repository_setup "php" "deb.sury.org-php" || {
msg_error "Failed to prepare PHP repository"
return 1
}
manage_tool_repository "php" "$PHP_VERSION" "" "https://packages.sury.org/debsuryorg-archive-keyring.deb" || {
msg_error "Failed to setup PHP repository"
return 1
}
ensure_apt_working || return 1
$STD apt-get update
# Get available PHP version from repository
local AVAILABLE_PHP_VERSION=""
AVAILABLE_PHP_VERSION=$(apt-cache show "php${PHP_VERSION}" 2>/dev/null | grep -m1 "^Version:" | awk '{print $2}' | cut -d- -f1) || true
if [[ -z "$AVAILABLE_PHP_VERSION" ]]; then
msg_error "PHP ${PHP_VERSION} not found in configured repositories"
return 1
fi
# Build module list - without version pinning (preferences.d handles it)
local MODULE_LIST="php${PHP_VERSION}" local MODULE_LIST="php${PHP_VERSION}"
IFS=',' read -ra MODULES <<<"$COMBINED_MODULES" IFS=',' read -ra MODULES <<<"$COMBINED_MODULES"
for mod in "${MODULES[@]}"; do for mod in "${MODULES[@]}"; do
if apt-cache show "php${PHP_VERSION}-${mod}" >/dev/null 2>&1; then MODULE_LIST+=" php${PHP_VERSION}-${mod}"
MODULE_LIST+=" php${PHP_VERSION}-${mod}"
fi
done done
if [[ "$PHP_FPM" == "YES" ]]; then if [[ "$PHP_FPM" == "YES" ]]; then
MODULE_LIST+=" php${PHP_VERSION}-fpm" MODULE_LIST+=" php${PHP_VERSION}-fpm"
fi fi
@@ -3688,18 +3686,52 @@ function setup_php() {
# install apache2 with PHP support if requested # install apache2 with PHP support if requested
if [[ "$PHP_APACHE" == "YES" ]]; then if [[ "$PHP_APACHE" == "YES" ]]; then
if ! dpkg -l 2>/dev/null | grep -q "libapache2-mod-php${PHP_VERSION}"; then if ! dpkg -l 2>/dev/null | grep -q "libapache2-mod-php${PHP_VERSION}"; then
install_packages_with_retry "apache2" "libapache2-mod-php${PHP_VERSION}" || { msg_info "Installing Apache with PHP ${PHP_VERSION} module"
msg_error "Failed to install Apache with PHP module" install_packages_with_retry "apache2" || {
msg_error "Failed to install Apache"
return 1 return 1
} }
install_packages_with_retry "libapache2-mod-php${PHP_VERSION}" || {
msg_warn "Failed to install libapache2-mod-php${PHP_VERSION}, continuing without Apache module"
}
fi fi
fi fi
# Install PHP packages with retry logic # Install PHP packages (pinning via preferences.d ensures correct version)
install_packages_with_retry $MODULE_LIST || { msg_info "Installing PHP ${PHP_VERSION} packages"
msg_error "Failed to install PHP packages" if ! install_packages_with_retry $MODULE_LIST; then
return 1 msg_warn "Failed to install PHP packages, attempting individual installation"
}
# Install main package first (critical)
install_packages_with_retry "php${PHP_VERSION}" || {
msg_error "Failed to install php${PHP_VERSION}"
return 1
}
# Try to install Apache module individually if requested
if [[ "$PHP_APACHE" == "YES" ]]; then
install_packages_with_retry "libapache2-mod-php${PHP_VERSION}" || {
msg_warn "Could not install libapache2-mod-php${PHP_VERSION}"
}
fi
# Try to install modules individually - skip those that don't exist
for pkg in "${MODULES[@]}"; do
if apt-cache search "^php${PHP_VERSION}-${pkg}\$" 2>/dev/null | grep -q "^php${PHP_VERSION}-${pkg}"; then
install_packages_with_retry "php${PHP_VERSION}-${pkg}" || {
msg_warn "Could not install php${PHP_VERSION}-${pkg}"
}
fi
done
if [[ "$PHP_FPM" == "YES" ]]; then
if apt-cache search "^php${PHP_VERSION}-fpm\$" 2>/dev/null | grep -q "^php${PHP_VERSION}-fpm"; then
install_packages_with_retry "php${PHP_VERSION}-fpm" || {
msg_warn "Could not install php${PHP_VERSION}-fpm"
}
fi
fi
fi
cache_installed_version "php" "$PHP_VERSION" cache_installed_version "php" "$PHP_VERSION"
# Patch all relevant php.ini files # Patch all relevant php.ini files
@@ -3735,7 +3767,24 @@ function setup_php() {
fi fi
fi fi
msg_ok "Setup PHP $PHP_VERSION" # Verify PHP installation - critical check
if ! command -v php >/dev/null 2>&1; then
msg_error "PHP installation verification failed - php command not found"
return 1
fi
local INSTALLED_VERSION=$(php -v 2>/dev/null | awk '/^PHP/{print $2}' | cut -d. -f1,2)
# Critical: if major.minor doesn't match, fail and cleanup
if [[ "$INSTALLED_VERSION" != "$PHP_VERSION" ]]; then
msg_error "PHP version mismatch: requested ${PHP_VERSION} but got ${INSTALLED_VERSION}"
msg_error "This indicates a critical package installation issue"
# Don't cache wrong version
return 1
fi
cache_installed_version "php" "$INSTALLED_VERSION"
msg_ok "Setup PHP ${INSTALLED_VERSION}"
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -4439,7 +4488,7 @@ function setup_rust() {
} }
# Update to latest patch version # Update to latest patch version
$STD rustup update "$RUST_TOOLCHAIN" || true $STD rustup update "$RUST_TOOLCHAIN" </dev/null || true
# Ensure PATH is updated for current shell session # Ensure PATH is updated for current shell session
export PATH="$CARGO_BIN:$PATH" export PATH="$CARGO_BIN:$PATH"