feat(vpn-ui): init frontend NC-134 (#4160)

This commit is contained in:
Pierre Dommerc
2023-11-22 15:04:02 +01:00
committed by GitHub
parent 8ee31d94ea
commit 809fabfc2b
32 changed files with 1759 additions and 808 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path ${{ env.CARGOTOML_PATH }} --lib --features custom-protocol
args: --manifest-path ${{ env.CARGOTOML_PATH }} --features custom-protocol
# - name: Run all tests
# uses: actions-rs/cargo@v1
-12
View File
@@ -80,18 +80,6 @@ Generated TS types will be located in `src-tauri/bindings/`
## Build
To build as a **shared library**
```
yarn build && cd src-tauri && cargo build --release --lib --features custom-protocol
#alias
yarn build:app
```
You can build for a different platform using [Cross](https://github.com/cross-rs/cross).
For example, to build for Windows on Linux:
```
cross build --target x86_64-pc-windows-gnu --release --lib --features custom-protocol
```
+3 -3
View File
@@ -4,11 +4,11 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tauri + React + TS</title>
<title>NymVPN</title>
</head>
<body>
<div id="root" class="bg-gray-900"></div>
<body class="h-screen">
<div id="root" class="h-full bg-gray-900 text-gray-400"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+10 -6
View File
@@ -8,7 +8,7 @@
"dev:app": "RUST_LOG=nymvpn_ui=trace tauri dev",
"dev:browser": "vite --mode dev-browser",
"build": "tsc && vite build",
"build:app": "yarn build && cd src-tauri && cargo build --release --lib --features custom-protocol",
"build:app": "yarn tauri build",
"preview": "vite preview",
"lint": "eslint --ext .ts,.tsx src/",
"lint:fix": "eslint --ext .js,.ts --fix src/",
@@ -18,17 +18,21 @@
"tauri": "tauri"
},
"dependencies": {
"@mui/base": "^5.0.0-beta.20",
"@mui/base": "^5.0.0-beta.24",
"@mui/material": "^5.14.14",
"@tauri-apps/api": "^1.5.0",
"clsx": "^2.0.0",
"i18next": "^23.7.6",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"react-i18next": "^13.5.0",
"react-router-dom": "^6.18.0"
},
"devDependencies": {
"@tauri-apps/cli": "^1.5.0",
"@types/react": "^18.2.31",
"@types/react-dom": "^18.2.14",
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"@types/react-router-dom": "^5.3.3",
"@typescript-eslint/eslint-plugin": "^6.8.0",
"@typescript-eslint/parser": "^6.8.0",
"@vitejs/plugin-react-swc": "^3.3.2",
@@ -42,6 +46,6 @@
"prettier": "^3.0.3",
"tailwindcss": "^3.3.3",
"typescript": "^5.0.2",
"vite": "^4.4.5"
"vite": "^5.0.0"
}
}
+504 -1
View File
@@ -206,6 +206,9 @@ name = "bytes"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
dependencies = [
"serde",
]
[[package]]
name = "cairo-rs"
@@ -615,7 +618,7 @@ dependencies = [
"rustc_version",
"toml 0.8.5",
"vswhom",
"winreg",
"winreg 0.51.0",
]
[[package]]
@@ -779,6 +782,12 @@ dependencies = [
"syn 2.0.38",
]
[[package]]
name = "futures-sink"
version = "0.3.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
[[package]]
name = "futures-task"
version = "0.3.28"
@@ -792,8 +801,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
dependencies = [
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
@@ -1105,6 +1117,25 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "h2"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http",
"indexmap 1.9.3",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@@ -1183,12 +1214,72 @@ dependencies = [
"itoa 1.0.9",
]
[[package]]
name = "http-body"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
dependencies = [
"bytes",
"http",
"pin-project-lite",
]
[[package]]
name = "http-range"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
[[package]]
name = "httparse"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
[[package]]
name = "httpdate"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "0.14.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"httparse",
"httpdate",
"itoa 1.0.9",
"pin-project-lite",
"socket2 0.4.10",
"tokio",
"tower-service",
"tracing",
"want",
]
[[package]]
name = "hyper-tls"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
"hyper",
"native-tls",
"tokio",
"tokio-native-tls",
]
[[package]]
name = "iana-time-zone"
version = "0.1.58"
@@ -1308,6 +1399,12 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "ipnet"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
[[package]]
name = "itoa"
version = "0.4.8"
@@ -1540,6 +1637,18 @@ dependencies = [
"autocfg",
]
[[package]]
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "minisign-verify"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "933dca44d65cdd53b355d0b73d380a2ff5da71f87f036053188bf1eab6a19881"
[[package]]
name = "miniz_oxide"
version = "0.7.1"
@@ -1550,6 +1659,35 @@ dependencies = [
"simd-adler32",
]
[[package]]
name = "mio"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
dependencies = [
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.48.0",
]
[[package]]
name = "native-tls"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "ndk"
version = "0.6.0"
@@ -1690,6 +1828,17 @@ dependencies = [
"objc_exception",
]
[[package]]
name = "objc-foundation"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
dependencies = [
"block",
"objc",
"objc_id",
]
[[package]]
name = "objc_exception"
version = "0.1.2"
@@ -1733,6 +1882,50 @@ dependencies = [
"windows-sys 0.42.0",
]
[[package]]
name = "openssl"
version = "0.10.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33"
dependencies = [
"bitflags 2.4.1",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "overload"
version = "0.1.1"
@@ -2206,6 +2399,70 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "reqwest"
version = "0.11.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
dependencies = [
"base64 0.21.5",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"hyper-tls",
"ipnet",
"js-sys",
"log",
"mime",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
"serde",
"serde_json",
"serde_urlencoded",
"system-configuration",
"tokio",
"tokio-native-tls",
"tokio-util",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"winreg 0.50.0",
]
[[package]]
name = "rfd"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea"
dependencies = [
"block",
"dispatch",
"glib-sys",
"gobject-sys",
"gtk-sys",
"js-sys",
"lazy_static",
"log",
"objc",
"objc-foundation",
"objc_id",
"raw-window-handle",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows 0.37.0",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
@@ -2261,6 +2518,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "schannel"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
@@ -2273,6 +2539,29 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "security-framework"
version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "selectors"
version = "0.22.0"
@@ -2353,6 +2642,18 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
"itoa 1.0.9",
"ryu",
"serde",
]
[[package]]
name = "serde_with"
version = "3.4.0"
@@ -2461,6 +2762,26 @@ version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
[[package]]
name = "socket2"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "socket2"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
dependencies = [
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "soup2"
version = "0.2.1"
@@ -2558,6 +2879,27 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "system-configuration"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "system-deps"
version = "5.0.0"
@@ -2666,6 +3008,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bfe673cf125ef364d6f56b15e8ce7537d9ca7e4dae1cf6fbbdeed2e024db3d9"
dependencies = [
"anyhow",
"base64 0.21.5",
"bytes",
"cocoa",
"dirs-next",
"embed_plist",
@@ -2678,6 +3022,7 @@ dependencies = [
"heck 0.4.1",
"http",
"ignore",
"minisign-verify",
"objc",
"once_cell",
"open",
@@ -2685,6 +3030,8 @@ dependencies = [
"rand 0.8.5",
"raw-window-handle",
"regex",
"reqwest",
"rfd",
"semver",
"serde",
"serde_json",
@@ -2698,12 +3045,14 @@ dependencies = [
"tauri-utils",
"tempfile",
"thiserror",
"time",
"tokio",
"url",
"uuid",
"webkit2gtk",
"webview2-com",
"windows 0.39.0",
"zip",
]
[[package]]
@@ -2967,8 +3316,36 @@ checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653"
dependencies = [
"backtrace",
"bytes",
"libc",
"mio",
"num_cpus",
"pin-project-lite",
"socket2 0.5.5",
"windows-sys 0.48.0",
]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "tokio-util"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
"tracing",
]
[[package]]
@@ -3039,6 +3416,12 @@ dependencies = [
"winnow",
]
[[package]]
name = "tower-service"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
[[package]]
name = "tracing"
version = "0.1.40"
@@ -3109,6 +3492,12 @@ dependencies = [
"serde_json",
]
[[package]]
name = "try-lock"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "ts-rs"
version = "7.0.0"
@@ -3199,6 +3588,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version-compare"
version = "0.0.11"
@@ -3247,6 +3642,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "want"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
dependencies = [
"try-lock",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
@@ -3284,6 +3688,18 @@ dependencies = [
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.87"
@@ -3313,6 +3729,29 @@ version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "wasm-streams"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7"
dependencies = [
"futures-util",
"js-sys",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "web-sys"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "webkit2gtk"
version = "0.18.2"
@@ -3429,6 +3868,19 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647"
dependencies = [
"windows_aarch64_msvc 0.37.0",
"windows_i686_gnu 0.37.0",
"windows_i686_msvc 0.37.0",
"windows_x86_64_gnu 0.37.0",
"windows_x86_64_msvc 0.37.0",
]
[[package]]
name = "windows"
version = "0.39.0"
@@ -3544,6 +3996,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
[[package]]
name = "windows_aarch64_msvc"
version = "0.39.0"
@@ -3562,6 +4020,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
[[package]]
name = "windows_i686_gnu"
version = "0.39.0"
@@ -3580,6 +4044,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
[[package]]
name = "windows_i686_msvc"
version = "0.39.0"
@@ -3598,6 +4068,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.39.0"
@@ -3628,6 +4104,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.39.0"
@@ -3655,6 +4137,16 @@ dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]]
name = "winreg"
version = "0.51.0"
@@ -3732,3 +4224,14 @@ checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985"
dependencies = [
"libc",
]
[[package]]
name = "zip"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
dependencies = [
"byteorder",
"crc32fast",
"crossbeam-utils",
]
+1 -4
View File
@@ -7,14 +7,11 @@ license = ""
repository = ""
edition = "2021"
[lib]
crate-type = ["cdylib"]
[build-dependencies]
tauri-build = { version = "1.5", features = [] }
[dependencies]
tauri = { version = "1.5.2", features = ["shell-open"] }
tauri = { version = "1.5.2", features = [ "updater", "shell-open"] }
tokio = { version = "1.33", features = ["rt", "sync", "time", "fs"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
@@ -1,6 +1,6 @@
use std::time::Duration;
use tauri::State;
use tauri::{Manager, State};
use tokio::time::sleep;
use tracing::{debug, instrument, trace};
@@ -9,7 +9,14 @@ use crate::{
states::{app::ConnectionState, SharedAppState},
};
#[instrument]
const EVENT_CONNECTION: &str = "connection-state";
#[derive(Clone, serde::Serialize)]
struct EventPayload {
state: ConnectionState,
}
#[instrument(skip_all)]
#[tauri::command]
pub async fn get_connection_state(
state: State<'_, SharedAppState>,
@@ -19,8 +26,12 @@ pub async fn get_connection_state(
Ok(app_state.state)
}
#[instrument(skip_all)]
#[tauri::command]
pub async fn connect(state: State<'_, SharedAppState>) -> Result<ConnectionState, CommandError> {
pub async fn connect(
app: tauri::AppHandle,
state: State<'_, SharedAppState>,
) -> Result<ConnectionState, CommandError> {
debug!("connect");
let mut app_state = state.lock().await;
let ConnectionState::Disconnected = app_state.state else {
@@ -30,23 +41,46 @@ pub async fn connect(state: State<'_, SharedAppState>) -> Result<ConnectionState
)));
};
// switch to "Connecting" state
app_state.state = ConnectionState::Connecting;
// unlock the mutex
drop(app_state);
app.emit_all(
EVENT_CONNECTION,
EventPayload {
state: ConnectionState::Connecting,
},
)
.ok();
// TODO fake some delay to establish connection
let app_state_cloned = state.inner().clone();
let task = tokio::spawn(async move {
sleep(Duration::from_secs(2)).await;
trace!("connected");
app_state_cloned.lock().await.state = ConnectionState::Connected;
debug!("sending event [{}]: connected", EVENT_CONNECTION);
app.emit_all(
EVENT_CONNECTION,
EventPayload {
state: ConnectionState::Connected,
},
)
.ok();
});
let _ = task.await;
app_state.state = ConnectionState::Connecting;
let app_state = state.lock().await;
Ok(app_state.state)
}
#[instrument]
#[instrument(skip_all)]
#[tauri::command]
pub async fn disconnect(state: State<'_, SharedAppState>) -> Result<ConnectionState, CommandError> {
pub async fn disconnect(
app: tauri::AppHandle,
state: State<'_, SharedAppState>,
) -> Result<ConnectionState, CommandError> {
debug!("disconnect");
let mut app_state = state.lock().await;
let ConnectionState::Connected = app_state.state else {
@@ -56,6 +90,36 @@ pub async fn disconnect(state: State<'_, SharedAppState>) -> Result<ConnectionSt
)));
};
// switch to "Disconnecting" state
app_state.state = ConnectionState::Disconnecting;
// unlock the mutex
drop(app_state);
app.emit_all(
EVENT_CONNECTION,
EventPayload {
state: ConnectionState::Disconnecting,
},
)
.ok();
// TODO fake some delay to confirm disconnection
let app_state_cloned = state.inner().clone();
let task = tokio::spawn(async move {
sleep(Duration::from_secs(2)).await;
trace!("disconnected");
app_state_cloned.lock().await.state = ConnectionState::Disconnected;
debug!("sending event [{}]: disconnected", EVENT_CONNECTION);
app.emit_all(
EVENT_CONNECTION,
EventPayload {
state: ConnectionState::Disconnected,
},
)
.ok();
});
let _ = task.await;
let app_state = state.lock().await;
Ok(app_state.state)
}
-16
View File
@@ -1,16 +0,0 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
#[no_mangle]
pub extern "C" fn run_tauri() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
+1 -1
View File
@@ -26,7 +26,7 @@ const APP_DATA_FILE: &str = "app-data.toml";
const APP_CONFIG_FILE: &str = "config.toml";
fn main() -> Result<()> {
dotenvy::dotenv()?;
dotenvy::dotenv().ok();
// uses RUST_LOG value for logging level
// eg. RUST_LOG=tauri=debug,nymvpn_ui=trace
+2 -2
View File
@@ -46,8 +46,8 @@
"fullscreen": false,
"resizable": true,
"title": "NymVPN",
"width": 200,
"height": 200
"width": 400,
"height": 600
}
]
}
+23 -46
View File
@@ -1,54 +1,31 @@
import React, { useState } from 'react';
import { invoke } from '@tauri-apps/api/tauri';
import { Button as BaseButton, ButtonProps } from '@mui/base/Button';
import clsx from 'clsx';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import { Home, Settings, Error, PageLayout } from './pages';
import { MainStateProvider } from './state';
import './i18n/config';
// eslint-disable-next-line react/display-name
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
(props, ref) => {
const { className, ...other } = props;
return (
<BaseButton
ref={ref}
className={clsx(
'cursor-pointer disabled:cursor-not-allowed text-sm font-sans bg-violet-500 hover:bg-violet-600 active:bg-violet-700 text-white rounded-lg font-semibold px-4 py-2 border-none disabled:opacity-50',
className,
)}
{...other}
/>
);
const router = createBrowserRouter([
{
element: <PageLayout />,
children: [
{
path: '/',
element: <Home />,
errorElement: <Error />,
},
{
path: '/settings',
element: <Settings />,
errorElement: <Error />,
},
],
},
);
]);
function App() {
const [greetMsg, setGreetMsg] = useState('');
const [name, setName] = useState('');
async function greet() {
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
setGreetMsg(await invoke('greet', { name }));
}
return (
<div>
<h1>Welcome to Tauri!</h1>
<form
onSubmit={(e) => {
e.preventDefault();
greet();
}}
>
<input
id="greet-input"
onChange={(e) => setName(e.currentTarget.value)}
placeholder="Enter a name..."
/>
<Button type="submit">Greet</Button>
</form>
<p>{greetMsg}</p>
</div>
<MainStateProvider>
<RouterProvider router={router} />
</MainStateProvider>
);
}
+1
View File
@@ -0,0 +1 @@
export const ConnectionEvent = 'connection-state';
+1
View File
@@ -0,0 +1 @@
export * from './main';
+15
View File
@@ -0,0 +1,15 @@
import { createContext, useContext } from 'react';
import { AppState } from '../types';
import { initialState, StateAction } from '../state';
export const MainStateContext = createContext<AppState>(initialState);
export const MainDispatchContext =
createContext<React.Dispatch<StateAction> | null>(null);
export const useMainState = () => {
return useContext(MainStateContext);
};
export const useMainDispatch = () => {
return useContext(MainDispatchContext);
};
+33 -8
View File
@@ -1,11 +1,36 @@
import { mockIPC, mockWindows } from '@tauri-apps/api/mocks';
import { greet } from './tauri-cmd-mocks';
import { ConnectionState } from '../types';
import { emit } from '@tauri-apps/api/event';
import { ConnectionEvent } from '../constants';
mockWindows('main');
export function mockTauriIPC() {
mockWindows('main');
mockIPC(async (cmd, args) => {
console.log(`IPC call mocked "${cmd}"`);
if (cmd === 'greet') {
return greet(args.name as string);
}
});
mockIPC(async (cmd, args) => {
console.log(`IPC call mocked "${cmd}"`);
console.log(args);
if (cmd === 'connect') {
await emit(ConnectionEvent, { state: 'Connecting' });
return new Promise<ConnectionState>((resolve) =>
setTimeout(async () => {
await emit(ConnectionEvent, { state: 'Connected' });
resolve('Connected');
}, 2000),
);
}
if (cmd === 'disconnect') {
await emit(ConnectionEvent, { state: 'Disconnecting' });
return new Promise<ConnectionState>((resolve) =>
setTimeout(async () => {
await emit(ConnectionEvent, { state: 'Disconnected' });
resolve('Disconnected');
}, 2000),
);
}
if (cmd === 'get_connection_state') {
return new Promise<ConnectionState>((resolve) =>
setTimeout(() => resolve('Disconnected'), 2000),
);
}
});
}
@@ -1,3 +0,0 @@
export default function greet(name: string): string {
return `Hello, ${name}!`;
}
@@ -1 +0,0 @@
export { default as greet } from './greet';
+22
View File
@@ -0,0 +1,22 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import main from './en/main.json';
const defaultNS = 'main';
i18n.use(initReactI18next).init({
lng: 'en',
debug: import.meta.env.DEV,
resources: {
en: {
main,
},
},
defaultNS,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
});
export default i18n;
+4
View File
@@ -0,0 +1,4 @@
{
"connect": "Connect",
"disconnect": "Disconnect"
}
+2 -1
View File
@@ -1,11 +1,12 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { mockTauriIPC } from './dev/setup';
import './styles.css';
if (import.meta.env.MODE === 'dev-browser') {
console.log('Running in dev-browser mode. Mocking tauri window and IPCs');
import('./dev/setup');
mockTauriIPC();
}
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
+21
View File
@@ -0,0 +1,21 @@
import { useRouteError } from 'react-router-dom';
type routerErrorType = {
statusText: string;
message: string;
};
export default function ErrorPage() {
const error: routerErrorType = useRouteError() as unknown as routerErrorType;
console.error(error);
return (
<div id="error-page">
<h1>Oops!</h1>
<p>Sorry, an unexpected error has occurred.</p>
<p>
<i>{error.statusText || error.message}</i>
</p>
</div>
);
}
+41
View File
@@ -0,0 +1,41 @@
import { useTranslation } from 'react-i18next';
import { invoke } from '@tauri-apps/api';
import { useMainDispatch, useMainState } from '../contexts';
import { StateDispatch } from '../types';
function Home() {
const state = useMainState();
const dispatch = useMainDispatch() as StateDispatch;
const { t } = useTranslation();
const handleClick = async () => {
if (state.state === 'Connected') {
dispatch({ type: 'disconnect' });
invoke('disconnect').then((result) => {
console.log(result);
});
} else if (state.state === 'Disconnected') {
dispatch({ type: 'connect' });
invoke('connect').then((result) => {
console.log(result);
});
}
};
return (
<div>
<h2>NymVPN</h2>
connection state: {state.state}
{state.loading ? (
'loading…'
) : (
<button onClick={handleClick}>
{state.state === 'Disconnected' ? t('connect') : t('disconnect')}
</button>
)}
</div>
);
}
export default Home;
+4
View File
@@ -0,0 +1,4 @@
export { default as PageLayout } from './pageLayout';
export { default as Home } from './home';
export { default as Settings } from './settings';
export { default as Error } from './error';
+11
View File
@@ -0,0 +1,11 @@
import { Outlet } from 'react-router-dom';
function PageLayout() {
return (
<div>
<Outlet />
</div>
);
}
export default PageLayout;
+5
View File
@@ -0,0 +1,5 @@
function Settings() {
return <div>Settings</div>;
}
export default Settings;
+2
View File
@@ -0,0 +1,2 @@
export * from './main';
export * from './provider';
+35
View File
@@ -0,0 +1,35 @@
import { AppState, ConnectionState } from '../types';
export type StateAction =
| { type: 'change-connection-state'; state: ConnectionState }
| { type: 'connect' }
| { type: 'disconnect' }
| { type: 'reset' };
export const initialState: AppState = {
state: 'Disconnected',
loading: false,
privacyMode: 'High',
tunnel: { name: 'nym', id: 'nym' },
};
export function reducer(state: AppState, action: StateAction): AppState {
switch (action.type) {
case 'change-connection-state': {
return {
...state,
state: action.state,
loading:
action.state === 'Connecting' || action.state === 'Disconnecting',
};
}
case 'connect': {
return { ...state, state: 'Connecting', loading: true };
}
case 'disconnect': {
return { ...state, state: 'Disconnecting', loading: true };
}
case 'reset':
return initialState;
}
}
+35
View File
@@ -0,0 +1,35 @@
import { useEffect, useReducer } from 'react';
import { invoke } from '@tauri-apps/api';
import { initialState, reducer } from './main';
import { useTauriEvents } from './useTauriEvents';
import { MainDispatchContext, MainStateContext } from '../contexts';
import { ConnectionState } from '../types';
type Props = {
children?: React.ReactNode;
};
export function MainStateProvider({ children }: Props) {
const [state, dispatch] = useReducer(reducer, initialState);
useTauriEvents(dispatch);
// initialize connection state
useEffect(() => {
const getInitialConnectionState = async () => {
return await invoke<ConnectionState>('get_connection_state');
};
getInitialConnectionState().then((state) =>
dispatch({ type: 'change-connection-state', state }),
);
}, []);
return (
<MainStateContext.Provider value={state}>
<MainDispatchContext.Provider value={dispatch}>
{children}
</MainDispatchContext.Provider>
</MainStateContext.Provider>
);
}
+39
View File
@@ -0,0 +1,39 @@
import { useCallback, useEffect } from 'react';
import { listen } from '@tauri-apps/api/event';
import { EventPayload, StateDispatch } from '../types';
import { ConnectionEvent } from '../constants';
export function useTauriEvents(dispatch: StateDispatch) {
const registerListener = useCallback(() => {
return listen<EventPayload>(ConnectionEvent, (event) => {
console.log(
`received event ${event.event}, state: ${event.payload.state}`,
);
switch (event.payload.state) {
case 'Connected':
dispatch({ type: 'change-connection-state', state: 'Connected' });
break;
case 'Disconnected':
dispatch({ type: 'change-connection-state', state: 'Disconnected' });
break;
case 'Connecting':
dispatch({ type: 'change-connection-state', state: 'Connecting' });
break;
case 'Disconnecting':
dispatch({ type: 'change-connection-state', state: 'Disconnecting' });
break;
case 'Error':
break;
}
});
}, [dispatch]);
// register/unregister event listener
useEffect(() => {
const unlisten = registerListener();
return () => {
unlisten.then((f) => f());
};
}, [registerListener]);
}
+29
View File
@@ -0,0 +1,29 @@
import { Dispatch } from 'react';
import { StateAction } from '../state';
export type ConnectionState =
| 'Connected'
| 'Disconnected'
| 'Connecting'
| 'Disconnecting'
| 'Error';
export type PrivacyMode = 'High' | 'Medium' | 'Low';
export interface TunnelConfig {
id: string;
name: string;
}
export type AppState = {
state: ConnectionState;
loading: boolean;
privacyMode: PrivacyMode;
tunnel: TunnelConfig;
};
export type EventPayload = {
state: ConnectionState;
};
export type StateDispatch = Dispatch<StateAction>;
+1
View File
@@ -0,0 +1 @@
export * from './app-state';
+843 -697
View File
File diff suppressed because it is too large Load Diff