diff --git a/CHANGELOG.md b/CHANGELOG.md index a36f2053a..a28f8425d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,45 @@ > [!CAUTION] Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit the project's popularity for potentially malicious purposes. +## 2025-11-23 + +### πŸš€ Updated Scripts + + - #### 🐞 Bug Fixes + + - [LibreNMS] Correcting mariadb sed string for Debian 13 default in install/librenms-install.sh, website config for Debian 13 #9369 [@htmlspinnr](https://github.com/htmlspinnr) ([#9370](https://github.com/community-scripts/ProxmoxVE/pull/9370)) + - fix: Snipe-IT update check failure [@ruanmed](https://github.com/ruanmed) ([#9371](https://github.com/community-scripts/ProxmoxVE/pull/9371)) + + - #### πŸ”§ Refactor + + - Update glpi-install.sh to remove install.php [@CrazyWolf13](https://github.com/CrazyWolf13) ([#9378](https://github.com/community-scripts/ProxmoxVE/pull/9378)) + +## 2025-11-22 + +### πŸ†• New Scripts + + - Upgopher ([#9360](https://github.com/community-scripts/ProxmoxVE/pull/9360)) + +### πŸš€ Updated Scripts + + - Expand support to Proxmox VE 9.1 in VM scripts [@MickLesk](https://github.com/MickLesk) ([#9351](https://github.com/community-scripts/ProxmoxVE/pull/9351)) + + - #### 🐞 Bug Fixes + + - fix: Snipe-IT install and update failure due to new repository url [@ruanmed](https://github.com/ruanmed) ([#9362](https://github.com/community-scripts/ProxmoxVE/pull/9362)) + - glpi - allow migration of existing databases [@moodyblue](https://github.com/moodyblue) ([#9353](https://github.com/community-scripts/ProxmoxVE/pull/9353)) + + - #### ✨ New Features + + - Refactor cleanup steps to use cleanup_lxc function (install/ Folder) [@MickLesk](https://github.com/MickLesk) ([#9354](https://github.com/community-scripts/ProxmoxVE/pull/9354)) + - Remove redundant cleanup steps from update scripts (ct/ Folder) [@MickLesk](https://github.com/MickLesk) ([#9359](https://github.com/community-scripts/ProxmoxVE/pull/9359)) + +### 🌐 Website + + - #### ✨ New Features + + - Refactor /data page [@BramSuurdje](https://github.com/BramSuurdje) ([#9343](https://github.com/community-scripts/ProxmoxVE/pull/9343)) + ## 2025-11-21 ### πŸš€ Updated Scripts diff --git a/ct/2fauth.sh b/ct/2fauth.sh index ba6195aa4..99a4eb008 100644 --- a/ct/2fauth.sh +++ b/ct/2fauth.sh @@ -57,15 +57,6 @@ function update_script() { $STD composer install --no-dev --prefer-dist php artisan 2fauth:install $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!" fi exit diff --git a/ct/adventurelog.sh b/ct/adventurelog.sh index 2902c76cf..bb9d90293 100644 --- a/ct/adventurelog.sh +++ b/ct/adventurelog.sh @@ -62,6 +62,7 @@ function update_script() { cd /opt/adventurelog/frontend || exit $STD pnpm i $STD pnpm build + rm -rf /opt/adventurelog-backup msg_ok "Updated ${APP}" msg_info "Starting Services" @@ -69,10 +70,6 @@ function update_script() { systemctl start adventurelog-backend systemctl start adventurelog-frontend msg_ok "Services Started" - - msg_info "Cleaning Up" - rm -rf /opt/adventurelog-backup - msg_ok "Cleaned" msg_ok "Updated successfully!" fi exit diff --git a/ct/apache-tika.sh b/ct/apache-tika.sh index 952d92a7b..29796bfe8 100755 --- a/ct/apache-tika.sh +++ b/ct/apache-tika.sh @@ -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" mv --force tika-server-standard.jar tika-server-standard-prev-version.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 msg_ok "Updated ${APP} to v${RELEASE}" msg_info "Starting Service" systemctl start apache-tika 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!" else msg_ok "No update required. ${APP} is already at v${RELEASE}" diff --git a/ct/authelia.sh b/ct/authelia.sh index 24b1ab0b9..d4717b4be 100644 --- a/ct/authelia.sh +++ b/ct/authelia.sh @@ -31,15 +31,11 @@ function update_script() { fi if check_for_gh_release "authelia" "authelia/authelia"; then - $STD apt-get update - $STD apt-get -y upgrade + $STD apt update + $STD apt -y upgrade 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!" fi exit diff --git a/ct/backrest.sh b/ct/backrest.sh index f4b098055..05aae23dd 100644 --- a/ct/backrest.sh +++ b/ct/backrest.sh @@ -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" tar xzf $temp_file -C /opt/backrest/bin chmod +x /opt/backrest/bin/backrest + rm -f "$temp_file" echo "${RELEASE}" >/opt/${APP}_version.txt msg_ok "Updated ${APP} to ${RELEASE}" msg_info "Starting Service" systemctl start backrest msg_ok "Started Service" - - msg_info "Cleaning up" - rm -f "$temp_file" - msg_ok "Cleaned up" msg_ok "Updated successfully!" else msg_ok "No update required. ${APP} is already at ${RELEASE}" diff --git a/ct/baikal.sh b/ct/baikal.sh index 5e0fab8c4..0d4364e1f 100644 --- a/ct/baikal.sh +++ b/ct/baikal.sh @@ -47,15 +47,12 @@ function update_script() { chmod -R 755 /opt/baikal/ cd /opt/baikal $STD composer install + rm -rf /opt/baikal-backup msg_ok "Configured Baikal" msg_info "Starting Service" systemctl start apache2 msg_ok "Started Service" - - msg_info "Cleaning up" - rm -rf /opt/baikal-backup - msg_ok "Cleaned" msg_ok "Updated successfully!" fi exit diff --git a/ct/bar-assistant.sh b/ct/bar-assistant.sh index 858c4599f..5f4dc4438 100644 --- a/ct/bar-assistant.sh +++ b/ct/bar-assistant.sh @@ -54,15 +54,12 @@ function update_script() { $STD php artisan route:cache $STD php artisan event:cache chown -R www-data:www-data /opt/bar-assistant + rm -rf /opt/bar-assistant-backup msg_ok "Updated Bar-Assistant" msg_info "Starting nginx" systemctl start nginx msg_ok "Started nginx" - - msg_info "Cleaning up" - rm -rf /opt/bar-assistant-backup - msg_ok "Cleaned" fi 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 $STD npm install $STD npm run build + rm -rf /opt/vue-salt-rim-backup msg_ok "Updated Vue Salt Rim" msg_info "Starting nginx" systemctl start nginx msg_ok "Started nginx" - - msg_info "Cleaning up" - rm -rf /opt/vue-salt-rim-backup - msg_ok "Cleaned" fi if check_for_gh_release "meilisearch" "meilisearch/meilisearch"; then diff --git a/ct/bookstack.sh b/ct/bookstack.sh index dab902519..d78bc74c8 100644 --- a/ct/bookstack.sh +++ b/ct/bookstack.sh @@ -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 775 /opt/bookstack/storage /opt/bookstack/bootstrap/cache /opt/bookstack/public/uploads chmod -R 640 /opt/bookstack/.env + rm -rf /opt/bookstack-backup msg_ok "Configured BookStack" msg_info "Starting Apache2" systemctl start apache2 msg_ok "Started Apache2" - - msg_info "Cleaning Up" - rm -rf /opt/bookstack-backup - msg_ok "Cleaned" msg_ok "Updated successfully!" fi exit diff --git a/ct/dispatcharr.sh b/ct/dispatcharr.sh index 14cc19a56..cf9bea3b3 100644 --- a/ct/dispatcharr.sh +++ b/ct/dispatcharr.sh @@ -109,6 +109,7 @@ function update_script() { fi $STD uv run python manage.py migrate --noinput $STD uv run python manage.py collectstatic --noinput + rm -f /tmp/dispatcharr_db_*.sql msg_ok "Migrations Complete" msg_info "Starting Services" @@ -117,10 +118,6 @@ function update_script() { systemctl start dispatcharr-celerybeat systemctl start dispatcharr-daphne msg_ok "Started Services" - - msg_info "Cleaning up" - rm -f /tmp/dispatcharr_db_*.sql - msg_ok "Cleanup completed" msg_ok "Updated successfully!" fi exit diff --git a/ct/docker.sh b/ct/docker.sh index 7a74fd8ed..f5b9b8c8e 100644 --- a/ct/docker.sh +++ b/ct/docker.sh @@ -76,11 +76,6 @@ function update_script() { portainer/agent msg_ok "Updated Portainer Agent" fi - - msg_info "Cleaning up" - $STD apt-get -y autoremove - $STD apt-get -y autoclean - msg_ok "Cleanup complete" msg_ok "Updated successfully!" exit } diff --git a/ct/documenso.sh b/ct/documenso.sh index bd0eec6f8..3eff7ff45 100644 --- a/ct/documenso.sh +++ b/ct/documenso.sh @@ -50,16 +50,13 @@ function update_script() { $STD turbo run build --filter=@documenso/remix $STD npm run prisma:migrate-deploy $STD turbo daemon stop + rm -rf /opt/v${RELEASE}.zip echo "${RELEASE}" >/opt/${APP}_version.txt msg_ok "Updated ${APP}" msg_info "Starting Service" systemctl start documenso msg_ok "Started Service" - - msg_info "Cleaning Up" - rm -rf /opt/v${RELEASE}.zip - msg_ok "Cleaned" msg_ok "Updated successfully!" else msg_ok "No update required. ${APP} is already at ${RELEASE}" diff --git a/ct/emqx.sh b/ct/emqx.sh index b274fe187..49d591614 100644 --- a/ct/emqx.sh +++ b/ct/emqx.sh @@ -47,16 +47,13 @@ function update_script() { msg_info "Installing EMQX" $STD apt-get install -y "$DEB_FILE" + rm -f "$DEB_FILE" + echo "$RELEASE" >~/.emqx msg_ok "Installed EMQX v${RELEASE}" msg_info "Starting EMQX" systemctl start emqx - echo "$RELEASE" >~/.emqx msg_ok "Started EMQX" - - msg_info "Cleaning Up" - rm -f "$DEB_FILE" - msg_ok "Cleanup Completed" msg_ok "Updated successfully!" else msg_ok "No update required. EMQX is already at v${RELEASE}" diff --git a/ct/fileflows.sh b/ct/fileflows.sh index 3417d5d65..51dcd905e 100644 --- a/ct/fileflows.sh +++ b/ct/fileflows.sh @@ -48,16 +48,13 @@ function update_script() { temp_file=$(mktemp) curl -fsSL https://fileflows.com/downloads/zip -o "$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_info "Starting Service" systemctl start fileflows msg_ok "Started Service" - - msg_info "Cleaning Up" - rm -rf "$temp_file" - rm -rf "$backup_filename" - msg_ok "Cleanup Completed" msg_ok "Updated successfully!" else msg_ok "No update required. ${APP} is already at latest version" diff --git a/ct/ghostfolio.sh b/ct/ghostfolio.sh index 56a8445e0..1929419fe 100644 --- a/ct/ghostfolio.sh +++ b/ct/ghostfolio.sh @@ -56,10 +56,6 @@ function update_script() { msg_info "Starting Service" systemctl start ghostfolio msg_ok "Started Service" - - msg_info "Cleaning Up" - $STD npm cache clean --force - msg_ok "Cleanup Completed" msg_ok "Updated successfully!" fi exit diff --git a/ct/headers/upgopher b/ct/headers/upgopher new file mode 100644 index 000000000..e1126d09c --- /dev/null +++ b/ct/headers/upgopher @@ -0,0 +1,6 @@ + __ __ __ + / / / /___ ____ _____ ____ / /_ ___ _____ + / / / / __ \/ __ `/ __ \/ __ \/ __ \/ _ \/ ___/ +/ /_/ / /_/ / /_/ / /_/ / /_/ / / / / __/ / +\____/ .___/\__, /\____/ .___/_/ /_/\___/_/ + /_/ /____/ /_/ diff --git a/ct/jellyseerr.sh b/ct/jellyseerr.sh index e6f53c275..bda9c92e6 100644 --- a/ct/jellyseerr.sh +++ b/ct/jellyseerr.sh @@ -20,62 +20,57 @@ color catch_errors function update_script() { - header_info - check_container_storage - check_container_resources + header_info + check_container_storage + check_container_resources - if [[ ! -d /opt/jellyseerr ]]; then - msg_error "No ${APP} Installation Found!" - exit - fi + if [[ ! -d /opt/jellyseerr ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi - if [ "$(node -v | cut -c2-3)" -ne 22 ]; then - 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 - msg_ok "Updating Node.js Repository" + if [ "$(node -v | cut -c2-3)" -ne 22 ]; then + 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 + msg_ok "Updating Node.js Repository" - msg_info "Updating Packages" - $STD apt-get update - $STD apt-get -y upgrade - msg_ok "Updating Packages" + msg_info "Updating Packages" + $STD apt-get update + $STD apt-get -y upgrade + msg_ok "Updating Packages" + fi - msg_info "Cleaning up" - apt-get -y autoremove - apt-get -y autoclean - msg_ok "Cleaning up" - fi + cd /opt/jellyseerr + output=$(git pull --no-rebase) - cd /opt/jellyseerr - output=$(git pull --no-rebase) + pnpm_current=$(pnpm --version 2>/dev/null) + pnpm_desired=$(grep -Po '"pnpm":\s*"\K[^"]+' /opt/jellyseerr/package.json) - pnpm_current=$(pnpm --version 2>/dev/null) - pnpm_desired=$(grep -Po '"pnpm":\s*"\K[^"]+' /opt/jellyseerr/package.json) + if [ -z "$pnpm_current" ]; then + 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_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 + msg_info "Updating $APP" + if echo "$output" | grep -q "Already up to date."; then + msg_ok "$APP is already up to date." + exit + fi - msg_info "Updating $APP" - if echo "$output" | grep -q "Already up to date."; then - msg_ok "$APP is already up to date." - exit - fi + systemctl stop jellyseerr + 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 - systemctl stop jellyseerr - 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 </etc/systemd/system/jellyseerr.service + cat </etc/systemd/system/jellyseerr.service [Unit] Description=jellyseerr Service After=network.target @@ -91,10 +86,10 @@ ExecStart=/usr/bin/node dist/index.js WantedBy=multi-user.target EOF - systemctl daemon-reload - systemctl start jellyseerr - msg_ok "Updated $APP" - exit + systemctl daemon-reload + systemctl start jellyseerr + msg_ok "Updated $APP" + exit } start diff --git a/ct/keycloak.sh b/ct/keycloak.sh index a4907bab5..5ede59bc2 100644 --- a/ct/keycloak.sh +++ b/ct/keycloak.sh @@ -49,15 +49,12 @@ function update_script() { cp -a keycloak.old/conf/. keycloak/conf/ cp -a keycloak.old/providers/. keycloak/providers/ 2>/dev/null || true cp -a keycloak.old/themes/. keycloak/themes/ 2>/dev/null || true + rm -rf keycloak.old msg_ok "Updated Keycloak" msg_info "Restarting Service" systemctl restart keycloak msg_ok "Restarted Service" - - msg_info "Cleaning up" - rm -rf keycloak.old - msg_ok "Cleanup complete" msg_ok "Updated successfully!" fi exit diff --git a/ct/koillection.sh b/ct/koillection.sh index c7ceae2f5..473f9b38e 100644 --- a/ct/koillection.sh +++ b/ct/koillection.sh @@ -50,15 +50,12 @@ function update_script() { $STD yarn install $STD yarn build chown -R www-data:www-data /opt/koillection/public/uploads + rm -r /opt/koillection-backup msg_ok "Updated Koillection" msg_info "Starting Service" systemctl start apache2 msg_ok "Started Service" - - msg_info "Cleaning up" - rm -r /opt/koillection-backup - msg_ok "Cleaned" msg_ok "Updated Successfully!" fi exit diff --git a/ct/linkwarden.sh b/ct/linkwarden.sh index d53138c7e..ebae99369 100644 --- a/ct/linkwarden.sh +++ b/ct/linkwarden.sh @@ -52,17 +52,14 @@ function update_script() { $STD yarn web:build $STD yarn prisma:deploy [ -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_info "Starting Service" systemctl start linkwarden 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!" fi exit diff --git a/ct/listmonk.sh b/ct/listmonk.sh index 64869e000..4f828b574 100644 --- a/ct/listmonk.sh +++ b/ct/listmonk.sh @@ -42,15 +42,12 @@ function update_script() { mv /opt/listmonk-backup/config.toml /opt/listmonk/config.toml mv /opt/listmonk-backup/uploads /opt/listmonk/uploads $STD /opt/listmonk/listmonk --upgrade --yes --config /opt/listmonk/config.toml + rm -rf /opt/listmonk-backup/ msg_ok "Configured listmonk" msg_info "Starting Service" systemctl start listmonk msg_ok "Started Service" - - msg_info "Cleaning up" - rm -rf /opt/listmonk-backup/ - msg_ok "Cleaned" msg_ok "Updated successfully!" fi exit diff --git a/ct/lubelogger.sh b/ct/lubelogger.sh index d6076e0e9..d33f00e01 100644 --- a/ct/lubelogger.sh +++ b/ct/lubelogger.sh @@ -53,15 +53,12 @@ function update_script() { msg_info "Configuring LubeLogger" chmod 700 /opt/lubelogger/CarCareTracker cp -rf /tmp/lubeloggerData/* /opt/lubelogger/ + rm -rf /tmp/lubeloggerData msg_ok "Configured LubeLogger" msg_info "Starting Service" systemctl start lubelogger msg_ok "Started Service" - - msg_info "Cleaning up" - rm -rf /tmp/lubeloggerData - msg_ok "Cleaned" msg_ok "Updated successfully!" fi exit diff --git a/ct/lyrionmusicserver.sh b/ct/lyrionmusicserver.sh index e074bd38a..f10fbf401 100644 --- a/ct/lyrionmusicserver.sh +++ b/ct/lyrionmusicserver.sh @@ -38,15 +38,9 @@ function update_script() { curl -fsSL -o "$DEB_FILE" "$DEB_URL" $STD apt install "$DEB_FILE" -y systemctl restart lyrion + $STD rm -f "$DEB_FILE" echo "${RELEASE}" >/opt/${APP}_version.txt 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!" else msg_ok "$APP is already up to date (${RELEASE})" diff --git a/ct/minio.sh b/ct/minio.sh index 5fb460164..4da24b0af 100644 --- a/ct/minio.sh +++ b/ct/minio.sh @@ -55,17 +55,13 @@ function update_script() { 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 chmod +x /usr/local/bin/minio + rm -f /usr/local/bin/minio_bak echo "${RELEASE}" >/opt/${APP}_version.txt msg_ok "Updated ${APP}" msg_info "Starting Service" systemctl start minio msg_ok "Started Service" - - msg_info "Cleaning up" - rm -f /usr/local/bin/minio_bak - msg_ok "Cleaned" - msg_ok "Updated successfully!" else msg_ok "No update required. ${APP} is already at ${RELEASE}" diff --git a/ct/monica.sh b/ct/monica.sh index 86e7f08c3..42ce3fc50 100644 --- a/ct/monica.sh +++ b/ct/monica.sh @@ -52,15 +52,12 @@ function update_script() { $STD php artisan monica:update --force chown -R www-data:www-data /opt/monica chmod -R 775 /opt/monica/storage + rm -r /opt/monica-backup msg_ok "Configured monica" msg_info "Starting Service" systemctl start apache2 msg_ok "Started Service" - - msg_info "Cleaning up" - rm -r /opt/monica-backup - msg_ok "Cleaned" msg_ok "Updated successfully!" fi exit diff --git a/ct/netbox.sh b/ct/netbox.sh index da65be321..5dbbf5784 100644 --- a/ct/netbox.sh +++ b/ct/netbox.sh @@ -57,17 +57,14 @@ function update_script() { fi $STD /opt/netbox/upgrade.sh + rm -r "/opt/v${RELEASE}.zip" + rm -r /opt/netbox-backup echo "${RELEASE}" >/opt/${APP}_version.txt msg_ok "Updated $APP to v${RELEASE}" msg_info "Starting Service" systemctl start netbox netbox-rq 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!" else msg_ok "No update required. ${APP} is already at v${RELEASE}" diff --git a/ct/nextpvr.sh b/ct/nextpvr.sh index 43f3c9d35..adb3b17fa 100644 --- a/ct/nextpvr.sh +++ b/ct/nextpvr.sh @@ -21,37 +21,34 @@ color catch_errors function update_script() { - header_info - check_container_storage - check_container_resources - if [[ ! -d /opt/nextpvr ]]; then - 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!" + header_info + check_container_storage + check_container_resources + if [[ ! -d /opt/nextpvr ]]; then + 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 + 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 diff --git a/ct/nxwitness.sh b/ct/nxwitness.sh index 25a011a4b..626be2501 100644 --- a/ct/nxwitness.sh +++ b/ct/nxwitness.sh @@ -42,17 +42,13 @@ function update_script() { export DEBIAN_FRONTEND=noninteractive export DEBCONF_NOWARNINGS=yes $STD dpkg -i nxwitness-server-$RELEASE-linux_x64.deb + rm -f /tmp/nxwitness-server-$RELEASE-linux_x64.deb echo "${RELEASE}" >/opt/${APP}_version.txt msg_ok "Updated ${APP}" msg_info "Starting Service" systemctl start networkoptix-root-tool networkoptix-mediaserver msg_ok "Started Service" - - msg_info "Cleaning up" - rm -f /tmp/nxwitness-server-$RELEASE-linux_x64.deb - msg_ok "Cleaned" - msg_ok "Updated successfully!" else msg_ok "No update required. ${APP} is already at ${RELEASE}" diff --git a/ct/odoo.sh b/ct/odoo.sh index ef6b9eee0..967334990 100644 --- a/ct/odoo.sh +++ b/ct/odoo.sh @@ -50,17 +50,13 @@ function update_script() { 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 $STD apt install -y /opt/odoo.deb + rm -f /opt/odoo.deb echo "$LATEST_VERSION" >/opt/${APP}_version.txt msg_ok "Updated ${APP} to ${LATEST_VERSION}" - msg_info "Starting ${APP} service" + msg_info "Starting Service" systemctl start odoo msg_ok "Started Service" - - msg_info "Cleaning Up" - rm -f /opt/odoo.deb - msg_ok "Cleaned" - msg_ok "Updated successfully!" else msg_ok "No update required. ${APP} is already at ${LATEST_VERSION}" diff --git a/ct/ollama.sh b/ct/ollama.sh index aada56e48..3677be131 100644 --- a/ct/ollama.sh +++ b/ct/ollama.sh @@ -43,16 +43,13 @@ function update_script() { mkdir -p /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 + rm -f "${TMP_TAR}" echo "${RELEASE}" >/opt/Ollama_version.txt msg_ok "Updated Ollama to ${RELEASE}" msg_info "Starting Services" systemctl start ollama msg_ok "Started Services" - - msg_info "Cleaning Up" - rm -f "${TMP_TAR}" - msg_ok "Cleaned" msg_ok "Updated successfully!" else msg_ok "No update required. Ollama is already at ${RELEASE}" diff --git a/ct/onedev.sh b/ct/onedev.sh index b42219a4a..e8694abba 100644 --- a/ct/onedev.sh +++ b/ct/onedev.sh @@ -39,17 +39,14 @@ function update_script() { tar -xzf onedev-latest.tar.gz $STD /opt/onedev-latest/bin/upgrade.sh /opt/onedev 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" msg_ok "Updated ${APP} to v${RELEASE}" msg_info "Starting Service" systemctl start onedev 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!" else msg_ok "No update required. ${APP} is already at v${RELEASE}." diff --git a/ct/paperless-ai.sh b/ct/paperless-ai.sh index 7ccdf9458..5b5031851 100644 --- a/ct/paperless-ai.sh +++ b/ct/paperless-ai.sh @@ -65,17 +65,14 @@ EOF $STD pip install --no-cache-dir -r requirements.txt mkdir -p data/chromadb $STD npm install + rm -rf /opt/v${RELEASE}.zip + rm -rf /opt/paperless-ai_bak echo "${RELEASE}" >/opt/${APP}_version.txt msg_ok "Updated $APP to v${RELEASE}" msg_info "Starting Service" systemctl start paperless-ai 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!" else msg_ok "No update required. ${APP} is already at v${RELEASE}" diff --git a/ct/paperless-gpt.sh b/ct/paperless-gpt.sh index 2f882b305..95c23820a 100644 --- a/ct/paperless-gpt.sh +++ b/ct/paperless-gpt.sh @@ -20,48 +20,45 @@ color catch_errors function update_script() { - header_info - check_container_storage - check_container_resources - if [[ ! -d /opt/paperless-gpt ]]; then - 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 + header_info + check_container_storage + check_container_resources + if [[ ! -d /opt/paperless-gpt ]]; then + 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 . + 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 diff --git a/ct/part-db.sh b/ct/part-db.sh index 46a25a504..e1fefbbb9 100644 --- a/ct/part-db.sh +++ b/ct/part-db.sh @@ -52,17 +52,14 @@ function update_script() { $STD php bin/console cache:clear $STD php bin/console doctrine:migrations:migrate -n 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 msg_ok "Updated $APP to v${RELEASE}" msg_info "Starting Service" systemctl start apache2 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!" else msg_ok "No update required. ${APP} is already at v${RELEASE}" diff --git a/ct/pelican-panel.sh b/ct/pelican-panel.sh index 996416baa..c1a62c87d 100644 --- a/ct/pelican-panel.sh +++ b/ct/pelican-panel.sh @@ -67,6 +67,7 @@ function update_script() { $STD php artisan migrate --seed --force chown -R www-data:www-data /opt/pelican-panel 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 msg_ok "Updated $APP to v${RELEASE}" @@ -74,10 +75,6 @@ function update_script() { $STD php artisan queue:restart $STD php artisan up msg_ok "Started Service" - - msg_info "Cleaning up" - rm -rf "/opt/pelican-panel/panel.tar.gz" - msg_ok "Cleaned" msg_ok "Updated successfully!" else msg_ok "No update required. ${APP} is already at v${RELEASE}" diff --git a/ct/pterodactyl-panel.sh b/ct/pterodactyl-panel.sh index 6bf9eefa0..6f3e2f427 100644 --- a/ct/pterodactyl-panel.sh +++ b/ct/pterodactyl-panel.sh @@ -70,6 +70,7 @@ EOF $STD php artisan migrate --seed --force --no-interaction chown -R www-data:www-data /opt/pterodactyl-panel/* 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 msg_ok "Updated $APP to v${RELEASE}" @@ -77,10 +78,6 @@ EOF $STD php artisan queue:restart $STD php artisan up msg_ok "Started Service" - - msg_info "Cleaning up" - rm -rf "/opt/pterodactyl-panel/panel.tar.gz" - msg_ok "Cleaned" msg_ok "Updated successfully!" else msg_ok "No update required. ${APP} is already at v${RELEASE}" diff --git a/ct/rdtclient.sh b/ct/rdtclient.sh index 687f14945..d625cd840 100755 --- a/ct/rdtclient.sh +++ b/ct/rdtclient.sh @@ -43,14 +43,11 @@ function update_script() { $STD apt remove --purge -y dotnet-sdk-8.0 $STD apt install -y dotnet-sdk-9.0 fi + rm -rf /opt/rdtc-backup msg_info "Starting Service" systemctl start rdtc msg_ok "Started Service" - - msg_info "Cleaning Up" - rm -rf /opt/rdtc-backup - msg_ok "Cleaned" msg_ok "Updated successfully!" fi exit diff --git a/ct/reactive-resume.sh b/ct/reactive-resume.sh index 68ea99299..a1b3e3626 100644 --- a/ct/reactive-resume.sh +++ b/ct/reactive-resume.sh @@ -54,6 +54,7 @@ function update_script() { cd /tmp curl -fsSL https://dl.min.io/server/minio/release/linux-amd64/minio.deb -o minio.deb $STD dpkg -i minio.deb + rm -f /tmp/minio.deb msg_ok "Updated Minio" msg_info "Updating Browserless (Patience)" @@ -75,16 +76,12 @@ function update_script() { $STD npm run build:function $STD npm prune production mv /opt/browserless.env /opt/browserless/.env + rm -f "$brwsr_tmp" msg_ok "Updated Browserless" msg_info "Restarting services" systemctl start minio Reactive-Resume browserless 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!" fi exit diff --git a/ct/revealjs.sh b/ct/revealjs.sh index 7cd03ead5..587caee88 100644 --- a/ct/revealjs.sh +++ b/ct/revealjs.sh @@ -41,15 +41,12 @@ function update_script() { $STD npm install cp -f /opt/index.html /opt/revealjs sed -i '25s/localhost/0.0.0.0/g' /opt/revealjs/gulpfile.js + rm -f /opt/index.html msg_ok "Updated $APP" msg_info "Starting Service" systemctl start revealjs msg_ok "Started Service" - - msg_info "Cleaning Up" - rm -f /opt/index.html - msg_ok "Cleanup Completed" msg_ok "Updated successfully!" fi exit diff --git a/ct/slskd.sh b/ct/slskd.sh index 174d5f388..8e6b3c26f 100644 --- a/ct/slskd.sh +++ b/ct/slskd.sh @@ -61,15 +61,12 @@ function update_script() { $STD pip install -r requirements.txt mv /opt/config.ini.bak /opt/soularr/config.ini mv /opt/run.sh.bak /opt/soularr/run.sh + rm -rf /tmp/main.zip msg_ok "Updated soularr" msg_info "Starting soularr timer" systemctl start soularr.timer msg_ok "Started soularr timer" - - msg_info "Cleaning Up" - rm -rf /tmp/main.zip - msg_ok "Cleanup Completed" exit } diff --git a/ct/snipeit.sh b/ct/snipeit.sh index 3f25fa32e..54aa64706 100644 --- a/ct/snipeit.sh +++ b/ct/snipeit.sh @@ -31,7 +31,7 @@ function update_script() { sed -i '/index index.php;/i \ client_max_body_size 100M;' /etc/nginx/conf.d/snipeit.conf fi - if check_for_gh_release "snipe-it" "snipe/snipe-it"; then + if check_for_gh_release "snipe-it" "grokability/snipe-it"; then msg_info "Stopping Services" systemctl stop nginx msg_ok "Services Stopped" @@ -40,7 +40,7 @@ function update_script() { mv /opt/snipe-it /opt/snipe-it-backup msg_ok "Backup created" - fetch_and_deploy_gh_release "snipe-it" "snipe/snipe-it" "tarball" + fetch_and_deploy_gh_release "snipe-it" "grokability/snipe-it" "tarball" [[ "$(php -v 2>/dev/null)" == PHP\ 8.2* ]] && PHP_VERSION="8.3" PHP_MODULE="common,ctype,ldap,fileinfo,iconv,mysql,soap,xsl" PHP_FPM="YES" setup_php sed -i 's/php8.2/php8.3/g' /etc/nginx/conf.d/snipeit.conf setup_composer diff --git a/ct/spoolman.sh b/ct/spoolman.sh index 0ccc25ee4..b6b7ab8b2 100644 --- a/ct/spoolman.sh +++ b/ct/spoolman.sh @@ -43,17 +43,13 @@ function update_script() { cd spoolman $STD pip3 install -r requirements.txt curl -fsSL "https://raw.githubusercontent.com/Donkie/Spoolman/master/.env.example" -o ".env" + rm -rf /opt/spoolman.zip echo "${RELEASE}" >/opt/${APP}_version.txt msg_ok "Updated ${APP} to ${RELEASE}" msg_info "Starting Service" systemctl start spoolman msg_ok "Started Service" - - msg_info "Cleaning up" - rm -rf /opt/spoolman.zip - msg_ok "Cleaned" - msg_ok "Updated successfully!" else msg_ok "No update required. ${APP} is already at ${RELEASE}" diff --git a/ct/tandoor.sh b/ct/tandoor.sh index 0ffeaac02..dc2b44d12 100644 --- a/ct/tandoor.sh +++ b/ct/tandoor.sh @@ -64,16 +64,13 @@ EOF cd /opt/tandoor $STD /opt/tandoor/.venv/bin/python manage.py migrate $STD /opt/tandoor/.venv/bin/python manage.py collectstatic --no-input + rm -rf /opt/tandoor.bak msg_ok "Updated Trandoor" msg_info "Starting Service" systemctl start tandoor systemctl reload nginx msg_ok "Started Service" - - msg_info "Cleaning Up" - rm -rf /opt/tandoor.bak - msg_ok "Cleanup Completed" msg_ok "Updated successfully!" fi exit diff --git a/ct/tasmocompiler.sh b/ct/tasmocompiler.sh index fb16107f1..b62e665e4 100644 --- a/ct/tasmocompiler.sh +++ b/ct/tasmocompiler.sh @@ -45,16 +45,13 @@ function update_script() { export NODE_OPTIONS=--openssl-legacy-provider $STD npm i $STD yarn build + rm -r "/opt/v${RELEASE}.tar.gz" + echo "${RELEASE}" >/opt/${APP}_version.txt msg_ok "Updated TasmoCompiler" msg_info "Starting Service" systemctl start tasmocompiler 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!" else msg_ok "No update required. ${APP} is already at v${RELEASE}" diff --git a/ct/tdarr.sh b/ct/tdarr.sh index e6f01fac9..299bd2f3f 100644 --- a/ct/tdarr.sh +++ b/ct/tdarr.sh @@ -37,11 +37,8 @@ function update_script() { $STD unzip Tdarr_Updater.zip chmod +x Tdarr_Updater $STD ./Tdarr_Updater - msg_ok "Updated Tdarr" - - msg_info "Cleaning up" rm -rf /opt/tdarr/Tdarr_Updater.zip - msg_ok "Cleaned up" + msg_ok "Updated Tdarr" msg_ok "Updated successfully!" exit } diff --git a/ct/technitiumdns.sh b/ct/technitiumdns.sh index 4ec9e3893..df67e1124 100644 --- a/ct/technitiumdns.sh +++ b/ct/technitiumdns.sh @@ -38,11 +38,8 @@ function update_script() { msg_info "Updating Technitium DNS" 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/ - msg_ok "Updated Technitium DNS" - - msg_info "Cleaning up" rm -f /opt/DnsServerPortable.tar.gz - msg_ok "Cleaned up" + msg_ok "Updated Technitium DNS" msg_ok "Updated successfully!" else msg_ok "No update required. Technitium DNS is already at v${RELEASE}." diff --git a/ct/teddycloud.sh b/ct/teddycloud.sh index 0dbd2dbbc..6d9992593 100644 --- a/ct/teddycloud.sh +++ b/ct/teddycloud.sh @@ -41,15 +41,12 @@ function update_script() { msg_info "Restoring data" 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_info "Starting Service" systemctl start teddycloud msg_ok "Started Service" - - msg_info "Cleaning up" - rm -rf /opt/teddycloud_bak - msg_ok "Cleaned up" msg_ok "Updated successfully!" fi exit diff --git a/ct/tianji.sh b/ct/tianji.sh index e332d9d76..86e0c0961 100644 --- a/ct/tianji.sh +++ b/ct/tianji.sh @@ -43,7 +43,7 @@ function update_script() { fetch_and_deploy_gh_release "tianji" "msgbyte/tianji" - msg_info "Updating ${APP}" + msg_info "Updating Tianji" cd /opt/tianji export NODE_OPTIONS="--max_old_space_size=4096" $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 cd src/server $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" $STD uv pip install apprise cryptography --system @@ -64,13 +68,6 @@ function update_script() { msg_info "Starting Service" systemctl start tianji 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!" fi exit diff --git a/ct/traccar.sh b/ct/traccar.sh index c660cfd5c..421488fcc 100644 --- a/ct/traccar.sh +++ b/ct/traccar.sh @@ -50,18 +50,12 @@ function update_script() { mv /opt/traccar.xml /opt/traccar/conf [[ -d /opt/data ]] && mv /opt/data /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_info "Starting Service" systemctl start traccar 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!" fi exit diff --git a/ct/trilium.sh b/ct/trilium.sh index 5d9e9a064..6ad9396bc 100644 --- a/ct/trilium.sh +++ b/ct/trilium.sh @@ -55,14 +55,8 @@ function update_script() { msg_info "Restoring Database" mkdir -p "$(dirname "${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 - $STD apt -y autoremove - $STD apt -y autoclean - $STD apt -y clean - msg_ok "Cleaned" + msg_ok "Restored Database" msg_info "Starting Service" systemctl start trilium diff --git a/ct/uhf.sh b/ct/uhf.sh index 62e587f83..6483e3294 100644 --- a/ct/uhf.sh +++ b/ct/uhf.sh @@ -43,12 +43,6 @@ function update_script() { msg_info "Starting Service" systemctl start uhf-server 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!" fi exit diff --git a/ct/upgopher.sh b/ct/upgopher.sh new file mode 100644 index 000000000..31a1a606c --- /dev/null +++ b/ct/upgopher.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) +# Copyright (c) 2021-2025 community-scripts ORG +# Author: Eduard GonzΓ‘lez (wanetty) +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/wanetty/upgopher + +APP="Upgopher" +var_tags="${var_tags:-file-sharing}" +var_cpu="${var_cpu:-1}" +var_ram="${var_ram:-512}" +var_disk="${var_disk:-4}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + if [[ ! -d /opt/upgopher ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "upgopher" "wanetty/upgopher"; then + msg_info "Stopping Service" + systemctl stop upgopher + msg_ok "Stopped Service" + + fetch_and_deploy_gh_release "upgopher" "wanetty/upgopher" "prebuild" "latest" "/opt/upgopher" "upgopher_*_linux_amd64.tar.gz" + chmod +x /opt/upgopher/upgopher + + msg_info "Starting Service" + systemctl start upgopher + msg_ok "Started Service" + msg_ok "Updated successfully!" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following URL:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:9090${CL}" diff --git a/ct/vaultwarden.sh b/ct/vaultwarden.sh index 46a9fccd6..e196899d6 100644 --- a/ct/vaultwarden.sh +++ b/ct/vaultwarden.sh @@ -57,11 +57,8 @@ function update_script() { else cp target/release/vaultwarden /opt/vaultwarden/bin/ fi - msg_ok "Updated VaultWarden" - - msg_info "Cleaning up" cd ~ && rm -rf vaultwarden - msg_ok "Cleaned" + msg_ok "Updated VaultWarden" msg_info "Starting Service" systemctl start vaultwarden @@ -77,11 +74,8 @@ function update_script() { 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 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 - msg_ok "Cleaned" + msg_ok "Updated Web-Vault" msg_info "Starting Service" systemctl start vaultwarden diff --git a/ct/vikunja.sh b/ct/vikunja.sh index 3556a4b51..085227d4f 100644 --- a/ct/vikunja.sh +++ b/ct/vikunja.sh @@ -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") export DEBIAN_FRONTEND=noninteractive $STD dpkg -i vikunja-"$RELEASE"-amd64.deb + rm -rf /opt/vikunja-"$RELEASE"-amd64.deb echo "${RELEASE}" >/opt/${APP}_version.txt msg_ok "Updated ${APP}" msg_info "Starting Service" systemctl start vikunja msg_ok "Started Service" - - msg_info "Cleaning Up" - rm -rf /opt/vikunja-"$RELEASE"-amd64.deb - msg_ok "Cleaned" msg_ok "Updated successfully!" else msg_ok "No update required. ${APP} is already at ${RELEASE}" diff --git a/ct/wastebin.sh b/ct/wastebin.sh index 9b74ad609..af1e59280 100644 --- a/ct/wastebin.sh +++ b/ct/wastebin.sh @@ -73,16 +73,13 @@ EOF cp -f wastebin* /opt/wastebin/ chmod +x /opt/wastebin/wastebin chmod +x /opt/wastebin/wastebin-ctl + rm -f "$temp_file" echo "${RELEASE}" >/opt/${APP}_version.txt msg_ok "Updated Wastebin" msg_info "Starting Wastebin" systemctl start wastebin msg_ok "Started Wastebin" - - 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 v${RELEASE}" diff --git a/ct/watchyourlan.sh b/ct/watchyourlan.sh index 9384c264b..d8e8093e9 100644 --- a/ct/watchyourlan.sh +++ b/ct/watchyourlan.sh @@ -37,10 +37,7 @@ function update_script() { fetch_and_deploy_gh_release "watchyourlan" "aceberg/WatchYourLAN" "binary" cp -R config.yaml /data/config.yaml sed -i 's|/etc/watchyourlan/config.yaml|/data/config.yaml|' /lib/systemd/system/watchyourlan.service - - msg_info "Cleaning up" rm ~/config.yaml - msg_ok "Cleaned up" msg_info "Starting service" systemctl enable -q --now watchyourlan diff --git a/ct/wger.sh b/ct/wger.sh index 0a3f0ffee..bca34c3bc 100644 --- a/ct/wger.sh +++ b/ct/wger.sh @@ -45,16 +45,13 @@ function update_script() { $STD python3 manage.py collectstatic --no-input $STD yarn install $STD yarn build:css:sass + rm -rf "$temp_file" echo "${RELEASE}" >/opt/${APP}_version.txt msg_ok "Updated $APP to v${RELEASE}" msg_info "Starting Service" systemctl start wger msg_ok "Started Service" - - msg_info "Cleaning Up" - rm -rf "$temp_file" - msg_ok "Cleanup Completed" msg_ok "Updated successfully!" else msg_ok "No update required. ${APP} is already at v${RELEASE}" diff --git a/ct/wikijs.sh b/ct/wikijs.sh index d83e62f89..cb4797dbd 100644 --- a/ct/wikijs.sh +++ b/ct/wikijs.sh @@ -54,15 +54,12 @@ function update_script() { msg_info "Restoring Data" cp -R /opt/wikijs-backup/* /opt/wikijs $SQLITE_INSTALL && $STD npm rebuild sqlite3 + rm -rf /opt/wikijs-backup msg_ok "Restored Data" msg_info "Starting Service" systemctl start wikijs msg_ok "Started Service" - - msg_info "Cleaning Up" - rm -rf /opt/wikijs-backup - msg_ok "Cleanup Completed" msg_ok "Updated successfully!" fi exit diff --git a/ct/wizarr.sh b/ct/wizarr.sh index 991b22272..3d5ac3f7a 100644 --- a/ct/wizarr.sh +++ b/ct/wizarr.sh @@ -56,15 +56,12 @@ function update_script() { if ! grep -q 'frozen' /opt/wizarr/start.sh; then sed -i 's/run/& --frozen/' /opt/wizarr/start.sh fi + rm -rf "$BACKUP_FILE" msg_ok "Updated Wizarr" msg_info "Starting Service" systemctl start wizarr msg_ok "Started Service" - - msg_info "Cleaning Up" - rm -rf "$BACKUP_FILE" - msg_ok "Cleanup Completed" msg_ok "Updated successfully!" fi exit diff --git a/ct/zabbix.sh b/ct/zabbix.sh index cbde042d3..e58ffefbc 100644 --- a/ct/zabbix.sh +++ b/ct/zabbix.sh @@ -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")" \ -o /tmp/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 install --only-upgrade zabbix-server-pgsql zabbix-frontend-php php8.4-pgsql @@ -88,13 +89,6 @@ function update_script() { systemctl start "$AGENT_SERVICE" systemctl restart apache2 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!" exit } diff --git a/ct/zigbee2mqtt.sh b/ct/zigbee2mqtt.sh index 642747032..aa483c77a 100644 --- a/ct/zigbee2mqtt.sh +++ b/ct/zigbee2mqtt.sh @@ -47,18 +47,15 @@ function update_script() { rm -rf /opt/zigbee2mqtt/data mv /opt/z2m_backup/data /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 build + rm -rf /opt/z2m_backup msg_ok "Updated Zigbee2MQTT" msg_info "Starting Service" systemctl start zigbee2mqtt msg_ok "Started Service" - - msg_info "Cleaning up" - rm -rf /opt/z2m_backup - msg_ok "Cleaned up" msg_ok "Updated successfully!" fi exit diff --git a/frontend/bun.lock b/frontend/bun.lock index 25812daf9..1a5258d09 100644 --- a/frontend/bun.lock +++ b/frontend/bun.lock @@ -11,6 +11,7 @@ "@radix-ui/react-label": "^2.1.2", "@radix-ui/react-navigation-menu": "^1.2.5", "@radix-ui/react-popover": "^1.1.6", + "@radix-ui/react-scroll-area": "^1.2.10", "@radix-ui/react-select": "^2.1.6", "@radix-ui/react-separator": "^1.1.2", "@radix-ui/react-slot": "^1.1.2", @@ -24,7 +25,9 @@ "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", - "lucide-react": "^0.542.0", + "framer-motion": "^11.18.2", + "fuse.js": "^7.1.0", + "lucide-react": "^0.554.0", "mini-svg-data-uri": "^1.4.4", "motion": "^12.23.12", "next": "15.5.2", @@ -37,6 +40,7 @@ "react-dom": "19.0.0", "react-icons": "^5.5.0", "react-use-measure": "^2.1.7", + "recharts": "2.15.4", "sharp": "^0.33.5", "sonner": "^1.7.4", "tailwind-merge": "^2.6.0", @@ -404,6 +408,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-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="], + "@radix-ui/react-select": ["@radix-ui/react-select@2.2.5", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA=="], "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], @@ -502,6 +508,24 @@ "@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="], + "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], + + "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], + + "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="], + + "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="], + + "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="], + + "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="], + + "@types/d3-shape": ["@types/d3-shape@3.1.7", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg=="], + + "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="], + + "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="], + "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], @@ -736,6 +760,28 @@ "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="], + + "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], + + "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="], + + "d3-format": ["d3-format@3.1.0", "", {}, "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA=="], + + "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], + + "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="], + + "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="], + + "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="], + + "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="], + + "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="], + + "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], + "damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="], "data-urls": ["data-urls@5.0.0", "", { "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0" } }, "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg=="], @@ -754,6 +800,8 @@ "decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="], + "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="], + "decode-named-character-reference": ["decode-named-character-reference@1.2.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="], "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], @@ -778,6 +826,8 @@ "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], + "dom-helpers": ["dom-helpers@5.2.1", "", { "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA=="], + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], @@ -910,12 +960,16 @@ "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + "eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], + "exsolve": ["exsolve@1.0.7", "", {}, "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw=="], "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], "fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="], + "fast-equals": ["fast-equals@5.3.3", "", {}, "sha512-/boTcHZeIAQ2r/tL11voclBHDeP9WPxLt+tyAbVSyyXuUFyh0Tne7gJZTqGbxnvj79TjLdCXLOY7UIPhyG5MTw=="], + "fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="], "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], @@ -1020,6 +1074,12 @@ "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], + "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], + + "is-alphabetical": ["is-alphabetical@1.0.4", "", {}, "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg=="], + + "is-alphanumerical": ["is-alphanumerical@1.0.4", "", { "dependencies": { "is-alphabetical": "^1.0.0", "is-decimal": "^1.0.0" } }, "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A=="], + "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], "is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="], @@ -1142,7 +1202,7 @@ "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=="], @@ -1394,7 +1454,7 @@ "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=="], @@ -1402,14 +1462,26 @@ "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], + "react-simple-typewriter": ["react-simple-typewriter@5.0.1", "", { "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-vA5HkABwJKL/DJ4RshSlY/igdr+FiVY4MLsSQYJX6FZG/f1/VwN4y1i3mPXRyfaswrvI8xii1kOVe1dYtO2Row=="], + + "react-smooth": ["react-smooth@4.0.4", "", { "dependencies": { "fast-equals": "^5.0.1", "prop-types": "^15.8.1", "react-transition-group": "^4.4.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q=="], + "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], + "react-syntax-highlighter": ["react-syntax-highlighter@15.6.1", "", { "dependencies": { "@babel/runtime": "^7.3.1", "highlight.js": "^10.4.1", "highlightjs-vue": "^1.0.0", "lowlight": "^1.17.0", "prismjs": "^1.27.0", "refractor": "^3.6.0" }, "peerDependencies": { "react": ">= 0.14.0" } }, "sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg=="], + + "react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="], + "react-use-measure": ["react-use-measure@2.1.7", "", { "peerDependencies": { "react": ">=16.13", "react-dom": ">=16.13" } }, "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg=="], "read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="], "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + "recharts": ["recharts@2.15.4", "", { "dependencies": { "clsx": "^2.0.0", "eventemitter3": "^4.0.1", "lodash": "^4.17.21", "react-is": "^18.3.1", "react-smooth": "^4.0.4", "recharts-scale": "^0.4.4", "tiny-invariant": "^1.3.1", "victory-vendor": "^36.6.8" }, "peerDependencies": { "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw=="], + + "recharts-scale": ["recharts-scale@0.4.5", "", { "dependencies": { "decimal.js-light": "^2.4.1" } }, "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w=="], + "refa": ["refa@0.12.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.8.0" } }, "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g=="], "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], @@ -1546,6 +1618,8 @@ "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], + "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], + "tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="], "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], @@ -1614,6 +1688,8 @@ "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "victory-vendor": ["victory-vendor@36.9.2", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ=="], + "vite": ["vite@7.1.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx"], "bin": "bin/vite.js" }, "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ=="], "vite-tsconfig-paths": ["vite-tsconfig-paths@5.1.4", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" } }, "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w=="], @@ -1684,6 +1760,12 @@ "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], + "@radix-ui/react-scroll-area/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], + + "@radix-ui/react-scroll-area/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="], + + "@types/hast/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + "@typescript-eslint/typescript-estree/fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], @@ -1752,6 +1834,8 @@ "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=="], "regjsparser/jsesc": ["jsesc@3.0.2", "", { "bin": "bin/jsesc" }, "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g=="], diff --git a/frontend/package.json b/frontend/package.json index 253fa1d8b..e79fe911c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,6 +23,7 @@ "@radix-ui/react-label": "^2.1.2", "@radix-ui/react-navigation-menu": "^1.2.5", "@radix-ui/react-popover": "^1.1.6", + "@radix-ui/react-scroll-area": "^1.2.10", "@radix-ui/react-select": "^2.1.6", "@radix-ui/react-separator": "^1.1.2", "@radix-ui/react-slot": "^1.1.2", @@ -36,7 +37,10 @@ "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", - "lucide-react": "^0.542.0", + + "framer-motion": "^11.18.2", + "fuse.js": "^7.1.0", + "lucide-react": "^0.554.0", "mini-svg-data-uri": "^1.4.4", "motion": "^12.23.12", "next": "15.5.2", @@ -49,6 +53,7 @@ "react-dom": "19.0.0", "react-icons": "^5.5.0", "react-use-measure": "^2.1.7", + "recharts": "2.15.4", "sharp": "^0.33.5", "sonner": "^1.7.4", "tailwind-merge": "^2.6.0", diff --git a/frontend/public/json/librenms.json b/frontend/public/json/librenms.json index 02ae2e9c7..85fad7ee7 100644 --- a/frontend/public/json/librenms.json +++ b/frontend/public/json/librenms.json @@ -23,7 +23,7 @@ "ram": 2048, "hdd": 4, "os": "Debian", - "version": "12" + "version": "13" } } ], diff --git a/frontend/public/json/upgopher.json b/frontend/public/json/upgopher.json new file mode 100644 index 000000000..6e62ce611 --- /dev/null +++ b/frontend/public/json/upgopher.json @@ -0,0 +1,44 @@ +{ + "name": "Upgopher", + "slug": "upgopher", + "categories": [ + 11 + ], + "date_created": "2025-11-22", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": 9090, + "documentation": "https://github.com/wanetty/upgopher#readme", + "config_path": "", + "website": "https://github.com/wanetty/upgopher", + "logo": "https://raw.githubusercontent.com/wanetty/upgopher/main/static/logopher.webp", + "description": "A simple Go web server for file upload, download, and browsing. Cross-platform alternative to Python-based file servers with no library dependencies. Features file upload via web interface, directory navigation, URL copying to clipboard, optional basic authentication, HTTPS support, and hidden files toggle.", + "install_methods": [ + { + "type": "default", + "script": "ct/upgopher.sh", + "resources": { + "cpu": 1, + "ram": 512, + "hdd": 4, + "os": "Debian", + "version": "13" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [ + { + "text": "Default uploads directory: `/opt/upgopher/uploads`", + "type": "info" + }, + { + "text": "Set application startup options by editing `/etc/systemd/system/upgopher.service`. Read documentation for available options.", + "type": "info" + } + ] +} diff --git a/frontend/public/json/versions.json b/frontend/public/json/versions.json index 771c3f1a2..d4d6b8179 100644 --- a/frontend/public/json/versions.json +++ b/frontend/public/json/versions.json @@ -1,4 +1,159 @@ [ + { + "name": "paperless-ngx/paperless-ngx", + "version": "v2.20.0", + "date": "2025-11-22T21:56:00Z" + }, + { + "name": "OliveTin/OliveTin", + "version": "2025.11.25", + "date": "2025-11-22T21:00:52Z" + }, + { + "name": "Cleanuparr/Cleanuparr", + "version": "v2.4.6", + "date": "2025-11-22T20:32:09Z" + }, + { + "name": "go-gitea/gitea", + "version": "v1.25.2", + "date": "2025-11-22T19:37:02Z" + }, + { + "name": "msgbyte/tianji", + "version": "v1.30.13", + "date": "2025-11-22T18:22:32Z" + }, + { + "name": "nzbgetcom/nzbget", + "version": "v25.4", + "date": "2025-10-09T10:27:01Z" + }, + { + "name": "bunkerity/bunkerweb", + "version": "v1.6.6", + "date": "2025-11-22T16:10:29Z" + }, + { + "name": "TechnitiumSoftware/DnsServer", + "version": "v14.2.0", + "date": "2025-11-22T12:54:08Z" + }, + { + "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": "chrisbenincasa/tunarr", + "version": "v0.23.0-alpha.24", + "date": "2025-11-21T12:16:39Z" + }, { "name": "rcourtman/Pulse", "version": "v4.32.3", @@ -29,11 +184,6 @@ "version": "v1.11.0", "date": "2025-11-21T08:09:03Z" }, - { - "name": "mattermost/mattermost", - "version": "v10.11.7", - "date": "2025-11-17T08:40:53Z" - }, { "name": "MariaDB/server", "version": "mariadb-12.1.2", @@ -44,50 +194,35 @@ "version": "v1.5.3", "date": "2025-09-20T12:12:33Z" }, - { - "name": "Jackett/Jackett", - "version": "v0.24.338", - "date": "2025-11-21T05:55:33Z" - }, { "name": "bluenviron/mediamtx", "version": "v1.15.4", "date": "2025-11-21T01:21:03Z" }, - { - "name": "jeedom/core", - "version": "4.4.20", - "date": "2025-11-21T00:27:06Z" - }, { "name": "TasmoAdmin/TasmoAdmin", "version": "v4.3.2", "date": "2025-10-18T12:11:00Z" }, + { + "name": "ollama/ollama", + "version": "v0.13.1-rc0", + "date": "2025-11-20T21:30:35Z" + }, { "name": "project-zot/zot", "version": "v2.1.11", "date": "2025-11-20T20:14:44Z" }, - { - "name": "readeck/readeck", - "version": "0.21.0", - "date": "2025-11-20T18:35:59Z" - }, { "name": "saltstack/salt", "version": "v3007.9", "date": "2025-11-20T17:58:32Z" }, { - "name": "keycloak/keycloak", - "version": "26.4.5", - "date": "2025-11-12T15:24:23Z" - }, - { - "name": "msgbyte/tianji", - "version": "v1.30.12", - "date": "2025-11-20T16:13:19Z" + "name": "neo4j/neo4j", + "version": "5.26.17", + "date": "2025-11-20T16:09:28Z" }, { "name": "meilisearch/meilisearch", @@ -124,11 +259,6 @@ "version": "v2.1.1", "date": "2025-11-20T10:54:07Z" }, - { - "name": "fuma-nama/fumadocs", - "version": "fumadocs-ui@16.0.15", - "date": "2025-11-20T10:52:04Z" - }, { "name": "Athou/commafeed", "version": "5.12.0", @@ -149,16 +279,6 @@ "version": "v1.56.0", "date": "2025-11-20T02:28:35Z" }, - { - "name": "BerriAI/litellm", - "version": "v1.80.0.dev6", - "date": "2025-11-20T02:03:21Z" - }, - { - "name": "steveiliop56/tinyauth", - "version": "v4.0.1", - "date": "2025-10-15T16:53:55Z" - }, { "name": "coder/code-server", "version": "v4.106.2", @@ -199,11 +319,6 @@ "version": "0.51.3", "date": "2025-11-19T15:45:28Z" }, - { - "name": "BookStackApp/BookStack", - "version": "v25.11.2", - "date": "2025-11-19T15:26:29Z" - }, { "name": "grafana/grafana", "version": "v12.3.0", @@ -224,11 +339,6 @@ "version": "2025.5", "date": "2025-11-19T14:48:47Z" }, - { - "name": "ollama/ollama", - "version": "v0.13.0", - "date": "2025-11-19T14:16:07Z" - }, { "name": "AdguardTeam/AdGuardHome", "version": "v0.107.69", @@ -259,16 +369,6 @@ "version": "v1.0.1-stable", "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", "version": "v3.0.1", @@ -309,11 +409,6 @@ "version": "v0.28.2", "date": "2025-11-18T05:51:46Z" }, - { - "name": "theonedev/onedev", - "version": "v13.1.0", - "date": "2025-11-18T00:06:49Z" - }, { "name": "ipfs/kubo", "version": "v0.38.2", @@ -369,11 +464,6 @@ "version": "v0.21.0", "date": "2025-08-23T18:33:53Z" }, - { - "name": "TwiN/gatus", - "version": "v5.32.0", - "date": "2025-11-16T21:08:56Z" - }, { "name": "binwiederhier/ntfy", "version": "v2.15.0", @@ -404,26 +494,11 @@ "version": "v25.11.1", "date": "2025-11-16T13:04:21Z" }, - { - "name": "TechnitiumSoftware/DnsServer", - "version": "v14.1.0", - "date": "2025-11-16T11:32:10Z" - }, { "name": "FlowiseAI/Flowise", "version": "flowise@3.0.11", "date": "2025-11-16T01:29:06Z" }, - { - "name": "OliveTin/OliveTin", - "version": "3000.4.0", - "date": "2025-11-16T01:02:49Z" - }, - { - "name": "paperless-ngx/paperless-ngx", - "version": "v2.19.6", - "date": "2025-11-15T22:56:45Z" - }, { "name": "karakeep-app/karakeep", "version": "android/v1.8.2-2", @@ -439,16 +514,6 @@ "version": "v0.16.1", "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", "version": "v3.5.0", @@ -464,11 +529,6 @@ "version": "v4.7.0", "date": "2025-11-14T09:45:13Z" }, - { - "name": "nzbgetcom/nzbget", - "version": "v25.4", - "date": "2025-10-09T10:27:01Z" - }, { "name": "verdaccio/verdaccio", "version": "generator-verdaccio-plugin@6.0.0-next-8.25", @@ -489,16 +549,6 @@ "version": "v1.7.7", "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", "version": "1.7.9", @@ -519,11 +569,6 @@ "version": "v1.0.25", "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", "version": "351", @@ -609,11 +654,6 @@ "version": "v1.0.0-beta19", "date": "2025-11-09T17:26:30Z" }, - { - "name": "Cleanuparr/Cleanuparr", - "version": "v2.4.5", - "date": "2025-11-09T17:14:01Z" - }, { "name": "authelia/authelia", "version": "v4.39.14", @@ -624,11 +664,6 @@ "version": "3.5.1", "date": "2025-11-09T05:09:28Z" }, - { - "name": "inventree/InvenTree", - "version": "1.1.3", - "date": "2025-11-09T00:28:21Z" - }, { "name": "raydak-labs/configarr", "version": "v1.17.2", @@ -704,11 +739,6 @@ "version": "v0.9.1", "date": "2025-11-06T02:26:53Z" }, - { - "name": "neo4j/neo4j", - "version": "5.26.16", - "date": "2025-11-05T20:41:40Z" - }, { "name": "leiweibau/Pi.Alert", "version": "v2025-11-05", @@ -754,11 +784,6 @@ "version": "v4.0.16.2944", "date": "2025-11-05T01:56:48Z" }, - { - "name": "go-gitea/gitea", - "version": "v1.25.1", - "date": "2025-11-04T20:01:09Z" - }, { "name": "jhuckaby/Cronicle", "version": "v0.9.100", @@ -864,11 +889,6 @@ "version": "v1.11.1", "date": "2025-10-29T22:09:26Z" }, - { - "name": "laurent22/joplin", - "version": "server-v3.4.4", - "date": "2025-09-25T13:19:26Z" - }, { "name": "apache/cassandra", "version": "cassandra-5.0.6", @@ -899,11 +919,6 @@ "version": "v25.8.0", "date": "2025-10-26T14:23:37Z" }, - { - "name": "forgejo/forgejo", - "version": "v13.0.2", - "date": "2025-10-26T06:33:05Z" - }, { "name": "usememos/memos", "version": "v0.25.2", @@ -939,11 +954,6 @@ "version": "v3.2.5-beta", "date": "2025-10-21T16:49:14Z" }, - { - "name": "rclone/rclone", - "version": "v1.71.2", - "date": "2025-10-20T15:25:52Z" - }, { "name": "Part-DB/Part-DB-server", "version": "v2.2.1", @@ -1009,11 +1019,6 @@ "version": "v5.0.85", "date": "2025-10-12T19:55:18Z" }, - { - "name": "gelbphoenix/autocaliweb", - "version": "v0.10.4", - "date": "2025-10-11T19:53:39Z" - }, { "name": "projectsend/projectsend", "version": "r1945", @@ -1314,11 +1319,6 @@ "version": "v1.11.11", "date": "2025-06-18T18:04:50Z" }, - { - "name": "Bubka/2FAuth", - "version": "v5.6.0", - "date": "2025-06-18T12:19:54Z" - }, { "name": "TriliumNext/Notes", "version": "v0.95.0", diff --git a/frontend/src/app/data/page.tsx b/frontend/src/app/data/page.tsx index 63bbb70cf..04943c991 100644 --- a/frontend/src/app/data/page.tsx +++ b/frontend/src/app/data/page.tsx @@ -1,8 +1,67 @@ "use client"; -import React, { useEffect, useState } from "react"; +import { + ArrowUpDown, + Box, + CheckCircle2, + ChevronLeft, + ChevronRight, + List, + Loader2, + Trophy, + XCircle, +} from "lucide-react"; +import { + Bar, + BarChart, + CartesianGrid, + Cell, + LabelList, + XAxis, +} from "recharts"; +import React, { useEffect, useMemo, useState } from "react"; -import 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 = { id: number; @@ -29,42 +88,76 @@ type SummaryData = { nsapp_count: Record; }; -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([]); const [summary, setSummary] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [currentPage, setCurrentPage] = useState(1); const [itemsPerPage, setItemsPerPage] = useState(25); - const [sortConfig, setSortConfig] = useState<{ key: string; direction: "ascending" | "descending" } | null>(null); + const [sortConfig, setSortConfig] = useState<{ + key: string; + direction: "ascending" | "descending"; + } | null>(null); + const nf = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 }); useEffect(() => { - const fetchSummary = async () => { - try { - const response = await fetch("https://api.htl-braunau.at/data/summary"); - if (!response.ok) - throw new Error(`Failed to fetch summary: ${response.statusText}`); - const result: SummaryData = await response.json(); - setSummary(result); - } - catch (err) { - setError((err as Error).message); - } - }; - - fetchSummary(); - }, []); - - useEffect(() => { - const fetchPaginatedData = async () => { + const fetchData = async () => { setLoading(true); try { - const response = await fetch(`https://api.htl-braunau.at/data/paginated?page=${currentPage}&limit=${itemsPerPage === 0 ? "" : itemsPerPage}`); - if (!response.ok) - throw new Error(`Failed to fetch data: ${response.statusText}`); - const result: DataModel[] = await response.json(); - setData(result); + const [summaryRes, dataRes] = await Promise.all([ + fetch("https://api.htl-braunau.at/data/summary"), + fetch( + `https://api.htl-braunau.at/data/paginated?page=${currentPage}&limit=${itemsPerPage === 0 ? "" : itemsPerPage + }`, + ), + ]); + + if (!summaryRes.ok) { + throw new Error(`Failed to fetch summary: ${summaryRes.statusText}`); + } + if (!dataRes.ok) { + throw new Error(`Failed to fetch data: ${dataRes.statusText}`); + } + + const summaryData: SummaryData = await summaryRes.json(); + const pageData: DataModel[] = await dataRes.json(); + + setSummary(summaryData); + setData(pageData); } catch (err) { setError((err as Error).message); @@ -74,13 +167,13 @@ const DataFetcher: React.FC = () => { } }; - fetchPaginatedData(); + fetchData(); }, [currentPage, itemsPerPage]); - const sortedData = React.useMemo(() => { + const sortedData = useMemo(() => { if (!sortConfig) return data; - const sorted = [...data].sort((a, b) => { + return [...data].sort((a, b) => { if (a[sortConfig.key] < b[sortConfig.key]) { return sortConfig.direction === "ascending" ? -1 : 1; } @@ -89,23 +182,15 @@ const DataFetcher: React.FC = () => { } return 0; }); - return sorted; }, [data, sortConfig]); - if (loading) - return

