From ef976518c926da55f05a8994a85baa2a01de0ac0 Mon Sep 17 00:00:00 2001 From: Ereli Date: Thu, 12 Feb 2026 22:40:56 -0500 Subject: [PATCH] sqash --- Cargo.lock | 780 ++++++++---------- crates/kftray-commons/Cargo.toml | 1 + .../kftray-commons/src/models/config_model.rs | 11 +- .../src/models/config_state_model.rs | 5 +- crates/kftray-commons/src/models/hostfile.rs | 5 +- .../src/models/http_logs_config_model.rs | 5 +- .../src/models/settings_model.rs | 36 +- .../src/models/tunnel_protocol.rs | 5 +- crates/kftray-commons/src/models/window.rs | 5 +- crates/kftray-commons/src/utils/config.rs | 27 +- crates/kftray-commons/src/utils/config_dir.rs | 6 +- .../kftray-commons/src/utils/config_state.rs | 10 +- crates/kftray-commons/src/utils/db.rs | 38 +- crates/kftray-commons/src/utils/db_mode.rs | 10 +- crates/kftray-commons/src/utils/env_export.rs | 396 +++++++++ crates/kftray-commons/src/utils/github.rs | 17 +- crates/kftray-commons/src/utils/hostsfile.rs | 17 +- .../src/utils/http_logs_config.rs | 10 +- crates/kftray-commons/src/utils/manifests.rs | 7 +- crates/kftray-commons/src/utils/migration.rs | 18 +- crates/kftray-commons/src/utils/mod.rs | 1 + crates/kftray-commons/src/utils/settings.rs | 47 +- .../src/utils/timeout_manager.rs | 15 +- crates/kftray-tauri/build.rs | 5 +- crates/kftray-tauri/src/commands/config.rs | 22 +- .../kftray-tauri/src/commands/env_export.rs | 8 + crates/kftray-tauri/src/commands/github.rs | 15 +- crates/kftray-tauri/src/commands/helper.rs | 5 +- crates/kftray-tauri/src/commands/httplogs.rs | 30 +- .../kftray-tauri/src/commands/kubecontext.rs | 28 +- crates/kftray-tauri/src/commands/logs.rs | 15 +- crates/kftray-tauri/src/commands/mod.rs | 1 + .../kftray-tauri/src/commands/portforward.rs | 89 +- .../src/commands/server_resources.rs | 26 +- crates/kftray-tauri/src/commands/settings.rs | 69 +- crates/kftray-tauri/src/commands/shortcuts.rs | 10 +- crates/kftray-tauri/src/commands/ssl.rs | 22 +- crates/kftray-tauri/src/commands/updater.rs | 21 +- .../kftray-tauri/src/commands/window_state.rs | 12 +- crates/kftray-tauri/src/glibc_detector.rs | 5 +- crates/kftray-tauri/src/init_check.rs | 24 +- crates/kftray-tauri/src/main.rs | 20 +- crates/kftray-tauri/src/shortcuts.rs | 30 +- crates/kftray-tauri/src/tray.rs | 40 +- crates/kftray-tauri/src/validation.rs | 16 +- crates/kftray-tauri/src/window.rs | 18 +- docs/kftray/USAGE.md | 38 + frontend/src/components/Footer/index.tsx | 7 + frontend/src/components/Main/index.tsx | 34 + .../SettingsModal/EnvAutoSyncSettings.tsx | 166 ++++ .../src/components/SettingsModal/index.tsx | 49 ++ frontend/src/types/index.ts | 1 + rust-toolchain.toml | 2 + 53 files changed, 1366 insertions(+), 934 deletions(-) create mode 100644 crates/kftray-commons/src/utils/env_export.rs create mode 100644 crates/kftray-tauri/src/commands/env_export.rs create mode 100644 frontend/src/components/SettingsModal/EnvAutoSyncSettings.tsx create mode 100644 rust-toolchain.toml diff --git a/Cargo.lock b/Cargo.lock index 3488a360..be82edc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,7 +75,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb4e440d04be07da1f1bf44fb4495ebd58669372fe0cffa6e48595ac5bd88a3" dependencies = [ "android_log-sys", - "env_filter 0.1.4", + "env_filter", "log", ] @@ -140,9 +140,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.101" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arbitrary" @@ -162,11 +162,11 @@ dependencies = [ "clipboard-win", "image", "log", - "objc2 0.6.3", + "objc2", "objc2-app-kit", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation 0.3.1", + "objc2-foundation", "parking_lot", "percent-encoding", "windows-sys 0.60.2", @@ -204,7 +204,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", "synstructure", ] @@ -216,7 +216,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -312,7 +312,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -352,7 +352,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -369,7 +369,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -437,9 +437,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.37.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549" +checksum = "5c34dda4df7017c8db52132f0f8a2e0f8161649d15723ed63fc00c82d0f2081a" dependencies = [ "cc", "cmake", @@ -527,22 +527,13 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block2" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" -dependencies = [ - "objc2 0.5.2", -] - [[package]] name = "block2" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" dependencies = [ - "objc2 0.6.3", + "objc2", ] [[package]] @@ -578,7 +569,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -621,7 +612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c6d47a4e2961fb8721bcfc54feae6455f2f64e7054f9bc67e875f0e77f4c58d" dependencies = [ "rust_decimal", - "schemars 1.2.1", + "schemars 1.2.0", "serde", "utf8-width", ] @@ -650,9 +641,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" [[package]] name = "byteorder" @@ -668,9 +659,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.11.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" dependencies = [ "serde", ] @@ -739,7 +730,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" dependencies = [ "serde", - "toml 0.9.12+spec-1.1.0", + "toml 0.9.11+spec-1.1.0", ] [[package]] @@ -829,9 +820,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.58" +version = "4.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" +checksum = "a75ca66430e33a14957acc24c5077b503e7d374151b2b4b3a10c83b4ceb4be0e" dependencies = [ "clap_builder", "clap_derive", @@ -839,9 +830,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.58" +version = "4.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" +checksum = "793207c7fa6300a0608d1080b858e5fdbe713cdc1c8db9fb17777d8a13e63df0" dependencies = [ "anstream", "anstyle", @@ -858,14 +849,14 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] name = "clap_lex" -version = "1.0.0" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" +checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" [[package]] name = "clipboard-win" @@ -1198,7 +1189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1208,7 +1199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1235,7 +1226,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1269,7 +1260,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1282,7 +1273,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1293,7 +1284,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1304,7 +1295,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core 0.23.0", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1365,9 +1356,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.6" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", "serde_core", @@ -1381,7 +1372,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1394,7 +1385,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1416,7 +1407,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1463,9 +1454,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ "bitflags 2.10.0", - "block2 0.6.2", + "block2", "libc", - "objc2 0.6.3", + "objc2", ] [[package]] @@ -1476,7 +1467,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1499,7 +1490,7 @@ checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1599,7 +1590,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1620,7 +1611,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.9.12+spec-1.1.0", + "toml 0.9.11+spec-1.1.0", "vswhom", "winreg", ] @@ -1669,7 +1660,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1690,7 +1681,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1703,25 +1694,15 @@ dependencies = [ "regex", ] -[[package]] -name = "env_filter" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" -dependencies = [ - "log", - "regex", -] - [[package]] name = "env_logger" -version = "0.11.9" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ "anstream", "anstyle", - "env_filter 1.0.0", + "env_filter", "jiff", "log", ] @@ -1834,7 +1815,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -1929,9 +1910,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.9" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" dependencies = [ "crc32fast", "miniz_oxide", @@ -1993,7 +1974,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -2125,7 +2106,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -2345,9 +2326,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.20.4" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b" +checksum = "3e2b37e2f62729cdada11f0e6b3b6fe383c69c29fc619e391223e12856af308c" dependencies = [ "bitflags 2.10.0", "libc", @@ -2392,7 +2373,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -2419,7 +2400,7 @@ checksum = "b9247516746aa8e53411a0db9b62b0e24efbcf6a76e0ba73e5a91b512ddabed7" dependencies = [ "crossbeam-channel", "keyboard-types", - "objc2 0.6.3", + "objc2", "objc2-app-kit", "once_cell", "serde", @@ -2501,7 +2482,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -2739,7 +2720,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.6", + "webpki-roots 1.0.5", ] [[package]] @@ -2773,13 +2754,14 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.20" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", + "futures-core", "futures-util", "http", "http-body", @@ -2823,9 +2805,9 @@ dependencies = [ [[package]] name = "ico" -version = "0.5.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" +checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" dependencies = [ "byteorder", "png 0.17.16", @@ -3037,9 +3019,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.46.3" +version = "1.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82db8c87c7f1ccecb34ce0c24399b8a73081427f3c7c50a5d597925356115e4" +checksum = "248b42847813a1550dafd15296fd9748c651d0c32194559dbc05d804d54b21e8" dependencies = [ "console", "once_cell", @@ -3057,7 +3039,7 @@ dependencies = [ "indoc", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -3141,9 +3123,9 @@ dependencies = [ [[package]] name = "jiff" -version = "0.2.20" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c867c356cc096b33f4981825ab281ecba3db0acefe60329f044c1789d94c6543" +checksum = "e67e8da4c49d6d9909fe03361f9b620f58898859f5c7aded68351e85e71ecf50" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -3156,13 +3138,13 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.20" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7946b4325269738f270bb55b3c19ab5c5040525f83fd625259422a9d25d9be5" +checksum = "e0c84ee7f197eca9a86c6fd6cb771e55eb991632f15f2bc3ca6ec838929e6e78" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -3333,6 +3315,7 @@ name = "kftray-commons" version = "0.27.26" dependencies = [ "anyhow", + "chrono", "dirs", "futures", "git2", @@ -3571,7 +3554,7 @@ dependencies = [ "log", "ratatui", "ratatui-explorer", - "reqwest 0.13.2", + "reqwest 0.13.1", "self_update", "semver", "serde_json", @@ -3735,9 +3718,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.181" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libgit2-sys" @@ -3771,7 +3754,7 @@ checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ "bitflags 2.10.0", "libc", - "redox_syscall 0.7.1", + "redox_syscall 0.7.0", ] [[package]] @@ -3909,8 +3892,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65fd3f75411f4725061682ed91f131946e912859d0044d39c4ec0aac818d7621" dependencies = [ "cc", - "objc2 0.6.3", - "objc2-foundation 0.3.1", + "objc2", + "objc2-foundation", "time", ] @@ -3946,7 +3929,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -3966,9 +3949,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "memchr" -version = "2.8.0" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memmem" @@ -4048,7 +4031,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -4071,10 +4054,10 @@ dependencies = [ "dpi", "gtk", "keyboard-types", - "objc2 0.6.3", + "objc2", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.1", + "objc2-foundation", "once_cell", "png 0.17.16", "serde", @@ -4084,9 +4067,9 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.15" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cdede44f9a69cab2899a2049e2c3bd49bf911a157f6a3353d4a91c61abbce44" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ "libc", "log", @@ -4200,9 +4183,9 @@ dependencies = [ [[package]] name = "notify-rust" -version = "4.12.0" +version = "4.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21af20a1b50be5ac5861f74af1a863da53a11c38684d9818d82f1c42f7fdc6c2" +checksum = "6442248665a5aa2514e794af3b39661a8e73033b1cc5e59899e1276117ee4400" dependencies = [ "futures-lite", "log", @@ -4214,9 +4197,9 @@ dependencies = [ [[package]] name = "ntapi" -version = "0.4.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" +checksum = "c70f219e21142367c70c0b30c6a9e3a14d55b4d12a204d897fbec83a0363f081" dependencies = [ "winapi", ] @@ -4265,7 +4248,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -4305,7 +4288,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -4323,22 +4306,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" -[[package]] -name = "objc-sys" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" - -[[package]] -name = "objc2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" -dependencies = [ - "objc-sys", - "objc2-encode", -] - [[package]] name = "objc2" version = "0.6.3" @@ -4351,87 +4318,114 @@ dependencies = [ [[package]] name = "objc2-app-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ "bitflags 2.10.0", - "block2 0.6.2", + "block2", "libc", - "objc2 0.6.3", + "objc2", "objc2-cloud-kit", "objc2-core-data", "objc2-core-foundation", "objc2-core-graphics", "objc2-core-image", - "objc2-foundation 0.3.1", - "objc2-quartz-core 0.3.1", + "objc2-core-text", + "objc2-core-video", + "objc2-foundation", + "objc2-quartz-core", ] [[package]] name = "objc2-cloud-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-foundation 0.3.1", + "objc2", + "objc2-foundation", ] [[package]] name = "objc2-core-data" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" dependencies = [ "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-foundation 0.3.1", + "objc2", + "objc2-foundation", ] [[package]] name = "objc2-core-foundation" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags 2.10.0", "dispatch2", - "objc2 0.6.3", + "objc2", ] [[package]] name = "objc2-core-graphics" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ "bitflags 2.10.0", "dispatch2", - "objc2 0.6.3", + "objc2", "objc2-core-foundation", "objc2-io-surface", ] [[package]] name = "objc2-core-image" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" dependencies = [ - "objc2 0.6.3", - "objc2-foundation 0.3.1", + "objc2", + "objc2-foundation", ] [[package]] name = "objc2-core-location" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac0f75792558aa9d618443bbb5db7426a7a0b6fddf96903f86ef9ad02e135740" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" dependencies = [ - "objc2 0.6.3", - "objc2-foundation 0.3.1", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-core-video" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-io-surface", ] [[package]] @@ -4451,34 +4445,22 @@ dependencies = [ [[package]] name = "objc2-foundation" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" -dependencies = [ - "bitflags 2.10.0", - "block2 0.5.1", - "libc", - "objc2 0.5.2", -] - -[[package]] -name = "objc2-foundation" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.10.0", - "block2 0.6.2", + "block2", "libc", - "objc2 0.6.3", + "objc2", "objc2-core-foundation", ] [[package]] name = "objc2-io-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" dependencies = [ "libc", "objc2-core-foundation", @@ -4486,127 +4468,103 @@ dependencies = [ [[package]] name = "objc2-io-surface" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ "bitflags 2.10.0", - "objc2 0.6.3", + "objc2", "objc2-core-foundation", ] [[package]] name = "objc2-javascript-core" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9052cb1bb50a4c161d934befcf879526fb87ae9a68858f241e693ca46225cf5a" +checksum = "2a1e6550c4caed348956ce3370c9ffeca70bb1dbed4fa96112e7c6170e074586" dependencies = [ - "objc2 0.6.3", + "objc2", "objc2-core-foundation", ] -[[package]] -name = "objc2-metal" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" -dependencies = [ - "bitflags 2.10.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", -] - [[package]] name = "objc2-osa-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26bb88504b5a050dbba515d2414607bf5e57dd56b107bc5f0351197a3e7bdc5d" +checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0" dependencies = [ "bitflags 2.10.0", - "objc2 0.6.3", + "objc2", "objc2-app-kit", - "objc2-foundation 0.3.1", + "objc2-foundation", ] [[package]] name = "objc2-quartz-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" -dependencies = [ - "bitflags 2.10.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ "bitflags 2.10.0", - "objc2 0.6.3", + "objc2", "objc2-core-foundation", - "objc2-foundation 0.3.1", + "objc2-foundation", ] [[package]] name = "objc2-security" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1f8e0ef3ab66b08c42644dcb34dba6ec0a574bbd8adbb8bdbdc7a2779731a44" +checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" dependencies = [ "bitflags 2.10.0", - "objc2 0.6.3", + "objc2", "objc2-core-foundation", ] [[package]] name = "objc2-ui-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ "bitflags 2.10.0", - "block2 0.6.2", - "objc2 0.6.3", + "block2", + "objc2", "objc2-cloud-kit", "objc2-core-data", "objc2-core-foundation", "objc2-core-graphics", "objc2-core-image", "objc2-core-location", - "objc2-foundation 0.3.1", - "objc2-quartz-core 0.3.1", + "objc2-core-text", + "objc2-foundation", + "objc2-quartz-core", "objc2-user-notifications", ] [[package]] name = "objc2-user-notifications" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3f5ec77a81d9e0c5a0b32159b0cb143d7086165e79708351e02bf37dfc65cd" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" dependencies = [ - "objc2 0.6.3", - "objc2-foundation 0.3.1", + "objc2", + "objc2-foundation", ] [[package]] name = "objc2-web-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad" +checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" dependencies = [ "bitflags 2.10.0", - "block2 0.6.2", - "objc2 0.6.3", + "block2", + "objc2", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.1", + "objc2-foundation", "objc2-javascript-core", "objc2-security", ] @@ -4667,7 +4625,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -4747,8 +4705,8 @@ dependencies = [ "android_system_properties", "log", "nix 0.30.1", - "objc2 0.6.3", - "objc2-foundation 0.3.1", + "objc2", + "objc2-foundation", "objc2-ui-kit", "serde", "windows-sys 0.61.2", @@ -4770,8 +4728,8 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b" dependencies = [ - "objc2 0.6.3", - "objc2-foundation 0.3.1", + "objc2", + "objc2-foundation", "objc2-osa-kit", "serde", "serde_json", @@ -4856,9 +4814,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.6" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +checksum = "2c9eb05c21a464ea704b53158d358a31e6425db2f63a1a7312268b05fe2b75f7" dependencies = [ "memchr", "ucd-trie", @@ -4866,9 +4824,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.6" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" +checksum = "68f9dbced329c441fa79d80472764b1a2c7e57123553b8519b36663a2fb234ed" dependencies = [ "pest", "pest_generator", @@ -4876,22 +4834,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.6" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" +checksum = "3bb96d5051a78f44f43c8f712d8e810adb0ebf923fc9ed2655a7f66f63ba8ee5" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] name = "pest_meta" -version = "2.8.6" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" +checksum = "602113b5b5e8621770cfd490cfd90b9f84ab29bd2b0e49ad83eb6d186cef2365" dependencies = [ "pest", "sha2", @@ -5012,7 +4970,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -5059,7 +5017,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -5156,15 +5114,15 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" [[package]] name = "portable-atomic-util" -version = "0.2.5" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" dependencies = [ "portable-atomic", ] @@ -5210,9 +5168,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" -version = "3.1.4" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" dependencies = [ "anstyle", "predicates-core", @@ -5220,15 +5178,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.10" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" [[package]] name = "predicates-tree" -version = "1.0.13" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" dependencies = [ "predicates-core", "termtree", @@ -5241,7 +5199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -5710,9 +5668,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.7.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35985aa610addc02e24fc232012c86fd11f14111180f902b67e2d5331f8ebf2b" +checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" dependencies = [ "bitflags 2.10.0", ] @@ -5745,14 +5703,14 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] name = "regex" -version = "1.12.3" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -5762,9 +5720,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -5773,9 +5731,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.9" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rend" @@ -5824,27 +5782,28 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls", + "tokio-util", "tower", "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", - "webpki-roots 1.0.6", + "webpki-roots 1.0.5", ] [[package]] name = "reqwest" -version = "0.13.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" +checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62" dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", "futures-core", - "futures-util", "h2", "http", "http-body", @@ -5863,20 +5822,16 @@ dependencies = [ "rustls", "rustls-pki-types", "rustls-platform-verifier", - "serde", - "serde_json", "sync_wrapper", "tokio", "tokio-native-tls", "tokio-rustls", - "tokio-util", "tower", "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", "web-sys", ] @@ -5886,17 +5841,17 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672" dependencies = [ - "block2 0.6.2", + "block2", "dispatch2", "glib-sys", "gobject-sys", "gtk-sys", "js-sys", "log", - "objc2 0.6.3", + "objc2", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.1", + "objc2-foundation", "raw-window-handle", "wasm-bindgen", "wasm-bindgen-futures", @@ -6085,9 +6040,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.23" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" [[package]] name = "same-file" @@ -6136,9 +6091,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" dependencies = [ "dyn-clone", "ref-cast", @@ -6155,7 +6110,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -6326,7 +6281,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -6337,7 +6292,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -6361,7 +6316,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -6406,7 +6361,7 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.13.0", "schemars 0.9.0", - "schemars 1.2.1", + "schemars 1.2.0", "serde_core", "serde_json", "serde_with_macros", @@ -6422,7 +6377,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -6457,7 +6412,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -6602,9 +6557,9 @@ checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "slab" -version = "0.4.12" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" @@ -6624,24 +6579,24 @@ dependencies = [ [[package]] name = "softbuffer" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" dependencies = [ "bytemuck", - "cfg_aliases", - "core-graphics", - "foreign-types 0.5.0", "js-sys", - "log", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-quartz-core 0.2.2", + "ndk", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "objc2-quartz-core", "raw-window-handle", "redox_syscall 0.5.18", + "tracing", "wasm-bindgen", "web-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -6744,7 +6699,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -6765,7 +6720,7 @@ dependencies = [ "sha2", "sqlx-core", "sqlx-sqlite", - "syn 2.0.115", + "syn 2.0.114", "tokio", "url", ] @@ -6864,7 +6819,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -6897,9 +6852,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.115" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -6923,7 +6878,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -6937,9 +6892,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.38.1" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5792d209c2eac902426c0c4a166c9f72147db453af548cf9bf3242644c4d4fe3" +checksum = "fe840c5b1afe259a5657392a4dbb74473a14c8db999c3ec2f4ae812e028a94da" dependencies = [ "libc", "memchr", @@ -6951,9 +6906,9 @@ dependencies = [ [[package]] name = "system-configuration" -version = "0.7.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags 2.10.0", "core-foundation 0.9.4", @@ -7005,7 +6960,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3a753bdc39c07b192151523a3f77cd0394aa75413802c883a0f6f6a0e5ee2e7" dependencies = [ "bitflags 2.10.0", - "block2 0.6.2", + "block2", "core-foundation 0.10.1", "core-graphics", "crossbeam-channel", @@ -7021,9 +6976,9 @@ dependencies = [ "ndk", "ndk-context", "ndk-sys", - "objc2 0.6.3", + "objc2", "objc2-app-kit", - "objc2-foundation 0.3.1", + "objc2-foundation", "once_cell", "parking_lot", "raw-window-handle", @@ -7044,7 +6999,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -7072,9 +7027,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.10.2" +version = "2.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463ae8677aa6d0f063a900b9c41ecd4ac2b7ca82f0b058cc4491540e55b20129" +checksum = "8a3868da5508446a7cd08956d523ac3edf0a8bc20bf7e4038f9a95c2800d2033" dependencies = [ "anyhow", "bytes", @@ -7093,15 +7048,15 @@ dependencies = [ "log", "mime", "muda", - "objc2 0.6.3", + "objc2", "objc2-app-kit", - "objc2-foundation 0.3.1", + "objc2-foundation", "objc2-ui-kit", "objc2-web-kit", "percent-encoding", "plist", "raw-window-handle", - "reqwest 0.13.2", + "reqwest 0.12.28", "serde", "serde_json", "serde_repr", @@ -7124,9 +7079,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.5.5" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca7bd893329425df750813e95bd2b643d5369d929438da96d5bbb7cc2c918f74" +checksum = "17fcb8819fd16463512a12f531d44826ce566f486d7ccd211c9c8cebdaec4e08" dependencies = [ "anyhow", "cargo_toml", @@ -7140,15 +7095,15 @@ dependencies = [ "serde_json", "tauri-utils", "tauri-winres", - "toml 0.9.12+spec-1.1.0", + "toml 0.9.11+spec-1.1.0", "walkdir", ] [[package]] name = "tauri-codegen" -version = "2.5.4" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac423e5859d9f9ccdd32e3cf6a5866a15bedbf25aa6630bcb2acde9468f6ae3" +checksum = "9fa9844cefcf99554a16e0a278156ae73b0d8680bbc0e2ad1e4287aadd8489cf" dependencies = [ "base64 0.22.1", "ico", @@ -7161,7 +7116,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "syn 2.0.115", + "syn 2.0.114", "tauri-utils", "thiserror 2.0.18", "time", @@ -7172,23 +7127,23 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.5.4" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6a1bd2861ff0c8766b1d38b32a6a410f6dc6532d4ef534c47cfb2236092f59" +checksum = "3764a12f886d8245e66b7ee9b43ccc47883399be2019a61d80cf0f4117446fde" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", "tauri-codegen", "tauri-utils", ] [[package]] name = "tauri-plugin" -version = "2.5.3" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692a77abd8b8773e107a42ec0e05b767b8d2b7ece76ab36c6c3947e34df9f53f" +checksum = "0e1d0a4860b7ff570c891e1d2a586bf1ede205ff858fbc305e0b5ae5d14c1377" dependencies = [ "anyhow", "glob", @@ -7197,7 +7152,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "toml 0.9.12+spec-1.1.0", + "toml 0.9.11+spec-1.1.0", "walkdir", ] @@ -7252,7 +7207,7 @@ dependencies = [ "tauri-plugin", "tauri-utils", "thiserror 2.0.18", - "toml 0.9.12+spec-1.1.0", + "toml 0.9.11+spec-1.1.0", "url", ] @@ -7273,9 +7228,9 @@ dependencies = [ [[package]] name = "tauri-plugin-http" -version = "2.5.7" +version = "2.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8f069451c4e87e7e2636b7f065a4c52866c4ce5e60e2d53fa1038edb6d184dc" +checksum = "68bef611ccbfbce67c813959c11b23c1c084d201aa94222de9eba5f9edc3f897" dependencies = [ "bytes", "cookie_store 0.21.1", @@ -7305,8 +7260,8 @@ dependencies = [ "byte-unit", "fern", "log", - "objc2 0.6.3", - "objc2-foundation 0.3.1", + "objc2", + "objc2-foundation", "serde", "serde_json", "serde_repr", @@ -7381,9 +7336,9 @@ dependencies = [ [[package]] name = "tauri-plugin-shell" -version = "2.3.5" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8457dbf9e2bab1edd8df22bb2c20857a59a9868e79cb3eac5ed639eec4d0c73b" +checksum = "39b76f884a3937e04b631ffdc3be506088fa979369d25147361352f2f352e5ed" dependencies = [ "encoding_rs", "log", @@ -7402,9 +7357,9 @@ dependencies = [ [[package]] name = "tauri-plugin-updater" -version = "2.10.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fe8e9bebd88fc222938ffdfbdcfa0307081423bd01e3252fc337d8bde81fc61" +checksum = "27cbc31740f4d507712550694749572ec0e43bdd66992db7599b89fbfd6b167b" dependencies = [ "base64 0.22.1", "dirs", @@ -7416,8 +7371,7 @@ dependencies = [ "minisign-verify", "osakit", "percent-encoding", - "reqwest 0.13.2", - "rustls", + "reqwest 0.12.28", "semver", "serde", "serde_json", @@ -7435,16 +7389,16 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.10.0" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b885ffeac82b00f1f6fd292b6e5aabfa7435d537cef57d11e38a489956535651" +checksum = "87f766fe9f3d1efc4b59b17e7a891ad5ed195fa8d23582abb02e6c9a01137892" dependencies = [ "cookie", "dpi", "gtk", "http", "jni", - "objc2 0.6.3", + "objc2", "objc2-ui-kit", "objc2-web-kit", "raw-window-handle", @@ -7460,17 +7414,17 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "2.10.0" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5204682391625e867d16584fedc83fc292fb998814c9f7918605c789cd876314" +checksum = "187a3f26f681bdf028f796ccf57cf478c1ee422c50128e5a0a6ebeb3f5910065" dependencies = [ "gtk", "http", "jni", "log", - "objc2 0.6.3", + "objc2", "objc2-app-kit", - "objc2-foundation 0.3.1", + "objc2-foundation", "once_cell", "percent-encoding", "raw-window-handle", @@ -7487,9 +7441,9 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.8.2" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcd169fccdff05eff2c1033210b9b94acd07a47e6fa9a3431cf09cfd4f01c87e" +checksum = "76a423c51176eb3616ee9b516a9fa67fed5f0e78baaba680e44eb5dd2cc37490" dependencies = [ "anyhow", "cargo_metadata", @@ -7515,7 +7469,7 @@ dependencies = [ "serde_with", "swift-rs", "thiserror 2.0.18", - "toml 0.9.12+spec-1.1.0", + "toml 0.9.11+spec-1.1.0", "url", "urlpattern", "uuid", @@ -7530,7 +7484,7 @@ checksum = "1087b111fe2b005e42dbdc1990fc18593234238d47453b0c99b7de1c9ab2c1e0" dependencies = [ "dunce", "embed-resource", - "toml 0.9.12+spec-1.1.0", + "toml 0.9.11+spec-1.1.0", ] [[package]] @@ -7547,12 +7501,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.25.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" dependencies = [ "fastrand", - "getrandom 0.4.1", + "getrandom 0.3.4", "once_cell", "rustix", "windows-sys 0.61.2", @@ -7664,7 +7618,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -7675,7 +7629,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -7712,9 +7666,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" dependencies = [ "deranged", "itoa", @@ -7735,9 +7689,9 @@ checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" dependencies = [ "num-conv", "time-core", @@ -7793,7 +7747,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -7885,9 +7839,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.12+spec-1.1.0" +version = "0.9.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" dependencies = [ "indexmap 2.13.0", "serde_core", @@ -7954,9 +7908,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.8+spec-1.1.0" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0742ff5ff03ea7e67c8ae6c93cac239e0d9784833362da3f9a9c1da8dfefcbdc" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" dependencies = [ "winnow 0.7.14", ] @@ -8051,7 +8005,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -8103,11 +8057,11 @@ dependencies = [ "dirs", "libappindicator", "muda", - "objc2 0.6.3", + "objc2", "objc2-app-kit", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation 0.3.1", + "objc2-foundation", "once_cell", "png 0.17.16", "serde", @@ -8139,7 +8093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9384df20a5244a6ab204bc4b6959b41f37f0ee7b5e0f2feb7a8a78f58e684d06" dependencies = [ "chrono", - "env_filter 0.1.4", + "env_filter", "lazy_static", "log", "parking_lot", @@ -8249,9 +8203,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.23" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" @@ -8543,7 +8497,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", "wasm-bindgen-shared", ] @@ -8580,9 +8534,9 @@ dependencies = [ [[package]] name = "wasm-streams" -version = "0.5.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", @@ -8695,9 +8649,9 @@ dependencies = [ [[package]] name = "webkit2gtk" -version = "2.0.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" +checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" dependencies = [ "bitflags 1.3.2", "cairo-rs", @@ -8719,9 +8673,9 @@ dependencies = [ [[package]] name = "webkit2gtk-sys" -version = "2.0.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" +checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" dependencies = [ "bitflags 1.3.2", "cairo-sys-rs", @@ -8739,9 +8693,9 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.6" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" +checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" dependencies = [ "rustls-pki-types", ] @@ -8752,14 +8706,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.6", + "webpki-roots 1.0.5", ] [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" dependencies = [ "rustls-pki-types", ] @@ -8786,7 +8740,7 @@ checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -8932,10 +8886,10 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" dependencies = [ - "objc2 0.6.3", + "objc2", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.1", + "objc2-foundation", "raw-window-handle", "windows-sys 0.59.0", "windows-version", @@ -9040,7 +8994,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -9051,7 +9005,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -9460,7 +9414,7 @@ dependencies = [ "heck 0.5.0", "indexmap 2.13.0", "prettyplease", - "syn 2.0.115", + "syn 2.0.114", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -9476,7 +9430,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -9544,12 +9498,12 @@ checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "wry" -version = "0.54.1" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ed1a195b0375491dd15a7066a10251be217ce743cf4bbbbdcf5391d6473bee0" +checksum = "728b7d4c8ec8d81cab295e0b5b8a4c263c0d41a785fb8f8c4df284e5411140a2" dependencies = [ "base64 0.22.1", - "block2 0.6.2", + "block2", "cookie", "crossbeam-channel", "dirs", @@ -9563,10 +9517,10 @@ dependencies = [ "kuchikiki", "libc", "ndk", - "objc2 0.6.3", + "objc2", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.1", + "objc2-foundation", "objc2-ui-kit", "objc2-web-kit", "once_cell", @@ -9613,9 +9567,9 @@ checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" [[package]] name = "x509-parser" -version = "0.18.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" +checksum = "eb3e137310115a65136898d2079f003ce33331a6c4b0d51f1531d1be082b6425" dependencies = [ "asn1-rs", "data-encoding", @@ -9673,7 +9627,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", "synstructure", ] @@ -9721,7 +9675,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", "zbus_names", "zvariant", "zvariant_utils", @@ -9740,22 +9694,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.39" +version = "0.8.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +checksum = "7456cf00f0685ad319c5b1693f291a650eaf345e941d082fc4e03df8a03996ac" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.39" +version = "0.8.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +checksum = "1328722bbf2115db7e19d69ebcc15e795719e2d66b60827c6a69a117365e37a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -9775,7 +9729,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", "synstructure", ] @@ -9815,7 +9769,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", ] [[package]] @@ -9843,9 +9797,9 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439" [[package]] name = "zune-core" @@ -9885,7 +9839,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.114", "zvariant_utils", ] @@ -9898,6 +9852,6 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.115", + "syn 2.0.114", "winnow 0.7.14", ] diff --git a/crates/kftray-commons/Cargo.toml b/crates/kftray-commons/Cargo.toml index 2a1f7cce..cc756934 100644 --- a/crates/kftray-commons/Cargo.toml +++ b/crates/kftray-commons/Cargo.toml @@ -14,6 +14,7 @@ path = "src/lib.rs" [dependencies] anyhow = { workspace = true } +chrono = { workspace = true } dirs = { workspace = true } futures = { workspace = true } git2 = { workspace = true } diff --git a/crates/kftray-commons/src/models/config_model.rs b/crates/kftray-commons/src/models/config_model.rs index 2a2f3a36..c0f0e2e5 100644 --- a/crates/kftray-commons/src/models/config_model.rs +++ b/crates/kftray-commons/src/models/config_model.rs @@ -1,8 +1,4 @@ -use serde::{ - Deserialize, - Deserializer, - Serialize, -}; +use serde::{Deserialize, Deserializer, Serialize}; fn deserialize_bool_from_anything<'de, D>(deserializer: D) -> Result, D::Error> where @@ -10,10 +6,7 @@ where { use std::fmt; - use serde::de::{ - self, - Visitor, - }; + use serde::de::{self, Visitor}; struct BoolOrStringVisitor; diff --git a/crates/kftray-commons/src/models/config_state_model.rs b/crates/kftray-commons/src/models/config_state_model.rs index 3643668a..64dfa079 100644 --- a/crates/kftray-commons/src/models/config_state_model.rs +++ b/crates/kftray-commons/src/models/config_state_model.rs @@ -1,7 +1,4 @@ -use serde::{ - Deserialize, - Serialize, -}; +use serde::{Deserialize, Serialize}; #[derive(Clone, Deserialize, PartialEq, Serialize, Debug)] pub struct ConfigState { diff --git a/crates/kftray-commons/src/models/hostfile.rs b/crates/kftray-commons/src/models/hostfile.rs index 344b9590..77c1046e 100644 --- a/crates/kftray-commons/src/models/hostfile.rs +++ b/crates/kftray-commons/src/models/hostfile.rs @@ -1,9 +1,6 @@ use std::net::IpAddr; -use serde::{ - Deserialize, - Serialize, -}; +use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct HostEntry { diff --git a/crates/kftray-commons/src/models/http_logs_config_model.rs b/crates/kftray-commons/src/models/http_logs_config_model.rs index c78e023e..81def34f 100644 --- a/crates/kftray-commons/src/models/http_logs_config_model.rs +++ b/crates/kftray-commons/src/models/http_logs_config_model.rs @@ -1,7 +1,4 @@ -use serde::{ - Deserialize, - Serialize, -}; +use serde::{Deserialize, Serialize}; #[derive(Clone, Deserialize, PartialEq, Serialize, Debug)] pub struct HttpLogsConfig { diff --git a/crates/kftray-commons/src/models/settings_model.rs b/crates/kftray-commons/src/models/settings_model.rs index 4aaa0127..7fb418fc 100644 --- a/crates/kftray-commons/src/models/settings_model.rs +++ b/crates/kftray-commons/src/models/settings_model.rs @@ -1,7 +1,4 @@ -use serde::{ - Deserialize, - Serialize, -}; +use serde::{Deserialize, Serialize}; #[derive(Clone, Deserialize, Serialize, Debug)] pub struct AppSettings { @@ -40,6 +37,12 @@ pub struct AppSettings { #[serde(default = "default_global_shortcut")] pub global_shortcut: String, + + #[serde(default = "default_env_auto_sync_enabled")] + pub env_auto_sync_enabled: bool, + + #[serde(default)] + pub env_auto_sync_path: String, } fn default_network_monitor() -> bool { @@ -73,6 +76,10 @@ fn default_global_shortcut() -> String { return "Ctrl+Shift+F1".to_string(); } +fn default_env_auto_sync_enabled() -> bool { + true +} + impl Default for AppSettings { fn default() -> Self { Self { @@ -88,11 +95,15 @@ impl Default for AppSettings { ssl_auto_regenerate: default_ssl_auto_regenerate(), ssl_ca_auto_install: false, global_shortcut: default_global_shortcut(), + env_auto_sync_enabled: default_env_auto_sync_enabled(), + env_auto_sync_path: String::new(), } } } impl AppSettings { + /// Creates an `AppSettings` instance from a settings key-value map. + /// Missing keys use default values defined in `AppSettings::default()`. pub fn from_settings_manager(settings: &std::collections::HashMap) -> Self { let mut app_settings = AppSettings::default(); @@ -144,9 +155,18 @@ impl AppSettings { app_settings.global_shortcut = value.clone(); } + if let Some(value) = settings.get("env_auto_sync_enabled") { + app_settings.env_auto_sync_enabled = value.parse().unwrap_or(false); + } + + if let Some(value) = settings.get("env_auto_sync_path") { + app_settings.env_auto_sync_path = value.clone(); + } + app_settings } + /// Converts this `AppSettings` instance to a key-value map for database storage. pub fn to_settings_map(&self) -> std::collections::HashMap { let mut settings = std::collections::HashMap::new(); @@ -193,6 +213,14 @@ impl AppSettings { self.ssl_ca_auto_install.to_string(), ); settings.insert("global_shortcut".to_string(), self.global_shortcut.clone()); + settings.insert( + "env_auto_sync_enabled".to_string(), + self.env_auto_sync_enabled.to_string(), + ); + settings.insert( + "env_auto_sync_path".to_string(), + self.env_auto_sync_path.clone(), + ); settings } diff --git a/crates/kftray-commons/src/models/tunnel_protocol.rs b/crates/kftray-commons/src/models/tunnel_protocol.rs index 7f4adcb3..37f07af0 100644 --- a/crates/kftray-commons/src/models/tunnel_protocol.rs +++ b/crates/kftray-commons/src/models/tunnel_protocol.rs @@ -1,9 +1,6 @@ use std::collections::HashMap; -use serde::{ - Deserialize, - Serialize, -}; +use serde::{Deserialize, Serialize}; /// Messages sent over WebSocket tunnel #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/crates/kftray-commons/src/models/window.rs b/crates/kftray-commons/src/models/window.rs index 2a7375cc..2acfada7 100644 --- a/crates/kftray-commons/src/models/window.rs +++ b/crates/kftray-commons/src/models/window.rs @@ -1,10 +1,7 @@ use std::sync::Arc; use std::sync::atomic::AtomicBool; -use serde::{ - Deserialize, - Serialize, -}; +use serde::{Deserialize, Serialize}; use tokio::runtime::Runtime; pub struct SaveDialogState { diff --git a/crates/kftray-commons/src/utils/config.rs b/crates/kftray-commons/src/utils/config.rs index b7b8b0d3..b1b89cd3 100644 --- a/crates/kftray-commons/src/utils/config.rs +++ b/crates/kftray-commons/src/utils/config.rs @@ -1,26 +1,14 @@ use futures::stream::StreamExt; -use log::{ - error, - info, -}; +use log::{error, info}; use portpicker::pick_unused_port; use serde_json::json; -use sqlx::{ - Row, - SqlitePool, -}; - -use crate::db::{ - create_db_table, - get_db_pool, -}; +use sqlx::{Row, SqlitePool}; + +use crate::db::{create_db_table, get_db_pool}; use crate::hostsfile::HostsFile; use crate::migration::migrate_configs; use crate::models::config_model::Config; -use crate::utils::db_mode::{ - DatabaseManager, - DatabaseMode, -}; +use crate::utils::db_mode::{DatabaseManager, DatabaseMode}; use crate::utils::error::DbError; pub async fn delete_config_with_pool(id: i64, pool: &SqlitePool) -> Result<(), DbError> { @@ -739,10 +727,7 @@ mod tests { use std::collections::BTreeMap; use lazy_static::lazy_static; - use serde_json::{ - Value, - json, - }; + use serde_json::{Value, json}; use sqlx::SqlitePool; use tokio::sync::Mutex; diff --git a/crates/kftray-commons/src/utils/config_dir.rs b/crates/kftray-commons/src/utils/config_dir.rs index 544e0670..d8e4fc55 100644 --- a/crates/kftray-commons/src/utils/config_dir.rs +++ b/crates/kftray-commons/src/utils/config_dir.rs @@ -1,8 +1,4 @@ -use std::{ - env, - fs, - path::PathBuf, -}; +use std::{env, fs, path::PathBuf}; use anyhow::Result; diff --git a/crates/kftray-commons/src/utils/config_state.rs b/crates/kftray-commons/src/utils/config_state.rs index 0a6795cc..63a22fa6 100644 --- a/crates/kftray-commons/src/utils/config_state.rs +++ b/crates/kftray-commons/src/utils/config_state.rs @@ -1,15 +1,9 @@ use log::error; -use sqlx::{ - Row, - SqlitePool, -}; +use sqlx::{Row, SqlitePool}; use crate::db::get_db_pool; use crate::models::config_state_model::ConfigState; -use crate::utils::db_mode::{ - DatabaseManager, - DatabaseMode, -}; +use crate::utils::db_mode::{DatabaseManager, DatabaseMode}; pub async fn update_config_state_with_pool( config_state: &ConfigState, pool: &SqlitePool, diff --git a/crates/kftray-commons/src/utils/db.rs b/crates/kftray-commons/src/utils/db.rs index 69ff3d6e..032c230a 100644 --- a/crates/kftray-commons/src/utils/db.rs +++ b/crates/kftray-commons/src/utils/db.rs @@ -1,34 +1,21 @@ -use std::fs::{ - self, - File, -}; +use std::fs::{self, File}; use std::io::Write; use std::path::Path; use std::sync::Arc; use std::sync::Mutex; use lazy_static::lazy_static; -use log::{ - error, - info, -}; +use log::{error, info}; use serde_json::json; use sqlx::SqlitePool; use tokio::sync::OnceCell; -use crate::config_dir::{ - get_db_file_path, - get_pod_manifest_path, -}; +use crate::config_dir::{get_db_file_path, get_pod_manifest_path}; use crate::utils::manifests::{ - create_expose_deployment_manifest, - create_expose_ingress_manifest, - create_expose_service_manifest, - create_proxy_deployment_manifest, - expose_deployment_manifest_exists, - expose_ingress_manifest_exists, - expose_service_manifest_exists, - proxy_deployment_manifest_exists, + create_expose_deployment_manifest, create_expose_ingress_manifest, + create_expose_service_manifest, create_proxy_deployment_manifest, + expose_deployment_manifest_exists, expose_ingress_manifest_exists, + expose_service_manifest_exists, proxy_deployment_manifest_exists, }; lazy_static! { @@ -297,10 +284,7 @@ fn create_db_file() -> Result<(), std::io::Error> { #[cfg(test)] mod tests { use std::env; - use std::fs::{ - self, - File, - }; + use std::fs::{self, File}; use std::sync::Mutex; use lazy_static::lazy_static; @@ -308,11 +292,7 @@ mod tests { use tempfile::tempdir; use super::*; - use crate::config_dir::{ - get_config_dir, - get_db_file_path, - get_pod_manifest_path, - }; + use crate::config_dir::{get_config_dir, get_db_file_path, get_pod_manifest_path}; lazy_static! { static ref ENV_TEST_MUTEX: Mutex<()> = Mutex::new(()); diff --git a/crates/kftray-commons/src/utils/db_mode.rs b/crates/kftray-commons/src/utils/db_mode.rs index b145a5c5..69948e1b 100644 --- a/crates/kftray-commons/src/utils/db_mode.rs +++ b/crates/kftray-commons/src/utils/db_mode.rs @@ -1,15 +1,9 @@ use std::sync::Arc; -use std::sync::{ - LazyLock, - Mutex, -}; +use std::sync::{LazyLock, Mutex}; use sqlx::SqlitePool; -use crate::db::{ - create_db_table, - get_db_pool, -}; +use crate::db::{create_db_table, get_db_pool}; #[derive(Debug, Clone, PartialEq, Default, Copy)] pub enum DatabaseMode { diff --git a/crates/kftray-commons/src/utils/env_export.rs b/crates/kftray-commons/src/utils/env_export.rs new file mode 100644 index 00000000..49faba1c --- /dev/null +++ b/crates/kftray-commons/src/utils/env_export.rs @@ -0,0 +1,396 @@ +use std::collections::HashSet; + +use chrono::Utc; +use log::{error, info}; +use sqlx::SqlitePool; + +use crate::db::get_db_pool; +use crate::models::config_model::Config; +use crate::utils::config::read_configs_with_pool; +use crate::utils::config_state::read_config_states_with_pool; +use crate::utils::settings::{get_env_auto_sync_enabled, get_env_auto_sync_path}; + +/// Generate .env file content from active port-forward configs +pub async fn generate_env_content(running_only: bool) -> Result { + let pool = get_db_pool().await.map_err(|e| e.to_string())?; + generate_env_content_with_pool(&pool, running_only).await +} + +/// Generate .env file content from active port-forward configs using a specific pool +pub async fn generate_env_content_with_pool( + pool: &SqlitePool, running_only: bool, +) -> Result { + let configs = read_configs_with_pool(pool).await?; + let states = read_config_states_with_pool(pool) + .await + .map_err(|e| e.to_string())?; + + // Build a set of running config IDs + let running_ids: HashSet = states + .iter() + .filter(|s| s.is_running) + .map(|s| s.config_id) + .collect(); + + // Filter configs if running_only is true + let filtered_configs: Vec<&Config> = configs + .iter() + .filter(|c| { + if running_only { + c.id.map(|id| running_ids.contains(&id)).unwrap_or(false) + } else { + true + } + }) + .collect(); + + // Detect duplicate names to append namespace for disambiguation + let mut name_counts: std::collections::HashMap = + std::collections::HashMap::new(); + for config in &filtered_configs { + let name = derive_env_var_name(config); + *name_counts.entry(name).or_insert(0) += 1; + } + + let mut lines = Vec::new(); + + // Add header + lines.push("# Generated by kftray".to_string()); + lines.push(format!( + "# Updated: {}", + Utc::now().format("%Y-%m-%dT%H:%M:%SZ") + )); + lines.push(String::new()); + + // Generate entries for each config + for config in &filtered_configs { + let base_name = derive_env_var_name(config); + + // Append namespace if there are duplicates + let var_name = if name_counts.get(&base_name).copied().unwrap_or(0) > 1 { + let namespace = sanitize_env_var_name(&config.namespace); + if namespace.is_empty() { + base_name + } else { + format!("{base_name}_{namespace}") + } + } else { + base_name + }; + + let host = config + .local_address + .as_deref() + .unwrap_or("127.0.0.1") + .to_string(); + let port = config.local_port.unwrap_or(0); + + lines.push(format!("{var_name}_HOST={host}")); + lines.push(format!("{var_name}_PORT={port}")); + } + + Ok(lines.join("\n")) +} + +/// Derive environment variable name from config +/// Priority: alias > service > target +fn derive_env_var_name(config: &Config) -> String { + let name = config + .alias + .as_deref() + .filter(|s| !s.is_empty()) + .or_else(|| config.service.as_deref().filter(|s| !s.is_empty())) + .or_else(|| config.target.as_deref().filter(|s| !s.is_empty())) + .unwrap_or("unknown"); + + sanitize_env_var_name(name) +} + +/// Write .env file if auto-sync is enabled and path is configured. +/// This is called from the port-forward state change detection loop. +pub async fn write_env_file_if_enabled() -> Result<(), String> { + let enabled = match get_env_auto_sync_enabled().await { + Ok(v) => { + info!("env_auto_sync_enabled from DB: {}", v); + v + } + Err(e) => { + error!("Failed to get env_auto_sync_enabled: {}", e); + return Ok(()); + } + }; + + if !enabled { + info!("Env auto-sync is disabled, skipping"); + return Ok(()); + } + + let path = match get_env_auto_sync_path().await { + Ok(p) => { + info!("env_auto_sync_path from DB: {:?}", p); + p + } + Err(e) => { + error!("Failed to get env_auto_sync_path: {}", e); + return Ok(()); + } + }; + + let Some(file_path) = path else { + info!("Env auto-sync enabled but no path configured"); + return Ok(()); + }; + + let content = generate_env_content(true).await?; + let line_count = content.lines().count(); + info!( + "Writing .env file to {} ({} lines, {} bytes)", + file_path, + line_count, + content.len() + ); + + std::fs::write(&file_path, &content).map_err(|e| { + error!("Failed to write .env file to {}: {}", file_path, e); + e.to_string() + })?; + + info!("Auto-synced .env file to {}", file_path); + Ok(()) +} + +/// Sanitize a string to be a valid environment variable name +/// - Convert to uppercase +/// - Replace invalid characters (dashes, dots, spaces) with underscores +/// - Remove any other non-alphanumeric characters except underscore +fn sanitize_env_var_name(name: &str) -> String { + name.to_uppercase() + .chars() + .map(|c| { + if c.is_ascii_alphanumeric() || c == '_' { + c + } else if c == '-' || c == '.' || c == ' ' { + '_' + } else { + '\0' // Will be filtered out + } + }) + .filter(|&c| c != '\0') + .collect() +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::db::create_db_table; + use crate::migration::migrate_configs; + use crate::models::config_state_model::ConfigState; + use crate::utils::config::insert_config_with_pool; + use crate::utils::config_state::update_config_state_with_pool; + + async fn setup_test_db() -> SqlitePool { + let pool = SqlitePool::connect("sqlite::memory:") + .await + .expect("Failed to connect to in-memory database"); + create_db_table(&pool) + .await + .expect("Failed to create tables"); + migrate_configs(Some(&pool)) + .await + .expect("Failed to run migrations"); + pool + } + + #[test] + fn test_sanitize_env_var_name() { + assert_eq!(sanitize_env_var_name("postgres"), "POSTGRES"); + assert_eq!(sanitize_env_var_name("my-service"), "MY_SERVICE"); + assert_eq!(sanitize_env_var_name("my.service"), "MY_SERVICE"); + assert_eq!(sanitize_env_var_name("my service"), "MY_SERVICE"); + assert_eq!(sanitize_env_var_name("Service_Name"), "SERVICE_NAME"); + assert_eq!(sanitize_env_var_name("test@#$%name"), "TESTNAME"); + } + + #[test] + fn test_derive_env_var_name_alias_priority() { + let config = Config { + alias: Some("my-alias".to_string()), + service: Some("my-service".to_string()), + target: Some("my-target".to_string()), + ..Config::default() + }; + assert_eq!(derive_env_var_name(&config), "MY_ALIAS"); + } + + #[test] + fn test_derive_env_var_name_service_fallback() { + let config = Config { + alias: None, + service: Some("my-service".to_string()), + target: Some("my-target".to_string()), + ..Config::default() + }; + assert_eq!(derive_env_var_name(&config), "MY_SERVICE"); + } + + #[test] + fn test_derive_env_var_name_target_fallback() { + let config = Config { + alias: None, + service: None, + target: Some("my-target".to_string()), + ..Config::default() + }; + assert_eq!(derive_env_var_name(&config), "MY_TARGET"); + } + + #[test] + fn test_derive_env_var_name_empty_alias_fallback() { + let config = Config { + alias: Some("".to_string()), + service: Some("my-service".to_string()), + target: None, + ..Config::default() + }; + assert_eq!(derive_env_var_name(&config), "MY_SERVICE"); + } + + #[tokio::test] + async fn test_generate_env_content_empty() { + let pool = setup_test_db().await; + let content = generate_env_content_with_pool(&pool, true).await.unwrap(); + + assert!(content.contains("# Generated by kftray")); + assert!(content.contains("# Updated:")); + } + + #[tokio::test] + async fn test_generate_env_content_with_running_config() { + let pool = setup_test_db().await; + + // Insert a config + let config = Config { + alias: Some("postgres".to_string()), + service: Some("postgres-service".to_string()), + local_address: Some("127.0.0.1".to_string()), + local_port: Some(5432), + namespace: "default".to_string(), + workload_type: Some("service".to_string()), + protocol: "tcp".to_string(), + ..Config::default() + }; + + insert_config_with_pool(config, &pool).await.unwrap(); + + // Get the config ID + let configs = crate::utils::config::read_configs_with_pool(&pool) + .await + .unwrap(); + let config_id = configs[0].id.unwrap(); + + // Mark it as running + let state = ConfigState { + id: None, + config_id, + is_running: true, + process_id: Some(1234), + }; + update_config_state_with_pool(&state, &pool).await.unwrap(); + + // Generate env content + let content = generate_env_content_with_pool(&pool, true).await.unwrap(); + + assert!(content.contains("POSTGRES_HOST=127.0.0.1")); + assert!(content.contains("POSTGRES_PORT=5432")); + } + + #[tokio::test] + async fn test_generate_env_content_excludes_non_running() { + let pool = setup_test_db().await; + + // Insert a config but don't mark it as running + let config = Config { + alias: Some("redis".to_string()), + service: Some("redis-service".to_string()), + local_address: Some("127.0.0.1".to_string()), + local_port: Some(6379), + namespace: "default".to_string(), + workload_type: Some("service".to_string()), + protocol: "tcp".to_string(), + ..Config::default() + }; + + insert_config_with_pool(config, &pool).await.unwrap(); + + // Generate env content with running_only=true + let content = generate_env_content_with_pool(&pool, true).await.unwrap(); + + // Should not contain redis entries since it's not running + assert!(!content.contains("REDIS_HOST")); + assert!(!content.contains("REDIS_PORT")); + } + + #[tokio::test] + async fn test_generate_env_content_includes_all_when_not_running_only() { + let pool = setup_test_db().await; + + // Insert a config but don't mark it as running + let config = Config { + alias: Some("redis".to_string()), + service: Some("redis-service".to_string()), + local_address: Some("127.0.0.1".to_string()), + local_port: Some(6379), + namespace: "default".to_string(), + workload_type: Some("service".to_string()), + protocol: "tcp".to_string(), + ..Config::default() + }; + + insert_config_with_pool(config, &pool).await.unwrap(); + + // Generate env content with running_only=false + let content = generate_env_content_with_pool(&pool, false).await.unwrap(); + + // Should contain redis entries even though it's not running + assert!(content.contains("REDIS_HOST=127.0.0.1")); + assert!(content.contains("REDIS_PORT=6379")); + } + + #[tokio::test] + async fn test_generate_env_content_duplicate_names() { + let pool = setup_test_db().await; + + // Insert two configs with the same alias but different namespaces + let config1 = Config { + alias: Some("postgres".to_string()), + service: Some("postgres-service".to_string()), + local_address: Some("127.0.0.1".to_string()), + local_port: Some(5432), + namespace: "production".to_string(), + workload_type: Some("service".to_string()), + protocol: "tcp".to_string(), + ..Config::default() + }; + + let config2 = Config { + alias: Some("postgres".to_string()), + service: Some("postgres-service".to_string()), + local_address: Some("127.0.0.1".to_string()), + local_port: Some(5433), + namespace: "staging".to_string(), + workload_type: Some("service".to_string()), + protocol: "tcp".to_string(), + ..Config::default() + }; + + insert_config_with_pool(config1, &pool).await.unwrap(); + insert_config_with_pool(config2, &pool).await.unwrap(); + + // Generate env content with running_only=false + let content = generate_env_content_with_pool(&pool, false).await.unwrap(); + + // Should contain namespaced entries to disambiguate + assert!(content.contains("POSTGRES_PRODUCTION_HOST")); + assert!(content.contains("POSTGRES_STAGING_HOST")); + } +} diff --git a/crates/kftray-commons/src/utils/github.rs b/crates/kftray-commons/src/utils/github.rs index c8ce4cb8..74391ebe 100644 --- a/crates/kftray-commons/src/utils/github.rs +++ b/crates/kftray-commons/src/utils/github.rs @@ -1,17 +1,10 @@ use std::path::Path; -use log::{ - error, - info, - warn, -}; +use log::{error, info, warn}; use sqlx::SqlitePool; use crate::db::get_db_pool; -use crate::utils::db_mode::{ - DatabaseManager, - DatabaseMode, -}; +use crate::utils::db_mode::{DatabaseManager, DatabaseMode}; pub struct GitHubConfig { pub repo_url: String, @@ -42,11 +35,7 @@ impl GitHubRepository { github_token: Option, ) -> GitHubResult { use git2::{ - CertificateCheckStatus, - Cred, - FetchOptions, - RemoteCallbacks, - build::RepoBuilder, + CertificateCheckStatus, Cred, FetchOptions, RemoteCallbacks, build::RepoBuilder, }; use tempfile::TempDir; diff --git a/crates/kftray-commons/src/utils/hostsfile.rs b/crates/kftray-commons/src/utils/hostsfile.rs index 09d0b631..ecb61dc9 100644 --- a/crates/kftray-commons/src/utils/hostsfile.rs +++ b/crates/kftray-commons/src/utils/hostsfile.rs @@ -2,21 +2,10 @@ use std::{ collections::BTreeMap, fmt, fs::OpenOptions, - io::{ - self, - BufRead, - BufReader, - Write, - }, + io::{self, BufRead, BufReader, Write}, net::IpAddr, - path::{ - Path, - PathBuf, - }, - time::{ - SystemTime, - UNIX_EPOCH, - }, + path::{Path, PathBuf}, + time::{SystemTime, UNIX_EPOCH}, }; pub type Result = std::result::Result; diff --git a/crates/kftray-commons/src/utils/http_logs_config.rs b/crates/kftray-commons/src/utils/http_logs_config.rs index 8ec03097..61bbe52a 100644 --- a/crates/kftray-commons/src/utils/http_logs_config.rs +++ b/crates/kftray-commons/src/utils/http_logs_config.rs @@ -1,15 +1,9 @@ use log::error; -use sqlx::{ - Row, - SqlitePool, -}; +use sqlx::{Row, SqlitePool}; use crate::db::get_db_pool; use crate::models::http_logs_config_model::HttpLogsConfig; -use crate::utils::db_mode::{ - DatabaseManager, - DatabaseMode, -}; +use crate::utils::db_mode::{DatabaseManager, DatabaseMode}; pub(crate) async fn get_http_logs_config_with_pool( config_id: i64, pool: &SqlitePool, diff --git a/crates/kftray-commons/src/utils/manifests.rs b/crates/kftray-commons/src/utils/manifests.rs index 2b3d298d..90a930e1 100644 --- a/crates/kftray-commons/src/utils/manifests.rs +++ b/crates/kftray-commons/src/utils/manifests.rs @@ -3,11 +3,8 @@ use std::io::Write; use std::path::Path; use crate::utils::config_dir::{ - create_config_dir, - get_expose_deployment_manifest_path, - get_expose_ingress_manifest_path, - get_expose_service_manifest_path, - get_proxy_deployment_manifest_path, + create_config_dir, get_expose_deployment_manifest_path, get_expose_ingress_manifest_path, + get_expose_service_manifest_path, get_proxy_deployment_manifest_path, }; /// Default proxy deployment manifest template (Deployment-based) diff --git a/crates/kftray-commons/src/utils/migration.rs b/crates/kftray-commons/src/utils/migration.rs index 81361e7a..c9e462d6 100644 --- a/crates/kftray-commons/src/utils/migration.rs +++ b/crates/kftray-commons/src/utils/migration.rs @@ -1,16 +1,7 @@ -use log::{ - error, - info, -}; +use log::{error, info}; use serde_json::Value as JsonValue; use sqlx::SqlitePool; -use sqlx::{ - Acquire, - Row, - Sqlite, - SqliteConnection, - Transaction, -}; +use sqlx::{Acquire, Row, Sqlite, SqliteConnection, Transaction}; use crate::db::get_db_pool; use crate::models::config_model::Config; @@ -479,10 +470,7 @@ mod tests { use super::*; use crate::db::create_db_table; use crate::models::config_model::Config; - use crate::utils::config::{ - insert_config_with_pool, - read_configs_with_pool, - }; + use crate::utils::config::{insert_config_with_pool, read_configs_with_pool}; use crate::utils::config_state::read_config_states_with_pool; async fn setup_test_db() -> SqlitePool { diff --git a/crates/kftray-commons/src/utils/mod.rs b/crates/kftray-commons/src/utils/mod.rs index 549edc01..0c7ee839 100644 --- a/crates/kftray-commons/src/utils/mod.rs +++ b/crates/kftray-commons/src/utils/mod.rs @@ -3,6 +3,7 @@ pub mod config_dir; pub mod config_state; pub mod db; pub mod db_mode; +pub mod env_export; pub mod error; pub mod github; pub mod hostsfile; diff --git a/crates/kftray-commons/src/utils/settings.rs b/crates/kftray-commons/src/utils/settings.rs index 33047dbb..fa5a267f 100644 --- a/crates/kftray-commons/src/utils/settings.rs +++ b/crates/kftray-commons/src/utils/settings.rs @@ -2,22 +2,13 @@ use std::collections::HashMap; use std::sync::Arc; use log::info; -use serde::{ - Deserialize, - Serialize, -}; -use sqlx::{ - Row, - SqlitePool, -}; +use serde::{Deserialize, Serialize}; +use sqlx::{Row, SqlitePool}; use tokio::sync::RwLock; use crate::models::settings_model::AppSettings; use crate::utils::db::get_db_pool; -use crate::utils::db_mode::{ - DatabaseManager, - DatabaseMode, -}; +use crate::utils::db_mode::{DatabaseManager, DatabaseMode}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Setting { @@ -618,6 +609,38 @@ pub async fn set_ssl_ca_auto_install_with_mode( set_setting_with_mode("ssl_ca_auto_install", &enabled.to_string(), mode).await } +/// Returns whether automatic .env file synchronization is enabled. +/// Defaults to `true` if not previously set. +pub async fn get_env_auto_sync_enabled() -> Result> { + if let Some(value) = get_setting("env_auto_sync_enabled").await? { + Ok(value.parse::().unwrap_or(true)) + } else { + Ok(true) // Default to enabled + } +} + +/// Sets whether automatic .env file synchronization is enabled. +pub async fn set_env_auto_sync_enabled( + enabled: bool, +) -> Result<(), Box> { + set_setting("env_auto_sync_enabled", &enabled.to_string()).await +} + +/// Returns the file path for automatic .env synchronization. +/// Returns `None` if no path is configured or the path is empty. +pub async fn get_env_auto_sync_path() +-> Result, Box> { + let value = get_setting("env_auto_sync_path").await?; + Ok(value.filter(|s| !s.is_empty())) +} + +/// Sets the file path for automatic .env synchronization. +pub async fn set_env_auto_sync_path( + path: &str, +) -> Result<(), Box> { + set_setting("env_auto_sync_path", path).await +} + pub async fn get_app_settings_with_mode( mode: DatabaseMode, ) -> Result> { diff --git a/crates/kftray-commons/src/utils/timeout_manager.rs b/crates/kftray-commons/src/utils/timeout_manager.rs index ba64d856..08459a2b 100644 --- a/crates/kftray-commons/src/utils/timeout_manager.rs +++ b/crates/kftray-commons/src/utils/timeout_manager.rs @@ -61,24 +61,15 @@ pub async fn get_timeout_info_for_forward(config_id: i64) -> Option { #[cfg(test)] mod tests { - use std::sync::atomic::{ - AtomicBool, - Ordering, - }; + use std::sync::atomic::{AtomicBool, Ordering}; use lazy_static::lazy_static; use sqlx::SqlitePool; use tokio::sync::Mutex; - use tokio::time::{ - Duration, - sleep, - }; + use tokio::time::{Duration, sleep}; use super::*; - use crate::utils::db::{ - DB_POOL, - create_db_table, - }; + use crate::utils::db::{DB_POOL, create_db_table}; use crate::utils::settings::set_disconnect_timeout; lazy_static! { diff --git a/crates/kftray-tauri/build.rs b/crates/kftray-tauri/build.rs index 9a556dd6..b3e71e2e 100644 --- a/crates/kftray-tauri/build.rs +++ b/crates/kftray-tauri/build.rs @@ -1,9 +1,6 @@ use std::env; use std::fs; -use std::path::{ - Path, - PathBuf, -}; +use std::path::{Path, PathBuf}; fn main() { let target_triple = std::env::var("TARGET").unwrap(); diff --git a/crates/kftray-tauri/src/commands/config.rs b/crates/kftray-tauri/src/commands/config.rs index 1e4a9224..f5a9a0f0 100644 --- a/crates/kftray-tauri/src/commands/config.rs +++ b/crates/kftray-tauri/src/commands/config.rs @@ -1,23 +1,12 @@ use kftray_commons::config::{ - delete_all_configs, - delete_config, - delete_configs, - export_configs, - get_config, - get_configs, - import_configs, - insert_config, - update_config, + delete_all_configs, delete_config, delete_configs, export_configs, get_config, get_configs, + import_configs, insert_config, update_config, }; use kftray_commons::models::config_model::Config; use kftray_commons::utils::settings::get_ssl_enabled; use kftray_portforward::kube::clear_stopped_by_timeout; use kftray_portforward::ssl::cert_manager::CertificateManager; -use log::{ - error, - info, - warn, -}; +use log::{error, info, warn}; fn validate_config(config: &Config) -> Result<(), String> { if config.auto_loopback_address && config.local_address.is_some() { @@ -76,10 +65,7 @@ async fn regenerate_ssl_certificate_if_needed() -> Result<(), String> { async fn restart_ssl_proxies_if_running() -> Result<(), String> { use kftray_commons::utils::config_state::get_configs_state; - use kftray_portforward::kube::{ - start_port_forward, - stop_port_forward, - }; + use kftray_portforward::kube::{start_port_forward, stop_port_forward}; info!("=== Starting SSL proxy restart process ==="); diff --git a/crates/kftray-tauri/src/commands/env_export.rs b/crates/kftray-tauri/src/commands/env_export.rs new file mode 100644 index 00000000..2e6790e1 --- /dev/null +++ b/crates/kftray-tauri/src/commands/env_export.rs @@ -0,0 +1,8 @@ +use kftray_commons::utils::env_export::generate_env_content; + +/// Tauri command to export port-forward configurations as .env file content. +/// When `running_only` is true, only includes currently active port-forwards. +#[tauri::command] +pub async fn export_env_cmd(running_only: bool) -> Result { + generate_env_content(running_only).await +} diff --git a/crates/kftray-tauri/src/commands/github.rs b/crates/kftray-tauri/src/commands/github.rs index 247e0bd8..631c50e8 100644 --- a/crates/kftray-tauri/src/commands/github.rs +++ b/crates/kftray-tauri/src/commands/github.rs @@ -1,16 +1,7 @@ -use keyring::{ - Entry, - Error as KeyringError, -}; +use keyring::{Entry, Error as KeyringError}; use kftray_commons::utils::db_mode::DatabaseMode; -use kftray_commons::utils::github::{ - GitHubConfig, - GitHubRepository, -}; -use tauri::{ - Error as TauriError, - ipc::InvokeError, -}; +use kftray_commons::utils::github::{GitHubConfig, GitHubRepository}; +use tauri::{Error as TauriError, ipc::InvokeError}; #[derive(Debug)] pub enum CustomError { diff --git a/crates/kftray-tauri/src/commands/helper.rs b/crates/kftray-tauri/src/commands/helper.rs index b7df617e..a138d47c 100644 --- a/crates/kftray-tauri/src/commands/helper.rs +++ b/crates/kftray-tauri/src/commands/helper.rs @@ -1,8 +1,5 @@ use kftray_helper::HelperClient; -use log::{ - info, - warn, -}; +use log::{info, warn}; #[tauri::command] pub async fn install_helper() -> Result { diff --git a/crates/kftray-tauri/src/commands/httplogs.rs b/crates/kftray-tauri/src/commands/httplogs.rs index e07d11fe..48ad1fd2 100644 --- a/crates/kftray-tauri/src/commands/httplogs.rs +++ b/crates/kftray-tauri/src/commands/httplogs.rs @@ -1,19 +1,10 @@ use std::fs; -use std::path::{ - Path, - PathBuf, -}; +use std::path::{Path, PathBuf}; use kftray_commons::models::http_logs_config_model::HttpLogsConfig; use kftray_commons::utils::config_dir::get_log_folder_path; -use kftray_commons::utils::http_logs_config::{ - get_http_logs_config, - update_http_logs_config, -}; -use log::{ - error, - info, -}; +use kftray_commons::utils::http_logs_config::{get_http_logs_config, update_http_logs_config}; +use log::{error, info}; // HTTP Log Management Commands (using direct database access) @@ -302,15 +293,9 @@ fn is_editor_available(editor: &str) -> bool { fn open_with_editor(file_path: &str, editor: &str) -> Result<(), String> { use std::ffi::OsStr; - use std::process::{ - Command, - Stdio, - }; + use std::process::{Command, Stdio}; use std::thread; - use std::time::{ - Duration, - Instant, - }; + use std::time::{Duration, Instant}; // Special handling for macOS 'open' command #[cfg(target_os = "macos")] @@ -518,10 +503,7 @@ mod tests { use std::collections::HashMap; use std::env; use std::io::Write; - use std::sync::{ - Arc, - Mutex, - }; + use std::sync::{Arc, Mutex}; use kftray_commons::models::config_model::Config; use tempfile::TempDir; diff --git a/crates/kftray-tauri/src/commands/kubecontext.rs b/crates/kftray-tauri/src/commands/kubecontext.rs index ba87c411..6af6b486 100644 --- a/crates/kftray-tauri/src/commands/kubecontext.rs +++ b/crates/kftray-tauri/src/commands/kubecontext.rs @@ -1,29 +1,18 @@ use std::collections::HashSet; use anyhow::Result; -use k8s_openapi::api::core::v1::{ - Namespace, - Pod, - Service, -}; +use k8s_openapi::api::core::v1::{Namespace, Pod, Service}; use k8s_openapi::apimachinery::pkg::util::intstr::IntOrString; use kftray_commons::config_model::Config; use kftray_portforward::kube::client::create_client_with_specific_context; use kftray_portforward::kube::models::{ - KubeContextInfo, - KubeNamespaceInfo, - KubeServiceInfo, - KubeServicePortInfo, - PodInfo, + KubeContextInfo, KubeNamespaceInfo, KubeServiceInfo, KubeServicePortInfo, PodInfo, }; use kftray_portforward::kube::retrieve_service_configs; use kube::Resource; use kube::{ ResourceExt, - api::{ - Api, - ListParams, - }, + api::{Api, ListParams}, }; use log::info; @@ -262,15 +251,8 @@ mod tests { use std::collections::BTreeMap; use k8s_openapi::api::core::v1::{ - Container, - ContainerPort, - Namespace as K8sNamespace, - NamespaceSpec, - Pod as K8sPod, - PodSpec, - Service as K8sService, - ServicePort, - ServiceSpec, + Container, ContainerPort, Namespace as K8sNamespace, NamespaceSpec, Pod as K8sPod, PodSpec, + Service as K8sService, ServicePort, ServiceSpec, }; use k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta; diff --git a/crates/kftray-tauri/src/commands/logs.rs b/crates/kftray-tauri/src/commands/logs.rs index 32f66072..b98f6a7b 100644 --- a/crates/kftray-tauri/src/commands/logs.rs +++ b/crates/kftray-tauri/src/commands/logs.rs @@ -1,25 +1,16 @@ use std::fs; -use std::io::{ - BufRead, - BufReader, -}; +use std::io::{BufRead, BufReader}; use std::path::PathBuf; use jiff::Zoned; use log::info; -use serde::{ - Deserialize, - Serialize, -}; +use serde::{Deserialize, Serialize}; use tauri::AppHandle; use tauri::Manager; use tauri::WebviewUrl; use tauri::WebviewWindowBuilder; -use super::settings::{ - DiagnosticsReport, - run_diagnostics, -}; +use super::settings::{DiagnosticsReport, run_diagnostics}; #[derive(Serialize)] pub struct LogInfo { diff --git a/crates/kftray-tauri/src/commands/mod.rs b/crates/kftray-tauri/src/commands/mod.rs index 5c2fcf7a..de750cac 100644 --- a/crates/kftray-tauri/src/commands/mod.rs +++ b/crates/kftray-tauri/src/commands/mod.rs @@ -1,5 +1,6 @@ pub mod config; pub mod config_state; +pub mod env_export; pub mod github; pub mod helper; pub mod httplogs; diff --git a/crates/kftray-tauri/src/commands/portforward.rs b/crates/kftray-tauri/src/commands/portforward.rs index ac02bd92..856b0813 100644 --- a/crates/kftray-tauri/src/commands/portforward.rs +++ b/crates/kftray-tauri/src/commands/portforward.rs @@ -5,34 +5,20 @@ use kftray_commons::config::get_configs; use kftray_commons::models::config_model::Config; use kftray_commons::models::response::CustomResponse; use kftray_commons::utils::config_state::{ - cleanup_current_process_config_states, - get_configs_state, + cleanup_current_process_config_states, get_configs_state, }; +use kftray_commons::utils::env_export::write_env_file_if_enabled; use kftray_portforward::kube::{ - deploy_and_forward_pod, - start_port_forward, - stop_all_port_forward, - stop_port_forward, + deploy_and_forward_pod, start_port_forward, stop_all_port_forward, stop_port_forward, stop_proxy_forward, }; use log::error; use log::info; use serde_json::json; -use tauri::{ - AppHandle, - Emitter, - Manager, - Wry, -}; -use tauri_plugin_dialog::{ - DialogExt, - MessageDialogButtons, -}; +use tauri::{AppHandle, Emitter, Manager, Wry}; +use tauri_plugin_dialog::{DialogExt, MessageDialogButtons}; use tokio::sync::Mutex; -use tokio::time::{ - Duration, - interval, -}; +use tokio::time::{Duration, interval}; pub async fn check_and_emit_changes(app_handle: AppHandle) { let mut interval = interval(Duration::from_millis(500)); @@ -97,9 +83,24 @@ pub async fn check_and_emit_changes(app_handle: AppHandle) { let mut prev_states = previous_config_states.lock().await; let mut prev_configs = previous_configs.lock().await; - if !config_compare_changes(&prev_states, ¤t_config_states) - || !config_compare_changes(&prev_configs, ¤t_configs) - { + let states_changed = !config_compare_changes(&prev_states, ¤t_config_states); + let configs_changed = !config_compare_changes(&prev_configs, ¤t_configs); + + if states_changed || configs_changed { + let running_count = current_config_states + .iter() + .filter(|s| s.is_running) + .count(); + info!( + "Config state change detected: states_changed={}, configs_changed={}, running_services={}", + states_changed, configs_changed, running_count + ); + + // Auto-sync .env file if enabled + if let Err(e) = write_env_file_if_enabled().await { + error!("Failed to auto-sync .env file: {e}"); + } + app_handle .emit("config_state_changed", &Vec::::new()) .unwrap_or_else(|e| { @@ -132,35 +133,60 @@ fn config_compare_changes(prev: &[T], current: &[T]) -> bool { pub async fn start_port_forward_udp_cmd( configs: Vec, _app_handle: tauri::AppHandle, ) -> Result, String> { - start_port_forward(configs.clone(), "udp").await + let result = start_port_forward(configs.clone(), "udp").await; + // Trigger env sync after start + if let Err(e) = write_env_file_if_enabled().await { + error!("Failed to auto-sync .env file after UDP start: {e}"); + } + result } #[tauri::command] pub async fn start_port_forward_tcp_cmd( configs: Vec, _app_handle: tauri::AppHandle, ) -> Result, String> { - start_port_forward(configs.clone(), "tcp").await + let result = start_port_forward(configs.clone(), "tcp").await; + // Trigger env sync after start + if let Err(e) = write_env_file_if_enabled().await { + error!("Failed to auto-sync .env file after TCP start: {e}"); + } + result } #[tauri::command] pub async fn stop_all_port_forward_cmd( _app_handle: tauri::AppHandle, ) -> Result, String> { - stop_all_port_forward().await + let result = stop_all_port_forward().await; + // Trigger env sync after stop all + if let Err(e) = write_env_file_if_enabled().await { + error!("Failed to auto-sync .env file after stop all: {e}"); + } + result } #[tauri::command] pub async fn stop_port_forward_cmd( config_id: String, _app_handle: tauri::AppHandle, ) -> Result { - stop_port_forward(config_id.clone()).await + let result = stop_port_forward(config_id.clone()).await; + // Trigger env sync after stop + if let Err(e) = write_env_file_if_enabled().await { + error!("Failed to auto-sync .env file after stop: {e}"); + } + result } #[tauri::command] pub async fn deploy_and_forward_pod_cmd( configs: Vec, _app_handle: tauri::AppHandle, ) -> Result, String> { - deploy_and_forward_pod(configs.clone()).await + let result = deploy_and_forward_pod(configs.clone()).await; + // Trigger env sync after deploy and forward + if let Err(e) = write_env_file_if_enabled().await { + error!("Failed to auto-sync .env file after deploy: {e}"); + } + result } #[tauri::command] @@ -171,7 +197,12 @@ pub async fn stop_proxy_forward_cmd( .parse::() .map_err(|e| format!("Failed to parse config_id: {e}"))?; - stop_proxy_forward(config_id, namespace, service_name).await + let result = stop_proxy_forward(config_id, namespace, service_name).await; + // Trigger env sync after stop proxy + if let Err(e) = write_env_file_if_enabled().await { + error!("Failed to auto-sync .env file after stop proxy: {e}"); + } + result } #[tauri::command] diff --git a/crates/kftray-tauri/src/commands/server_resources.rs b/crates/kftray-tauri/src/commands/server_resources.rs index 5324c493..729f3894 100644 --- a/crates/kftray-tauri/src/commands/server_resources.rs +++ b/crates/kftray-tauri/src/commands/server_resources.rs @@ -1,31 +1,15 @@ use std::collections::HashMap; use k8s_openapi::api::{ - apps::v1::Deployment, - core::v1::Pod, - core::v1::Service, - networking::v1::Ingress, + apps::v1::Deployment, core::v1::Pod, core::v1::Service, networking::v1::Ingress, }; use k8s_openapi::apimachinery::pkg::apis::meta::v1::Time; use kftray_commons::utils::db_mode::DatabaseMode; use kftray_portforward::kube::client::create_client_with_specific_context; -use kube::api::{ - Api, - DeleteParams, - ListParams, -}; -use kube::{ - Client, - ResourceExt, -}; -use log::{ - error, - info, -}; -use serde::{ - Deserialize, - Serialize, -}; +use kube::api::{Api, DeleteParams, ListParams}; +use kube::{Client, ResourceExt}; +use log::{error, info}; +use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct ServerResource { diff --git a/crates/kftray-tauri/src/commands/settings.rs b/crates/kftray-tauri/src/commands/settings.rs index 4dabbff9..455aebdf 100644 --- a/crates/kftray-tauri/src/commands/settings.rs +++ b/crates/kftray-tauri/src/commands/settings.rs @@ -2,22 +2,12 @@ use std::collections::HashMap; use std::process::Command; use kftray_commons::utils::settings::{ - get_auto_update_enabled, - get_last_update_check, - get_setting, - set_auto_update_enabled, - set_disconnect_timeout, - set_network_monitor, - set_setting, -}; -use kftray_commons::utils::settings::{ - get_disconnect_timeout, - get_network_monitor, -}; -use log::{ - error, - info, + get_auto_update_enabled, get_env_auto_sync_enabled, get_env_auto_sync_path, + get_last_update_check, get_setting, set_auto_update_enabled, set_disconnect_timeout, + set_env_auto_sync_enabled, set_env_auto_sync_path, set_network_monitor, set_setting, }; +use kftray_commons::utils::settings::{get_disconnect_timeout, get_network_monitor}; +use log::{error, info}; use serde::Serialize; #[tauri::command] @@ -182,6 +172,55 @@ pub async fn get_auto_update_status() -> Result, String> Ok(status) } +#[derive(Serialize)] +pub struct EnvAutoSyncSettings { + pub enabled: bool, + pub path: Option, +} + +#[tauri::command] +pub async fn get_env_auto_sync_settings() -> Result { + let enabled = get_env_auto_sync_enabled().await.map_err(|e| { + error!("Failed to get env_auto_sync_enabled: {e}"); + format!("Failed to get env_auto_sync_enabled: {e}") + })?; + + let path = get_env_auto_sync_path().await.map_err(|e| { + error!("Failed to get env_auto_sync_path: {e}"); + format!("Failed to get env_auto_sync_path: {e}") + })?; + + Ok(EnvAutoSyncSettings { enabled, path }) +} + +#[tauri::command] +pub async fn set_env_auto_sync_settings(enabled: bool, path: Option) -> Result<(), String> { + info!("Setting env auto-sync: enabled={enabled}, path={path:?}"); + + set_env_auto_sync_enabled(enabled).await.map_err(|e| { + error!("Failed to set env_auto_sync_enabled: {e}"); + format!("Failed to set env_auto_sync_enabled: {e}") + })?; + + let path_value = path.clone().unwrap_or_default(); + info!("Saving env_auto_sync_path to database: '{}'", path_value); + set_env_auto_sync_path(&path_value).await.map_err(|e| { + error!("Failed to set env_auto_sync_path: {e}"); + format!("Failed to set env_auto_sync_path: {e}") + })?; + + // Verify the settings were saved correctly + let verify_enabled = get_env_auto_sync_enabled().await.unwrap_or(false); + let verify_path = get_env_auto_sync_path().await.ok().flatten(); + info!( + "Verified saved settings: enabled={}, path={:?}", + verify_enabled, verify_path + ); + + info!("Successfully set env auto-sync settings"); + Ok(()) +} + #[derive(Serialize)] pub struct DiagnosticResult { pub name: String, diff --git a/crates/kftray-tauri/src/commands/shortcuts.rs b/crates/kftray-tauri/src/commands/shortcuts.rs index 836c03d5..c1bf35fb 100644 --- a/crates/kftray-tauri/src/commands/shortcuts.rs +++ b/crates/kftray-tauri/src/commands/shortcuts.rs @@ -1,13 +1,7 @@ use kftray_shortcuts::ShortcutDefinition; use log::info; -use serde::{ - Deserialize, - Serialize, -}; -use tauri::{ - AppHandle, - Emitter, -}; +use serde::{Deserialize, Serialize}; +use tauri::{AppHandle, Emitter}; use crate::shortcuts::get_manager; diff --git a/crates/kftray-tauri/src/commands/ssl.rs b/crates/kftray-tauri/src/commands/ssl.rs index 2f994150..62364367 100644 --- a/crates/kftray-tauri/src/commands/ssl.rs +++ b/crates/kftray-tauri/src/commands/ssl.rs @@ -1,22 +1,10 @@ use kftray_commons::utils::settings::{ - get_app_settings, - get_ssl_auto_regenerate as get_ssl_auto_regen, - get_ssl_cert_validity_days, - get_ssl_enabled, - set_ssl_auto_regenerate as set_ssl_auto_regen, - set_ssl_ca_auto_install, - set_ssl_cert_validity_days, - set_ssl_enabled, -}; -use kftray_portforward::ssl::{ - CertificateInfo, - CertificateManager, -}; -use log::{ - error, - info, - warn, + get_app_settings, get_ssl_auto_regenerate as get_ssl_auto_regen, get_ssl_cert_validity_days, + get_ssl_enabled, set_ssl_auto_regenerate as set_ssl_auto_regen, set_ssl_ca_auto_install, + set_ssl_cert_validity_days, set_ssl_enabled, }; +use kftray_portforward::ssl::{CertificateInfo, CertificateManager}; +use log::{error, info, warn}; use tauri::command; #[command] diff --git a/crates/kftray-tauri/src/commands/updater.rs b/crates/kftray-tauri/src/commands/updater.rs index 4250a9a0..76bcbe2d 100644 --- a/crates/kftray-tauri/src/commands/updater.rs +++ b/crates/kftray-tauri/src/commands/updater.rs @@ -1,22 +1,9 @@ -use std::time::{ - SystemTime, - UNIX_EPOCH, -}; +use std::time::{SystemTime, UNIX_EPOCH}; use kftray_commons::utils::settings::set_last_update_check; -use log::{ - error, - info, -}; -use tauri::{ - AppHandle, - command, -}; -use tauri_plugin_dialog::{ - DialogExt, - MessageDialogButtons, - MessageDialogKind, -}; +use log::{error, info}; +use tauri::{AppHandle, command}; +use tauri_plugin_dialog::{DialogExt, MessageDialogButtons, MessageDialogKind}; use tauri_plugin_updater::UpdaterExt; fn get_current_timestamp() -> i64 { diff --git a/crates/kftray-tauri/src/commands/window_state.rs b/crates/kftray-tauri/src/commands/window_state.rs index f198c923..6bdc2f5b 100644 --- a/crates/kftray-tauri/src/commands/window_state.rs +++ b/crates/kftray-tauri/src/commands/window_state.rs @@ -4,11 +4,7 @@ use kftray_commons::models::window::AppState; use kftray_commons::models::window::SaveDialogState; use log::error; use tauri::State; -use tauri::{ - Emitter, - WebviewWindow, - Wry, -}; +use tauri::{Emitter, WebviewWindow, Wry}; #[tauri::command] pub fn open_save_dialog(state: State) { @@ -53,11 +49,7 @@ pub fn toggle_pin_state(app_state: tauri::State, window: WebviewWindow #[cfg(test)] mod tests { use std::collections::HashMap; - use std::sync::{ - Arc, - Mutex, - atomic::AtomicBool, - }; + use std::sync::{Arc, Mutex, atomic::AtomicBool}; use tokio::runtime::Runtime; diff --git a/crates/kftray-tauri/src/glibc_detector.rs b/crates/kftray-tauri/src/glibc_detector.rs index 49f591d2..14aa5974 100644 --- a/crates/kftray-tauri/src/glibc_detector.rs +++ b/crates/kftray-tauri/src/glibc_detector.rs @@ -2,10 +2,7 @@ use std::process::Command; #[cfg(target_os = "linux")] -use log::{ - debug, - warn, -}; +use log::{debug, warn}; #[derive(Debug, Clone, PartialEq)] #[allow(dead_code)] diff --git a/crates/kftray-tauri/src/init_check.rs b/crates/kftray-tauri/src/init_check.rs index ca16f8e3..4fc6b951 100644 --- a/crates/kftray-tauri/src/init_check.rs +++ b/crates/kftray-tauri/src/init_check.rs @@ -2,30 +2,14 @@ use std::sync::Arc; use async_trait::async_trait; use kftray_commons::config::get_config; -use kftray_commons::config_state::{ - get_configs_state, - update_config_state, -}; +use kftray_commons::config_state::{get_configs_state, update_config_state}; use kftray_commons::config_state_model::ConfigState; use kftray_commons::models::config_model::Config; use kftray_portforward::kube::deploy_and_forward_pod; use kftray_portforward::start_port_forward; -use log::{ - debug, - error, - info, - warn, -}; -use netstat2::{ - AddressFamilyFlags, - ProtocolFlags, - ProtocolSocketInfo, - get_sockets_info, -}; -use sysinfo::{ - Pid, - System, -}; +use log::{debug, error, info, warn}; +use netstat2::{AddressFamilyFlags, ProtocolFlags, ProtocolSocketInfo, get_sockets_info}; +use sysinfo::{Pid, System}; #[cfg_attr(test, mockall::automock)] #[async_trait] diff --git a/crates/kftray-tauri/src/main.rs b/crates/kftray-tauri/src/main.rs index e0485e62..07a40596 100644 --- a/crates/kftray-tauri/src/main.rs +++ b/crates/kftray-tauri/src/main.rs @@ -5,10 +5,7 @@ use std::sync::Arc; -use log::{ - error, - info, -}; +use log::{error, info}; use crate::validation::alert_multiple_configs; mod commands; @@ -32,12 +29,7 @@ use crate::commands::portforward::check_and_emit_changes; use crate::glibc_detector::get_updater_target_platform; use crate::init_check::RealPortOperations; use crate::shortcuts::setup_shortcut_integration; -use crate::tray::{ - TrayPositionState, - create_tray_icon, - handle_run_event, - handle_window_event, -}; +use crate::tray::{TrayPositionState, create_tray_icon, handle_run_event, handle_window_event}; fn main() { // CRITICAL: Must be called before ANY other code that might touch X11. @@ -350,6 +342,8 @@ fn main() { commands::settings::update_auto_update_enabled, commands::settings::get_auto_update_status, commands::settings::run_diagnostics, + commands::settings::get_env_auto_sync_settings, + commands::settings::set_env_auto_sync_settings, commands::logs::get_log_info, commands::logs::get_log_contents, commands::logs::get_log_contents_json, @@ -396,6 +390,7 @@ fn main() { commands::server_resources::delete_kftray_resource, commands::server_resources::cleanup_all_kftray_resources, commands::server_resources::cleanup_orphaned_kftray_resources, + commands::env_export::export_env_cmd, ]) .build(tauri::generate_context!()) .expect("error while running tauri application"); @@ -405,10 +400,7 @@ fn main() { #[cfg(test)] mod tests { - use std::sync::{ - Mutex, - atomic::AtomicBool, - }; + use std::sync::{Mutex, atomic::AtomicBool}; use super::*; diff --git a/crates/kftray-tauri/src/shortcuts.rs b/crates/kftray-tauri/src/shortcuts.rs index b1fe52b2..edc68cf4 100644 --- a/crates/kftray-tauri/src/shortcuts.rs +++ b/crates/kftray-tauri/src/shortcuts.rs @@ -2,36 +2,18 @@ use std::sync::Arc; use async_trait::async_trait; use kftray_commons::models::config_model::Config; -use kftray_shortcuts::{ - ActionContext, - ActionHandler, - ActionRegistry, - ShortcutManager, -}; -use log::{ - error, - info, -}; -use tauri::{ - AppHandle, - Emitter, - Manager, -}; +use kftray_shortcuts::{ActionContext, ActionHandler, ActionRegistry, ShortcutManager}; +use log::{error, info}; +use tauri::{AppHandle, Emitter, Manager}; use tauri_plugin_notification::NotificationExt; -use tokio::sync::{ - Mutex, - OnceCell, -}; +use tokio::sync::{Mutex, OnceCell}; use crate::commands::{ config::get_configs_cmd, config_state::get_config_states, portforward::{ - deploy_and_forward_pod_cmd, - start_port_forward_tcp_cmd, - stop_all_port_forward_cmd, - stop_port_forward_cmd, - stop_proxy_forward_cmd, + deploy_and_forward_pod_cmd, start_port_forward_tcp_cmd, stop_all_port_forward_cmd, + stop_port_forward_cmd, stop_proxy_forward_cmd, }, }; diff --git a/crates/kftray-tauri/src/tray.rs b/crates/kftray-tauri/src/tray.rs index de49fc7a..47bb2ae5 100644 --- a/crates/kftray-tauri/src/tray.rs +++ b/crates/kftray-tauri/src/tray.rs @@ -1,36 +1,16 @@ use std::sync::atomic::Ordering; -use std::sync::{ - Arc, - Mutex, -}; +use std::sync::{Arc, Mutex}; use std::time::Duration; use kftray_commons::models::window::AppState; use kftray_commons::models::window::SaveDialogState; -use log::{ - error, - info, - warn, -}; +use log::{error, info, warn}; use tauri::PhysicalPosition; use tauri::PhysicalSize; use tauri::{ - Manager, - RunEvent, - WindowEvent, - Wry, - menu::{ - MenuBuilder, - MenuItemBuilder, - PredefinedMenuItem, - SubmenuBuilder, - }, - tray::{ - MouseButton, - MouseButtonState, - TrayIconBuilder, - TrayIconEvent, - }, + Manager, RunEvent, WindowEvent, Wry, + menu::{MenuBuilder, MenuItemBuilder, PredefinedMenuItem, SubmenuBuilder}, + tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent}, }; use tauri_plugin_positioner::Position; use tokio::time::sleep; @@ -45,10 +25,7 @@ pub struct TrayPositionState { use crate::commands::portforward::handle_exit_app; use crate::commands::window_state::toggle_pin_state; use crate::window::{ - reset_window_position, - save_window_position, - set_window_position, - toggle_window_visibility, + reset_window_position, save_window_position, set_window_position, toggle_window_visibility, }; pub fn create_tray_icon(app: &tauri::App) -> Result, tauri::Error> { @@ -386,10 +363,7 @@ pub fn handle_run_event(app_handle: &tauri::AppHandle, event: RunEvent) { mod tests { use std::sync::Arc; - use kftray_commons::models::window::{ - AppState, - SaveDialogState, - }; + use kftray_commons::models::window::{AppState, SaveDialogState}; use tokio::runtime::Runtime; #[test] diff --git a/crates/kftray-tauri/src/validation.rs b/crates/kftray-tauri/src/validation.rs index 64d21674..7bb15f88 100644 --- a/crates/kftray-tauri/src/validation.rs +++ b/crates/kftray-tauri/src/validation.rs @@ -1,18 +1,8 @@ use kftray_commons::utils::validate_configs::{ - ConfigLocation, - detect_multiple_configs, - format_alert_message, -}; -use tauri::{ - AppHandle, - Manager, - Runtime, - async_runtime::spawn_blocking, -}; -use tauri_plugin_dialog::{ - DialogExt, - MessageDialogButtons, + ConfigLocation, detect_multiple_configs, format_alert_message, }; +use tauri::{AppHandle, Manager, Runtime, async_runtime::spawn_blocking}; +use tauri_plugin_dialog::{DialogExt, MessageDialogButtons}; async fn show_alert_dialog( app_handle: AppHandle, configs: Vec, active_config: Option, diff --git a/crates/kftray-tauri/src/window.rs b/crates/kftray-tauri/src/window.rs index 2de753c9..03038ab3 100644 --- a/crates/kftray-tauri/src/window.rs +++ b/crates/kftray-tauri/src/window.rs @@ -6,21 +6,9 @@ use std::time::Duration; use kftray_commons::models::window::AppState; use kftray_commons::models::window::WindowPosition; use kftray_commons::utils::config_dir::get_window_state_path; -use log::{ - info, - warn, -}; -use tauri::{ - Manager, - PhysicalPosition, - PhysicalSize, - WebviewWindow, - Wry, -}; -use tauri_plugin_positioner::{ - Position, - WindowExt, -}; +use log::{info, warn}; +use tauri::{Manager, PhysicalPosition, PhysicalSize, WebviewWindow, Wry}; +use tauri_plugin_positioner::{Position, WindowExt}; use tokio::time::sleep; pub fn save_window_position(window: &WebviewWindow) { diff --git a/docs/kftray/USAGE.md b/docs/kftray/USAGE.md index 3c33b0ad..7f63dc01 100644 --- a/docs/kftray/USAGE.md +++ b/docs/kftray/USAGE.md @@ -110,3 +110,41 @@ To import and sync your GitHub configs in kftray: 6. KFtray will now sync with the Git repository to automatically import any new configurations or changes committed to the JSON file. This allows you to quickly deploy any port forward changes to all team members. And if someone on your team adds a new configuration, it will be automatically synced to everyone else's KFtray. + +## Auto-Sync .env File + +KFtray can automatically generate and update a `.env` file with the host and port information of your running port-forwards. This is useful for integrating with local development environments that read configuration from `.env` files. + +### How it works + +When enabled, KFtray will automatically write a `.env` file whenever port-forwards start or stop. The file contains environment variables for each running service: + +```bash +# Generated by kftray +# Updated: 2024-01-15T10:30:00Z + +POSTGRES_HOST=127.0.0.1 +POSTGRES_PORT=5432 +REDIS_HOST=127.0.0.1 +REDIS_PORT=6379 +``` + +The variable names are derived from the service alias (or service name if no alias is set), converted to uppercase with dashes replaced by underscores. + +### Configuration + +1. Open **Settings** from the system tray menu +2. Find the **.env Auto-Sync** section +3. The feature is **enabled by default** - toggle to disable if needed +4. Click **Browse...** to select the file path where the `.env` file should be saved +5. Click **Save Settings** + +Once configured: +- Starting a port-forward will add its `_HOST` and `_PORT` variables to the file +- Stopping a port-forward will remove its variables from the file +- Stopping all port-forwards will leave the file with just the header comments + +### Tips + +- Point the `.env` file to your project directory so your application can read it automatically +- If you have services with the same alias in different namespaces, the namespace will be appended to disambiguate (e.g., `POSTGRES_PRODUCTION_HOST`, `POSTGRES_STAGING_HOST`) diff --git a/frontend/src/components/Footer/index.tsx b/frontend/src/components/Footer/index.tsx index 020d0dde..435a98c2 100644 --- a/frontend/src/components/Footer/index.tsx +++ b/frontend/src/components/Footer/index.tsx @@ -1,6 +1,7 @@ import React, { useCallback, useState } from 'react' import { Download, + FileCode, Github, Keyboard, Menu as MenuIcon, @@ -39,6 +40,7 @@ const Footer: React.FC = ({ openGitSyncModal, handleExportConfigs, handleImportConfigs, + handleExportEnv, credentialsSaved, setCredentialsSaved, isGitSyncModalOpen, @@ -142,6 +144,11 @@ const Footer: React.FC = ({ Export Local File + + + Export .env File + + { } } + const handleExportEnv = async () => { + try { + await invoke('open_save_dialog') + const content = await invoke('export_env_cmd', { runningOnly: true }) + + const filePath = await save({ + defaultPath: '.env', + filters: [{ name: 'Environment', extensions: ['env'] }], + }) + + await invoke('close_save_dialog') + + if (filePath) { + await writeTextFile(filePath, content) + toaster.success({ + title: 'Success', + description: '.env file exported successfully.', + duration: 1000, + }) + } + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : String(error) + + console.error('Failed to export .env file:', errorMessage) + toaster.error({ + title: 'Failed to export .env file', + description: errorMessage, + duration: 1000, + }) + } + } + const handleImportConfigs = async () => { try { await invoke('open_save_dialog') @@ -904,6 +937,7 @@ return { id: config.id, error: null, aborted: false } openGitSyncModal={openGitSyncModal} handleExportConfigs={handleExportConfigs} handleImportConfigs={handleImportConfigs} + handleExportEnv={handleExportEnv} setCredentialsSaved={handleSetCredentialsSaved} credentialsSaved={credentialsSaved} isGitSyncModalOpen={isGitSyncModalOpen} diff --git a/frontend/src/components/SettingsModal/EnvAutoSyncSettings.tsx b/frontend/src/components/SettingsModal/EnvAutoSyncSettings.tsx new file mode 100644 index 00000000..f89988d7 --- /dev/null +++ b/frontend/src/components/SettingsModal/EnvAutoSyncSettings.tsx @@ -0,0 +1,166 @@ +import React from 'react' +import { FileCode, FolderOpen } from 'lucide-react' + +import { Box, Flex, Text } from '@chakra-ui/react' +import { invoke } from '@tauri-apps/api/core' +import { save } from '@tauri-apps/plugin-dialog' + +import { Button } from '@/components/ui/button' +import { Checkbox } from '@/components/ui/checkbox' +import { toaster } from '@/components/ui/toaster' + +interface EnvAutoSyncSettingsProps { + envAutoSyncEnabled: boolean + setEnvAutoSyncEnabled: (enabled: boolean) => void + envAutoSyncPath: string + setEnvAutoSyncPath: (path: string) => void + isLoading: boolean +} + +const EnvAutoSyncSettings: React.FC = ({ + envAutoSyncEnabled, + setEnvAutoSyncEnabled, + envAutoSyncPath, + setEnvAutoSyncPath, + isLoading, +}) => { + const selectEnvPath = async () => { + try { + await invoke('open_save_dialog') + const filePath = await save({ + defaultPath: envAutoSyncPath || '.env', + filters: [ + { name: 'Environment Files', extensions: ['env'] }, + { name: 'All Files', extensions: ['*'] }, + ], + }) + + if (filePath) { + setEnvAutoSyncPath(filePath) + } + } catch (error) { + console.error('Error selecting env file path:', error) + toaster.error({ + title: 'Error', + description: 'Failed to select file path', + duration: 3000, + }) + } finally { + await invoke('close_save_dialog') + } + } + + return ( + <> + {/* Left Column - .env Auto-Sync Enable */} + + + + + .env Auto-Sync + + + + + Auto-update .env file when port-forwards start or stop. + + + + + Enabled: + + + setEnvAutoSyncEnabled(e.checked === true) + } + disabled={isLoading} + size='sm' + /> + + + + + {/* Right Column - .env File Path */} + + + .env File Path + + + {envAutoSyncPath || 'No path selected'} + + + + + + + + + ) +} + +export default EnvAutoSyncSettings diff --git a/frontend/src/components/SettingsModal/index.tsx b/frontend/src/components/SettingsModal/index.tsx index a2063b4c..810b764b 100644 --- a/frontend/src/components/SettingsModal/index.tsx +++ b/frontend/src/components/SettingsModal/index.tsx @@ -6,6 +6,7 @@ import { app } from '@tauri-apps/api' import { invoke } from '@tauri-apps/api/core' import type { LogFileInfo, LogSettings } from '@/components/LogViewer' +import EnvAutoSyncSettings from '@/components/SettingsModal/EnvAutoSyncSettings' import { Button } from '@/components/ui/button' import { Checkbox } from '@/components/ui/checkbox' import { DialogCloseTrigger } from '@/components/ui/dialog' @@ -42,11 +43,15 @@ const SettingsModal: React.FC = ({ isOpen, onClose }) => { const [logTotalSize, setLogTotalSize] = useState(0) const [isCleaningLogs, setIsCleaningLogs] = useState(false) + const [envAutoSyncEnabled, setEnvAutoSyncEnabled] = useState(false) + const [envAutoSyncPath, setEnvAutoSyncPath] = useState('') + useEffect(() => { if (isOpen) { loadSettings() loadVersionInfo() loadLogInfo() + loadEnvAutoSyncSettings() } }, [isOpen]) @@ -134,6 +139,22 @@ const SettingsModal: React.FC = ({ isOpen, onClose }) => { } } + const loadEnvAutoSyncSettings = async () => { + try { + const settings = await invoke<{ enabled: boolean; path: string | null }>( + 'get_env_auto_sync_settings', + ) + + console.log('Loaded env auto-sync settings from DB:', settings) + setEnvAutoSyncEnabled(settings.enabled) + setEnvAutoSyncPath(settings.path || '') + } catch (error) { + console.error('Error loading env auto-sync settings:', error) + setEnvAutoSyncEnabled(false) + setEnvAutoSyncPath('') + } + } + const checkForUpdates = async () => { try { setIsCheckingUpdates(true) @@ -357,6 +378,26 @@ const SettingsModal: React.FC = ({ isOpen, onClose }) => { }) } + try { + console.log('Saving env auto-sync settings:', { + enabled: envAutoSyncEnabled, + path: envAutoSyncPath, + }) + await invoke('set_env_auto_sync_settings', { + enabled: envAutoSyncEnabled, + path: envAutoSyncPath || null, + }) + console.log('Env auto-sync settings saved successfully') + } catch (envError) { + console.error('Error saving env auto-sync settings:', envError) + toaster.error({ + title: 'Env Auto-Sync Error', + description: + 'Failed to save .env auto-sync settings, but other settings were saved', + duration: 4000, + }) + } + await loadSettings() if (!(wasDisabled && willBeEnabled)) { @@ -973,6 +1014,14 @@ const SettingsModal: React.FC = ({ isOpen, onClose }) => { + + diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 1f31e6e7..fed9d686 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -97,6 +97,7 @@ export interface FooterProps { openGitSyncModal: () => void handleExportConfigs: () => void handleImportConfigs: () => void + handleExportEnv?: () => void credentialsSaved: boolean setCredentialsSaved: (value: boolean) => void isGitSyncModalOpen: boolean diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..5d56faf9 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly"