mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-01-18 23:16:59 +01:00
Compare commits
9 Commits
v2024.11.4
...
v2024.12.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57a05d5486 | ||
|
|
e216214085 | ||
|
|
aa7f18a16f | ||
|
|
b9f397e04a | ||
|
|
57c3a86799 | ||
|
|
52ac41b0c6 | ||
|
|
741ccbe741 | ||
|
|
2ecd86da78 | ||
|
|
30e4e7665a |
@@ -1,4 +1,4 @@
|
||||
# [Yaak API Client](https://yaak.app)
|
||||
# Yaak API Client
|
||||
|
||||
Yaak is a desktop API client for organizing and executing REST, GraphQL, and gRPC
|
||||
requests. It's built using [Tauri](https://tauri.app), Rust, and ReactJS.
|
||||
|
||||
88
package-lock.json
generated
88
package-lock.json
generated
@@ -18,7 +18,7 @@
|
||||
"src-web"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2.0.3",
|
||||
"@tauri-apps/cli": "^2.0.4",
|
||||
"@typescript-eslint/eslint-plugin": "^8.5.0",
|
||||
"@typescript-eslint/parser": "^8.5.0",
|
||||
"eslint": "^8",
|
||||
@@ -2689,9 +2689,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.0.3.tgz",
|
||||
"integrity": "sha512-JwEyhc5BAVpn4E8kxzY/h7+bVOiXQdudR1r3ODMfyyumZBfgIWqpD/WuTcPq6Yjchju1BSS+80jAE/oYwI/RKg==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.0.4.tgz",
|
||||
"integrity": "sha512-Hl9eFXz+O366+6su9PfaSzu2EJdFe1p8K8ghkWmi40dz8VmSE7vsMTaOStD0I71ckSOkh2ICDX7FQTBgjlpjWw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"bin": {
|
||||
@@ -2705,22 +2705,22 @@
|
||||
"url": "https://opencollective.com/tauri"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tauri-apps/cli-darwin-arm64": "2.0.3",
|
||||
"@tauri-apps/cli-darwin-x64": "2.0.3",
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf": "2.0.3",
|
||||
"@tauri-apps/cli-linux-arm64-gnu": "2.0.3",
|
||||
"@tauri-apps/cli-linux-arm64-musl": "2.0.3",
|
||||
"@tauri-apps/cli-linux-x64-gnu": "2.0.3",
|
||||
"@tauri-apps/cli-linux-x64-musl": "2.0.3",
|
||||
"@tauri-apps/cli-win32-arm64-msvc": "2.0.3",
|
||||
"@tauri-apps/cli-win32-ia32-msvc": "2.0.3",
|
||||
"@tauri-apps/cli-win32-x64-msvc": "2.0.3"
|
||||
"@tauri-apps/cli-darwin-arm64": "2.0.4",
|
||||
"@tauri-apps/cli-darwin-x64": "2.0.4",
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf": "2.0.4",
|
||||
"@tauri-apps/cli-linux-arm64-gnu": "2.0.4",
|
||||
"@tauri-apps/cli-linux-arm64-musl": "2.0.4",
|
||||
"@tauri-apps/cli-linux-x64-gnu": "2.0.4",
|
||||
"@tauri-apps/cli-linux-x64-musl": "2.0.4",
|
||||
"@tauri-apps/cli-win32-arm64-msvc": "2.0.4",
|
||||
"@tauri-apps/cli-win32-ia32-msvc": "2.0.4",
|
||||
"@tauri-apps/cli-win32-x64-msvc": "2.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-darwin-arm64": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.0.3.tgz",
|
||||
"integrity": "sha512-jIsbxGWS+As1ZN7umo90nkql/ZAbrDK0GBT6UsgHSz5zSwwArICsZFFwE1pLZip5yoiV5mn3TGG2c1+v+0puzQ==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.0.4.tgz",
|
||||
"integrity": "sha512-siH7rOHobb16rPbc11k64p1mxIpiRCkWmzs2qmL5IX21Gx9K5onI3Tk67Oqpf2uNupbYzItrOttaDT4NHFC7tw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2735,9 +2735,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-darwin-x64": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.0.3.tgz",
|
||||
"integrity": "sha512-ROITHtLTA1muyrwgyuwyasmaLCGtT4as/Kd1kerXaSDtFcYrnxiM984ZD0+FDUEDl5BgXtYa/sKKkKQFjgmM0A==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.0.4.tgz",
|
||||
"integrity": "sha512-zIccfbCoZMfmUpnk6PFCV0keFyfVj1A9XV3Oiiitj/dkTZ9CQvzjhX3XC0XcK4rsTWegfr2PjSrK06aiPAROAw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2752,9 +2752,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.0.3.tgz",
|
||||
"integrity": "sha512-bQ3EZwCFfrLg/ZQ2I8sLuifSxESz4TP56SleTkKsPtTIZgNnKpM88PRDz4neiRroHVOq8NK0X276qi9LjGcXPw==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.0.4.tgz",
|
||||
"integrity": "sha512-fgQqJzefOGWCBNg4yrVA82Rg4s1XQr5K0dc2rCxBhJfa696e8dQ1LDrnWq/AiO5r+uHfVaoQTIUvxxpFicYRSA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -2769,9 +2769,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm64-gnu": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.0.3.tgz",
|
||||
"integrity": "sha512-aLfAA8P9OTErVUk3sATxtXqpAtlfDPMPp4fGjDysEELG/MyekGhmh2k/kG/i32OdPeCfO+Nr37wJksARJKubGw==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.0.4.tgz",
|
||||
"integrity": "sha512-u8wbt5tPA9pI6j+d7jGrfOz9UVCiTp+IYzKNiIqlrDsAjqAUFaNXYHKqOUboeFWEmI4zoCWj6LgpS2OJTQ5FKg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2786,9 +2786,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm64-musl": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.3.tgz",
|
||||
"integrity": "sha512-I4MVD7nf6lLLRmNQPpe5beEIFM6q7Zkmh77ROA5BNu/+vHNL5kiTMD+bmd10ZL2r753A6pO7AvqkIxcBuIl0tg==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.0.4.tgz",
|
||||
"integrity": "sha512-hntF1V8e3V1hlrESm93PsghDhf3lA5pbvFrRfYxU1c+fVD/jRXGVw8BH3O1lW8MWwhEg1YdhKk01oAgsuHLuig==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2803,9 +2803,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-x64-gnu": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.0.3.tgz",
|
||||
"integrity": "sha512-C6Jkx2zZGKkoi+sg5FK9GoH/0EvAaOgrZfF5azV5EALGba46g7VpWcZgp9zFUd7K2IzTi+0OOY8TQ2OVfKZgew==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.0.4.tgz",
|
||||
"integrity": "sha512-Iq1GGJb+oT1T0ZV8izrgf0cBtlzPCJaWcNueRbf1ZXquMf+FSTyQv+/Lo8rq5T6buOIJOH7cAOTuEWWqiCZteg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2820,9 +2820,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-x64-musl": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.3.tgz",
|
||||
"integrity": "sha512-qi4ghmTfSAl+EEUDwmwI9AJUiOLNSmU1RgiGgcPRE+7A/W+Am9UnxYySAiRbB/gJgTl9sj/pqH5Y9duP1/sqHg==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.0.4.tgz",
|
||||
"integrity": "sha512-9NTk6Pf0bSwXqCBdAA+PDYts9HeHebZzIo8mbRzRyUbER6QngG5HZb9Ka36Z1QWtJjdRy6uxSb4zb/9NuTeHfA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2837,9 +2837,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-arm64-msvc": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.0.3.tgz",
|
||||
"integrity": "sha512-UXxHkYmFesC97qVmZre4vY7oDxRDtC2OeKNv0bH+iSnuUp/ROxzJYGyaelnv9Ybvgl4YVqDCnxgB28qMM938TA==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.0.4.tgz",
|
||||
"integrity": "sha512-OF2e9oxiBFR8A8wVMOhUx9QGN/I1ZkquWC7gVQBnA56nx9PabJlDT08QBy5UD8USqZFVznnfNr2ehlheQahb3g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2854,9 +2854,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-ia32-msvc": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.0.3.tgz",
|
||||
"integrity": "sha512-D+xoaa35RGlkXDpnL5uDTpj29untuC5Wp6bN9snfgFDagD0wnFfC8+2ZQGu16bD0IteWqDI0OSoIXhNvy+F+wg==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.0.4.tgz",
|
||||
"integrity": "sha512-T+hCKB3rFP6q0saHHtR02hm6wr1ZPJ0Mkii3oRTxjPG6BBXoVzHNCYzvdgEGJPTA2sFuAQtJH764NRtNlDMifw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -2871,9 +2871,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-x64-msvc": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.0.3.tgz",
|
||||
"integrity": "sha512-eWV9XWb4dSYHXl13OtYWLjX1JHphUEkHkkGwJrhr8qFBm7RbxXxQvrsUEprSi51ug/dwJenjJgM4zR8By4htfw==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.0.4.tgz",
|
||||
"integrity": "sha512-GVaiI3KWRFLomjJmApHqihhYlkJ+7FqhumhVfBO6Z2tWzZjQyVQgTdNp0kYEuW2WoAYEj0dKY6qd4YM33xYcUA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"tauri-before-dev": "npm run --workspaces --if-present dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2.0.3",
|
||||
"@tauri-apps/cli": "^2.0.4",
|
||||
"@typescript-eslint/eslint-plugin": "^8.5.0",
|
||||
"@typescript-eslint/parser": "^8.5.0",
|
||||
"eslint": "^8",
|
||||
|
||||
99
src-tauri/Cargo.lock
generated
99
src-tauri/Cargo.lock
generated
@@ -209,7 +209,7 @@ version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"brotli 6.0.0",
|
||||
"flate2",
|
||||
"futures-core",
|
||||
"memchr",
|
||||
@@ -638,6 +638,17 @@ dependencies = [
|
||||
"brotli-decompressor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "7.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
"brotli-decompressor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "4.0.1"
|
||||
@@ -2938,7 +2949,19 @@ version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc"
|
||||
dependencies = [
|
||||
"jsonptr",
|
||||
"jsonptr 0.4.7",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "json-patch"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08"
|
||||
dependencies = [
|
||||
"jsonptr 0.6.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
@@ -2955,6 +2978,16 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonptr"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keyboard-types"
|
||||
version = "0.7.0"
|
||||
@@ -4767,9 +4800,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.6"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -4779,9 +4812,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.7"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -4790,9 +4823,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "rend"
|
||||
@@ -6095,9 +6128,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.0.4"
|
||||
version = "2.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44438500b50708bfc1e6083844e135d1b516325aae58710dcd8fb67e050ae87c"
|
||||
checksum = "d3889b392db6d32a105d3757230ea0220090b8f94c90d3e60b6c5eb91178ab1b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -6146,16 +6179,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-build"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "935f9b3c49b22b3e2e485a57f46d61cd1ae07b1cbb2ba87387a387caf2d8c4e7"
|
||||
checksum = "9f96827ccfb1aa40d55d0ded79562d18ba18566657a553f992a982d755148376"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_toml",
|
||||
"dirs",
|
||||
"glob",
|
||||
"heck 0.5.0",
|
||||
"json-patch",
|
||||
"json-patch 3.0.1",
|
||||
"schemars",
|
||||
"semver",
|
||||
"serde",
|
||||
@@ -6168,14 +6201,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-codegen"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95d7443dd4f0b597704b6a14b964ee2ed16e99928d8e6292ae9825f09fbcd30e"
|
||||
checksum = "8947f16f47becd9e9cd39b74ee337fd1981574d78819be18e4384d85e5a0b82f"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"brotli",
|
||||
"brotli 7.0.0",
|
||||
"ico",
|
||||
"json-patch",
|
||||
"json-patch 2.0.0",
|
||||
"plist",
|
||||
"png",
|
||||
"proc-macro2",
|
||||
@@ -6195,9 +6228,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-macros"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d2c0963ccfc3f5194415f2cce7acc975942a8797fbabfb0aa1ed6f59326ae7f"
|
||||
checksum = "8bd1c8d4a66799d3438747c3a79705cd665a95d6f24cb5f315413ff7a981fe2a"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
@@ -6242,9 +6275,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-dialog"
|
||||
version = "2.0.1"
|
||||
version = "2.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddb2fe88b602461c118722c574e2775ab26a4e68886680583874b2f6520608b7"
|
||||
checksum = "4307310e1d2c09ab110235834722e7c2b85099b683e1eb7342ab351b0be5ada3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"raw-window-handle",
|
||||
@@ -6260,9 +6293,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-fs"
|
||||
version = "2.0.1"
|
||||
version = "2.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab300488ebec3487ca5f56289692e7e45feb07eea8d5e1dba497f7dc9dd9c407"
|
||||
checksum = "96ba7d46e86db8c830d143ef90ab5a453328365b0cc834c24edea4267b16aba0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dunce",
|
||||
@@ -6321,9 +6354,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-shell"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "371fb9aca2823990a2d0db7970573be5fdf07881fcaa2b835b29631feb84aec1"
|
||||
checksum = "0ad7880c5586b6b2104be451e3d7fc0f3800c84bda69e9ba81c828f87cb34267"
|
||||
dependencies = [
|
||||
"encoding_rs",
|
||||
"log",
|
||||
@@ -6387,9 +6420,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime"
|
||||
version = "2.1.0"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8f437293d6f5e5dce829250f4dbdce4e0b52905e297a6689cc2963eb53ac728"
|
||||
checksum = "a1ef7363e7229ac8d04e8a5d405670dbd43dde8fc4bc3bc56105c35452d03784"
|
||||
dependencies = [
|
||||
"dpi",
|
||||
"gtk",
|
||||
@@ -6406,9 +6439,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime-wry"
|
||||
version = "2.1.1"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1431602bcc71f2f840ad623915c9842ecc32999b867c4a787d975a17a9625cc6"
|
||||
checksum = "62fa2068e8498ad007b54d5773d03d57c3ff6dd96f8c8ce58beff44d0d5e0d30"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http 1.1.0",
|
||||
@@ -6432,18 +6465,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c38b0230d6880cf6dd07b6d7dd7789a0869f98ac12146e0d18d1c1049215a045"
|
||||
checksum = "1fc65d6f5c54e56b66258948a6d9e47a82ea41f4b5a7612bfbdd1634c2913ed0"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"brotli 7.0.0",
|
||||
"cargo_metadata",
|
||||
"ctor",
|
||||
"dunce",
|
||||
"glob",
|
||||
"html5ever",
|
||||
"infer",
|
||||
"json-patch",
|
||||
"json-patch 2.0.0",
|
||||
"kuchikiki",
|
||||
"log",
|
||||
"memchr",
|
||||
|
||||
@@ -16,7 +16,7 @@ crate-type = ["staticlib", "cdylib", "lib"]
|
||||
strip = true # Automatically strip symbols from the binary.
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.0.1", features = [] }
|
||||
tauri-build = { version = "2.0.2", features = [] }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
objc = "0.2.7"
|
||||
@@ -48,8 +48,8 @@ serde_yaml = "0.9.34"
|
||||
tauri = { workspace = true }
|
||||
tauri-plugin-shell = { workspace = true }
|
||||
tauri-plugin-clipboard-manager = "2.0.1"
|
||||
tauri-plugin-dialog = "2.0.1"
|
||||
tauri-plugin-fs = "2.0.1"
|
||||
tauri-plugin-dialog = "2.0.3"
|
||||
tauri-plugin-fs = "2.0.3"
|
||||
tauri-plugin-log = { version = "2.0.1", features = ["colored"] }
|
||||
tauri-plugin-os = "2.0.1"
|
||||
tauri-plugin-updater = "2.0.2"
|
||||
@@ -65,5 +65,5 @@ eventsource-client = { git = "https://github.com/yaakapp/rust-eventsource-client
|
||||
[workspace.dependencies]
|
||||
yaak_models = { path = "yaak_models" }
|
||||
yaak_plugin_runtime = { path = "yaak_plugin_runtime" }
|
||||
tauri-plugin-shell = "2.0.1"
|
||||
tauri = { version = "2.0.4", features = ["devtools", "protocol-asset"] }
|
||||
tauri-plugin-shell = "2.0.2"
|
||||
tauri = { version = "2.0.6", features = ["devtools", "protocol-asset"] }
|
||||
|
||||
2
src-tauri/gen/schemas/desktop-schema.json
generated
2
src-tauri/gen/schemas/desktop-schema.json
generated
@@ -37,7 +37,7 @@
|
||||
],
|
||||
"definitions": {
|
||||
"Capability": {
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"identifier",
|
||||
|
||||
2
src-tauri/gen/schemas/macOS-schema.json
generated
2
src-tauri/gen/schemas/macOS-schema.json
generated
@@ -37,7 +37,7 @@
|
||||
],
|
||||
"definitions": {
|
||||
"Capability": {
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"identifier",
|
||||
|
||||
@@ -442,7 +442,6 @@ pub async fn send_http_request<R: Runtime>(
|
||||
}
|
||||
|
||||
// Write body to FS
|
||||
println!("BODYPATH {body_path:?}");
|
||||
let mut f = File::options()
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
@@ -460,11 +459,11 @@ pub async fn send_http_request<R: Runtime>(
|
||||
}
|
||||
match chunk {
|
||||
Ok(Some(bytes)) => {
|
||||
let mut r = response.lock().await;
|
||||
r.elapsed = start.elapsed().as_millis() as i32;
|
||||
f.write_all(&bytes).await.expect("Failed to write to file");
|
||||
f.flush().await.expect("Failed to flush file");
|
||||
written_bytes += bytes.len();
|
||||
let mut r = response.lock().await;
|
||||
r.elapsed = start.elapsed().as_millis() as i32;
|
||||
r.content_length = Some(written_bytes as i32);
|
||||
update_response_if_id(&window, &r)
|
||||
.await
|
||||
|
||||
@@ -75,6 +75,7 @@ use yaak_plugin_runtime::events::{
|
||||
use yaak_plugin_runtime::plugin_handle::PluginHandle;
|
||||
use yaak_sse::sse::ServerSentEvent;
|
||||
use yaak_templates::{Parser, Tokens};
|
||||
use yaak_templates::format::format_json;
|
||||
|
||||
mod analytics;
|
||||
mod export_resources;
|
||||
@@ -737,6 +738,11 @@ async fn cmd_send_ephemeral_request(
|
||||
send_http_request(&window, &request, &response, environment, cookie_jar, &mut cancel_rx).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn cmd_format_json(text: &str) -> Result<String, String> {
|
||||
Ok(format_json(text, " "))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn cmd_filter_response<R: Runtime>(
|
||||
window: WebviewWindow<R>,
|
||||
@@ -1711,12 +1717,10 @@ pub fn run() {
|
||||
cmd_create_folder,
|
||||
cmd_create_grpc_request,
|
||||
cmd_create_http_request,
|
||||
cmd_install_plugin,
|
||||
cmd_create_workspace,
|
||||
cmd_curl_to_request,
|
||||
cmd_delete_all_grpc_connections,
|
||||
cmd_delete_all_http_responses,
|
||||
cmd_delete_send_history,
|
||||
cmd_delete_cookie_jar,
|
||||
cmd_delete_environment,
|
||||
cmd_delete_folder,
|
||||
@@ -1724,26 +1728,28 @@ pub fn run() {
|
||||
cmd_delete_grpc_request,
|
||||
cmd_delete_http_request,
|
||||
cmd_delete_http_response,
|
||||
cmd_uninstall_plugin,
|
||||
cmd_delete_send_history,
|
||||
cmd_delete_workspace,
|
||||
cmd_dismiss_notification,
|
||||
cmd_duplicate_grpc_request,
|
||||
cmd_duplicate_http_request,
|
||||
cmd_export_data,
|
||||
cmd_filter_response,
|
||||
cmd_format_json,
|
||||
cmd_get_cookie_jar,
|
||||
cmd_get_environment,
|
||||
cmd_get_folder,
|
||||
cmd_get_grpc_request,
|
||||
cmd_get_http_request,
|
||||
cmd_get_sse_events,
|
||||
cmd_get_key_value,
|
||||
cmd_get_settings,
|
||||
cmd_get_sse_events,
|
||||
cmd_get_workspace,
|
||||
cmd_grpc_go,
|
||||
cmd_grpc_reflect,
|
||||
cmd_http_request_actions,
|
||||
cmd_import_data,
|
||||
cmd_install_plugin,
|
||||
cmd_list_cookie_jars,
|
||||
cmd_list_environments,
|
||||
cmd_list_folders,
|
||||
@@ -1769,6 +1775,7 @@ pub fn run() {
|
||||
cmd_template_functions,
|
||||
cmd_template_tokens_to_string,
|
||||
cmd_track_event,
|
||||
cmd_uninstall_plugin,
|
||||
cmd_update_cookie_jar,
|
||||
cmd_update_environment,
|
||||
cmd_update_folder,
|
||||
@@ -1969,7 +1976,7 @@ fn monitor_plugin_events<R: Runtime>(app_handle: &AppHandle<R>) {
|
||||
let app_handle = app_handle.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let plugin_manager: State<'_, PluginManager> = app_handle.state();
|
||||
let (rx_id, mut rx) = plugin_manager.subscribe().await;
|
||||
let (rx_id, mut rx) = plugin_manager.subscribe("app").await;
|
||||
|
||||
while let Some(event) = rx.recv().await {
|
||||
let app_handle = app_handle.clone();
|
||||
|
||||
@@ -72,9 +72,6 @@
|
||||
"rpm"
|
||||
],
|
||||
"createUpdaterArtifacts": "v1Compatible",
|
||||
"iOS": {
|
||||
"developmentTeam": "7PU3P6ELJ8"
|
||||
},
|
||||
"macOS": {
|
||||
"minimumSystemVersion": "13.0",
|
||||
"exceptionDomain": "",
|
||||
|
||||
@@ -63,8 +63,12 @@ async function pluginHookExport(_ctx, request) {
|
||||
}
|
||||
xs.push(NEWLINE);
|
||||
}
|
||||
} else if (typeof request.body?.query === "string") {
|
||||
const body = { query: request.body.query || "", variables: maybeParseJSON(request.body.variables, void 0) };
|
||||
xs.push("--data-raw", `${quote(JSON.stringify(body))}`);
|
||||
xs.push(NEWLINE);
|
||||
} else if (typeof request.body?.text === "string") {
|
||||
xs.push("--data-raw", `$${quote(request.body.text)}`);
|
||||
xs.push("--data-raw", `${quote(request.body.text)}`);
|
||||
xs.push(NEWLINE);
|
||||
}
|
||||
if (request.authenticationType === "basic" || request.authenticationType === "digest") {
|
||||
@@ -91,6 +95,13 @@ function quote(arg) {
|
||||
function onlyEnabled(v) {
|
||||
return v.enabled !== false && !!v.name;
|
||||
}
|
||||
function maybeParseJSON(v, fallback) {
|
||||
try {
|
||||
return JSON.parse(v);
|
||||
} catch (err) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
plugin,
|
||||
|
||||
@@ -273,9 +273,9 @@ impl PluginManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn subscribe(&self) -> (String, mpsc::Receiver<InternalEvent>) {
|
||||
pub async fn subscribe(&self, label: &str) -> (String, mpsc::Receiver<InternalEvent>) {
|
||||
let (tx, rx) = mpsc::channel(128);
|
||||
let rx_id = generate_id();
|
||||
let rx_id = format!("{label}_{}", generate_id());
|
||||
self.subscribers.lock().await.insert(rx_id.clone(), tx);
|
||||
(rx_id, rx)
|
||||
}
|
||||
@@ -362,7 +362,8 @@ impl PluginManager {
|
||||
payload: &InternalEventPayload,
|
||||
plugins: Vec<PluginHandle>,
|
||||
) -> Result<Vec<InternalEvent>> {
|
||||
let (rx_id, mut rx) = self.subscribe().await;
|
||||
let label = format!("wait[{}]", plugins.len());
|
||||
let (rx_id, mut rx) = self.subscribe(label.as_str()).await;
|
||||
|
||||
// 1. Build the events with IDs and everything
|
||||
let events_to_send = plugins
|
||||
@@ -557,9 +558,9 @@ impl PluginManager {
|
||||
content_type: &str,
|
||||
) -> Result<FilterResponse> {
|
||||
let plugin_name = if content_type.to_lowercase().contains("json") {
|
||||
"filter-jsonpath"
|
||||
"@yaakapp/filter-jsonpath"
|
||||
} else {
|
||||
"filter-xpath"
|
||||
"@yaakapp/filter-xpath"
|
||||
};
|
||||
|
||||
let plugin = self
|
||||
|
||||
255
src-tauri/yaak_templates/src/format.rs
Normal file
255
src-tauri/yaak_templates/src/format.rs
Normal file
@@ -0,0 +1,255 @@
|
||||
enum FormatState {
|
||||
TemplateTag,
|
||||
String,
|
||||
None,
|
||||
}
|
||||
|
||||
/// Formats JSON that might contain template tags (skipped entirely)
|
||||
pub fn format_json(text: &str, tab: &str) -> String {
|
||||
let mut chars = text.chars().peekable();
|
||||
|
||||
let mut new_json = "".to_string();
|
||||
let mut depth = 0;
|
||||
let mut state = FormatState::None;
|
||||
|
||||
loop {
|
||||
let rest_of_chars = chars.clone();
|
||||
let current_char = match chars.next() {
|
||||
None => break,
|
||||
Some(c) => c,
|
||||
};
|
||||
|
||||
// Handle JSON string states
|
||||
if let FormatState::String = state {
|
||||
match current_char {
|
||||
'"' => {
|
||||
state = FormatState::None;
|
||||
new_json.push(current_char);
|
||||
continue;
|
||||
}
|
||||
'\\' => {
|
||||
new_json.push(current_char);
|
||||
if let Some(c) = chars.next() {
|
||||
new_json.push(c);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
new_json.push(current_char);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Close Template tag states
|
||||
if let FormatState::TemplateTag = state {
|
||||
if rest_of_chars.take(2).collect::<String>() == "]}" {
|
||||
state = FormatState::None;
|
||||
new_json.push_str("]}");
|
||||
chars.next(); // Skip the second closing bracket
|
||||
continue;
|
||||
} else {
|
||||
new_json.push(current_char);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if rest_of_chars.take(3).collect::<String>() == "${[" {
|
||||
state = FormatState::TemplateTag;
|
||||
new_json.push_str("${[");
|
||||
chars.next(); // Skip {
|
||||
chars.next(); // Skip [
|
||||
continue;
|
||||
}
|
||||
|
||||
match current_char {
|
||||
',' => {
|
||||
new_json.push(current_char);
|
||||
new_json.push('\n');
|
||||
new_json.push_str(tab.to_string().repeat(depth).as_str());
|
||||
}
|
||||
'{' => match chars.peek() {
|
||||
Some('}') => {
|
||||
new_json.push(current_char);
|
||||
new_json.push('}');
|
||||
}
|
||||
_ => {
|
||||
depth += 1;
|
||||
new_json.push(current_char);
|
||||
new_json.push('\n');
|
||||
new_json.push_str(tab.to_string().repeat(depth).as_str());
|
||||
}
|
||||
},
|
||||
'[' => match chars.peek() {
|
||||
Some(']') => {
|
||||
new_json.push(current_char);
|
||||
new_json.push(']');
|
||||
}
|
||||
_ => {
|
||||
depth += 1;
|
||||
new_json.push(current_char);
|
||||
new_json.push('\n');
|
||||
new_json.push_str(tab.to_string().repeat(depth).as_str());
|
||||
}
|
||||
},
|
||||
'}' => {
|
||||
depth -= 1;
|
||||
new_json.push('\n');
|
||||
new_json.push_str(tab.to_string().repeat(depth).as_str());
|
||||
new_json.push(current_char);
|
||||
}
|
||||
']' => {
|
||||
depth -= 1;
|
||||
new_json.push('\n');
|
||||
new_json.push_str(tab.to_string().repeat(depth).as_str());
|
||||
new_json.push(current_char);
|
||||
}
|
||||
':' => {
|
||||
new_json.push(current_char);
|
||||
new_json.push(' '); // Pad with space
|
||||
}
|
||||
'"' => {
|
||||
state = FormatState::String;
|
||||
new_json.push(current_char);
|
||||
}
|
||||
_ => {
|
||||
if current_char == ' '
|
||||
|| current_char == '\n'
|
||||
|| current_char == '\t'
|
||||
|| current_char == '\r'
|
||||
{
|
||||
// Don't add these
|
||||
} else {
|
||||
new_json.push(current_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replace only lines containing whitespace with nothing
|
||||
new_json
|
||||
.lines()
|
||||
.filter(|line| !line.trim().is_empty()) // Filter out whitespace-only lines
|
||||
.collect::<Vec<&str>>() // Collect the non-empty lines into a vector
|
||||
.join("\n") // Join the lines back into a single string
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::format::format_json;
|
||||
|
||||
#[test]
|
||||
fn test_simple_object() {
|
||||
assert_eq!(
|
||||
format_json(r#"{"foo":"bar","baz":"qux"}"#, " "),
|
||||
r#"
|
||||
{
|
||||
"foo": "bar",
|
||||
"baz": "qux"
|
||||
}
|
||||
"#
|
||||
.trim()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_array() {
|
||||
assert_eq!(
|
||||
format_json(r#"["foo","bar","baz","qux"]"#, " "),
|
||||
r#"
|
||||
[
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
"qux"
|
||||
]
|
||||
"#
|
||||
.trim()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extra_whitespace() {
|
||||
assert_eq!(
|
||||
format_json(
|
||||
r#"["foo", "bar", "baz","qux"
|
||||
|
||||
]"#,
|
||||
" "
|
||||
),
|
||||
r#"
|
||||
[
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
"qux"
|
||||
]
|
||||
"#
|
||||
.trim()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_json() {
|
||||
assert_eq!(
|
||||
format_json(r#"["foo", {"bar", }"baz",["qux" ]]"#, " "),
|
||||
r#"
|
||||
[
|
||||
"foo",
|
||||
{
|
||||
"bar",
|
||||
}"baz",
|
||||
[
|
||||
"qux"
|
||||
]
|
||||
]
|
||||
"#
|
||||
.trim()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_skip_template_tags() {
|
||||
assert_eq!(
|
||||
format_json(r#"{"foo":${[ fn("hello", "world") ]} }"#, " "),
|
||||
r#"
|
||||
{
|
||||
"foo": ${[ fn("hello", "world") ]}
|
||||
}
|
||||
"#
|
||||
.trim()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_graphql_response() {
|
||||
assert_eq!(
|
||||
format_json(r#"{"data":{"capsules":[{"landings":null,"original_launch":null,"reuse_count":0,"status":"retired","type":"Dragon 1.0","missions":null},{"id":"5e9e2c5bf3591882af3b2665","landings":null,"original_launch":null,"reuse_count":0,"status":"retired","type":"Dragon 1.0","missions":null}]}}"#, " "),
|
||||
r#"
|
||||
{
|
||||
"data": {
|
||||
"capsules": [
|
||||
{
|
||||
"landings": null,
|
||||
"original_launch": null,
|
||||
"reuse_count": 0,
|
||||
"status": "retired",
|
||||
"type": "Dragon 1.0",
|
||||
"missions": null
|
||||
},
|
||||
{
|
||||
"id": "5e9e2c5bf3591882af3b2665",
|
||||
"landings": null,
|
||||
"original_launch": null,
|
||||
"reuse_count": 0,
|
||||
"status": "retired",
|
||||
"type": "Dragon 1.0",
|
||||
"missions": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"#
|
||||
.trim()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
pub mod parser;
|
||||
pub mod renderer;
|
||||
pub mod format;
|
||||
|
||||
pub use parser::*;
|
||||
pub use renderer::*;
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { KeyboardEvent, ReactNode } from 'react';
|
||||
import type { HotkeyAction } from '../hooks/useHotKey';
|
||||
import classNames from 'classnames';
|
||||
import { fuzzyFilter } from 'fuzzbunny';
|
||||
import type { KeyboardEvent, ReactNode } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useActiveCookieJar } from '../hooks/useActiveCookieJar';
|
||||
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
||||
@@ -13,7 +14,6 @@ import { useCreateWorkspace } from '../hooks/useCreateWorkspace';
|
||||
import { useDebouncedState } from '../hooks/useDebouncedState';
|
||||
import { useDeleteRequest } from '../hooks/useDeleteRequest';
|
||||
import { useEnvironments } from '../hooks/useEnvironments';
|
||||
import type { HotkeyAction } from '../hooks/useHotKey';
|
||||
import { useHotKey } from '../hooks/useHotKey';
|
||||
import { useHttpRequestActions } from '../hooks/useHttpRequestActions';
|
||||
import { useOpenSettings } from '../hooks/useOpenSettings';
|
||||
@@ -335,7 +335,9 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||
})),
|
||||
command,
|
||||
{ fields: ['filterBy'] },
|
||||
).map((v) => v.item)
|
||||
)
|
||||
.sort((a, b) => b.score - a.score)
|
||||
.map((v) => v.item)
|
||||
: allItems;
|
||||
|
||||
const filteredGroups = groups
|
||||
|
||||
@@ -20,12 +20,12 @@ type Props = Pick<EditorProps, 'heightMode' | 'className' | 'forceUpdateKey'> &
|
||||
export function GraphQLEditor({ body, onChange, baseRequest, ...extraEditorProps }: Props) {
|
||||
const editorViewRef = useRef<EditorView>(null);
|
||||
const { schema, isLoading, error, refetch } = useIntrospectGraphQL(baseRequest);
|
||||
const [currentBody, setCurrentBody] = useState<{ query: string; variables: string }>(() => {
|
||||
const [currentBody, setCurrentBody] = useState<{ query: string; variables: string | undefined }>(() => {
|
||||
// Migrate text bodies to GraphQL format
|
||||
// NOTE: This is how GraphQL used to be stored
|
||||
if ('text' in body) {
|
||||
const b = tryParseJson(body.text, {});
|
||||
const variables = JSON.stringify(b.variables ?? '', null, 2);
|
||||
const variables = JSON.stringify(b.variables || undefined, null, 2);
|
||||
return { query: b.query ?? '', variables };
|
||||
}
|
||||
|
||||
@@ -33,13 +33,13 @@ export function GraphQLEditor({ body, onChange, baseRequest, ...extraEditorProps
|
||||
});
|
||||
|
||||
const handleChangeQuery = (query: string) => {
|
||||
const newBody = { query, variables: currentBody.variables };
|
||||
const newBody = { query, variables: currentBody.variables || undefined };
|
||||
setCurrentBody(newBody);
|
||||
onChange(newBody);
|
||||
};
|
||||
|
||||
const handleChangeVariables = (variables: string) => {
|
||||
const newBody = { query: currentBody.query, variables };
|
||||
const newBody = { query: currentBody.query, variables: variables || undefined };
|
||||
setCurrentBody(newBody);
|
||||
onChange(newBody);
|
||||
};
|
||||
|
||||
@@ -350,8 +350,9 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
||||
container: CSSProperties;
|
||||
menu: CSSProperties;
|
||||
triangle: CSSProperties;
|
||||
upsideDown: boolean;
|
||||
}>(() => {
|
||||
if (triggerShape == null) return { container: {}, triangle: {}, menu: {} };
|
||||
if (triggerShape == null) return { container: {}, triangle: {}, menu: {}, upsideDown: false };
|
||||
|
||||
const menuMarginY = 5;
|
||||
const docRect = document.documentElement.getBoundingClientRect();
|
||||
@@ -364,6 +365,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
||||
const upsideDown = heightBelow < heightAbove && heightBelow < items.length * 25 + 20 + 200;
|
||||
const triggerWidth = triggerShape.right - triggerShape.left;
|
||||
return {
|
||||
upsideDown,
|
||||
container: {
|
||||
top: !upsideDown ? top + menuMarginY : undefined,
|
||||
bottom: upsideDown
|
||||
@@ -426,7 +428,7 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle'>, MenuPro
|
||||
<motion.div
|
||||
tabIndex={0}
|
||||
onKeyDown={handleMenuKeyDown}
|
||||
initial={{ opacity: 0, y: -5, scale: 0.98 }}
|
||||
initial={{ opacity: 0, y: (styles.upsideDown ? 1 : -1) * 5, scale: 0.98 }}
|
||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||
role="menu"
|
||||
aria-orientation="vertical"
|
||||
|
||||
@@ -61,7 +61,7 @@ export interface EditorProps {
|
||||
onKeyDown?: (e: KeyboardEvent) => void;
|
||||
singleLine?: boolean;
|
||||
wrapLines?: boolean;
|
||||
format?: (v: string) => string;
|
||||
format?: (v: string) => Promise<string>;
|
||||
autocomplete?: GenericCompletionConfig;
|
||||
autocompleteVariables?: boolean;
|
||||
extraExtensions?: Extension[];
|
||||
@@ -387,10 +387,10 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
||||
icon="magic_wand"
|
||||
variant="border"
|
||||
className={classNames(actionClassName)}
|
||||
onClick={() => {
|
||||
onClick={async () => {
|
||||
if (cm.current === null) return;
|
||||
const { doc } = cm.current.view.state;
|
||||
const formatted = format(doc.toString());
|
||||
const formatted = await format(doc.toString());
|
||||
// Update editor and blur because the cursor will reset anyway
|
||||
cm.current.view.dispatch({
|
||||
changes: { from: 0, to: doc.length, insert: formatted },
|
||||
|
||||
@@ -52,7 +52,7 @@ export const syntaxHighlightStyle = HighlightStyle.define([
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
{
|
||||
tag: [t.paren, t.bracket, t.brace],
|
||||
tag: [t.paren, t.bracket, t.squareBracket, t.brace, t.separator],
|
||||
color: 'var(--textSubtle)',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -4,10 +4,11 @@ import type { ServerSentEvent } from '@yaakapp-internal/sse';
|
||||
import classNames from 'classnames';
|
||||
import { motion } from 'framer-motion';
|
||||
import React, { Fragment, useMemo, useRef, useState } from 'react';
|
||||
import { useFormatText } from '../../hooks/useFormatText';
|
||||
import { useResponseBodyEventSource } from '../../hooks/useResponseBodyEventSource';
|
||||
import { isJSON } from '../../lib/contentType';
|
||||
import { tryFormatJson } from '../../lib/formatters';
|
||||
import { Button } from '../core/Button';
|
||||
import type { EditorProps } from '../core/Editor';
|
||||
import { Editor } from '../core/Editor';
|
||||
import { Icon } from '../core/Icon';
|
||||
import { InlineCode } from '../core/InlineCode';
|
||||
@@ -95,11 +96,7 @@ function ActualEventStreamViewer({ response }: Props) {
|
||||
</div>
|
||||
</VStack>
|
||||
) : (
|
||||
<Editor
|
||||
readOnly
|
||||
defaultValue={tryFormatJson(activeEvent.data)}
|
||||
language={language}
|
||||
/>
|
||||
<FormattedEditor language={language} text={activeEvent.data} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -110,6 +107,12 @@ function ActualEventStreamViewer({ response }: Props) {
|
||||
);
|
||||
}
|
||||
|
||||
function FormattedEditor({ text, language }: { text: string; language: EditorProps['language'] }) {
|
||||
const formatted = useFormatText({ text, language, pretty: true });
|
||||
if (formatted.data == null) return null;
|
||||
return <Editor readOnly defaultValue={formatted.data} language={language} />;
|
||||
}
|
||||
|
||||
function EventStreamEventsVirtual({
|
||||
events,
|
||||
activeEventIndex,
|
||||
|
||||
@@ -31,7 +31,7 @@ export function HTMLOrTextViewer({ response, pretty, textViewerClassName }: Prop
|
||||
}
|
||||
|
||||
if (language === 'html' && pretty) {
|
||||
return <WebPageViewer response={response} />;
|
||||
return <WebPageViewer response={response}/>;
|
||||
} else {
|
||||
return (
|
||||
<TextViewer
|
||||
@@ -41,6 +41,7 @@ export function HTMLOrTextViewer({ response, pretty, textViewerClassName }: Prop
|
||||
className={textViewerClassName}
|
||||
onSaveResponse={saveResponse.mutate}
|
||||
responseId={response.id}
|
||||
requestId={response.requestId}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import { createGlobalState } from 'react-use';
|
||||
import { useCopy } from '../../hooks/useCopy';
|
||||
import { useDebouncedValue } from '../../hooks/useDebouncedValue';
|
||||
import { useFilterResponse } from '../../hooks/useFilterResponse';
|
||||
import { useFormatText } from '../../hooks/useFormatText';
|
||||
import { useToggle } from '../../hooks/useToggle';
|
||||
import { tryFormatJson, tryFormatXml } from '../../lib/formatters';
|
||||
import { CopyButton } from '../CopyButton';
|
||||
import { Banner } from '../core/Banner';
|
||||
import { Button } from '../core/Button';
|
||||
@@ -28,6 +28,7 @@ interface Props {
|
||||
text: string;
|
||||
language: EditorProps['language'];
|
||||
responseId: string;
|
||||
requestId: string;
|
||||
onSaveResponse: () => void;
|
||||
}
|
||||
|
||||
@@ -37,20 +38,21 @@ export function TextViewer({
|
||||
language,
|
||||
text,
|
||||
responseId,
|
||||
requestId,
|
||||
pretty,
|
||||
className,
|
||||
onSaveResponse,
|
||||
}: Props) {
|
||||
const [filterTextMap, setFilterTextMap] = useFilterText();
|
||||
const [showLargeResponse, toggleShowLargeResponse] = useToggle();
|
||||
const filterText = filterTextMap[responseId] ?? null;
|
||||
const filterText = filterTextMap[requestId] ?? null;
|
||||
const copy = useCopy();
|
||||
const debouncedFilterText = useDebouncedValue(filterText, 200);
|
||||
const setFilterText = useCallback(
|
||||
(v: string | null) => {
|
||||
setFilterTextMap((m) => ({ ...m, [responseId]: v }));
|
||||
setFilterTextMap((m) => ({ ...m, [requestId]: v }));
|
||||
},
|
||||
[setFilterTextMap, responseId],
|
||||
[setFilterTextMap, requestId],
|
||||
);
|
||||
|
||||
const isSearching = filterText != null;
|
||||
@@ -75,7 +77,7 @@ export function TextViewer({
|
||||
nodes.push(
|
||||
<div key="input" className="w-full !opacity-100">
|
||||
<Input
|
||||
key={responseId}
|
||||
key={requestId}
|
||||
validate={!filteredResponse.error}
|
||||
hideLabel
|
||||
autoFocus
|
||||
@@ -110,11 +112,13 @@ export function TextViewer({
|
||||
filteredResponse.error,
|
||||
isSearching,
|
||||
language,
|
||||
responseId,
|
||||
requestId,
|
||||
setFilterText,
|
||||
toggleSearch,
|
||||
]);
|
||||
|
||||
const formattedBody = useFormatText({ text, language, pretty });
|
||||
|
||||
if (!showLargeResponse && text.length > LARGE_RESPONSE_BYTES) {
|
||||
return (
|
||||
<Banner color="primary" className="h-full flex flex-col gap-3">
|
||||
@@ -138,12 +142,9 @@ export function TextViewer({
|
||||
);
|
||||
}
|
||||
|
||||
const formattedBody =
|
||||
pretty && language === 'json'
|
||||
? tryFormatJson(text)
|
||||
: pretty && (language === 'xml' || language === 'html')
|
||||
? tryFormatXml(text)
|
||||
: text;
|
||||
if (formattedBody.data == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let body;
|
||||
if (isSearching && filterText?.length > 0) {
|
||||
@@ -153,7 +154,7 @@ export function TextViewer({
|
||||
body = filteredResponse.data != null ? filteredResponse.data : '';
|
||||
}
|
||||
} else {
|
||||
body = formattedBody;
|
||||
body = formattedBody.data;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
28
src-web/hooks/useFormatText.ts
Normal file
28
src-web/hooks/useFormatText.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { EditorProps } from '../components/core/Editor';
|
||||
import { tryFormatJson, tryFormatXml } from '../lib/formatters';
|
||||
|
||||
export function useFormatText({
|
||||
text,
|
||||
language,
|
||||
pretty,
|
||||
}: {
|
||||
text: string;
|
||||
language: EditorProps['language'];
|
||||
pretty: boolean;
|
||||
}) {
|
||||
return useQuery({
|
||||
queryKey: [text, language, pretty],
|
||||
queryFn: async () => {
|
||||
if (text === '' || !pretty) {
|
||||
return text;
|
||||
} else if (language === 'json') {
|
||||
return tryFormatJson(text);
|
||||
} else if (language === 'xml' || language === 'html') {
|
||||
return tryFormatXml(text);
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -23,6 +23,7 @@ export function useSyncWorkspaceChildModels() {
|
||||
const workspaceId = workspace?.id ?? 'n/a';
|
||||
useEffect(() => {
|
||||
(async function () {
|
||||
console.log('Syncing model stores', { workspaceId });
|
||||
// Set the things we need first, first
|
||||
setHttpRequests(await invokeCmd('cmd_list_http_requests', { workspaceId }));
|
||||
setGrpcRequests(await invokeCmd('cmd_list_grpc_requests', { workspaceId }));
|
||||
|
||||
@@ -1,20 +1,31 @@
|
||||
import xmlFormat from 'xml-formatter';
|
||||
import { invokeCmd } from './tauri';
|
||||
|
||||
const INDENT = ' ';
|
||||
|
||||
export function tryFormatJson(text: string, pretty = true): string {
|
||||
export async function tryFormatJson(text: string): Promise<string> {
|
||||
if (text === '') return text;
|
||||
|
||||
try {
|
||||
if (pretty) return JSON.stringify(JSON.parse(text), null, INDENT);
|
||||
else return JSON.stringify(JSON.parse(text));
|
||||
const result = await invokeCmd<string>('cmd_format_json', { text });
|
||||
return result;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (err) {
|
||||
return text;
|
||||
console.warn("Failed to format JSON", err);
|
||||
// Nothing
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.stringify(JSON.parse(text), null, 2);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (err) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
export function tryFormatXml(text: string): string {
|
||||
export async function tryFormatXml(text: string): Promise<string> {
|
||||
if (text === '') return text;
|
||||
|
||||
try {
|
||||
|
||||
@@ -28,6 +28,7 @@ type TauriCmd =
|
||||
| 'cmd_duplicate_http_request'
|
||||
| 'cmd_export_data'
|
||||
| 'cmd_filter_response'
|
||||
| 'cmd_format_json'
|
||||
| 'cmd_get_cookie_jar'
|
||||
| 'cmd_get_environment'
|
||||
| 'cmd_get_folder'
|
||||
|
||||
Reference in New Issue
Block a user