Loading...

; - if (error) { - return ( -

- Error: - {error} -

- ); - } - const requestSort = (key: string) => { let direction: "ascending" | "descending" = "ascending"; - if (sortConfig && sortConfig.key === key && sortConfig.direction === "ascending") { + if ( + sortConfig + && sortConfig.key === key + && sortConfig.direction === "ascending" + ) { direction = "descending"; } setSortConfig({ key, direction }); @@ -113,135 +198,447 @@ const DataFetcher: React.FC = () => { const formatDate = (dateString: string): string => { const date = new Date(dateString); - const year = date.getFullYear(); - const month = date.getMonth() + 1; - const day = date.getDate(); - const hours = String(date.getHours()).padStart(2, "0"); - const minutes = String(date.getMinutes()).padStart(2, "0"); - const timezoneOffset = dateString.slice(-6); - return `${day}.${month}.${year} ${hours}:${minutes} ${timezoneOffset} GMT`; + return new Intl.DateTimeFormat("en-US", { + dateStyle: "medium", + timeStyle: "short", + }).format(date); }; - return ( -
-

Created LXCs

- -

-
-

- {nf.format( - summary?.total_entries ?? 0, - )} - {" "} - results found -

-

- Status Legend: πŸ”„ installing - {" "} - {nf.format(summary?.status_count.installing ?? 0)} - {" "} - | βœ”οΈ completed - {" "} - {nf.format(summary?.status_count.done ?? 0)} - {" "} - | ❌ failed - {" "} - {nf.format(summary?.status_count.failed ?? 0)} - {" "} - | ❓ unknown + const getTypeBadge = (type: string) => { + if (type === "lxc") + return formattedBadge("ct"); + if (type === "vm") + return formattedBadge("vm"); + return null; + }; + + // Stats calculations + const successCount = summary?.status_count.done ?? 0; + const failureCount = summary?.status_count.failed ?? 0; + const totalCount = summary?.total_entries ?? 0; + const successRate = totalCount > 0 ? (successCount / totalCount) * 100 : 0; + + const allApps = useMemo(() => { + if (!summary?.nsapp_count) + return []; + return Object.entries(summary.nsapp_count).sort(([, a], [, b]) => b - a); + }, [summary]); + + const topApps = useMemo(() => { + return allApps.slice(0, 15); + }, [allApps]); + + const mostPopularApp = topApps[0]; + + // Chart Data + const appsChartData = topApps.map(([name, count], index) => ({ + app: name, + count, + fill: CHART_COLORS[index % CHART_COLORS.length], + })); + + if (error) { + return ( +

+

+ Error loading data: + {error}

-
-
- - - - - - - - - - - - - - - - - - - {sortedData.map((item, index) => ( - -
requestSort("status")}>Status requestSort("type")}>Type requestSort("nsapp")}>Application requestSort("os_type")}>OS requestSort("os_version")}>OS Version requestSort("disk_size")}>Disk Size requestSort("core_count")}>Core Count requestSort("ram_size")}>RAM Size requestSort("method")}>Method requestSort("pve_version")}>PVE Version requestSort("error")}>Error Message requestSort("created_at")}>Created At
- {item.status === "done" + ); + } + + return ( +
+
+
+ {/* Header */} +
+

Analytics

+

+ Overview of container installations and system statistics. +

+
+ + {/* Widgets */} +
+ + + Total Created + + + +
{nf.format(totalCount)}
+

+ Total LXC/VM entries found +

+
+
+ + + + Success Rate + + + +
+ {successRate.toFixed(1)} + % +
+

+ {nf.format(successCount)} + {" "} + successful installations +

+
+
+ + + + Failures + + + +
{nf.format(failureCount)}
+

+ Installations encountered errors +

+
+
+ + + + Most Popular + + + +
+ {mostPopularApp ? mostPopularApp[0] : "N/A"} +
+

+ {mostPopularApp ? nf.format(mostPopularApp[1]) : 0} + {" "} + installations +

+
+
+
+ + {/* Graphs */} + + +
+ Top Applications + + The most frequently installed applications. + +
+ + + + + + + Application Statistics + + Installation counts for all + {" "} + {allApps.length} + {" "} + applications. + + + +
+ {allApps.map(([name, count], index) => ( +
+
+ + {index + 1} + . + + {name} +
+ {nf.format(count)} +
+ ))} +
+
+
+
+
+ +
+ {loading + ? ( +
+ +
+ ) + : ( + + + + (value.length > 8 ? `${value.slice(0, 8)}...` : value)} + /> + } + /> + + {appsChartData.map((entry, index) => ( + + ))} + + + + + )} +
+
+
+ + {/* Data Table */} + + +
+ Installation Log + + Detailed records of all container creation attempts. + +
+
+ +
+
+ +
+ + + + requestSort("status")} + > + Status + {sortConfig?.key === "status" && ( + + )} + + requestSort("type")} + > + Type + {sortConfig?.key === "type" && ( + + )} + + requestSort("nsapp")} + > + Application + {sortConfig?.key === "nsapp" && ( + + )} + + requestSort("os_type")} + > + OS + {sortConfig?.key === "os_type" && ( + + )} + + requestSort("disk_size")} + > + Disk Size + {sortConfig?.key === "disk_size" && ( + + )} + + requestSort("core_count")} + > + Core Count + {sortConfig?.key === "core_count" && ( + + )} + + requestSort("ram_size")} + > + RAM Size + {sortConfig?.key === "ram_size" && ( + + )} + + requestSort("created_at")} + > + Created At + {sortConfig?.key === "created_at" && ( + + )} + + + + + {loading ? ( - "βœ”οΈ" + + +
+ + {" "} + Loading data... +
+
+
) - : item.status === "failed" + : sortedData.length > 0 ? ( - "❌" - ) - : item.status === "installing" - ? ( - "πŸ”„" - ) - : ( - item.status - )} - -
- - - - - - - - - - - - ))} - -
- {item.type === "lxc" - ? ( - "πŸ“¦" - ) - : item.type === "vm" - ? ( - "πŸ–₯️" + sortedData.map((item, idx) => ( + + + {item.status === "done" + ? ( + + Success + + ) + : item.status === "failed" + ? ( + + Failed + + ) + : item.status === "installing" + ? ( + + Installing + + ) + : ( + + {item.status} + + )} + + + {getTypeBadge(item.type) || ( + + {item.type} + + )} + + + {item.nsapp} + + + {item.os_type} + {" "} + {item.os_version} + + + {item.disk_size} + MB + + + {item.core_count} + + + {item.ram_size} + MB + + + {formatDate(item.created_at)} + + + )) ) : ( - item.type + + + No results found. + + )} - {item.nsapp}{item.os_type}{item.os_version}{item.disk_size}{item.core_count}{item.ram_size}{item.method}{item.pve_version}{item.error}{formatDate(item.created_at)}
+ +
+
+ +
+ +
+ Page + {" "} + {currentPage} +
+ +
+ +
-
- - - Page - {currentPage} - - - -
); -}; - -export default DataFetcher; +} diff --git a/frontend/src/components/application-chart.tsx b/frontend/src/components/application-chart.tsx deleted file mode 100644 index 0311754af..000000000 --- a/frontend/src/components/application-chart.tsx +++ /dev/null @@ -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; -}; - -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 ( -
- - - - - - Open Chart View - - - - - - - Open Table View - - - - - - - Applications Distribution - -
- -
-
- - -
-
-
- - - - - Applications Count - -
- - - - Application - Count - - - - {sortedApps.slice(0, tableLimit).map(([name, count]) => ( - - {name} - {count} - - ))} - -
-
- {tableLimit < sortedApps.length && ( - - )} -
-
-
- ); -} diff --git a/frontend/src/components/ui/chart.tsx b/frontend/src/components/ui/chart.tsx new file mode 100644 index 000000000..f7b762f55 --- /dev/null +++ b/frontend/src/components/ui/chart.tsx @@ -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 } + ) +} + +type ChartContextProps = { + config: ChartConfig +} + +const ChartContext = React.createContext(null) + +function useChart() { + const context = React.useContext(ChartContext) + + if (!context) { + throw new Error("useChart must be used within a ") + } + + 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 ( + +
+ + + {children} + +
+
+ ) +}) +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 ( +