Compare commits

...

13 Commits

Author SHA1 Message Date
shanshanzhong147 cf55495c1f ci(docker): 更新工作流中的镜像名称和容器名称
CI / build (20.15.1) (push) Successful in 22m38s
将工作流中的 ppanel 相关镜像和容器名称统一更新为 fastvpn
修复 develop 分支名称拼写错误
2026-01-03 20:32:31 -08:00
shanshanzhong147 c381a2b2ba fix(docker): 修正Dockerfile中的用户创建命令和CI分支条件
CI / build (20.15.1) (push) Failing after 15m20s
修复Dockerfile中使用addgroup/adduser命令导致的兼容性问题,改用groupadd/useradd
修正CI配置中分支条件判断错误,将dev改为develop
2026-01-03 20:10:53 -08:00
shanshanzhong147 43c909d1f2 ci: 更新构建任务的运行主机为fastvpn-admin01
CI / build (20.15.1) (push) Failing after 16m8s
2026-01-03 19:50:27 -08:00
shanshanzhong147 9eff6aa40d ci(workflow): 更新分支名称和API地址配置
CI / build (20.15.1) (push) Has been cancelled
将dev分支重命名为develop分支
统一所有分支的API地址为https://api.hifast.biz
2026-01-03 19:47:44 -08:00
shanshanzhong147 a211035025 ci(workflow): 更新构建任务运行的服务器节点
将构建任务从 fastvpn-admin01 迁移到 fastvpn-admin-web01 节点执行
2026-01-03 19:46:11 -08:00
shanshanzhong147 aa745079db chore: 移除不再使用的GitHub工作流和模板文件
删除以下不再需要的文件:
- GitHub issue和pull request模板
- 自动合并、发布和issue管理的工作流
- VS Code配置文件
2026-01-03 19:44:33 -08:00
shanshanzhong147 11942e2b9f docs: 添加项目说明文档和初始化配置
ci: 添加docker工作流配置并更新项目名称
2026-01-03 19:43:40 -08:00
web 5eac6a9f4a 🐛 fix: Fixing issues with generating standard and quantum-resistant encryption keys 2025-11-04 20:40:53 -08:00
web@ppanel 2182400adc Merge pull request #61 from Ember-Moth/main
fix: 服务器编辑时合并协议默认配置
2025-11-04 19:51:05 -08:00
Ember Moth 5318b9cf44 Refactor protocol configuration logic in server form 2025-11-02 16:48:41 +08:00
semantic-release-bot 705391f82a 🔖 chore(release): v1.6.0 [skip ci]
# [1.6.0](https://github.com/perfect-panel/ppanel-web/compare/v1.5.4...v1.6.0) (2025-10-28)

###  Features

