mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2025-11-22 13:35:15 +00:00
Compare commits
27 Commits
MickLesk-p
...
ct_cleanup
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6e53dea01 | ||
|
|
e4b2e051bf | ||
|
|
e05a351712 | ||
|
|
053e5ab128 | ||
|
|
1f6a141341 | ||
|
|
b47d4747d6 | ||
|
|
27bd55364c | ||
|
|
8ad68e7c97 | ||
|
|
088186712a | ||
|
|
6dd0195912 | ||
|
|
afa385d225 | ||
|
|
f43efc1431 | ||
|
|
06d8e5354a | ||
|
|
60fc5573aa | ||
|
|
29ee6cdff3 | ||
|
|
bda9286043 | ||
|
|
4389a43670 | ||
|
|
43877a8b17 | ||
|
|
ff6cb3b87e | ||
|
|
4b0fb547e9 | ||
|
|
e2c6020c64 | ||
|
|
33f4482012 | ||
|
|
9b375bccab | ||
|
|
3f2f29d352 | ||
|
|
636b0d3afd | ||
|
|
36acad3b25 | ||
|
|
00060740d9 |
23
CHANGELOG.md
23
CHANGELOG.md
@@ -10,6 +10,29 @@
|
|||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit the project's popularity for potentially malicious purposes.
|
Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit the project's popularity for potentially malicious purposes.
|
||||||
|
|
||||||
|
## 2025-11-22
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Refactor /data page [@BramSuurdje](https://github.com/BramSuurdje) ([#9343](https://github.com/community-scripts/ProxmoxVE/pull/9343))
|
||||||
|
|
||||||
|
## 2025-11-21
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- plex: prevent [] syntax issue [@MickLesk](https://github.com/MickLesk) ([#9318](https://github.com/community-scripts/ProxmoxVE/pull/9318))
|
||||||
|
- fix: karakeep strip "v" from release version [@CrazyWolf13](https://github.com/CrazyWolf13) ([#9324](https://github.com/community-scripts/ProxmoxVE/pull/9324))
|
||||||
|
- NetVisor: fix grep in update [@vhsdream](https://github.com/vhsdream) ([#9334](https://github.com/community-scripts/ProxmoxVE/pull/9334))
|
||||||
|
- Immich: pin correct version [@vhsdream](https://github.com/vhsdream) ([#9332](https://github.com/community-scripts/ProxmoxVE/pull/9332))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Refactor IPv6 disable logic and add 'disable' option [@MickLesk](https://github.com/MickLesk) ([#9326](https://github.com/community-scripts/ProxmoxVE/pull/9326))
|
||||||
|
|
||||||
## 2025-11-20
|
## 2025-11-20
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
### 🚀 Updated Scripts
|
||||||
|
|||||||
@@ -57,15 +57,6 @@ function update_script() {
|
|||||||
$STD composer install --no-dev --prefer-dist
|
$STD composer install --no-dev --prefer-dist
|
||||||
php artisan 2fauth:install
|
php artisan 2fauth:install
|
||||||
$STD systemctl restart nginx
|
$STD systemctl restart nginx
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
if dpkg -l | grep -q 'php8.2'; then
|
|
||||||
$STD apt remove --purge -y php8.2*
|
|
||||||
fi
|
|
||||||
$STD apt -y autoremove
|
|
||||||
$STD apt -y autoclean
|
|
||||||
$STD apt -y clean
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ function update_script() {
|
|||||||
cd /opt/adventurelog/frontend || exit
|
cd /opt/adventurelog/frontend || exit
|
||||||
$STD pnpm i
|
$STD pnpm i
|
||||||
$STD pnpm build
|
$STD pnpm build
|
||||||
|
rm -rf /opt/adventurelog-backup
|
||||||
msg_ok "Updated ${APP}"
|
msg_ok "Updated ${APP}"
|
||||||
|
|
||||||
msg_info "Starting Services"
|
msg_info "Starting Services"
|
||||||
@@ -69,10 +70,6 @@ function update_script() {
|
|||||||
systemctl start adventurelog-backend
|
systemctl start adventurelog-backend
|
||||||
systemctl start adventurelog-frontend
|
systemctl start adventurelog-frontend
|
||||||
msg_ok "Services Started"
|
msg_ok "Services Started"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /opt/adventurelog-backup
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -38,15 +38,13 @@ function update_script() {
|
|||||||
curl -fsSL -o tika-server-standard-${RELEASE}.jar "https://dlcdn.apache.org/tika/${RELEASE}/tika-server-standard-${RELEASE}.jar"
|
curl -fsSL -o tika-server-standard-${RELEASE}.jar "https://dlcdn.apache.org/tika/${RELEASE}/tika-server-standard-${RELEASE}.jar"
|
||||||
mv --force tika-server-standard.jar tika-server-standard-prev-version.jar
|
mv --force tika-server-standard.jar tika-server-standard-prev-version.jar
|
||||||
mv tika-server-standard-${RELEASE}.jar tika-server-standard.jar
|
mv tika-server-standard-${RELEASE}.jar tika-server-standard.jar
|
||||||
|
rm -rf /opt/apache-tika/tika-server-standard-prev-version.jar
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated ${APP} to v${RELEASE}"
|
msg_ok "Updated ${APP} to v${RELEASE}"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start apache-tika
|
systemctl start apache-tika
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /opt/apache-tika/tika-server-standard-prev-version.jar
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
||||||
|
|||||||
@@ -31,15 +31,11 @@ function update_script() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if check_for_gh_release "authelia" "authelia/authelia"; then
|
if check_for_gh_release "authelia" "authelia/authelia"; then
|
||||||
$STD apt-get update
|
$STD apt update
|
||||||
$STD apt-get -y upgrade
|
$STD apt -y upgrade
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "authelia" "authelia/authelia" "binary"
|
fetch_and_deploy_gh_release "authelia" "authelia/authelia" "binary"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
$STD apt-get -y autoremove
|
|
||||||
$STD apt-get -y autoclean
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -39,16 +39,13 @@ function update_script() {
|
|||||||
curl -fsSL "https://github.com/garethgeorge/backrest/releases/download/v${RELEASE}/backrest_Linux_x86_64.tar.gz" -o "$temp_file"
|
curl -fsSL "https://github.com/garethgeorge/backrest/releases/download/v${RELEASE}/backrest_Linux_x86_64.tar.gz" -o "$temp_file"
|
||||||
tar xzf $temp_file -C /opt/backrest/bin
|
tar xzf $temp_file -C /opt/backrest/bin
|
||||||
chmod +x /opt/backrest/bin/backrest
|
chmod +x /opt/backrest/bin/backrest
|
||||||
|
rm -f "$temp_file"
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated ${APP} to ${RELEASE}"
|
msg_ok "Updated ${APP} to ${RELEASE}"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start backrest
|
systemctl start backrest
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -f "$temp_file"
|
|
||||||
msg_ok "Cleaned up"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
||||||
|
|||||||
@@ -47,15 +47,12 @@ function update_script() {
|
|||||||
chmod -R 755 /opt/baikal/
|
chmod -R 755 /opt/baikal/
|
||||||
cd /opt/baikal
|
cd /opt/baikal
|
||||||
$STD composer install
|
$STD composer install
|
||||||
|
rm -rf /opt/baikal-backup
|
||||||
msg_ok "Configured Baikal"
|
msg_ok "Configured Baikal"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start apache2
|
systemctl start apache2
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf /opt/baikal-backup
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -54,15 +54,12 @@ function update_script() {
|
|||||||
$STD php artisan route:cache
|
$STD php artisan route:cache
|
||||||
$STD php artisan event:cache
|
$STD php artisan event:cache
|
||||||
chown -R www-data:www-data /opt/bar-assistant
|
chown -R www-data:www-data /opt/bar-assistant
|
||||||
|
rm -rf /opt/bar-assistant-backup
|
||||||
msg_ok "Updated Bar-Assistant"
|
msg_ok "Updated Bar-Assistant"
|
||||||
|
|
||||||
msg_info "Starting nginx"
|
msg_info "Starting nginx"
|
||||||
systemctl start nginx
|
systemctl start nginx
|
||||||
msg_ok "Started nginx"
|
msg_ok "Started nginx"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf /opt/bar-assistant-backup
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if check_for_gh_release "vue-salt-rim" "karlomikus/vue-salt-rim"; then
|
if check_for_gh_release "vue-salt-rim" "karlomikus/vue-salt-rim"; then
|
||||||
@@ -81,15 +78,12 @@ function update_script() {
|
|||||||
cd /opt/vue-salt-rim
|
cd /opt/vue-salt-rim
|
||||||
$STD npm install
|
$STD npm install
|
||||||
$STD npm run build
|
$STD npm run build
|
||||||
|
rm -rf /opt/vue-salt-rim-backup
|
||||||
msg_ok "Updated Vue Salt Rim"
|
msg_ok "Updated Vue Salt Rim"
|
||||||
|
|
||||||
msg_info "Starting nginx"
|
msg_info "Starting nginx"
|
||||||
systemctl start nginx
|
systemctl start nginx
|
||||||
msg_ok "Started nginx"
|
msg_ok "Started nginx"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf /opt/vue-salt-rim-backup
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if check_for_gh_release "meilisearch" "meilisearch/meilisearch"; then
|
if check_for_gh_release "meilisearch" "meilisearch/meilisearch"; then
|
||||||
|
|||||||
@@ -57,15 +57,12 @@ function update_script() {
|
|||||||
chmod -R 755 /opt/bookstack /opt/bookstack/bootstrap/cache /opt/bookstack/public/uploads /opt/bookstack/storage
|
chmod -R 755 /opt/bookstack /opt/bookstack/bootstrap/cache /opt/bookstack/public/uploads /opt/bookstack/storage
|
||||||
chmod -R 775 /opt/bookstack/storage /opt/bookstack/bootstrap/cache /opt/bookstack/public/uploads
|
chmod -R 775 /opt/bookstack/storage /opt/bookstack/bootstrap/cache /opt/bookstack/public/uploads
|
||||||
chmod -R 640 /opt/bookstack/.env
|
chmod -R 640 /opt/bookstack/.env
|
||||||
|
rm -rf /opt/bookstack-backup
|
||||||
msg_ok "Configured BookStack"
|
msg_ok "Configured BookStack"
|
||||||
|
|
||||||
msg_info "Starting Apache2"
|
msg_info "Starting Apache2"
|
||||||
systemctl start apache2
|
systemctl start apache2
|
||||||
msg_ok "Started Apache2"
|
msg_ok "Started Apache2"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /opt/bookstack-backup
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ function update_script() {
|
|||||||
fi
|
fi
|
||||||
$STD uv run python manage.py migrate --noinput
|
$STD uv run python manage.py migrate --noinput
|
||||||
$STD uv run python manage.py collectstatic --noinput
|
$STD uv run python manage.py collectstatic --noinput
|
||||||
|
rm -f /tmp/dispatcharr_db_*.sql
|
||||||
msg_ok "Migrations Complete"
|
msg_ok "Migrations Complete"
|
||||||
|
|
||||||
msg_info "Starting Services"
|
msg_info "Starting Services"
|
||||||
@@ -117,10 +118,6 @@ function update_script() {
|
|||||||
systemctl start dispatcharr-celerybeat
|
systemctl start dispatcharr-celerybeat
|
||||||
systemctl start dispatcharr-daphne
|
systemctl start dispatcharr-daphne
|
||||||
msg_ok "Started Services"
|
msg_ok "Started Services"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -f /tmp/dispatcharr_db_*.sql
|
|
||||||
msg_ok "Cleanup completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -76,11 +76,6 @@ function update_script() {
|
|||||||
portainer/agent
|
portainer/agent
|
||||||
msg_ok "Updated Portainer Agent"
|
msg_ok "Updated Portainer Agent"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt-get -y autoremove
|
|
||||||
$STD apt-get -y autoclean
|
|
||||||
msg_ok "Cleanup complete"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,16 +50,13 @@ function update_script() {
|
|||||||
$STD turbo run build --filter=@documenso/remix
|
$STD turbo run build --filter=@documenso/remix
|
||||||
$STD npm run prisma:migrate-deploy
|
$STD npm run prisma:migrate-deploy
|
||||||
$STD turbo daemon stop
|
$STD turbo daemon stop
|
||||||
|
rm -rf /opt/v${RELEASE}.zip
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated ${APP}"
|
msg_ok "Updated ${APP}"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start documenso
|
systemctl start documenso
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /opt/v${RELEASE}.zip
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
||||||
|
|||||||
@@ -47,16 +47,13 @@ function update_script() {
|
|||||||
|
|
||||||
msg_info "Installing EMQX"
|
msg_info "Installing EMQX"
|
||||||
$STD apt-get install -y "$DEB_FILE"
|
$STD apt-get install -y "$DEB_FILE"
|
||||||
|
rm -f "$DEB_FILE"
|
||||||
|
echo "$RELEASE" >~/.emqx
|
||||||
msg_ok "Installed EMQX v${RELEASE}"
|
msg_ok "Installed EMQX v${RELEASE}"
|
||||||
|
|
||||||
msg_info "Starting EMQX"
|
msg_info "Starting EMQX"
|
||||||
systemctl start emqx
|
systemctl start emqx
|
||||||
echo "$RELEASE" >~/.emqx
|
|
||||||
msg_ok "Started EMQX"
|
msg_ok "Started EMQX"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -f "$DEB_FILE"
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. EMQX is already at v${RELEASE}"
|
msg_ok "No update required. EMQX is already at v${RELEASE}"
|
||||||
|
|||||||
@@ -48,16 +48,13 @@ function update_script() {
|
|||||||
temp_file=$(mktemp)
|
temp_file=$(mktemp)
|
||||||
curl -fsSL https://fileflows.com/downloads/zip -o "$temp_file"
|
curl -fsSL https://fileflows.com/downloads/zip -o "$temp_file"
|
||||||
$STD unzip -o -d /opt/fileflows "$temp_file"
|
$STD unzip -o -d /opt/fileflows "$temp_file"
|
||||||
|
rm -rf "$temp_file"
|
||||||
|
rm -rf "$backup_filename"
|
||||||
msg_ok "Updated $APP to latest version"
|
msg_ok "Updated $APP to latest version"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start fileflows
|
systemctl start fileflows
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf "$temp_file"
|
|
||||||
rm -rf "$backup_filename"
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at latest version"
|
msg_ok "No update required. ${APP} is already at latest version"
|
||||||
|
|||||||
@@ -56,10 +56,6 @@ function update_script() {
|
|||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start ghostfolio
|
systemctl start ghostfolio
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
$STD npm cache clean --force
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -20,62 +20,57 @@ color
|
|||||||
catch_errors
|
catch_errors
|
||||||
|
|
||||||
function update_script() {
|
function update_script() {
|
||||||
header_info
|
header_info
|
||||||
check_container_storage
|
check_container_storage
|
||||||
check_container_resources
|
check_container_resources
|
||||||
|
|
||||||
if [[ ! -d /opt/jellyseerr ]]; then
|
if [[ ! -d /opt/jellyseerr ]]; then
|
||||||
msg_error "No ${APP} Installation Found!"
|
msg_error "No ${APP} Installation Found!"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$(node -v | cut -c2-3)" -ne 22 ]; then
|
if [ "$(node -v | cut -c2-3)" -ne 22 ]; then
|
||||||
msg_info "Updating Node.js Repository"
|
msg_info "Updating Node.js Repository"
|
||||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" >/etc/apt/sources.list.d/nodesource.list
|
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" >/etc/apt/sources.list.d/nodesource.list
|
||||||
msg_ok "Updating Node.js Repository"
|
msg_ok "Updating Node.js Repository"
|
||||||
|
|
||||||
msg_info "Updating Packages"
|
msg_info "Updating Packages"
|
||||||
$STD apt-get update
|
$STD apt-get update
|
||||||
$STD apt-get -y upgrade
|
$STD apt-get -y upgrade
|
||||||
msg_ok "Updating Packages"
|
msg_ok "Updating Packages"
|
||||||
|
fi
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
cd /opt/jellyseerr
|
||||||
apt-get -y autoremove
|
output=$(git pull --no-rebase)
|
||||||
apt-get -y autoclean
|
|
||||||
msg_ok "Cleaning up"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd /opt/jellyseerr
|
pnpm_current=$(pnpm --version 2>/dev/null)
|
||||||
output=$(git pull --no-rebase)
|
pnpm_desired=$(grep -Po '"pnpm":\s*"\K[^"]+' /opt/jellyseerr/package.json)
|
||||||
|
|
||||||
pnpm_current=$(pnpm --version 2>/dev/null)
|
if [ -z "$pnpm_current" ]; then
|
||||||
pnpm_desired=$(grep -Po '"pnpm":\s*"\K[^"]+' /opt/jellyseerr/package.json)
|
msg_error "pnpm not found. Installing version $pnpm_desired..."
|
||||||
|
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
|
||||||
|
elif ! node -e "const semver = require('semver'); process.exit(semver.satisfies('$pnpm_current', '$pnpm_desired') ? 0 : 1)"; then
|
||||||
|
msg_error "Updating pnpm from version $pnpm_current to $pnpm_desired..."
|
||||||
|
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
|
||||||
|
else
|
||||||
|
msg_ok "pnpm is already installed and satisfies version $pnpm_desired."
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -z "$pnpm_current" ]; then
|
msg_info "Updating $APP"
|
||||||
msg_error "pnpm not found. Installing version $pnpm_desired..."
|
if echo "$output" | grep -q "Already up to date."; then
|
||||||
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
|
msg_ok "$APP is already up to date."
|
||||||
elif ! node -e "const semver = require('semver'); process.exit(semver.satisfies('$pnpm_current', '$pnpm_desired') ? 0 : 1)"; then
|
exit
|
||||||
msg_error "Updating pnpm from version $pnpm_current to $pnpm_desired..."
|
fi
|
||||||
NODE_VERSION="22" NODE_MODULE="pnpm@$pnpm_desired" setup_nodejs
|
|
||||||
else
|
|
||||||
msg_ok "pnpm is already installed and satisfies version $pnpm_desired."
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_info "Updating $APP"
|
systemctl stop jellyseerr
|
||||||
if echo "$output" | grep -q "Already up to date."; then
|
rm -rf dist .next node_modules
|
||||||
msg_ok "$APP is already up to date."
|
export CYPRESS_INSTALL_BINARY=0
|
||||||
exit
|
cd /opt/jellyseerr
|
||||||
fi
|
$STD pnpm install --frozen-lockfile
|
||||||
|
export NODE_OPTIONS="--max-old-space-size=3072"
|
||||||
|
$STD pnpm build
|
||||||
|
|
||||||
systemctl stop jellyseerr
|
cat <<EOF >/etc/systemd/system/jellyseerr.service
|
||||||
rm -rf dist .next node_modules
|
|
||||||
export CYPRESS_INSTALL_BINARY=0
|
|
||||||
cd /opt/jellyseerr
|
|
||||||
$STD pnpm install --frozen-lockfile
|
|
||||||
export NODE_OPTIONS="--max-old-space-size=3072"
|
|
||||||
$STD pnpm build
|
|
||||||
|
|
||||||
cat <<EOF >/etc/systemd/system/jellyseerr.service
|
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=jellyseerr Service
|
Description=jellyseerr Service
|
||||||
After=network.target
|
After=network.target
|
||||||
@@ -91,10 +86,10 @@ ExecStart=/usr/bin/node dist/index.js
|
|||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl start jellyseerr
|
systemctl start jellyseerr
|
||||||
msg_ok "Updated $APP"
|
msg_ok "Updated $APP"
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
start
|
start
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ function update_script() {
|
|||||||
cd /opt/karakeep/packages/db
|
cd /opt/karakeep/packages/db
|
||||||
$STD pnpm migrate
|
$STD pnpm migrate
|
||||||
$STD pnpm store prune
|
$STD pnpm store prune
|
||||||
sed -i "s/^SERVER_VERSION=.*$/SERVER_VERSION=${CHECK_UPDATE_RELEASE}/" /etc/karakeep/karakeep.env
|
sed -i "s/^SERVER_VERSION=.*$/SERVER_VERSION=${CHECK_UPDATE_RELEASE#v}/" /etc/karakeep/karakeep.env
|
||||||
msg_ok "Updated Karakeep"
|
msg_ok "Updated Karakeep"
|
||||||
|
|
||||||
msg_info "Starting Services"
|
msg_info "Starting Services"
|
||||||
|
|||||||
@@ -49,15 +49,12 @@ function update_script() {
|
|||||||
cp -a keycloak.old/conf/. keycloak/conf/
|
cp -a keycloak.old/conf/. keycloak/conf/
|
||||||
cp -a keycloak.old/providers/. keycloak/providers/ 2>/dev/null || true
|
cp -a keycloak.old/providers/. keycloak/providers/ 2>/dev/null || true
|
||||||
cp -a keycloak.old/themes/. keycloak/themes/ 2>/dev/null || true
|
cp -a keycloak.old/themes/. keycloak/themes/ 2>/dev/null || true
|
||||||
|
rm -rf keycloak.old
|
||||||
msg_ok "Updated Keycloak"
|
msg_ok "Updated Keycloak"
|
||||||
|
|
||||||
msg_info "Restarting Service"
|
msg_info "Restarting Service"
|
||||||
systemctl restart keycloak
|
systemctl restart keycloak
|
||||||
msg_ok "Restarted Service"
|
msg_ok "Restarted Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf keycloak.old
|
|
||||||
msg_ok "Cleanup complete"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -50,15 +50,12 @@ function update_script() {
|
|||||||
$STD yarn install
|
$STD yarn install
|
||||||
$STD yarn build
|
$STD yarn build
|
||||||
chown -R www-data:www-data /opt/koillection/public/uploads
|
chown -R www-data:www-data /opt/koillection/public/uploads
|
||||||
|
rm -r /opt/koillection-backup
|
||||||
msg_ok "Updated Koillection"
|
msg_ok "Updated Koillection"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start apache2
|
systemctl start apache2
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -r /opt/koillection-backup
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated Successfully!"
|
msg_ok "Updated Successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -52,17 +52,14 @@ function update_script() {
|
|||||||
$STD yarn web:build
|
$STD yarn web:build
|
||||||
$STD yarn prisma:deploy
|
$STD yarn prisma:deploy
|
||||||
[ -d /opt/data.bak ] && mv /opt/data.bak /opt/linkwarden/data
|
[ -d /opt/data.bak ] && mv /opt/data.bak /opt/linkwarden/data
|
||||||
|
rm -rf ~/.cargo/registry ~/.cargo/git ~/.cargo/.package-cache ~/.rustup
|
||||||
|
rm -rf /root/.cache/yarn
|
||||||
|
rm -rf /opt/linkwarden/.next/cache
|
||||||
msg_ok "Updated ${APP}"
|
msg_ok "Updated ${APP}"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start linkwarden
|
systemctl start linkwarden
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf ~/.cargo/registry ~/.cargo/git ~/.cargo/.package-cache ~/.rustup
|
|
||||||
rm -rf /root/.cache/yarn
|
|
||||||
rm -rf /opt/linkwarden/.next/cache
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -42,15 +42,12 @@ function update_script() {
|
|||||||
mv /opt/listmonk-backup/config.toml /opt/listmonk/config.toml
|
mv /opt/listmonk-backup/config.toml /opt/listmonk/config.toml
|
||||||
mv /opt/listmonk-backup/uploads /opt/listmonk/uploads
|
mv /opt/listmonk-backup/uploads /opt/listmonk/uploads
|
||||||
$STD /opt/listmonk/listmonk --upgrade --yes --config /opt/listmonk/config.toml
|
$STD /opt/listmonk/listmonk --upgrade --yes --config /opt/listmonk/config.toml
|
||||||
|
rm -rf /opt/listmonk-backup/
|
||||||
msg_ok "Configured listmonk"
|
msg_ok "Configured listmonk"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start listmonk
|
systemctl start listmonk
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf /opt/listmonk-backup/
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -53,15 +53,12 @@ function update_script() {
|
|||||||
msg_info "Configuring LubeLogger"
|
msg_info "Configuring LubeLogger"
|
||||||
chmod 700 /opt/lubelogger/CarCareTracker
|
chmod 700 /opt/lubelogger/CarCareTracker
|
||||||
cp -rf /tmp/lubeloggerData/* /opt/lubelogger/
|
cp -rf /tmp/lubeloggerData/* /opt/lubelogger/
|
||||||
|
rm -rf /tmp/lubeloggerData
|
||||||
msg_ok "Configured LubeLogger"
|
msg_ok "Configured LubeLogger"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start lubelogger
|
systemctl start lubelogger
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf /tmp/lubeloggerData
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -38,15 +38,9 @@ function update_script() {
|
|||||||
curl -fsSL -o "$DEB_FILE" "$DEB_URL"
|
curl -fsSL -o "$DEB_FILE" "$DEB_URL"
|
||||||
$STD apt install "$DEB_FILE" -y
|
$STD apt install "$DEB_FILE" -y
|
||||||
systemctl restart lyrion
|
systemctl restart lyrion
|
||||||
|
$STD rm -f "$DEB_FILE"
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated $APP to ${RELEASE}"
|
msg_ok "Updated $APP to ${RELEASE}"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD rm -f "$DEB_FILE"
|
|
||||||
$STD apt -y autoremove
|
|
||||||
$STD apt -y autoclean
|
|
||||||
$STD apt -y clean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "$APP is already up to date (${RELEASE})"
|
msg_ok "$APP is already up to date (${RELEASE})"
|
||||||
|
|||||||
@@ -55,17 +55,13 @@ function update_script() {
|
|||||||
mv /usr/local/bin/minio /usr/local/bin/minio_bak
|
mv /usr/local/bin/minio /usr/local/bin/minio_bak
|
||||||
curl -fsSL "https://dl.min.io/server/minio/release/linux-amd64/minio" -o /usr/local/bin/minio
|
curl -fsSL "https://dl.min.io/server/minio/release/linux-amd64/minio" -o /usr/local/bin/minio
|
||||||
chmod +x /usr/local/bin/minio
|
chmod +x /usr/local/bin/minio
|
||||||
|
rm -f /usr/local/bin/minio_bak
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated ${APP}"
|
msg_ok "Updated ${APP}"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start minio
|
systemctl start minio
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -f /usr/local/bin/minio_bak
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
||||||
|
|||||||
@@ -52,15 +52,12 @@ function update_script() {
|
|||||||
$STD php artisan monica:update --force
|
$STD php artisan monica:update --force
|
||||||
chown -R www-data:www-data /opt/monica
|
chown -R www-data:www-data /opt/monica
|
||||||
chmod -R 775 /opt/monica/storage
|
chmod -R 775 /opt/monica/storage
|
||||||
|
rm -r /opt/monica-backup
|
||||||
msg_ok "Configured monica"
|
msg_ok "Configured monica"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start apache2
|
systemctl start apache2
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -r /opt/monica-backup
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -57,17 +57,14 @@ function update_script() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
$STD /opt/netbox/upgrade.sh
|
$STD /opt/netbox/upgrade.sh
|
||||||
|
rm -r "/opt/v${RELEASE}.zip"
|
||||||
|
rm -r /opt/netbox-backup
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated $APP to v${RELEASE}"
|
msg_ok "Updated $APP to v${RELEASE}"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start netbox netbox-rq
|
systemctl start netbox netbox-rq
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -r "/opt/v${RELEASE}.zip"
|
|
||||||
rm -r /opt/netbox-backup
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ function update_script() {
|
|||||||
|
|
||||||
cp /opt/netvisor.env.bak /opt/netvisor/.env
|
cp /opt/netvisor.env.bak /opt/netvisor/.env
|
||||||
LOCAL_IP="$(hostname -I | awk '{print $1}')"
|
LOCAL_IP="$(hostname -I | awk '{print $1}')"
|
||||||
if ! grep -q "PUBLIC_URL"; then
|
if ! grep -q "PUBLIC_URL" /opt/netvisor/.env; then
|
||||||
sed -i "\|_PATH=|a\NETVISOR_PUBLIC_URL=http://${LOCAL_IP}:60072" /opt/netvisor/.env
|
sed -i "\|_PATH=|a\NETVISOR_PUBLIC_URL=http://${LOCAL_IP}:60072" /opt/netvisor/.env
|
||||||
fi
|
fi
|
||||||
sed -i 's|_TARGET=.*$|_URL=http://127.0.0.1:60072|' /opt/netvisor/.env
|
sed -i 's|_TARGET=.*$|_URL=http://127.0.0.1:60072|' /opt/netvisor/.env
|
||||||
|
|||||||
@@ -21,37 +21,34 @@ color
|
|||||||
catch_errors
|
catch_errors
|
||||||
|
|
||||||
function update_script() {
|
function update_script() {
|
||||||
header_info
|
header_info
|
||||||
check_container_storage
|
check_container_storage
|
||||||
check_container_resources
|
check_container_resources
|
||||||
if [[ ! -d /opt/nextpvr ]]; then
|
if [[ ! -d /opt/nextpvr ]]; then
|
||||||
msg_error "No ${APP} Installation Found!"
|
msg_error "No ${APP} Installation Found!"
|
||||||
exit
|
|
||||||
fi
|
|
||||||
msg_info "Stopping Service"
|
|
||||||
systemctl stop nextpvr-server
|
|
||||||
msg_ok "Stopped Service"
|
|
||||||
|
|
||||||
msg_info "Updating LXC packages"
|
|
||||||
$STD apt update
|
|
||||||
$STD apt -y upgrade
|
|
||||||
msg_ok "Updated LXC packages"
|
|
||||||
|
|
||||||
msg_info "Updating ${APP}"
|
|
||||||
cd /opt
|
|
||||||
curl -fsSL "https://nextpvr.com/nextpvr-helper.deb" -o $(basename "https://nextpvr.com/nextpvr-helper.deb")
|
|
||||||
$STD dpkg -i nextpvr-helper.deb
|
|
||||||
msg_ok "Updated ${APP}"
|
|
||||||
|
|
||||||
msg_info "Starting Service"
|
|
||||||
systemctl start nextpvr-server
|
|
||||||
msg_ok "Started Service"
|
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /opt/nextpvr-helper.deb
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
|
||||||
exit
|
exit
|
||||||
|
fi
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop nextpvr-server
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
msg_info "Updating LXC packages"
|
||||||
|
$STD apt update
|
||||||
|
$STD apt -y upgrade
|
||||||
|
msg_ok "Updated LXC packages"
|
||||||
|
|
||||||
|
msg_info "Updating ${APP}"
|
||||||
|
cd /opt
|
||||||
|
curl -fsSL "https://nextpvr.com/nextpvr-helper.deb" -o $(basename "https://nextpvr.com/nextpvr-helper.deb")
|
||||||
|
$STD dpkg -i nextpvr-helper.deb
|
||||||
|
rm -rf /opt/nextpvr-helper.deb
|
||||||
|
msg_ok "Updated ${APP}"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start nextpvr-server
|
||||||
|
msg_ok "Started Service"
|
||||||
|
msg_ok "Updated successfully!"
|
||||||
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
start
|
start
|
||||||
|
|||||||
@@ -42,17 +42,13 @@ function update_script() {
|
|||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
export DEBCONF_NOWARNINGS=yes
|
export DEBCONF_NOWARNINGS=yes
|
||||||
$STD dpkg -i nxwitness-server-$RELEASE-linux_x64.deb
|
$STD dpkg -i nxwitness-server-$RELEASE-linux_x64.deb
|
||||||
|
rm -f /tmp/nxwitness-server-$RELEASE-linux_x64.deb
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated ${APP}"
|
msg_ok "Updated ${APP}"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start networkoptix-root-tool networkoptix-mediaserver
|
systemctl start networkoptix-root-tool networkoptix-mediaserver
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -f /tmp/nxwitness-server-$RELEASE-linux_x64.deb
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
||||||
|
|||||||
@@ -50,17 +50,13 @@ function update_script() {
|
|||||||
msg_info "Updating ${APP} to ${LATEST_VERSION}"
|
msg_info "Updating ${APP} to ${LATEST_VERSION}"
|
||||||
curl -fsSL https://nightly.odoo.com/${RELEASE}/nightly/deb/odoo_${RELEASE}.latest_all.deb -o /opt/odoo.deb
|
curl -fsSL https://nightly.odoo.com/${RELEASE}/nightly/deb/odoo_${RELEASE}.latest_all.deb -o /opt/odoo.deb
|
||||||
$STD apt install -y /opt/odoo.deb
|
$STD apt install -y /opt/odoo.deb
|
||||||
|
rm -f /opt/odoo.deb
|
||||||
echo "$LATEST_VERSION" >/opt/${APP}_version.txt
|
echo "$LATEST_VERSION" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated ${APP} to ${LATEST_VERSION}"
|
msg_ok "Updated ${APP} to ${LATEST_VERSION}"
|
||||||
|
|
||||||
msg_info "Starting ${APP} service"
|
msg_info "Starting Service"
|
||||||
systemctl start odoo
|
systemctl start odoo
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -f /opt/odoo.deb
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at ${LATEST_VERSION}"
|
msg_ok "No update required. ${APP} is already at ${LATEST_VERSION}"
|
||||||
|
|||||||
@@ -43,16 +43,13 @@ function update_script() {
|
|||||||
mkdir -p /usr/local/lib/ollama
|
mkdir -p /usr/local/lib/ollama
|
||||||
tar -xzf "${TMP_TAR}" -C /usr/local/lib/ollama
|
tar -xzf "${TMP_TAR}" -C /usr/local/lib/ollama
|
||||||
ln -sf /usr/local/lib/ollama/bin/ollama /usr/local/bin/ollama
|
ln -sf /usr/local/lib/ollama/bin/ollama /usr/local/bin/ollama
|
||||||
|
rm -f "${TMP_TAR}"
|
||||||
echo "${RELEASE}" >/opt/Ollama_version.txt
|
echo "${RELEASE}" >/opt/Ollama_version.txt
|
||||||
msg_ok "Updated Ollama to ${RELEASE}"
|
msg_ok "Updated Ollama to ${RELEASE}"
|
||||||
|
|
||||||
msg_info "Starting Services"
|
msg_info "Starting Services"
|
||||||
systemctl start ollama
|
systemctl start ollama
|
||||||
msg_ok "Started Services"
|
msg_ok "Started Services"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -f "${TMP_TAR}"
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. Ollama is already at ${RELEASE}"
|
msg_ok "No update required. Ollama is already at ${RELEASE}"
|
||||||
|
|||||||
@@ -39,17 +39,14 @@ function update_script() {
|
|||||||
tar -xzf onedev-latest.tar.gz
|
tar -xzf onedev-latest.tar.gz
|
||||||
$STD /opt/onedev-latest/bin/upgrade.sh /opt/onedev
|
$STD /opt/onedev-latest/bin/upgrade.sh /opt/onedev
|
||||||
RELEASE=$(cat /opt/onedev/release.properties | grep "version" | cut -d'=' -f2)
|
RELEASE=$(cat /opt/onedev/release.properties | grep "version" | cut -d'=' -f2)
|
||||||
|
rm -rf /opt/onedev-latest
|
||||||
|
rm -rf /opt/onedev-latest.tar.gz
|
||||||
echo "${RELEASE}" >"/opt/${APP}_version.txt"
|
echo "${RELEASE}" >"/opt/${APP}_version.txt"
|
||||||
msg_ok "Updated ${APP} to v${RELEASE}"
|
msg_ok "Updated ${APP} to v${RELEASE}"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start onedev
|
systemctl start onedev
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf /opt/onedev-latest
|
|
||||||
rm -rf /opt/onedev-latest.tar.gz
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at v${RELEASE}."
|
msg_ok "No update required. ${APP} is already at v${RELEASE}."
|
||||||
|
|||||||
@@ -65,17 +65,14 @@ EOF
|
|||||||
$STD pip install --no-cache-dir -r requirements.txt
|
$STD pip install --no-cache-dir -r requirements.txt
|
||||||
mkdir -p data/chromadb
|
mkdir -p data/chromadb
|
||||||
$STD npm install
|
$STD npm install
|
||||||
|
rm -rf /opt/v${RELEASE}.zip
|
||||||
|
rm -rf /opt/paperless-ai_bak
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated $APP to v${RELEASE}"
|
msg_ok "Updated $APP to v${RELEASE}"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start paperless-ai
|
systemctl start paperless-ai
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /opt/v${RELEASE}.zip
|
|
||||||
rm -rf /opt/paperless-ai_bak
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
||||||
|
|||||||
@@ -20,48 +20,45 @@ color
|
|||||||
catch_errors
|
catch_errors
|
||||||
|
|
||||||
function update_script() {
|
function update_script() {
|
||||||
header_info
|
header_info
|
||||||
check_container_storage
|
check_container_storage
|
||||||
check_container_resources
|
check_container_resources
|
||||||
if [[ ! -d /opt/paperless-gpt ]]; then
|
if [[ ! -d /opt/paperless-gpt ]]; then
|
||||||
msg_error "No Paperless-GPT installation found!"
|
msg_error "No Paperless-GPT installation found!"
|
||||||
exit
|
|
||||||
fi
|
|
||||||
RELEASE=$(curl -fsSL https://api.github.com/repos/icereed/paperless-gpt/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
|
|
||||||
if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
|
|
||||||
msg_info "Stopping Service"
|
|
||||||
systemctl stop paperless-gpt
|
|
||||||
msg_ok "Service Stopped"
|
|
||||||
|
|
||||||
msg_info "Updating Paperless-GPT to ${RELEASE}"
|
|
||||||
temp_file=$(mktemp)
|
|
||||||
curl -fsSL "https://github.com/icereed/paperless-gpt/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file"
|
|
||||||
tar zxf $temp_file
|
|
||||||
rm -rf /opt/paperless-gpt
|
|
||||||
mv paperless-gpt-${RELEASE} /opt/paperless-gpt
|
|
||||||
cd /opt/paperless-gpt/web-app
|
|
||||||
$STD npm install
|
|
||||||
$STD npm run build
|
|
||||||
cd /opt/paperless-gpt
|
|
||||||
go mod download
|
|
||||||
export CC=musl-gcc
|
|
||||||
CGO_ENABLED=1 go build -tags musl -o /dev/null github.com/mattn/go-sqlite3
|
|
||||||
CGO_ENABLED=1 go build -tags musl -o paperless-gpt .
|
|
||||||
echo "${RELEASE}" >"/opt/paperless-gpt_version.txt"
|
|
||||||
msg_ok "Updated Paperless-GPT to ${RELEASE}"
|
|
||||||
|
|
||||||
msg_info "Starting Service"
|
|
||||||
systemctl start paperless-gpt
|
|
||||||
msg_ok "Started Service"
|
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -f $temp_file
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
|
||||||
else
|
|
||||||
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
|
||||||
fi
|
|
||||||
exit
|
exit
|
||||||
|
fi
|
||||||
|
RELEASE=$(curl -fsSL https://api.github.com/repos/icereed/paperless-gpt/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
|
||||||
|
if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop paperless-gpt
|
||||||
|
msg_ok "Service Stopped"
|
||||||
|
|
||||||
|
msg_info "Updating Paperless-GPT to ${RELEASE}"
|
||||||
|
temp_file=$(mktemp)
|
||||||
|
curl -fsSL "https://github.com/icereed/paperless-gpt/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file"
|
||||||
|
tar zxf $temp_file
|
||||||
|
rm -rf /opt/paperless-gpt
|
||||||
|
mv paperless-gpt-${RELEASE} /opt/paperless-gpt
|
||||||
|
cd /opt/paperless-gpt/web-app
|
||||||
|
$STD npm install
|
||||||
|
$STD npm run build
|
||||||
|
cd /opt/paperless-gpt
|
||||||
|
go mod download
|
||||||
|
export CC=musl-gcc
|
||||||
|
CGO_ENABLED=1 go build -tags musl -o /dev/null github.com/mattn/go-sqlite3
|
||||||
|
CGO_ENABLED=1 go build -tags musl -o paperless-gpt .
|
||||||
|
rm -f $temp_file
|
||||||
|
echo "${RELEASE}" >"/opt/paperless-gpt_version.txt"
|
||||||
|
msg_ok "Updated Paperless-GPT to ${RELEASE}"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start paperless-gpt
|
||||||
|
msg_ok "Started Service"
|
||||||
|
msg_ok "Updated successfully!"
|
||||||
|
else
|
||||||
|
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
||||||
|
fi
|
||||||
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
start
|
start
|
||||||
|
|||||||
@@ -52,17 +52,14 @@ function update_script() {
|
|||||||
$STD php bin/console cache:clear
|
$STD php bin/console cache:clear
|
||||||
$STD php bin/console doctrine:migrations:migrate -n
|
$STD php bin/console doctrine:migrations:migrate -n
|
||||||
chown -R www-data:www-data /opt/partdb
|
chown -R www-data:www-data /opt/partdb
|
||||||
|
rm -r "/opt/v${RELEASE}.zip"
|
||||||
|
rm -r /opt/partdb-backup
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated $APP to v${RELEASE}"
|
msg_ok "Updated $APP to v${RELEASE}"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start apache2
|
systemctl start apache2
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -r "/opt/v${RELEASE}.zip"
|
|
||||||
rm -r /opt/partdb-backup
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ function update_script() {
|
|||||||
$STD php artisan migrate --seed --force
|
$STD php artisan migrate --seed --force
|
||||||
chown -R www-data:www-data /opt/pelican-panel
|
chown -R www-data:www-data /opt/pelican-panel
|
||||||
chmod -R 755 /opt/pelican-panel/storage /opt/pelican-panel/bootstrap/cache/
|
chmod -R 755 /opt/pelican-panel/storage /opt/pelican-panel/bootstrap/cache/
|
||||||
|
rm -rf "/opt/pelican-panel/panel.tar.gz"
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated $APP to v${RELEASE}"
|
msg_ok "Updated $APP to v${RELEASE}"
|
||||||
|
|
||||||
@@ -74,10 +75,6 @@ function update_script() {
|
|||||||
$STD php artisan queue:restart
|
$STD php artisan queue:restart
|
||||||
$STD php artisan up
|
$STD php artisan up
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf "/opt/pelican-panel/panel.tar.gz"
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ EOF
|
|||||||
$STD php artisan migrate --seed --force --no-interaction
|
$STD php artisan migrate --seed --force --no-interaction
|
||||||
chown -R www-data:www-data /opt/pterodactyl-panel/*
|
chown -R www-data:www-data /opt/pterodactyl-panel/*
|
||||||
chmod -R 755 /opt/pterodactyl-panel/storage /opt/pterodactyl-panel/bootstrap/cache/
|
chmod -R 755 /opt/pterodactyl-panel/storage /opt/pterodactyl-panel/bootstrap/cache/
|
||||||
|
rm -rf "/opt/pterodactyl-panel/panel.tar.gz"
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated $APP to v${RELEASE}"
|
msg_ok "Updated $APP to v${RELEASE}"
|
||||||
|
|
||||||
@@ -77,10 +78,6 @@ EOF
|
|||||||
$STD php artisan queue:restart
|
$STD php artisan queue:restart
|
||||||
$STD php artisan up
|
$STD php artisan up
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf "/opt/pterodactyl-panel/panel.tar.gz"
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
||||||
|
|||||||
@@ -43,14 +43,11 @@ function update_script() {
|
|||||||
$STD apt remove --purge -y dotnet-sdk-8.0
|
$STD apt remove --purge -y dotnet-sdk-8.0
|
||||||
$STD apt install -y dotnet-sdk-9.0
|
$STD apt install -y dotnet-sdk-9.0
|
||||||
fi
|
fi
|
||||||
|
rm -rf /opt/rdtc-backup
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start rdtc
|
systemctl start rdtc
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /opt/rdtc-backup
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ function update_script() {
|
|||||||
cd /tmp
|
cd /tmp
|
||||||
curl -fsSL https://dl.min.io/server/minio/release/linux-amd64/minio.deb -o minio.deb
|
curl -fsSL https://dl.min.io/server/minio/release/linux-amd64/minio.deb -o minio.deb
|
||||||
$STD dpkg -i minio.deb
|
$STD dpkg -i minio.deb
|
||||||
|
rm -f /tmp/minio.deb
|
||||||
msg_ok "Updated Minio"
|
msg_ok "Updated Minio"
|
||||||
|
|
||||||
msg_info "Updating Browserless (Patience)"
|
msg_info "Updating Browserless (Patience)"
|
||||||
@@ -75,16 +76,12 @@ function update_script() {
|
|||||||
$STD npm run build:function
|
$STD npm run build:function
|
||||||
$STD npm prune production
|
$STD npm prune production
|
||||||
mv /opt/browserless.env /opt/browserless/.env
|
mv /opt/browserless.env /opt/browserless/.env
|
||||||
|
rm -f "$brwsr_tmp"
|
||||||
msg_ok "Updated Browserless"
|
msg_ok "Updated Browserless"
|
||||||
|
|
||||||
msg_info "Restarting services"
|
msg_info "Restarting services"
|
||||||
systemctl start minio Reactive-Resume browserless
|
systemctl start minio Reactive-Resume browserless
|
||||||
msg_ok "Restarted services"
|
msg_ok "Restarted services"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -f /tmp/minio.deb
|
|
||||||
rm -f "$brwsr_tmp"
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -41,15 +41,12 @@ function update_script() {
|
|||||||
$STD npm install
|
$STD npm install
|
||||||
cp -f /opt/index.html /opt/revealjs
|
cp -f /opt/index.html /opt/revealjs
|
||||||
sed -i '25s/localhost/0.0.0.0/g' /opt/revealjs/gulpfile.js
|
sed -i '25s/localhost/0.0.0.0/g' /opt/revealjs/gulpfile.js
|
||||||
|
rm -f /opt/index.html
|
||||||
msg_ok "Updated $APP"
|
msg_ok "Updated $APP"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start revealjs
|
systemctl start revealjs
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -f /opt/index.html
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -61,15 +61,12 @@ function update_script() {
|
|||||||
$STD pip install -r requirements.txt
|
$STD pip install -r requirements.txt
|
||||||
mv /opt/config.ini.bak /opt/soularr/config.ini
|
mv /opt/config.ini.bak /opt/soularr/config.ini
|
||||||
mv /opt/run.sh.bak /opt/soularr/run.sh
|
mv /opt/run.sh.bak /opt/soularr/run.sh
|
||||||
|
rm -rf /tmp/main.zip
|
||||||
msg_ok "Updated soularr"
|
msg_ok "Updated soularr"
|
||||||
|
|
||||||
msg_info "Starting soularr timer"
|
msg_info "Starting soularr timer"
|
||||||
systemctl start soularr.timer
|
systemctl start soularr.timer
|
||||||
msg_ok "Started soularr timer"
|
msg_ok "Started soularr timer"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /tmp/main.zip
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,17 +43,13 @@ function update_script() {
|
|||||||
cd spoolman
|
cd spoolman
|
||||||
$STD pip3 install -r requirements.txt
|
$STD pip3 install -r requirements.txt
|
||||||
curl -fsSL "https://raw.githubusercontent.com/Donkie/Spoolman/master/.env.example" -o ".env"
|
curl -fsSL "https://raw.githubusercontent.com/Donkie/Spoolman/master/.env.example" -o ".env"
|
||||||
|
rm -rf /opt/spoolman.zip
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated ${APP} to ${RELEASE}"
|
msg_ok "Updated ${APP} to ${RELEASE}"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start spoolman
|
systemctl start spoolman
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf /opt/spoolman.zip
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
||||||
|
|||||||
@@ -64,16 +64,13 @@ EOF
|
|||||||
cd /opt/tandoor
|
cd /opt/tandoor
|
||||||
$STD /opt/tandoor/.venv/bin/python manage.py migrate
|
$STD /opt/tandoor/.venv/bin/python manage.py migrate
|
||||||
$STD /opt/tandoor/.venv/bin/python manage.py collectstatic --no-input
|
$STD /opt/tandoor/.venv/bin/python manage.py collectstatic --no-input
|
||||||
|
rm -rf /opt/tandoor.bak
|
||||||
msg_ok "Updated Trandoor"
|
msg_ok "Updated Trandoor"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start tandoor
|
systemctl start tandoor
|
||||||
systemctl reload nginx
|
systemctl reload nginx
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /opt/tandoor.bak
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -45,16 +45,13 @@ function update_script() {
|
|||||||
export NODE_OPTIONS=--openssl-legacy-provider
|
export NODE_OPTIONS=--openssl-legacy-provider
|
||||||
$STD npm i
|
$STD npm i
|
||||||
$STD yarn build
|
$STD yarn build
|
||||||
|
rm -r "/opt/v${RELEASE}.tar.gz"
|
||||||
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated TasmoCompiler"
|
msg_ok "Updated TasmoCompiler"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start tasmocompiler
|
systemctl start tasmocompiler
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -r "/opt/v${RELEASE}.tar.gz"
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
||||||
|
|||||||
@@ -37,11 +37,8 @@ function update_script() {
|
|||||||
$STD unzip Tdarr_Updater.zip
|
$STD unzip Tdarr_Updater.zip
|
||||||
chmod +x Tdarr_Updater
|
chmod +x Tdarr_Updater
|
||||||
$STD ./Tdarr_Updater
|
$STD ./Tdarr_Updater
|
||||||
msg_ok "Updated Tdarr"
|
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf /opt/tdarr/Tdarr_Updater.zip
|
rm -rf /opt/tdarr/Tdarr_Updater.zip
|
||||||
msg_ok "Cleaned up"
|
msg_ok "Updated Tdarr"
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,11 +38,8 @@ function update_script() {
|
|||||||
msg_info "Updating Technitium DNS"
|
msg_info "Updating Technitium DNS"
|
||||||
curl -fsSL "https://download.technitium.com/dns/DnsServerPortable.tar.gz" -o /opt/DnsServerPortable.tar.gz
|
curl -fsSL "https://download.technitium.com/dns/DnsServerPortable.tar.gz" -o /opt/DnsServerPortable.tar.gz
|
||||||
$STD tar zxvf /opt/DnsServerPortable.tar.gz -C /opt/technitium/dns/
|
$STD tar zxvf /opt/DnsServerPortable.tar.gz -C /opt/technitium/dns/
|
||||||
msg_ok "Updated Technitium DNS"
|
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -f /opt/DnsServerPortable.tar.gz
|
rm -f /opt/DnsServerPortable.tar.gz
|
||||||
msg_ok "Cleaned up"
|
msg_ok "Updated Technitium DNS"
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. Technitium DNS is already at v${RELEASE}."
|
msg_ok "No update required. Technitium DNS is already at v${RELEASE}."
|
||||||
|
|||||||
@@ -41,15 +41,12 @@ function update_script() {
|
|||||||
|
|
||||||
msg_info "Restoring data"
|
msg_info "Restoring data"
|
||||||
cp -R /opt/teddycloud_bak/certs /opt/teddycloud_bak/config /opt/teddycloud_bak/data /opt/teddycloud
|
cp -R /opt/teddycloud_bak/certs /opt/teddycloud_bak/config /opt/teddycloud_bak/data /opt/teddycloud
|
||||||
|
rm -rf /opt/teddycloud_bak
|
||||||
msg_ok "Data restored"
|
msg_ok "Data restored"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start teddycloud
|
systemctl start teddycloud
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf /opt/teddycloud_bak
|
|
||||||
msg_ok "Cleaned up"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
15
ct/tianji.sh
15
ct/tianji.sh
@@ -43,7 +43,7 @@ function update_script() {
|
|||||||
|
|
||||||
fetch_and_deploy_gh_release "tianji" "msgbyte/tianji"
|
fetch_and_deploy_gh_release "tianji" "msgbyte/tianji"
|
||||||
|
|
||||||
msg_info "Updating ${APP}"
|
msg_info "Updating Tianji"
|
||||||
cd /opt/tianji
|
cd /opt/tianji
|
||||||
export NODE_OPTIONS="--max_old_space_size=4096"
|
export NODE_OPTIONS="--max_old_space_size=4096"
|
||||||
$STD pnpm install --filter @tianji/client... --config.dedupe-peer-dependents=false --frozen-lockfile
|
$STD pnpm install --filter @tianji/client... --config.dedupe-peer-dependents=false --frozen-lockfile
|
||||||
@@ -55,7 +55,11 @@ function update_script() {
|
|||||||
mv /opt/.env /opt/tianji/src/server/.env
|
mv /opt/.env /opt/tianji/src/server/.env
|
||||||
cd src/server
|
cd src/server
|
||||||
$STD pnpm db:migrate:apply
|
$STD pnpm db:migrate:apply
|
||||||
msg_ok "Updated ${APP}"
|
rm -rf /opt/tianji_bak
|
||||||
|
rm -rf /opt/tianji/src/client
|
||||||
|
rm -rf /opt/tianji/website
|
||||||
|
rm -rf /opt/tianji/reporter
|
||||||
|
msg_ok "Updated Tianji"
|
||||||
|
|
||||||
msg_info "Updating AppRise"
|
msg_info "Updating AppRise"
|
||||||
$STD uv pip install apprise cryptography --system
|
$STD uv pip install apprise cryptography --system
|
||||||
@@ -64,13 +68,6 @@ function update_script() {
|
|||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start tianji
|
systemctl start tianji
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf /opt/tianji_bak
|
|
||||||
rm -rf /opt/tianji/src/client
|
|
||||||
rm -rf /opt/tianji/website
|
|
||||||
rm -rf /opt/tianji/reporter
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -50,18 +50,12 @@ function update_script() {
|
|||||||
mv /opt/traccar.xml /opt/traccar/conf
|
mv /opt/traccar.xml /opt/traccar/conf
|
||||||
[[ -d /opt/data ]] && mv /opt/data /opt/traccar
|
[[ -d /opt/data ]] && mv /opt/data /opt/traccar
|
||||||
[[ -d /opt/media ]] && mv /opt/media /opt/traccar
|
[[ -d /opt/media ]] && mv /opt/media /opt/traccar
|
||||||
|
[ -f README.txt ] || [ -f traccar.run ] && rm -f README.txt traccar.run
|
||||||
msg_ok "Data restored"
|
msg_ok "Data restored"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start traccar
|
systemctl start traccar
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
[ -f README.txt ] || [ -f traccar.run ] && rm -f README.txt traccar.run
|
|
||||||
$STD apt -y autoremove
|
|
||||||
$STD apt -y autoclean
|
|
||||||
$STD apt -y clean
|
|
||||||
msg_ok "Cleaned up"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -55,14 +55,8 @@ function update_script() {
|
|||||||
msg_info "Restoring Database"
|
msg_info "Restoring Database"
|
||||||
mkdir -p "$(dirname "${DB_RESTORE_PATH}")"
|
mkdir -p "$(dirname "${DB_RESTORE_PATH}")"
|
||||||
cp -r /opt/trilium_backup/$(basename "${DB_PATH}") "${DB_RESTORE_PATH}"
|
cp -r /opt/trilium_backup/$(basename "${DB_PATH}") "${DB_RESTORE_PATH}"
|
||||||
msg_ok "Restored Database"
|
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf /opt/trilium_backup
|
rm -rf /opt/trilium_backup
|
||||||
$STD apt -y autoremove
|
msg_ok "Restored Database"
|
||||||
$STD apt -y autoclean
|
|
||||||
$STD apt -y clean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start trilium
|
systemctl start trilium
|
||||||
|
|||||||
@@ -43,12 +43,6 @@ function update_script() {
|
|||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start uhf-server
|
systemctl start uhf-server
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
$STD apt -y autoremove
|
|
||||||
$STD apt -y autoclean
|
|
||||||
$STD apt -y clean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -57,11 +57,8 @@ function update_script() {
|
|||||||
else
|
else
|
||||||
cp target/release/vaultwarden /opt/vaultwarden/bin/
|
cp target/release/vaultwarden /opt/vaultwarden/bin/
|
||||||
fi
|
fi
|
||||||
msg_ok "Updated VaultWarden"
|
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
cd ~ && rm -rf vaultwarden
|
cd ~ && rm -rf vaultwarden
|
||||||
msg_ok "Cleaned"
|
msg_ok "Updated VaultWarden"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start vaultwarden
|
systemctl start vaultwarden
|
||||||
@@ -77,11 +74,8 @@ function update_script() {
|
|||||||
msg_info "Updating Web-Vault to $WVRELEASE"
|
msg_info "Updating Web-Vault to $WVRELEASE"
|
||||||
$STD curl -fsSLO https://github.com/dani-garcia/bw_web_builds/releases/download/"$WVRELEASE"/bw_web_"$WVRELEASE".tar.gz
|
$STD curl -fsSLO https://github.com/dani-garcia/bw_web_builds/releases/download/"$WVRELEASE"/bw_web_"$WVRELEASE".tar.gz
|
||||||
$STD tar -zxf bw_web_"$WVRELEASE".tar.gz -C /opt/vaultwarden/
|
$STD tar -zxf bw_web_"$WVRELEASE".tar.gz -C /opt/vaultwarden/
|
||||||
msg_ok "Updated Web-Vault"
|
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm bw_web_"$WVRELEASE".tar.gz
|
rm bw_web_"$WVRELEASE".tar.gz
|
||||||
msg_ok "Cleaned"
|
msg_ok "Updated Web-Vault"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start vaultwarden
|
systemctl start vaultwarden
|
||||||
|
|||||||
@@ -39,16 +39,13 @@ function update_script() {
|
|||||||
curl -fsSL "https://dl.vikunja.io/vikunja/$RELEASE/vikunja-$RELEASE-amd64.deb" -o $(basename "https://dl.vikunja.io/vikunja/$RELEASE/vikunja-$RELEASE-amd64.deb")
|
curl -fsSL "https://dl.vikunja.io/vikunja/$RELEASE/vikunja-$RELEASE-amd64.deb" -o $(basename "https://dl.vikunja.io/vikunja/$RELEASE/vikunja-$RELEASE-amd64.deb")
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
$STD dpkg -i vikunja-"$RELEASE"-amd64.deb
|
$STD dpkg -i vikunja-"$RELEASE"-amd64.deb
|
||||||
|
rm -rf /opt/vikunja-"$RELEASE"-amd64.deb
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated ${APP}"
|
msg_ok "Updated ${APP}"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start vikunja
|
systemctl start vikunja
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /opt/vikunja-"$RELEASE"-amd64.deb
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
||||||
|
|||||||
@@ -73,16 +73,13 @@ EOF
|
|||||||
cp -f wastebin* /opt/wastebin/
|
cp -f wastebin* /opt/wastebin/
|
||||||
chmod +x /opt/wastebin/wastebin
|
chmod +x /opt/wastebin/wastebin
|
||||||
chmod +x /opt/wastebin/wastebin-ctl
|
chmod +x /opt/wastebin/wastebin-ctl
|
||||||
|
rm -f "$temp_file"
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated Wastebin"
|
msg_ok "Updated Wastebin"
|
||||||
|
|
||||||
msg_info "Starting Wastebin"
|
msg_info "Starting Wastebin"
|
||||||
systemctl start wastebin
|
systemctl start wastebin
|
||||||
msg_ok "Started Wastebin"
|
msg_ok "Started Wastebin"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -f "$temp_file"
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
||||||
|
|||||||
@@ -37,10 +37,7 @@ function update_script() {
|
|||||||
fetch_and_deploy_gh_release "watchyourlan" "aceberg/WatchYourLAN" "binary"
|
fetch_and_deploy_gh_release "watchyourlan" "aceberg/WatchYourLAN" "binary"
|
||||||
cp -R config.yaml /data/config.yaml
|
cp -R config.yaml /data/config.yaml
|
||||||
sed -i 's|/etc/watchyourlan/config.yaml|/data/config.yaml|' /lib/systemd/system/watchyourlan.service
|
sed -i 's|/etc/watchyourlan/config.yaml|/data/config.yaml|' /lib/systemd/system/watchyourlan.service
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm ~/config.yaml
|
rm ~/config.yaml
|
||||||
msg_ok "Cleaned up"
|
|
||||||
|
|
||||||
msg_info "Starting service"
|
msg_info "Starting service"
|
||||||
systemctl enable -q --now watchyourlan
|
systemctl enable -q --now watchyourlan
|
||||||
|
|||||||
@@ -45,16 +45,13 @@ function update_script() {
|
|||||||
$STD python3 manage.py collectstatic --no-input
|
$STD python3 manage.py collectstatic --no-input
|
||||||
$STD yarn install
|
$STD yarn install
|
||||||
$STD yarn build:css:sass
|
$STD yarn build:css:sass
|
||||||
|
rm -rf "$temp_file"
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
echo "${RELEASE}" >/opt/${APP}_version.txt
|
||||||
msg_ok "Updated $APP to v${RELEASE}"
|
msg_ok "Updated $APP to v${RELEASE}"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start wger
|
systemctl start wger
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf "$temp_file"
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
||||||
|
|||||||
@@ -54,15 +54,12 @@ function update_script() {
|
|||||||
msg_info "Restoring Data"
|
msg_info "Restoring Data"
|
||||||
cp -R /opt/wikijs-backup/* /opt/wikijs
|
cp -R /opt/wikijs-backup/* /opt/wikijs
|
||||||
$SQLITE_INSTALL && $STD npm rebuild sqlite3
|
$SQLITE_INSTALL && $STD npm rebuild sqlite3
|
||||||
|
rm -rf /opt/wikijs-backup
|
||||||
msg_ok "Restored Data"
|
msg_ok "Restored Data"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start wikijs
|
systemctl start wikijs
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /opt/wikijs-backup
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -56,15 +56,12 @@ function update_script() {
|
|||||||
if ! grep -q 'frozen' /opt/wizarr/start.sh; then
|
if ! grep -q 'frozen' /opt/wizarr/start.sh; then
|
||||||
sed -i 's/run/& --frozen/' /opt/wizarr/start.sh
|
sed -i 's/run/& --frozen/' /opt/wizarr/start.sh
|
||||||
fi
|
fi
|
||||||
|
rm -rf "$BACKUP_FILE"
|
||||||
msg_ok "Updated Wizarr"
|
msg_ok "Updated Wizarr"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start wizarr
|
systemctl start wizarr
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf "$BACKUP_FILE"
|
|
||||||
msg_ok "Cleanup Completed"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ function update_script() {
|
|||||||
xargs -I{} echo "https://repo.zabbix.com/zabbix/{}/release/debian/pool/main/z/zabbix-release/zabbix-release_latest+debian13_all.deb")" \
|
xargs -I{} echo "https://repo.zabbix.com/zabbix/{}/release/debian/pool/main/z/zabbix-release/zabbix-release_latest+debian13_all.deb")" \
|
||||||
-o /tmp/zabbix-release_latest+debian13_all.deb
|
-o /tmp/zabbix-release_latest+debian13_all.deb
|
||||||
$STD dpkg -i zabbix-release_latest+debian13_all.deb
|
$STD dpkg -i zabbix-release_latest+debian13_all.deb
|
||||||
|
rm -rf /tmp/zabbix-release_latest+debian13_all.deb
|
||||||
$STD apt update
|
$STD apt update
|
||||||
|
|
||||||
$STD apt install --only-upgrade zabbix-server-pgsql zabbix-frontend-php php8.4-pgsql
|
$STD apt install --only-upgrade zabbix-server-pgsql zabbix-frontend-php php8.4-pgsql
|
||||||
@@ -88,13 +89,6 @@ function update_script() {
|
|||||||
systemctl start "$AGENT_SERVICE"
|
systemctl start "$AGENT_SERVICE"
|
||||||
systemctl restart apache2
|
systemctl restart apache2
|
||||||
msg_ok "Started Services"
|
msg_ok "Started Services"
|
||||||
|
|
||||||
msg_info "Cleaning Up"
|
|
||||||
rm -rf /tmp/zabbix-release_latest+debian13_all.deb
|
|
||||||
$STD apt -y autoremove
|
|
||||||
$STD apt -y autoclean
|
|
||||||
$STD apt -y clean
|
|
||||||
msg_ok "Cleaned"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,18 +47,15 @@ function update_script() {
|
|||||||
rm -rf /opt/zigbee2mqtt/data
|
rm -rf /opt/zigbee2mqtt/data
|
||||||
mv /opt/z2m_backup/data /opt/zigbee2mqtt
|
mv /opt/z2m_backup/data /opt/zigbee2mqtt
|
||||||
cd /opt/zigbee2mqtt
|
cd /opt/zigbee2mqtt
|
||||||
grep -q "^packageImportMethod" ./pnpm-workspace.yaml || echo "packageImportMethod: hardlink" >> ./pnpm-workspace.yaml
|
grep -q "^packageImportMethod" ./pnpm-workspace.yaml || echo "packageImportMethod: hardlink" >>./pnpm-workspace.yaml
|
||||||
$STD pnpm install --frozen-lockfile
|
$STD pnpm install --frozen-lockfile
|
||||||
$STD pnpm build
|
$STD pnpm build
|
||||||
|
rm -rf /opt/z2m_backup
|
||||||
msg_ok "Updated Zigbee2MQTT"
|
msg_ok "Updated Zigbee2MQTT"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
systemctl start zigbee2mqtt
|
systemctl start zigbee2mqtt
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_info "Cleaning up"
|
|
||||||
rm -rf /opt/z2m_backup
|
|
||||||
msg_ok "Cleaned up"
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
100
frontend/bun.lock
generated
100
frontend/bun.lock
generated
@@ -11,6 +11,7 @@
|
|||||||
"@radix-ui/react-label": "^2.1.2",
|
"@radix-ui/react-label": "^2.1.2",
|
||||||
"@radix-ui/react-navigation-menu": "^1.2.5",
|
"@radix-ui/react-navigation-menu": "^1.2.5",
|
||||||
"@radix-ui/react-popover": "^1.1.6",
|
"@radix-ui/react-popover": "^1.1.6",
|
||||||
|
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||||
"@radix-ui/react-select": "^2.1.6",
|
"@radix-ui/react-select": "^2.1.6",
|
||||||
"@radix-ui/react-separator": "^1.1.2",
|
"@radix-ui/react-separator": "^1.1.2",
|
||||||
"@radix-ui/react-slot": "^1.1.2",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
@@ -26,7 +27,7 @@
|
|||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"framer-motion": "^11.18.2",
|
"framer-motion": "^11.18.2",
|
||||||
"fuse.js": "^7.1.0",
|
"fuse.js": "^7.1.0",
|
||||||
"lucide-react": "^0.542.0",
|
"lucide-react": "^0.554.0",
|
||||||
"mini-svg-data-uri": "^1.4.4",
|
"mini-svg-data-uri": "^1.4.4",
|
||||||
"motion": "^12.23.12",
|
"motion": "^12.23.12",
|
||||||
"next": "15.5.2",
|
"next": "15.5.2",
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-simple-typewriter": "^5.0.1",
|
"react-simple-typewriter": "^5.0.1",
|
||||||
"react-use-measure": "^2.1.7",
|
"react-use-measure": "^2.1.7",
|
||||||
|
"recharts": "2.15.4",
|
||||||
"sharp": "^0.33.5",
|
"sharp": "^0.33.5",
|
||||||
"simple-icons": "^13.21.0",
|
"simple-icons": "^13.21.0",
|
||||||
"sonner": "^1.7.4",
|
"sonner": "^1.7.4",
|
||||||
@@ -417,6 +419,8 @@
|
|||||||
|
|
||||||
"@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q=="],
|
"@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q=="],
|
||||||
|
|
||||||
|
"@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="],
|
||||||
|
|
||||||
"@radix-ui/react-select": ["@radix-ui/react-select@2.2.5", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA=="],
|
"@radix-ui/react-select": ["@radix-ui/react-select@2.2.5", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA=="],
|
||||||
|
|
||||||
"@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="],
|
"@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="],
|
||||||
@@ -515,6 +519,24 @@
|
|||||||
|
|
||||||
"@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="],
|
"@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="],
|
||||||
|
|
||||||
|
"@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="],
|
||||||
|
|
||||||
|
"@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="],
|
||||||
|
|
||||||
|
"@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="],
|
||||||
|
|
||||||
|
"@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="],
|
||||||
|
|
||||||
|
"@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="],
|
||||||
|
|
||||||
|
"@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="],
|
||||||
|
|
||||||
|
"@types/d3-shape": ["@types/d3-shape@3.1.7", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg=="],
|
||||||
|
|
||||||
|
"@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="],
|
||||||
|
|
||||||
|
"@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="],
|
||||||
|
|
||||||
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
||||||
|
|
||||||
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||||
@@ -765,6 +787,28 @@
|
|||||||
|
|
||||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||||
|
|
||||||
|
"d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="],
|
||||||
|
|
||||||
|
"d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="],
|
||||||
|
|
||||||
|
"d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="],
|
||||||
|
|
||||||
|
"d3-format": ["d3-format@3.1.0", "", {}, "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA=="],
|
||||||
|
|
||||||
|
"d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="],
|
||||||
|
|
||||||
|
"d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="],
|
||||||
|
|
||||||
|
"d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="],
|
||||||
|
|
||||||
|
"d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="],
|
||||||
|
|
||||||
|
"d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="],
|
||||||
|
|
||||||
|
"d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="],
|
||||||
|
|
||||||
|
"d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="],
|
||||||
|
|
||||||
"damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="],
|
"damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="],
|
||||||
|
|
||||||
"data-urls": ["data-urls@5.0.0", "", { "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0" } }, "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg=="],
|
"data-urls": ["data-urls@5.0.0", "", { "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0" } }, "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg=="],
|
||||||
@@ -783,6 +827,8 @@
|
|||||||
|
|
||||||
"decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="],
|
"decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="],
|
||||||
|
|
||||||
|
"decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="],
|
||||||
|
|
||||||
"decode-named-character-reference": ["decode-named-character-reference@1.2.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="],
|
"decode-named-character-reference": ["decode-named-character-reference@1.2.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="],
|
||||||
|
|
||||||
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
|
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
|
||||||
@@ -807,6 +853,8 @@
|
|||||||
|
|
||||||
"doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="],
|
"doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="],
|
||||||
|
|
||||||
|
"dom-helpers": ["dom-helpers@5.2.1", "", { "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA=="],
|
||||||
|
|
||||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||||
|
|
||||||
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
||||||
@@ -939,12 +987,16 @@
|
|||||||
|
|
||||||
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
||||||
|
|
||||||
|
"eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="],
|
||||||
|
|
||||||
"exsolve": ["exsolve@1.0.7", "", {}, "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw=="],
|
"exsolve": ["exsolve@1.0.7", "", {}, "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw=="],
|
||||||
|
|
||||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||||
|
|
||||||
"fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
|
"fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
|
||||||
|
|
||||||
|
"fast-equals": ["fast-equals@5.3.3", "", {}, "sha512-/boTcHZeIAQ2r/tL11voclBHDeP9WPxLt+tyAbVSyyXuUFyh0Tne7gJZTqGbxnvj79TjLdCXLOY7UIPhyG5MTw=="],
|
||||||
|
|
||||||
"fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="],
|
"fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="],
|
||||||
|
|
||||||
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
||||||
@@ -1059,6 +1111,8 @@
|
|||||||
|
|
||||||
"internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="],
|
"internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="],
|
||||||
|
|
||||||
|
"internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
|
||||||
|
|
||||||
"is-alphabetical": ["is-alphabetical@1.0.4", "", {}, "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg=="],
|
"is-alphabetical": ["is-alphabetical@1.0.4", "", {}, "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg=="],
|
||||||
|
|
||||||
"is-alphanumerical": ["is-alphanumerical@1.0.4", "", { "dependencies": { "is-alphabetical": "^1.0.0", "is-decimal": "^1.0.0" } }, "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A=="],
|
"is-alphanumerical": ["is-alphanumerical@1.0.4", "", { "dependencies": { "is-alphabetical": "^1.0.0", "is-decimal": "^1.0.0" } }, "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A=="],
|
||||||
@@ -1191,7 +1245,7 @@
|
|||||||
|
|
||||||
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||||
|
|
||||||
"lucide-react": ["lucide-react@0.542.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-w3hD8/SQB7+lzU2r4VdFyzzOzKnUjTZIF/MQJGSSvni7Llewni4vuViRppfRAa2guOsY5k4jZyxw/i9DQHv+dw=="],
|
"lucide-react": ["lucide-react@0.554.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-St+z29uthEJVx0Is7ellNkgTEhaeSoA42I7JjOCBCrc5X6LYMGSv0P/2uS5HDLTExP5tpiqRD2PyUEOS6s9UXA=="],
|
||||||
|
|
||||||
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
|
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
|
||||||
|
|
||||||
@@ -1455,7 +1509,7 @@
|
|||||||
|
|
||||||
"react-icons": ["react-icons@5.5.0", "", { "peerDependencies": { "react": "*" } }, "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw=="],
|
"react-icons": ["react-icons@5.5.0", "", { "peerDependencies": { "react": "*" } }, "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw=="],
|
||||||
|
|
||||||
"react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
|
"react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
|
||||||
|
|
||||||
"react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
|
"react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
|
||||||
|
|
||||||
@@ -1465,16 +1519,24 @@
|
|||||||
|
|
||||||
"react-simple-typewriter": ["react-simple-typewriter@5.0.1", "", { "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-vA5HkABwJKL/DJ4RshSlY/igdr+FiVY4MLsSQYJX6FZG/f1/VwN4y1i3mPXRyfaswrvI8xii1kOVe1dYtO2Row=="],
|
"react-simple-typewriter": ["react-simple-typewriter@5.0.1", "", { "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-vA5HkABwJKL/DJ4RshSlY/igdr+FiVY4MLsSQYJX6FZG/f1/VwN4y1i3mPXRyfaswrvI8xii1kOVe1dYtO2Row=="],
|
||||||
|
|
||||||
|
"react-smooth": ["react-smooth@4.0.4", "", { "dependencies": { "fast-equals": "^5.0.1", "prop-types": "^15.8.1", "react-transition-group": "^4.4.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q=="],
|
||||||
|
|
||||||
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
|
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
|
||||||
|
|
||||||
"react-syntax-highlighter": ["react-syntax-highlighter@15.6.1", "", { "dependencies": { "@babel/runtime": "^7.3.1", "highlight.js": "^10.4.1", "highlightjs-vue": "^1.0.0", "lowlight": "^1.17.0", "prismjs": "^1.27.0", "refractor": "^3.6.0" }, "peerDependencies": { "react": ">= 0.14.0" } }, "sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg=="],
|
"react-syntax-highlighter": ["react-syntax-highlighter@15.6.1", "", { "dependencies": { "@babel/runtime": "^7.3.1", "highlight.js": "^10.4.1", "highlightjs-vue": "^1.0.0", "lowlight": "^1.17.0", "prismjs": "^1.27.0", "refractor": "^3.6.0" }, "peerDependencies": { "react": ">= 0.14.0" } }, "sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg=="],
|
||||||
|
|
||||||
|
"react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="],
|
||||||
|
|
||||||
"react-use-measure": ["react-use-measure@2.1.7", "", { "peerDependencies": { "react": ">=16.13", "react-dom": ">=16.13" } }, "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg=="],
|
"react-use-measure": ["react-use-measure@2.1.7", "", { "peerDependencies": { "react": ">=16.13", "react-dom": ">=16.13" } }, "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg=="],
|
||||||
|
|
||||||
"read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="],
|
"read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="],
|
||||||
|
|
||||||
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
||||||
|
|
||||||
|
"recharts": ["recharts@2.15.4", "", { "dependencies": { "clsx": "^2.0.0", "eventemitter3": "^4.0.1", "lodash": "^4.17.21", "react-is": "^18.3.1", "react-smooth": "^4.0.4", "recharts-scale": "^0.4.4", "tiny-invariant": "^1.3.1", "victory-vendor": "^36.6.8" }, "peerDependencies": { "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw=="],
|
||||||
|
|
||||||
|
"recharts-scale": ["recharts-scale@0.4.5", "", { "dependencies": { "decimal.js-light": "^2.4.1" } }, "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w=="],
|
||||||
|
|
||||||
"refa": ["refa@0.12.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.8.0" } }, "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g=="],
|
"refa": ["refa@0.12.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.8.0" } }, "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g=="],
|
||||||
|
|
||||||
"reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="],
|
"reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="],
|
||||||
@@ -1625,6 +1687,8 @@
|
|||||||
|
|
||||||
"thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="],
|
"thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="],
|
||||||
|
|
||||||
|
"tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="],
|
||||||
|
|
||||||
"tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="],
|
"tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="],
|
||||||
|
|
||||||
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
||||||
@@ -1693,6 +1757,8 @@
|
|||||||
|
|
||||||
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||||
|
|
||||||
|
"victory-vendor": ["victory-vendor@36.9.2", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ=="],
|
||||||
|
|
||||||
"vite": ["vite@7.1.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx"], "bin": "bin/vite.js" }, "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ=="],
|
"vite": ["vite@7.1.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx"], "bin": "bin/vite.js" }, "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ=="],
|
||||||
|
|
||||||
"vite-tsconfig-paths": ["vite-tsconfig-paths@5.1.4", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" } }, "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w=="],
|
"vite-tsconfig-paths": ["vite-tsconfig-paths@5.1.4", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" } }, "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w=="],
|
||||||
@@ -1757,18 +1823,18 @@
|
|||||||
|
|
||||||
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
||||||
|
|
||||||
"@eslint/config-array/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
|
||||||
|
|
||||||
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
|
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
|
||||||
|
|
||||||
"@eslint/eslintrc/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
"@eslint/eslintrc/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
||||||
|
|
||||||
"@eslint/eslintrc/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
|
||||||
|
|
||||||
"@eslint/plugin-kit/@eslint/core": ["@eslint/core@0.15.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA=="],
|
"@eslint/plugin-kit/@eslint/core": ["@eslint/core@0.15.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA=="],
|
||||||
|
|
||||||
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
|
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
|
||||||
|
|
||||||
|
"@radix-ui/react-scroll-area/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||||
|
|
||||||
|
"@radix-ui/react-scroll-area/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
|
||||||
|
|
||||||
"@types/hast/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
"@types/hast/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree/fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
"@typescript-eslint/typescript-estree/fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
||||||
@@ -1797,24 +1863,18 @@
|
|||||||
|
|
||||||
"eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
|
"eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
|
||||||
|
|
||||||
"eslint-plugin-import/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
|
||||||
|
|
||||||
"eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
"eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||||
|
|
||||||
"eslint-plugin-jsdoc/@es-joy/jsdoccomment": ["@es-joy/jsdoccomment@0.52.0", "", { "dependencies": { "@types/estree": "^1.0.8", "@typescript-eslint/types": "^8.34.1", "comment-parser": "1.4.1", "esquery": "^1.6.0", "jsdoc-type-pratt-parser": "~4.1.0" } }, "sha512-BXuN7BII+8AyNtn57euU2Yxo9yA/KUDNzrpXyi3pfqKmBhhysR6ZWOebFh3vyPoqA3/j1SOvGgucElMGwlXing=="],
|
"eslint-plugin-jsdoc/@es-joy/jsdoccomment": ["@es-joy/jsdoccomment@0.52.0", "", { "dependencies": { "@types/estree": "^1.0.8", "@typescript-eslint/types": "^8.34.1", "comment-parser": "1.4.1", "esquery": "^1.6.0", "jsdoc-type-pratt-parser": "~4.1.0" } }, "sha512-BXuN7BII+8AyNtn57euU2Yxo9yA/KUDNzrpXyi3pfqKmBhhysR6ZWOebFh3vyPoqA3/j1SOvGgucElMGwlXing=="],
|
||||||
|
|
||||||
"eslint-plugin-jsonc/synckit": ["synckit@0.11.8", "", { "dependencies": { "@pkgr/core": "^0.2.4" } }, "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A=="],
|
"eslint-plugin-jsonc/synckit": ["synckit@0.11.8", "", { "dependencies": { "@pkgr/core": "^0.2.4" } }, "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A=="],
|
||||||
|
|
||||||
"eslint-plugin-jsx-a11y/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
|
||||||
|
|
||||||
"eslint-plugin-n/globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="],
|
"eslint-plugin-n/globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="],
|
||||||
|
|
||||||
"eslint-plugin-n/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
"eslint-plugin-n/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
||||||
|
|
||||||
"eslint-plugin-n/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
"eslint-plugin-n/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||||
|
|
||||||
"eslint-plugin-react/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
|
||||||
|
|
||||||
"eslint-plugin-react/resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="],
|
"eslint-plugin-react/resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="],
|
||||||
|
|
||||||
"eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
"eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||||
@@ -1851,6 +1911,8 @@
|
|||||||
|
|
||||||
"path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
"path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||||
|
|
||||||
|
"prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
|
||||||
|
|
||||||
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
"refractor/prismjs": ["prismjs@1.27.0", "", {}, "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA=="],
|
"refractor/prismjs": ["prismjs@1.27.0", "", {}, "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA=="],
|
||||||
@@ -1873,8 +1935,6 @@
|
|||||||
|
|
||||||
"tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": "lib/cli.js" }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="],
|
"tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": "lib/cli.js" }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="],
|
||||||
|
|
||||||
"w3c-xmlserializer/xml-name-validator": ["xml-name-validator@5.0.0", "", {}, "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg=="],
|
|
||||||
|
|
||||||
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
|
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
|
||||||
|
|
||||||
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||||
@@ -1883,24 +1943,14 @@
|
|||||||
|
|
||||||
"yaml-eslint-parser/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
"yaml-eslint-parser/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
||||||
|
|
||||||
"@eslint/config-array/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
|
||||||
|
|
||||||
"@eslint/eslintrc/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
"@typescript-eslint/typescript-estree/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
||||||
|
|
||||||
"eslint-plugin-import/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
|
||||||
|
|
||||||
"eslint-plugin-jsonc/synckit/@pkgr/core": ["@pkgr/core@0.2.7", "", {}, "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg=="],
|
"eslint-plugin-jsonc/synckit/@pkgr/core": ["@pkgr/core@0.2.7", "", {}, "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg=="],
|
||||||
|
|
||||||
"eslint-plugin-jsx-a11y/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
|
||||||
|
|
||||||
"eslint-plugin-n/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
"eslint-plugin-n/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
||||||
|
|
||||||
"eslint-plugin-react/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
|
||||||
|
|
||||||
"eslint-plugin-unicorn/@eslint/plugin-kit/@eslint/core": ["@eslint/core@0.13.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw=="],
|
"eslint-plugin-unicorn/@eslint/plugin-kit/@eslint/core": ["@eslint/core@0.13.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw=="],
|
||||||
|
|
||||||
"glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
"glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
||||||
|
|||||||
4
frontend/package.json
generated
4
frontend/package.json
generated
@@ -23,6 +23,7 @@
|
|||||||
"@radix-ui/react-label": "^2.1.2",
|
"@radix-ui/react-label": "^2.1.2",
|
||||||
"@radix-ui/react-navigation-menu": "^1.2.5",
|
"@radix-ui/react-navigation-menu": "^1.2.5",
|
||||||
"@radix-ui/react-popover": "^1.1.6",
|
"@radix-ui/react-popover": "^1.1.6",
|
||||||
|
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||||
"@radix-ui/react-select": "^2.1.6",
|
"@radix-ui/react-select": "^2.1.6",
|
||||||
"@radix-ui/react-separator": "^1.1.2",
|
"@radix-ui/react-separator": "^1.1.2",
|
||||||
"@radix-ui/react-slot": "^1.1.2",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
@@ -38,7 +39,7 @@
|
|||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"framer-motion": "^11.18.2",
|
"framer-motion": "^11.18.2",
|
||||||
"fuse.js": "^7.1.0",
|
"fuse.js": "^7.1.0",
|
||||||
"lucide-react": "^0.542.0",
|
"lucide-react": "^0.554.0",
|
||||||
"mini-svg-data-uri": "^1.4.4",
|
"mini-svg-data-uri": "^1.4.4",
|
||||||
"motion": "^12.23.12",
|
"motion": "^12.23.12",
|
||||||
"next": "15.5.2",
|
"next": "15.5.2",
|
||||||
@@ -55,6 +56,7 @@
|
|||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-simple-typewriter": "^5.0.1",
|
"react-simple-typewriter": "^5.0.1",
|
||||||
"react-use-measure": "^2.1.7",
|
"react-use-measure": "^2.1.7",
|
||||||
|
"recharts": "2.15.4",
|
||||||
"sharp": "^0.33.5",
|
"sharp": "^0.33.5",
|
||||||
"simple-icons": "^13.21.0",
|
"simple-icons": "^13.21.0",
|
||||||
"sonner": "^1.7.4",
|
"sonner": "^1.7.4",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
"privileged": false,
|
"privileged": false,
|
||||||
"interface_port": 8080,
|
"interface_port": 8080,
|
||||||
"documentation": null,
|
"documentation": null,
|
||||||
"website": "https://filebrowser.org/features",
|
"website": "https://filebrowser.org/index.html#features",
|
||||||
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/file-browser.webp",
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/file-browser.webp",
|
||||||
"config_path": "",
|
"config_path": "",
|
||||||
"description": "File Browser offers a user-friendly web interface for managing files within a designated directory. It allows you to perform various actions such as uploading, deleting, previewing, renaming, and editing files.",
|
"description": "File Browser offers a user-friendly web interface for managing files within a designated directory. It allows you to perform various actions such as uploading, deleting, previewing, renaming, and editing files.",
|
||||||
|
|||||||
@@ -1,4 +1,224 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"name": "pocketbase/pocketbase",
|
||||||
|
"version": "v0.34.0",
|
||||||
|
"date": "2025-11-22T09:18:14Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "laurent22/joplin",
|
||||||
|
"version": "server-v3.4.4",
|
||||||
|
"date": "2025-09-25T13:19:26Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "zwave-js/zwave-js-ui",
|
||||||
|
"version": "v11.8.0",
|
||||||
|
"date": "2025-11-22T07:54:42Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "inventree/InvenTree",
|
||||||
|
"version": "1.1.5",
|
||||||
|
"date": "2025-11-22T07:02:52Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jackett/Jackett",
|
||||||
|
"version": "v0.24.339",
|
||||||
|
"date": "2025-11-22T06:05:53Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "theonedev/onedev",
|
||||||
|
"version": "v13.1.0",
|
||||||
|
"date": "2025-11-22T04:29:25Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "jeedom/core",
|
||||||
|
"version": "4.4.20",
|
||||||
|
"date": "2025-11-22T00:27:05Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "steveiliop56/tinyauth",
|
||||||
|
"version": "v4.0.1",
|
||||||
|
"date": "2025-10-15T16:53:55Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TwiN/gatus",
|
||||||
|
"version": "v5.33.0",
|
||||||
|
"date": "2025-11-21T22:54:49Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "BerriAI/litellm",
|
||||||
|
"version": "v1.78.5-stable-patch-1",
|
||||||
|
"date": "2025-11-21T19:57:45Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "homarr-labs/homarr",
|
||||||
|
"version": "v1.44.0",
|
||||||
|
"date": "2025-11-21T19:17:09Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "gelbphoenix/autocaliweb",
|
||||||
|
"version": "v0.11.0",
|
||||||
|
"date": "2025-11-21T18:42:15Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rclone/rclone",
|
||||||
|
"version": "v1.72.0",
|
||||||
|
"date": "2025-11-21T18:20:58Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "keycloak/keycloak",
|
||||||
|
"version": "26.4.5",
|
||||||
|
"date": "2025-11-12T15:24:23Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "readeck/readeck",
|
||||||
|
"version": "0.21.1",
|
||||||
|
"date": "2025-11-21T17:17:52Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mattermost/mattermost",
|
||||||
|
"version": "v10.11.8",
|
||||||
|
"date": "2025-11-21T17:06:07Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "home-assistant/core",
|
||||||
|
"version": "2025.11.3",
|
||||||
|
"date": "2025-11-21T17:03:22Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bubka/2FAuth",
|
||||||
|
"version": "v5.6.1",
|
||||||
|
"date": "2025-11-21T16:51:21Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "BookStackApp/BookStack",
|
||||||
|
"version": "v25.11.3",
|
||||||
|
"date": "2025-11-21T14:06:50Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pommee/goaway",
|
||||||
|
"version": "v0.62.19",
|
||||||
|
"date": "2025-11-21T13:24:09Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fuma-nama/fumadocs",
|
||||||
|
"version": "fumadocs-ui@16.1.0",
|
||||||
|
"date": "2025-11-21T13:02:57Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "forgejo/forgejo",
|
||||||
|
"version": "v13.0.3",
|
||||||
|
"date": "2025-11-21T12:43:04Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bunkerity/bunkerweb",
|
||||||
|
"version": "v1.6.5",
|
||||||
|
"date": "2025-10-06T15:25:17Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "chrisbenincasa/tunarr",
|
||||||
|
"version": "v0.23.0-alpha.24",
|
||||||
|
"date": "2025-11-21T12:16:39Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rcourtman/Pulse",
|
||||||
|
"version": "v4.32.3",
|
||||||
|
"date": "2025-11-21T11:16:25Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seriousm4x/UpSnap",
|
||||||
|
"version": "5.2.4",
|
||||||
|
"date": "2025-11-21T10:25:05Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "emqx/emqx",
|
||||||
|
"version": "e6.0.2-beta.2",
|
||||||
|
"date": "2025-11-21T10:20:27Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sabnzbd/sabnzbd",
|
||||||
|
"version": "4.5.5",
|
||||||
|
"date": "2025-10-24T11:12:22Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "openobserve/openobserve",
|
||||||
|
"version": "v0.16.3",
|
||||||
|
"date": "2025-11-21T08:54:06Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "booklore-app/booklore",
|
||||||
|
"version": "v1.11.0",
|
||||||
|
"date": "2025-11-21T08:09:03Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "MariaDB/server",
|
||||||
|
"version": "mariadb-12.1.2",
|
||||||
|
"date": "2025-11-18T15:16:21Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "morpheus65535/bazarr",
|
||||||
|
"version": "v1.5.3",
|
||||||
|
"date": "2025-09-20T12:12:33Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bluenviron/mediamtx",
|
||||||
|
"version": "v1.15.4",
|
||||||
|
"date": "2025-11-21T01:21:03Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TasmoAdmin/TasmoAdmin",
|
||||||
|
"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": "saltstack/salt",
|
||||||
|
"version": "v3007.9",
|
||||||
|
"date": "2025-11-20T17:58:32Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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",
|
||||||
|
"version": "prototype-v1.26.0.arm-native-docker-build-1",
|
||||||
|
"date": "2025-11-20T15:38:39Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "duplicati/duplicati",
|
||||||
|
"version": "v2.2.0.101-2.2.0.101_canary_2025-11-20",
|
||||||
|
"date": "2025-11-20T14:50:45Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "NodeBB/NodeBB",
|
||||||
|
"version": "v4.6.3",
|
||||||
|
"date": "2025-11-20T14:13:22Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "n8n-io/n8n",
|
||||||
|
"version": "n8n@1.120.4",
|
||||||
|
"date": "2025-11-19T12:57:55Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SigNoz/signoz",
|
||||||
|
"version": "v0.102.1",
|
||||||
|
"date": "2025-11-20T12:20:18Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "kimai/kimai",
|
"name": "kimai/kimai",
|
||||||
"version": "2.44.0",
|
"version": "2.44.0",
|
||||||
@@ -9,26 +229,11 @@
|
|||||||
"version": "v2.1.1",
|
"version": "v2.1.1",
|
||||||
"date": "2025-11-20T10:54:07Z"
|
"date": "2025-11-20T10:54:07Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "fuma-nama/fumadocs",
|
|
||||||
"version": "fumadocs-ui@16.0.15",
|
|
||||||
"date": "2025-11-20T10:52:04Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "mattermost/mattermost",
|
|
||||||
"version": "v10.11.7",
|
|
||||||
"date": "2025-11-17T08:40:53Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Athou/commafeed",
|
"name": "Athou/commafeed",
|
||||||
"version": "5.12.0",
|
"version": "5.12.0",
|
||||||
"date": "2025-11-20T06:18:58Z"
|
"date": "2025-11-20T06:18:58Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Jackett/Jackett",
|
|
||||||
"version": "v0.24.336",
|
|
||||||
"date": "2025-11-20T05:55:54Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "documenso/documenso",
|
"name": "documenso/documenso",
|
||||||
"version": "v2.0.14",
|
"version": "v2.0.14",
|
||||||
@@ -44,31 +249,11 @@
|
|||||||
"version": "v1.56.0",
|
"version": "v1.56.0",
|
||||||
"date": "2025-11-20T02:28:35Z"
|
"date": "2025-11-20T02:28:35Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "BerriAI/litellm",
|
|
||||||
"version": "v1.80.0.dev6",
|
|
||||||
"date": "2025-11-20T02:03:21Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "jeedom/core",
|
|
||||||
"version": "4.4.20",
|
|
||||||
"date": "2025-11-20T00:27:04Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "steveiliop56/tinyauth",
|
|
||||||
"version": "v4.0.1",
|
|
||||||
"date": "2025-10-15T16:53:55Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "coder/code-server",
|
"name": "coder/code-server",
|
||||||
"version": "v4.106.2",
|
"version": "v4.106.2",
|
||||||
"date": "2025-11-20T00:23:05Z"
|
"date": "2025-11-20T00:23:05Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "keycloak/keycloak",
|
|
||||||
"version": "26.4.5",
|
|
||||||
"date": "2025-11-12T15:24:23Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "esphome/esphome",
|
"name": "esphome/esphome",
|
||||||
"version": "2025.11.0",
|
"version": "2025.11.0",
|
||||||
@@ -104,16 +289,6 @@
|
|||||||
"version": "0.51.3",
|
"version": "0.51.3",
|
||||||
"date": "2025-11-19T15:45:28Z"
|
"date": "2025-11-19T15:45:28Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "NodeBB/NodeBB",
|
|
||||||
"version": "v4.6.2",
|
|
||||||
"date": "2025-11-19T15:31:59Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "BookStackApp/BookStack",
|
|
||||||
"version": "v25.11.2",
|
|
||||||
"date": "2025-11-19T15:26:29Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "grafana/grafana",
|
"name": "grafana/grafana",
|
||||||
"version": "v12.3.0",
|
"version": "v12.3.0",
|
||||||
@@ -134,16 +309,6 @@
|
|||||||
"version": "2025.5",
|
"version": "2025.5",
|
||||||
"date": "2025-11-19T14:48:47Z"
|
"date": "2025-11-19T14:48:47Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "ollama/ollama",
|
|
||||||
"version": "v0.13.0",
|
|
||||||
"date": "2025-11-19T14:16:07Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "n8n-io/n8n",
|
|
||||||
"version": "n8n@1.120.4",
|
|
||||||
"date": "2025-11-19T12:57:55Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "AdguardTeam/AdGuardHome",
|
"name": "AdguardTeam/AdGuardHome",
|
||||||
"version": "v0.107.69",
|
"version": "v0.107.69",
|
||||||
@@ -159,16 +324,6 @@
|
|||||||
"version": "v7.5.0",
|
"version": "v7.5.0",
|
||||||
"date": "2025-11-19T08:36:29Z"
|
"date": "2025-11-19T08:36:29Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "SigNoz/signoz",
|
|
||||||
"version": "v0.102.0",
|
|
||||||
"date": "2025-11-19T06:53:59Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "morpheus65535/bazarr",
|
|
||||||
"version": "v1.5.3",
|
|
||||||
"date": "2025-09-20T12:12:33Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "element-hq/synapse",
|
"name": "element-hq/synapse",
|
||||||
"version": "v1.143.0rc1",
|
"version": "v1.143.0rc1",
|
||||||
@@ -184,16 +339,6 @@
|
|||||||
"version": "v1.0.1-stable",
|
"version": "v1.0.1-stable",
|
||||||
"date": "2025-11-10T16:51:44Z"
|
"date": "2025-11-10T16:51:44Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "bunkerity/bunkerweb",
|
|
||||||
"version": "testing",
|
|
||||||
"date": "2025-11-17T16:24:26Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "chrisbenincasa/tunarr",
|
|
||||||
"version": "v0.23.0-alpha.23",
|
|
||||||
"date": "2025-11-18T21:36:15Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "umami-software/umami",
|
"name": "umami-software/umami",
|
||||||
"version": "v3.0.1",
|
"version": "v3.0.1",
|
||||||
@@ -209,11 +354,6 @@
|
|||||||
"version": "v3.6.2",
|
"version": "v3.6.2",
|
||||||
"date": "2025-11-18T16:25:16Z"
|
"date": "2025-11-18T16:25:16Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "MariaDB/server",
|
|
||||||
"version": "mariadb-12.1.2",
|
|
||||||
"date": "2025-11-18T15:16:21Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "redis/redis",
|
"name": "redis/redis",
|
||||||
"version": "8.4.0",
|
"version": "8.4.0",
|
||||||
@@ -229,11 +369,6 @@
|
|||||||
"version": "v0.7.5",
|
"version": "v0.7.5",
|
||||||
"date": "2025-11-18T10:50:21Z"
|
"date": "2025-11-18T10:50:21Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "emqx/emqx",
|
|
||||||
"version": "e6.1.0-alpha.1",
|
|
||||||
"date": "2025-11-18T10:33:45Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "wazuh/wazuh",
|
"name": "wazuh/wazuh",
|
||||||
"version": "coverity-w47-4.14.2",
|
"version": "coverity-w47-4.14.2",
|
||||||
@@ -244,11 +379,6 @@
|
|||||||
"version": "v0.28.2",
|
"version": "v0.28.2",
|
||||||
"date": "2025-11-18T05:51:46Z"
|
"date": "2025-11-18T05:51:46Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "theonedev/onedev",
|
|
||||||
"version": "v13.1.0",
|
|
||||||
"date": "2025-11-18T00:06:49Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "ipfs/kubo",
|
"name": "ipfs/kubo",
|
||||||
"version": "v0.38.2",
|
"version": "v0.38.2",
|
||||||
@@ -274,11 +404,6 @@
|
|||||||
"version": "v1.4.5",
|
"version": "v1.4.5",
|
||||||
"date": "2025-11-17T15:20:35Z"
|
"date": "2025-11-17T15:20:35Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "meilisearch/meilisearch",
|
|
||||||
"version": "latest",
|
|
||||||
"date": "2025-11-17T09:29:20Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "rabbitmq/rabbitmq-server",
|
"name": "rabbitmq/rabbitmq-server",
|
||||||
"version": "v4.2.1",
|
"version": "v4.2.1",
|
||||||
@@ -309,11 +434,6 @@
|
|||||||
"version": "v0.21.0",
|
"version": "v0.21.0",
|
||||||
"date": "2025-08-23T18:33:53Z"
|
"date": "2025-08-23T18:33:53Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "TwiN/gatus",
|
|
||||||
"version": "v5.32.0",
|
|
||||||
"date": "2025-11-16T21:08:56Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "binwiederhier/ntfy",
|
"name": "binwiederhier/ntfy",
|
||||||
"version": "v2.15.0",
|
"version": "v2.15.0",
|
||||||
@@ -324,11 +444,6 @@
|
|||||||
"version": "3.3.8",
|
"version": "3.3.8",
|
||||||
"date": "2025-11-16T17:04:37Z"
|
"date": "2025-11-16T17:04:37Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "msgbyte/tianji",
|
|
||||||
"version": "v1.30.11",
|
|
||||||
"date": "2025-11-16T16:21:04Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "AlexxIT/go2rtc",
|
"name": "AlexxIT/go2rtc",
|
||||||
"version": "v1.9.12",
|
"version": "v1.9.12",
|
||||||
@@ -384,16 +499,6 @@
|
|||||||
"version": "v0.16.1",
|
"version": "v0.16.1",
|
||||||
"date": "2025-11-14T22:50:06Z"
|
"date": "2025-11-14T22:50:06Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "home-assistant/core",
|
|
||||||
"version": "2025.11.2",
|
|
||||||
"date": "2025-11-14T22:10:50Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "homarr-labs/homarr",
|
|
||||||
"version": "v1.43.3",
|
|
||||||
"date": "2025-11-14T19:16:17Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "mealie-recipes/mealie",
|
"name": "mealie-recipes/mealie",
|
||||||
"version": "v3.5.0",
|
"version": "v3.5.0",
|
||||||
@@ -404,11 +509,6 @@
|
|||||||
"version": "22.0.3",
|
"version": "22.0.3",
|
||||||
"date": "2025-11-14T14:49:25Z"
|
"date": "2025-11-14T14:49:25Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "openobserve/openobserve",
|
|
||||||
"version": "v0.16.2",
|
|
||||||
"date": "2025-11-14T12:05:36Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "zitadel/zitadel",
|
"name": "zitadel/zitadel",
|
||||||
"version": "v4.7.0",
|
"version": "v4.7.0",
|
||||||
@@ -434,26 +534,11 @@
|
|||||||
"version": "v0.86.1",
|
"version": "v0.86.1",
|
||||||
"date": "2025-11-14T05:05:44Z"
|
"date": "2025-11-14T05:05:44Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "rcourtman/Pulse",
|
|
||||||
"version": "v4.31.0",
|
|
||||||
"date": "2025-11-14T00:18:50Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "gristlabs/grist-core",
|
"name": "gristlabs/grist-core",
|
||||||
"version": "v1.7.7",
|
"version": "v1.7.7",
|
||||||
"date": "2025-11-13T21:28:44Z"
|
"date": "2025-11-13T21:28:44Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "pommee/goaway",
|
|
||||||
"version": "v0.62.18",
|
|
||||||
"date": "2025-11-13T19:49:21Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "pocketbase/pocketbase",
|
|
||||||
"version": "v0.33.0",
|
|
||||||
"date": "2025-11-13T14:09:14Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "PrivateBin/PrivateBin",
|
"name": "PrivateBin/PrivateBin",
|
||||||
"version": "1.7.9",
|
"version": "1.7.9",
|
||||||
@@ -474,11 +559,6 @@
|
|||||||
"version": "v1.0.25",
|
"version": "v1.0.25",
|
||||||
"date": "2025-11-12T16:57:54Z"
|
"date": "2025-11-12T16:57:54Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "zwave-js/zwave-js-ui",
|
|
||||||
"version": "v11.7.0",
|
|
||||||
"date": "2025-11-12T14:09:36Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "cockpit-project/cockpit",
|
"name": "cockpit-project/cockpit",
|
||||||
"version": "351",
|
"version": "351",
|
||||||
@@ -564,11 +644,6 @@
|
|||||||
"version": "v1.0.0-beta19",
|
"version": "v1.0.0-beta19",
|
||||||
"date": "2025-11-09T17:26:30Z"
|
"date": "2025-11-09T17:26:30Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "duplicati/duplicati",
|
|
||||||
"version": "v2.2.0.1_stable_2025-11-09",
|
|
||||||
"date": "2025-11-09T17:21:54Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Cleanuparr/Cleanuparr",
|
"name": "Cleanuparr/Cleanuparr",
|
||||||
"version": "v2.4.5",
|
"version": "v2.4.5",
|
||||||
@@ -584,11 +659,6 @@
|
|||||||
"version": "3.5.1",
|
"version": "3.5.1",
|
||||||
"date": "2025-11-09T05:09:28Z"
|
"date": "2025-11-09T05:09:28Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "inventree/InvenTree",
|
|
||||||
"version": "1.1.3",
|
|
||||||
"date": "2025-11-09T00:28:21Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "raydak-labs/configarr",
|
"name": "raydak-labs/configarr",
|
||||||
"version": "v1.17.2",
|
"version": "v1.17.2",
|
||||||
@@ -664,11 +734,6 @@
|
|||||||
"version": "v0.9.1",
|
"version": "v0.9.1",
|
||||||
"date": "2025-11-06T02:26:53Z"
|
"date": "2025-11-06T02:26:53Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "neo4j/neo4j",
|
|
||||||
"version": "5.26.16",
|
|
||||||
"date": "2025-11-05T20:41:40Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "leiweibau/Pi.Alert",
|
"name": "leiweibau/Pi.Alert",
|
||||||
"version": "v2025-11-05",
|
"version": "v2025-11-05",
|
||||||
@@ -824,21 +889,11 @@
|
|||||||
"version": "v1.11.1",
|
"version": "v1.11.1",
|
||||||
"date": "2025-10-29T22:09:26Z"
|
"date": "2025-10-29T22:09:26Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "laurent22/joplin",
|
|
||||||
"version": "server-v3.4.4",
|
|
||||||
"date": "2025-09-25T13:19:26Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "apache/cassandra",
|
"name": "apache/cassandra",
|
||||||
"version": "cassandra-5.0.6",
|
"version": "cassandra-5.0.6",
|
||||||
"date": "2025-10-29T07:40:47Z"
|
"date": "2025-10-29T07:40:47Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "booklore-app/booklore",
|
|
||||||
"version": "v1.10.0",
|
|
||||||
"date": "2025-10-28T19:04:35Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "pi-hole/pi-hole",
|
"name": "pi-hole/pi-hole",
|
||||||
"version": "v6.2.2",
|
"version": "v6.2.2",
|
||||||
@@ -864,21 +919,11 @@
|
|||||||
"version": "v25.8.0",
|
"version": "v25.8.0",
|
||||||
"date": "2025-10-26T14:23:37Z"
|
"date": "2025-10-26T14:23:37Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "forgejo/forgejo",
|
|
||||||
"version": "v13.0.2",
|
|
||||||
"date": "2025-10-26T06:33:05Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "usememos/memos",
|
"name": "usememos/memos",
|
||||||
"version": "v0.25.2",
|
"version": "v0.25.2",
|
||||||
"date": "2025-10-24T12:30:04Z"
|
"date": "2025-10-24T12:30:04Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "sabnzbd/sabnzbd",
|
|
||||||
"version": "4.5.5",
|
|
||||||
"date": "2025-10-24T11:12:22Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "crowdsecurity/crowdsec",
|
"name": "crowdsecurity/crowdsec",
|
||||||
"version": "v1.7.3",
|
"version": "v1.7.3",
|
||||||
@@ -904,26 +949,11 @@
|
|||||||
"version": "release-1.24.1",
|
"version": "release-1.24.1",
|
||||||
"date": "2025-10-22T10:28:00Z"
|
"date": "2025-10-22T10:28:00Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "bluenviron/mediamtx",
|
|
||||||
"version": "v1.15.3",
|
|
||||||
"date": "2025-10-21T19:56:55Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "kyantech/Palmr",
|
"name": "kyantech/Palmr",
|
||||||
"version": "v3.2.5-beta",
|
"version": "v3.2.5-beta",
|
||||||
"date": "2025-10-21T16:49:14Z"
|
"date": "2025-10-21T16:49:14Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "rclone/rclone",
|
|
||||||
"version": "v1.71.2",
|
|
||||||
"date": "2025-10-20T15:25:52Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "seriousm4x/UpSnap",
|
|
||||||
"version": "5.2.3",
|
|
||||||
"date": "2025-10-19T20:50:15Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Part-DB/Part-DB-server",
|
"name": "Part-DB/Part-DB-server",
|
||||||
"version": "v2.2.1",
|
"version": "v2.2.1",
|
||||||
@@ -939,21 +969,6 @@
|
|||||||
"version": "v4.5.0",
|
"version": "v4.5.0",
|
||||||
"date": "2025-10-18T22:00:50Z"
|
"date": "2025-10-18T22:00:50Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "project-zot/zot",
|
|
||||||
"version": "v2.1.10",
|
|
||||||
"date": "2025-10-18T18:46:36Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "TasmoAdmin/TasmoAdmin",
|
|
||||||
"version": "v4.3.2",
|
|
||||||
"date": "2025-10-18T12:11:00Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "readeck/readeck",
|
|
||||||
"version": "0.20.4",
|
|
||||||
"date": "2025-10-18T10:00:42Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "diced/zipline",
|
"name": "diced/zipline",
|
||||||
"version": "v4.3.2",
|
"version": "v4.3.2",
|
||||||
@@ -1004,11 +1019,6 @@
|
|||||||
"version": "v5.0.85",
|
"version": "v5.0.85",
|
||||||
"date": "2025-10-12T19:55:18Z"
|
"date": "2025-10-12T19:55:18Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "gelbphoenix/autocaliweb",
|
|
||||||
"version": "v0.10.4",
|
|
||||||
"date": "2025-10-11T19:53:39Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "projectsend/projectsend",
|
"name": "projectsend/projectsend",
|
||||||
"version": "r1945",
|
"version": "r1945",
|
||||||
@@ -1104,11 +1114,6 @@
|
|||||||
"version": "v0.17.0",
|
"version": "v0.17.0",
|
||||||
"date": "2025-09-19T22:23:28Z"
|
"date": "2025-09-19T22:23:28Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "saltstack/salt",
|
|
||||||
"version": "v3007.8",
|
|
||||||
"date": "2025-09-18T18:19:04Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "docmost/docmost",
|
"name": "docmost/docmost",
|
||||||
"version": "v0.23.2",
|
"version": "v0.23.2",
|
||||||
@@ -1314,11 +1319,6 @@
|
|||||||
"version": "v1.11.11",
|
"version": "v1.11.11",
|
||||||
"date": "2025-06-18T18:04:50Z"
|
"date": "2025-06-18T18:04:50Z"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Bubka/2FAuth",
|
|
||||||
"version": "v5.6.0",
|
|
||||||
"date": "2025-06-18T12:19:54Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "TriliumNext/Notes",
|
"name": "TriliumNext/Notes",
|
||||||
"version": "v0.95.0",
|
"version": "v0.95.0",
|
||||||
|
|||||||
@@ -1,9 +1,67 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useEffect, useState } from "react";
|
import {
|
||||||
import "react-datepicker/dist/react-datepicker.css";
|
ArrowUpDown,
|
||||||
|
Box,
|
||||||
|
CheckCircle2,
|
||||||
|
ChevronLeft,
|
||||||
|
ChevronRight,
|
||||||
|
List,
|
||||||
|
Loader2,
|
||||||
|
Trophy,
|
||||||
|
XCircle,
|
||||||
|
} from "lucide-react";
|
||||||
|
import {
|
||||||
|
Bar,
|
||||||
|
BarChart,
|
||||||
|
CartesianGrid,
|
||||||
|
Cell,
|
||||||
|
LabelList,
|
||||||
|
XAxis,
|
||||||
|
} from "recharts";
|
||||||
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
|
|
||||||
import ApplicationChart from "../../components/application-chart";
|
import type { ChartConfig } from "@/components/ui/chart";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardDescription,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from "@/components/ui/card";
|
||||||
|
import {
|
||||||
|
ChartContainer,
|
||||||
|
ChartTooltip,
|
||||||
|
ChartTooltipContent,
|
||||||
|
} from "@/components/ui/chart";
|
||||||
|
import { formattedBadge } from "@/components/command-menu";
|
||||||
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
|
||||||
type DataModel = {
|
type DataModel = {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -30,42 +88,76 @@ type SummaryData = {
|
|||||||
nsapp_count: Record<string, number>;
|
nsapp_count: Record<string, number>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DataFetcher: React.FC = () => {
|
// Chart colors optimized for both light and dark modes
|
||||||
|
// Medium-toned colors that are visible and not too flashy in both themes
|
||||||
|
const CHART_COLORS = [
|
||||||
|
"#5B8DEF", // blue - medium tone
|
||||||
|
"#4ECDC4", // teal - medium tone
|
||||||
|
"#FF8C42", // orange - medium tone
|
||||||
|
"#A78BFA", // purple - medium tone
|
||||||
|
"#F472B6", // pink - medium tone
|
||||||
|
"#38BDF8", // cyan - medium tone
|
||||||
|
"#4ADE80", // green - medium tone
|
||||||
|
"#FBBF24", // yellow - medium tone
|
||||||
|
"#818CF8", // indigo - medium tone
|
||||||
|
"#FB7185", // rose - medium tone
|
||||||
|
"#2DD4BF", // turquoise - medium tone
|
||||||
|
"#C084FC", // violet - medium tone
|
||||||
|
"#60A5FA", // sky blue - medium tone
|
||||||
|
"#84CC16", // lime - medium tone
|
||||||
|
"#F59E0B", // amber - medium tone
|
||||||
|
"#A855F7", // purple - medium tone
|
||||||
|
"#10B981", // emerald - medium tone
|
||||||
|
"#EAB308", // gold - medium tone
|
||||||
|
"#3B82F6", // royal blue - medium tone
|
||||||
|
"#EF4444", // red - medium tone
|
||||||
|
];
|
||||||
|
|
||||||
|
const chartConfigApps = {
|
||||||
|
count: {
|
||||||
|
label: "Installations",
|
||||||
|
color: "hsl(var(--chart-1))",
|
||||||
|
},
|
||||||
|
} satisfies ChartConfig;
|
||||||
|
|
||||||
|
export default function DataPage() {
|
||||||
const [data, setData] = useState<DataModel[]>([]);
|
const [data, setData] = useState<DataModel[]>([]);
|
||||||
const [summary, setSummary] = useState<SummaryData | null>(null);
|
const [summary, setSummary] = useState<SummaryData | null>(null);
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [itemsPerPage, setItemsPerPage] = useState(25);
|
const [itemsPerPage, setItemsPerPage] = useState(25);
|
||||||
const [sortConfig, setSortConfig] = useState<{ key: string; direction: "ascending" | "descending" } | null>(null);
|
const [sortConfig, setSortConfig] = useState<{
|
||||||
|
key: string;
|
||||||
|
direction: "ascending" | "descending";
|
||||||
|
} | null>(null);
|
||||||
|
|
||||||
const nf = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
|
const nf = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchSummary = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
|
||||||
const response = await fetch("https://api.htl-braunau.at/data/summary");
|
|
||||||
if (!response.ok)
|
|
||||||
throw new Error(`Failed to fetch summary: ${response.statusText}`);
|
|
||||||
const result: SummaryData = await response.json();
|
|
||||||
setSummary(result);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
setError((err as Error).message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchSummary();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const fetchPaginatedData = async () => {
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`https://api.htl-braunau.at/data/paginated?page=${currentPage}&limit=${itemsPerPage === 0 ? "" : itemsPerPage}`);
|
const [summaryRes, dataRes] = await Promise.all([
|
||||||
if (!response.ok)
|
fetch("https://api.htl-braunau.at/data/summary"),
|
||||||
throw new Error(`Failed to fetch data: ${response.statusText}`);
|
fetch(
|
||||||
const result: DataModel[] = await response.json();
|
`https://api.htl-braunau.at/data/paginated?page=${currentPage}&limit=${itemsPerPage === 0 ? "" : itemsPerPage
|
||||||
setData(result);
|
}`,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!summaryRes.ok) {
|
||||||
|
throw new Error(`Failed to fetch summary: ${summaryRes.statusText}`);
|
||||||
|
}
|
||||||
|
if (!dataRes.ok) {
|
||||||
|
throw new Error(`Failed to fetch data: ${dataRes.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const summaryData: SummaryData = await summaryRes.json();
|
||||||
|
const pageData: DataModel[] = await dataRes.json();
|
||||||
|
|
||||||
|
setSummary(summaryData);
|
||||||
|
setData(pageData);
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
setError((err as Error).message);
|
setError((err as Error).message);
|
||||||
@@ -75,13 +167,13 @@ const DataFetcher: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchPaginatedData();
|
fetchData();
|
||||||
}, [currentPage, itemsPerPage]);
|
}, [currentPage, itemsPerPage]);
|
||||||
|
|
||||||
const sortedData = React.useMemo(() => {
|
const sortedData = useMemo(() => {
|
||||||
if (!sortConfig)
|
if (!sortConfig)
|
||||||
return data;
|
return data;
|
||||||
const sorted = [...data].sort((a, b) => {
|
return [...data].sort((a, b) => {
|
||||||
if (a[sortConfig.key] < b[sortConfig.key]) {
|
if (a[sortConfig.key] < b[sortConfig.key]) {
|
||||||
return sortConfig.direction === "ascending" ? -1 : 1;
|
return sortConfig.direction === "ascending" ? -1 : 1;
|
||||||
}
|
}
|
||||||
@@ -90,23 +182,15 @@ const DataFetcher: React.FC = () => {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
return sorted;
|
|
||||||
}, [data, sortConfig]);
|
}, [data, sortConfig]);
|
||||||
|
|
||||||
if (loading)
|
|
||||||
return <p>Loading...</p>;
|
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<p>
|
|
||||||
Error:
|
|
||||||
{error}
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const requestSort = (key: string) => {
|
const requestSort = (key: string) => {
|
||||||
let direction: "ascending" | "descending" = "ascending";
|
let direction: "ascending" | "descending" = "ascending";
|
||||||
if (sortConfig && sortConfig.key === key && sortConfig.direction === "ascending") {
|
if (
|
||||||
|
sortConfig
|
||||||
|
&& sortConfig.key === key
|
||||||
|
&& sortConfig.direction === "ascending"
|
||||||
|
) {
|
||||||
direction = "descending";
|
direction = "descending";
|
||||||
}
|
}
|
||||||
setSortConfig({ key, direction });
|
setSortConfig({ key, direction });
|
||||||
@@ -114,135 +198,447 @@ const DataFetcher: React.FC = () => {
|
|||||||
|
|
||||||
const formatDate = (dateString: string): string => {
|
const formatDate = (dateString: string): string => {
|
||||||
const date = new Date(dateString);
|
const date = new Date(dateString);
|
||||||
const year = date.getFullYear();
|
return new Intl.DateTimeFormat("en-US", {
|
||||||
const month = date.getMonth() + 1;
|
dateStyle: "medium",
|
||||||
const day = date.getDate();
|
timeStyle: "short",
|
||||||
const hours = String(date.getHours()).padStart(2, "0");
|
}).format(date);
|
||||||
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
||||||
const timezoneOffset = dateString.slice(-6);
|
|
||||||
return `${day}.${month}.${year} ${hours}:${minutes} ${timezoneOffset} GMT`;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
const getTypeBadge = (type: string) => {
|
||||||
<div className="p-6 mt-20">
|
if (type === "lxc")
|
||||||
<h1 className="text-2xl font-bold mb-4 text-center">Created LXCs</h1>
|
return formattedBadge("ct");
|
||||||
<ApplicationChart data={summary} />
|
if (type === "vm")
|
||||||
<p className="text-lg font-bold mt-4"> </p>
|
return formattedBadge("vm");
|
||||||
<div className="mb-4 flex justify-between items-center">
|
return null;
|
||||||
<p className="text-lg font-bold">
|
};
|
||||||
{nf.format(
|
|
||||||
summary?.total_entries ?? 0,
|
// Stats calculations
|
||||||
)}
|
const successCount = summary?.status_count.done ?? 0;
|
||||||
{" "}
|
const failureCount = summary?.status_count.failed ?? 0;
|
||||||
results found
|
const totalCount = summary?.total_entries ?? 0;
|
||||||
</p>
|
const successRate = totalCount > 0 ? (successCount / totalCount) * 100 : 0;
|
||||||
<p className="text-lg font">
|
|
||||||
Status Legend: 🔄 installing
|
const allApps = useMemo(() => {
|
||||||
{" "}
|
if (!summary?.nsapp_count)
|
||||||
{nf.format(summary?.status_count.installing ?? 0)}
|
return [];
|
||||||
{" "}
|
return Object.entries(summary.nsapp_count).sort(([, a], [, b]) => b - a);
|
||||||
| ✔️ completed
|
}, [summary]);
|
||||||
{" "}
|
|
||||||
{nf.format(summary?.status_count.done ?? 0)}
|
const topApps = useMemo(() => {
|
||||||
{" "}
|
return allApps.slice(0, 15);
|
||||||
| ❌ failed
|
}, [allApps]);
|
||||||
{" "}
|
|
||||||
{nf.format(summary?.status_count.failed ?? 0)}
|
const mostPopularApp = topApps[0];
|
||||||
{" "}
|
|
||||||
| ❓ unknown
|
// Chart Data
|
||||||
|
const appsChartData = topApps.map(([name, count], index) => ({
|
||||||
|
app: name,
|
||||||
|
count,
|
||||||
|
fill: CHART_COLORS[index % CHART_COLORS.length],
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div className="p-6 text-center text-red-500">
|
||||||
|
<p>
|
||||||
|
Error loading data:
|
||||||
|
{error}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="overflow-x-auto">
|
);
|
||||||
<div className="overflow-y-auto lg:overflow-y-visible">
|
}
|
||||||
<table className="min-w-full table-auto border-collapse">
|
|
||||||
<thead>
|
return (
|
||||||
<tr>
|
<div className="mb-3">
|
||||||
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("status")}>Status</th>
|
<div className="mt-20 flex sm:px-4 xl:px-0">
|
||||||
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("type")}>Type</th>
|
<div className="mx-4 w-full sm:mx-0 space-y-8">
|
||||||
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("nsapp")}>Application</th>
|
{/* Header */}
|
||||||
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("os_type")}>OS</th>
|
<div>
|
||||||
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("os_version")}>OS Version</th>
|
<h1 className="text-3xl font-bold tracking-tight">Analytics</h1>
|
||||||
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("disk_size")}>Disk Size</th>
|
<p className="text-muted-foreground">
|
||||||
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("core_count")}>Core Count</th>
|
Overview of container installations and system statistics.
|
||||||
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("ram_size")}>RAM Size</th>
|
</p>
|
||||||
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("method")}>Method</th>
|
</div>
|
||||||
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("pve_version")}>PVE Version</th>
|
|
||||||
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("error")}>Error Message</th>
|
{/* Widgets */}
|
||||||
<th className="px-4 py-2 border-b cursor-pointer" onClick={() => requestSort("created_at")}>Created At</th>
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
||||||
</tr>
|
<Card>
|
||||||
</thead>
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
<tbody>
|
<CardTitle className="text-sm font-medium">Total Created</CardTitle>
|
||||||
{sortedData.map((item, index) => (
|
<Box className="h-4 w-4 text-muted-foreground" />
|
||||||
<tr key={index}>
|
</CardHeader>
|
||||||
<td className="px-4 py-2 border-b">
|
<CardContent>
|
||||||
{item.status === "done"
|
<div className="text-2xl font-bold">{nf.format(totalCount)}</div>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Total LXC/VM entries found
|
||||||
|
</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Success Rate</CardTitle>
|
||||||
|
<CheckCircle2 className="h-4 w-4 text-green-500" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">
|
||||||
|
{successRate.toFixed(1)}
|
||||||
|
%
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
{nf.format(successCount)}
|
||||||
|
{" "}
|
||||||
|
successful installations
|
||||||
|
</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Failures</CardTitle>
|
||||||
|
<XCircle className="h-4 w-4 text-red-500" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">{nf.format(failureCount)}</div>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Installations encountered errors
|
||||||
|
</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Most Popular</CardTitle>
|
||||||
|
<Trophy className="h-4 w-4 text-yellow-500" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="truncate text-2xl font-bold">
|
||||||
|
{mostPopularApp ? mostPopularApp[0] : "N/A"}
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
{mostPopularApp ? nf.format(mostPopularApp[1]) : 0}
|
||||||
|
{" "}
|
||||||
|
installations
|
||||||
|
</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Graphs */}
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between">
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<CardTitle>Top Applications</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
The most frequently installed applications.
|
||||||
|
</CardDescription>
|
||||||
|
</div>
|
||||||
|
<Dialog>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button variant="outline" size="sm" className="ml-auto">
|
||||||
|
<List className="mr-2 h-4 w-4" />
|
||||||
|
View All
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent className="max-h-[80vh] sm:max-w-md">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Application Statistics</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Installation counts for all
|
||||||
|
{" "}
|
||||||
|
{allApps.length}
|
||||||
|
{" "}
|
||||||
|
applications.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<ScrollArea className="h-[60vh] w-full rounded-md border p-4">
|
||||||
|
<div className="space-y-4">
|
||||||
|
{allApps.map(([name, count], index) => (
|
||||||
|
<div
|
||||||
|
key={name}
|
||||||
|
className="flex items-center justify-between text-sm"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="w-8 font-mono text-muted-foreground">
|
||||||
|
{index + 1}
|
||||||
|
.
|
||||||
|
</span>
|
||||||
|
<span className="font-medium">{name}</span>
|
||||||
|
</div>
|
||||||
|
<span className="font-mono">{nf.format(count)}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="pl-2">
|
||||||
|
<div className="h-[300px] w-full">
|
||||||
|
{loading
|
||||||
|
? (
|
||||||
|
<div className="flex h-full w-full items-center justify-center">
|
||||||
|
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<ChartContainer config={chartConfigApps} className="h-full w-full">
|
||||||
|
<BarChart
|
||||||
|
accessibilityLayer
|
||||||
|
data={appsChartData}
|
||||||
|
margin={{
|
||||||
|
top: 20,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CartesianGrid vertical={false} />
|
||||||
|
<XAxis
|
||||||
|
dataKey="app"
|
||||||
|
tickLine={false}
|
||||||
|
tickMargin={10}
|
||||||
|
axisLine={false}
|
||||||
|
tickFormatter={value => (value.length > 8 ? `${value.slice(0, 8)}...` : value)}
|
||||||
|
/>
|
||||||
|
<ChartTooltip
|
||||||
|
cursor={false}
|
||||||
|
content={<ChartTooltipContent nameKey="app" />}
|
||||||
|
/>
|
||||||
|
<Bar dataKey="count" radius={8}>
|
||||||
|
{appsChartData.map((entry, index) => (
|
||||||
|
<Cell key={`cell-${index}`} fill={entry.fill} />
|
||||||
|
))}
|
||||||
|
<LabelList
|
||||||
|
position="top"
|
||||||
|
offset={12}
|
||||||
|
className="fill-foreground"
|
||||||
|
fontSize={12}
|
||||||
|
/>
|
||||||
|
</Bar>
|
||||||
|
</BarChart>
|
||||||
|
</ChartContainer>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Data Table */}
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<CardTitle>Installation Log</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Detailed records of all container creation attempts.
|
||||||
|
</CardDescription>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Select
|
||||||
|
value={String(itemsPerPage)}
|
||||||
|
onValueChange={val => setItemsPerPage(Number(val))}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-[80px]">
|
||||||
|
<SelectValue placeholder="Limit" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="10">10</SelectItem>
|
||||||
|
<SelectItem value="25">25</SelectItem>
|
||||||
|
<SelectItem value="50">50</SelectItem>
|
||||||
|
<SelectItem value="100">100</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="rounded-md border">
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead
|
||||||
|
className="w-[100px] cursor-pointer"
|
||||||
|
onClick={() => requestSort("status")}
|
||||||
|
>
|
||||||
|
Status
|
||||||
|
{sortConfig?.key === "status" && (
|
||||||
|
<ArrowUpDown className="ml-2 inline h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</TableHead>
|
||||||
|
<TableHead
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => requestSort("type")}
|
||||||
|
>
|
||||||
|
Type
|
||||||
|
{sortConfig?.key === "type" && (
|
||||||
|
<ArrowUpDown className="ml-2 inline h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</TableHead>
|
||||||
|
<TableHead
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => requestSort("nsapp")}
|
||||||
|
>
|
||||||
|
Application
|
||||||
|
{sortConfig?.key === "nsapp" && (
|
||||||
|
<ArrowUpDown className="ml-2 inline h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</TableHead>
|
||||||
|
<TableHead
|
||||||
|
className="hidden cursor-pointer md:table-cell"
|
||||||
|
onClick={() => requestSort("os_type")}
|
||||||
|
>
|
||||||
|
OS
|
||||||
|
{sortConfig?.key === "os_type" && (
|
||||||
|
<ArrowUpDown className="ml-2 inline h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</TableHead>
|
||||||
|
<TableHead
|
||||||
|
className="hidden cursor-pointer md:table-cell"
|
||||||
|
onClick={() => requestSort("disk_size")}
|
||||||
|
>
|
||||||
|
Disk Size
|
||||||
|
{sortConfig?.key === "disk_size" && (
|
||||||
|
<ArrowUpDown className="ml-2 inline h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</TableHead>
|
||||||
|
<TableHead
|
||||||
|
className="hidden cursor-pointer lg:table-cell"
|
||||||
|
onClick={() => requestSort("core_count")}
|
||||||
|
>
|
||||||
|
Core Count
|
||||||
|
{sortConfig?.key === "core_count" && (
|
||||||
|
<ArrowUpDown className="ml-2 inline h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</TableHead>
|
||||||
|
<TableHead
|
||||||
|
className="hidden cursor-pointer lg:table-cell"
|
||||||
|
onClick={() => requestSort("ram_size")}
|
||||||
|
>
|
||||||
|
RAM Size
|
||||||
|
{sortConfig?.key === "ram_size" && (
|
||||||
|
<ArrowUpDown className="ml-2 inline h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</TableHead>
|
||||||
|
<TableHead
|
||||||
|
className="cursor-pointer text-right"
|
||||||
|
onClick={() => requestSort("created_at")}
|
||||||
|
>
|
||||||
|
Created At
|
||||||
|
{sortConfig?.key === "created_at" && (
|
||||||
|
<ArrowUpDown className="ml-2 inline h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{loading
|
||||||
? (
|
? (
|
||||||
"✔️"
|
<TableRow>
|
||||||
|
<TableCell colSpan={8} className="h-24 text-center">
|
||||||
|
<div className="flex items-center justify-center gap-2">
|
||||||
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
|
{" "}
|
||||||
|
Loading data...
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
)
|
)
|
||||||
: item.status === "failed"
|
: sortedData.length > 0
|
||||||
? (
|
? (
|
||||||
"❌"
|
sortedData.map((item, idx) => (
|
||||||
)
|
<TableRow key={`${item.id}-${idx}`}>
|
||||||
: item.status === "installing"
|
<TableCell>
|
||||||
? (
|
{item.status === "done"
|
||||||
"🔄"
|
? (
|
||||||
)
|
<Badge className="text-green-500/75 border-green-500/75">
|
||||||
: (
|
Success
|
||||||
item.status
|
</Badge>
|
||||||
)}
|
)
|
||||||
</td>
|
: item.status === "failed"
|
||||||
<td className="px-4 py-2 border-b">
|
? (
|
||||||
{item.type === "lxc"
|
<Badge className="text-red-500/75 border-red-500/75">
|
||||||
? (
|
Failed
|
||||||
"📦"
|
</Badge>
|
||||||
)
|
)
|
||||||
: item.type === "vm"
|
: item.status === "installing"
|
||||||
? (
|
? (
|
||||||
"🖥️"
|
<Badge className="text-blue-500/75 border-blue-500/75">
|
||||||
|
Installing
|
||||||
|
</Badge>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<Badge variant="outline">
|
||||||
|
{item.status}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{getTypeBadge(item.type) || (
|
||||||
|
<Badge variant="outline">
|
||||||
|
{item.type}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
{item.nsapp}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="hidden md:table-cell">
|
||||||
|
{item.os_type}
|
||||||
|
{" "}
|
||||||
|
{item.os_version}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="hidden md:table-cell">
|
||||||
|
{item.disk_size}
|
||||||
|
MB
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="hidden lg:table-cell">
|
||||||
|
{item.core_count}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="hidden lg:table-cell">
|
||||||
|
{item.ram_size}
|
||||||
|
MB
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right">
|
||||||
|
{formatDate(item.created_at)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
item.type
|
<TableRow>
|
||||||
|
<TableCell colSpan={8} className="h-24 text-center">
|
||||||
|
No results found.
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
</td>
|
</TableBody>
|
||||||
<td className="px-4 py-2 border-b">{item.nsapp}</td>
|
</Table>
|
||||||
<td className="px-4 py-2 border-b">{item.os_type}</td>
|
</div>
|
||||||
<td className="px-4 py-2 border-b">{item.os_version}</td>
|
|
||||||
<td className="px-4 py-2 border-b">{item.disk_size}</td>
|
<div className="flex items-center justify-end space-x-2 py-4">
|
||||||
<td className="px-4 py-2 border-b">{item.core_count}</td>
|
<Button
|
||||||
<td className="px-4 py-2 border-b">{item.ram_size}</td>
|
variant="outline"
|
||||||
<td className="px-4 py-2 border-b">{item.method}</td>
|
size="sm"
|
||||||
<td className="px-4 py-2 border-b">{item.pve_version}</td>
|
onClick={() => setCurrentPage(prev => Math.max(prev - 1, 1))}
|
||||||
<td className="px-4 py-2 border-b">{item.error}</td>
|
disabled={currentPage === 1 || loading}
|
||||||
<td className="px-4 py-2 border-b">{formatDate(item.created_at)}</td>
|
>
|
||||||
</tr>
|
<ChevronLeft className="mr-2 h-4 w-4" />
|
||||||
))}
|
Previous
|
||||||
</tbody>
|
</Button>
|
||||||
</table>
|
<div className="text-sm text-muted-foreground">
|
||||||
|
Page
|
||||||
|
{" "}
|
||||||
|
{currentPage}
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => setCurrentPage(prev => prev + 1)}
|
||||||
|
disabled={loading || sortedData.length < itemsPerPage}
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
<ChevronRight className="ml-2 h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 flex justify-between items-center">
|
|
||||||
<button onClick={() => setCurrentPage(prev => Math.max(prev - 1, 1))} disabled={currentPage === 1} className="p-2 border">Previous</button>
|
|
||||||
<span>
|
|
||||||
Page
|
|
||||||
{currentPage}
|
|
||||||
</span>
|
|
||||||
<button onClick={() => setCurrentPage(prev => prev + 1)} className="p-2 border">Next</button>
|
|
||||||
<select
|
|
||||||
value={itemsPerPage}
|
|
||||||
onChange={e => setItemsPerPage(Number(e.target.value))}
|
|
||||||
className="p-2 border"
|
|
||||||
>
|
|
||||||
<option value={10}>10</option>
|
|
||||||
<option value={20}>20</option>
|
|
||||||
<option value={50}>50</option>
|
|
||||||
<option value={100}>100</option>
|
|
||||||
<option value={250}>250</option>
|
|
||||||
<option value={500}>500</option>
|
|
||||||
<option value={5000}>5000</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default DataFetcher;
|
|
||||||
|
|||||||
@@ -1,199 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { ArcElement, Chart as ChartJS, Tooltip as ChartTooltip, Legend } from "chart.js";
|
|
||||||
import ChartDataLabels from "chartjs-plugin-datalabels";
|
|
||||||
import { BarChart3, PieChart } from "lucide-react";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import { Pie } from "react-chartjs-2";
|
|
||||||
|
|
||||||
import {
|
|
||||||
Table,
|
|
||||||
TableBody,
|
|
||||||
TableCell,
|
|
||||||
TableHead,
|
|
||||||
TableHeader,
|
|
||||||
TableRow,
|
|
||||||
} from "@/components/ui/table";
|
|
||||||
import {
|
|
||||||
Tooltip,
|
|
||||||
TooltipContent,
|
|
||||||
TooltipProvider,
|
|
||||||
TooltipTrigger,
|
|
||||||
} from "@/components/ui/tooltip";
|
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogContent,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
} from "@/components/ui/dialog";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
|
|
||||||
ChartJS.register(ArcElement, ChartTooltip, Legend, ChartDataLabels);
|
|
||||||
|
|
||||||
type SummaryData = {
|
|
||||||
nsapp_count: Record<string, number>;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ApplicationChartProps = {
|
|
||||||
data: SummaryData | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ITEMS_PER_PAGE = 20;
|
|
||||||
const CHART_COLORS = [
|
|
||||||
"#ff6384",
|
|
||||||
"#36a2eb",
|
|
||||||
"#ffce56",
|
|
||||||
"#4bc0c0",
|
|
||||||
"#9966ff",
|
|
||||||
"#ff9f40",
|
|
||||||
"#4dc9f6",
|
|
||||||
"#f67019",
|
|
||||||
"#537bc4",
|
|
||||||
"#acc236",
|
|
||||||
"#166a8f",
|
|
||||||
"#00a950",
|
|
||||||
"#58595b",
|
|
||||||
"#8549ba",
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function ApplicationChart({ data }: ApplicationChartProps) {
|
|
||||||
const [isChartOpen, setIsChartOpen] = useState(false);
|
|
||||||
const [isTableOpen, setIsTableOpen] = useState(false);
|
|
||||||
const [chartStartIndex, setChartStartIndex] = useState(0);
|
|
||||||
const [tableLimit, setTableLimit] = useState(ITEMS_PER_PAGE);
|
|
||||||
|
|
||||||
if (!data)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
const sortedApps = Object.entries(data.nsapp_count)
|
|
||||||
.sort(([, a], [, b]) => b - a);
|
|
||||||
|
|
||||||
const chartApps = sortedApps.slice(
|
|
||||||
chartStartIndex,
|
|
||||||
chartStartIndex + ITEMS_PER_PAGE,
|
|
||||||
);
|
|
||||||
|
|
||||||
const chartData = {
|
|
||||||
labels: chartApps.map(([name]) => name),
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
data: chartApps.map(([, count]) => count),
|
|
||||||
backgroundColor: CHART_COLORS,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const chartOptions = {
|
|
||||||
plugins: {
|
|
||||||
legend: { display: false },
|
|
||||||
datalabels: {
|
|
||||||
color: "white",
|
|
||||||
font: { weight: "bold" as const },
|
|
||||||
formatter: (value: number, context: any) => {
|
|
||||||
const label = context.chart.data.labels?.[context.dataIndex];
|
|
||||||
return `${label}\n(${value})`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="mt-6 flex justify-center gap-4">
|
|
||||||
<TooltipProvider>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="icon"
|
|
||||||
onClick={() => setIsChartOpen(true)}
|
|
||||||
>
|
|
||||||
<PieChart className="h-5 w-5" />
|
|
||||||
</Button>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>Open Chart View</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="icon"
|
|
||||||
onClick={() => setIsTableOpen(true)}
|
|
||||||
>
|
|
||||||
<BarChart3 className="h-5 w-5" />
|
|
||||||
</Button>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>Open Table View</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
|
|
||||||
<Dialog open={isChartOpen} onOpenChange={setIsChartOpen}>
|
|
||||||
<DialogContent className="max-w-3xl">
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>Applications Distribution</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
<div className="h-[60vh] w-full">
|
|
||||||
<Pie data={chartData} options={chartOptions} />
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-center gap-4">
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => setChartStartIndex(Math.max(0, chartStartIndex - ITEMS_PER_PAGE))}
|
|
||||||
disabled={chartStartIndex === 0}
|
|
||||||
>
|
|
||||||
Previous
|
|
||||||
{" "}
|
|
||||||
{ITEMS_PER_PAGE}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => setChartStartIndex(chartStartIndex + ITEMS_PER_PAGE)}
|
|
||||||
disabled={chartStartIndex + ITEMS_PER_PAGE >= sortedApps.length}
|
|
||||||
>
|
|
||||||
Next
|
|
||||||
{" "}
|
|
||||||
{ITEMS_PER_PAGE}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
|
|
||||||
<Dialog open={isTableOpen} onOpenChange={setIsTableOpen}>
|
|
||||||
<DialogContent className="max-w-2xl">
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>Applications Count</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
<div className="max-h-[60vh] overflow-y-auto">
|
|
||||||
<Table>
|
|
||||||
<TableHeader>
|
|
||||||
<TableRow>
|
|
||||||
<TableHead>Application</TableHead>
|
|
||||||
<TableHead className="text-right">Count</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{sortedApps.slice(0, tableLimit).map(([name, count]) => (
|
|
||||||
<TableRow key={name}>
|
|
||||||
<TableCell>{name}</TableCell>
|
|
||||||
<TableCell className="text-right">{count}</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</div>
|
|
||||||
{tableLimit < sortedApps.length && (
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
className="w-full"
|
|
||||||
onClick={() => setTableLimit(prev => prev + ITEMS_PER_PAGE)}
|
|
||||||
>
|
|
||||||
Load More
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
369
frontend/src/components/ui/chart.tsx
Normal file
369
frontend/src/components/ui/chart.tsx
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as RechartsPrimitive from "recharts"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
// Format: { THEME_NAME: CSS_SELECTOR }
|
||||||
|
const THEMES = { light: "", dark: ".dark" } as const
|
||||||
|
|
||||||
|
export type ChartConfig = {
|
||||||
|
[k in string]: {
|
||||||
|
label?: React.ReactNode
|
||||||
|
icon?: React.ComponentType
|
||||||
|
} & (
|
||||||
|
| { color?: string; theme?: never }
|
||||||
|
| { color?: never; theme: Record<keyof typeof THEMES, string> }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChartContextProps = {
|
||||||
|
config: ChartConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChartContext = React.createContext<ChartContextProps | null>(null)
|
||||||
|
|
||||||
|
function useChart() {
|
||||||
|
const context = React.useContext(ChartContext)
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error("useChart must be used within a <ChartContainer />")
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChartContainer = React.forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
React.ComponentProps<"div"> & {
|
||||||
|
config: ChartConfig
|
||||||
|
children: React.ComponentProps<
|
||||||
|
typeof RechartsPrimitive.ResponsiveContainer
|
||||||
|
>["children"]
|
||||||
|
}
|
||||||
|
>(({ id, className, children, config, ...props }, ref) => {
|
||||||
|
const uniqueId = React.useId()
|
||||||
|
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ChartContext.Provider value={{ config }}>
|
||||||
|
<div
|
||||||
|
data-chart={chartId}
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ChartStyle id={chartId} config={config} />
|
||||||
|
<RechartsPrimitive.ResponsiveContainer>
|
||||||
|
{children}
|
||||||
|
</RechartsPrimitive.ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
</ChartContext.Provider>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
ChartContainer.displayName = "Chart"
|
||||||
|
|
||||||
|
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
|
||||||
|
const colorConfig = Object.entries(config).filter(
|
||||||
|
([, config]) => config.theme || config.color
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!colorConfig.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<style
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: Object.entries(THEMES)
|
||||||
|
.map(
|
||||||
|
([theme, prefix]) => `
|
||||||
|
${prefix} [data-chart=${id}] {
|
||||||
|
${colorConfig
|
||||||
|
.map(([key, itemConfig]) => {
|
||||||
|
const color =
|
||||||
|
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
|
||||||
|
itemConfig.color
|
||||||
|
return color ? ` --color-${key}: ${color};` : null
|
||||||
|
})
|
||||||
|
.join("\n")}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
.join("\n"),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChartTooltip = RechartsPrimitive.Tooltip
|
||||||
|
|
||||||
|
const ChartTooltipContent = React.forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
|
||||||
|
React.ComponentProps<"div"> & {
|
||||||
|
hideLabel?: boolean
|
||||||
|
hideIndicator?: boolean
|
||||||
|
indicator?: "line" | "dot" | "dashed"
|
||||||
|
nameKey?: string
|
||||||
|
labelKey?: string
|
||||||
|
}
|
||||||
|
>(
|
||||||
|
(
|
||||||
|
{
|
||||||
|
active,
|
||||||
|
payload,
|
||||||
|
className,
|
||||||
|
indicator = "dot",
|
||||||
|
hideLabel = false,
|
||||||
|
hideIndicator = false,
|
||||||
|
label,
|
||||||
|
labelFormatter,
|
||||||
|
labelClassName,
|
||||||
|
formatter,
|
||||||
|
color,
|
||||||
|
nameKey,
|
||||||
|
labelKey,
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
|
const { config } = useChart()
|
||||||
|
|
||||||
|
const tooltipLabel = React.useMemo(() => {
|
||||||
|
if (hideLabel || !payload?.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const [item] = payload
|
||||||
|
const key = `${labelKey || item?.dataKey || item?.name || "value"}`
|
||||||
|
const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
||||||
|
const value =
|
||||||
|
!labelKey && typeof label === "string"
|
||||||
|
? config[label as keyof typeof config]?.label || label
|
||||||
|
: itemConfig?.label
|
||||||
|
|
||||||
|
if (labelFormatter) {
|
||||||
|
return (
|
||||||
|
<div className={cn("font-medium", labelClassName)}>
|
||||||
|
{labelFormatter(value, payload)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className={cn("font-medium", labelClassName)}>{value}</div>
|
||||||
|
}, [
|
||||||
|
label,
|
||||||
|
labelFormatter,
|
||||||
|
payload,
|
||||||
|
hideLabel,
|
||||||
|
labelClassName,
|
||||||
|
config,
|
||||||
|
labelKey,
|
||||||
|
])
|
||||||
|
|
||||||
|
if (!active || !payload?.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const nestLabel = payload.length === 1 && indicator !== "dot"
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{!nestLabel ? tooltipLabel : null}
|
||||||
|
<div className="grid gap-1.5">
|
||||||
|
{payload
|
||||||
|
.filter((item) => item.type !== "none")
|
||||||
|
.map((item, index) => {
|
||||||
|
const key = `${nameKey || item.name || item.dataKey || "value"}`
|
||||||
|
const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
||||||
|
const indicatorColor = color || item.payload.fill || item.color
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={item.dataKey}
|
||||||
|
className={cn(
|
||||||
|
"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
|
||||||
|
indicator === "dot" && "items-center"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{formatter && item?.value !== undefined && item.name ? (
|
||||||
|
formatter(item.value, item.name, item, index, item.payload)
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{itemConfig?.icon ? (
|
||||||
|
<itemConfig.icon />
|
||||||
|
) : (
|
||||||
|
!hideIndicator && (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
|
||||||
|
{
|
||||||
|
"h-2.5 w-2.5": indicator === "dot",
|
||||||
|
"w-1": indicator === "line",
|
||||||
|
"w-0 border-[1.5px] border-dashed bg-transparent":
|
||||||
|
indicator === "dashed",
|
||||||
|
"my-0.5": nestLabel && indicator === "dashed",
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"--color-bg": indicatorColor,
|
||||||
|
"--color-border": indicatorColor,
|
||||||
|
} as React.CSSProperties
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex flex-1 justify-between leading-none",
|
||||||
|
nestLabel ? "items-end" : "items-center"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="grid gap-1.5">
|
||||||
|
{nestLabel ? tooltipLabel : null}
|
||||||
|
<span className="text-muted-foreground">
|
||||||
|
{itemConfig?.label || item.name}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{item.value && (
|
||||||
|
<span className="font-mono font-medium tabular-nums text-foreground">
|
||||||
|
{item.value.toLocaleString()}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ChartTooltipContent.displayName = "ChartTooltip"
|
||||||
|
|
||||||
|
const ChartLegend = RechartsPrimitive.Legend
|
||||||
|
|
||||||
|
const ChartLegendContent = React.forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
React.ComponentProps<"div"> &
|
||||||
|
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
|
||||||
|
hideIcon?: boolean
|
||||||
|
nameKey?: string
|
||||||
|
}
|
||||||
|
>(
|
||||||
|
(
|
||||||
|
{ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
|
const { config } = useChart()
|
||||||
|
|
||||||
|
if (!payload?.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex items-center justify-center gap-4",
|
||||||
|
verticalAlign === "top" ? "pb-3" : "pt-3",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{payload
|
||||||
|
.filter((item) => item.type !== "none")
|
||||||
|
.map((item) => {
|
||||||
|
const key = `${nameKey || item.dataKey || "value"}`
|
||||||
|
const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={item.value}
|
||||||
|
className={cn(
|
||||||
|
"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{itemConfig?.icon && !hideIcon ? (
|
||||||
|
<itemConfig.icon />
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
className="h-2 w-2 shrink-0 rounded-[2px]"
|
||||||
|
style={{
|
||||||
|
backgroundColor: item.color,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{itemConfig?.label}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ChartLegendContent.displayName = "ChartLegend"
|
||||||
|
|
||||||
|
// Helper to extract item config from a payload.
|
||||||
|
function getPayloadConfigFromPayload(
|
||||||
|
config: ChartConfig,
|
||||||
|
payload: unknown,
|
||||||
|
key: string
|
||||||
|
) {
|
||||||
|
if (typeof payload !== "object" || payload === null) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const payloadPayload =
|
||||||
|
"payload" in payload &&
|
||||||
|
typeof payload.payload === "object" &&
|
||||||
|
payload.payload !== null
|
||||||
|
? payload.payload
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
let configLabelKey: string = key
|
||||||
|
|
||||||
|
if (
|
||||||
|
key in payload &&
|
||||||
|
typeof payload[key as keyof typeof payload] === "string"
|
||||||
|
) {
|
||||||
|
configLabelKey = payload[key as keyof typeof payload] as string
|
||||||
|
} else if (
|
||||||
|
payloadPayload &&
|
||||||
|
key in payloadPayload &&
|
||||||
|
typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
|
||||||
|
) {
|
||||||
|
configLabelKey = payloadPayload[
|
||||||
|
key as keyof typeof payloadPayload
|
||||||
|
] as string
|
||||||
|
}
|
||||||
|
|
||||||
|
return configLabelKey in config
|
||||||
|
? config[configLabelKey]
|
||||||
|
: config[key as keyof typeof config]
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
ChartContainer,
|
||||||
|
ChartTooltip,
|
||||||
|
ChartTooltipContent,
|
||||||
|
ChartLegend,
|
||||||
|
ChartLegendContent,
|
||||||
|
ChartStyle,
|
||||||
|
}
|
||||||
48
frontend/src/components/ui/scroll-area.tsx
Normal file
48
frontend/src/components/ui/scroll-area.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const ScrollArea = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<ScrollAreaPrimitive.Root
|
||||||
|
ref={ref}
|
||||||
|
className={cn("relative overflow-hidden", className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
||||||
|
{children}
|
||||||
|
</ScrollAreaPrimitive.Viewport>
|
||||||
|
<ScrollBar />
|
||||||
|
<ScrollAreaPrimitive.Corner />
|
||||||
|
</ScrollAreaPrimitive.Root>
|
||||||
|
))
|
||||||
|
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
|
||||||
|
|
||||||
|
const ScrollBar = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||||
|
>(({ className, orientation = "vertical", ...props }, ref) => (
|
||||||
|
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||||
|
ref={ref}
|
||||||
|
orientation={orientation}
|
||||||
|
className={cn(
|
||||||
|
"flex touch-none select-none transition-colors",
|
||||||
|
orientation === "vertical" &&
|
||||||
|
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
||||||
|
orientation === "horizontal" &&
|
||||||
|
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
||||||
|
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||||
|
))
|
||||||
|
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
||||||
|
|
||||||
|
export { ScrollArea, ScrollBar }
|
||||||
@@ -290,7 +290,7 @@ GEO_DIR="${INSTALL_DIR}/geodata"
|
|||||||
mkdir -p "$INSTALL_DIR"
|
mkdir -p "$INSTALL_DIR"
|
||||||
mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache}
|
mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache}
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v2.2.3" "$SRC_DIR"
|
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v2.3.1" "$SRC_DIR"
|
||||||
|
|
||||||
msg_info "Installing ${APPLICATION} (patience)"
|
msg_info "Installing ${APPLICATION} (patience)"
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export DATA_DIR=/opt/karakeep_data
|
|||||||
karakeep_SECRET=$(openssl rand -base64 36 | cut -c1-24)
|
karakeep_SECRET=$(openssl rand -base64 36 | cut -c1-24)
|
||||||
mkdir -p /etc/karakeep
|
mkdir -p /etc/karakeep
|
||||||
cat <<EOF >/etc/karakeep/karakeep.env
|
cat <<EOF >/etc/karakeep/karakeep.env
|
||||||
SERVER_VERSION="$(cat ~/.karakeep)"
|
SERVER_VERSION="$(sed 's/^v//' ~/.karakeep)"
|
||||||
NEXTAUTH_SECRET="$karakeep_SECRET"
|
NEXTAUTH_SECRET="$karakeep_SECRET"
|
||||||
NEXTAUTH_URL="http://localhost:3000"
|
NEXTAUTH_URL="http://localhost:3000"
|
||||||
DATA_DIR=${DATA_DIR}
|
DATA_DIR=${DATA_DIR}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ msg_info "Installing Dependencies"
|
|||||||
$STD apt install -y fping
|
$STD apt install -y fping
|
||||||
msg_ok "Installed Dependencies"
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
PHP_VERSION="8.3" PHP_APACHE="YES" PHP_FPM="YES" PHP_MODULE="mysql,gmp,snmp,ldap,apcu" setup_php
|
PHP_VERSION="8.3" PHP_APACHE="YES" PHP_FPM="YES" PHP_MODULE="pdo,pdo-mysql,gmp,snmp,ldap,apcu" setup_php
|
||||||
|
|
||||||
msg_info "Installing PHP-PEAR"
|
msg_info "Installing PHP-PEAR"
|
||||||
$STD apt install -y \
|
$STD apt install -y \
|
||||||
|
|||||||
@@ -13,14 +13,17 @@ load_functions
|
|||||||
verb_ip6() {
|
verb_ip6() {
|
||||||
set_std_mode # Set STD mode based on VERBOSE
|
set_std_mode # Set STD mode based on VERBOSE
|
||||||
|
|
||||||
if [ "$IPV6_METHOD" == "none" ] || [ "$DISABLEIPV6" == "yes" ]; then
|
if [ "$IPV6_METHOD" == "disable" ]; then
|
||||||
msg_info "Disabling IPv6"
|
msg_info "Disabling IPv6 (this may affect some services)"
|
||||||
$STD sysctl -w net.ipv6.conf.all.disable_ipv6=1
|
$STD sysctl -w net.ipv6.conf.all.disable_ipv6=1
|
||||||
$STD sysctl -w net.ipv6.conf.default.disable_ipv6=1
|
$STD sysctl -w net.ipv6.conf.default.disable_ipv6=1
|
||||||
$STD sysctl -w net.ipv6.conf.lo.disable_ipv6=1
|
$STD sysctl -w net.ipv6.conf.lo.disable_ipv6=1
|
||||||
echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf
|
mkdir -p /etc/sysctl.d
|
||||||
echo "net.ipv6.conf.default.disable_ipv6 = 1" >>/etc/sysctl.conf
|
$STD tee /etc/sysctl.d/99-disable-ipv6.conf >/dev/null <<EOF
|
||||||
echo "net.ipv6.conf.lo.disable_ipv6 = 1" >>/etc/sysctl.conf
|
net.ipv6.conf.all.disable_ipv6 = 1
|
||||||
|
net.ipv6.conf.default.disable_ipv6 = 1
|
||||||
|
net.ipv6.conf.lo.disable_ipv6 = 1
|
||||||
|
EOF
|
||||||
$STD rc-update add sysctl default
|
$STD rc-update add sysctl default
|
||||||
msg_ok "Disabled IPv6"
|
msg_ok "Disabled IPv6"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -627,11 +627,12 @@ advanced_settings() {
|
|||||||
# IPv6 Address Management selection
|
# IPv6 Address Management selection
|
||||||
while true; do
|
while true; do
|
||||||
IPV6_METHOD=$(whiptail --backtitle "Proxmox VE Helper Scripts" --menu \
|
IPV6_METHOD=$(whiptail --backtitle "Proxmox VE Helper Scripts" --menu \
|
||||||
"Select IPv6 Address Management Type:" 15 58 4 \
|
"Select IPv6 Address Management Type:" 16 70 5 \
|
||||||
"auto" "SLAAC/AUTO (recommended, default)" \
|
"auto" "SLAAC/AUTO (recommended) - Dynamic IPv6 from network" \
|
||||||
"dhcp" "DHCPv6" \
|
"dhcp" "DHCPv6 - DHCP-assigned IPv6 address" \
|
||||||
"static" "Static (manual entry)" \
|
"static" "Static - Manual IPv6 address configuration" \
|
||||||
"none" "Disabled" \
|
"none" "None - No IPv6 assignment (most containers)" \
|
||||||
|
"disable" "Fully Disabled - (breaks some services)" \
|
||||||
--default-item "auto" 3>&1 1>&2 2>&3)
|
--default-item "auto" 3>&1 1>&2 2>&3)
|
||||||
[ $? -ne 0 ] && exit_script
|
[ $? -ne 0 ] && exit_script
|
||||||
|
|
||||||
@@ -680,7 +681,15 @@ advanced_settings() {
|
|||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
none)
|
none)
|
||||||
echo -e "${NETWORK}${BOLD}${DGN}IPv6: ${BGN}Disabled${CL}"
|
echo -e "${NETWORK}${BOLD}${DGN}IPv6: ${BGN}None${CL}"
|
||||||
|
IPV6_ADDR="none"
|
||||||
|
IPV6_GATE=""
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
disable)
|
||||||
|
whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox \
|
||||||
|
"⚠️ WARNING - FULLY DISABLE IPv6:\n\nThis will completely disable IPv6 inside the container via sysctl.\n\nSide Effects:\n • Services requiring IPv6 will fail\n • Localhost IPv6 (::1) will not work\n • Some applications may not start\n\nOnly use if you have a specific reason to completely disable IPv6.\n\nFor most use cases, select 'None' instead." 14 70
|
||||||
|
echo -e "${NETWORK}${BOLD}${DGN}IPv6: ${BGN}Fully Disabled (IPv6 disabled via sysctl)${CL}"
|
||||||
IPV6_ADDR="none"
|
IPV6_ADDR="none"
|
||||||
IPV6_GATE=""
|
IPV6_GATE=""
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -15,12 +15,16 @@ load_functions
|
|||||||
verb_ip6() {
|
verb_ip6() {
|
||||||
set_std_mode # Set STD mode based on VERBOSE
|
set_std_mode # Set STD mode based on VERBOSE
|
||||||
|
|
||||||
if [ "$IPV6_METHOD" == "none" ] || [ "$DISABLEIPV6" == "yes" ]; then
|
if [ "$IPV6_METHOD" == "disable" ]; then
|
||||||
msg_info "Disabling IPv6"
|
msg_info "Disabling IPv6 (this may affect some services)"
|
||||||
$STD echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf
|
mkdir -p /etc/sysctl.d
|
||||||
$STD echo "net.ipv6.conf.default.disable_ipv6 = 1" >>/etc/sysctl.conf
|
$STD tee /etc/sysctl.d/99-disable-ipv6.conf >/dev/null <<EOF
|
||||||
$STD echo "net.ipv6.conf.lo.disable_ipv6 = 1" >>/etc/sysctl.conf
|
# Disable IPv6 (set by community-scripts)
|
||||||
$STD sysctl -p
|
net.ipv6.conf.all.disable_ipv6 = 1
|
||||||
|
net.ipv6.conf.default.disable_ipv6 = 1
|
||||||
|
net.ipv6.conf.lo.disable_ipv6 = 1
|
||||||
|
EOF
|
||||||
|
$STD sysctl -p /etc/sysctl.d/99-disable-ipv6.conf
|
||||||
msg_ok "Disabled IPv6"
|
msg_ok "Disabled IPv6"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|||||||
161
misc/tools.func
161
misc/tools.func
@@ -3628,59 +3628,57 @@ function setup_php() {
|
|||||||
local CURRENT_PHP=""
|
local CURRENT_PHP=""
|
||||||
CURRENT_PHP=$(is_tool_installed "php" 2>/dev/null) || true
|
CURRENT_PHP=$(is_tool_installed "php" 2>/dev/null) || true
|
||||||
|
|
||||||
# Scenario 1: Already at target version - just update packages
|
# CRITICAL: If wrong version is installed, remove it FIRST before any pinning
|
||||||
if [[ -n "$CURRENT_PHP" && "$CURRENT_PHP" == "$PHP_VERSION" ]]; then
|
if [[ -n "$CURRENT_PHP" && "$CURRENT_PHP" != "$PHP_VERSION" ]]; then
|
||||||
msg_info "Update PHP $PHP_VERSION"
|
msg_info "Removing conflicting PHP ${CURRENT_PHP} (need ${PHP_VERSION})"
|
||||||
|
stop_all_services "php.*-fpm"
|
||||||
# Ensure Sury repo is available
|
$STD apt-get purge -y "php*" 2>/dev/null || true
|
||||||
if [[ ! -f /etc/apt/sources.list.d/php.sources ]]; then
|
$STD apt-get autoremove -y 2>/dev/null || true
|
||||||
manage_tool_repository "php" "$PHP_VERSION" "" "https://packages.sury.org/debsuryorg-archive-keyring.deb" || {
|
|
||||||
msg_error "Failed to setup PHP repository"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
fi
|
|
||||||
|
|
||||||
ensure_apt_working || return 1
|
|
||||||
|
|
||||||
# Perform upgrade with retry logic (non-fatal if fails)
|
|
||||||
upgrade_packages_with_retry "php${PHP_VERSION}" || true
|
|
||||||
|
|
||||||
cache_installed_version "php" "$PHP_VERSION"
|
|
||||||
msg_ok "Update PHP $PHP_VERSION"
|
|
||||||
else
|
|
||||||
# Scenario 2: Different version installed - clean upgrade
|
|
||||||
if [[ -n "$CURRENT_PHP" && "$CURRENT_PHP" != "$PHP_VERSION" ]]; then
|
|
||||||
msg_info "Upgrade PHP from $CURRENT_PHP to $PHP_VERSION"
|
|
||||||
# Stop and disable ALL PHP-FPM versions
|
|
||||||
stop_all_services "php.*-fpm"
|
|
||||||
remove_old_tool_version "php"
|
|
||||||
else
|
|
||||||
msg_info "Setup PHP $PHP_VERSION"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Prepare repository (cleanup + validation)
|
|
||||||
prepare_repository_setup "php" "deb.sury.org-php" || {
|
|
||||||
msg_error "Failed to prepare PHP repository"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Setup Sury repository
|
|
||||||
manage_tool_repository "php" "$PHP_VERSION" "" "https://packages.sury.org/debsuryorg-archive-keyring.deb" || {
|
|
||||||
msg_error "Failed to setup PHP repository"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_apt_working || return 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Build module list
|
# NOW create pinning for the desired version
|
||||||
|
mkdir -p /etc/apt/preferences.d
|
||||||
|
cat <<EOF >/etc/apt/preferences.d/php-pin
|
||||||
|
Package: php${PHP_VERSION}*
|
||||||
|
Pin: version ${PHP_VERSION}.*
|
||||||
|
Pin-Priority: 1001
|
||||||
|
|
||||||
|
Package: php[0-9].*
|
||||||
|
Pin: release o=packages.sury.org-php
|
||||||
|
Pin-Priority: -1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Setup repository
|
||||||
|
prepare_repository_setup "php" "deb.sury.org-php" || {
|
||||||
|
msg_error "Failed to prepare PHP repository"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
manage_tool_repository "php" "$PHP_VERSION" "" "https://packages.sury.org/debsuryorg-archive-keyring.deb" || {
|
||||||
|
msg_error "Failed to setup PHP repository"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_apt_working || return 1
|
||||||
|
$STD apt-get update
|
||||||
|
|
||||||
|
# Get available PHP version from repository
|
||||||
|
local AVAILABLE_PHP_VERSION=""
|
||||||
|
AVAILABLE_PHP_VERSION=$(apt-cache show "php${PHP_VERSION}" 2>/dev/null | grep -m1 "^Version:" | awk '{print $2}' | cut -d- -f1) || true
|
||||||
|
|
||||||
|
if [[ -z "$AVAILABLE_PHP_VERSION" ]]; then
|
||||||
|
msg_error "PHP ${PHP_VERSION} not found in configured repositories"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build module list - without version pinning (preferences.d handles it)
|
||||||
local MODULE_LIST="php${PHP_VERSION}"
|
local MODULE_LIST="php${PHP_VERSION}"
|
||||||
|
|
||||||
IFS=',' read -ra MODULES <<<"$COMBINED_MODULES"
|
IFS=',' read -ra MODULES <<<"$COMBINED_MODULES"
|
||||||
for mod in "${MODULES[@]}"; do
|
for mod in "${MODULES[@]}"; do
|
||||||
if apt-cache show "php${PHP_VERSION}-${mod}" >/dev/null 2>&1; then
|
MODULE_LIST+=" php${PHP_VERSION}-${mod}"
|
||||||
MODULE_LIST+=" php${PHP_VERSION}-${mod}"
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ "$PHP_FPM" == "YES" ]]; then
|
if [[ "$PHP_FPM" == "YES" ]]; then
|
||||||
MODULE_LIST+=" php${PHP_VERSION}-fpm"
|
MODULE_LIST+=" php${PHP_VERSION}-fpm"
|
||||||
fi
|
fi
|
||||||
@@ -3688,18 +3686,52 @@ function setup_php() {
|
|||||||
# install apache2 with PHP support if requested
|
# install apache2 with PHP support if requested
|
||||||
if [[ "$PHP_APACHE" == "YES" ]]; then
|
if [[ "$PHP_APACHE" == "YES" ]]; then
|
||||||
if ! dpkg -l 2>/dev/null | grep -q "libapache2-mod-php${PHP_VERSION}"; then
|
if ! dpkg -l 2>/dev/null | grep -q "libapache2-mod-php${PHP_VERSION}"; then
|
||||||
install_packages_with_retry "apache2" "libapache2-mod-php${PHP_VERSION}" || {
|
msg_info "Installing Apache with PHP ${PHP_VERSION} module"
|
||||||
msg_error "Failed to install Apache with PHP module"
|
install_packages_with_retry "apache2" || {
|
||||||
|
msg_error "Failed to install Apache"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
install_packages_with_retry "libapache2-mod-php${PHP_VERSION}" || {
|
||||||
|
msg_warn "Failed to install libapache2-mod-php${PHP_VERSION}, continuing without Apache module"
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install PHP packages with retry logic
|
# Install PHP packages (pinning via preferences.d ensures correct version)
|
||||||
install_packages_with_retry $MODULE_LIST || {
|
msg_info "Installing PHP ${PHP_VERSION} packages"
|
||||||
msg_error "Failed to install PHP packages"
|
if ! install_packages_with_retry $MODULE_LIST; then
|
||||||
return 1
|
msg_warn "Failed to install PHP packages, attempting individual installation"
|
||||||
}
|
|
||||||
|
# Install main package first (critical)
|
||||||
|
install_packages_with_retry "php${PHP_VERSION}" || {
|
||||||
|
msg_error "Failed to install php${PHP_VERSION}"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Try to install Apache module individually if requested
|
||||||
|
if [[ "$PHP_APACHE" == "YES" ]]; then
|
||||||
|
install_packages_with_retry "libapache2-mod-php${PHP_VERSION}" || {
|
||||||
|
msg_warn "Could not install libapache2-mod-php${PHP_VERSION}"
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Try to install modules individually - skip those that don't exist
|
||||||
|
for pkg in "${MODULES[@]}"; do
|
||||||
|
if apt-cache search "^php${PHP_VERSION}-${pkg}\$" 2>/dev/null | grep -q "^php${PHP_VERSION}-${pkg}"; then
|
||||||
|
install_packages_with_retry "php${PHP_VERSION}-${pkg}" || {
|
||||||
|
msg_warn "Could not install php${PHP_VERSION}-${pkg}"
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$PHP_FPM" == "YES" ]]; then
|
||||||
|
if apt-cache search "^php${PHP_VERSION}-fpm\$" 2>/dev/null | grep -q "^php${PHP_VERSION}-fpm"; then
|
||||||
|
install_packages_with_retry "php${PHP_VERSION}-fpm" || {
|
||||||
|
msg_warn "Could not install php${PHP_VERSION}-fpm"
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
cache_installed_version "php" "$PHP_VERSION"
|
cache_installed_version "php" "$PHP_VERSION"
|
||||||
|
|
||||||
# Patch all relevant php.ini files
|
# Patch all relevant php.ini files
|
||||||
@@ -3735,7 +3767,24 @@ function setup_php() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
msg_ok "Setup PHP $PHP_VERSION"
|
# Verify PHP installation - critical check
|
||||||
|
if ! command -v php >/dev/null 2>&1; then
|
||||||
|
msg_error "PHP installation verification failed - php command not found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local INSTALLED_VERSION=$(php -v 2>/dev/null | awk '/^PHP/{print $2}' | cut -d. -f1,2)
|
||||||
|
|
||||||
|
# Critical: if major.minor doesn't match, fail and cleanup
|
||||||
|
if [[ "$INSTALLED_VERSION" != "$PHP_VERSION" ]]; then
|
||||||
|
msg_error "PHP version mismatch: requested ${PHP_VERSION} but got ${INSTALLED_VERSION}"
|
||||||
|
msg_error "This indicates a critical package installation issue"
|
||||||
|
# Don't cache wrong version
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cache_installed_version "php" "$INSTALLED_VERSION"
|
||||||
|
msg_ok "Setup PHP ${INSTALLED_VERSION}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@@ -4439,7 +4488,7 @@ function setup_rust() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Update to latest patch version
|
# Update to latest patch version
|
||||||
$STD rustup update "$RUST_TOOLCHAIN" || true
|
$STD rustup update "$RUST_TOOLCHAIN" </dev/null || true
|
||||||
|
|
||||||
# Ensure PATH is updated for current shell session
|
# Ensure PATH is updated for current shell session
|
||||||
export PATH="$CARGO_BIN:$PATH"
|
export PATH="$CARGO_BIN:$PATH"
|
||||||
|
|||||||
Reference in New Issue
Block a user