mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-08 11:02:08 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18a0a15e16 | ||
|
|
c8fd62f388 | ||
|
|
97f03de295 | ||
|
|
2c0a5666fc | ||
|
|
5c3f0d5b60 | ||
|
|
746763ed34 | ||
|
|
e3800a575f | ||
|
|
c78c936762 | ||
|
|
ea5d6f9c46 | ||
|
|
97f8022276 | ||
|
|
d718bd9141 | ||
|
|
8ddd48eda1 | ||
|
|
3e20404959 | ||
|
|
dde7ead751 | ||
|
|
be719680b0 | ||
|
|
d6f5a79ac9 | ||
|
|
26dd097962 | ||
|
|
eb1a1b3786 |
@@ -57,6 +57,6 @@ body:
|
|||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: 日志 / Log
|
label: 日志 / Log
|
||||||
description: 请提供完整或相关部分的Debug日志(请在“软件左侧菜单”->“设置”->“日志等级”调整到debug,Verge错误请把“杂项设置”->“app日志等级”调整到trace,并重启Verge生效。日志文件在“软件左侧菜单”->“设置”->“日志目录”下) / Please provide a complete or relevant part of the Debug log (please adjust the "Log level" to debug in "Software left menu" -> "Settings" -> "Log level". If there is a Verge error, please adjust "Miscellaneous settings" -> "app log level" to trace, and restart Verge to take effect. The log file is under "Software left menu" -> "Settings" -> "Log directory")
|
description: 请提供完整或相关部分的Debug日志(请在“软件左侧菜单”->“设置”->“日志等级”调整到debug,Verge错误请把“杂项设置”->“app日志等级”调整到debug/trace,并重启Verge生效。日志文件在“软件左侧菜单”->“设置”->“日志目录”下) / Please provide a complete or relevant part of the Debug log (please adjust the "Log level" to debug in "Software left menu" -> "Settings" -> "Log level". If there is a Verge error, please adjust "Miscellaneous settings" -> "app log level" to trace, and restart Verge to take effect. The log file is under "Software left menu" -> "Settings" -> "Log directory")
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ jobs:
|
|||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: "20"
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
@@ -141,7 +141,7 @@ jobs:
|
|||||||
pnpm i
|
pnpm i
|
||||||
pnpm check ${{ matrix.target }}
|
pnpm check ${{ matrix.target }}
|
||||||
|
|
||||||
- name: 'Setup for linux'
|
- name: "Setup for linux"
|
||||||
run: |-
|
run: |-
|
||||||
sudo ls -lR /etc/apt/
|
sudo ls -lR /etc/apt/
|
||||||
|
|
||||||
@@ -170,14 +170,14 @@ jobs:
|
|||||||
patchelf:${{ matrix.arch }} \
|
patchelf:${{ matrix.arch }} \
|
||||||
librsvg2-dev:${{ matrix.arch }}
|
librsvg2-dev:${{ matrix.arch }}
|
||||||
|
|
||||||
- name: 'Install aarch64 tools'
|
- name: "Install aarch64 tools"
|
||||||
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
||||||
run: |
|
run: |
|
||||||
sudo apt install -y \
|
sudo apt install -y \
|
||||||
gcc-aarch64-linux-gnu \
|
gcc-aarch64-linux-gnu \
|
||||||
g++-aarch64-linux-gnu
|
g++-aarch64-linux-gnu
|
||||||
|
|
||||||
- name: 'Install armv7 tools'
|
- name: "Install armv7 tools"
|
||||||
if: matrix.target == 'armv7-unknown-linux-gnueabihf'
|
if: matrix.target == 'armv7-unknown-linux-gnueabihf'
|
||||||
run: |
|
run: |
|
||||||
sudo apt install -y \
|
sudo apt install -y \
|
||||||
@@ -196,7 +196,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
pnpm build --target ${{ matrix.target }}
|
pnpm build --target ${{ matrix.target }}
|
||||||
env:
|
env:
|
||||||
NODE_OPTIONS: '--max_old_space_size=4096'
|
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ jobs:
|
|||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
name: Install pnpm
|
name: Install pnpm
|
||||||
@@ -67,8 +67,8 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||||
@@ -119,7 +119,7 @@ jobs:
|
|||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: "22"
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
@@ -131,7 +131,7 @@ jobs:
|
|||||||
pnpm i
|
pnpm i
|
||||||
pnpm check ${{ matrix.target }}
|
pnpm check ${{ matrix.target }}
|
||||||
|
|
||||||
- name: 'Setup for linux'
|
- name: "Setup for linux"
|
||||||
run: |-
|
run: |-
|
||||||
sudo ls -lR /etc/apt/
|
sudo ls -lR /etc/apt/
|
||||||
|
|
||||||
@@ -160,14 +160,14 @@ jobs:
|
|||||||
patchelf:${{ matrix.arch }} \
|
patchelf:${{ matrix.arch }} \
|
||||||
librsvg2-dev:${{ matrix.arch }}
|
librsvg2-dev:${{ matrix.arch }}
|
||||||
|
|
||||||
- name: 'Install aarch64 tools'
|
- name: "Install aarch64 tools"
|
||||||
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
||||||
run: |
|
run: |
|
||||||
sudo apt install -y \
|
sudo apt install -y \
|
||||||
gcc-aarch64-linux-gnu \
|
gcc-aarch64-linux-gnu \
|
||||||
g++-aarch64-linux-gnu
|
g++-aarch64-linux-gnu
|
||||||
|
|
||||||
- name: 'Install armv7 tools'
|
- name: "Install armv7 tools"
|
||||||
if: matrix.target == 'armv7-unknown-linux-gnueabihf'
|
if: matrix.target == 'armv7-unknown-linux-gnueabihf'
|
||||||
run: |
|
run: |
|
||||||
sudo apt install -y \
|
sudo apt install -y \
|
||||||
@@ -186,7 +186,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
pnpm build --target ${{ matrix.target }}
|
pnpm build --target ${{ matrix.target }}
|
||||||
env:
|
env:
|
||||||
NODE_OPTIONS: '--max_old_space_size=4096'
|
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
|
|
||||||
@@ -195,6 +195,7 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install jq
|
sudo apt-get install jq
|
||||||
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
||||||
|
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Upload Release
|
- name: Upload Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
@@ -237,7 +238,7 @@ jobs:
|
|||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
name: Install pnpm
|
name: Install pnpm
|
||||||
@@ -262,8 +263,8 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
with:
|
with:
|
||||||
tauriScript: pnpm
|
tauriScript: pnpm
|
||||||
args: --target ${{ matrix.target }}
|
args: --target ${{ matrix.target }}
|
||||||
@@ -298,7 +299,7 @@ jobs:
|
|||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
name: Install pnpm
|
name: Install pnpm
|
||||||
@@ -323,7 +324,7 @@ jobs:
|
|||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
name: Install pnpm
|
name: Install pnpm
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
name: Install pnpm
|
name: Install pnpm
|
||||||
@@ -36,7 +36,7 @@ jobs:
|
|||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "22"
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
name: Install pnpm
|
name: Install pnpm
|
||||||
|
|||||||
+20
-6
@@ -1,16 +1,30 @@
|
|||||||
## v2.0.0
|
## v2.0.1
|
||||||
|
|
||||||
### Notice
|
### Notice
|
||||||
|
|
||||||
|
- 强烈建议完全删除 1.x 老版本再安装此版本!
|
||||||
- 历时3个月的紧密开发与严格测试稳定版2.0.0终于发布了:巨量改进与性能、稳定性提升,目前Clash Verge Rev已经有了比肩cfw的健壮性;而且更强大易用!
|
- 历时3个月的紧密开发与严格测试稳定版2.0.0终于发布了:巨量改进与性能、稳定性提升,目前Clash Verge Rev已经有了比肩cfw的健壮性;而且更强大易用!
|
||||||
- 由于更改了服务安装逻辑,Mac/Linux 首次安装需要输入 2 遍系统密码卸载和安装服务,以后可以丝滑使用 tun(虚拟网卡)模式
|
- 由于更改了服务安装逻辑,Mac/Linux 首次安装需要输入系统密码卸载和安装服务,以后可以丝滑使用 tun(虚拟网卡)模式
|
||||||
- 因 Tauri 2.0 底层 bug,关闭窗口暂时修改为最小化功能
|
- 因 Tauri 2.0 底层 bug,关闭窗口后保留webview进程,优点是再次打开面板更快,缺点是内存使用略有增加
|
||||||
|
|
||||||
|
### 2.0.1相对于2.0.0改进了:
|
||||||
|
|
||||||
|
- 无法从 2.0rc和2.0.0 升级的问题(已经安装了2.0版本的需手动下载安装)
|
||||||
|
- MacOS 系统下少有的无法安装服务,无法启动的问题,目前更健壮了
|
||||||
|
- 当系统中没有 yaml 编辑器的情况下,打开文件程序崩溃的问题
|
||||||
|
- Windows 应用内升级和覆盖安装不会删除老执行文件的问题
|
||||||
|
- 修改优化了 mac 下 fakeip 段和 dns
|
||||||
|
- 测试菜单 svg 图标格式检查
|
||||||
|
- 应用内升级重复安装 vs runtime 的问题
|
||||||
|
- 修复外部控制下密码有特殊字符认证出错的问题
|
||||||
|
- 修复恢复 Webdav 备份设置后, Webdav 设置丢失的问题
|
||||||
|
- 代理页面增加快速回到顶部的按钮
|
||||||
|
|
||||||
### Breaking changes
|
### Breaking changes
|
||||||
|
|
||||||
- 重大框架升级:使用 Tauri 2.0(巨量改进与性能提升)
|
- 重大框架升级:使用 Tauri 2.0(巨量改进与性能提升)
|
||||||
- 强烈建议完全删除 1.x 老版本再安装此版本
|
|
||||||
- 出现 bug 到 issues 中提出;以后不再接受1.x版本的bug反馈。
|
- 出现 bug 到 issues 中提出;以后不再接受1.x版本的bug反馈。
|
||||||
|
- 强烈建议完全删除 1.x 老版本再安装此版本
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
@@ -30,7 +44,7 @@
|
|||||||
- 添加统一延迟的设置开关
|
- 添加统一延迟的设置开关
|
||||||
- 添加 Windows 下自动检测并下载 vc runtime 的功能
|
- 添加 Windows 下自动检测并下载 vc runtime 的功能
|
||||||
- 支持显示 mux 和 mptcp 的节点标识
|
- 支持显示 mux 和 mptcp 的节点标识
|
||||||
- 延迟测试连接更换 https 的 cp.cloudflare.com/generate_204 以防止机场劫持(关闭统一延迟的情况下延迟测试结果会有所增加)。
|
- 延迟测试连接更换 http 的 cp.cloudflare.com/generate_204 (关闭统一延迟的情况下延迟测试结果会有所增加)
|
||||||
- 重构日志记录逻辑,可以收集和筛选所有日志类型了(之前无法记录debug的日志类型)
|
- 重构日志记录逻辑,可以收集和筛选所有日志类型了(之前无法记录debug的日志类型)
|
||||||
|
|
||||||
### Performance
|
### Performance
|
||||||
@@ -58,7 +72,7 @@
|
|||||||
- 修复快捷键设置的相关 bug
|
- 修复快捷键设置的相关 bug
|
||||||
- 修复 Win 下点左键菜单闪现的问题(Mac 下的操作逻辑相反,默认情况下不管点左/右键均会打开菜单,闪现不属于 bug)
|
- 修复 Win 下点左键菜单闪现的问题(Mac 下的操作逻辑相反,默认情况下不管点左/右键均会打开菜单,闪现不属于 bug)
|
||||||
|
|
||||||
### Know issues
|
### Known issues
|
||||||
|
|
||||||
- Windows 下窗口大小无法记忆(等待上游修复)
|
- Windows 下窗口大小无法记忆(等待上游修复)
|
||||||
- Webdav 备份因为安全性和兼容性问题,暂不支持同步 Webdav 服务器地址和登录信息;跨平台配置同步
|
- Webdav 备份因为安全性和兼容性问题,暂不支持同步 Webdav 服务器地址和登录信息;跨平台配置同步
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "clash-verge",
|
"name": "clash-verge",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "cross-env RUST_BACKTRACE=1 tauri dev",
|
"dev": "cross-env RUST_BACKTRACE=1 tauri dev",
|
||||||
|
|||||||
+3
-3
@@ -153,13 +153,13 @@ async function getLatestReleaseVersion() {
|
|||||||
*/
|
*/
|
||||||
if (!META_MAP[`${platform}-${arch}`]) {
|
if (!META_MAP[`${platform}-${arch}`]) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`clash meta alpha unsupported platform "${platform}-${arch}"`
|
`clash meta alpha unsupported platform "${platform}-${arch}"`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!META_ALPHA_MAP[`${platform}-${arch}`]) {
|
if (!META_ALPHA_MAP[`${platform}-${arch}`]) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`clash meta alpha unsupported platform "${platform}-${arch}"`
|
`clash meta alpha unsupported platform "${platform}-${arch}"`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +354,7 @@ const resolvePlugin = async () => {
|
|||||||
const tempDir = path.join(TEMP_DIR, "SimpleSC");
|
const tempDir = path.join(TEMP_DIR, "SimpleSC");
|
||||||
const tempZip = path.join(
|
const tempZip = path.join(
|
||||||
tempDir,
|
tempDir,
|
||||||
"NSIS_Simple_Service_Plugin_Unicode_1.30.zip"
|
"NSIS_Simple_Service_Plugin_Unicode_1.30.zip",
|
||||||
);
|
);
|
||||||
const tempDll = path.join(tempDir, "SimpleSC.dll");
|
const tempDll = path.join(tempDir, "SimpleSC.dll");
|
||||||
const pluginDir = path.join(process.env.APPDATA, "Local/NSIS");
|
const pluginDir = path.join(process.env.APPDATA, "Local/NSIS");
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ async function resolvePortable() {
|
|||||||
zip.addLocalFolder(
|
zip.addLocalFolder(
|
||||||
path.join(
|
path.join(
|
||||||
releaseDir,
|
releaseDir,
|
||||||
`Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${arch}`
|
`Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${arch}`,
|
||||||
),
|
),
|
||||||
`Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${arch}`
|
`Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${arch}`,
|
||||||
);
|
);
|
||||||
zip.addLocalFolder(configDir, ".config");
|
zip.addLocalFolder(configDir, ".config");
|
||||||
|
|
||||||
|
|||||||
Generated
+1
-1
@@ -988,7 +988,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clash-verge"
|
name = "clash-verge"
|
||||||
version = "2.0.0"
|
version = "2.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "clash-verge"
|
name = "clash-verge"
|
||||||
version = "2.0.0"
|
version = "2.0.1"
|
||||||
description = "clash verge"
|
description = "clash verge"
|
||||||
authors = ["zzzgydi", "wonfen", "MystiPanda"]
|
authors = ["zzzgydi", "wonfen", "MystiPanda"]
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
|
|||||||
@@ -697,25 +697,62 @@ Var VC_REDIST_URL
|
|||||||
Var VC_REDIST_EXE
|
Var VC_REDIST_EXE
|
||||||
|
|
||||||
Section CheckAndInstallVSRuntime
|
Section CheckAndInstallVSRuntime
|
||||||
|
; 检查是否已安装 Visual C++ Redistributable
|
||||||
${If} ${IsNativeARM64}
|
${If} ${IsNativeARM64}
|
||||||
StrCpy $VC_REDIST_URL "https://aka.ms/vs/17/release/vc_redist.arm64.exe"
|
StrCpy $VC_REDIST_URL "https://aka.ms/vs/17/release/vc_redist.arm64.exe"
|
||||||
StrCpy $VC_REDIST_EXE "vc_redist.arm64.exe"
|
StrCpy $VC_REDIST_EXE "vc_redist.arm64.exe"
|
||||||
IfFileExists "$SYSDIR\msvcp140.dll" Done
|
|
||||||
|
; 检查关键DLL
|
||||||
|
IfFileExists "$SYSDIR\vcruntime140.dll" 0 checkInstall
|
||||||
|
IfFileExists "$SYSDIR\msvcp140.dll" Done checkInstall
|
||||||
|
|
||||||
${ElseIf} ${RunningX64}
|
${ElseIf} ${RunningX64}
|
||||||
StrCpy $VC_REDIST_URL "https://aka.ms/vs/17/release/vc_redist.x64.exe"
|
StrCpy $VC_REDIST_URL "https://aka.ms/vs/17/release/vc_redist.x64.exe"
|
||||||
StrCpy $VC_REDIST_EXE "vc_redist.x64.exe"
|
StrCpy $VC_REDIST_EXE "vc_redist.x64.exe"
|
||||||
IfFileExists "$WINDIR\SysWOW64\msvcp140.dll" Done
|
|
||||||
|
; 检查关键DLL
|
||||||
|
IfFileExists "$SYSDIR\vcruntime140.dll" 0 checkInstall
|
||||||
|
IfFileExists "$SYSDIR\msvcp140.dll" Done checkInstall
|
||||||
|
|
||||||
${Else}
|
${Else}
|
||||||
StrCpy $VC_REDIST_URL "https://aka.ms/vs/17/release/vc_redist.x86.exe"
|
StrCpy $VC_REDIST_URL "https://aka.ms/vs/17/release/vc_redist.x86.exe"
|
||||||
StrCpy $VC_REDIST_EXE "vc_redist.x86.exe"
|
StrCpy $VC_REDIST_EXE "vc_redist.x86.exe"
|
||||||
IfFileExists "$SYSDIR\msvcp140.dll" Done
|
|
||||||
|
; 检查关键DLL
|
||||||
|
IfFileExists "$SYSDIR\vcruntime140.dll" 0 checkInstall
|
||||||
|
IfFileExists "$SYSDIR\msvcp140.dll" Done checkInstall
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
; 下载并安装VC运行库
|
checkInstall:
|
||||||
|
; 检查注册表
|
||||||
|
${If} ${RunningX64}
|
||||||
|
SetRegView 64
|
||||||
|
ReadRegDword $R0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\${ARCH}" "Installed"
|
||||||
|
${If} $R0 == "1"
|
||||||
|
Goto Done
|
||||||
|
${EndIf}
|
||||||
|
${Else}
|
||||||
|
ReadRegDword $R0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x86" "Installed"
|
||||||
|
${If} $R0 == "1"
|
||||||
|
Goto Done
|
||||||
|
${EndIf}
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
; 如果没有安装,则下载并安装
|
||||||
|
DetailPrint "正在下载 Visual C++ Redistributable..."
|
||||||
nsisdl::download "$VC_REDIST_URL" "$TEMP\$VC_REDIST_EXE"
|
nsisdl::download "$VC_REDIST_URL" "$TEMP\$VC_REDIST_EXE"
|
||||||
Pop $0
|
Pop $0
|
||||||
${If} $0 == "success"
|
${If} $0 == "success"
|
||||||
nsExec::Exec '"$TEMP\$VC_REDIST_EXE" /quiet /norestart'
|
DetailPrint "正在安装 Visual C++ Redistributable..."
|
||||||
|
ExecWait '"$TEMP\$VC_REDIST_EXE" /quiet /norestart' $0
|
||||||
|
${If} $0 == 0
|
||||||
|
DetailPrint "Visual C++ Redistributable 安装成功"
|
||||||
|
${Else}
|
||||||
|
DetailPrint "Visual C++ Redistributable 安装失败"
|
||||||
|
${EndIf}
|
||||||
|
Delete "$TEMP\$VC_REDIST_EXE"
|
||||||
|
${Else}
|
||||||
|
DetailPrint "Visual C++ Redistributable 下载失败"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
Done:
|
Done:
|
||||||
@@ -728,6 +765,12 @@ Section Install
|
|||||||
nsExec::Exec 'netsh int tcp res'
|
nsExec::Exec 'netsh int tcp res'
|
||||||
!insertmacro CheckIfAppIsRunning
|
!insertmacro CheckIfAppIsRunning
|
||||||
!insertmacro CheckAllVergeProcesses
|
!insertmacro CheckAllVergeProcesses
|
||||||
|
|
||||||
|
; Delete old files before installation
|
||||||
|
; Delete clash-verge.desktop
|
||||||
|
IfFileExists "$INSTDIR\Clash Verge.exe" 0 +2
|
||||||
|
Delete "$INSTDIR\Clash Verge.exe"
|
||||||
|
|
||||||
; Copy main executable
|
; Copy main executable
|
||||||
File "${MAINBINARYSRCPATH}"
|
File "${MAINBINARYSRCPATH}"
|
||||||
|
|
||||||
@@ -862,6 +905,10 @@ Section Uninstall
|
|||||||
Delete "$INSTDIR\\{{this}}"
|
Delete "$INSTDIR\\{{this}}"
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
|
; Delete clash-verge.desktop
|
||||||
|
IfFileExists "$INSTDIR\Clash Verge.exe" 0 +2
|
||||||
|
Delete "$INSTDIR\Clash Verge.exe"
|
||||||
|
|
||||||
; Delete uninstaller
|
; Delete uninstaller
|
||||||
Delete "$INSTDIR\uninstall.exe"
|
Delete "$INSTDIR\uninstall.exe"
|
||||||
|
|
||||||
|
|||||||
@@ -34,11 +34,11 @@ pub async fn use_tun(mut config: Mapping, enable: bool) -> Mapping {
|
|||||||
revise!(dns_val, "enable", true);
|
revise!(dns_val, "enable", true);
|
||||||
revise!(dns_val, "ipv6", true);
|
revise!(dns_val, "ipv6", true);
|
||||||
revise!(dns_val, "enhanced-mode", "fake-ip");
|
revise!(dns_val, "enhanced-mode", "fake-ip");
|
||||||
revise!(dns_val, "fake-ip-range", "10.96.0.0/16");
|
revise!(dns_val, "fake-ip-range", "198.18.0.1/16");
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
{
|
{
|
||||||
crate::utils::resolve::restore_public_dns().await;
|
crate::utils::resolve::restore_public_dns().await;
|
||||||
crate::utils::resolve::set_public_dns("10.96.0.2".to_string()).await;
|
crate::utils::resolve::set_public_dns("8.8.8.8".to_string()).await;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
revise!(dns_val, "enhanced-mode", "redir-host");
|
revise!(dns_val, "enhanced-mode", "redir-host");
|
||||||
|
|||||||
@@ -464,6 +464,12 @@ pub async fn delete_webdav_backup(filename: String) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn restore_webdav_backup(filename: String) -> Result<()> {
|
pub async fn restore_webdav_backup(filename: String) -> Result<()> {
|
||||||
|
let verge = Config::verge();
|
||||||
|
let verge_data = verge.data().clone();
|
||||||
|
let webdav_url = verge_data.webdav_url.clone();
|
||||||
|
let webdav_username = verge_data.webdav_username.clone();
|
||||||
|
let webdav_password = verge_data.webdav_password.clone();
|
||||||
|
|
||||||
let backup_storage_path = app_home_dir().unwrap().join(&filename);
|
let backup_storage_path = app_home_dir().unwrap().join(&filename);
|
||||||
backup::WebDavClient::global()
|
backup::WebDavClient::global()
|
||||||
.download(filename, backup_storage_path.clone())
|
.download(filename, backup_storage_path.clone())
|
||||||
@@ -477,6 +483,15 @@ pub async fn restore_webdav_backup(filename: String) -> Result<()> {
|
|||||||
let mut zip = zip::ZipArchive::new(fs::File::open(backup_storage_path.clone())?)?;
|
let mut zip = zip::ZipArchive::new(fs::File::open(backup_storage_path.clone())?)?;
|
||||||
zip.extract(app_home_dir()?)?;
|
zip.extract(app_home_dir()?)?;
|
||||||
|
|
||||||
|
log_err!(
|
||||||
|
patch_verge(IVerge {
|
||||||
|
webdav_url: webdav_url,
|
||||||
|
webdav_username: webdav_username,
|
||||||
|
webdav_password: webdav_password,
|
||||||
|
..IVerge::default()
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
);
|
||||||
// 最后删除临时文件
|
// 最后删除临时文件
|
||||||
fs::remove_file(backup_storage_path)?;
|
fs::remove_file(backup_storage_path)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -99,9 +99,41 @@ pub fn get_last_part_and_decode(url: &str) -> Option<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// open file
|
/// open file
|
||||||
/// use vscode by default
|
/// try to use vscode first, if not found then use system default app
|
||||||
pub fn open_file(app: tauri::AppHandle, path: PathBuf) -> Result<()> {
|
pub fn open_file(app: tauri::AppHandle, path: PathBuf) -> Result<()> {
|
||||||
app.shell().open(path.to_string_lossy(), None).unwrap();
|
#[cfg(target_os = "macos")]
|
||||||
|
let code = "Visual Studio Code";
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
let code = "code";
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let vscode_exists = {
|
||||||
|
use std::process::Command;
|
||||||
|
Command::new("where").arg("code").output().is_ok()
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
let vscode_exists = {
|
||||||
|
use std::process::Command;
|
||||||
|
Command::new("which").arg("code").output().is_ok()
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
let vscode_exists = {
|
||||||
|
use std::process::Command;
|
||||||
|
Command::new("which").arg("code").output().is_ok()
|
||||||
|
};
|
||||||
|
|
||||||
|
// 如果 VS Code 存在就用它打开,否则用系统默认程序
|
||||||
|
if vscode_exists {
|
||||||
|
if let Err(err) = open::with(&path.as_os_str(), code) {
|
||||||
|
log::error!(target: "app", "Failed to open with VS Code: {}", err);
|
||||||
|
app.shell().open(path.to_string_lossy(), None)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
app.shell().open(path.to_string_lossy(), None)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"devUrl": "http://localhost:3000/"
|
"devUrl": "http://localhost:3000/"
|
||||||
},
|
},
|
||||||
"productName": "Clash Verge",
|
"productName": "Clash Verge",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
"identifier": "io.github.clash-verge-rev.clash-verge-rev",
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"updater": {
|
"updater": {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export const ConnectionDetail = forwardRef<ConnectionDetailRef>(
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
interface InnerProps {
|
interface InnerProps {
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export const LayoutTraffic = () => {
|
|||||||
this.close();
|
this.close();
|
||||||
next(event, { up: 0, down: 0 });
|
next(event, { up: 0, down: 0 });
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -69,7 +69,7 @@ export const LayoutTraffic = () => {
|
|||||||
{
|
{
|
||||||
fallbackData: { up: 0, down: 0 },
|
fallbackData: { up: 0, down: 0 },
|
||||||
keepPreviousData: true,
|
keepPreviousData: true,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/* --------- meta memory information --------- */
|
/* --------- meta memory information --------- */
|
||||||
@@ -96,7 +96,7 @@ export const LayoutTraffic = () => {
|
|||||||
this.close();
|
this.close();
|
||||||
next(event, { inuse: 0 });
|
next(event, { inuse: 0 });
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -106,7 +106,7 @@ export const LayoutTraffic = () => {
|
|||||||
{
|
{
|
||||||
fallbackData: { inuse: 0 },
|
fallbackData: { inuse: 0 },
|
||||||
keepPreviousData: true,
|
keepPreviousData: true,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const [up, upUnit] = parseTraffic(traffic.up);
|
const [up, upUnit] = parseTraffic(traffic.up);
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export const useCustomTheme = () => {
|
|||||||
rootEle.style.setProperty("--primary-main", theme.palette.primary.main);
|
rootEle.style.setProperty("--primary-main", theme.palette.primary.main);
|
||||||
rootEle.style.setProperty(
|
rootEle.style.setProperty(
|
||||||
"--background-color-alpha",
|
"--background-color-alpha",
|
||||||
alpha(theme.palette.primary.main, 0.1)
|
alpha(theme.palette.primary.main, 0.1),
|
||||||
);
|
);
|
||||||
|
|
||||||
// inject css
|
// inject css
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export const ProviderButton = () => {
|
|||||||
|
|
||||||
const hasProvider = Object.keys(data || {}).length > 0;
|
const hasProvider = Object.keys(data || {}).length > 0;
|
||||||
const [updating, setUpdating] = useState(
|
const [updating, setUpdating] = useState(
|
||||||
Object.keys(data || {}).map(() => false)
|
Object.keys(data || {}).map(() => false),
|
||||||
);
|
);
|
||||||
|
|
||||||
const setUpdatingAt = (status: boolean, index: number) => {
|
const setUpdatingAt = (status: boolean, index: number) => {
|
||||||
@@ -107,7 +107,7 @@ export const ProviderButton = () => {
|
|||||||
const expire = sub?.Expire || 0;
|
const expire = sub?.Expire || 0;
|
||||||
const progress = Math.min(
|
const progress = Math.min(
|
||||||
Math.round(((download + upload) * 100) / (total + 0.01)) + 1,
|
Math.round(((download + upload) * 100) / (total + 0.01)) + 1,
|
||||||
100
|
100,
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -213,7 +213,7 @@ const StyledTypeBox = styled(Box)<{ component?: React.ElementType }>(
|
|||||||
marginRight: "4px",
|
marginRight: "4px",
|
||||||
padding: "0 2px",
|
padding: "0 2px",
|
||||||
lineHeight: 1.25,
|
lineHeight: 1.25,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const boxStyle = {
|
const boxStyle = {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export const useRenderList = (mode: string) => {
|
|||||||
const { data: proxiesData, mutate: mutateProxies } = useSWR(
|
const { data: proxiesData, mutate: mutateProxies } = useSWR(
|
||||||
"getProxies",
|
"getProxies",
|
||||||
getProxies,
|
getProxies,
|
||||||
{ refreshInterval: 45000 }
|
{ refreshInterval: 45000 },
|
||||||
);
|
);
|
||||||
|
|
||||||
const { verge } = useVerge();
|
const { verge } = useVerge();
|
||||||
@@ -78,7 +78,7 @@ export const useRenderList = (mode: string) => {
|
|||||||
group.all,
|
group.all,
|
||||||
group.name,
|
group.name,
|
||||||
headState.filterText,
|
headState.filterText,
|
||||||
headState.sortType
|
headState.sortType,
|
||||||
);
|
);
|
||||||
|
|
||||||
ret.push({ type: 1, key: `head-${group.name}`, group, headState });
|
ret.push({ type: 1, key: `head-${group.name}`, group, headState });
|
||||||
@@ -97,7 +97,7 @@ export const useRenderList = (mode: string) => {
|
|||||||
headState,
|
headState,
|
||||||
col,
|
col,
|
||||||
proxyCol,
|
proxyCol,
|
||||||
}))
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ export const useRenderList = (mode: string) => {
|
|||||||
group,
|
group,
|
||||||
proxy,
|
proxy,
|
||||||
headState,
|
headState,
|
||||||
}))
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export const ProviderButton = () => {
|
|||||||
|
|
||||||
const hasProvider = Object.keys(data || {}).length > 0;
|
const hasProvider = Object.keys(data || {}).length > 0;
|
||||||
const [updating, setUpdating] = useState(
|
const [updating, setUpdating] = useState(
|
||||||
Object.keys(data || {}).map(() => false)
|
Object.keys(data || {}).map(() => false),
|
||||||
);
|
);
|
||||||
|
|
||||||
const setUpdatingAt = (status: boolean, index: number) => {
|
const setUpdatingAt = (status: boolean, index: number) => {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export interface BackupTableViewerProps {
|
|||||||
page: number;
|
page: number;
|
||||||
onPageChange: (
|
onPageChange: (
|
||||||
event: React.MouseEvent<HTMLButtonElement> | null,
|
event: React.MouseEvent<HTMLButtonElement> | null,
|
||||||
page: number
|
page: number,
|
||||||
) => void;
|
) => void;
|
||||||
total: number;
|
total: number;
|
||||||
onRefresh: () => Promise<void>;
|
onRefresh: () => Promise<void>;
|
||||||
@@ -109,7 +109,7 @@ export const BackupTableViewer = memo(
|
|||||||
onClick={async (e: React.MouseEvent) => {
|
onClick={async (e: React.MouseEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const confirmed = await window.confirm(
|
const confirmed = await window.confirm(
|
||||||
t("Confirm to delete this backup file?")
|
t("Confirm to delete this backup file?"),
|
||||||
);
|
);
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
await handleDelete(file.filename);
|
await handleDelete(file.filename);
|
||||||
@@ -132,7 +132,7 @@ export const BackupTableViewer = memo(
|
|||||||
onClick={async (e: React.MouseEvent) => {
|
onClick={async (e: React.MouseEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const confirmed = await window.confirm(
|
const confirmed = await window.confirm(
|
||||||
t("Confirm to restore this backup file?")
|
t("Confirm to restore this backup file?"),
|
||||||
);
|
);
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
await handleRestore(file.filename);
|
await handleRestore(file.filename);
|
||||||
@@ -181,7 +181,7 @@ export const BackupTableViewer = memo(
|
|||||||
/>
|
/>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
function LinuxIcon(props: SVGProps<SVGSVGElement>) {
|
function LinuxIcon(props: SVGProps<SVGSVGElement>) {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export const BackupViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
(_: React.MouseEvent<HTMLButtonElement> | null, page: number) => {
|
(_: React.MouseEvent<HTMLButtonElement> | null, page: number) => {
|
||||||
setPage(page);
|
setPage(page);
|
||||||
},
|
},
|
||||||
[]
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const fetchAndSetBackupFiles = async () => {
|
const fetchAndSetBackupFiles = async () => {
|
||||||
@@ -95,8 +95,8 @@ export const BackupViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
setDataSource(
|
setDataSource(
|
||||||
backupFiles.slice(
|
backupFiles.slice(
|
||||||
page * DEFAULT_ROWS_PER_PAGE,
|
page * DEFAULT_ROWS_PER_PAGE,
|
||||||
page * DEFAULT_ROWS_PER_PAGE + DEFAULT_ROWS_PER_PAGE
|
page * DEFAULT_ROWS_PER_PAGE + DEFAULT_ROWS_PER_PAGE,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}, [page, backupFiles]);
|
}, [page, backupFiles]);
|
||||||
|
|
||||||
|
|||||||
@@ -76,10 +76,10 @@ export const UpdateViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
setDownloaded((a) => {
|
setDownloaded((a) => {
|
||||||
return a + e.payload.chunkLength;
|
return a + e.payload.chunkLength;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
await updateInfo.install();
|
await updateInfo.downloadAndInstall();
|
||||||
await relaunch();
|
await relaunch();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
Notice.error(err?.message || err.toString());
|
Notice.error(err?.message || err.toString());
|
||||||
@@ -100,7 +100,7 @@ export const UpdateViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
size="small"
|
size="small"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openUrl(
|
openUrl(
|
||||||
`https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/v${updateInfo?.version}`
|
`https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/v${updateInfo?.version}`,
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
>
|
>
|
||||||
<GuardState
|
<GuardState
|
||||||
// clash premium 2022.08.26 值为warn
|
// clash premium 2022.08.26 值为warn
|
||||||
value={logLevel === "warn" ? "warning" : logLevel ?? "info"}
|
value={logLevel === "warn" ? "warning" : (logLevel ?? "info")}
|
||||||
onCatch={onError}
|
onCatch={onError}
|
||||||
onFormat={(e: any) => e.target.value}
|
onFormat={(e: any) => e.target.value}
|
||||||
onChange={(e) => onChangeData({ "log-level": e })}
|
onChange={(e) => onChangeData({ "log-level": e })}
|
||||||
@@ -165,7 +165,7 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
Notice.success(
|
Notice.success(
|
||||||
t("Restart Application to Apply Modifications"),
|
t("Restart Application to Apply Modifications"),
|
||||||
1000
|
1000,
|
||||||
);
|
);
|
||||||
onChangeVerge({ enable_random_port: !enable_random_port });
|
onChangeVerge({ enable_random_port: !enable_random_port });
|
||||||
patchVerge({ enable_random_port: !enable_random_port });
|
patchVerge({ enable_random_port: !enable_random_port });
|
||||||
|
|||||||
@@ -64,13 +64,18 @@ export const TestViewer = forwardRef<TestViewerRef, Props>((props, ref) => {
|
|||||||
try {
|
try {
|
||||||
if (!form.name) throw new Error("`Name` should not be null");
|
if (!form.name) throw new Error("`Name` should not be null");
|
||||||
if (!form.url) throw new Error("`Url` should not be null");
|
if (!form.url) throw new Error("`Url` should not be null");
|
||||||
|
|
||||||
let newList;
|
let newList;
|
||||||
let uid;
|
let uid;
|
||||||
|
|
||||||
if (form.icon && form.icon.startsWith("<svg")) {
|
if (form.icon && form.icon.startsWith("<svg")) {
|
||||||
|
// 移除 icon 中的注释
|
||||||
|
if (form.icon) {
|
||||||
|
form.icon = form.icon.replace(/<!--[\s\S]*?-->/g, "");
|
||||||
|
}
|
||||||
const doc = new DOMParser().parseFromString(
|
const doc = new DOMParser().parseFromString(
|
||||||
form.icon,
|
form.icon,
|
||||||
"image/svg+xml"
|
"image/svg+xml",
|
||||||
);
|
);
|
||||||
if (doc.querySelector("parsererror")) {
|
if (doc.querySelector("parsererror")) {
|
||||||
throw new Error("`Icon`svg format error");
|
throw new Error("`Icon`svg format error");
|
||||||
@@ -97,7 +102,7 @@ export const TestViewer = forwardRef<TestViewerRef, Props>((props, ref) => {
|
|||||||
Notice.error(err.message || err.toString());
|
Notice.error(err.message || err.toString());
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ import {
|
|||||||
export const useClash = () => {
|
export const useClash = () => {
|
||||||
const { data: clash, mutate: mutateClash } = useSWR(
|
const { data: clash, mutate: mutateClash } = useSWR(
|
||||||
"getRuntimeConfig",
|
"getRuntimeConfig",
|
||||||
getRuntimeConfig
|
getRuntimeConfig,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: versionData, mutate: mutateVersion } = useSWR(
|
const { data: versionData, mutate: mutateVersion } = useSWR(
|
||||||
"getVersion",
|
"getVersion",
|
||||||
getVersion
|
getVersion,
|
||||||
);
|
);
|
||||||
|
|
||||||
const patchClash = useLockFn(async (patch: Partial<IConfigData>) => {
|
const patchClash = useLockFn(async (patch: Partial<IConfigData>) => {
|
||||||
@@ -26,8 +26,8 @@ export const useClash = () => {
|
|||||||
const version = versionData?.premium
|
const version = versionData?.premium
|
||||||
? `${versionData.version} Premium`
|
? `${versionData.version} Premium`
|
||||||
: versionData?.meta
|
: versionData?.meta
|
||||||
? `${versionData.version} Mihomo`
|
? `${versionData.version} Mihomo`
|
||||||
: versionData?.version || "-";
|
: versionData?.version || "-";
|
||||||
|
|
||||||
return {
|
return {
|
||||||
clash,
|
clash,
|
||||||
@@ -41,7 +41,7 @@ export const useClash = () => {
|
|||||||
export const useClashInfo = () => {
|
export const useClashInfo = () => {
|
||||||
const { data: clashInfo, mutate: mutateInfo } = useSWR(
|
const { data: clashInfo, mutate: mutateInfo } = useSWR(
|
||||||
"getClashInfo",
|
"getClashInfo",
|
||||||
getClashInfo
|
getClashInfo,
|
||||||
);
|
);
|
||||||
|
|
||||||
const patchInfo = async (
|
const patchInfo = async (
|
||||||
@@ -56,7 +56,7 @@ export const useClashInfo = () => {
|
|||||||
| "external-controller"
|
| "external-controller"
|
||||||
| "secret"
|
| "secret"
|
||||||
>
|
>
|
||||||
>
|
>,
|
||||||
) => {
|
) => {
|
||||||
const hasInfo =
|
const hasInfo =
|
||||||
patch["redir-port"] != null ||
|
patch["redir-port"] != null ||
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export const useListen = () => {
|
|||||||
|
|
||||||
const addListener = async <T>(
|
const addListener = async <T>(
|
||||||
eventName: string,
|
eventName: string,
|
||||||
handler: EventCallback<T>
|
handler: EventCallback<T>,
|
||||||
) => {
|
) => {
|
||||||
const unlisten = await listen(eventName, handler);
|
const unlisten = await listen(eventName, handler);
|
||||||
unlistenFns.current.push(unlisten);
|
unlistenFns.current.push(unlisten);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const buildWSUrl = (server: string, secret: string, logLevel: LogLevel) => {
|
|||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
|
|
||||||
if (secret) {
|
if (secret) {
|
||||||
params.append("token", encodeURIComponent(secret));
|
params.append("token", secret);
|
||||||
}
|
}
|
||||||
if (logLevel === "all") {
|
if (logLevel === "all") {
|
||||||
params.append("level", "debug");
|
params.append("level", "debug");
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const ConnectionsPage = () => {
|
|||||||
list.sort(
|
list.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
new Date(b.start || "0").getTime()! -
|
new Date(b.start || "0").getTime()! -
|
||||||
new Date(a.start || "0").getTime()!
|
new Date(a.start || "0").getTime()!,
|
||||||
),
|
),
|
||||||
"Upload Speed": (list) => list.sort((a, b) => b.curUpload! - a.curUpload!),
|
"Upload Speed": (list) => list.sort((a, b) => b.curUpload! - a.curUpload!),
|
||||||
"Download Speed": (list) =>
|
"Download Speed": (list) =>
|
||||||
@@ -103,7 +103,7 @@ const ConnectionsPage = () => {
|
|||||||
next(event);
|
next(event);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
3
|
3,
|
||||||
);
|
);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -114,7 +114,7 @@ const ConnectionsPage = () => {
|
|||||||
const [filterConn, download, upload] = useMemo(() => {
|
const [filterConn, download, upload] = useMemo(() => {
|
||||||
const orderFunc = orderOpts[curOrderOpt];
|
const orderFunc = orderOpts[curOrderOpt];
|
||||||
let connections = connData.connections.filter((conn) =>
|
let connections = connData.connections.filter((conn) =>
|
||||||
match(conn.metadata.host || conn.metadata.destinationIP || "")
|
match(conn.metadata.host || conn.metadata.destinationIP || ""),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (orderFunc) connections = orderFunc(connections);
|
if (orderFunc) connections = orderFunc(connections);
|
||||||
@@ -152,7 +152,7 @@ const ConnectionsPage = () => {
|
|||||||
setSetting((o) =>
|
setSetting((o) =>
|
||||||
o?.layout !== "table"
|
o?.layout !== "table"
|
||||||
? { ...o, layout: "table" }
|
? { ...o, layout: "table" }
|
||||||
: { ...o, layout: "list" }
|
: { ...o, layout: "list" },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ const ProfilePage = () => {
|
|||||||
useSensor(PointerSensor),
|
useSensor(PointerSensor),
|
||||||
useSensor(KeyboardSensor, {
|
useSensor(KeyboardSensor, {
|
||||||
coordinateGetter: sortableKeyboardCoordinates,
|
coordinateGetter: sortableKeyboardCoordinates,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
const { current } = location.state || {};
|
const { current } = location.state || {};
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ const ProfilePage = () => {
|
|||||||
|
|
||||||
const { data: chainLogs = {}, mutate: mutateLogs } = useSWR(
|
const { data: chainLogs = {}, mutate: mutateLogs } = useSWR(
|
||||||
"getRuntimeLogs",
|
"getRuntimeLogs",
|
||||||
getRuntimeLogs
|
getRuntimeLogs,
|
||||||
);
|
);
|
||||||
|
|
||||||
const viewerRef = useRef<ProfileViewerRef>(null);
|
const viewerRef = useRef<ProfileViewerRef>(null);
|
||||||
@@ -240,7 +240,7 @@ const ProfilePage = () => {
|
|||||||
setLoadingCache((cache) => {
|
setLoadingCache((cache) => {
|
||||||
// 获取没有正在更新的订阅
|
// 获取没有正在更新的订阅
|
||||||
const items = profileItems.filter(
|
const items = profileItems.filter(
|
||||||
(e) => e.type === "remote" && !cache[e.uid]
|
(e) => e.type === "remote" && !cache[e.uid],
|
||||||
);
|
);
|
||||||
const change = Object.fromEntries(items.map((e) => [e.uid, true]));
|
const change = Object.fromEntries(items.map((e) => [e.uid, true]));
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const ProxyPage = () => {
|
|||||||
|
|
||||||
const { data: clashConfig, mutate: mutateClash } = useSWR(
|
const { data: clashConfig, mutate: mutateClash } = useSWR(
|
||||||
"getClashConfig",
|
"getClashConfig",
|
||||||
getClashConfig
|
getClashConfig,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { verge } = useVerge();
|
const { verge } = useVerge();
|
||||||
|
|||||||
+12
-7
@@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
import { Box, Button, Grid } from "@mui/material";
|
import { Box, Button } from "@mui/material";
|
||||||
|
import Grid2 from "@mui/material/Grid2";
|
||||||
import {
|
import {
|
||||||
DndContext,
|
DndContext,
|
||||||
closestCenter,
|
closestCenter,
|
||||||
@@ -34,7 +35,7 @@ const TestPage = () => {
|
|||||||
useSensor(PointerSensor),
|
useSensor(PointerSensor),
|
||||||
useSensor(KeyboardSensor, {
|
useSensor(KeyboardSensor, {
|
||||||
coordinateGetter: sortableKeyboardCoordinates,
|
coordinateGetter: sortableKeyboardCoordinates,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
const { verge, mutateVerge, patchVerge } = useVerge();
|
const { verge, mutateVerge, patchVerge } = useVerge();
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@ const TestPage = () => {
|
|||||||
|
|
||||||
const onTestListItemChange = (
|
const onTestListItemChange = (
|
||||||
uid: string,
|
uid: string,
|
||||||
patch?: Partial<IVergeTestItem>
|
patch?: Partial<IVergeTestItem>,
|
||||||
) => {
|
) => {
|
||||||
if (patch) {
|
if (patch) {
|
||||||
const newList = testList.map((x) => {
|
const newList = testList.map((x) => {
|
||||||
@@ -157,24 +158,28 @@ const TestPage = () => {
|
|||||||
onDragEnd={onDragEnd}
|
onDragEnd={onDragEnd}
|
||||||
>
|
>
|
||||||
<Box sx={{ mb: 4.5 }}>
|
<Box sx={{ mb: 4.5 }}>
|
||||||
<Grid container spacing={{ xs: 1, lg: 1 }}>
|
<Grid2 container spacing={{ xs: 1, lg: 1 }}>
|
||||||
<SortableContext
|
<SortableContext
|
||||||
items={testList.map((x) => {
|
items={testList.map((x) => {
|
||||||
return x.uid;
|
return x.uid;
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{testList.map((item) => (
|
{testList.map((item) => (
|
||||||
<Grid item xs={6} sm={4} md={3} lg={2} key={item.uid}>
|
<Grid2
|
||||||
|
component={"div"}
|
||||||
|
size={{ xs: 6, lg: 2, sm: 4, md: 3 }}
|
||||||
|
key={item.uid}
|
||||||
|
>
|
||||||
<TestItem
|
<TestItem
|
||||||
id={item.uid}
|
id={item.uid}
|
||||||
itemData={item}
|
itemData={item}
|
||||||
onEdit={() => viewerRef.current?.edit(item)}
|
onEdit={() => viewerRef.current?.edit(item)}
|
||||||
onDelete={onDeleteTestListItem}
|
onDelete={onDeleteTestListItem}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid2>
|
||||||
))}
|
))}
|
||||||
</SortableContext>
|
</SortableContext>
|
||||||
</Grid>
|
</Grid2>
|
||||||
</Box>
|
</Box>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export const useConnectionSetting = () =>
|
|||||||
{
|
{
|
||||||
serializer: JSON.stringify,
|
serializer: JSON.stringify,
|
||||||
deserializer: JSON.parse,
|
deserializer: JSON.parse,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// save the state of each profile item loading
|
// save the state of each profile item loading
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import Sockette, { type SocketteOptions } from "sockette";
|
|||||||
export const createSockette = (
|
export const createSockette = (
|
||||||
url: string,
|
url: string,
|
||||||
opt: SocketteOptions,
|
opt: SocketteOptions,
|
||||||
maxError = 10
|
maxError = 10,
|
||||||
) => {
|
) => {
|
||||||
let remainRetryCount = maxError;
|
let remainRetryCount = maxError;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ import monacoEditorPlugin, {
|
|||||||
type IMonacoEditorOpts,
|
type IMonacoEditorOpts,
|
||||||
} from "vite-plugin-monaco-editor";
|
} from "vite-plugin-monaco-editor";
|
||||||
const monacoEditorPluginDefault = (monacoEditorPlugin as any).default as (
|
const monacoEditorPluginDefault = (monacoEditorPlugin as any).default as (
|
||||||
options: IMonacoEditorOpts
|
options: IMonacoEditorOpts,
|
||||||
) => any;
|
) => any;
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
|||||||
Reference in New Issue
Block a user