Compare commits

...
Author SHA1 Message Date
renovate[bot] 6e3be5a27f chore(deps): update node.js to v26.13.1 2026-11-11 17:45:06 +00:00
4adac9e4b6 fix(config): stop rewriting unchanged configs on exit (#8017)
* fix(config): stop rewriting unchanged configs on exit

apply_all_and_save_file() committed the drafts and then saved clash.yaml,
verge.yaml and profiles.yaml unconditionally. With nothing staged that write
replaced each file with content equal to what was already on disk - fields are
encrypted with a fresh nonce, so the bytes differ every time - which reset the
files' creation time on every exit (#7759).

Draft::apply now reports whether it committed a draft, and the exit path saves
only the configs that had one.

* refactor(tests): remove test snippets

Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>

* docs(changelog): add entry of the PR modifications

Assisted-by: Gemini 3.8 Flash Medium (VSCode Copilot Chat)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>

---------

Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>
Co-authored-by: sdhfsl <sdhfsl@users.noreply.github.com>
Co-authored-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-11-11 17:33:03 +00:00
Tunglies 2c60f55f45 feat(connections): add network protocol filter (#8611)
* feat(connections): add network protocol filter

Filter connections by metadata.network (All/TCP/UDP) in both table and
list layouts, combined with search, and kept across page switches like
the existing search state.

Refs #6140

* fix(connections): keep network filter labels in English

Remove the All Networks translation and use All alongside TCP and UDP.\n\nRefs #6140

* fix(connections): narrow network filter select
2026-11-11 09:50:25 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> b8c13c0370 chore(deps): update dependency github/gh-aw to v1.2.2 (#8620)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-11-11 04:02:03 +00:00
❤是纱雾酱哟~andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> f86db4b344 chore(deps): update cargo dependencies (#8619)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-11-10 17:29:51 +00:00
renovate[bot]renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>❤是纱雾酱哟~
389dddf512 chore(deps): update github/gh-aw-actions action to v1.2.2 (#8617)
* chore(deps): update github/gh-aw-actions action to v1.2.2

* ci(workflows): recompile workflow lockfiles with gh-aw v1.2.2

Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>

* ci(workflows): set permissions to suppress tips

Agentic workflows of this repository are using available credits by some
collaborators' personal API Key. Configuring permissions of these
workflows to suppress warnings by GitHub Agentic Workflow extension
during lockfile compilation.

Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>

---------

Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>
2026-11-10 14:01:34 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> 304a65fc36 chore(deps): update npm dependencies (#8615)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-11-10 05:17:19 +00:00
28 changed files with 974 additions and 387 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
"features": { "features": {
"ghcr.io/devcontainers/features/node:2": { "ghcr.io/devcontainers/features/node:2": {
"version": "26.13.0", "version": "26.13.1",
"pnpmVersion": "12.18.0" "pnpmVersion": "12.18.0"
}, },
"ghcr.io/devcontainers/features/rust:1": { "ghcr.io/devcontainers/features/rust:1": {
+3 -3
View File
@@ -5,10 +5,10 @@
"version": "v9.0.0", "version": "v9.0.0",
"sha": "3a2844b7e9c422d3c10d287c895573f7108da1b3" "sha": "3a2844b7e9c422d3c10d287c895573f7108da1b3"
}, },
"github/gh-aw-actions/setup@v1.0.1": { "github/gh-aw-actions/setup@v1.2.2": {
"repo": "github/gh-aw-actions/setup", "repo": "github/gh-aw-actions/setup",
"version": "v1.0.1", "version": "v1.2.2",
"sha": "221ba4f4319de6b8e809d1a15528b3ae6a818aa5" "sha": "53d0749e19424a918acd82b4d140264ce48f2f14"
} }
}, },
"containers": { "containers": {
+5 -5
View File
@@ -51,7 +51,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
@@ -182,7 +182,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
cache: 'pnpm' cache: 'pnpm'
- name: Pnpm install and check - name: Pnpm install and check
@@ -262,7 +262,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
cache: 'pnpm' cache: 'pnpm'
- name: Pnpm install and check - name: Pnpm install and check
@@ -395,7 +395,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
cache: 'pnpm' cache: 'pnpm'
- name: Pnpm install and check - name: Pnpm install and check
@@ -479,7 +479,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
- uses: pnpm/action-setup@v6.1.1 - uses: pnpm/action-setup@v6.1.1
name: Install pnpm name: Install pnpm
+1 -1
View File
@@ -63,7 +63,7 @@ jobs:
- uses: actions/setup-node@v7 - uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
cache: 'pnpm' cache: 'pnpm'
- run: pnpm install --frozen-lockfile - run: pnpm install --frozen-lockfile
+3 -3
View File
@@ -31,9 +31,9 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Install gh-aw extension - name: Install gh-aw extension
uses: github/gh-aw-actions/setup-cli@406c7719e31d7fe354224d4bb8fe3d4aeb47da1c # v1.2.1 uses: github/gh-aw-actions/setup-cli@53d0749e19424a918acd82b4d140264ce48f2f14 # v1.2.2
with: with:
version: v1.0.1 version: v1.2.2
- name: Install Rust Stable - name: Install Rust Stable
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
@@ -49,7 +49,7 @@ jobs:
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
cache: 'pnpm' cache: 'pnpm'
- name: Install frontend dependencies - name: Install frontend dependencies
env: env:
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
- uses: pnpm/action-setup@v6 - uses: pnpm/action-setup@v6
name: Install pnpm name: Install pnpm
+1 -1
View File
@@ -104,7 +104,7 @@ jobs:
if: github.event.inputs[matrix.input] == 'true' if: github.event.inputs[matrix.input] == 'true'
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
cache: 'pnpm' cache: 'pnpm'
- name: Pnpm install and check - name: Pnpm install and check
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
- uses: actions/setup-node@v7 - uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
cache: 'pnpm' cache: 'pnpm'
- run: pnpm install --frozen-lockfile - run: pnpm install --frozen-lockfile
File diff suppressed because one or more lines are too long
+1
View File
@@ -33,6 +33,7 @@ max-daily-ai-credits: 5000
permissions: permissions:
issues: read issues: read
pull-requests: read pull-requests: read
copilot-requests: none
pre-agent-steps: pre-agent-steps:
- name: Make Copilot quota exhaustion non-blocking - name: Make Copilot quota exhaustion non-blocking
+288 -107
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -30,6 +30,7 @@ permissions:
contents: read contents: read
issues: read issues: read
pull-requests: read pull-requests: read
copilot-requests: none
steps: steps:
- name: Load review rules from the base revision - name: Load review rules from the base revision
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+1 -1
View File
@@ -61,7 +61,7 @@ jobs:
- uses: actions/setup-node@v7 - uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
- uses: pnpm/action-setup@v6 - uses: pnpm/action-setup@v6
if: github.event.action != 'closed' if: github.event.action != 'closed'
+8 -8
View File
@@ -46,7 +46,7 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- uses: actions/setup-node@v7 - uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
- name: Validate source and publish the approved snapshot - name: Validate source and publish the approved snapshot
id: source id: source
env: env:
@@ -231,7 +231,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
cache: 'pnpm' cache: 'pnpm'
- name: Pnpm install and check - name: Pnpm install and check
@@ -330,7 +330,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
cache: 'pnpm' cache: 'pnpm'
- name: Pnpm install and check - name: Pnpm install and check
@@ -461,7 +461,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
cache: 'pnpm' cache: 'pnpm'
- name: Pnpm install and check - name: Pnpm install and check
@@ -542,7 +542,7 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- uses: actions/setup-node@v7 - uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
- uses: pnpm/action-setup@v6 - uses: pnpm/action-setup@v6
with: with:
run_install: false run_install: false
@@ -565,7 +565,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
- uses: pnpm/action-setup@v6 - uses: pnpm/action-setup@v6
name: Install pnpm name: Install pnpm
@@ -593,7 +593,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
- uses: pnpm/action-setup@v6 - uses: pnpm/action-setup@v6
name: Install pnpm name: Install pnpm
@@ -661,7 +661,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
- uses: pnpm/action-setup@v6 - uses: pnpm/action-setup@v6
name: Install pnpm name: Install pnpm
File diff suppressed because one or more lines are too long
@@ -28,6 +28,7 @@ permissions:
contents: read contents: read
issues: read issues: read
pull-requests: read pull-requests: read
copilot-requests: none
max-ai-credits: 60 max-ai-credits: 60
max-turns: 12 max-turns: 12
max-daily-ai-credits: 500 max-daily-ai-credits: 500
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v6 uses: pnpm/action-setup@v6
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
- uses: pnpm/action-setup@v6 - uses: pnpm/action-setup@v6
name: Install pnpm name: Install pnpm
+2 -2
View File
@@ -15,7 +15,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
- uses: pnpm/action-setup@v6 - uses: pnpm/action-setup@v6
name: Install pnpm name: Install pnpm
@@ -39,7 +39,7 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v7 uses: actions/setup-node@v7
with: with:
node-version: '26.13.0' node-version: '26.13.1'
- uses: pnpm/action-setup@v6 - uses: pnpm/action-setup@v6
name: Install pnpm name: Install pnpm
+1 -1
View File
@@ -1,3 +1,3 @@
nodejs 26.13.0 nodejs 26.13.1
pnpm 12.18.0 pnpm 12.18.0
rust 1.99.1 rust 1.99.1
Generated
+4 -4
View File
@@ -159,9 +159,9 @@ dependencies = [
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
version = "1.9.4" version = "1.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db4c94f57a570fce5d381be3289b3f79aef6332d72948fe82ab5772e423ccf92" checksum = "84a22b5d51209f6de83d37a0b33d320acb8da88823e42a94c075140708f032a5"
dependencies = [ dependencies = [
"rustversion", "rustversion",
] ]
@@ -10126,9 +10126,9 @@ dependencies = [
[[package]] [[package]]
name = "zip" name = "zip"
version = "9.4.2" version = "9.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3845f734baabdd02de353a20580e30ceccd03897def44a4eb8e9654992e294" checksum = "0700e6c427aff64acdbf02e85fbfd946c2ee12319d1af013092f3a2178914ff8"
dependencies = [ dependencies = [
"aes", "aes",
"bzip2", "bzip2",
+3
View File
@@ -24,6 +24,8 @@
<details> <details>
<summary><strong> 🐞 修复问题 </strong></summary> <summary><strong> 🐞 修复问题 </strong></summary>
- 修复应用退出时无条件重写 `clash.yaml`、`verge.yaml` 和 `profiles.yaml` 导致文件创建时间丢失的问题
- 修复检测更新后又发布新版时,应用内更新失败 - 修复检测更新后又发布新版时,应用内更新失败
- 修复订阅响应过大导致内存占用过高,限制单次下载为 4 MiB - 修复订阅响应过大导致内存占用过高,限制单次下载为 4 MiB
- 修复全局模式默认停在 `DIRECT` 或 `REJECT` 导致流量未经代理,现自动切换到第一个策略组 - 修复全局模式默认停在 `DIRECT` 或 `REJECT` 导致流量未经代理,现自动切换到第一个策略组
@@ -40,6 +42,7 @@
<details> <details>
<summary><strong> ✨ 新增功能 </strong></summary> <summary><strong> ✨ 新增功能 </strong></summary>
- 新增连接页面按网络协议(TCP/UDP)筛选连接
</details> </details>
+8 -4
View File
@@ -74,12 +74,16 @@ impl<T: Clone> Draft<T> {
result result
} }
/// Commits and clears the draft. /// Commits and clears the draft, reporting whether one was staged.
#[inline] #[inline]
pub fn apply(&self) { pub fn apply(&self) -> bool {
let mut guard = self.inner.data.lock(); let mut guard = self.inner.data.lock();
if let Some(d) = guard.1.take() { match guard.1.take() {
guard.0 = d; Some(d) => {
guard.0 = d;
true
}
None => false,
} }
} }
+2 -2
View File
@@ -67,7 +67,7 @@
"dayjs": "1.11.23", "dayjs": "1.11.23",
"foxact": "^0.3.12", "foxact": "^0.3.12",
"foxts": "^5.9.1", "foxts": "^5.9.1",
"i18next": "^26.4.2", "i18next": "^27.0.0",
"js-yaml": "^5.4.2", "js-yaml": "^5.4.2",
"lodash-es": "^4.18.1", "lodash-es": "^4.18.1",
"meta-json-schema": "^1.19.31", "meta-json-schema": "^1.19.31",
@@ -79,7 +79,7 @@
"react-dom": "19.3.1", "react-dom": "19.3.1",
"react-error-boundary": "6.1.6", "react-error-boundary": "6.1.6",
"react-hook-form": "^7.88.0", "react-hook-form": "^7.88.0",
"react-i18next": "17.1.13", "react-i18next": "18.0.1",
"react-markdown": "10.1.0", "react-markdown": "10.1.0",
"react-router": "^8.4.0", "react-router": "^8.4.0",
"rehype-raw": "^7.0.0", "rehype-raw": "^7.0.0",
+18 -21
View File
@@ -239,8 +239,8 @@ importers:
specifier: ^5.9.1 specifier: ^5.9.1
version: 5.9.1 version: 5.9.1
i18next: i18next:
specifier: ^26.4.2 specifier: ^27.0.0
version: 26.4.2(typescript@6.0.3) version: 27.0.1(typescript@6.0.3)
js-yaml: js-yaml:
specifier: ^5.4.2 specifier: ^5.4.2
version: 5.4.2 version: 5.4.2
@@ -275,8 +275,8 @@ importers:
specifier: ^7.88.0 specifier: ^7.88.0
version: 7.88.0(react@19.3.1) version: 7.88.0(react@19.3.1)
react-i18next: react-i18next:
specifier: 17.1.13 specifier: 18.0.1
version: 17.1.13(i18next@26.4.2(typescript@6.0.3))(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(typescript@6.0.3) version: 18.0.1(@types/react@19.3.0)(i18next@27.0.1(typescript@6.0.3))(react@19.3.1)(typescript@6.0.3)
react-markdown: react-markdown:
specifier: 10.1.0 specifier: 10.1.0
version: 10.1.0(@types/react@19.3.0)(react@19.3.1)(supports-color@7.2.0) version: 10.1.0(@types/react@19.3.0)(react@19.3.1)(supports-color@7.2.0)
@@ -3689,8 +3689,9 @@ packages:
engines: {node: '>=18'} engines: {node: '>=18'}
hasBin: true hasBin: true
i18next@26.4.2: i18next@27.0.1:
resolution: {integrity: sha512-RX+R0VLg13IbvRuJSxnqykUFS9vQZTl8wYpWPCIUDWVrSGjsQywB5Y+pjzrkboxGAuYfJZVH1InFTdgBdxq6ug==} resolution: {integrity: sha512-KaE5ozP8UUeVpOJIwMVbbnpRKpyYQuxd9ZbseJoDzezE3nvLnZZQn20pkzyIJwPI2Uet/Qs3WzPTG812f6F/Eg==}
engines: {node: '>=22'}
peerDependencies: peerDependencies:
typescript: ^5 || ^6 || ^7 typescript: ^5 || ^6 || ^7
peerDependenciesMeta: peerDependenciesMeta:
@@ -4396,18 +4397,16 @@ packages:
peerDependencies: peerDependencies:
react: ^16.8.0 || ^17 || ^18 || ^19 react: ^16.8.0 || ^17 || ^18 || ^19
react-i18next@17.1.13: react-i18next@18.0.1:
resolution: {integrity: sha512-ZxhOSlyKSKPtbUNPLwYMmE3w3bhoc0jaZJZ6bc7wGOT6cLbrbs//6m01HxCLtFdSjHvFpwFwoPhxxzIlHSs9cw==} resolution: {integrity: sha512-kPWXI0E/lrPj3+/umcKNzYZVnWmEedLiamMzDIHfbs+5ANf6yzvlZsjKou8f7kaGkfMMDLIZBejV+4aSN1CyBw==}
engines: {node: '>=22'}
peerDependencies: peerDependencies:
i18next: '>= 26.2.0' '@types/react': '*'
react: '>= 16.8.0' i18next: '>= 27.0.1'
react-dom: '*' react: '>= 18.0.0'
react-native: '*'
typescript: ^5 || ^6 || ^7 typescript: ^5 || ^6 || ^7
peerDependenciesMeta: peerDependenciesMeta:
react-dom: '@types/react':
optional: true
react-native:
optional: true optional: true
typescript: typescript:
optional: true optional: true
@@ -8533,7 +8532,7 @@ snapshots:
husky@9.1.7: {} husky@9.1.7: {}
i18next@26.4.2(typescript@6.0.3): i18next@27.0.1(typescript@6.0.3):
optionalDependencies: optionalDependencies:
typescript: 6.0.3 typescript: 6.0.3
@@ -9357,15 +9356,13 @@ snapshots:
dependencies: dependencies:
react: 19.3.1 react: 19.3.1
react-i18next@17.1.13(i18next@26.4.2(typescript@6.0.3))(react-dom@19.3.1(react@19.3.1))(react@19.3.1)(typescript@6.0.3): react-i18next@18.0.1(@types/react@19.3.0)(i18next@27.0.1(typescript@6.0.3))(react@19.3.1)(typescript@6.0.3):
dependencies: dependencies:
'@babel/runtime': 7.29.7
html-parse-stringify: 4.0.1 html-parse-stringify: 4.0.1
i18next: 26.4.2(typescript@6.0.3) i18next: 27.0.1(typescript@6.0.3)
react: 19.3.1 react: 19.3.1
use-sync-external-store: 1.7.0(react@19.3.1)
optionalDependencies: optionalDependencies:
react-dom: 19.3.1(react@19.3.1) '@types/react': 19.3.0
typescript: 6.0.3 typescript: 6.0.3
react-is@16.13.1: {} react-is@16.13.1: {}
+2 -2
View File
@@ -77,7 +77,7 @@ tauri-plugin-dialog = "2.8.4"
tauri-plugin-fs = "2.7.1" tauri-plugin-fs = "2.7.1"
tauri-plugin-deep-link = "2.6.3" tauri-plugin-deep-link = "2.6.3"
tauri-plugin-window-state = "2.5.0" tauri-plugin-window-state = "2.5.0"
zip = "9.4.2" zip = "9.5.0"
flate2 = "1.1.11" flate2 = "1.1.11"
reqwest_dav = "0.3.3" reqwest_dav = "0.3.3"
aes-gcm = { version = "0.11.1" } aes-gcm = { version = "0.11.1" }
@@ -97,7 +97,7 @@ async-trait = "0.1.92"
clash_verge_service_ipc = { git = "https://github.com/clash-verge-rev/clash-verge-service-ipc.git", tag = "v2.7.7", version = "2.7.7", features = [ clash_verge_service_ipc = { git = "https://github.com/clash-verge-rev/clash-verge-service-ipc.git", tag = "v2.7.7", version = "2.7.7", features = [
"client", "client",
] } ] }
arc-swap = "1.9.4" arc-swap = "1.9.5"
tokio-rustls = "0.26.6" tokio-rustls = "0.26.6"
rustls = { version = "0.23.46", features = ["ring"] } rustls = { version = "0.23.46", features = ["ring"] }
webpki-roots = "1.0.11" webpki-roots = "1.0.11"
+10 -6
View File
@@ -280,25 +280,29 @@ impl Config {
} }
/// Commits drafts during exit/restart/shutdown so user changes are not lost. /// Commits drafts during exit/restart/shutdown so user changes are not lost.
/// A config with nothing staged keeps its file, so its timestamps stay put.
pub async fn apply_all_and_save_file() { pub async fn apply_all_and_save_file() {
logging!(debug, Type::Config, "save all draft data"); logging!(debug, Type::Config, "save all draft data");
let save_clash_task = AsyncHandler::spawn(|| async { let save_clash_task = AsyncHandler::spawn(|| async {
let clash = Self::clash().await; let clash = Self::clash().await;
clash.apply(); if clash.apply() {
logging_error!(Type::Config, clash.data_arc().save_config().await); logging_error!(Type::Config, clash.data_arc().save_config().await);
}
}); });
let save_verge_task = AsyncHandler::spawn(|| async { let save_verge_task = AsyncHandler::spawn(|| async {
let verge = Self::verge().await; let verge = Self::verge().await;
verge.apply(); if verge.apply() {
logging_error!(Type::Config, verge.data_arc().save_file().await); logging_error!(Type::Config, verge.data_arc().save_file().await);
}
}); });
let save_profiles_task = AsyncHandler::spawn(|| async { let save_profiles_task = AsyncHandler::spawn(|| async {
let _profile_write = super::profiles::PROFILE_WRITE_LOCK.lock().await; let _profile_write = super::profiles::PROFILE_WRITE_LOCK.lock().await;
let profiles = Self::profiles().await; let profiles = Self::profiles().await;
profiles.apply(); if profiles.apply() {
logging_error!(Type::Config, profiles.data_arc().save_file().await); logging_error!(Type::Config, profiles.data_arc().save_file().await);
}
}); });
let _ = tokio::join!(save_clash_task, save_verge_task, save_profiles_task); let _ = tokio::join!(save_clash_task, save_verge_task, save_profiles_task);
+42 -5
View File
@@ -71,6 +71,10 @@ const ORDER_OPTIONS = [
type OrderKey = (typeof ORDER_OPTIONS)[number]['id'] type OrderKey = (typeof ORDER_OPTIONS)[number]['id']
type NetworkFilter = 'all' | 'tcp' | 'udp'
let savedNetworkFilter: NetworkFilter = 'all'
const orderFunctionMap = ORDER_OPTIONS.reduce<Record<OrderKey, OrderFunc>>( const orderFunctionMap = ORDER_OPTIONS.reduce<Record<OrderKey, OrderFunc>>(
(acc, option) => { (acc, option) => {
acc[option.id] = option.fn acc[option.id] = option.fn
@@ -86,6 +90,9 @@ const ConnectionsPage = () => {
const { searchState, match, onSearch } = usePageSearch('connections') const { searchState, match, onSearch } = usePageSearch('connections')
const hasSearch = searchState.text.length > 0 const hasSearch = searchState.text.length > 0
const [curOrderOpt, setCurOrderOpt] = useState<OrderKey>('default') const [curOrderOpt, setCurOrderOpt] = useState<OrderKey>('default')
const [networkFilter, setNetworkFilter] =
useState<NetworkFilter>(savedNetworkFilter)
const hasFilter = networkFilter !== 'all'
const [connectionsType, setConnectionsType] = useState<'active' | 'closed'>( const [connectionsType, setConnectionsType] = useState<'active' | 'closed'>(
'active', 'active',
) )
@@ -112,18 +119,30 @@ const ConnectionsPage = () => {
const filterConn = useMemo(() => { const filterConn = useMemo(() => {
const orderFunc = orderFunctionMap[curOrderOpt] const orderFunc = orderFunctionMap[curOrderOpt]
if (isTableLayout && !hasSearch) return selectedConnections if (isTableLayout && !hasSearch && !hasFilter) return selectedConnections
if (!hasSearch) return orderFunc([...selectedConnections]) if (!hasSearch && !hasFilter) return orderFunc([...selectedConnections])
const matchConns = selectedConnections.filter((conn) => { const matchConns = selectedConnections.filter((conn) => {
const { host, destinationIP, process } = conn.metadata const { host, destinationIP, process, network } = conn.metadata
if (networkFilter !== 'all' && network !== networkFilter) return false
return ( return (
match(host || '') || match(destinationIP || '') || match(process || '') !hasSearch ||
match(host || '') ||
match(destinationIP || '') ||
match(process || '')
) )
}) })
return orderFunc ? orderFunc(matchConns) : matchConns return orderFunc ? orderFunc(matchConns) : matchConns
}, [selectedConnections, isTableLayout, hasSearch, match, curOrderOpt]) }, [
selectedConnections,
isTableLayout,
hasSearch,
hasFilter,
networkFilter,
match,
curOrderOpt,
])
const displayRows = useConnectionRowViews( const displayRows = useConnectionRowViews(
isTableLayout ? EMPTY_CONNECTIONS : filterConn, isTableLayout ? EMPTY_CONNECTIONS : filterConn,
@@ -255,6 +274,24 @@ const ConnectionsPage = () => {
))} ))}
</BaseStyledSelect> </BaseStyledSelect>
)} )}
<BaseStyledSelect
style={{ width: 80 }}
value={networkFilter}
onChange={(e) => {
savedNetworkFilter = e.target.value as NetworkFilter
setNetworkFilter(savedNetworkFilter)
}}
>
<MenuItem value="all">
<span style={{ fontSize: 14 }}>All</span>
</MenuItem>
<MenuItem value="tcp">
<span style={{ fontSize: 14 }}>TCP</span>
</MenuItem>
<MenuItem value="udp">
<span style={{ fontSize: 14 }}>UDP</span>
</MenuItem>
</BaseStyledSelect>
<Box <Box
sx={{ sx={{
flex: 1, flex: 1,