* Add server installation dialog and commands ([4429c9d](https://github.com/perfect-panel/ppanel-web/commit/4429c9d))

### 🐛 Bug Fixes

* Add typeRoots configuration to ensure type definitions are resolved correctly ([ad60ea9](https://github.com/perfect-panel/ppanel-web/commit/ad60ea9))
2025-10-28 09:13:37 +00:00
web 4429c9ddc9 feat: Add server installation dialog and commands 2025-10-28 02:10:12 -07:00
web ad60ea9b18 🐛 fix: Add typeRoots configuration to ensure type definitions are resolved correctly 2025-10-27 04:05:20 -07:00
49 changed files with 1201 additions and 420 deletions
+790
View File
@@ -0,0 +1,790 @@
name: CI
on:
push:
branches:
- main
- develop
- cicd
pull_request:
branches:
- main
- develop
- cicd
env:
DOMAIN_URL: git.kxsw.us
REPO: ${{ vars.REPO }}
TELEGRAM_BOT_TOKEN: 8114337882:AAHkEx03HSu7RxN4IHBJJEnsK9aPPzNLIk0
TELEGRAM_CHAT_ID: "-4940243803"
DOCKER_REGISTRY: registry.kxsw.us
DOCKER_BUILDKIT: 1
DOCKER_API_VERSION: "1.44"
# Host SSH - 根据分支动态选择
SSH_HOST: ${{ github.ref_name == 'main' && vars.PRO_SSH_HOST || (github.ref_name == 'develop' && vars.DEV_SSH_HOST || vars.PRO_SSH_HOST) }}
SSH_PORT: ${{ github.ref_name == 'main' && vars.PRO_SSH_PORT || (github.ref_name == 'develop' && vars.DEV_SSH_PORT || vars.PRO_SSH_PORT) }}
SSH_USER: ${{ github.ref_name == 'main' && vars.PRO_SSH_USER || (github.ref_name == 'dedevelopv' && vars.DEV_SSH_USER || vars.PRO_SSH_USER) }}
SSH_PASSWORD: ${{ github.ref_name == 'main' && vars.PRO_SSH_PASSWORD || (github.ref_name == 'dedevelopv' && vars.DEV_SSH_PASSWORD || vars.PRO_SSH_PASSWORD) }}
jobs:
build:
runs-on: fastvpn-admin01
container:
image: node:20
strategy:
matrix:
# 只有node支持版本号别名
node: ['20.15.1']
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 缓存服务健康检查
id: cache-health
continue-on-error: true
run: |
echo "检查缓存服务可用性..."
# 设置缓存可用性标志
CACHE_AVAILABLE=true
# 测试GitHub Actions缓存API
if ! curl -s --connect-timeout 10 --max-time 30 "https://api.github.com/repos/${{ github.repository }}/actions/caches" > /dev/null 2>&1; then
echo "⚠️ GitHub Actions缓存服务不可用,将跳过缓存步骤"
CACHE_AVAILABLE=false
else
echo "✅ 缓存服务可用"
fi
echo "CACHE_AVAILABLE=$CACHE_AVAILABLE" >> $GITHUB_ENV
echo "cache-available=$CACHE_AVAILABLE" >> $GITHUB_OUTPUT
- name: 缓存降级提示
if: env.CACHE_AVAILABLE == 'false'
run: |
echo "🔄 缓存服务不可用,构建将在无缓存模式下进行"
echo "⏱️ 这可能会增加构建时间,但不会影响构建结果"
echo "📦 所有依赖将重新下载和安装"
- name: Install system tools (jq, docker, curl)
run: |
set -e
export DEBIAN_FRONTEND=noninteractive
echo "Waiting for apt/dpkg locks (unattended-upgrades) to release..."
# Wait up to 300s for unattended-upgrades/apt/dpkg locks
end=$((SECONDS+300))
while true; do
LOCKS_BUSY=0
# If unattended-upgrades is running, mark busy
if pgrep -x unattended-upgrades >/dev/null 2>&1; then LOCKS_BUSY=1; fi
# If fuser exists, check common lock files
if command -v fuser >/dev/null 2>&1; then
if fuser /var/lib/dpkg/lock >/dev/null 2>&1 \
|| fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 \
|| fuser /var/lib/apt/lists/lock >/dev/null 2>&1; then
LOCKS_BUSY=1
fi
fi
# Break if not busy
if [ "$LOCKS_BUSY" -eq 0 ]; then break; fi
# Timeout after ~5 minutes
if [ $SECONDS -ge $end ]; then
echo "Timeout waiting for apt/dpkg locks, proceeding with Dpkg::Lock::Timeout..."
break
fi
echo "Still waiting for locks..."; sleep 5
done
apt-get update -y -o Dpkg::Lock::Timeout=600
# 基础工具和GPG
apt-get install -y -o Dpkg::Lock::Timeout=600 jq curl ca-certificates gnupg
# 配置Docker官方源,安装新版CLI与Buildx插件(支持 API 1.44+
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo $VERSION_CODENAME) stable" > /etc/apt/sources.list.d/docker.list
apt-get update -y -o Dpkg::Lock::Timeout=600
apt-get install -y -o Dpkg::Lock::Timeout=600 docker-ce-cli docker-buildx-plugin
docker --version
jq --version
curl --version
- name: Set up Docker Buildx
run: |
# Check if buildx is available
if docker buildx version >/dev/null 2>&1; then
echo "Docker Buildx is available"
# Create builder if it doesn't exist
if ! docker buildx ls | grep -q "builder"; then
docker buildx create --name builder --driver docker-container
fi
# Use the builder
docker buildx use builder
docker buildx inspect --bootstrap
else
echo "Docker Buildx not available, using regular docker build"
fi
- name: Install Bun
run: |
echo "=== Installing Bun ==="
echo "Current working directory: $(pwd)"
echo "Current user: $(whoami)"
echo "Home directory: $HOME"
# 设置Bun安装路径
export BUN_INSTALL="$HOME/.bun"
echo "BUN_INSTALL=$BUN_INSTALL" >> $GITHUB_ENV
echo "PATH=$BUN_INSTALL/bin:${PATH}" >> $GITHUB_ENV
# 检查缓存是否存在
if [ -d "$BUN_INSTALL" ]; then
echo "✅ Bun cache found at $BUN_INSTALL"
ls -la "$BUN_INSTALL" || true
else
echo "❌ No Bun cache found, will install fresh"
fi
# 安装Bun
curl -fsSL https://bun.sh/install | bash
# 验证安装
"$BUN_INSTALL/bin/bun" --version
echo "✅ Bun installed successfully"
- name: Configure npm registry (npmmirror) and canvas mirror
run: |
echo "registry=https://registry.npmmirror.com" >> .npmrc
echo "canvas_binary_host_mirror=https://registry.npmmirror.com/-/binary/canvas" >> .npmrc
- name: Install dependencies cache (Bun)
if: env.CACHE_AVAILABLE == 'true'
uses: actions/cache@v4
continue-on-error: true
with:
path: ~/.bun
key: bun-${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('bun.lock') }}
restore-keys: |
bun-${{ runner.os }}-${{ matrix.node }}-
bun-${{ runner.os }}-
- name: Install dependencies cache (node_modules)
if: env.CACHE_AVAILABLE == 'true'
uses: actions/cache@v4
continue-on-error: true
with:
path: |
node_modules
apps/*/node_modules
packages/*/node_modules
key: node-modules-${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('bun.lock', 'package.json', 'apps/*/package.json', 'packages/*/package.json') }}
restore-keys: |
node-modules-${{ runner.os }}-${{ matrix.node }}-
node-modules-${{ runner.os }}-
- name: 缓存状态检查和设置
run: |
echo "=== 缓存状态检查 ==="
echo "检查缓存恢复状态..."
# 检查各种缓存目录
echo "Bun缓存: $([ -d ~/.bun ] && echo '✅ 已发现' || echo '❌ 缺失')"
echo "node_modules: $([ -d node_modules ] && echo '✅ 已发现' || echo '❌ 缺失')"
echo "Turbo缓存: $([ -d .turbo ] && echo '✅ 已发现' || echo '❌ 缺失')"
# 显示缓存大小
if [ -d ~/.bun ]; then
echo "Bun缓存大小: $(du -sh ~/.bun 2>/dev/null || echo '未知')"
fi
if [ -d node_modules ]; then
echo "node_modules大小: $(du -sh node_modules 2>/dev/null || echo '未知')"
fi
if [ -d .turbo ]; then
echo "Turbo缓存大小: $(du -sh .turbo 2>/dev/null || echo '未知')"
fi
echo "=== 缓存设置 ==="
# 确保缓存目录存在且权限正确
mkdir -p ~/.bun ~/.cache .turbo
chmod -R 755 ~/.bun ~/.cache .turbo 2>/dev/null || true
# 设置Bun环境变量
echo "BUN_INSTALL_CACHE_DIR=$HOME/.cache/bun" >> $GITHUB_ENV
echo "BUN_INSTALL_BIN_DIR=$HOME/.bun/bin" >> $GITHUB_ENV
echo "✅ 缓存目录已准备完成"
- name: Turborepo cache (.turbo)
if: env.CACHE_AVAILABLE == 'true'
uses: actions/cache@v4
continue-on-error: true
with:
path: .turbo
key: turbo-${{ runner.os }}-${{ hashFiles('turbo.json') }}-${{ hashFiles('apps//package.json') }}-${{ hashFiles('packages//package.json') }}-${{ hashFiles('bun.lock') }}
restore-keys: |
turbo-${{ runner.os }}-${{ hashFiles('turbo.json') }}-${{ hashFiles('apps//package.json') }}-${{ hashFiles('packages//package.json') }}-
turbo-${{ runner.os }}-${{ hashFiles('turbo.json') }}-
turbo-${{ runner.os }}-
- name: 安装依赖 (bun)
run: |
echo "=== 依赖安装调试信息 ==="
echo "当前目录: $(pwd)"
echo "Bun版本: $(bun --version)"
# 检查node_modules缓存状态
if [ -d "node_modules" ]; then
echo "✅ 发现node_modules缓存"
echo "node_modules大小: $(du -sh node_modules 2>/dev/null || echo '未知')"
else
echo "❌ 未发现node_modules缓存"
fi
# 检查bun.lock文件
if [ -f "bun.lock" ]; then
echo "✅ 发现bun.lock文件"
else
echo "❌ 未发现bun.lock文件"
fi
echo "=== 开始安装依赖 ==="
echo "安装开始时间: $(date)"
bun install --frozen-lockfile
echo "安装完成时间: $(date)"
echo "=== 依赖安装完成 ==="
echo "最终node_modules大小: $(du -sh node_modules 2>/dev/null || echo '未知')"
# 验证缓存效果
echo "=== 缓存效果验证 ==="
if [ -d "node_modules" ]; then
echo "✅ 依赖安装成功"
echo "包数量: $(ls node_modules | wc -l 2>/dev/null || echo '未知')"
else
echo "⚠️ 依赖可能未完全安装"
fi
- name: Decide build target (admin/user/both)
run: |
set -e
COMMIT_MSG="${{ github.event.head_commit.message }}"
BUILD_TARGET="both"
if echo "$COMMIT_MSG" | grep -qi "\[admin-only\]"; then
BUILD_TARGET="admin"
elif echo "$COMMIT_MSG" | grep -qi "\[user-only\]"; then
BUILD_TARGET="user"
else
if git rev-parse HEAD^ >/dev/null 2>&1; then
RANGE="HEAD^..HEAD"
else
RANGE="$(git rev-list --max-parents=0 HEAD)..HEAD"
fi
CHANGED=$(git diff --name-only $RANGE || true)
ADMIN_MATCH=$(echo "$CHANGED" | grep -E '^(apps/admin/|docker/ppanel-admin-web/)' || true)
USER_MATCH=$(echo "$CHANGED" | grep -E '^(apps/user/|docker/ppanel-user-web/)' || true)
PACKAGE_MATCH=$(echo "$CHANGED" | grep -E '^(packages/|turbo.json|package.json|bun.lock)' || true)
if [ -n "$PACKAGE_MATCH" ]; then
BUILD_TARGET="both"
else
if [ -n "$ADMIN_MATCH" ] && [ -z "$USER_MATCH" ]; then BUILD_TARGET="admin"; fi
if [ -n "$USER_MATCH" ] && [ -z "$ADMIN_MATCH" ]; then BUILD_TARGET="user"; fi
if [ -n "$ADMIN_MATCH" ] && [ -n "$USER_MATCH" ]; then BUILD_TARGET="both"; fi
fi
fi
echo "BUILD_TARGET=$BUILD_TARGET" >> $GITHUB_ENV
echo "Decided BUILD_TARGET=$BUILD_TARGET"
- name: Read version from package.json
run: |
if [ "$BUILD_TARGET" = "admin" ]; then
VERSION=$(jq -r .version apps/admin/package.json)
echo "使用 admin 应用版本: $VERSION"
elif [ "$BUILD_TARGET" = "user" ]; then
VERSION=$(jq -r .version apps/user/package.json)
echo "使用 user 应用版本: $VERSION"
else
# both 或其他情况使用根目录版本
VERSION=$(jq -r .version package.json)
echo "使用根目录版本: $VERSION"
fi
if [ "$VERSION" = "null" ] || [ -z "$VERSION" ] || [ "$VERSION" = "undefined" ]; then
echo "检测到版本为空,回退到根目录版本"
VERSION=$(jq -r .version package.json)
fi
echo "VERSION=$VERSION" >> $GITHUB_ENV
- name: 根据分支动态设置API地址
run: |
if [ "${{ github.ref_name }}" = "main" ]; then
echo "NEXT_PUBLIC_API_URL=https://api.hifast.biz" >> $GITHUB_ENV
echo "为main分支设置生产环境API地址"
elif [ "${{ github.ref_name }}" = "develop" ]; then
echo "NEXT_PUBLIC_API_URL=https://api.hifast.biz" >> $GITHUB_ENV
echo "为 develop 分支设置开发环境API地址"
else
echo "NEXT_PUBLIC_API_URL=https://api.hifast.biz" >> $GITHUB_ENV
echo "为其他分支设置默认API地址"
fi
echo "BRANCH=${{ github.ref_name }}" >> $GITHUB_ENV
- name: Cache Next.js build artifacts (.next/cache)
if: env.CACHE_AVAILABLE == 'true'
uses: actions/cache@v4
continue-on-error: true
with:
path: |
apps/admin/.next/cache
apps/user/.next/cache
key: nextcache-${{ runner.os }}-${{ hashFiles('apps//package.json') }}-${{ hashFiles('packages//package.json') }}-${{ hashFiles('turbo.json') }}-${{ hashFiles('bun.lock') }}
restore-keys: |
nextcache-${{ runner.os }}-${{ hashFiles('apps//package.json') }}-${{ hashFiles('packages//package.json') }}-
nextcache-${{ runner.os }}-
- name: Cache build outputs
if: env.CACHE_AVAILABLE == 'true'
uses: actions/cache@v4
continue-on-error: true
with:
path: |
apps/admin/.next
apps/user/.next
apps/admin/dist
apps/user/dist
key: build-${{ runner.os }}-${{ hashFiles('apps//*.ts', 'apps//*.tsx', 'apps//*.js', 'apps//*.jsx') }}-${{ hashFiles('packages//*.ts', 'packages//*.tsx') }}-${{ hashFiles('bun.lock') }}
restore-keys: |
build-${{ runner.os }}-${{ hashFiles('apps//*.ts', 'apps//*.tsx', 'apps//*.js', 'apps//*.jsx') }}-
build-${{ runner.os }}-
- name: Cache ESLint
if: env.CACHE_AVAILABLE == 'true'
uses: actions/cache@v4
continue-on-error: true
with:
path: |
.eslintcache
apps/admin/.eslintcache
apps/user/.eslintcache
key: eslint-${{ runner.os }}-${{ hashFiles('.eslintrc*', 'apps//.eslintrc*', 'packages//.eslintrc*') }}-${{ hashFiles('bun.lock') }}
restore-keys: |
eslint-${{ runner.os }}-
- name: Cache TypeScript
if: env.CACHE_AVAILABLE == 'true'
uses: actions/cache@v4
continue-on-error: true
with:
path: |
.tsbuildinfo
apps/admin/.tsbuildinfo
apps/user/.tsbuildinfo
packages//.tsbuildinfo
key: typescript-${{ runner.os }}-${{ hashFiles('tsconfig*.json', 'apps//tsconfig*.json', 'packages//tsconfig*.json') }}-${{ hashFiles('bun.lock') }}
restore-keys: |
typescript-${{ runner.os }}-
- name: 构建管理面板
if: env.BUILD_TARGET == 'admin' || env.BUILD_TARGET == 'both'
run: bun run build --filter=ppanel-admin-web
- name: 构建用户面板
if: env.BUILD_TARGET == 'user' || env.BUILD_TARGET == 'both'
run: bun run build --filter=ppanel-user-web
- name: 构建并推送管理面板Docker镜像
if: env.BUILD_TARGET == 'admin' || env.BUILD_TARGET == 'both'
run: |
if docker buildx version >/dev/null 2>&1; then
echo "使用docker buildx进行优化构建"
docker buildx build \
--platform linux/amd64 \
--cache-from type=registry,ref=${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-admin-web:cache \
--cache-to type=registry,ref=${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-admin-web:cache,mode=max \
-f ./docker/ppanel-admin-web/Dockerfile \
-t ${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-admin-web:${{ env.VERSION }} \
--push .
else
echo "使用常规docker构建"
docker build -f ./docker/ppanel-admin-web/Dockerfile -t ${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-admin-web:${{ env.VERSION }} .
docker push ${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-admin-web:${{ env.VERSION }}
fi
- name: 构建并推送用户面板Docker镜像
if: env.BUILD_TARGET == 'user' || env.BUILD_TARGET == 'both'
run: |
if docker buildx version >/dev/null 2>&1; then
echo "使用docker buildx进行优化构建"
docker buildx build \
--platform linux/amd64 \
--cache-from type=registry,ref=${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-user-web:cache \
--cache-to type=registry,ref=${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-user-web:cache,mode=max \
-f ./docker/ppanel-user-web/Dockerfile \
-t ${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-user-web:${{ env.VERSION }} \
--push .
else
echo "使用常规docker构建"
docker build -f ./docker/ppanel-user-web/Dockerfile -t ${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-user-web:${{ env.VERSION }} .
docker push ${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-user-web:${{ env.VERSION }}
fi
- name: SSH连接预检查
if: env.BUILD_TARGET == 'admin' || env.BUILD_TARGET == 'user' || env.BUILD_TARGET == 'both'
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ env.SSH_HOST }}
username: ${{ env.SSH_USER }}
password: ${{ env.SSH_PASSWORD }}
port: ${{ env.SSH_PORT }}
timeout: 300s
command_timeout: 600s
debug: true
script: |
echo "=== SSH连接测试 ==="
echo "连接时间: $(date)"
echo "服务器主机名: $(hostname)"
echo "当前用户: $(whoami)"
echo "系统信息: $(uname -a)"
echo "Docker版本: $(docker --version 2>/dev/null || echo 'Docker未安装')"
echo "✅ SSH连接成功"
- name: 部署管理面板到服务器
if: env.BUILD_TARGET == 'admin' || env.BUILD_TARGET == 'both'
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ env.SSH_HOST }}
username: ${{ env.SSH_USER }}
password: ${{ env.SSH_PASSWORD }}
port: ${{ env.SSH_PORT }}
timeout: 300s
command_timeout: 600s
script: |
echo "=== SSH变量调试信息 ==="
echo "DOCKER_REGISTRY: ${{ env.DOCKER_REGISTRY }}"
echo "VERSION: ${{ env.VERSION }}"
echo "NEXT_PUBLIC_API_URL: ${{ env.NEXT_PUBLIC_API_URL }}"
echo "BRANCH: ${{ env.BRANCH }}"
echo "=== 部署管理面板 ==="
# 网络连通性检查
echo "检查镜像服务器连通性..."
REGISTRY_HOST=$(echo "${{ env.DOCKER_REGISTRY }}" | sed 's|https\?://||' | cut -d'/' -f1)
echo "镜像仓库地址: $REGISTRY_HOST"
if ping -c 3 "$REGISTRY_HOST" > /dev/null 2>&1; then
echo "✅ 镜像服务器连通性正常"
else
echo "⚠️ 镜像服务器ping失败,但继续尝试拉取镜像"
fi
# 检查Docker登录状态
echo "检查Docker登录状态..."
if docker info > /dev/null 2>&1; then
echo "✅ Docker服务正常"
else
echo "❌ Docker服务异常"
exit 1
fi
# 拉取镜像(带重试)
echo "拉取Docker镜像..."
for i in {1..3}; do
echo "尝试拉取镜像 ($i/3): ${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-admin-web:${{ env.VERSION }}"
if docker pull ${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-admin-web:${{ env.VERSION }}; then
echo "✅ 镜像拉取成功"
break
else
echo "❌ 镜像拉取失败,重试 $i/3"
echo "检查网络和镜像仓库状态..."
# 显示详细错误信息
echo "--- 网络诊断信息 ---"
echo "DNS解析测试:"
nslookup "$REGISTRY_HOST" || echo "DNS解析失败"
echo "网络连通性测试:"
ping -c 2 "$REGISTRY_HOST" || echo "ping失败"
echo "Docker镜像仓库连接测试:"
curl -I "https://$REGISTRY_HOST/v2/" 2>/dev/null || echo "仓库API访问失败"
sleep 5
if [ $i -eq 3 ]; then
echo "❌ 镜像拉取失败,部署终止"
echo "请检查:"
echo "1. 网络连接是否正常"
echo "2. 镜像仓库是否可访问"
echo "3. 镜像标签是否存在"
echo "4. Docker登录凭据是否正确"
exit 1
fi
fi
done
# 安全停止和移除容器
echo "检查现有容器状态..."
CONTAINER_NAME="ppanel-admin-web"
# 检查容器是否存在
if docker ps -aq -f name=$CONTAINER_NAME | grep -q .; then
echo "发现现有容器,开始清理..."
# 检查容器是否正在运行
if docker ps -q -f name=$CONTAINER_NAME | grep -q .; then
echo "停止运行中的容器..."
docker stop $CONTAINER_NAME --time=15 || true
sleep 5
fi
# 检查容器是否正在被移除
echo "检查容器移除状态..."
for i in {1..15}; do
# 尝试获取容器状态
CONTAINER_STATUS=$(docker inspect $CONTAINER_NAME --format='{{.State.Status}}' 2>/dev/null || echo "not_found")
if [ "$CONTAINER_STATUS" = "not_found" ]; then
echo "✅ 容器已不存在"
break
elif [ "$CONTAINER_STATUS" = "removing" ]; then
echo "⏳ 容器正在移除中,等待完成... $i/15"
sleep 3
else
echo "尝试移除容器... $i/15"
if docker rm -f $CONTAINER_NAME 2>/dev/null; then
echo "✅ 容器移除成功"
break
else
echo "⚠️ 容器移除失败,重试..."
sleep 2
fi
fi
# 最后一次尝试强制清理
if [ $i -eq 15 ]; then
echo "🔧 执行强制清理..."
docker kill $CONTAINER_NAME 2>/dev/null || true
sleep 2
docker rm -f $CONTAINER_NAME 2>/dev/null || true
sleep 2
fi
done
else
echo "✅ 未发现现有容器"
fi
echo "启动新容器..."
docker run -d \
--add-host api.airoport.co:103.150.215.40 \
--name fastvpn-admin-web \
--restart unless-stopped \
-p 3001:3000 \
-e NEXT_PUBLIC_API_URL=${{ env.NEXT_PUBLIC_API_URL }} \
${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-admin-web:${{ env.VERSION }}
# 验证容器启动
echo "验证容器启动状态..."
for i in {1..10}; do
if docker ps -q -f name=fastvpn-admin-web | grep -q .; then
echo "✅ 管理面板部署成功"
docker ps -f name=fastvpn-admin-web --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
exit 0
else
echo "等待容器启动... $i/10"
sleep 3
fi
done
echo "❌ 管理面板部署失败 - 容器未能正常启动"
docker logs fastvpn-admin-web || true
exit 1
- name: 部署用户面板到服务器
if: env.BUILD_TARGET == 'user' || env.BUILD_TARGET == 'both'
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ env.SSH_HOST }}
username: ${{ env.SSH_USER }}
password: ${{ env.SSH_PASSWORD }}
port: ${{ env.SSH_PORT }}
timeout: 300s
command_timeout: 600s
debug: true
script: |
echo "=== SSH变量调试信息 ==="
echo "DOCKER_REGISTRY: ${{ env.DOCKER_REGISTRY }}"
echo "VERSION: ${{ env.VERSION }}"
echo "NEXT_PUBLIC_API_URL: ${{ env.NEXT_PUBLIC_API_URL }}"
echo "BRANCH: ${{ env.BRANCH }}"
echo "=== 部署用户面板 ==="
# 网络连通性检查
echo "检查镜像服务器连通性..."
REGISTRY_HOST=$(echo "${{ env.DOCKER_REGISTRY }}" | sed 's|https\?://||' | cut -d'/' -f1)
echo "镜像仓库地址: $REGISTRY_HOST"
if ping -c 3 "$REGISTRY_HOST" > /dev/null 2>&1; then
echo "✅ 镜像服务器连通性正常"
else
echo "⚠️ 镜像服务器ping失败,但继续尝试拉取镜像"
fi
# 检查Docker登录状态
echo "检查Docker登录状态..."
if docker info > /dev/null 2>&1; then
echo "✅ Docker服务正常"
else
echo "❌ Docker服务异常"
exit 1
fi
# 拉取镜像(带重试)
echo "拉取Docker镜像..."
for i in {1..3}; do
echo "尝试拉取镜像 ($i/3): ${{ env.DOCKER_REGISTRY }}/ppanel/ppanel-user-web:${{ env.VERSION }}"
if docker pull ${{ env.DOCKER_REGISTRY }}/ppanel/ppanel-user-web:${{ env.VERSION }}; then
echo "✅ 镜像拉取成功"
break
else
echo "❌ 镜像拉取失败,重试 $i/3"
echo "检查网络和镜像仓库状态..."
# 显示详细错误信息
echo "--- 网络诊断信息 ---"
echo "DNS解析测试:"
nslookup "$REGISTRY_HOST" || echo "DNS解析失败"
echo "网络连通性测试:"
ping -c 2 "$REGISTRY_HOST" || echo "ping失败"
echo "Docker镜像仓库连接测试:"
curl -I "https://$REGISTRY_HOST/v2/" 2>/dev/null || echo "仓库API访问失败"
sleep 5
if [ $i -eq 3 ]; then
echo "❌ 镜像拉取失败,部署终止"
echo "请检查:"
echo "1. 网络连接是否正常"
echo "2. 镜像仓库是否可访问"
echo "3. 镜像标签是否存在"
echo "4. Docker登录凭据是否正确"
exit 1
fi
fi
done
# 安全停止和移除容器
echo "检查现有容器状态..."
CONTAINER_NAME="ppanel-user-web"
# 检查容器是否存在
if docker ps -aq -f name=$CONTAINER_NAME | grep -q .; then
echo "发现现有容器,开始清理..."
# 检查容器是否正在运行
if docker ps -q -f name=$CONTAINER_NAME | grep -q .; then
echo "停止运行中的容器..."
docker stop $CONTAINER_NAME --time=15 || true
sleep 5
fi
# 检查容器是否正在被移除
echo "检查容器移除状态..."
for i in {1..15}; do
# 尝试获取容器状态
CONTAINER_STATUS=$(docker inspect $CONTAINER_NAME --format='{{.State.Status}}' 2>/dev/null || echo "not_found")
if [ "$CONTAINER_STATUS" = "not_found" ]; then
echo "✅ 容器已不存在"
break
elif [ "$CONTAINER_STATUS" = "removing" ]; then
echo "⏳ 容器正在移除中,等待完成... $i/15"
sleep 3
else
echo "尝试移除容器... $i/15"
if docker rm -f $CONTAINER_NAME 2>/dev/null; then
echo "✅ 容器移除成功"
break
else
echo "⚠️ 容器移除失败,重试..."
sleep 2
fi
fi
# 最后一次尝试强制清理
if [ $i -eq 15 ]; then
echo "🔧 执行强制清理..."
docker kill $CONTAINER_NAME 2>/dev/null || true
sleep 2
docker rm -f $CONTAINER_NAME 2>/dev/null || true
sleep 2
fi
done
else
echo "✅ 未发现现有容器"
fi
echo "启动新容器..."
docker run -d \
--add-host api.airoport.co:103.150.215.40 \
--name fastvpn-user-web \
--restart unless-stopped \
-p 3002:3000 \
-e NEXT_PUBLIC_API_URL=${{ env.NEXT_PUBLIC_API_URL }} \
${{ env.DOCKER_REGISTRY }}/ppanel/fastvpn-user-web:${{ env.VERSION }}
# 验证容器启动
echo "验证容器启动状态..."
for i in {1..10}; do
if docker ps -q -f name=fastvpn-user-web | grep -q .; then
echo "✅ 用户面板部署成功"
docker ps -f name=fastvpn-user-web --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
exit 0
else
echo "等待容器启动... $i/10"
sleep 3
fi
done
echo "❌ 用户面板部署失败 - 容器未能正常启动"
docker logs fastvpn-user-web || true
exit 1
# 步骤5: TG通知 (成功)
- name: 📱 发送成功通知到Telegram
if: success()
uses: appleboy/telegram-action@master
with:
token: ${{ env.TELEGRAM_BOT_TOKEN }}
to: ${{ env.TELEGRAM_CHAT_ID }}
message: |
✅ 部署成功!
📦 项目: ${{ github.repository }}
🌿 分支: ${{ github.ref_name }}
🔖 版本: ${{ env.VERSION }}
🎯 构建目标: ${{ env.BUILD_TARGET }}
🔗 API地址: ${{ env.NEXT_PUBLIC_API_URL }}
📝 提交: ${{ github.sha }}
👤 提交者: ${{ github.actor }}
🕐 时间: ${{ github.event.head_commit.timestamp }}
🚀 服务已成功部署到生产环境
# 步骤5: TG通知 (失败)
- name: 📱 发送失败通知到Telegram
if: failure()
uses: appleboy/telegram-action@master
with:
token: ${{ env.TELEGRAM_BOT_TOKEN }}
to: ${{ env.TELEGRAM_CHAT_ID }}
message: |
❌ 部署失败!
📦 项目: ${{ github.repository }}
🌿 分支: ${{ github.ref_name }}
🔖 版本: ${{ env.VERSION }}
🎯 构建目标: ${{ env.BUILD_TARGET }}
📝 提交: ${{ github.sha }}
👤 提交者: ${{ github.actor }}
🕐 时间: ${{ github.event.head_commit.timestamp }}
⚠️ 请检查构建日志获取详细信息
-45
View File
@@ -1,45 +0,0 @@
name: '🐛 反馈缺陷 Bug Report'
description: '反馈一个问题缺陷 | Report an bug'
title: '[Bug] '
labels: '🐛 Bug'
body:
- type: dropdown
attributes:
label: '💻 系统环境 | Operating System'
options:
- Windows
- macOS
- Ubuntu
- Other Linux
- Other
validations:
required: true
- type: dropdown
attributes:
label: '🌐 浏览器 | Browser'
options:
- Chrome
- Edge
- Safari
- Firefox
- Other
validations:
required: true
- type: textarea
attributes:
label: '🐛 问题描述 | Bug Description'
description: A clear and concise description of the bug.
validations:
required: true
- type: textarea
attributes:
label: '🚦 期望结果 | Expected Behavior'
description: A clear and concise description of what you expected to happen.
- type: textarea
attributes:
label: '📷 复现步骤 | Recurrence Steps'
description: A clear and concise description of how to recurrence.
- type: textarea
attributes:
label: '📝 补充信息 | Additional Information'
description: If your problem needs further explanation, or if the issue you're seeing cannot be reproduced in a gist, please add more information here.
@@ -1,21 +0,0 @@
name: '🌠 功能需求 Feature Request'
description: '需求或建议 | Suggest an idea'
title: '[Request] '
labels: '🌠 Feature Request'
body:
- type: textarea
attributes:
label: '🥰 需求描述 | Feature Description'
description: Please add a clear and concise description of the problem you are seeking to solve with this feature request.
validations:
required: true
- type: textarea
attributes:
label: '🧐 解决方案 | Proposed Solution'
description: Describe the solution you'd like in a clear and concise manner.
validations:
required: true
- type: textarea
attributes:
label: '📝 补充信息 | Additional Information'
description: Add any other context about the problem here.
-15
View File
@@ -1,15 +0,0 @@
name: '😇 疑问或帮助 Help Wanted'
description: '疑问或需要帮助 | Need help'
title: '[Question] '
labels: '😇 Help Wanted'
body:
- type: textarea
attributes:
label: '🧐 问题描述 | Proposed Solution'
description: A clear and concise description of the proplem.
validations:
required: true
- type: textarea
attributes:
label: '📝 补充信息 | Additional Information'
description: Add any other context about the problem here.
-7
View File
@@ -1,7 +0,0 @@
---
name: '📝 其他 Other'
about: '其他问题 | Other issues'
title: ''
labels: ''
assignees: ''
---
-17
View File
@@ -1,17 +0,0 @@
#### 💻 变更类型 | Change Type
<!-- For change type, change [ ] to [x]. -->
- \[ ] ✨ feat
- \[ ] 🐛 fix
- \[ ] 💄 style
- \[ ] 🔨 chore
- \[ ] 📝 docs
#### 🔀 变更说明 | Description of Change
<!-- Thank you for your Pull Request. Please provide a description above. -->
#### 📝 补充信息 | Additional Information
<!-- Add any other context about the Pull Request here. -->
-30
View File
@@ -1,30 +0,0 @@
name: Dependabot Auto Merge
on:
pull_request_target:
types: [labeled, edited]
jobs:
merge:
if: contains(github.event.pull_request.labels.*.name, 'dependencies')
name: Dependabot Auto Merge
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install deps
run: pnpm install
- name: Merge
uses: ahmadnassri/action-dependabot-auto-merge@v2
with:
command: merge
target: minor
github-token: ${{ secrets.GH_TOKEN }}
@@ -1,22 +0,0 @@
name: Issue Check Inactive
on:
schedule:
- cron: '0 0 */15 * *'
permissions:
contents: read
jobs:
issue-check-inactive:
permissions:
issues: write # for actions-cool/issues-helper to update issues
pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest
steps:
- name: check-inactive
uses: actions-cool/issues-helper@v3
with:
actions: 'check-inactive'
inactive-label: 'Inactive'
inactive-day: 30
-46
View File
@@ -1,46 +0,0 @@
name: Issue Close Require
on:
schedule:
- cron: '0 0 * * *'
permissions:
contents: read
jobs:
issue-close-require:
permissions:
issues: write # for actions-cool/issues-helper to update issues
pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest
steps:
- name: need reproduce
uses: actions-cool/issues-helper@v3
with:
actions: 'close-issues'
labels: '✅ Fixed'
inactive-day: 3
body: |
Since the issue was labeled with `✅ Fixed`, but no response in 3 days. This issue will be closed. If you have any questions, you can comment and reply.
由于该 issue 被标记为已修复,同时 3 天未收到回应。现关闭 issue,若有任何问题,可评论回复。
- name: need reproduce
uses: actions-cool/issues-helper@v3
with:
actions: 'close-issues'
labels: '🤔 Need Reproduce'
inactive-day: 3
body: |
Since the issue was labeled with `🤔 Need Reproduce`, but no response in 3 days. This issue will be closed. If you have any questions, you can comment and reply.
由于该 issue 被标记为需要更多信息,却 3 天未收到回应。现关闭 issue,若有任何问题,可评论回复。
- name: need reproduce
uses: actions-cool/issues-helper@v3
with:
actions: 'close-issues'
labels: "🙅🏻‍♀️ WON'T DO"
inactive-day: 3
body: |
Since the issue was labeled with `🙅🏻‍♀️ WON'T DO`, and no response in 3 days. This issue will be closed. If you have any questions, you can comment and reply.
由于该 issue 被标记为暂不处理,同时 3 天未收到回应。现关闭 issue,若有任何问题,可评论回复。
@@ -1,25 +0,0 @@
name: Issue Remove Inactive
on:
issues:
types: [edited]
issue_comment:
types: [created, edited]
permissions:
contents: read
jobs:
issue-remove-inactive:
permissions:
issues: write # for actions-cool/issues-helper to update issues
pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest
steps:
- name: remove inactive
if: github.event.issue.state == 'open' && github.actor == github.event.issue.user.login
uses: actions-cool/issues-helper@v3
with:
actions: 'remove-labels'
issue-number: ${{ github.event.issue.number }}
labels: 'Inactive'
@@ -1,89 +0,0 @@
name: Publish Release Assets
on:
release:
types: [published]
permissions:
contents: write
jobs:
publish:
name: Publish Release Assets
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: 'latest'
- name: Cache Bun dependencies
uses: actions/cache@v3
with:
path: |
~/.bun
key: ${{ runner.os }}-bun-cache-${{ hashFiles('**/bun.lockb') }}
restore-keys: |
${{ runner.os }}-bun-cache-
- name: Install deps
run: bun install --cache
- name: Build
run: bun run build
- name: Run publish script
run: |
chmod +x scripts/publish.sh
./scripts/publish.sh
- name: Upload tar.gz file to release
uses: softprops/action-gh-release@v2
with:
files: |
out/ppanel-admin-web.tar.gz
out/ppanel-user-web.tar.gz
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Install jq
run: sudo apt-get install -y jq
- name: Extract version from package.json
id: version
run: echo "PPANEL_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_ENV
- name: Build and push Docker image for ppanel-admin-web
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/ppanel-admin-web/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/ppanel-admin-web:latest
${{ secrets.DOCKER_USERNAME }}/ppanel-admin-web:${{ env.PPANEL_VERSION }}
- name: Build and push Docker image for ppanel-user-web
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/ppanel-user-web/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/ppanel-user-web:latest
${{ secrets.DOCKER_USERNAME }}/ppanel-user-web:${{ env.PPANEL_VERSION }}
-42
View File
@@ -1,42 +0,0 @@
name: Build and Release
on:
push:
branches: [main, next, beta]
permissions:
contents: write
jobs:
release:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: 'latest'
- name: Cache Bun dependencies
uses: actions/cache@v3
with:
path: |
~/.bun
node_modules
key: ${{ runner.os }}-bun-cache-${{ hashFiles('**/bun.lockb') }}
restore-keys: |
${{ runner.os }}-bun-cache-
- name: Install deps
run: bun install
- name: Build
run: bun run build
- name: Release
id: release
run: bun run release
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
-15
View File
@@ -1,15 +0,0 @@
{
"eslint.workingDirectories": [
{
"mode": "auto"
}
],
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": {
"*.ts": "${capture}.js",
"*.js": "${capture}.js.map, ${capture}.min.js, ${capture}.d.ts",
"*.jsx": "${capture}.js",
"*.tsx": "${capture}.ts",
"README.md": "*.md, LICENSE"
}
}
+21 -8
View File
@@ -1,23 +1,36 @@
<a name="readme-top"></a> <a name="readme-top"></a>
# Changelog
# [1.6.0](https://github.com/perfect-panel/ppanel-web/compare/v1.5.4...v1.6.0) (2025-10-28)
### ✨ Features
- Add server installation dialog and commands ([4429c9d](https://github.com/perfect-panel/ppanel-web/commit/4429c9d))
### 🐛 Bug Fixes
- Add typeRoots configuration to ensure type definitions are resolved correctly ([ad60ea9](https://github.com/perfect-panel/ppanel-web/commit/ad60ea9))
<a name="readme-top"></a>
# Changelog # Changelog
## [1.5.4](https://github.com/perfect-panel/ppanel-web/compare/v1.5.3...v1.5.4) (2025-10-26) ## [1.5.4](https://github.com/perfect-panel/ppanel-web/compare/v1.5.3...v1.5.4) (2025-10-26)
### 🐛 Bug Fixes ### 🐛 Bug Fixes
* Update generateRealityKeyPair to use async key generation ([e60e369](https://github.com/perfect-panel/ppanel-web/commit/e60e369)) - Update generateRealityKeyPair to use async key generation ([e60e369](https://github.com/perfect-panel/ppanel-web/commit/e60e369))
* Update the wallet localization file and add new fields such as automatic reset and recharge ([88aa965](https://github.com/perfect-panel/ppanel-web/commit/88aa965)) - Update the wallet localization file and add new fields such as automatic reset and recharge ([88aa965](https://github.com/perfect-panel/ppanel-web/commit/88aa965))
## [1.5.3](https://github.com/perfect-panel/ppanel-web/compare/v1.5.2...v1.5.3) (2025-10-21) ## [1.5.3](https://github.com/perfect-panel/ppanel-web/compare/v1.5.2...v1.5.3) (2025-10-21)
### 🐛 Bug Fixes ### 🐛 Bug Fixes
* Fix bugs ([a46657d](https://github.com/perfect-panel/ppanel-web/commit/a46657d)) - Fix bugs ([a46657d](https://github.com/perfect-panel/ppanel-web/commit/a46657d))
* Fix dependencies ([8bd25d6](https://github.com/perfect-panel/ppanel-web/commit/8bd25d6)) - Fix dependencies ([8bd25d6](https://github.com/perfect-panel/ppanel-web/commit/8bd25d6))
* Remove unnecessary migration function code and add device configuration options ([521a7a9](https://github.com/perfect-panel/ppanel-web/commit/521a7a9)) - Remove unnecessary migration function code and add device configuration options ([521a7a9](https://github.com/perfect-panel/ppanel-web/commit/521a7a9))
* Update bun.lockb to reflect dependency changes ([ca892dd](https://github.com/perfect-panel/ppanel-web/commit/ca892dd)) - Update bun.lockb to reflect dependency changes ([ca892dd](https://github.com/perfect-panel/ppanel-web/commit/ca892dd))
<a name="readme-top"></a> <a name="readme-top"></a>
@@ -444,7 +444,16 @@ export const PROTOCOL_FIELDS: Record<string, FieldConfig[]> = {
placeholder: (t) => t('encryption_private_key_placeholder'), placeholder: (t) => t('encryption_private_key_placeholder'),
group: 'encryption', group: 'encryption',
generate: { generate: {
functions: [
{
label: (t) => t('generate_standard_encryption_key'),
function: generateRealityKeyPair,
},
{
label: (t) => t('generate_quantum_resistant_key'),
function: generateMLKEM768KeyPair, function: generateMLKEM768KeyPair,
},
],
updateFields: { updateFields: {
encryption_private_key: 'privateKey', encryption_private_key: 'privateKey',
encryption_password: 'publicKey', encryption_password: 'publicKey',
@@ -12,7 +12,11 @@ export type FieldConfig = {
step?: number; step?: number;
suffix?: string; suffix?: string;
generate?: { generate?: {
function?: () => Promise<string | Record<string, string>> | string | Record<string, string>;
functions?: {
label: string | ((t: (key: string) => string, protocol: any) => string);
function: () => Promise<string | Record<string, string>> | string | Record<string, string>; function: () => Promise<string | Record<string, string>> | string | Record<string, string>;
}[];
updateFields?: Record<string, string>; updateFields?: Record<string, string>;
}; };
condition?: (protocol: any, values: any) => boolean; condition?: (protocol: any, values: any) => boolean;
@@ -1,11 +1,11 @@
import * as x25519 from '@noble/ed25519'; import { x25519 } from '@noble/curves/ed25519.js';
import { toB64Url } from './util'; import { toB64Url } from './util';
/** /**
* Generate a Reality key pair * Generate a Reality key pair
* @returns An object containing the private and public keys in base64url format * @returns An object containing the private and public keys in base64url format
*/ */
export async function generateRealityKeyPair() { export function generateRealityKeyPair() {
const { secretKey, publicKey } = await x25519.keygenAsync(); const { secretKey, publicKey } = x25519.keygen();
return { privateKey: toB64Url(secretKey), publicKey: toB64Url(publicKey) }; return { privateKey: toB64Url(secretKey), publicKey: toB64Url(publicKey) };
} }
+2 -1
View File
@@ -21,6 +21,7 @@ import DynamicMultiplier from './dynamic-multiplier';
import OnlineUsersCell from './online-users-cell'; import OnlineUsersCell from './online-users-cell';
import ServerConfig from './server-config'; import ServerConfig from './server-config';
import ServerForm from './server-form'; import ServerForm from './server-form';
import ServerInstall from './server-install';
function PctBar({ value }: { value: number }) { function PctBar({ value }: { value: number }) {
const v = value.toFixed(2); const v = value.toFixed(2);
@@ -60,7 +61,6 @@ export default function ServersPage() {
const { fetchServers } = useServer(); const { fetchServers } = useServer();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [migrating, setMigrating] = useState(false);
const ref = useRef<ProTableActions>(null); const ref = useRef<ProTableActions>(null);
return ( return (
@@ -224,6 +224,7 @@ export default function ServersPage() {
} }
}} }}
/>, />,
<ServerInstall key='install' server={row} />,
<ConfirmButton <ConfirmButton
key='delete' key='delete'
trigger={ trigger={
@@ -10,6 +10,12 @@ import {
} from '@workspace/ui/components/accordion'; } from '@workspace/ui/components/accordion';
import { Badge } from '@workspace/ui/components/badge'; import { Badge } from '@workspace/ui/components/badge';
import { Button } from '@workspace/ui/components/button'; import { Button } from '@workspace/ui/components/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@workspace/ui/components/dropdown-menu';
import { import {
Form, Form,
FormControl, FormControl,
@@ -99,11 +105,49 @@ function DynamicField({
onValueChange={(v) => fieldProps.onChange(v)} onValueChange={(v) => fieldProps.onChange(v)}
suffix={ suffix={
field.generate ? ( field.generate ? (
field.generate.functions && field.generate.functions.length > 0 ? (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button type='button' variant='ghost' size='sm'>
<Icon icon='mdi:key' className='h-4 w-4' />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align='end'>
{field.generate.functions.map((genFunc, idx) => (
<DropdownMenuItem
key={idx}
onClick={async () => {
const result = await genFunc.function();
if (typeof result === 'string') {
fieldProps.onChange(result);
} else if (field.generate!.updateFields) {
Object.entries(field.generate!.updateFields).forEach(
([fieldName, resultKey]) => {
const fullFieldName = `protocols.${protocolIndex}.${fieldName}`;
form.setValue(fullFieldName, (result as any)[resultKey]);
},
);
} else {
if (result.privateKey) {
fieldProps.onChange(result.privateKey);
}
}
}}
>
{typeof genFunc.label === 'function'
? genFunc.label(t, protocolData)
: genFunc.label}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
) : field.generate.function ? (
<Button <Button
type='button' type='button'
variant='ghost' variant='ghost'
size='sm'
onClick={async () => { onClick={async () => {
const result = await field.generate!.function(); const result = await field.generate!.function!();
if (typeof result === 'string') { if (typeof result === 'string') {
fieldProps.onChange(result); fieldProps.onChange(result);
} else if (field.generate!.updateFields) { } else if (field.generate!.updateFields) {
@@ -122,6 +166,7 @@ function DynamicField({
> >
<Icon icon='mdi:key' className='h-4 w-4' /> <Icon icon='mdi:key' className='h-4 w-4' />
</Button> </Button>
) : null
) : ( ) : (
field.suffix field.suffix
) )
@@ -356,7 +401,8 @@ export default function ServerForm(props: {
...initialValues, ...initialValues,
protocols: PROTOCOLS.map((type) => { protocols: PROTOCOLS.map((type) => {
const existingProtocol = initialValues.protocols?.find((p) => p.type === type); const existingProtocol = initialValues.protocols?.find((p) => p.type === type);
return existingProtocol || getProtocolDefaultConfig(type); const defaultConfig = getProtocolDefaultConfig(type);
return existingProtocol ? { ...defaultConfig, ...existingProtocol } : defaultConfig;
}), }),
}); });
} }
@@ -0,0 +1,119 @@
'use client';
import { getNodeConfig } from '@/services/admin/system';
import { useQuery } from '@tanstack/react-query';
import { Button } from '@workspace/ui/components/button';
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@workspace/ui/components/dialog';
import { Input } from '@workspace/ui/components/input';
import { Label } from '@workspace/ui/components/label';
import { useTranslations } from 'next-intl';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { toast } from 'sonner';
type Props = {
server: API.Server;
};
export default function ServerInstall({ server }: Props) {
const t = useTranslations('servers');
const [open, setOpen] = useState(false);
const [domain, setDomain] = useState('');
const { data: cfgResp } = useQuery({
queryKey: ['getNodeConfig'],
queryFn: async () => {
const { data } = await getNodeConfig();
return data.data as API.NodeConfig | undefined;
},
enabled: open,
});
useEffect(() => {
if (open) {
const host = localStorage.getItem('API_HOST') ?? window.location.origin;
setDomain(host);
}
}, [open]);
const installCommand = useMemo(() => {
const secret = cfgResp?.node_secret ?? '';
return `wget -N https://raw.githubusercontent.com/perfect-panel/ppanel-node/master/scripts/install.sh && bash install.sh --api-host ${domain} --server-id ${server.id} --secret-key ${secret}`;
}, [domain, server.id, cfgResp?.node_secret]);
async function handleCopy() {
try {
if (navigator?.clipboard?.writeText) {
await navigator.clipboard.writeText(installCommand);
} else {
// fallback for environments without clipboard API
const el = document.createElement('textarea');
el.value = installCommand;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
}
toast.success(t('copied'));
setOpen(false);
} catch (error) {
toast.error(t('copyFailed'));
}
}
const onDomainChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
setDomain(e.target.value);
localStorage.setItem('API_HOST', e.target.value);
}, []);
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant='secondary'>{t('connect')}</Button>
</DialogTrigger>
<DialogContent className='w-[720px] max-w-full md:max-w-screen-md'>
<DialogHeader>
<DialogTitle>{t('oneClickInstall')}</DialogTitle>
</DialogHeader>
<div className='space-y-4'>
<div>
<Label>{t('apiHost')}</Label>
<div className='flex items-center gap-2'>
<Input
value={domain}
placeholder={t('apiHostPlaceholder')}
onChange={onDomainChange}
/>
</div>
</div>
<div>
<Label>{t('installCommand')}</Label>
<div className='flex flex-col gap-2'>
<textarea
readOnly
aria-label={t('installCommand')}
value={installCommand}
className='min-h-[88px] w-full rounded border p-2 font-mono text-sm'
/>
</div>
</div>
</div>
<DialogFooter className='flex-row justify-end gap-2 pt-3'>
<Button variant='outline' onClick={() => setOpen(false)}>
{t('close')}
</Button>
<Button onClick={handleCopy}>{t('copyAndClose')}</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Adresa", "address": "Adresa",
"address_placeholder": "Adresa serveru", "address_placeholder": "Adresa serveru",
"apiHost": "API hostitel",
"apiHostPlaceholder": "http(s)://example.com",
"bandwidth_placeholder": "Zadejte šířku pásma, nechte prázdné pro BBR", "bandwidth_placeholder": "Zadejte šířku pásma, nechte prázdné pro BBR",
"basic": "Základní konfigurace", "basic": "Základní konfigurace",
"cancel": "Zrušit", "cancel": "Zrušit",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Tuto akci nelze vrátit zpět.", "confirmDeleteDesc": "Tuto akci nelze vrátit zpět.",
"confirmDeleteTitle": "Smazat tento server?", "confirmDeleteTitle": "Smazat tento server?",
"congestion_controller": "Ovladač přetížení", "congestion_controller": "Ovladač přetížení",
"connect": "Připojit",
"copied": "Zkopírováno", "copied": "Zkopírováno",
"copy": "Kopírovat", "copy": "Kopírovat",
"country": "Země", "country": "Země",
@@ -47,11 +50,14 @@
"expired": "Vypršelo", "expired": "Vypršelo",
"extra": "Další konfigurace", "extra": "Další konfigurace",
"flow": "Tok", "flow": "Tok",
"generate_quantum_resistant_key": "Generovat kvantově odolný klíč",
"generate_standard_encryption_key": "Generovat standardní šifrovací klíč",
"hop_interval": "Interval skoku", "hop_interval": "Interval skoku",
"hop_ports": "Porty skoku", "hop_ports": "Porty skoku",
"hop_ports_placeholder": "např. 1-65535", "hop_ports_placeholder": "např. 1-65535",
"host": "Hostitel", "host": "Hostitel",
"id": "ID", "id": "ID",
"installCommand": "Instalační příkaz",
"ipAddresses": "IP adresy", "ipAddresses": "IP adresy",
"memory": "Paměť", "memory": "Paměť",
"migrate": "Migrace dat", "migrate": "Migrace dat",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Zadejte heslo pro obfuskaci", "obfs_password_placeholder": "Zadejte heslo pro obfuskaci",
"obfs_path": "Obfs cesta", "obfs_path": "Obfs cesta",
"offline": "Offline", "offline": "Offline",
"oneClickInstall": "Instalace jedním kliknutím",
"online": "Online", "online": "Online",
"onlineUsers": "Online uživatelé", "onlineUsers": "Online uživatelé",
"padding_scheme": "Schéma vycpání", "padding_scheme": "Schéma vycpání",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Adresse", "address": "Adresse",
"address_placeholder": "Serveradresse", "address_placeholder": "Serveradresse",
"apiHost": "API-Host",
"apiHostPlaceholder": "http(s)://beispiel.de",
"bandwidth_placeholder": "Geben Sie die Bandbreite ein, lassen Sie das Feld leer für BBR", "bandwidth_placeholder": "Geben Sie die Bandbreite ein, lassen Sie das Feld leer für BBR",
"basic": "Grundkonfiguration", "basic": "Grundkonfiguration",
"cancel": "Abbrechen", "cancel": "Abbrechen",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Diese Aktion kann nicht rückgängig gemacht werden.", "confirmDeleteDesc": "Diese Aktion kann nicht rückgängig gemacht werden.",
"confirmDeleteTitle": "Diesen Server löschen?", "confirmDeleteTitle": "Diesen Server löschen?",
"congestion_controller": "Staukontroller", "congestion_controller": "Staukontroller",
"connect": "Verbinden",
"copied": "Kopiert", "copied": "Kopiert",
"copy": "Kopieren", "copy": "Kopieren",
"country": "Land", "country": "Land",
@@ -47,11 +50,14 @@
"expired": "Abgelaufen", "expired": "Abgelaufen",
"extra": "Zusätzliche Konfiguration", "extra": "Zusätzliche Konfiguration",
"flow": "Fluss", "flow": "Fluss",
"generate_quantum_resistant_key": "Quantenresistenten Schlüssel generieren",
"generate_standard_encryption_key": "Standard-Verschlüsselungsschlüssel generieren",
"hop_interval": "Hop-Intervall", "hop_interval": "Hop-Intervall",
"hop_ports": "Hop-Ports", "hop_ports": "Hop-Ports",
"hop_ports_placeholder": "z.B. 1-65535", "hop_ports_placeholder": "z.B. 1-65535",
"host": "Host", "host": "Host",
"id": "ID", "id": "ID",
"installCommand": "Installationsbefehl",
"ipAddresses": "IP-Adressen", "ipAddresses": "IP-Adressen",
"memory": "Speicher", "memory": "Speicher",
"migrate": "Daten migrieren", "migrate": "Daten migrieren",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Obfuskationspasswort eingeben", "obfs_password_placeholder": "Obfuskationspasswort eingeben",
"obfs_path": "Obfs-Pfad", "obfs_path": "Obfs-Pfad",
"offline": "Offline", "offline": "Offline",
"oneClickInstall": "Ein-Klick-Installation",
"online": "Online", "online": "Online",
"onlineUsers": "Online-Benutzer", "onlineUsers": "Online-Benutzer",
"padding_scheme": "Polsterungsschema", "padding_scheme": "Polsterungsschema",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Address", "address": "Address",
"address_placeholder": "Server address", "address_placeholder": "Server address",
"apiHost": "API Host",
"apiHostPlaceholder": "http(s)://example.com",
"bandwidth_placeholder": "Enter bandwidth, leave empty for BBR", "bandwidth_placeholder": "Enter bandwidth, leave empty for BBR",
"basic": "Basic Configuration", "basic": "Basic Configuration",
"cancel": "Cancel", "cancel": "Cancel",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "This action cannot be undone.", "confirmDeleteDesc": "This action cannot be undone.",
"confirmDeleteTitle": "Delete this server?", "confirmDeleteTitle": "Delete this server?",
"congestion_controller": "Congestion controller", "congestion_controller": "Congestion controller",
"connect": "Connect",
"copied": "Copied", "copied": "Copied",
"copy": "Copy", "copy": "Copy",
"country": "Country", "country": "Country",
@@ -47,11 +50,14 @@
"expired": "Expired", "expired": "Expired",
"extra": "Extra Configuration", "extra": "Extra Configuration",
"flow": "Flow", "flow": "Flow",
"generate_quantum_resistant_key": "Generate Quantum-Resistant Key",
"generate_standard_encryption_key": "Generate Standard Encryption Key",
"hop_interval": "Hop interval", "hop_interval": "Hop interval",
"hop_ports": "Hop ports", "hop_ports": "Hop ports",
"hop_ports_placeholder": "e.g. 1-65535", "hop_ports_placeholder": "e.g. 1-65535",
"host": "Host", "host": "Host",
"id": "ID", "id": "ID",
"installCommand": "Install command",
"ipAddresses": "IP addresses", "ipAddresses": "IP addresses",
"memory": "Memory", "memory": "Memory",
"migrate": "Migrate Data", "migrate": "Migrate Data",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Enter obfuscation password", "obfs_password_placeholder": "Enter obfuscation password",
"obfs_path": "Obfs Path", "obfs_path": "Obfs Path",
"offline": "Offline", "offline": "Offline",
"oneClickInstall": "One-click Install",
"online": "Online", "online": "Online",
"onlineUsers": "Online users", "onlineUsers": "Online users",
"padding_scheme": "Padding Scheme", "padding_scheme": "Padding Scheme",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Dirección", "address": "Dirección",
"address_placeholder": "Dirección del servidor", "address_placeholder": "Dirección del servidor",
"apiHost": "Host de API",
"apiHostPlaceholder": "http(s)://ejemplo.com",
"bandwidth_placeholder": "Introduce el ancho de banda, deja vacío para BBR", "bandwidth_placeholder": "Introduce el ancho de banda, deja vacío para BBR",
"basic": "Configuración Básica", "basic": "Configuración Básica",
"cancel": "Cancelar", "cancel": "Cancelar",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Esta acción no se puede deshacer.", "confirmDeleteDesc": "Esta acción no se puede deshacer.",
"confirmDeleteTitle": "¿Eliminar este servidor?", "confirmDeleteTitle": "¿Eliminar este servidor?",
"congestion_controller": "Controlador de congestión", "congestion_controller": "Controlador de congestión",
"connect": "Conectar",
"copied": "Copiado", "copied": "Copiado",
"copy": "Copiar", "copy": "Copiar",
"country": "País", "country": "País",
@@ -47,11 +50,14 @@
"expired": "Expirado", "expired": "Expirado",
"extra": "Configuración Extra", "extra": "Configuración Extra",
"flow": "Flujo", "flow": "Flujo",
"generate_quantum_resistant_key": "Generar clave resistente a cuánticos",
"generate_standard_encryption_key": "Generar clave de cifrado estándar",
"hop_interval": "Intervalo de salto", "hop_interval": "Intervalo de salto",
"hop_ports": "Puertos de salto", "hop_ports": "Puertos de salto",
"hop_ports_placeholder": "p. ej. 1-65535", "hop_ports_placeholder": "p. ej. 1-65535",
"host": "Host", "host": "Host",
"id": "ID", "id": "ID",
"installCommand": "Comando de instalación",
"ipAddresses": "Direcciones IP", "ipAddresses": "Direcciones IP",
"memory": "Memoria", "memory": "Memoria",
"migrate": "Migrar datos", "migrate": "Migrar datos",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Ingrese la contraseña de ofuscación", "obfs_password_placeholder": "Ingrese la contraseña de ofuscación",
"obfs_path": "Ruta de Ofuscación", "obfs_path": "Ruta de Ofuscación",
"offline": "Desconectado", "offline": "Desconectado",
"oneClickInstall": "Instalación con un clic",
"online": "Conectado", "online": "Conectado",
"onlineUsers": "Usuarios en línea", "onlineUsers": "Usuarios en línea",
"padding_scheme": "Esquema de Relleno", "padding_scheme": "Esquema de Relleno",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Dirección", "address": "Dirección",
"address_placeholder": "Dirección del servidor", "address_placeholder": "Dirección del servidor",
"apiHost": "Host de API",
"apiHostPlaceholder": "http(s)://ejemplo.com",
"bandwidth_placeholder": "Ingresa el ancho de banda, deja vacío para BBR", "bandwidth_placeholder": "Ingresa el ancho de banda, deja vacío para BBR",
"basic": "Configuración Básica", "basic": "Configuración Básica",
"cancel": "Cancelar", "cancel": "Cancelar",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Esta acción no se puede deshacer.", "confirmDeleteDesc": "Esta acción no se puede deshacer.",
"confirmDeleteTitle": "¿Eliminar este servidor?", "confirmDeleteTitle": "¿Eliminar este servidor?",
"congestion_controller": "Controlador de congestión", "congestion_controller": "Controlador de congestión",
"connect": "Conectar",
"copied": "Copiado", "copied": "Copiado",
"copy": "Copiar", "copy": "Copiar",
"country": "País", "country": "País",
@@ -47,11 +50,14 @@
"expired": "Expirado", "expired": "Expirado",
"extra": "Configuración Extra", "extra": "Configuración Extra",
"flow": "Flujo", "flow": "Flujo",
"generate_quantum_resistant_key": "Generar clave resistente a cuánticos",
"generate_standard_encryption_key": "Generar clave de cifrado estándar",
"hop_interval": "Intervalo de salto", "hop_interval": "Intervalo de salto",
"hop_ports": "Puertos de salto", "hop_ports": "Puertos de salto",
"hop_ports_placeholder": "p. ej. 1-65535", "hop_ports_placeholder": "p. ej. 1-65535",
"host": "Host", "host": "Host",
"id": "ID", "id": "ID",
"installCommand": "Comando de instalación",
"ipAddresses": "Direcciones IP", "ipAddresses": "Direcciones IP",
"memory": "Memoria", "memory": "Memoria",
"migrate": "Migrar datos", "migrate": "Migrar datos",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Ingresa la contraseña de ofuscación", "obfs_password_placeholder": "Ingresa la contraseña de ofuscación",
"obfs_path": "Ruta de Ofuscación", "obfs_path": "Ruta de Ofuscación",
"offline": "Desconectado", "offline": "Desconectado",
"oneClickInstall": "Instalación con un clic",
"online": "Conectado", "online": "Conectado",
"onlineUsers": "Usuarios en línea", "onlineUsers": "Usuarios en línea",
"padding_scheme": "Esquema de Relleno", "padding_scheme": "Esquema de Relleno",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "آدرس", "address": "آدرس",
"address_placeholder": "آدرس سرور", "address_placeholder": "آدرس سرور",
"apiHost": "میزبان API",
"apiHostPlaceholder": "http(s)://example.com",
"bandwidth_placeholder": "عرض پهنای باند، برای BBR خالی بگذارید", "bandwidth_placeholder": "عرض پهنای باند، برای BBR خالی بگذارید",
"basic": "پیکربندی پایه", "basic": "پیکربندی پایه",
"cancel": "لغو", "cancel": "لغو",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "این عمل قابل بازگشت نیست.", "confirmDeleteDesc": "این عمل قابل بازگشت نیست.",
"confirmDeleteTitle": "آیا این سرور را حذف کنید؟", "confirmDeleteTitle": "آیا این سرور را حذف کنید؟",
"congestion_controller": "کنترل‌کننده ترافیک", "congestion_controller": "کنترل‌کننده ترافیک",
"connect": "اتصال",
"copied": "کپی شد", "copied": "کپی شد",
"copy": "کپی", "copy": "کپی",
"country": "کشور", "country": "کشور",
@@ -47,11 +50,14 @@
"expired": "منقضی شده", "expired": "منقضی شده",
"extra": "پیکربندی اضافی", "extra": "پیکربندی اضافی",
"flow": "جریان", "flow": "جریان",
"generate_quantum_resistant_key": "تولید کلید مقاوم در برابر کوانتوم",
"generate_standard_encryption_key": "تولید کلید رمزگذاری استاندارد",
"hop_interval": "فاصله پرش", "hop_interval": "فاصله پرش",
"hop_ports": "پورت‌های پرش", "hop_ports": "پورت‌های پرش",
"hop_ports_placeholder": "مثلاً 1-65535", "hop_ports_placeholder": "مثلاً 1-65535",
"host": "میزبان", "host": "میزبان",
"id": "شناسه", "id": "شناسه",
"installCommand": "دستور نصب",
"ipAddresses": "آدرس‌های IP", "ipAddresses": "آدرس‌های IP",
"memory": "حافظه", "memory": "حافظه",
"migrate": "انتقال داده", "migrate": "انتقال داده",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "رمز عبور اختفا را وارد کنید", "obfs_password_placeholder": "رمز عبور اختفا را وارد کنید",
"obfs_path": "مسیر پنهان‌سازی", "obfs_path": "مسیر پنهان‌سازی",
"offline": "آفلاین", "offline": "آفلاین",
"oneClickInstall": "نصب با یک کلیک",
"online": "آنلاین", "online": "آنلاین",
"onlineUsers": "کاربران آنلاین", "onlineUsers": "کاربران آنلاین",
"padding_scheme": "طرح پدینگ", "padding_scheme": "طرح پدینگ",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Osoite", "address": "Osoite",
"address_placeholder": "Palvelimen osoite", "address_placeholder": "Palvelimen osoite",
"apiHost": "API-isäntä",
"apiHostPlaceholder": "http(s)://esimerkki.com",
"bandwidth_placeholder": "Syötä kaistanleveys, jätä tyhjäksi BBR:lle", "bandwidth_placeholder": "Syötä kaistanleveys, jätä tyhjäksi BBR:lle",
"basic": "Perusasetukset", "basic": "Perusasetukset",
"cancel": "Peruuta", "cancel": "Peruuta",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Tätä toimintoa ei voi peruuttaa.", "confirmDeleteDesc": "Tätä toimintoa ei voi peruuttaa.",
"confirmDeleteTitle": "Poista tämä palvelin?", "confirmDeleteTitle": "Poista tämä palvelin?",
"congestion_controller": "Ruuhkansäätö", "congestion_controller": "Ruuhkansäätö",
"connect": "Yhdistä",
"copied": "Kopioitu", "copied": "Kopioitu",
"copy": "Kopioi", "copy": "Kopioi",
"country": "Maa", "country": "Maa",
@@ -47,11 +50,14 @@
"expired": "Vanhentunut", "expired": "Vanhentunut",
"extra": "Lisäasetukset", "extra": "Lisäasetukset",
"flow": "Virta", "flow": "Virta",
"generate_quantum_resistant_key": "Luo kvanttikestävä avain",
"generate_standard_encryption_key": "Luo standardi salausavain",
"hop_interval": "Hyppyvälit", "hop_interval": "Hyppyvälit",
"hop_ports": "Hyppysatamat", "hop_ports": "Hyppysatamat",
"hop_ports_placeholder": "esim. 1-65535", "hop_ports_placeholder": "esim. 1-65535",
"host": "Isäntä", "host": "Isäntä",
"id": "ID", "id": "ID",
"installCommand": "Asennuskomento",
"ipAddresses": "IP-osoitteet", "ipAddresses": "IP-osoitteet",
"memory": "Muisti", "memory": "Muisti",
"migrate": "Siirrä tiedot", "migrate": "Siirrä tiedot",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Syötä häilytyssalasana", "obfs_password_placeholder": "Syötä häilytyssalasana",
"obfs_path": "Häilytys polku", "obfs_path": "Häilytys polku",
"offline": "Offline", "offline": "Offline",
"oneClickInstall": "Yhden napsautuksen asennus",
"online": "Online", "online": "Online",
"onlineUsers": "Verkossa olevat käyttäjät", "onlineUsers": "Verkossa olevat käyttäjät",
"padding_scheme": "Täyttökaavio", "padding_scheme": "Täyttökaavio",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Adresse", "address": "Adresse",
"address_placeholder": "Adresse du serveur", "address_placeholder": "Adresse du serveur",
"apiHost": "Hôte API",
"apiHostPlaceholder": "http(s)://exemple.com",
"bandwidth_placeholder": "Entrez la bande passante, laissez vide pour BBR", "bandwidth_placeholder": "Entrez la bande passante, laissez vide pour BBR",
"basic": "Configuration de base", "basic": "Configuration de base",
"cancel": "Annuler", "cancel": "Annuler",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Cette action ne peut pas être annulée.", "confirmDeleteDesc": "Cette action ne peut pas être annulée.",
"confirmDeleteTitle": "Supprimer ce serveur ?", "confirmDeleteTitle": "Supprimer ce serveur ?",
"congestion_controller": "Contrôleur de congestion", "congestion_controller": "Contrôleur de congestion",
"connect": "Se connecter",
"copied": "Copié", "copied": "Copié",
"copy": "Copier", "copy": "Copier",
"country": "Pays", "country": "Pays",
@@ -47,11 +50,14 @@
"expired": "Expiré", "expired": "Expiré",
"extra": "Configuration supplémentaire", "extra": "Configuration supplémentaire",
"flow": "Flux", "flow": "Flux",
"generate_quantum_resistant_key": "Générer une clé résistante aux quantiques",
"generate_standard_encryption_key": "Générer une clé de chiffrement standard",
"hop_interval": "Intervalle de saut", "hop_interval": "Intervalle de saut",
"hop_ports": "Ports de saut", "hop_ports": "Ports de saut",
"hop_ports_placeholder": "ex. 1-65535", "hop_ports_placeholder": "ex. 1-65535",
"host": "Hôte", "host": "Hôte",
"id": "ID", "id": "ID",
"installCommand": "Commande d'installation",
"ipAddresses": "Adresses IP", "ipAddresses": "Adresses IP",
"memory": "Mémoire", "memory": "Mémoire",
"migrate": "Migrer les données", "migrate": "Migrer les données",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Entrez le mot de passe d'obfuscation", "obfs_password_placeholder": "Entrez le mot de passe d'obfuscation",
"obfs_path": "Chemin Obfs", "obfs_path": "Chemin Obfs",
"offline": "Hors ligne", "offline": "Hors ligne",
"oneClickInstall": "Installation en un clic",
"online": "En ligne", "online": "En ligne",
"onlineUsers": "Utilisateurs en ligne", "onlineUsers": "Utilisateurs en ligne",
"padding_scheme": "Schéma de remplissage", "padding_scheme": "Schéma de remplissage",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "पता", "address": "पता",
"address_placeholder": "सर्वर का पता", "address_placeholder": "सर्वर का पता",
"apiHost": "एपीआई होस्ट",
"apiHostPlaceholder": "http(s)://example.com",
"bandwidth_placeholder": "बैंडविड्थ दर्ज करें, BBR के लिए खाली छोड़ें", "bandwidth_placeholder": "बैंडविड्थ दर्ज करें, BBR के लिए खाली छोड़ें",
"basic": "बुनियादी कॉन्फ़िगरेशन", "basic": "बुनियादी कॉन्फ़िगरेशन",
"cancel": "रद्द करें", "cancel": "रद्द करें",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "यह क्रिया पूर्ववत नहीं की जा सकती।", "confirmDeleteDesc": "यह क्रिया पूर्ववत नहीं की जा सकती।",
"confirmDeleteTitle": "क्या इस सर्वर को हटाएं?", "confirmDeleteTitle": "क्या इस सर्वर को हटाएं?",
"congestion_controller": "भीड़ नियंत्रण", "congestion_controller": "भीड़ नियंत्रण",
"connect": "जोड़ें",
"copied": "कॉपी किया गया", "copied": "कॉपी किया गया",
"copy": "कॉपी करें", "copy": "कॉपी करें",
"country": "देश", "country": "देश",
@@ -47,11 +50,14 @@
"expired": "समय समाप्त", "expired": "समय समाप्त",
"extra": "अतिरिक्त कॉन्फ़िगरेशन", "extra": "अतिरिक्त कॉन्फ़िगरेशन",
"flow": "प्रवाह", "flow": "प्रवाह",
"generate_quantum_resistant_key": "क्वांटम-प्रतिरोधी कुंजी उत्पन्न करें",
"generate_standard_encryption_key": "मानक एन्क्रिप्शन कुंजी उत्पन्न करें",
"hop_interval": "हॉप अंतराल", "hop_interval": "हॉप अंतराल",
"hop_ports": "हॉप पोर्ट", "hop_ports": "हॉप पोर्ट",
"hop_ports_placeholder": "जैसे 1-65535", "hop_ports_placeholder": "जैसे 1-65535",
"host": "होस्ट", "host": "होस्ट",
"id": "आईडी", "id": "आईडी",
"installCommand": "इंस्टॉल कमांड",
"ipAddresses": "आईपी पते", "ipAddresses": "आईपी पते",
"memory": "मेमोरी", "memory": "मेमोरी",
"migrate": "डेटा माइग्रेट करें", "migrate": "डेटा माइग्रेट करें",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "अवशोषण पासवर्ड दर्ज करें", "obfs_password_placeholder": "अवशोषण पासवर्ड दर्ज करें",
"obfs_path": "ओबफ्स पथ", "obfs_path": "ओबफ्स पथ",
"offline": "ऑफलाइन", "offline": "ऑफलाइन",
"oneClickInstall": "एक-क्लिक इंस्टॉलेशन",
"online": "ऑनलाइन", "online": "ऑनलाइन",
"onlineUsers": "ऑनलाइन उपयोगकर्ता", "onlineUsers": "ऑनलाइन उपयोगकर्ता",
"padding_scheme": "पैडिंग योजना", "padding_scheme": "पैडिंग योजना",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Cím", "address": "Cím",
"address_placeholder": "Szerver cím", "address_placeholder": "Szerver cím",
"apiHost": "API gazda",
"apiHostPlaceholder": "http(s)://pelda.com",
"bandwidth_placeholder": "Adja meg a sávszélességet, hagyja üresen a BBR-hez", "bandwidth_placeholder": "Adja meg a sávszélességet, hagyja üresen a BBR-hez",
"basic": "Alapértelmezett Beállítások", "basic": "Alapértelmezett Beállítások",
"cancel": "Mégse", "cancel": "Mégse",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Ez a művelet nem vonható vissza.", "confirmDeleteDesc": "Ez a művelet nem vonható vissza.",
"confirmDeleteTitle": "Törölni szeretné ezt a szervert?", "confirmDeleteTitle": "Törölni szeretné ezt a szervert?",
"congestion_controller": "Torlaszkezelő", "congestion_controller": "Torlaszkezelő",
"connect": "Csatlakozás",
"copied": "Másolva", "copied": "Másolva",
"copy": "Másolás", "copy": "Másolás",
"country": "Ország", "country": "Ország",
@@ -47,11 +50,14 @@
"expired": "Lejárt", "expired": "Lejárt",
"extra": "További konfiguráció", "extra": "További konfiguráció",
"flow": "Forgalom", "flow": "Forgalom",
"generate_quantum_resistant_key": "Kvantumálló kulcs generálása",
"generate_standard_encryption_key": "Szabványos titkosítási kulcs generálása",
"hop_interval": "Ugrás időköz", "hop_interval": "Ugrás időköz",
"hop_ports": "Ugrás portok", "hop_ports": "Ugrás portok",
"hop_ports_placeholder": "pl. 1-65535", "hop_ports_placeholder": "pl. 1-65535",
"host": "Gazda", "host": "Gazda",
"id": "ID", "id": "ID",
"installCommand": "Telepítési parancs",
"ipAddresses": "IP címek", "ipAddresses": "IP címek",
"memory": "Memória", "memory": "Memória",
"migrate": "Adatok migrálása", "migrate": "Adatok migrálása",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Adja meg az obfuszkálás jelszót", "obfs_password_placeholder": "Adja meg az obfuszkálás jelszót",
"obfs_path": "Obfs útvonal", "obfs_path": "Obfs útvonal",
"offline": "Offline", "offline": "Offline",
"oneClickInstall": "Egylépéses telepítés",
"online": "Online", "online": "Online",
"onlineUsers": "Online felhasználók", "onlineUsers": "Online felhasználók",
"padding_scheme": "Kitöltési Sémák", "padding_scheme": "Kitöltési Sémák",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "アドレス", "address": "アドレス",
"address_placeholder": "サーバーアドレス", "address_placeholder": "サーバーアドレス",
"apiHost": "APIホスト",
"apiHostPlaceholder": "http(s)://example.com",
"bandwidth_placeholder": "帯域幅を入力してください。BBRの場合は空白のままにしてください。", "bandwidth_placeholder": "帯域幅を入力してください。BBRの場合は空白のままにしてください。",
"basic": "基本設定", "basic": "基本設定",
"cancel": "キャンセル", "cancel": "キャンセル",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "この操作は元に戻せません。", "confirmDeleteDesc": "この操作は元に戻せません。",
"confirmDeleteTitle": "このサーバーを削除しますか?", "confirmDeleteTitle": "このサーバーを削除しますか?",
"congestion_controller": "混雑制御", "congestion_controller": "混雑制御",
"connect": "接続",
"copied": "コピーしました", "copied": "コピーしました",
"copy": "コピー", "copy": "コピー",
"country": "国", "country": "国",
@@ -47,11 +50,14 @@
"expired": "期限切れ", "expired": "期限切れ",
"extra": "追加設定", "extra": "追加設定",
"flow": "フロー", "flow": "フロー",
"generate_quantum_resistant_key": "量子耐性キーを生成",
"generate_standard_encryption_key": "標準暗号化キーを生成",
"hop_interval": "ホップ間隔", "hop_interval": "ホップ間隔",
"hop_ports": "ホップポート", "hop_ports": "ホップポート",
"hop_ports_placeholder": "例: 1-65535", "hop_ports_placeholder": "例: 1-65535",
"host": "ホスト", "host": "ホスト",
"id": "ID", "id": "ID",
"installCommand": "インストールコマンド",
"ipAddresses": "IPアドレス", "ipAddresses": "IPアドレス",
"memory": "メモリ", "memory": "メモリ",
"migrate": "データを移行する", "migrate": "データを移行する",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "難読化パスワードを入力してください", "obfs_password_placeholder": "難読化パスワードを入力してください",
"obfs_path": "難読化パス", "obfs_path": "難読化パス",
"offline": "オフライン", "offline": "オフライン",
"oneClickInstall": "ワンクリックインストール",
"online": "オンライン", "online": "オンライン",
"onlineUsers": "オンラインユーザー", "onlineUsers": "オンラインユーザー",
"padding_scheme": "パディングスキーム", "padding_scheme": "パディングスキーム",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "주소", "address": "주소",
"address_placeholder": "서버 주소", "address_placeholder": "서버 주소",
"apiHost": "API 호스트",
"apiHostPlaceholder": "http(s)://example.com",
"bandwidth_placeholder": "대역폭을 입력하세요. BBR을 사용하려면 비워 두세요.", "bandwidth_placeholder": "대역폭을 입력하세요. BBR을 사용하려면 비워 두세요.",
"basic": "기본 설정", "basic": "기본 설정",
"cancel": "취소", "cancel": "취소",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "이 작업은 실행 취소할 수 없습니다.", "confirmDeleteDesc": "이 작업은 실행 취소할 수 없습니다.",
"confirmDeleteTitle": "이 서버를 삭제하시겠습니까?", "confirmDeleteTitle": "이 서버를 삭제하시겠습니까?",
"congestion_controller": "혼잡 제어기", "congestion_controller": "혼잡 제어기",
"connect": "연결",
"copied": "복사됨", "copied": "복사됨",
"copy": "복사", "copy": "복사",
"country": "국가", "country": "국가",
@@ -47,11 +50,14 @@
"expired": "만료됨", "expired": "만료됨",
"extra": "추가 구성", "extra": "추가 구성",
"flow": "흐름", "flow": "흐름",
"generate_quantum_resistant_key": "양자 저항 키 생성",
"generate_standard_encryption_key": "표준 암호화 키 생성",
"hop_interval": "홉 간격", "hop_interval": "홉 간격",
"hop_ports": "홉 포트", "hop_ports": "홉 포트",
"hop_ports_placeholder": "예: 1-65535", "hop_ports_placeholder": "예: 1-65535",
"host": "호스트", "host": "호스트",
"id": "ID", "id": "ID",
"installCommand": "설치 명령",
"ipAddresses": "IP 주소", "ipAddresses": "IP 주소",
"memory": "메모리", "memory": "메모리",
"migrate": "데이터 마이그레이션", "migrate": "데이터 마이그레이션",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "난독화 비밀번호를 입력하세요", "obfs_password_placeholder": "난독화 비밀번호를 입력하세요",
"obfs_path": "난독화 경로", "obfs_path": "난독화 경로",
"offline": "오프라인", "offline": "오프라인",
"oneClickInstall": "원클릭 설치",
"online": "온라인", "online": "온라인",
"onlineUsers": "온라인 사용자", "onlineUsers": "온라인 사용자",
"padding_scheme": "패딩 규칙", "padding_scheme": "패딩 규칙",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Adresse", "address": "Adresse",
"address_placeholder": "Serveradresse", "address_placeholder": "Serveradresse",
"apiHost": "API-vert",
"apiHostPlaceholder": "http(s)://eksempel.com",
"bandwidth_placeholder": "Skriv inn båndbredde, la stå tomt for BBR", "bandwidth_placeholder": "Skriv inn båndbredde, la stå tomt for BBR",
"basic": "Grunnleggende Konfigurasjon", "basic": "Grunnleggende Konfigurasjon",
"cancel": "Avbryt", "cancel": "Avbryt",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Denne handlingen kan ikke angres.", "confirmDeleteDesc": "Denne handlingen kan ikke angres.",
"confirmDeleteTitle": "Slette denne serveren?", "confirmDeleteTitle": "Slette denne serveren?",
"congestion_controller": "Kongestjonskontroller", "congestion_controller": "Kongestjonskontroller",
"connect": "Koble til",
"copied": "Kopiert", "copied": "Kopiert",
"copy": "Kopier", "copy": "Kopier",
"country": "Land", "country": "Land",
@@ -47,11 +50,14 @@
"expired": "Utløpt", "expired": "Utløpt",
"extra": "Ekstra konfigurasjon", "extra": "Ekstra konfigurasjon",
"flow": "Flyt", "flow": "Flyt",
"generate_quantum_resistant_key": "Generer kvantumresistent nøkkel",
"generate_standard_encryption_key": "Generer standard krypteringsnøkkel",
"hop_interval": "Hoppintervall", "hop_interval": "Hoppintervall",
"hop_ports": "Hoppporter", "hop_ports": "Hoppporter",
"hop_ports_placeholder": "f.eks. 1-65535", "hop_ports_placeholder": "f.eks. 1-65535",
"host": "Vert", "host": "Vert",
"id": "ID", "id": "ID",
"installCommand": "Installasjonskommando",
"ipAddresses": "IP-adresser", "ipAddresses": "IP-adresser",
"memory": "Minne", "memory": "Minne",
"migrate": "Migrer data", "migrate": "Migrer data",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Skriv inn obfuskasjonspassord", "obfs_password_placeholder": "Skriv inn obfuskasjonspassord",
"obfs_path": "Obfs Sti", "obfs_path": "Obfs Sti",
"offline": "Frakoblet", "offline": "Frakoblet",
"oneClickInstall": "Én-klikk installasjon",
"online": "På nett", "online": "På nett",
"onlineUsers": "Brukere på nett", "onlineUsers": "Brukere på nett",
"padding_scheme": "Polstring Skjema", "padding_scheme": "Polstring Skjema",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Adres", "address": "Adres",
"address_placeholder": "Adres serwera", "address_placeholder": "Adres serwera",
"apiHost": "Host API",
"apiHostPlaceholder": "http(s)://przyklad.com",
"bandwidth_placeholder": "Wprowadź przepustowość, pozostaw puste dla BBR", "bandwidth_placeholder": "Wprowadź przepustowość, pozostaw puste dla BBR",
"basic": "Podstawowa konfiguracja", "basic": "Podstawowa konfiguracja",
"cancel": "Anuluj", "cancel": "Anuluj",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Ta akcja nie może być cofnięta.", "confirmDeleteDesc": "Ta akcja nie może być cofnięta.",
"confirmDeleteTitle": "Usunąć ten serwer?", "confirmDeleteTitle": "Usunąć ten serwer?",
"congestion_controller": "Kontroler przeciążenia", "congestion_controller": "Kontroler przeciążenia",
"connect": "Połącz",
"copied": "Skopiowano", "copied": "Skopiowano",
"copy": "Kopiuj", "copy": "Kopiuj",
"country": "Kraj", "country": "Kraj",
@@ -47,11 +50,14 @@
"expired": "Wygasł", "expired": "Wygasł",
"extra": "Dodatkowa konfiguracja", "extra": "Dodatkowa konfiguracja",
"flow": "Przepływ", "flow": "Przepływ",
"generate_quantum_resistant_key": "Generuj klucz odporny na kwanty",
"generate_standard_encryption_key": "Generuj standardowy klucz szyfrowania",
"hop_interval": "Interwał skoku", "hop_interval": "Interwał skoku",
"hop_ports": "Porty skoku", "hop_ports": "Porty skoku",
"hop_ports_placeholder": "np. 1-65535", "hop_ports_placeholder": "np. 1-65535",
"host": "Host", "host": "Host",
"id": "ID", "id": "ID",
"installCommand": "Polecenie instalacji",
"ipAddresses": "Adresy IP", "ipAddresses": "Adresy IP",
"memory": "Pamięć", "memory": "Pamięć",
"migrate": "Migracja danych", "migrate": "Migracja danych",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Wprowadź hasło obfuskacji", "obfs_password_placeholder": "Wprowadź hasło obfuskacji",
"obfs_path": "Ścieżka obfuskacji", "obfs_path": "Ścieżka obfuskacji",
"offline": "Offline", "offline": "Offline",
"oneClickInstall": "Instalacja jednym kliknięciem",
"online": "Online", "online": "Online",
"onlineUsers": "Użytkownicy online", "onlineUsers": "Użytkownicy online",
"padding_scheme": "Schemat wypełnienia", "padding_scheme": "Schemat wypełnienia",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Endereço", "address": "Endereço",
"address_placeholder": "Endereço do servidor", "address_placeholder": "Endereço do servidor",
"apiHost": "Host da API",
"apiHostPlaceholder": "http(s)://exemplo.com",
"bandwidth_placeholder": "Insira a largura de banda, deixe em branco para BBR", "bandwidth_placeholder": "Insira a largura de banda, deixe em branco para BBR",
"basic": "Configuração Básica", "basic": "Configuração Básica",
"cancel": "Cancelar", "cancel": "Cancelar",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Esta ação não pode ser desfeita.", "confirmDeleteDesc": "Esta ação não pode ser desfeita.",
"confirmDeleteTitle": "Excluir este servidor?", "confirmDeleteTitle": "Excluir este servidor?",
"congestion_controller": "Controlador de congestionamento", "congestion_controller": "Controlador de congestionamento",
"connect": "Conectar",
"copied": "Copiado", "copied": "Copiado",
"copy": "Copiar", "copy": "Copiar",
"country": "País", "country": "País",
@@ -47,11 +50,14 @@
"expired": "Expirado", "expired": "Expirado",
"extra": "Configuração Extra", "extra": "Configuração Extra",
"flow": "Fluxo", "flow": "Fluxo",
"generate_quantum_resistant_key": "Gerar chave resistente a quânticos",
"generate_standard_encryption_key": "Gerar chave de criptografia padrão",
"hop_interval": "Intervalo de salto", "hop_interval": "Intervalo de salto",
"hop_ports": "Portas de salto", "hop_ports": "Portas de salto",
"hop_ports_placeholder": "ex. 1-65535", "hop_ports_placeholder": "ex. 1-65535",
"host": "Host", "host": "Host",
"id": "ID", "id": "ID",
"installCommand": "Comando de instalação",
"ipAddresses": "Endereços IP", "ipAddresses": "Endereços IP",
"memory": "Memória", "memory": "Memória",
"migrate": "Migrar Dados", "migrate": "Migrar Dados",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Insira a senha de ofuscação", "obfs_password_placeholder": "Insira a senha de ofuscação",
"obfs_path": "Caminho de Ofuscação", "obfs_path": "Caminho de Ofuscação",
"offline": "Offline", "offline": "Offline",
"oneClickInstall": "Instalação com um clique",
"online": "Online", "online": "Online",
"onlineUsers": "Usuários online", "onlineUsers": "Usuários online",
"padding_scheme": "Esquema de Preenchimento", "padding_scheme": "Esquema de Preenchimento",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Adresă", "address": "Adresă",
"address_placeholder": "Adresă server", "address_placeholder": "Adresă server",
"apiHost": "Gazda API",
"apiHostPlaceholder": "http(s)://exemplu.com",
"bandwidth_placeholder": "Introduceți lățimea de bandă, lăsați liber pentru BBR", "bandwidth_placeholder": "Introduceți lățimea de bandă, lăsați liber pentru BBR",
"basic": "Configurare de bază", "basic": "Configurare de bază",
"cancel": "Anulează", "cancel": "Anulează",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Această acțiune nu poate fi anulată.", "confirmDeleteDesc": "Această acțiune nu poate fi anulată.",
"confirmDeleteTitle": "Șterge acest server?", "confirmDeleteTitle": "Șterge acest server?",
"congestion_controller": "Controler de congestie", "congestion_controller": "Controler de congestie",
"connect": "Conectare",
"copied": "Copiat", "copied": "Copiat",
"copy": "Copiază", "copy": "Copiază",
"country": "Țară", "country": "Țară",
@@ -47,11 +50,14 @@
"expired": "Expirat", "expired": "Expirat",
"extra": "Configurație suplimentară", "extra": "Configurație suplimentară",
"flow": "Flux", "flow": "Flux",
"generate_quantum_resistant_key": "Generează cheie rezistentă la cuantică",
"generate_standard_encryption_key": "Generează cheie de criptare standard",
"hop_interval": "Interval de hop", "hop_interval": "Interval de hop",
"hop_ports": "Porturi hop", "hop_ports": "Porturi hop",
"hop_ports_placeholder": "de ex. 1-65535", "hop_ports_placeholder": "de ex. 1-65535",
"host": "Gazdă", "host": "Gazdă",
"id": "ID", "id": "ID",
"installCommand": "Comandă de instalare",
"ipAddresses": "Adrese IP", "ipAddresses": "Adrese IP",
"memory": "Memorie", "memory": "Memorie",
"migrate": "Migrați datele", "migrate": "Migrați datele",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Introdu parola de obfuscare", "obfs_password_placeholder": "Introdu parola de obfuscare",
"obfs_path": "Cale Obfs", "obfs_path": "Cale Obfs",
"offline": "Offline", "offline": "Offline",
"oneClickInstall": "Instalare cu un singur clic",
"online": "Online", "online": "Online",
"onlineUsers": "Utilizatori online", "onlineUsers": "Utilizatori online",
"padding_scheme": "Schema de umplere", "padding_scheme": "Schema de umplere",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Адрес", "address": "Адрес",
"address_placeholder": "Адрес сервера", "address_placeholder": "Адрес сервера",
"apiHost": "API хост",
"apiHostPlaceholder": "http(s)://пример.ком",
"bandwidth_placeholder": "Введите пропускную способность, оставьте пустым для BBR", "bandwidth_placeholder": "Введите пропускную способность, оставьте пустым для BBR",
"basic": "Базовая конфигурация", "basic": "Базовая конфигурация",
"cancel": "Отмена", "cancel": "Отмена",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Это действие нельзя отменить.", "confirmDeleteDesc": "Это действие нельзя отменить.",
"confirmDeleteTitle": "Удалить этот сервер?", "confirmDeleteTitle": "Удалить этот сервер?",
"congestion_controller": "Контроллер перегрузки", "congestion_controller": "Контроллер перегрузки",
"connect": "Подключить",
"copied": "Скопировано", "copied": "Скопировано",
"copy": "Копировать", "copy": "Копировать",
"country": "Страна", "country": "Страна",
@@ -47,11 +50,14 @@
"expired": "Истекло", "expired": "Истекло",
"extra": "Дополнительная конфигурация", "extra": "Дополнительная конфигурация",
"flow": "Поток", "flow": "Поток",
"generate_quantum_resistant_key": "Генерировать квантово-устойчивый ключ",
"generate_standard_encryption_key": "Генерировать стандартный ключ шифрования",
"hop_interval": "Интервал перехода", "hop_interval": "Интервал перехода",
"hop_ports": "Порты перехода", "hop_ports": "Порты перехода",
"hop_ports_placeholder": "например, 1-65535", "hop_ports_placeholder": "например, 1-65535",
"host": "Хост", "host": "Хост",
"id": "ID", "id": "ID",
"installCommand": "Команда установки",
"ipAddresses": "IP-адреса", "ipAddresses": "IP-адреса",
"memory": "Память", "memory": "Память",
"migrate": "Перенести данные", "migrate": "Перенести данные",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Введите пароль обфускации", "obfs_password_placeholder": "Введите пароль обфускации",
"obfs_path": "Обфусцированный путь", "obfs_path": "Обфусцированный путь",
"offline": "Офлайн", "offline": "Офлайн",
"oneClickInstall": "Установка в один клик",
"online": "Онлайн", "online": "Онлайн",
"onlineUsers": "Онлайн пользователи", "onlineUsers": "Онлайн пользователи",
"padding_scheme": "Схема выравнивания", "padding_scheme": "Схема выравнивания",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "ที่อยู่", "address": "ที่อยู่",
"address_placeholder": "ที่อยู่เซิร์ฟเวอร์", "address_placeholder": "ที่อยู่เซิร์ฟเวอร์",
"apiHost": "โฮสต์ API",
"apiHostPlaceholder": "http(s)://example.com",
"bandwidth_placeholder": "กรุณากรอกแบนด์วิธ ทิ้งว่างไว้สำหรับ BBR", "bandwidth_placeholder": "กรุณากรอกแบนด์วิธ ทิ้งว่างไว้สำหรับ BBR",
"basic": "การตั้งค่าพื้นฐาน", "basic": "การตั้งค่าพื้นฐาน",
"cancel": "ยกเลิก", "cancel": "ยกเลิก",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "การกระทำนี้ไม่สามารถย้อนกลับได้", "confirmDeleteDesc": "การกระทำนี้ไม่สามารถย้อนกลับได้",
"confirmDeleteTitle": "ลบเซิร์ฟเวอร์นี้หรือไม่?", "confirmDeleteTitle": "ลบเซิร์ฟเวอร์นี้หรือไม่?",
"congestion_controller": "ตัวควบคุมความแออัด", "congestion_controller": "ตัวควบคุมความแออัด",
"connect": "เชื่อมต่อ",
"copied": "คัดลอกแล้ว", "copied": "คัดลอกแล้ว",
"copy": "คัดลอก", "copy": "คัดลอก",
"country": "ประเทศ", "country": "ประเทศ",
@@ -47,11 +50,14 @@
"expired": "หมดอายุ", "expired": "หมดอายุ",
"extra": "การกำหนดค่าพิเศษ", "extra": "การกำหนดค่าพิเศษ",
"flow": "การไหล", "flow": "การไหล",
"generate_quantum_resistant_key": "สร้างคีย์ต้านทานควอนตัม",
"generate_standard_encryption_key": "สร้างคีย์เข้ารหัสมาตรฐาน",
"hop_interval": "ช่วงเวลาการกระโดด", "hop_interval": "ช่วงเวลาการกระโดด",
"hop_ports": "พอร์ตการกระโดด", "hop_ports": "พอร์ตการกระโดด",
"hop_ports_placeholder": "เช่น 1-65535", "hop_ports_placeholder": "เช่น 1-65535",
"host": "โฮสต์", "host": "โฮสต์",
"id": "ID", "id": "ID",
"installCommand": "คำสั่งติดตั้ง",
"ipAddresses": "ที่อยู่ IP", "ipAddresses": "ที่อยู่ IP",
"memory": "หน่วยความจำ", "memory": "หน่วยความจำ",
"migrate": "ย้ายข้อมูล", "migrate": "ย้ายข้อมูล",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "กรอกรหัสผ่านการปกปิด", "obfs_password_placeholder": "กรอกรหัสผ่านการปกปิด",
"obfs_path": "เส้นทางการทำให้ไม่สามารถอ่านได้", "obfs_path": "เส้นทางการทำให้ไม่สามารถอ่านได้",
"offline": "ออฟไลน์", "offline": "ออฟไลน์",
"oneClickInstall": "ติดตั้งด้วยคลิกเดียว",
"online": "ออนไลน์", "online": "ออนไลน์",
"onlineUsers": "ผู้ใช้งานออนไลน์", "onlineUsers": "ผู้ใช้งานออนไลน์",
"padding_scheme": "รูปแบบการเติม", "padding_scheme": "รูปแบบการเติม",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Adres", "address": "Adres",
"address_placeholder": "Sunucu adresi", "address_placeholder": "Sunucu adresi",
"apiHost": "API Sunucusu",
"apiHostPlaceholder": "http(s)://ornek.com",
"bandwidth_placeholder": "Bant genişliğini girin, BBR için boş bırakın", "bandwidth_placeholder": "Bant genişliğini girin, BBR için boş bırakın",
"basic": "Temel Yapılandırma", "basic": "Temel Yapılandırma",
"cancel": "İptal", "cancel": "İptal",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Bu işlem geri alınamaz.", "confirmDeleteDesc": "Bu işlem geri alınamaz.",
"confirmDeleteTitle": "Bu sunucuyu silmek istiyor musunuz?", "confirmDeleteTitle": "Bu sunucuyu silmek istiyor musunuz?",
"congestion_controller": "Tıkanıklık kontrolörü", "congestion_controller": "Tıkanıklık kontrolörü",
"connect": "Bağlan",
"copied": "Kopyalandı", "copied": "Kopyalandı",
"copy": "Kopyala", "copy": "Kopyala",
"country": "Ülke", "country": "Ülke",
@@ -47,11 +50,14 @@
"expired": "Süresi dolmuş", "expired": "Süresi dolmuş",
"extra": "Ek Yapılandırma", "extra": "Ek Yapılandırma",
"flow": "Akış", "flow": "Akış",
"generate_quantum_resistant_key": "Kuantuma Dayanıklı Anahtar Oluştur",
"generate_standard_encryption_key": "Standart Şifreleme Anahtarı Oluştur",
"hop_interval": "Atlama aralığı", "hop_interval": "Atlama aralığı",
"hop_ports": "Atlama portları", "hop_ports": "Atlama portları",
"hop_ports_placeholder": "örn. 1-65535", "hop_ports_placeholder": "örn. 1-65535",
"host": "Ana bilgisayar", "host": "Ana bilgisayar",
"id": "ID", "id": "ID",
"installCommand": "Kurulum komutu",
"ipAddresses": "IP adresleri", "ipAddresses": "IP adresleri",
"memory": "Bellek", "memory": "Bellek",
"migrate": "Veri Taşı", "migrate": "Veri Taşı",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Gizleme şifresini girin", "obfs_password_placeholder": "Gizleme şifresini girin",
"obfs_path": "Obfs Yolu", "obfs_path": "Obfs Yolu",
"offline": "Çevrimdışı", "offline": "Çevrimdışı",
"oneClickInstall": "Tek Tıkla Kurulum",
"online": "Çevrimiçi", "online": "Çevrimiçi",
"onlineUsers": "Çevrimiçi kullanıcılar", "onlineUsers": "Çevrimiçi kullanıcılar",
"padding_scheme": "Dolgu Şeması", "padding_scheme": "Dolgu Şeması",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Адреса", "address": "Адреса",
"address_placeholder": "Адреса сервера", "address_placeholder": "Адреса сервера",
"apiHost": "API хост",
"apiHostPlaceholder": "http(s)://example.com",
"bandwidth_placeholder": "Введіть пропускну здатність, залиште порожнім для BBR", "bandwidth_placeholder": "Введіть пропускну здатність, залиште порожнім для BBR",
"basic": "Базова конфігурація", "basic": "Базова конфігурація",
"cancel": "Скасувати", "cancel": "Скасувати",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Цю дію не можна скасувати.", "confirmDeleteDesc": "Цю дію не можна скасувати.",
"confirmDeleteTitle": "Видалити цей сервер?", "confirmDeleteTitle": "Видалити цей сервер?",
"congestion_controller": "Контролер перевантаження", "congestion_controller": "Контролер перевантаження",
"connect": "Підключити",
"copied": "Скопійовано", "copied": "Скопійовано",
"copy": "Копіювати", "copy": "Копіювати",
"country": "Країна", "country": "Країна",
@@ -47,11 +50,14 @@
"expired": "Термін дії закінчився", "expired": "Термін дії закінчився",
"extra": "Додаткова конфігурація", "extra": "Додаткова конфігурація",
"flow": "Потік", "flow": "Потік",
"generate_quantum_resistant_key": "Згенерувати квантово-стійкий ключ",
"generate_standard_encryption_key": "Згенерувати стандартний ключ шифрування",
"hop_interval": "Інтервал стрибка", "hop_interval": "Інтервал стрибка",
"hop_ports": "Порти стрибка", "hop_ports": "Порти стрибка",
"hop_ports_placeholder": "наприклад, 1-65535", "hop_ports_placeholder": "наприклад, 1-65535",
"host": "Хост", "host": "Хост",
"id": "ID", "id": "ID",
"installCommand": "Команда встановлення",
"ipAddresses": "IP адреси", "ipAddresses": "IP адреси",
"memory": "Пам'ять", "memory": "Пам'ять",
"migrate": "Міграція даних", "migrate": "Міграція даних",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Введіть пароль обфускації", "obfs_password_placeholder": "Введіть пароль обфускації",
"obfs_path": "Обфускаційний шлях", "obfs_path": "Обфускаційний шлях",
"offline": "Офлайн", "offline": "Офлайн",
"oneClickInstall": "Встановлення в один клік",
"online": "Онлайн", "online": "Онлайн",
"onlineUsers": "Онлайн користувачі", "onlineUsers": "Онлайн користувачі",
"padding_scheme": "Схема заповнення", "padding_scheme": "Схема заповнення",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "Địa chỉ", "address": "Địa chỉ",
"address_placeholder": "Địa chỉ máy chủ", "address_placeholder": "Địa chỉ máy chủ",
"apiHost": "Máy chủ API",
"apiHostPlaceholder": "http(s)://example.com",
"bandwidth_placeholder": "Nhập băng thông, để trống cho BBR", "bandwidth_placeholder": "Nhập băng thông, để trống cho BBR",
"basic": "Cấu Hình Cơ Bản", "basic": "Cấu Hình Cơ Bản",
"cancel": "Hủy", "cancel": "Hủy",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "Hành động này không thể hoàn tác.", "confirmDeleteDesc": "Hành động này không thể hoàn tác.",
"confirmDeleteTitle": "Xóa máy chủ này?", "confirmDeleteTitle": "Xóa máy chủ này?",
"congestion_controller": "Bộ điều khiển tắc nghẽn", "congestion_controller": "Bộ điều khiển tắc nghẽn",
"connect": "Kết nối",
"copied": "Đã sao chép", "copied": "Đã sao chép",
"copy": "Sao chép", "copy": "Sao chép",
"country": "Quốc gia", "country": "Quốc gia",
@@ -47,11 +50,14 @@
"expired": "Đã hết hạn", "expired": "Đã hết hạn",
"extra": "Cấu hình thêm", "extra": "Cấu hình thêm",
"flow": "Lưu lượng", "flow": "Lưu lượng",
"generate_quantum_resistant_key": "Tạo khóa chống lượng tử",
"generate_standard_encryption_key": "Tạo khóa mã hóa tiêu chuẩn",
"hop_interval": "Khoảng thời gian nhảy", "hop_interval": "Khoảng thời gian nhảy",
"hop_ports": "Cổng nhảy", "hop_ports": "Cổng nhảy",
"hop_ports_placeholder": "vd. 1-65535", "hop_ports_placeholder": "vd. 1-65535",
"host": "Máy chủ", "host": "Máy chủ",
"id": "ID", "id": "ID",
"installCommand": "Lệnh cài đặt",
"ipAddresses": "Địa chỉ IP", "ipAddresses": "Địa chỉ IP",
"memory": "Bộ nhớ", "memory": "Bộ nhớ",
"migrate": "Di chuyển dữ liệu", "migrate": "Di chuyển dữ liệu",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "Nhập mật khẩu làm mờ", "obfs_password_placeholder": "Nhập mật khẩu làm mờ",
"obfs_path": "Đường dẫn Obfs", "obfs_path": "Đường dẫn Obfs",
"offline": "Ngoại tuyến", "offline": "Ngoại tuyến",
"oneClickInstall": "Cài đặt một lần nhấp",
"online": "Trực tuyến", "online": "Trực tuyến",
"onlineUsers": "Người dùng trực tuyến", "onlineUsers": "Người dùng trực tuyến",
"padding_scheme": "Sơ Đồ Đệm", "padding_scheme": "Sơ Đồ Đệm",
+10
View File
@@ -5,6 +5,8 @@
}, },
"address": "地址", "address": "地址",
"address_placeholder": "服务器地址", "address_placeholder": "服务器地址",
"apiHost": "API Host",
"apiHostPlaceholder": "http(s)://example.com",
"bandwidth_placeholder": "请输入带宽,留空则使用BBR", "bandwidth_placeholder": "请输入带宽,留空则使用BBR",
"basic": "基础配置", "basic": "基础配置",
"cancel": "取消", "cancel": "取消",
@@ -13,12 +15,16 @@
"cert_mode": "证书模式", "cert_mode": "证书模式",
"cipher": "加密算法", "cipher": "加密算法",
"city": "城市", "city": "城市",
"close": "关闭",
"confirm": "确认", "confirm": "确认",
"confirmDeleteDesc": "该操作不可撤销。", "confirmDeleteDesc": "该操作不可撤销。",
"confirmDeleteTitle": "确认删除该服务器?", "confirmDeleteTitle": "确认删除该服务器?",
"congestion_controller": "拥塞控制", "congestion_controller": "拥塞控制",
"connect": "对接",
"copied": "已复制", "copied": "已复制",
"copy": "复制", "copy": "复制",
"copyAndClose": "复制并关闭",
"copyFailed": "复制失败",
"country": "国家", "country": "国家",
"cpu": "CPU", "cpu": "CPU",
"create": "新建", "create": "新建",
@@ -47,11 +53,14 @@
"expired": "已过期", "expired": "已过期",
"extra": "额外配置", "extra": "额外配置",
"flow": "流控", "flow": "流控",
"generate_quantum_resistant_key": "生成抗量子密钥",
"generate_standard_encryption_key": "生成标准加密密钥",
"hop_interval": "跳跃端口间隔", "hop_interval": "跳跃端口间隔",
"hop_ports": "跳跃端口", "hop_ports": "跳跃端口",
"hop_ports_placeholder": "例如 1-65535", "hop_ports_placeholder": "例如 1-65535",
"host": "Host", "host": "Host",
"id": "编号", "id": "编号",
"installCommand": "一键安装命令",
"ipAddresses": "IP 地址", "ipAddresses": "IP 地址",
"memory": "内存", "memory": "内存",
"migrate": "迁移数据", "migrate": "迁移数据",
@@ -69,6 +78,7 @@
"obfs_password_placeholder": "输入混淆密码", "obfs_password_placeholder": "输入混淆密码",
"obfs_path": "混淆路径", "obfs_path": "混淆路径",
"offline": "离线", "offline": "离线",
"oneClickInstall": "一键接入",
"online": "在线", "online": "在线",
"onlineUsers": "在线人数", "onlineUsers": "在线人数",
"padding_scheme": "填充方案", "padding_scheme": "填充方案",
+7
View File
@@ -5,6 +5,8 @@
}, },
"address": "地址", "address": "地址",
"address_placeholder": "伺服器地址", "address_placeholder": "伺服器地址",
"apiHost": "API 主機",
"apiHostPlaceholder": "http(s)://example.com",
"bandwidth_placeholder": "輸入帶寬,留空以使用BBR", "bandwidth_placeholder": "輸入帶寬,留空以使用BBR",
"basic": "基本配置", "basic": "基本配置",
"cancel": "取消", "cancel": "取消",
@@ -17,6 +19,7 @@
"confirmDeleteDesc": "此操作無法撤銷。", "confirmDeleteDesc": "此操作無法撤銷。",
"confirmDeleteTitle": "刪除此伺服器?", "confirmDeleteTitle": "刪除此伺服器?",
"congestion_controller": "擁塞控制器", "congestion_controller": "擁塞控制器",
"connect": "連接",
"copied": "已複製", "copied": "已複製",
"copy": "複製", "copy": "複製",
"country": "國家", "country": "國家",
@@ -47,11 +50,14 @@
"expired": "已過期", "expired": "已過期",
"extra": "額外配置", "extra": "額外配置",
"flow": "流量", "flow": "流量",
"generate_quantum_resistant_key": "生成抗量子密鑰",
"generate_standard_encryption_key": "生成標準加密密鑰",
"hop_interval": "跳躍間隔", "hop_interval": "跳躍間隔",
"hop_ports": "跳躍端口", "hop_ports": "跳躍端口",
"hop_ports_placeholder": "例如 1-65535", "hop_ports_placeholder": "例如 1-65535",
"host": "主機", "host": "主機",
"id": "ID", "id": "ID",
"installCommand": "安裝命令",
"ipAddresses": "IP 地址", "ipAddresses": "IP 地址",
"memory": "內存", "memory": "內存",
"migrate": "遷移數據", "migrate": "遷移數據",
@@ -69,6 +75,7 @@
"obfs_password_placeholder": "輸入混淆密碼", "obfs_password_placeholder": "輸入混淆密碼",
"obfs_path": "混淆路徑", "obfs_path": "混淆路徑",
"offline": "離線", "offline": "離線",
"oneClickInstall": "一鍵安裝",
"online": "在線", "online": "在線",
"onlineUsers": "在線用戶", "onlineUsers": "在線用戶",
"padding_scheme": "填充方案", "padding_scheme": "填充方案",
+1
View File
@@ -11,6 +11,7 @@
}, },
"dependencies": { "dependencies": {
"@lottiefiles/dotlottie-react": "^0.15.1", "@lottiefiles/dotlottie-react": "^0.15.1",
"@noble/curves": "^2.0.1",
"@noble/ed25519": "^3.0.0", "@noble/ed25519": "^3.0.0",
"@tanstack/react-query": "^5.85.5", "@tanstack/react-query": "^5.85.5",
"@tanstack/react-query-next-experimental": "^5.85.5", "@tanstack/react-query-next-experimental": "^5.85.5",
+6
View File
@@ -16,6 +16,7 @@
"@iconify/react": "^5.2.0", "@iconify/react": "^5.2.0",
"@lottiefiles/dotlottie-react": "^0.15.1", "@lottiefiles/dotlottie-react": "^0.15.1",
"@monaco-editor/react": "^4.7.0", "@monaco-editor/react": "^4.7.0",
"@noble/curves": "^2.0.1",
"@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-aspect-ratio": "^1.1.7", "@radix-ui/react-aspect-ratio": "^1.1.7",
@@ -104,6 +105,7 @@
"name": "ppanel-admin-web", "name": "ppanel-admin-web",
"dependencies": { "dependencies": {
"@lottiefiles/dotlottie-react": "^0.15.1", "@lottiefiles/dotlottie-react": "^0.15.1",
"@noble/curves": "^2.0.1",
"@noble/ed25519": "^3.0.0", "@noble/ed25519": "^3.0.0",
"@tanstack/react-query": "^5.85.5", "@tanstack/react-query": "^5.85.5",
"@tanstack/react-query-next-experimental": "^5.85.5", "@tanstack/react-query-next-experimental": "^5.85.5",
@@ -548,8 +550,12 @@
"@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-pxK4VIjFRx1MY92UycLOOw7dTdvccWsNETQ0kDHkBlcFH1GrTLUjSiHU1ohrznnux6TqRHgv5oflhfIWZwVROQ=="], "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-pxK4VIjFRx1MY92UycLOOw7dTdvccWsNETQ0kDHkBlcFH1GrTLUjSiHU1ohrznnux6TqRHgv5oflhfIWZwVROQ=="],
"@noble/curves": ["@noble/curves@2.0.1", "", { "dependencies": { "@noble/hashes": "2.0.1" } }, "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw=="],
"@noble/ed25519": ["@noble/ed25519@3.0.0", "", {}, "sha512-QyteqMNm0GLqfa5SoYbSC3+Pvykwpn95Zgth4MFVSMKBB75ELl9tX1LAVsN4c3HXOrakHsF2gL4zWDAYCcsnzg=="], "@noble/ed25519": ["@noble/ed25519@3.0.0", "", {}, "sha512-QyteqMNm0GLqfa5SoYbSC3+Pvykwpn95Zgth4MFVSMKBB75ELl9tX1LAVsN4c3HXOrakHsF2gL4zWDAYCcsnzg=="],
"@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
+2 -2
View File
@@ -5,8 +5,8 @@ FROM oven/bun:latest AS base
WORKDIR /app WORKDIR /app
# Create a non-root user for running the production application # Create a non-root user for running the production application
RUN addgroup --system --gid 1001 nodejs \ RUN groupadd -r -g 1001 nodejs \
&& adduser --system --uid 1001 nextjs && useradd -r -u 1001 -g nodejs nextjs
# Change to non-root user # Change to non-root user
USER nextjs USER nextjs
+2 -2
View File
@@ -5,8 +5,8 @@ FROM oven/bun:latest AS base
WORKDIR /app WORKDIR /app
# Create non-root user and set permissions # Create non-root user and set permissions
RUN addgroup --system --gid 1001 nodejs \ RUN groupadd -r -g 1001 nodejs \
&& adduser --system --uid 1001 nextjs && useradd -r -u 1001 -g nodejs nextjs
# Copy build output and static files # Copy build output and static files
COPY ./apps/user/.next/standalone ./ COPY ./apps/user/.next/standalone ./
+6 -5
View File
@@ -1,14 +1,14 @@
{ {
"name": "ppanel-web", "name": "fastvpn-web",
"version": "1.5.4", "version": "1.6.0",
"private": true, "private": true,
"homepage": "https://github.com/perfect-panel/ppanel-web", "homepage": "https://github.com/perfect-panel/fastvpn-web",
"bugs": { "bugs": {
"url": "https://github.com/perfect-panel/ppanel-web/issues/new" "url": "https://github.com/perfect-panel/fastvpn-web/issues/new"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/perfect-panel/ppanel-web.git" "url": "https://github.com/perfect-panel/fastvpn-web.git"
}, },
"license": "GUN", "license": "GUN",
"workspaces": [ "workspaces": [
@@ -60,6 +60,7 @@
"@iconify/react": "^5.2.0", "@iconify/react": "^5.2.0",
"@lottiefiles/dotlottie-react": "^0.15.1", "@lottiefiles/dotlottie-react": "^0.15.1",
"@monaco-editor/react": "^4.7.0", "@monaco-editor/react": "^4.7.0",
"@noble/curves": "^2.0.1",
"@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-aspect-ratio": "^1.1.7", "@radix-ui/react-aspect-ratio": "^1.1.7",
+1
View File
@@ -11,6 +11,7 @@
"moduleDetection": "force", "moduleDetection": "force",
"moduleResolution": "NodeNext", "moduleResolution": "NodeNext",
"noUncheckedIndexedAccess": true, "noUncheckedIndexedAccess": true,
"typeRoots": ["./node_modules/@types"],
"resolveJsonModule": true, "resolveJsonModule": true,
"skipLibCheck": true, "skipLibCheck": true,
"strict": true, "strict": true,